Skip to content

Commit

Permalink
cmd/cue/cmd: wire up modmux
Browse files Browse the repository at this point in the history
This gives the cue command the capability to specify
multiple registries.

Signed-off-by: Roger Peppe <[email protected]>
Change-Id: Iccf78185044ff8a19bce27b42926534ae27c6e8e
Reviewed-on: https://review-eu.gerrithub.io/c/cue-lang/cue/+/1170886
TryBot-Result: CUEcueckoo <[email protected]>
Unity-Result: CUE porcuepine <[email protected]>
Reviewed-by: Daniel Martí <[email protected]>
  • Loading branch information
rogpeppe committed Oct 25, 2023
1 parent 8e24597 commit ac1b433
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 161 deletions.
86 changes: 9 additions & 77 deletions cmd/cue/cmd/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,14 @@ package cmd

import (
"fmt"
"net"
"os"
"strings"

"cuelabs.dev/go/oci/ociregistry"
"cuelabs.dev/go/oci/ociregistry/ociclient"
"cuelabs.dev/go/oci/ociregistry/ocifilter"
"cuelabs.dev/go/oci/ociregistry/ociref"

"cuelang.org/go/internal/cueexperiment"
"cuelang.org/go/internal/mod/modmux"
"cuelang.org/go/internal/mod/modresolve"
)

func getRegistry() (ociregistry.Interface, error) {
Expand All @@ -23,79 +21,13 @@ func getRegistry() (ociregistry.Interface, error) {
}
return nil, nil
}
if env == "" {
env = "registry.cuelabs.dev"
}

host, prefix, insecure, err := parseRegistry(env)
if err != nil {
return nil, err
}
r, err := ociclient.New(host, &ociclient.Options{
Insecure: insecure,
})
if err != nil {
return nil, fmt.Errorf("cannot make OCI client: %v", err)
}
if prefix != "" {
r = ocifilter.Sub(r, prefix)
}
return r, nil
}

func parseRegistry(env string) (hostPort, prefix string, insecure bool, err error) {
var suffix string
if i := strings.LastIndex(env, "+"); i > 0 {
suffix = env[i:]
env = env[:i]
}
var r ociref.Reference
if !strings.Contains(env, "/") {
// OCI references don't allow a host name on its own without a repo,
// but we do.
r.Host = env
if !ociref.IsValidHost(r.Host) {
return "", "", false, fmt.Errorf("$CUE_REGISTRY %q is not a valid host name", r.Host)
}
} else {
var err error
r, err = ociref.Parse(env)
if err != nil {
return "", "", false, fmt.Errorf("cannot parse $CUE_REGISTRY: %v", err)
}
if r.Tag != "" || r.Digest != "" {
return "", "", false, fmt.Errorf("$CUE_REGISTRY %q cannot have an associated tag or digest", env)
}
}
if suffix == "" {
if isInsecureHost(r.Host) {
suffix = "+insecure"
} else {
suffix = "+secure"
}
}
switch suffix {
case "+insecure":
insecure = true
case "+secure":
default:
return "", "", false, fmt.Errorf("unknown suffix (%q) to CUE_REGISTRY (need +insecure or +secure)", suffix)
}
return r.Host, r.Repository, insecure, nil
}

func isInsecureHost(hostPort string) bool {
host, _, err := net.SplitHostPort(hostPort)
resolver, err := modresolve.ParseCUERegistry(env, "registry.cuelabs.dev")
if err != nil {
host = hostPort
}
switch host {
case "localhost",
"127.0.0.1",
"::1":
return true
return nil, fmt.Errorf("bad value for $CUE_REGISTRY: %v", err)
}
// TODO other clients have logic for RFC1918 too, amongst other
// things. Maybe we should do that too.
return false
return modmux.New(resolver, func(host string, insecure bool) (ociregistry.Interface, error) {
return ociclient.New(host, &ociclient.Options{
Insecure: insecure,
})
}), nil
}
77 changes: 0 additions & 77 deletions cmd/cue/cmd/registry_test.go

This file was deleted.

