this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue/load: more correct treatment of module paths with major versions

Currently if the module path contains a major version,
the cue/load logic naively appends the relative package
path, but that's not correct, as the major version comes after
the import path and before the qualifier.

We can use the `module.ImportPath` logic to correctly form such
an import path.

Also return a `*PackageError` in modules mode too.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: I8a703cb92e81161ca06a1f8647985770b69bf9b9
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194789
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+60 -48
+1 -1
cmd/cue/cmd/testdata/script/registry_lazy_config.txtar
··· 12 12 cp OTHER/main.cue main.cue 13 13 cp OTHER/cue.mod/module.cue cue.mod/module.cue 14 14 ! exec cue export . 15 - stderr '^import failed: cannot find package "example.com/e": cannot fetch example.com/e@v0.0.1: module example.com/e@v0.0.1: cannot do HTTP request: Get ".*": cannot load OCI auth configuration: invalid config file ".*config.json": decode failed: .*' 15 + stderr '^test.org@v0: import failed: cannot find package "example.com/e": cannot fetch example.com/e@v0.0.1: module example.com/e@v0.0.1: cannot do HTTP request: Get ".*": cannot load OCI auth configuration: invalid config file ".*config.json": decode failed: .*' 16 16 -- dockerconfig/config.json -- 17 17 should be JSON but isn't 18 18 -- expect-stdout --
+1 -1
cmd/cue/cmd/testdata/script/registry_module_not_found.txtar
··· 5 5 cmp stderr expect-stderr 6 6 7 7 -- expect-stderr -- 8 - import failed: cannot find package "example.com/e": cannot fetch example.com/e@v0.0.2: module example.com/e@v0.0.2: module not found: 8 + test.org@v0: import failed: cannot find package "example.com/e": cannot fetch example.com/e@v0.0.2: module example.com/e@v0.0.2: module not found: 9 9 ./main.cue:2:8 10 10 -- main.cue -- 11 11 package main
+1 -1
cmd/cue/cmd/testdata/script/registry_nofallback.txtar
··· 4 4 cmp stderr expect-stderr 5 5 6 6 -- expect-stderr -- 7 - import failed: cannot find package "example.com@v0": cannot fetch example.com@v0.0.1: module not found: 7 + main.org@v0: import failed: cannot find package "example.com@v0": cannot fetch example.com@v0.0.1: module not found: 8 8 ./main.cue:2:8 9 9 -- cue.mod/module.cue -- 10 10 module: "main.org@v0"
+1 -1
cmd/cue/cmd/testdata/script/registry_with_pkg_conflict.txtar
··· 6 6 cmp stderr expect-stderr 7 7 8 8 -- expect-stderr -- 9 - import failed: cannot find package "example.com/e": ambiguous import: found package example.com/e in multiple modules: 9 + test.org@v0: import failed: cannot find package "example.com/e": ambiguous import: found package example.com/e in multiple modules: 10 10 example.com/e@v0 v0.0.1 (.) 11 11 local (cue.mod/pkg/example.com/e): 12 12 ./main.cue:2:8
+1 -1
cmd/cue/cmd/testdata/script/registry_wrong_prefix.txtar
··· 3 3 cmp stderr expect-stderr 4 4 5 5 -- expect-stderr -- 6 - import failed: cannot find package "example.com/e": cannot fetch example.com/e@v0.0.1: module example.com/e@v0.0.1: module not found: 6 + test.org@v0: import failed: cannot find package "example.com/e": cannot fetch example.com/e@v0.0.1: module example.com/e@v0.0.1: module not found: 7 7 ./main.cue:2:8 8 8 -- main.cue -- 9 9 package main
+8 -19
cue/load/config.go
··· 20 20 "io" 21 21 "os" 22 22 "path/filepath" 23 - "strings" 24 23 25 24 "cuelang.org/go/cue/ast" 26 25 "cuelang.org/go/cue/build" ··· 306 305 type fsPath string 307 306 308 307 func addImportQualifier(pkg importPath, name string) (importPath, errors.Error) { 309 - if name != "" { 310 - // TODO use module.ParseImportPath 311 - s := string(pkg) 312 - if i := strings.LastIndexByte(s, '/'); i >= 0 { 313 - s = s[i+1:] 314 - } 315 - if i := strings.LastIndexByte(s, ':'); i >= 0 { 316 - // should never happen, but just in case. 317 - s = s[i+1:] 318 - if s != name { 319 - return "", errors.Newf(token.NoPos, 320 - "non-matching package names (%s != %s)", s, name) 321 - } 322 - } else if s != name { 323 - pkg += importPath(":" + name) 324 - } 308 + if name == "" { 309 + return pkg, nil 310 + } 311 + ip := module.ParseImportPath(string(pkg)) 312 + if ip.ExplicitQualifier && ip.Qualifier != name { 313 + return "", errors.Newf(token.NoPos, "non-matching package names (%s != %s)", ip.Qualifier, name) 325 314 } 326 - 327 - return pkg, nil 315 + ip.Qualifier = name 316 + return importPath(ip.String()), nil 328 317 } 329 318 330 319 // Complete updates the configuration information. After calling complete,
+14 -5
cue/load/import.go
··· 343 343 return "", errors.Newf(token.NoPos, 344 344 "cannot determine import path for %q (no module)", key) 345 345 default: 346 - pkg = l.cfg.Module + pkg 346 + impPath := module.ParseImportPath(l.cfg.Module) 347 + impPath.Path += pkg 348 + impPath.Qualifier = "" 349 + pkg = impPath.String() 347 350 } 348 351 349 352 name := l.cfg.Package ··· 374 377 // 375 378 // The returned directory may not exist. 376 379 func (l *loader) absDirFromImportPath(pos token.Pos, p importPath) (absDir, name string, err errors.Error) { 380 + if p == "" { 381 + return "", "", errors.Newf(pos, "empty package name in import path %q", p) 382 + } 377 383 if l.cfg.ModuleRoot == "" { 378 384 return "", "", errors.Newf(pos, "cannot import %q (root undefined)", p) 379 385 } ··· 405 411 // and hence it's available by that name via Pkg. 406 412 pkg := l.pkgs.Pkg(string(origp)) 407 413 if pkg == nil { 408 - return "", name, errors.Newf(pos, "no dependency found for package %q", p) 414 + return "", name, l.errPkgf([]token.Pos{pos}, "no dependency found for package %q", p) 409 415 } 410 416 if err := pkg.Error(); err != nil { 411 - return "", name, errors.Newf(pos, "cannot find package %q: %v", p, err) 417 + return "", name, l.errPkgf([]token.Pos{pos}, "cannot find package %q: %v", p, err) 412 418 } 413 419 if mv := pkg.Mod(); mv.IsLocal() { 414 420 // It's a local package that's present inside one or both of the gen, usr or pkg ··· 419 425 } else { 420 426 locs := pkg.Locations() 421 427 if len(locs) > 1 { 422 - return "", "", errors.Newf(pos, "package %q unexpectedly found in multiple locations", p) 428 + return "", "", l.errPkgf([]token.Pos{pos}, "package %q unexpectedly found in multiple locations", p) 429 + } 430 + if len(locs) == 0 { 431 + return "", "", l.errPkgf([]token.Pos{pos}, "no location found for package %q", p) 423 432 } 424 433 var err error 425 434 absDir, err = absPathForSourceLoc(locs[0]) 426 435 if err != nil { 427 - return "", name, errors.Newf(pos, "cannot determine source directory for package %q: %v", p, err) 436 + return "", name, l.errPkgf([]token.Pos{pos}, "cannot determine source directory for package %q: %v", p, err) 428 437 } 429 438 } 430 439 return absDir, name, nil
+1 -1
cue/load/instances.go
··· 82 82 // logic resolves such paths without consulting pkgs. 83 83 pkgs, err := loadPackages(ctx, c, synCache, pkgArgs, otherFiles) 84 84 if err != nil { 85 - return []*build.Instance{c.newErrInstance(fmt.Errorf("xxx: %v", err))} 85 + return []*build.Instance{c.newErrInstance(err)} 86 86 } 87 87 tg := newTagger(c) 88 88 l := newLoader(c, tg, synCache, pkgs)
+30 -16
cue/load/loader_test.go
··· 67 67 Dir: testdata("badmod"), 68 68 } 69 69 type loadTest struct { 70 + name string 70 71 cfg *Config 71 72 args []string 72 73 want string 73 74 } 74 75 75 76 testCases := []loadTest{{ 77 + name: "BadModuleFile", 76 78 cfg: badModCfg, 77 79 args: []string{"."}, 78 80 want: `err: module: cannot use value 123 (type int) as string: ··· 83 85 dir: "" 84 86 display:""`, 85 87 }, { 88 + name: "DefaultPackage", 86 89 // Even though the directory is called testdata, the last path in 87 90 // the module is test. So "package test" is correctly the default 88 91 // package of this directory. ··· 97 100 $CWD/testdata/testmod/test.cue 98 101 imports: 99 102 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 103 + name: "DefaultPackageWithExplicitDotArgument", 100 104 // Even though the directory is called testdata, the last path in 101 105 // the module is test. So "package test" is correctly the default 102 106 // package of this directory. ··· 111 115 $CWD/testdata/testmod/test.cue 112 116 imports: 113 117 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 114 - // TODO: 115 - // - path incorrect, should be mod.test/test/other:main. 118 + name: "RelativeImportPathWildcard", 116 119 cfg: dirCfg, 117 120 args: []string{"./other/..."}, 118 121 want: `err: import failed: relative import paths not allowed ("./file"): ··· 122 125 root: $CWD/testdata/testmod 123 126 dir: "" 124 127 display:""`}, { 128 + name: "NoPackageName", 125 129 cfg: dirCfg, 126 130 args: []string{"./anon"}, 127 131 want: `err: build constraints exclude all CUE files in ./anon: ··· 131 135 root: $CWD/testdata/testmod 132 136 dir: $CWD/testdata/testmod/anon 133 137 display:./anon`}, { 134 - // TODO: 135 - // - paths are incorrect, should be mod.test/test/other:main. 138 + name: "RelativeImportPathSingle", 136 139 cfg: dirCfg, 137 140 args: []string{"./other"}, 138 141 want: `err: import failed: relative import paths not allowed ("./file"): 139 142 $CWD/testdata/testmod/other/main.cue:6:2 140 - path: mod.test/test/other:main 143 + path: mod.test/test/other 141 144 module: mod.test/test 142 145 root: $CWD/testdata/testmod 143 146 dir: $CWD/testdata/testmod/other 144 147 display:./other 145 148 files: 146 149 $CWD/testdata/testmod/other/main.cue`}, { 147 - // TODO: 148 - // - incorrect path, should be mod.test/test/hello:test 150 + name: "RelativePathSuccess", 149 151 cfg: dirCfg, 150 152 args: []string{"./hello"}, 151 - want: `path: mod.test/test/hello:test 153 + want: `path: mod.test/test/hello 152 154 module: mod.test/test 153 155 root: $CWD/testdata/testmod 154 156 dir: $CWD/testdata/testmod/hello ··· 158 160 $CWD/testdata/testmod/hello/test.cue 159 161 imports: 160 162 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 161 - // TODO: 162 - // - incorrect path, should be mod.test/test/hello:test 163 + name: "ExplicitPackageIdentifier", 163 164 cfg: dirCfg, 164 165 args: []string{"mod.test/test/hello:test"}, 165 166 want: `path: mod.test/test/hello:test ··· 172 173 $CWD/testdata/testmod/hello/test.cue 173 174 imports: 174 175 mod.test/test/sub: $CWD/testdata/testmod/sub/sub.cue`}, { 175 - // TODO: 176 - // - incorrect path, should be mod.test/test/hello:test 176 + name: "NoPackageName", 177 177 cfg: dirCfg, 178 178 args: []string{"mod.test/test/hello:nonexist"}, 179 179 want: `err: build constraints exclude all CUE files in mod.test/test/hello:nonexist: ··· 185 185 root: $CWD/testdata/testmod 186 186 dir: $CWD/testdata/testmod/hello 187 187 display:mod.test/test/hello:nonexist`}, { 188 + name: "ExplicitNonPackageFiles", 188 189 cfg: dirCfg, 189 190 args: []string{"./anon.cue", "./other/anon.cue"}, 190 191 want: `path: "" ··· 195 196 files: 196 197 $CWD/testdata/testmod/anon.cue 197 198 $CWD/testdata/testmod/other/anon.cue`}, { 198 - cfg: dirCfg, 199 + name: "AbsoluteFileIsNormalized", // TODO(rogpeppe) what is this actually testing? 200 + cfg: dirCfg, 199 201 // Absolute file is normalized. 200 202 args: []string{filepath.Join(cwd, testdata("testmod", "anon.cue"))}, 201 203 want: `path: "" ··· 205 207 display:command-line-arguments 206 208 files: 207 209 $CWD/testdata/testmod/anon.cue`}, { 210 + name: "StandardInput", 208 211 cfg: dirCfg, 209 212 args: []string{"-"}, 210 213 want: `path: "" ··· 214 217 display:command-line-arguments 215 218 files: 216 219 -`}, { 220 + name: "BadIdentifier", 217 221 cfg: dirCfg, 218 222 args: []string{"foo.com/bad-identifier"}, 219 223 want: `err: implied package identifier "bad-identifier" from import path "foo.com/bad-identifier" is not valid ··· 223 227 dir: $CWD/testdata/testmod/cue.mod/gen/foo.com/bad-identifier 224 228 display:foo.com/bad-identifier`, 225 229 }, { 230 + name: "NonexistentStdlibImport", 226 231 cfg: dirCfg, 227 232 args: []string{"nonexisting"}, 228 233 want: `err: standard library import path "nonexisting" cannot be imported as a CUE package ··· 232 237 dir: "" 233 238 display:nonexisting`, 234 239 }, { 240 + name: "ExistingStdlibImport", 235 241 cfg: dirCfg, 236 242 args: []string{"strconv"}, 237 243 want: `err: standard library import path "strconv" cannot be imported as a CUE package ··· 241 247 dir: "" 242 248 display:strconv`, 243 249 }, { 250 + name: "EmptyPackageDirectory", 244 251 cfg: dirCfg, 245 252 args: []string{"./empty"}, 246 253 want: `err: no CUE files in ./empty ··· 250 257 dir: $CWD/testdata/testmod/empty 251 258 display:./empty`, 252 259 }, { 260 + name: "PackageWithImports", 253 261 cfg: dirCfg, 254 262 args: []string{"./imports"}, 255 263 want: `path: mod.test/test/imports ··· 262 270 imports: 263 271 mod.test/catch: $CWD/testdata/testmod/cue.mod/pkg/mod.test/catch/catch.cue 264 272 mod.test/helper:helper1: $CWD/testdata/testmod/cue.mod/pkg/mod.test/helper/helper1.cue`}, { 273 + name: "OnlyToolFiles", 265 274 cfg: dirCfg, 266 275 args: []string{"./toolonly"}, 267 - want: `path: mod.test/test/toolonly:foo 276 + want: `path: mod.test/test/toolonly 268 277 module: mod.test/test 269 278 root: $CWD/testdata/testmod 270 279 dir: $CWD/testdata/testmod/toolonly 271 280 display:./toolonly 272 281 files: 273 282 $CWD/testdata/testmod/toolonly/foo_tool.cue`}, { 283 + name: "OnlyToolFilesWithToolsDisabledInConfig", 274 284 cfg: &Config{ 275 285 Dir: testdataDir, 276 286 }, ··· 279 289 anon.cue: no package name 280 290 test.cue: package is test, want foo 281 291 toolonly/foo_tool.cue: _tool.cue files excluded in non-cmd mode 282 - path: mod.test/test/toolonly:foo 292 + path: mod.test/test/toolonly 283 293 module: mod.test/test 284 294 root: $CWD/testdata/testmod 285 295 dir: $CWD/testdata/testmod/toolonly 286 296 display:./toolonly`}, { 297 + name: "WithBoolTag", 287 298 cfg: &Config{ 288 299 Dir: testdataDir, 289 300 Tags: []string{"prod"}, ··· 296 307 display:./tags 297 308 files: 298 309 $CWD/testdata/testmod/tags/prod.cue`}, { 310 + name: "WithAttrValTag", 299 311 cfg: &Config{ 300 312 Dir: testdataDir, 301 313 Tags: []string{"prod", "foo=bar"}, ··· 308 320 display:./tags 309 321 files: 310 322 $CWD/testdata/testmod/tags/prod.cue`}, { 323 + name: "UnusedTag", 311 324 cfg: &Config{ 312 325 Dir: testdataDir, 313 326 Tags: []string{"prod"}, ··· 323 336 root: $CWD/testdata/testmod 324 337 dir: $CWD/testdata/testmod/tagsbad 325 338 display:./tagsbad`}, { 339 + name: "ImportCycle", 326 340 cfg: &Config{ 327 341 Dir: testdataDir, 328 342 }, ··· 397 411 c := &Config{ 398 412 Overlay: map[string]Source{ 399 413 // Not necessary, but nice to add. 400 - abs("cue.mod/module.cue"): FromString(`module: "mod.test"`), 414 + abs("cue.mod/module.cue"): FromString(`module: "mod.test", language: version: "v0.9.0"`), 401 415 402 416 abs("dir/top.cue"): FromBytes([]byte(` 403 417 package top
+2 -2
cue/load/module_test.go
··· 57 57 } 58 58 } 59 59 insts = load.Instances([]string{"."}, cfg) 60 - qt.Assert(t, qt.ErrorMatches(insts[0].Err, `import failed: cannot find package "example.com@v0": cannot fetch example.com@v0.0.1: bad value for \$CUE_REGISTRY: invalid registry "invalid}host:": invalid host name "invalid}host:" in registry`)) 60 + qt.Assert(t, qt.ErrorMatches(insts[0].Err, `import failed: .*main.cue:2:8: cannot find package "example.com@v0": cannot fetch example.com@v0.0.1: bad value for \$CUE_REGISTRY: invalid registry "invalid}host:": invalid host name "invalid}host:" in registry`)) 61 61 62 62 // Try again with environment variables passed in Env. 63 63 // This is really just a smoke test to make sure that Env is ··· 67 67 "CUE_CACHE_DIR=" + cacheDir, 68 68 } 69 69 insts = load.Instances([]string{"."}, cfg) 70 - qt.Assert(t, qt.ErrorMatches(insts[0].Err, `import failed: cannot find package "example.com@v0": cannot fetch example.com@v0.0.1: bad value for \$CUE_REGISTRY: invalid registry "invalid}host2:": invalid host name "invalid}host2:" in registry`)) 70 + qt.Assert(t, qt.ErrorMatches(insts[0].Err, `import failed: .*main.cue:2:8: cannot find package "example.com@v0": cannot fetch example.com@v0.0.1: bad value for \$CUE_REGISTRY: invalid registry "invalid}host2:": invalid host name "invalid}host2:" in registry`)) 71 71 } 72 72 73 73 func TestModuleFetch(t *testing.T) {