cmd/cue/cmd: added cue mod init command
Tests done in follow-up CL
Change-Id: Ib2238f54b82c69c7c81e568b0180ad67bc8115ed
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3866
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/mod.go b/cmd/cue/cmd/mod.go
new file mode 100644
index 0000000..5e356f1
--- /dev/null
+++ b/cmd/cue/cmd/mod.go
@@ -0,0 +1,175 @@
+// Copyright 2019 CUE Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cmd
+
+import (
+ "fmt"
+ "math/rand"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/spf13/cobra"
+)
+
+func newModCmd(c *Command) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "mod <cmd> [arguments]",
+ Short: "module maintenace",
+ Long: `
+`,
+ RunE: mkRunE(c, func(cmd *Command, args []string) error {
+ stderr := cmd.Stderr()
+ if len(args) == 0 {
+ fmt.Fprintln(stderr, "mod must be run as one of its subcommands")
+ } else {
+ fmt.Fprintf(stderr, "get must be run as one of its subcommands: unknown subcommand %q\n", args[0])
+ }
+ fmt.Fprintln(stderr, "Run 'cue help mod' for known subcommands.")
+ os.Exit(1) // TODO: get rid of this
+ return nil
+ }),
+ }
+
+ cmd.AddCommand(newModInitCmd(c))
+ return cmd
+}
+
+func newModInitCmd(c *Command) *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "init [module]",
+ Short: "initialize new module in current director",
+ Long: `Init initializes a cue.mod directory in the current directory,
+in effect creating a new module rooted at the current directory.
+The cue.mod directory must not already exist.
+A legacy cue.mod file in the current directory is moved
+to the new subdirectory.
+
+A module name is optional, but if it is not given a packages
+within the module cannot imported another package defined
+in the module.
+`,
+ RunE: mkRunE(c, runModInit),
+ }
+
+ cmd.Flags().BoolP(string(flagForce), "f", false, "force moving old-style cue.mod file")
+
+ return cmd
+}
+
+func runModInit(cmd *Command, args []string) (err error) {
+ defer func() {
+ if err != nil {
+ // TODO: Refactor Cobra usage to do something more principled
+ fmt.Fprintln(cmd.OutOrStderr(), err)
+ os.Exit(1)
+ }
+ }()
+
+ module := ""
+ if len(args) > 0 {
+ if len(args) != 1 {
+ return fmt.Errorf("too many arguments")
+ }
+ module := args[0]
+ u, err := url.Parse("https://" + module)
+ if err != nil {
+ return fmt.Errorf("invalid module name: %v", module)
+ }
+ if h := u.Hostname(); !strings.Contains(h, ".") {
+ return fmt.Errorf("invalid host name %q", h)
+ }
+ }
+
+ cwd, err := os.Getwd()
+ if err != nil {
+ return err
+ }
+
+ mod := filepath.Join(cwd, "cue.mod")
+
+ info, err := os.Stat(mod)
+
+ // Detect old setups and backport it if requested.
+ if err == nil && !info.IsDir() {
+ // This path backports
+ if !flagForce.Bool(cmd) {
+ return fmt.Errorf("detected old-style config file; use --force to upgrade")
+ }
+ return backport(mod, cwd)
+ }
+
+ if err == nil {
+ return fmt.Errorf("cue.mod directory already exists")
+ }
+
+ err = os.Mkdir(mod, 0755)
+ if err != nil && !os.IsExist(err) {
+ return err
+ }
+
+ f, err := os.Create(filepath.Join(mod, "module.cue"))
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ // Set module even if it is empty, making it easier for users to fill it in.
+ _, err = fmt.Fprintf(f, "module: %q\n", module)
+
+ if err = os.Mkdir(filepath.Join(mod, "usr"), 0755); err != nil {
+ return err
+ }
+ if err = os.Mkdir(filepath.Join(mod, "pkg"), 0755); err != nil {
+ return err
+ }
+
+ return err
+}
+
+// backport backports an old cue.mod setup to a new one.
+func backport(mod, cwd string) error {
+ tmp := filepath.Join(cwd, fmt.Sprintf("_%x_cue.mod", rand.Int()))
+ err := os.Rename(mod, tmp)
+ if err != nil {
+ return err
+ }
+
+ err = os.Mkdir(filepath.Join(cwd, "cue.mod"), 0755)
+ if err != nil {
+ os.Rename(tmp, mod)
+ return err
+ }
+
+ err = os.Rename(tmp, filepath.Join(cwd, "cue.mod", "module.cue"))
+ if err != nil {
+ return err
+ }
+
+ err = os.Rename(filepath.Join(cwd, "pkg"), filepath.Join(cwd, "cue.mod", "gen"))
+ if err != nil && !os.IsNotExist(err) {
+ return err
+ }
+
+ if err = os.Mkdir(filepath.Join(mod, "usr"), 0755); err != nil {
+ return err
+ }
+ if err = os.Mkdir(filepath.Join(mod, "pkg"), 0755); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/cmd/cue/cmd/root.go b/cmd/cue/cmd/root.go
index 6fcc8ce..75e8e58 100644
--- a/cmd/cue/cmd/root.go
+++ b/cmd/cue/cmd/root.go
@@ -81,15 +81,18 @@
c.cmd = cmdCmd
subCommands := []*cobra.Command{
- newTrimCmd(c),
- newImportCmd(c),
- newEvalCmd(c),
- newGetCmd(c),
- newFmtCmd(c),
- newExportCmd(c),
cmdCmd,
+ newEvalCmd(c),
+ newExportCmd(c),
+ newFmtCmd(c),
+ newGetCmd(c),
+ newImportCmd(c),
+ newModCmd(c),
+ newTrimCmd(c),
newVersionCmd(c),
newVetCmd(c),
+
+ // Hidden
newAddCmd(c),
}