cue/load: allow using `path:pkgname` on command line

Change-Id: I4710464457cc7f626dfad6448129e0234c6754f6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4562
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/testdata/script/export_select.txt b/cmd/cue/cmd/testdata/script/export_select.txt
new file mode 100644
index 0000000..d6f9115
--- /dev/null
+++ b/cmd/cue/cmd/testdata/script/export_select.txt
@@ -0,0 +1,26 @@
+cue export .:foo example.org/bar:baz
+
+cmp stdout expect-stdout
+-- cue.mod/module.cue --
+
+-- foo.cue --
+package foo
+
+a: 1
+
+-- bar.cue --
+package bar
+
+b: 1
+
+-- expect-stdout --
+{
+    "a": 1
+}
+{
+    "c": 1
+}
+-- cue.mod/gen/example.org/bar/bar.cue --
+package baz
+
+c:1
diff --git a/cue/load/config.go b/cue/load/config.go
index dc752ce..bb8b902 100644
--- a/cue/load/config.go
+++ b/cue/load/config.go
@@ -165,14 +165,14 @@
 	return i
 }
 
-func (c *Config) newRelInstance(pos token.Pos, path string) *build.Instance {
+func (c *Config) newRelInstance(pos token.Pos, path, pkgName string) *build.Instance {
 	fs := c.fileSystem
 
 	var err errors.Error
 	dir := path
 
 	p := c.Context.NewInstance(path, c.loadFunc)
-	p.PkgName = c.Package
+	p.PkgName = pkgName
 	p.DisplayPath = filepath.ToSlash(path)
 	// p.ImportPath = string(dir) // compute unique ID.
 	p.Root = c.ModuleRoot
diff --git a/cue/load/import_test.go b/cue/load/import_test.go
index 1d51904..1ff43f5 100644
--- a/cue/load/import_test.go
+++ b/cue/load/import_test.go
@@ -29,7 +29,7 @@
 func getInst(pkg, cwd string) (*build.Instance, error) {
 	c, _ := (&Config{Dir: cwd}).complete()
 	l := loader{cfg: c}
-	inst := c.newRelInstance(token.NoPos, pkg)
+	inst := c.newRelInstance(token.NoPos, pkg, c.Package)
 	p := l.importPkg(token.NoPos, inst)
 	return p, p.Err
 }
diff --git a/cue/load/loader.go b/cue/load/loader.go
index debd4ae..54fa070 100644
--- a/cue/load/loader.go
+++ b/cue/load/loader.go
@@ -50,9 +50,11 @@
 
 	// TODO: this is work in progress. We aim to replace the original Go
 	// implementation, which is not ideal for CUE.
-
-	if len(args) > 0 && encoding.MapExtension(filepath.Ext(args[0])) != nil {
-		return []*build.Instance{l.cueFilesPackage(args)}
+	if len(args) > 0 {
+		arg := strings.Split(args[0], ":")[0]
+		if arg == "-" || encoding.MapExtension(filepath.Ext(arg)) != nil {
+			return []*build.Instance{l.cueFilesPackage(args)}
+		}
 	}
 
 	a := []*build.Instance{}
diff --git a/cue/load/search.go b/cue/load/search.go
index 97fea45..a1556b7 100644
--- a/cue/load/search.go
+++ b/cue/load/search.go
@@ -39,7 +39,7 @@
 // TODO: should be matched from module file only.
 // The pattern is either "all" (all packages), "std" (standard packages),
 // "cmd" (standard commands), or a path including "...".
-func (l *loader) matchPackages(pattern string) *match {
+func (l *loader) matchPackages(pattern, pkgName string) *match {
 	// cfg := l.cfg
 	m := &match{
 		Pattern: pattern,
@@ -132,7 +132,7 @@
 // beginning ./ or ../, meaning it should scan the tree rooted
 // at the given directory. There are ... in the pattern too.
 // (See go help packages for pattern syntax.)
-func (l *loader) matchPackagesInFS(pattern string) *match {
+func (l *loader) matchPackagesInFS(pattern, pkgName string) *match {
 	c := l.cfg
 	m := &match{
 		Pattern: pattern,
@@ -204,7 +204,7 @@
 			dir = "./" + dir
 		}
 		// TODO: consider not doing these checks here.
-		inst := c.newRelInstance(token.NoPos, dir)
+		inst := c.newRelInstance(token.NoPos, dir, pkgName)
 		p := l.importPkg(token.NoPos, inst)
 		if err := p.Err; err != nil && (p == nil || len(p.InvalidCUEFiles) == 0) {
 			switch err.(type) {
@@ -333,23 +333,36 @@
 	var out []*match
 	for _, a := range cleanPatterns(patterns) {
 		if isMetaPackage(a) {
-			out = append(out, l.matchPackages(a))
+			out = append(out, l.matchPackages(a, l.cfg.Package))
 			continue
 		}
+
+		orig := a
+		pkgName := l.cfg.Package
+		switch p := strings.IndexByte(a, ':'); {
+		case p < 0:
+		case p == 0:
+			pkgName = a[1:]
+			a = "."
+		default:
+			pkgName = a[p+1:]
+			a = a[:p]
+		}
+
 		if strings.Contains(a, "...") {
 			if isLocalImport(a) {
-				out = append(out, l.matchPackagesInFS(a))
+				out = append(out, l.matchPackagesInFS(a, pkgName))
 			} else {
-				out = append(out, l.matchPackages(a))
+				out = append(out, l.matchPackages(a, pkgName))
 			}
 			continue
 		}
 
 		var p *build.Instance
 		if isLocalImport(a) {
-			p = l.cfg.newRelInstance(token.NoPos, a)
+			p = l.cfg.newRelInstance(token.NoPos, a, pkgName)
 		} else {
-			p = l.cfg.newInstance(token.NoPos, importPath(a))
+			p = l.cfg.newInstance(token.NoPos, importPath(orig))
 		}
 
 		pkg := l.importPkg(token.NoPos, p)