this repo has no description
0
fork

Configure Feed

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

cue/load: support absolute directory paths as package args

Previously, passing an absolute directory path like `/path/to/pkg` or
`$PWD` to commands such as `cue eval` or `cue export` failed with
"cannot use absolute directory ... as package path". Convert absolute
package arguments into relative paths rooted at the configured working
directory up front so the rest of the loading logic handles them as
ordinary local import paths.

The rewrite runs before splitting arguments into packages and files so
that Windows-style absolute paths like `C:\foo\bar` are handled
correctly; filetypes.IsPackage rejects them because of the drive-letter
colon, so without the early rewrite they were misclassified as files.

While here, consolidate the Windows-courtesy `\` to `/` rewrite in
the same loop, and clone the args slice so we do not mutate the
callers input when rewriting qualifiers or normalising paths.

Fixes #1908.

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

+36 -30
+9 -11
cmd/cue/cmd/testdata/script/cmd_filetypes.txtar
··· 27 27 cmp stdout export.golden 28 28 exec cue export ./somepkg/ 29 29 cmp stdout export.golden 30 - # TODO(mvdan): we should support loading packages from absolute directories. 31 - ! exec cue export ${WORK}${/}somepkg 32 - [!windows] stderr 'cannot use absolute directory ".*somepkg" as package path' 33 - [windows] stderr 'no encoding specified for file ".*somepkg.*"' 34 - ! exec cue export ${WORK}${/}somepkg${/} 35 - [!windows] stderr 'cannot use absolute directory ".*somepkg/" as package path' 36 - [windows] stderr 'no encoding specified for file ".*somepkg.*"' 30 + exec cue export ${WORK}${/}somepkg 31 + cmp stdout export.golden 32 + exec cue export ${WORK}${/}somepkg${/} 33 + cmp stdout export.golden 37 34 38 35 # Now do some of the same filename tests, but for a file without any extension. 39 36 cp somefile.cue somefile ··· 54 51 55 52 ! exec cue export ./somefile 56 53 stderr '\./somefile is a file and not a package directory' 57 - # TODO(mvdan): we probably should not behave differently on Windows. 58 54 ! exec cue export ${WORK}${/}somefile 59 - [!windows] stderr 'cannot use absolute directory ".*somefile" as package path' 60 - [windows] stderr 'no encoding specified for file ".*somefile"' 55 + stderr '\./somefile is a file and not a package directory' 61 56 62 - # A package path pointing outside the current module is rejected. 57 + # A package path pointing outside the current module is rejected, 58 + # whether given as a relative or absolute path. 63 59 cd nested 64 60 ! exec cue export ./../somepkg 61 + stderr 'cannot determine import path for "\./\.\./somepkg" \(dir outside of root\)' 62 + ! exec cue export ${WORK}${/}somepkg 65 63 stderr 'cannot determine import path for "\./\.\./somepkg" \(dir outside of root\)' 66 64 cd ${WORK} 67 65
+27 -11
cue/load/instances.go
··· 35 35 "cuelang.org/go/internal/mod/semver" 36 36 "cuelang.org/go/mod/modfile" 37 37 "cuelang.org/go/mod/module" 38 + pkgpath "cuelang.org/go/pkg/path" 38 39 ) 39 40 40 41 // Instances returns the instances named by the command line arguments 'args'. ··· 51 52 c = &Config{} 52 53 } 53 54 55 + ctx := context.TODO() 56 + newC, err := c.complete() 57 + if err != nil { 58 + return []*build.Instance{c.newErrInstance(err)} 59 + } 60 + c = newC 61 + 62 + // Rewrite absolute directory arguments as relative paths rooted at 63 + // [Config.Dir] so the rest of the loading logic handles them as ordinary 64 + // local import paths. Must happen before the package/file split, as 65 + // [filetypes.IsPackage] rejects Windows paths like `C:\foo` due to the colon. 66 + // Also rewrite \ to / as a courtesy to Windows developers. 67 + args = slices.Clone(args) 68 + for i, p := range args { 69 + if pkgpath.IsAbs(p, c.pathOS) { 70 + rel, err := pkgpath.Rel(c.Dir, p, c.pathOS) 71 + if err != nil { 72 + return []*build.Instance{c.newErrInstance(err)} 73 + } 74 + p = "./" + rel 75 + } 76 + args[i] = pkgpath.ToSlash(p, c.pathOS) 77 + } 78 + 54 79 // TODO: This requires packages to be placed before files. At some point this 55 80 // could be relaxed. 56 81 i := 0 ··· 69 94 if err != nil { 70 95 return []*build.Instance{c.newErrInstance(err)} 71 96 } 72 - ctx := context.TODO() 73 - newC, err := c.complete() 74 - if err != nil { 75 - return []*build.Instance{c.newErrInstance(err)} 76 - } 77 - c = newC 78 97 for _, f := range otherFiles { 79 98 if err := setFileSource(c, f); err != nil { 80 99 return []*build.Instance{c.newErrInstance(err)} ··· 88 107 // between package paths specified as arguments, which 89 108 // have the qualifier added, and package paths that are dependencies 90 109 // of those, which don't. 91 - pkgArgs1 := make([]string, 0, len(pkgArgs)) 92 - for _, p := range pkgArgs { 110 + for i, p := range pkgArgs { 93 111 if ip := ast.ParseImportPath(p); !ip.ExplicitQualifier { 94 112 ip.Qualifier = c.Package 95 - p = ip.String() 113 + pkgArgs[i] = ip.String() 96 114 } 97 - pkgArgs1 = append(pkgArgs1, p) 98 115 } 99 - pkgArgs = pkgArgs1 100 116 } 101 117 102 118 // When outside a module, a major-only version like foo.com/bar@v2
-8
cue/load/search.go
··· 305 305 // Its semantics follow those of [Config.Package]. 306 306 func appendExpandedPackageArg(c *Config, pkgPaths []resolvedPackageArg, p string, pkgQual string, tg *tagger) ([]resolvedPackageArg, error) { 307 307 origp := p 308 - if pkgpath.IsAbs(p, c.pathOS) { 309 - return nil, fmt.Errorf("cannot use absolute directory %q as package path", p) 310 - } 311 - // Arguments are supposed to be import paths, but 312 - // as a courtesy to Windows developers, rewrite \ to / 313 - // in command-line arguments. Handles .\... and so on. 314 - p = pkgpath.ToSlash(p, c.pathOS) 315 - 316 308 ip := ast.ParseImportPath(p) 317 309 if ip.Qualifier == "_" { 318 310 return nil, fmt.Errorf("invalid import path qualifier _ in %q", origp)