29 changes: 23 additions & 6 deletions cmd/cue/cmd/script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,25 @@ func TestScript(t *testing.T) {
"GONOSUMDB=*", // GOPROXY is a private proxy
homeEnvName()+"="+home,
)
registryDir := filepath.Join(e.WorkDir, "_registry")
if info, err := os.Stat(registryDir); err == nil && info.IsDir() {
entries, err := os.ReadDir(e.WorkDir)
if err != nil {
return fmt.Errorf("cannot read workdir: %v", err)
}
hasRegistry := false
for _, entry := range entries {
if !entry.IsDir() {
continue
}
regID, ok := strings.CutPrefix(entry.Name(), "_registry")
if !ok {
continue
}
// There's a _registry directory. Start a fake registry server to serve
// the modules in it.
hasRegistry = true
registryDir := filepath.Join(e.WorkDir, entry.Name())
prefix := ""
if data, err := os.ReadFile(filepath.Join(e.WorkDir, "_registry_prefix")); err == nil {
if data, err := os.ReadFile(filepath.Join(e.WorkDir, "_registry"+regID+"_prefix")); err == nil {
prefix = strings.TrimSpace(string(data))
}
reg, err := registrytest.New(os.DirFS(registryDir), prefix)
Expand All @@ -124,14 +137,18 @@ func TestScript(t *testing.T) {
prefix = "/" + prefix
}
e.Vars = append(e.Vars,
"CUE_REGISTRY="+reg.Host()+prefix+"+insecure",
"CUE_REGISTRY"+regID+"="+reg.Host()+prefix+"+insecure",
// This enables some tests to construct their own malformed
// CUE_REGISTRY values that still refer to the test registry.
"DEBUG_REGISTRY_HOST="+reg.Host(),
"CUE_EXPERIMENT=modules",
"DEBUG_REGISTRY"+regID+"_HOST="+reg.Host(),
)
e.Defer(reg.Close)
}
if hasRegistry {
e.Vars = append(e.Vars,
"CUE_EXPERIMENT=modules",
)
}
return nil
},
Condition: cuetest.Condition,
Expand Down
2 changes: 1 addition & 1 deletion cmd/cue/cmd/testdata/script/registry_invalid_env.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ env CUE_REGISTRY=malformed!registry@url
cmp stderr expect-stderr

-- expect-stderr --
$CUE_REGISTRY "malformed!registry@url" is not a valid host name
bad value for $CUE_REGISTRY: invalid registry "malformed!registry@url": invalid host name "malformed!registry@url" in registry
-- main.cue --
package main
import "example.com/e"
Expand Down
129 changes: 129 additions & 0 deletions cmd/cue/cmd/testdata/script/registry_mux.txtar
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
env CUE_REGISTRY=${CUE_REGISTRY1},baz.org=$CUE_REGISTRY2
exec cue eval .
cmp stdout expect-stdout
-- expect-stdout --
main: "main"
"foo.com/bar/hello@v0": "v0.2.3"
"bar.com@v0": "v0.5.0"
"baz.org@v0": "v0.10.1 in registry2"
"example.com@v0": "v0.0.1"
-- cue.mod/module.cue --
module: "main.org"

deps: "example.com@v0": v: "v0.0.1"

-- main.cue --
package main
import "example.com@v0:main"

main

-- _registry1/example.com_v0.0.1/cue.mod/module.cue --
module: "example.com@v0"
deps: {
"foo.com/bar/hello@v0": v: "v0.2.3"
"bar.com@v0": v: "v0.5.0"
}

-- _registry1/example.com_v0.0.1/top.cue --
package main

// Note: import without a major version takes
// the major version from the module.cue file.
import a "foo.com/bar/hello"
a
main: "main"
"example.com@v0": "v0.0.1"

-- _registry1/foo.com_bar_hello_v0.2.3/cue.mod/module.cue --
module: "foo.com/bar/hello@v0"
deps: {
"bar.com@v0": v: "v0.0.2"
"baz.org@v0": v: "v0.10.1"
}

-- _registry1/foo.com_bar_hello_v0.2.3/x.cue --
package hello
import (
a "bar.com/bar@v0"
b "baz.org@v0:baz"
)
"foo.com/bar/hello@v0": "v0.2.3"
a
b


-- _registry1/bar.com_v0.0.2/cue.mod/module.cue --
module: "bar.com@v0"
deps: "baz.org@v0": v: "v0.0.2"

-- _registry1/bar.com_v0.0.2/bar/x.cue --
package bar
import a "baz.org@v0:baz"
"bar.com@v0": "v0.0.2"
a


-- _registry1/bar.com_v0.5.0/cue.mod/module.cue --
module: "bar.com@v0"
deps: "baz.org@v0": v: "v0.5.0"

-- _registry1/bar.com_v0.5.0/bar/x.cue --
package bar
import a "baz.org@v0:baz"
"bar.com@v0": "v0.5.0"
a


-- _registry1/baz.org_v0.0.2/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry1/baz.org_v0.0.2/baz.cue --
package baz
"baz.org@v0": "v0.0.2"

-- _registry1/baz.org_v0.1.2/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry1/baz.org_v0.1.2/baz.cue --
package baz
"baz.org@v0": "v0.1.2"


-- _registry1/baz.org_v0.5.0/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry1/baz.org_v0.5.0/baz.cue --
package baz
"baz.org@v0": "v0.5.0"

-- _registry1/baz.org_v0.10.1/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry1/baz.org_v0.10.1/baz.cue --
package baz
"baz.org@v0": "v0.10.1"

-- _registry2/baz.org_v0.0.2/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry2/baz.org_v0.0.2/baz.cue --
package baz
"baz.org@v0": "v0.0.2"

-- _registry2/baz.org_v0.1.2/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry2/baz.org_v0.5.0/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry2/baz.org_v0.5.0/baz.cue --
package baz
"baz.org@v0": "v0.5.0 in registry2"

-- _registry2/baz.org_v0.10.1/cue.mod/module.cue --
module: "baz.org@v0"

-- _registry2/baz.org_v0.10.1/baz.cue --
package baz
"baz.org@v0": "v0.10.1 in registry2"

0 comments on commit ac1b433

Please sign in to comment.