Skip to content

Commit

Permalink
internal/mod/module: add CheckPathWithoutVersion
Browse files Browse the repository at this point in the history
This enables us to check that module path is valid when it doesn't
have a version suffix.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: Ia28e2fb305c1c3e63a7b06cf898be4c844201f1f
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1170841
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
  • Loading branch information
rogpeppe committed Oct 17, 2023
1 parent 63307bd commit c6da768
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 24 deletions.
26 changes: 26 additions & 0 deletions internal/mod/module/module_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,32 @@ func TestCheck(t *testing.T) {
}
}

var checkPathWithoutVersionTests = []struct {
path string
wantErr string
}{{
path: "rsc io/quote",
wantErr: `invalid char ' '`,
}, {
path: "foo.com@v0",
wantErr: `module path inappropriately contains major version`,
}, {
path: "foo.com/bar/baz",
}}

func TestCheckPathWithoutVersion(t *testing.T) {
for _, test := range checkPathWithoutVersionTests {
t.Run(test.path, func(t *testing.T) {
err := CheckPathWithoutVersion(test.path)
if test.wantErr != "" {
qt.Assert(t, qt.ErrorMatches(err, test.wantErr))
return
}
qt.Assert(t, qt.IsNil(err))
})
}
}

var newVersionTests = []struct {
path, vers string
wantError string
Expand Down
59 changes: 35 additions & 24 deletions internal/mod/module/path.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,40 @@ func fileNameOK(r rune) bool {
return unicode.IsLetter(r)
}

// CheckPathWithoutVersion is like CheckPath except that
// it expects a module path without a major version.
func CheckPathWithoutVersion(basePath string) (err error) {
if _, _, ok := SplitPathVersion(basePath); ok {
return fmt.Errorf("module path inappropriately contains major version")
}
if err := checkPath(basePath, modulePath); err != nil {
return err
}
i := strings.Index(basePath, "/")
if i < 0 {
i = len(basePath)
}
if i == 0 {
return fmt.Errorf("leading slash")
}
if !strings.Contains(basePath[:i], ".") {
return fmt.Errorf("missing dot in first path element")
}
if basePath[0] == '-' {
return fmt.Errorf("leading dash in first path element")
}
for _, r := range basePath[:i] {
if !firstPathOK(r) {
return fmt.Errorf("invalid char %q in first path element", r)
}
}
// Sanity check agreement with OCI specs.
if !basePathPat.MatchString(basePath) {
return fmt.Errorf("non-conforming path %q", basePath)
}
return nil
}

// CheckPath checks that a module path is valid.
// A valid module path is a valid import path, as checked by CheckImportPath,
// with three additional constraints.
Expand Down Expand Up @@ -135,32 +169,9 @@ func CheckPath(mpath string) (err error) {
if semver.Major(vers) != vers {
return fmt.Errorf("path can contain major version only")
}

if err := checkPath(basePath, modulePath); err != nil {
if err := CheckPathWithoutVersion(basePath); err != nil {
return err
}
i := strings.Index(basePath, "/")
if i < 0 {
i = len(basePath)
}
if i == 0 {
return fmt.Errorf("leading slash")
}
if !strings.Contains(basePath[:i], ".") {
return fmt.Errorf("missing dot in first path element")
}
if basePath[0] == '-' {
return fmt.Errorf("leading dash in first path element")
}
for _, r := range basePath[:i] {
if !firstPathOK(r) {
return fmt.Errorf("invalid char %q in first path element", r)
}
}
// Sanity check agreement with OCI specs.
if !basePathPat.MatchString(basePath) {
return fmt.Errorf("non-conforming path %q", basePath)
}
if !tagPat.MatchString(vers) {
return fmt.Errorf("non-conforming version %q", vers)
}
Expand Down

0 comments on commit c6da768

Please sign in to comment.