cue/load: allow imports from a module root package directory
It is unclear whether we should have a module cache similar to Go.
For now we will use this. It is compatible with using a go get
(module style) approach later.
Change-Id: I5fa34f81c6e7c0baacbff38aa8cc6ea41d078324
Reviewed-on: https://cue-review.googlesource.com/c/1601
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/load/config.go b/cue/load/config.go
index 3e1633b..bf5f398 100644
--- a/cue/load/config.go
+++ b/cue/load/config.go
@@ -26,6 +26,7 @@
cueSuffix = ".cue"
defaultDir = "cue"
modFile = "cue.mod"
+ pkgDir = "pkg" // TODO: vendor?
)
// FromArgsUsage is a partial usage message that applications calling
@@ -138,17 +139,6 @@
}
}
- c.loader = &loader{cfg: &c}
-
- if c.Context == nil {
- c.Context = build.NewContext(build.Loader(c.loader.loadFunc(c.Dir)))
- }
-
- if c.cache == "" {
- c.cache = filepath.Join(home(), defaultDir)
- // os.MkdirAll(c.Cache, 0755) // TODO: tools task
- }
-
// TODO: determine root on a package basis. Maybe we even need a
// pkgname.cue.mod
// Look to see if there is a cue.mod.
@@ -161,26 +151,50 @@
c.modRoot = abs
}
}
+
+ c.loader = &loader{cfg: &c}
+
+ if c.Context == nil {
+ c.Context = build.NewContext(build.Loader(c.loader.loadFunc(c.Dir)))
+ }
+
+ if c.cache == "" {
+ c.cache = filepath.Join(home(), defaultDir)
+ // os.MkdirAll(c.Cache, 0755) // TODO: tools task
+ }
+
return &c, nil
}
func findRoot(dir string) (string, error) {
- abs, err := filepath.Abs(dir)
+ absDir, err := filepath.Abs(dir)
if err != nil {
return "", err
}
+ abs := absDir
for {
info, err := os.Stat(filepath.Join(abs, modFile))
if err == nil && !info.IsDir() {
- break
+ return abs, nil
}
d := filepath.Dir(abs)
if len(d) >= len(abs) {
- return "", err // reached top of file system, no cue.mod
+ break // reached top of file system, no cue.mod
}
abs = d
}
- return abs, nil
+ abs = absDir
+ for {
+ info, err := os.Stat(filepath.Join(abs, pkgDir))
+ if err == nil && info.IsDir() {
+ return abs, nil
+ }
+ d := filepath.Dir(abs)
+ if len(d) >= len(abs) {
+ return "", err // reached top of file system, no pkg dir.
+ }
+ abs = d
+ }
}
func home() string {
diff --git a/cue/load/import.go b/cue/load/import.go
index 0d2d35c..7ad72ee 100644
--- a/cue/load/import.go
+++ b/cue/load/import.go
@@ -18,6 +18,7 @@
"bytes"
"fmt"
"log"
+ "os"
pathpkg "path"
"path/filepath"
"sort"
@@ -75,7 +76,7 @@
parentPath := path
if isLocalImport(path) {
- parentPath = filepath.Join(srcDir, path)
+ parentPath = filepath.Join(srcDir, filepath.FromSlash(path))
}
p := cfg.Context.NewInstance(path, l.loadFunc(parentPath))
p.DisplayPath = path
@@ -162,10 +163,18 @@
return func(path string) *build.Instance {
cfg := l.cfg
- // TODO: HACK: for now we don't handle any imports that are not
- // relative paths.
if !isLocalImport(path) {
- return nil
+ // is it a builtin?
+ if strings.IndexByte(strings.Split(path, "/")[0], '.') == -1 {
+ return nil
+ }
+ if cfg.modRoot == "" {
+ i := cfg.newInstance(path)
+ report(i, l.errPkgf(nil,
+ "import %q not found in the pkg directory", path))
+ return i
+ }
+ return l.importPkg(path, filepath.Join(cfg.modRoot, "pkg"))
}
if strings.Contains(path, "@") {
@@ -186,6 +195,10 @@
return fmt.Errorf("import %q: invalid import path", path)
}
+ if ctxt.isAbsPath(path) || strings.HasPrefix(path, "/") {
+ return fmt.Errorf("load: absolute import path %q not allowed", path)
+ }
+
if isLocalImport(path) {
if srcDir == "" {
return fmt.Errorf("import %q: import relative to unknown directory", path)
@@ -194,14 +207,15 @@
p.Dir = ctxt.joinPath(srcDir, path)
}
return nil
+ } else {
+ dir := ctxt.joinPath(srcDir, path)
+ info, err := os.Stat(filepath.Join(srcDir, path))
+ if err == nil && info.IsDir() {
+ p.Dir = dir
+ return nil
+ }
}
- if strings.HasPrefix(path, "/") {
- return fmt.Errorf("import %q: cannot import absolute path", path)
- }
-
- // TODO: Lookup the import in dir "pkg" at the module root.
-
// package was not found
return fmt.Errorf("cannot find package %q", path)
}
diff --git a/cue/load/loader_test.go b/cue/load/loader_test.go
index 36effb6..5d79d41 100644
--- a/cue/load/loader_test.go
+++ b/cue/load/loader_test.go
@@ -77,6 +77,12 @@
args: args("./empty"),
want: ": (0 files)",
err: `no CUE files in ./empty`,
+ }, {
+ args: args("./imports"),
+ want: `
+imports: imports/imports.cue (1 files)
+ catch: pkg/acme.com/catch/catch.cue (1 files)`,
+ err: ``,
}}
for i, tc := range testCases {
t.Run(strconv.Itoa(i)+"/"+strings.Join(tc.args, ":"), func(t *testing.T) {
diff --git a/cue/load/testdata/imports/imports.cue b/cue/load/testdata/imports/imports.cue
new file mode 100644
index 0000000..8fbaa13
--- /dev/null
+++ b/cue/load/testdata/imports/imports.cue
@@ -0,0 +1,7 @@
+package imports
+
+import "acme.com/catch"
+
+coyoteTry1: catch.Method & "tnt"
+
+coyoteTry2: catch.Method & =~"cat"
diff --git a/cue/load/testdata/other/file/file.cue b/cue/load/testdata/other/file/file.cue
index 57dcc90..bd56fec 100644
--- a/cue/load/testdata/other/file/file.cue
+++ b/cue/load/testdata/other/file/file.cue
@@ -1,5 +1,3 @@
-// Test data - not compiled.
-
package file
{}
diff --git a/cue/load/testdata/pkg/acme.com/catch/catch.cue b/cue/load/testdata/pkg/acme.com/catch/catch.cue
new file mode 100644
index 0000000..7b952fe
--- /dev/null
+++ b/cue/load/testdata/pkg/acme.com/catch/catch.cue
@@ -0,0 +1,3 @@
+package catch
+
+Method: "tnt" | "catapult" | "net"