cmd/cue/cmd: remove most global variables

This to improve testing abilities.

Issue #50

Change-Id: Ib9f5c0cfe4e0885e0189c1e1393bdb6968c384b8
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2161
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/add.go b/cmd/cue/cmd/add.go
index 430ecc8..d4787ac 100644
--- a/cmd/cue/cmd/add.go
+++ b/cmd/cue/cmd/add.go
@@ -33,28 +33,27 @@
 	"github.com/spf13/cobra"
 )
 
-var addCmd = &cobra.Command{
-	// TODO: this command is still experimental, don't show it in
-	// the documentation just yet.
-	Hidden: true,
+func newAddCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		// TODO: this command is still experimental, don't show it in
+		// the documentation just yet.
+		Hidden: true,
 
-	Use:   "add <glob> [--list]",
-	Short: "bulk append to CUE files",
-	Long: `Append a common snippet of CUE to many files and commit atomically.
+		Use:   "add <glob> [--list]",
+		Short: "bulk append to CUE files",
+		Long: `Append a common snippet of CUE to many files and commit atomically.
 `,
-	RunE: runAdd,
-}
+		RunE: runAdd,
+	}
 
-func init() {
-	rootCmd.AddCommand(addCmd)
-
-	fList = addCmd.Flags().Bool("list", false,
+	f := cmd.Flags()
+	f.Bool(string(flagList), false,
 		"text executed as Go template with instance info")
-}
+	f.BoolP(string(flagDryrun), "n", false,
+		"only run simulation")
 
-var (
-	fList *bool
-)
+	return cmd
+}
 
 func runAdd(cmd *cobra.Command, args []string) (err error) {
 	return doAdd(cmd, stdin, args)
@@ -113,13 +112,13 @@
 				continue
 			}
 			done[file] = true
-			fi, err := initFile(file, getBuild)
+			fi, err := initFile(cmd, file, getBuild)
 			if err != nil {
 				return err
 			}
 			todo = append(todo, fi)
 			b := fi.build
-			if *fList && (b == nil) {
+			if flagList.Bool(cmd) && (b == nil) {
 				return fmt.Errorf("instance info not available for %s", fi.filename)
 			}
 		}
@@ -132,7 +131,7 @@
 	}
 
 	var tmpl *template.Template
-	if *fList {
+	if flagList.Bool(cmd) {
 		tmpl, err = template.New("append").Parse(string(text))
 		if err != nil {
 			return err
@@ -149,7 +148,7 @@
 		}
 	}
 
-	if *fDryrun {
+	if flagDryrun.Bool(cmd) {
 		stdout := cmd.OutOrStdout()
 		for _, fi := range todo {
 			fmt.Fprintln(stdout, "---", fi.filename)
@@ -214,7 +213,7 @@
 	build    *build.Instance
 }
 
-func initFile(file string, getBuild func(path string) *build.Instance) (todo *fileInfo, err error) {
+func initFile(cmd *cobra.Command, file string, getBuild func(path string) *build.Instance) (todo *fileInfo, err error) {
 	defer func() {
 		if err != nil {
 			err = fmt.Errorf("init file: %v", err)
@@ -230,9 +229,8 @@
 		// File does not exist
 		b := getBuild(dir)
 		todo.build = b
-		pkg := ""
-		if *fPackage != "" {
-			pkg = *fPackage
+		pkg := flagPackage.String(cmd)
+		if pkg != "" {
 			// TODO: do something more intelligent once the package name is
 			// computed on a module basis, even for empty directories.
 			b.PkgName = pkg
@@ -255,13 +253,13 @@
 			return nil, err
 		}
 		if f.Name != nil {
-			if *fPackage != "" && f.Name.Name != *fPackage {
-				return nil, fmt.Errorf("package mismatch (%s vs %s) for file %s", f.Name.Name, *fPackage, file)
+			if pkg := flagPackage.String(cmd); pkg != "" && f.Name.Name != pkg {
+				return nil, fmt.Errorf("package mismatch (%s vs %s) for file %s", f.Name.Name, pkg, file)
 			}
 			todo.build = getBuild(dir)
 		} else {
-			if *fPackage != "" {
-				return nil, fmt.Errorf("file %s has no package clause but package %s requested", file, *fPackage)
+			if pkg := flagPackage.String(cmd); pkg != "" {
+				return nil, fmt.Errorf("file %s has no package clause but package %s requested", file, pkg)
 			}
 			todo.build = getBuild(file)
 			todo.buildArg = file
diff --git a/cmd/cue/cmd/cmd.go b/cmd/cue/cmd/cmd.go
index c041fbe..001af58 100644
--- a/cmd/cue/cmd/cmd.go
+++ b/cmd/cue/cmd/cmd.go
@@ -22,11 +22,11 @@
 
 // TODO: generate long description from documentation.
 
-// cmdCmd represents the cmd command
-var cmdCmd = &cobra.Command{
-	Use:   "cmd <name> [-x] [instances]",
-	Short: "run a user-defined shell command",
-	Long: `cmd executes defined the named command for each of the named instances.
+func newCmdCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "cmd <name> [-x] [instances]",
+		Short: "run a user-defined shell command",
+		Long: `cmd executes defined the named command for each of the named instances.
 
 Commands define actions on instances. For example, they may specify
 how to upload a configuration to Kubernetes. Commands are defined
@@ -209,12 +209,9 @@
 	}
 
 `,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		fmt.Println("cmd run but shouldn't")
-		return nil
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(cmdCmd)
+		RunE: func(cmd *cobra.Command, args []string) error {
+			fmt.Println("cmd run but shouldn't")
+			return nil
+		},
+	}
 }
diff --git a/cmd/cue/cmd/cmd_test.go b/cmd/cue/cmd/cmd_test.go
index f96e457..a92d869 100644
--- a/cmd/cue/cmd/cmd_test.go
+++ b/cmd/cue/cmd/cmd_test.go
@@ -36,6 +36,7 @@
 		stderr = os.Stderr
 	}()
 	for _, name := range testCases {
+		rootCmd := newRootCmd()
 		run := func(cmd *cobra.Command, args []string) error {
 			stdout = cmd.OutOrStdout()
 			stderr = cmd.OutOrStderr()
@@ -51,6 +52,6 @@
 			}
 			return nil
 		}
-		runCommand(t, run, "cmd_"+name)
+		runCommand(t, &cobra.Command{RunE: run}, "cmd_"+name)
 	}
 }
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 9cd6b4b..9878325 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -101,7 +101,7 @@
 	for _, inst := range instances {
 		// TODO: consider merging errors of multiple files, but ensure
 		// duplicates are removed.
-		exitIfErr(cmd, inst, inst.Value().Validate(), !*fIgnore)
+		exitIfErr(cmd, inst, inst.Value().Validate(), !flagIgnore.Bool(cmd))
 	}
 	return instances
 }
diff --git a/cmd/cue/cmd/common_test.go b/cmd/cue/cmd/common_test.go
index 01bcb7a..2920aec 100644
--- a/cmd/cue/cmd/common_test.go
+++ b/cmd/cue/cmd/common_test.go
@@ -34,7 +34,7 @@
 
 var update = flag.Bool("update", false, "update the test files")
 
-func runCommand(t *testing.T, f func(cmd *cobra.Command, args []string) error, name string, args ...string) {
+func runCommand(t *testing.T, cmd *cobra.Command, name string, args ...string) {
 	t.Helper()
 	log.SetFlags(0)
 
@@ -61,7 +61,6 @@
 				return
 			}
 
-			cmd := &cobra.Command{RunE: f}
 			cmd.SetArgs(append(args, "./"+path))
 			rOut, wOut := io.Pipe()
 			cmd.SetOutput(wOut)
@@ -107,5 +106,5 @@
 }
 
 func TestLoadError(t *testing.T) {
-	runCommand(t, evalCmd.RunE, "loaderr", "non-existing", ".")
+	runCommand(t, newEvalCmd(), "loaderr", "non-existing", ".")
 }
diff --git a/cmd/cue/cmd/eval.go b/cmd/cue/cmd/eval.go
index 7590bf8..45224c4 100644
--- a/cmd/cue/cmd/eval.go
+++ b/cmd/cue/cmd/eval.go
@@ -24,11 +24,12 @@
 	"github.com/spf13/cobra"
 )
 
-// evalCmd represents the eval command
-var evalCmd = &cobra.Command{
-	Use:   "eval",
-	Short: "evaluate and print a configuration",
-	Long: `eval evaluates, validates, and prints a configuration.
+// newEvalCmd creates a new eval command
+func newEvalCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "eval",
+		Short: "evaluate and print a configuration",
+		Long: `eval evaluates, validates, and prints a configuration.
 
 Printing is skipped if validation fails.
 
@@ -45,84 +46,82 @@
   "a"
   "c"
 `,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		instances := buildFromArgs(cmd, args)
+		RunE: runEval,
+	}
 
-		var exprs []ast.Expr
-		for _, e := range *expressions {
-			expr, err := parser.ParseExpr("<expression flag>", e)
-			if err != nil {
-				return err
-			}
-			exprs = append(exprs, expr)
-		}
+	cmd.Flags().StringArrayP(string(flagExpression), "e", nil, "evaluate this expression only")
 
-		w := cmd.OutOrStdout()
-
-		for _, inst := range instances {
-			// TODO: use ImportPath or some other sanitized path.
-			fmt.Fprintf(w, "// %s\n", inst.Dir)
-			syn := []cue.Option{
-				cue.Attributes(*attrs),
-				cue.Optional(*all || *optional),
-			}
-			if *compile {
-				syn = append(syn, cue.Concrete(true))
-			}
-			if *hidden || *all {
-				syn = append(syn, cue.Hidden(true))
-			}
-			opts := []format.Option{
-				format.UseSpaces(4),
-				format.TabIndent(false),
-			}
-			if exprs == nil {
-				v := inst.Value()
-				if *compile {
-					err := v.Validate(cue.Concrete(true))
-					exitIfErr(cmd, inst, err, false)
-					continue
-				}
-				format.Node(w, v.Syntax(syn...), opts...)
-				fmt.Fprintln(w)
-			}
-			for _, e := range exprs {
-				format.Node(w, inst.Eval(e).Syntax(syn...), opts...)
-				fmt.Fprintln(w)
-			}
-		}
-		return nil
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(evalCmd)
-
-	expressions = evalCmd.Flags().StringArrayP("expression", "e", nil, "evaluate this expression only")
-
-	compile = evalCmd.Flags().BoolP("concrete", "c", false,
+	cmd.Flags().BoolP(string(flagConcrete), "c", false,
 		"require the evaluation to be concrete")
 
-	hidden = evalCmd.Flags().BoolP("show-hidden", "H", false,
+	cmd.Flags().BoolP(string(flagHidden), "H", false,
 		"display hidden attributes")
 
-	optional = evalCmd.Flags().BoolP("show-optional", "O", false,
+	cmd.Flags().BoolP(string(flagOptional), "O", false,
 		"display hidden attributes")
 
-	attrs = evalCmd.Flags().BoolP("attributes", "l", false,
+	cmd.Flags().BoolP(string(flagAttributes), "l", false,
 		"display field attributes")
 
-	all = evalCmd.Flags().BoolP("all", "a", false,
+	cmd.Flags().BoolP(string(flagAll), "a", false,
 		"show optional and hidden fields")
 
 	// TODO: Option to include comments in output.
+	return cmd
 }
 
-var (
-	expressions *[]string
-	compile     *bool
-	attrs       *bool
-	all         *bool
-	hidden      *bool
-	optional    *bool
+const (
+	flagConcrete   flagName = "concrete"
+	flagHidden     flagName = "show-hidden"
+	flagOptional   flagName = "show-optional"
+	flagAttributes flagName = "attributes"
 )
+
+func runEval(cmd *cobra.Command, args []string) error {
+	instances := buildFromArgs(cmd, args)
+
+	var exprs []ast.Expr
+	for _, e := range flagExpression.StringArray(cmd) {
+		expr, err := parser.ParseExpr("<expression flag>", e)
+		if err != nil {
+			return err
+		}
+		exprs = append(exprs, expr)
+	}
+
+	w := cmd.OutOrStdout()
+
+	for _, inst := range instances {
+		// TODO: use ImportPath or some other sanitized path.
+		fmt.Fprintf(w, "// %s\n", inst.Dir)
+		syn := []cue.Option{
+			cue.Attributes(flagAttributes.Bool(cmd)),
+			cue.Optional(flagAll.Bool(cmd) || flagOptional.Bool(cmd)),
+		}
+		if flagConcrete.Bool(cmd) {
+			syn = append(syn, cue.Concrete(true))
+		}
+		if flagHidden.Bool(cmd) || flagAll.Bool(cmd) {
+			syn = append(syn, cue.Hidden(true))
+		}
+		opts := []format.Option{
+			format.UseSpaces(4),
+			format.TabIndent(false),
+		}
+		if exprs == nil {
+			v := inst.Value()
+			if flagConcrete.Bool(cmd) {
+				err := v.Validate(cue.Concrete(true))
+				exitIfErr(cmd, inst, err, false)
+				continue
+			}
+			format.Node(w, v.Syntax(syn...), opts...)
+			fmt.Fprintln(w)
+		}
+		for _, e := range exprs {
+			format.Node(w, inst.Eval(e).Syntax(syn...), opts...)
+			fmt.Fprintln(w)
+		}
+	}
+	return nil
+}
diff --git a/cmd/cue/cmd/eval_test.go b/cmd/cue/cmd/eval_test.go
index 67e7c41..d073448 100644
--- a/cmd/cue/cmd/eval_test.go
+++ b/cmd/cue/cmd/eval_test.go
@@ -17,5 +17,5 @@
 import "testing"
 
 func TestEval(t *testing.T) {
-	runCommand(t, evalCmd.RunE, "eval")
+	runCommand(t, newEvalCmd(), "eval")
 }
diff --git a/cmd/cue/cmd/export.go b/cmd/cue/cmd/export.go
index 93dacec..beee972 100644
--- a/cmd/cue/cmd/export.go
+++ b/cmd/cue/cmd/export.go
@@ -23,11 +23,12 @@
 	"github.com/spf13/cobra"
 )
 
-// exportCmd represents the emit command
-var exportCmd = &cobra.Command{
-	Use:   "export",
-	Short: "output data in a standard format",
-	Long: `export evaluates the configuration found in the current
+// newExportCmd creates and export command
+func newExportCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "export",
+		Short: "output data in a standard format",
+		Long: `export evaluates the configuration found in the current
 directory and prints the emit value to stdout.
 
 Examples:
@@ -85,46 +86,41 @@
         The evaluated value must be of type string.
 `,
 
-	RunE: func(cmd *cobra.Command, args []string) error {
-		instances := buildFromArgs(cmd, args)
-		w := cmd.OutOrStdout()
+		RunE: runExport,
+	}
+	flagMedia.Add(cmd)
+	cmd.Flags().Bool(string(flagEscape), false, "use HTML escaping")
 
-		for _, inst := range instances {
-			root := inst.Value()
-			if !root.IsValid() {
-				continue
-			}
-			switch *media {
-			case "json":
-				err := outputJSON(w, root)
-				exitIfErr(cmd, inst, err, true)
-			case "text":
-				err := outputText(w, root)
-				exitIfErr(cmd, inst, err, true)
-			default:
-				return fmt.Errorf("export: unknown format %q", *media)
-			}
+	return cmd
+}
+
+func runExport(cmd *cobra.Command, args []string) error {
+	instances := buildFromArgs(cmd, args)
+	w := cmd.OutOrStdout()
+
+	for _, inst := range instances {
+		root := inst.Value()
+		if !root.IsValid() {
+			continue
 		}
-		return nil
-	},
+		switch media := flagMedia.String(cmd); media {
+		case "json":
+			err := outputJSON(cmd, w, root)
+			exitIfErr(cmd, inst, err, true)
+		case "text":
+			err := outputText(w, root)
+			exitIfErr(cmd, inst, err, true)
+		default:
+			return fmt.Errorf("export: unknown format %q", media)
+		}
+	}
+	return nil
 }
 
-var (
-	escape *bool
-	media  *string
-)
-
-func init() {
-	rootCmd.AddCommand(exportCmd)
-
-	media = exportCmd.Flags().String("out", "json", "output format (json or text)")
-	escape = exportCmd.Flags().Bool("escape", false, "use HTML escaping")
-}
-
-func outputJSON(w io.Writer, v cue.Value) error {
+func outputJSON(cmd *cobra.Command, w io.Writer, v cue.Value) error {
 	e := json.NewEncoder(w)
 	e.SetIndent("", "    ")
-	e.SetEscapeHTML(*escape)
+	e.SetEscapeHTML(flagEscape.Bool(cmd))
 
 	err := e.Encode(v)
 	if err != nil {
diff --git a/cmd/cue/cmd/export_test.go b/cmd/cue/cmd/export_test.go
index 77f7f83..9067630 100644
--- a/cmd/cue/cmd/export_test.go
+++ b/cmd/cue/cmd/export_test.go
@@ -17,6 +17,6 @@
 import "testing"
 
 func TestExport(t *testing.T) {
-	runCommand(t, exportCmd.RunE, "export")
-	runCommand(t, exportCmd.RunE, "export_err")
+	runCommand(t, newExportCmd(), "export")
+	runCommand(t, newExportCmd(), "export_err")
 }
diff --git a/cmd/cue/cmd/flags.go b/cmd/cue/cmd/flags.go
new file mode 100644
index 0000000..cfc4b9b
--- /dev/null
+++ b/cmd/cue/cmd/flags.go
@@ -0,0 +1,107 @@
+// 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 (
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+)
+
+// Common flags
+const (
+	flagAll      flagName = "all"
+	flagDryrun   flagName = "dryrun"
+	flagVerbose  flagName = "verbose"
+	flagTrace    flagName = "trace"
+	flagForce    flagName = "force"
+	flagIgnore   flagName = "ignore"
+	flagSimplify flagName = "simplify"
+	flagPackage  flagName = "package"
+	flagDebug    flagName = "debug"
+
+	flagExpression flagName = "expression"
+	flagEscape     flagName = "escape"
+	flagGlob       flagName = "name"
+	flagRecursive  flagName = "recursive"
+	flagType       flagName = "type"
+	flagList       flagName = "list"
+	flagPath       flagName = "path"
+)
+
+var flagMedia = stringFlag{
+	name: "out",
+	text: "output format (json or text)",
+	def:  "json",
+}
+
+var flagOut = stringFlag{
+	name:  "out",
+	short: "o",
+	text:  "alternative output or - for stdout",
+}
+
+func addGlobalFlags(f *pflag.FlagSet) {
+	f.StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cue)")
+	f.Bool("root", false, "load a CUE package from its root")
+
+	f.Bool(string(flagDebug), false,
+		"give detailed error info")
+	f.Bool(string(flagTrace), false,
+		"trace computation")
+	f.StringP(string(flagPackage), "p", "",
+		"CUE package to evaluate")
+	f.BoolP(string(flagSimplify), "s", false,
+		"simplify output")
+	f.BoolP(string(flagIgnore), "i", false,
+		"proceed in the presence of errors")
+	f.BoolP(string(flagVerbose), "v", false,
+		"print information about progress")
+}
+
+type flagName string
+
+func (f flagName) Bool(cmd *cobra.Command) bool {
+	v, _ := cmd.Flags().GetBool(string(f))
+	return v
+}
+
+func (f flagName) String(cmd *cobra.Command) string {
+	v, _ := cmd.Flags().GetString(string(f))
+	return v
+}
+
+func (f flagName) StringArray(cmd *cobra.Command) []string {
+	v, _ := cmd.Flags().GetStringArray(string(f))
+	return v
+}
+
+type stringFlag struct {
+	name  string
+	short string
+	text  string
+	def   string
+}
+
+func (f *stringFlag) Add(cmd *cobra.Command) {
+	cmd.Flags().StringP(f.name, f.short, f.def, f.text)
+}
+
+func (f *stringFlag) String(cmd *cobra.Command) string {
+	v, err := cmd.Flags().GetString(f.name)
+	if err != nil {
+		return f.def
+	}
+	return v
+}
diff --git a/cmd/cue/cmd/fmt.go b/cmd/cue/cmd/fmt.go
index 854a972..b2f1b75 100644
--- a/cmd/cue/cmd/fmt.go
+++ b/cmd/cue/cmd/fmt.go
@@ -23,51 +23,49 @@
 	"github.com/spf13/cobra"
 )
 
-// fmtCmd represents the fmt command
-var fmtCmd = &cobra.Command{
-	Use:   "fmt [-s] [packages]",
-	Short: "formats CUE configuration files",
-	Long: `Fmt formats the given files or the files for the given packages in place
+func newFmtCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "fmt [-s] [packages]",
+		Short: "formats CUE configuration files",
+		Long: `Fmt formats the given files or the files for the given packages in place
 `,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		for _, inst := range load.Instances(args, nil) {
-			all := []string{}
-			all = append(all, inst.CUEFiles...)
-			all = append(all, inst.ToolCUEFiles...)
-			all = append(all, inst.TestCUEFiles...)
-			for _, path := range all {
-				fullpath := inst.Abs(path)
+		RunE: func(cmd *cobra.Command, args []string) error {
+			for _, inst := range load.Instances(args, nil) {
+				all := []string{}
+				all = append(all, inst.CUEFiles...)
+				all = append(all, inst.ToolCUEFiles...)
+				all = append(all, inst.TestCUEFiles...)
+				for _, path := range all {
+					fullpath := inst.Abs(path)
 
-				stat, err := os.Stat(fullpath)
-				if err != nil {
-					return err
-				}
+					stat, err := os.Stat(fullpath)
+					if err != nil {
+						return err
+					}
 
-				b, err := ioutil.ReadFile(fullpath)
-				if err != nil {
-					return err
-				}
+					b, err := ioutil.ReadFile(fullpath)
+					if err != nil {
+						return err
+					}
 
-				opts := []format.Option{}
-				if *fSimplify {
-					opts = append(opts, format.Simplify())
-				}
+					opts := []format.Option{}
+					if flagSimplify.Bool(cmd) {
+						opts = append(opts, format.Simplify())
+					}
 
-				b, err = format.Source(b, opts...)
-				if err != nil {
-					return err
-				}
+					b, err = format.Source(b, opts...)
+					if err != nil {
+						return err
+					}
 
-				err = ioutil.WriteFile(fullpath, b, stat.Mode())
-				if err != nil {
-					return err
+					err = ioutil.WriteFile(fullpath, b, stat.Mode())
+					if err != nil {
+						return err
+					}
 				}
 			}
-		}
-		return nil
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(fmtCmd)
+			return nil
+		},
+	}
+	return cmd
 }
diff --git a/cmd/cue/cmd/get.go b/cmd/cue/cmd/get.go
index 4222db7..a0603ef 100644
--- a/cmd/cue/cmd/get.go
+++ b/cmd/cue/cmd/get.go
@@ -20,11 +20,11 @@
 	"github.com/spf13/cobra"
 )
 
-// getCmd represents the extract command
-var getCmd = &cobra.Command{
-	Use:   "get <language> [packages]",
-	Short: "add dependencies to the current module",
-	Long: `Get downloads packages or modules for CUE or another language
+func newGetCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "get <language> [packages]",
+		Short: "add dependencies to the current module",
+		Long: `Get downloads packages or modules for CUE or another language
 to include them in the module's pkg directory.
 
 Get requires an additional language field to determine for which
@@ -34,12 +34,11 @@
 The specifics on how dependencies are fechted and converted vary
 per language and are documented in the respective subcommands.
 `,
-	RunE: func(cmd *cobra.Command, args []string) error {
-		fmt.Println("get must be run as one of its subcommands")
-		return nil
-	},
-}
-
-func init() {
-	rootCmd.AddCommand(getCmd)
+		RunE: func(cmd *cobra.Command, args []string) error {
+			fmt.Println("get must be run as one of its subcommands")
+			return nil
+		},
+	}
+	cmd.AddCommand(newGoCmd())
+	return cmd
 }
diff --git a/cmd/cue/cmd/get_go.go b/cmd/cue/cmd/get_go.go
index 60f24a1..707eb3d 100644
--- a/cmd/cue/cmd/get_go.go
+++ b/cmd/cue/cmd/get_go.go
@@ -47,10 +47,11 @@
 //   package foo
 //   Type: enumType
 
-var getGoCmd = &cobra.Command{
-	Use:   "go [packages]",
-	Short: "add Go dependencies to the current module",
-	Long: `go converts Go types into CUE definitions
+func newGoCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "go [packages]",
+		Short: "add Go dependencies to the current module",
+		Long: `go converts Go types into CUE definitions
 
 The command "cue get go" is like "go get", but converts the retrieved Go
 packages to CUE. The retrieved packages are put in the CUE module's pkg
@@ -195,45 +196,44 @@
 CUE handles this in the usual way by unifying the two definitions, in which case
 the more restrictive enum interpretation of Switch remains.
 `,
-	// - TODO: interpret cuego's struct tags and annotations.
+		// - TODO: interpret cuego's struct tags and annotations.
 
-	RunE: func(cmd *cobra.Command, args []string) error {
-		return extract(cmd, args)
-	},
-}
+		RunE: func(cmd *cobra.Command, args []string) error {
+			return extract(cmd, args)
+		},
+	}
 
-func init() {
-	getCmd.AddCommand(getGoCmd)
-
-	exclude = getGoCmd.Flags().StringP("exclude", "e", "",
+	cmd.Flags().StringP(string(flagExclude), "e", "",
 		"comma-separated list of regexps of entries")
+
+	return cmd
 }
 
-var (
-	cueTestRoot string // the CUE module root for test purposes.
-	exclude     *string
-
-	exclusions []*regexp.Regexp
+const (
+	flagExclude flagName = "exclude"
 )
 
+var cueTestRoot string // the CUE module root for test purposes.
+
 type dstUsed struct {
 	dst  string
 	used bool
 }
 
-func initExclusions() {
-	for _, re := range strings.Split(*exclude, ",") {
+func (e *extractor) initExclusions(str string) {
+	e.exclude = str
+	for _, re := range strings.Split(str, ",") {
 		if re != "" {
-			exclusions = append(exclusions, regexp.MustCompile(re))
+			e.exclusions = append(e.exclusions, regexp.MustCompile(re))
 		}
 	}
 }
 
-func filter(name string) bool {
+func (e *extractor) filter(name string) bool {
 	if !ast.IsExported(name) {
 		return true
 	}
-	for _, ex := range exclusions {
+	for _, ex := range e.exclusions {
 		if ex.MatchString(name) {
 			return true
 		}
@@ -242,6 +242,8 @@
 }
 
 type extractor struct {
+	cmd *cobra.Command
+
 	stderr io.Writer
 	err    error
 	pkgs   []*packages.Package
@@ -259,10 +261,13 @@
 	pkgNames   map[string]string
 	usedInFile map[string]bool
 	indent     int
+
+	exclusions []*regexp.Regexp
+	exclude    string
 }
 
 func (e *extractor) logf(format string, args ...interface{}) {
-	if *fVerbose {
+	if flagVerbose.Bool(e.cmd) {
 		fmt.Fprintf(e.stderr, format+"\n", args...)
 	}
 }
@@ -344,12 +349,13 @@
 	}
 
 	e := extractor{
+		cmd:    cmd,
 		stderr: cmd.OutOrStderr(),
 		pkgs:   pkgs,
 		orig:   map[types.Type]*ast.StructType{},
 	}
 
-	initExclusions()
+	e.initExclusions(flagExclude.String(cmd))
 
 	e.done = map[string]bool{}
 
@@ -403,8 +409,8 @@
 	e.usedPkgs = map[string]bool{}
 
 	args := pkg
-	if *exclude != "" {
-		args += " --exclude=" + *exclude
+	if e.exclude != "" {
+		args += " --exclude=" + e.exclude
 	}
 
 	for i, f := range p.Syntax {
@@ -568,7 +574,7 @@
 	case token.TYPE:
 		for _, s := range x.Specs {
 			v, ok := s.(*ast.TypeSpec)
-			if !ok || filter(v.Name.Name) {
+			if !ok || e.filter(v.Name.Name) {
 				continue
 			}
 
diff --git a/cmd/cue/cmd/get_go_test.go b/cmd/cue/cmd/get_go_test.go
index 36b1884..1034819 100644
--- a/cmd/cue/cmd/get_go_test.go
+++ b/cmd/cue/cmd/get_go_test.go
@@ -22,7 +22,6 @@
 	"testing"
 
 	"github.com/retr0h/go-gilt/copy"
-	"github.com/spf13/cobra"
 )
 
 func TestGetGo(t *testing.T) {
@@ -39,7 +38,7 @@
 	cueTestRoot = tmp
 
 	// We don't use runCommand here, as we are interested in generated packages.
-	cmd := &cobra.Command{RunE: getGoCmd.RunE}
+	cmd := newGoCmd()
 	cmd.SetArgs([]string{"./testdata/code/go/..."})
 	err = cmd.Execute()
 	if err != nil {
diff --git a/cmd/cue/cmd/import.go b/cmd/cue/cmd/import.go
index 72235ae..c0132b2 100644
--- a/cmd/cue/cmd/import.go
+++ b/cmd/cue/cmd/import.go
@@ -45,10 +45,13 @@
 )
 
 // importCmd represents the import command
-var importCmd = &cobra.Command{
-	Use:   "import",
-	Short: "convert other data formats to CUE files",
-	Long: `import converts other data formats, like JSON and YAML to CUE files
+var importCmd = newImportCmd()
+
+func newImportCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "import",
+		Short: "convert other data formats to CUE files",
+		Long: `import converts other data formats, like JSON and YAML to CUE files
 
 The following file formats are currently supported:
 
@@ -195,43 +198,34 @@
       }
   }
 `,
-	RunE: runImport,
+		RunE: runImport,
+	}
+
+	flagOut.Add(cmd)
+	cmd.Flags().StringP(string(flagGlob), "n", "", "glob filter for file names")
+	cmd.Flags().String(string(flagType), "", "only apply to files of this type")
+	cmd.Flags().BoolP(string(flagForce), "f", false, "force overwriting existing files")
+	cmd.Flags().Bool(string(flagDryrun), false, "force overwriting existing files")
+
+	cmd.Flags().StringP(string(flagPath), "l", "", "path to include root")
+	cmd.Flags().Bool(string(flagList), false, "concatenate multiple objects into a list")
+	cmd.Flags().Bool(string(flagFiles), false, "split multiple entries into different files")
+	cmd.Flags().BoolP(string(flagRecursive), "R", false, "recursively parse string values")
+
+	cmd.Flags().String("fix", "", "apply given fix")
+
+	cmd.Flags().StringArrayP(string(flagProtoPath), "I", nil, "paths in which to search for imports")
+
+	return cmd
 }
 
-func init() {
-	rootCmd.AddCommand(importCmd)
-
-	out = importCmd.Flags().StringP("out", "o", "", "alternative output or - for stdout")
-	name = importCmd.Flags().StringP("name", "n", "", "glob filter for file names")
-	typ = importCmd.Flags().String("type", "", "only apply to files of this type")
-	force = importCmd.Flags().BoolP("force", "f", false, "force overwriting existing files")
-	dryrun = importCmd.Flags().Bool("dryrun", false, "force overwriting existing files")
-
-	node = importCmd.Flags().StringP("path", "l", "", "path to include root")
-	list = importCmd.Flags().Bool("list", false, "concatenate multiple objects into a list")
-	files = importCmd.Flags().Bool("files", false, "split multiple entries into different files")
-	parseStrings = importCmd.Flags().BoolP("recursive", "R", false, "recursively parse string values")
-
-	importCmd.Flags().String("fix", "", "apply given fix")
-
-	protoPaths = importCmd.Flags().StringArrayP("proto_path", "I", nil, "paths in which to search for imports")
-}
-
-var (
-	force        *bool
-	name         *string
-	typ          *string
-	node         *string
-	out          *string
-	dryrun       *bool
-	list         *bool
-	files        *bool
-	parseStrings *bool
-	protoPaths   *[]string
+const (
+	flagFiles     flagName = "files"
+	flagProtoPath flagName = "proto_path"
 )
 
 type importStreamFunc func(path string, r io.Reader) ([]ast.Expr, error)
-type importFileFunc func(path string, r io.Reader) (*ast.File, error)
+type importFileFunc func(cmd *cobra.Command, path string, r io.Reader) (*ast.File, error)
 
 type encodingInfo struct {
 	fnStream importStreamFunc
@@ -266,10 +260,12 @@
 
 	var group errgroup.Group
 
+	pkgFlag := flagPackage.String(cmd)
+
 	group.Go(func() (err error) {
 		if len(args) > 0 && len(filepath.Ext(args[0])) > len(".") {
 			for _, a := range args {
-				group.Go(func() error { return handleFile(cmd, *fPackage, a) })
+				group.Go(func() error { return handleFile(cmd, pkgFlag, a) })
 			}
 			return nil
 		}
@@ -278,7 +274,7 @@
 
 		inst := load.Instances(args, &load.Config{DataFiles: true})
 		for _, pkg := range inst {
-			pkgName := *fPackage
+			pkgName := pkgFlag
 			if pkgName == "" {
 				pkgName = pkg.PkgName
 			}
@@ -300,7 +296,8 @@
 			}
 			for _, file := range files {
 				ext := filepath.Ext(file.Name())
-				if enc := getExtInfo(ext); enc == nil || (*typ != "" && *typ != enc.typ) {
+				typ := flagType.String(cmd)
+				if enc := getExtInfo(ext); enc == nil || (typ != "" && typ != enc.typ) {
 					continue
 				}
 				path := filepath.Join(dir, file.Name())
@@ -316,7 +313,7 @@
 }
 
 func handleFile(cmd *cobra.Command, pkg, filename string) (err error) {
-	re, err := regexp.Compile(*name)
+	re, err := regexp.Compile(flagGlob.String(cmd))
 	if err != nil {
 		return err
 	}
@@ -337,7 +334,7 @@
 		return fmt.Errorf("unsupported extension %q", ext)
 
 	case handler.fnFile != nil:
-		file, err := handler.fnFile(filename, f)
+		file, err := handler.fnFile(cmd, filename, f)
 		if err != nil {
 			return err
 		}
@@ -368,7 +365,7 @@
 }
 
 func processStream(cmd *cobra.Command, pkg, filename string, objs []ast.Expr) error {
-	if *files {
+	if flagFiles.Bool(cmd) {
 		for i, f := range objs {
 			err := combineExpressions(cmd, pkg, newName(filename, i), f)
 			if err != nil {
@@ -377,7 +374,7 @@
 		}
 		return nil
 	} else if len(objs) > 1 {
-		if !*list && *node == "" && !*files {
+		if !flagList.Bool(cmd) && flagPath.String(cmd) == "" && !flagFiles.Bool(cmd) {
 			return fmt.Errorf("list, flag, or files flag needed to handle multiple objects in file %q", filename)
 		}
 	}
@@ -391,14 +388,14 @@
 	mutex.Lock()
 	defer mutex.Unlock()
 
-	if *out != "" {
-		cueFile = *out
+	if out := flagOut.String(cmd); out != "" {
+		cueFile = out
 	}
 	if cueFile != "-" {
 		switch _, err := os.Stat(cueFile); {
 		case os.IsNotExist(err):
 		case err == nil:
-			if !*force {
+			if !flagForce.Bool(cmd) {
 				log.Printf("skipping file %q: already exists", cueFile)
 				return nil
 			}
@@ -419,7 +416,7 @@
 
 	index := newIndex()
 	for _, expr := range objs {
-		if *parseStrings {
+		if flagRecursive.Bool(cmd) {
 			h.hoist(expr)
 		}
 
@@ -427,13 +424,13 @@
 		var pathElems []ast.Label
 
 		switch {
-		case *node != "":
+		case flagPath.String(cmd) != "":
 			inst, err := runtime.FromExpr(expr)
 			if err != nil {
 				return err
 			}
 
-			labels, err := parsePath(*node)
+			labels, err := parsePath(flagPath.String(cmd))
 			if err != nil {
 				return err
 			}
@@ -455,7 +452,7 @@
 			}
 		}
 
-		if *list {
+		if flagList.Bool(cmd) {
 			idx := index
 			for _, e := range pathElems {
 				idx = idx.label(e)
@@ -509,7 +506,7 @@
 		f.Decls = append([]ast.Decl{imports}, f.Decls...)
 	}
 
-	if *list {
+	if flagList.Bool(cmd) {
 		switch x := index.field.Value.(type) {
 		case *ast.StructLit:
 			f.Decls = append(f.Decls, x.Elts...)
@@ -652,8 +649,8 @@
 	return objects, nil
 }
 
-func handleProtoDef(path string, r io.Reader) (f *ast.File, err error) {
-	return protobuf.Parse(path, r, &protobuf.Config{Paths: *protoPaths})
+func handleProtoDef(cmd *cobra.Command, path string, r io.Reader) (f *ast.File, err error) {
+	return protobuf.Parse(path, r, &protobuf.Config{Paths: flagProtoPath.StringArray(cmd)})
 }
 
 type hoister struct {
diff --git a/cmd/cue/cmd/import_test.go b/cmd/cue/cmd/import_test.go
index caf74b7..c0ce198 100644
--- a/cmd/cue/cmd/import_test.go
+++ b/cmd/cue/cmd/import_test.go
@@ -17,24 +17,28 @@
 import "testing"
 
 func TestImport(t *testing.T) {
-	importCmd.ParseFlags([]string{
+	cmd := newImportCmd()
+	cmd.ParseFlags([]string{
 		"-o", "-", "-f", "--files",
 	})
-	runCommand(t, importCmd.RunE, "import_files")
+	runCommand(t, cmd, "import_files")
 
-	*files = false
-	importCmd.ParseFlags([]string{
-		"-f", "-l", `"\(strings.ToLower(kind))" "\(name)"`,
+	cmd = newImportCmd()
+	cmd.ParseFlags([]string{
+		"-o", "-", "-f", "-l", `"\(strings.ToLower(kind))" "\(name)"`,
 	})
-	runCommand(t, importCmd.RunE, "import_path")
+	runCommand(t, cmd, "import_path")
 
-	importCmd.ParseFlags([]string{
-		"-f", "-l", `"\(strings.ToLower(kind))"`, "--list",
+	cmd = newImportCmd()
+	cmd.ParseFlags([]string{
+		"-o", "-", "-f", "-l", `"\(strings.ToLower(kind))"`, "--list",
 	})
-	runCommand(t, importCmd.RunE, "import_list")
+	runCommand(t, cmd, "import_list")
 
-	importCmd.ParseFlags([]string{
-		"-f", "-l", `"\(strings.ToLower(kind))" "\(name)"`, "--recursive",
+	cmd = newImportCmd()
+	cmd.ParseFlags([]string{
+		"-o", "-", "-f", "--list",
+		"-l", `"\(strings.ToLower(kind))" "\(name)"`, "--recursive",
 	})
-	runCommand(t, importCmd.RunE, "import_hoiststr")
+	runCommand(t, cmd, "import_hoiststr")
 }
diff --git a/cmd/cue/cmd/root.go b/cmd/cue/cmd/root.go
index df8b155..164ad8e 100644
--- a/cmd/cue/cmd/root.go
+++ b/cmd/cue/cmd/root.go
@@ -42,11 +42,12 @@
 
 var cfgFile string
 
-// rootCmd represents the base command when called without any subcommands
-var rootCmd = &cobra.Command{
-	Use:   "cue",
-	Short: "cue emits configuration files to user-defined commands.",
-	Long: `cue evaluates CUE files, an extension of JSON, and sends them
+// newRootCmd creates the base command when called without any subcommands
+func newRootCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "cue",
+		Short: "cue emits configuration files to user-defined commands.",
+		Long: `cue evaluates CUE files, an extension of JSON, and sends them
 to user-defined commands for processing.
 
 Commands are defined in CUE as follows:
@@ -62,11 +63,32 @@
 run 'cue help cmd' or go to cuelang.org/pkg/cmd.
 
 For more information on writing CUE configuration files see cuelang.org.`,
-	// Uncomment the following line if your bare application
-	// has an action associated with it:
-	//	Run: func(cmd *cobra.Command, args []string) { },
+		// Uncomment the following line if your bare application
+		// has an action associated with it:
+		//	Run: func(cmd *cobra.Command, args []string) { },
 
-	SilenceUsage: true,
+		SilenceUsage: true,
+	}
+
+	subCommands := []*cobra.Command{
+		newTrimCmd(),
+		newImportCmd(),
+		newEvalCmd(),
+		newGetCmd(),
+		newFmtCmd(),
+		newExportCmd(),
+		newCmdCmd(),
+		newVetCmd(),
+		newAddCmd(),
+	}
+
+	addGlobalFlags(cmd.PersistentFlags())
+
+	for _, sub := range subCommands {
+		cmd.AddCommand(sub)
+	}
+
+	return cmd
 }
 
 // Main runs the cue tool. It loads the tool flags.
@@ -87,6 +109,7 @@
 		}
 		// We use panic to escape, instead of os.Exit
 	}()
+	rootCmd := newRootCmd()
 	rootCmd.SetArgs(args)
 	if len(args) >= 1 && args[0] != "help" {
 		// TODO: for now we only allow one instance. Eventually, we can allow
@@ -102,7 +125,7 @@
 			cmd  *cobra.Command
 		}
 		sub := map[string]subSpec{
-			"cmd": {commandSection, cmdCmd},
+			"cmd": {commandSection, newCmdCmd()},
 			// "serve": {"server", nil},
 			// "fix":   {"fix", nil},
 		}
@@ -143,27 +166,8 @@
 func init() {
 	cobra.OnInitialize(initConfig)
 
-	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cue)")
-	rootCmd.PersistentFlags().Bool("root", false, "load a CUE package from its root")
 }
 
-var (
-	fDebug = rootCmd.PersistentFlags().Bool("debug", false,
-		"give detailed error info")
-	fTrace = rootCmd.PersistentFlags().Bool("trace", false,
-		"trace computation")
-	fDryrun = rootCmd.PersistentFlags().BoolP("dryrun", "n", false,
-		"only run simulation")
-	fPackage = rootCmd.PersistentFlags().StringP("package", "p", "",
-		"CUE package to evaluate")
-	fSimplify = rootCmd.PersistentFlags().BoolP("simplify", "s", false,
-		"simplify output")
-	fIgnore = rootCmd.PersistentFlags().BoolP("ignore", "i", false,
-		"proceed in the presence of errors")
-	fVerbose = rootCmd.PersistentFlags().BoolP("verbose", "v", false,
-		"print information about progress")
-)
-
 // initConfig reads in config file and ENV variables if set.
 func initConfig() {
 	if cfgFile != "" {
diff --git a/cmd/cue/cmd/testdata/trim/trim.cue b/cmd/cue/cmd/testdata/trim/trim.cue
index 9d1c203..61353fe 100644
--- a/cmd/cue/cmd/testdata/trim/trim.cue
+++ b/cmd/cue/cmd/testdata/trim/trim.cue
@@ -25,22 +25,10 @@
 
 foo bar: {
 	_value: "here"
+	b:      "foo"
+	c:      45
 
-	a: 4
-	b: "foo"
-	c: 45
-	e: string
-	f: ">> here <<"
-
-	n: int
-
-	struct: {a: 3.0}
-
-	list: ["foo", float]
-
-	sList: [{a: 8, b: "foo"}, {b: "foo"}]
-	rList: [{a: string}]
-	rcList: [{a: "a", c: "foo"}]
+	sList: [{b: "foo"}, {}]
 }
 
 foo baz: {}
@@ -53,7 +41,6 @@
 	}
 
 	t u: {
-		x: 5
 	}
 }
 
@@ -62,9 +49,6 @@
 	comp "\(k)": v for k, v in foo
 
 	comp bar: {
-		a:  4
 		aa: 8 // new value
 	}
-
-	comp baz: {} // removed: fully implied by comprehension above
 }
diff --git a/cmd/cue/cmd/trim.go b/cmd/cue/cmd/trim.go
index e6ff1ad..5d3d3dc 100644
--- a/cmd/cue/cmd/trim.go
+++ b/cmd/cue/cmd/trim.go
@@ -38,11 +38,12 @@
 // - remove the limitations mentioned in the documentation
 // - implement verification post-processing as extra safety
 
-// trimCmd represents the trim command
-var trimCmd = &cobra.Command{
-	Use:   "trim",
-	Short: "remove superfluous fields",
-	Long: `trim removes fields from structs that are already defined by a template
+// newTrimCmd creates a trim command
+func newTrimCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "trim",
+		Short: "remove superfluous fields",
+		Long: `trim removes fields from structs that are already defined by a template
 
 A field, struct, or list is removed if it is implied by a template, a list type
 value, a comprehension or any other implied content. It will modify the files
@@ -87,18 +88,13 @@
 It is guaranteed that the resulting files give the same output as before the
 removal.
 `,
-	RunE: runTrim,
-}
+		RunE: runTrim,
+	}
 
-func init() {
-	rootCmd.AddCommand(trimCmd)
-	fOut = trimCmd.Flags().StringP("out", "o", "", "alternative output or - for stdout")
+	flagOut.Add(cmd)
+	return cmd
 }
 
-var (
-	fOut *string
-)
-
 func runTrim(cmd *cobra.Command, args []string) error {
 	// TODO: Do something more fine-grained. Optional fields are mostly not
 	// useful to consider as an optional field will almost never subsume
@@ -122,8 +118,10 @@
 		}
 	}
 
-	if *fOut != "" && *fOut != "-" {
-		switch _, err := os.Stat(*fOut); {
+	// dst := flagName("o").String(cmd)
+	dst := flagOut.String(cmd)
+	if dst != "" && dst != "-" {
+		switch _, err := os.Stat(dst); {
 		case os.IsNotExist(err):
 		case err == nil:
 		default:
@@ -132,8 +130,7 @@
 	}
 
 	for i, inst := range binst {
-
-		gen := newTrimSet()
+		gen := newTrimSet(cmd)
 		for _, f := range inst.Files {
 			gen.markNodes(f)
 		}
@@ -141,7 +138,7 @@
 		root := instances[i].Lookup()
 		rm := gen.trim("root", root, cue.Value{}, root)
 
-		if *fDryrun {
+		if flagDryrun.Bool(cmd) {
 			continue
 		}
 
@@ -151,7 +148,7 @@
 			f.Decls = gen.trimDecls(f.Decls, rm, root, true)
 
 			opts := []format.Option{}
-			if *fSimplify {
+			if flagSimplify.Bool(cmd) {
 				opts = append(opts, format.Simplify())
 			}
 
@@ -161,14 +158,14 @@
 				return fmt.Errorf("error formatting file: %v", err)
 			}
 
-			if *fOut == "-" {
+			if dst == "-" {
 				_, err := io.Copy(cmd.OutOrStdout(), &buf)
 				if err != nil {
 					return err
 				}
 				continue
-			} else if *fOut != "" {
-				filename = *fOut
+			} else if dst != "" {
+				filename = dst
 			}
 
 			err = ioutil.WriteFile(filename, buf.Bytes(), 0644)
@@ -181,14 +178,16 @@
 }
 
 type trimSet struct {
+	cmd       *cobra.Command
 	stack     []string
 	exclude   map[ast.Node]bool // don't remove fields marked here
 	alwaysGen map[ast.Node]bool // node is always from a generated source
 	fromComp  map[ast.Node]bool // node originated from a comprehension
 }
 
-func newTrimSet() *trimSet {
+func newTrimSet(cmd *cobra.Command) *trimSet {
 	return &trimSet{
+		cmd:       cmd,
 		exclude:   map[ast.Node]bool{},
 		alwaysGen: map[ast.Node]bool{},
 		fromComp:  map[ast.Node]bool{},
@@ -200,7 +199,7 @@
 }
 
 func (t *trimSet) traceMsg(msg string) {
-	if *fTrace {
+	if flagTrace.Bool(t.cmd) {
 		fmt.Print(t.path())
 		msg = strings.TrimRight(msg, "\n")
 		msg = strings.Replace(msg, "\n", "\n    ", -1)
@@ -409,7 +408,7 @@
 			}
 		}
 
-		if *fTrace {
+		if flagTrace.Bool(t.cmd) {
 			w := &bytes.Buffer{}
 			fmt.Fprintln(w)
 			fmt.Fprintln(w, "value:    ", v)
@@ -491,7 +490,7 @@
 			}
 		}
 
-		if *fTrace {
+		if flagTrace.Bool(t.cmd) {
 			w := &bytes.Buffer{}
 			if len(rmSet) > 0 {
 				fmt.Fprint(w, "field: SUBSUMED\n")
diff --git a/cmd/cue/cmd/trim_test.go b/cmd/cue/cmd/trim_test.go
index 7b23082..5c5d8d0 100644
--- a/cmd/cue/cmd/trim_test.go
+++ b/cmd/cue/cmd/trim_test.go
@@ -14,9 +14,12 @@
 
 package cmd
 
-import "testing"
+import (
+	"testing"
+)
 
 func TestTrim(t *testing.T) {
-	trimCmd.ParseFlags([]string{"-o", "-"})
-	runCommand(t, trimCmd.RunE, "trim")
+	cmd := newTrimCmd()
+	cmd.ParseFlags([]string{"-o", "-"})
+	runCommand(t, cmd, "trim")
 }
diff --git a/cmd/cue/cmd/vet.go b/cmd/cue/cmd/vet.go
index 81987da..b4175df 100644
--- a/cmd/cue/cmd/vet.go
+++ b/cmd/cue/cmd/vet.go
@@ -21,29 +21,20 @@
 	"github.com/spf13/cobra"
 )
 
-// vetCmd represents the vet command
-var vetCmd = &cobra.Command{
-	Use:   "vet",
-	Short: "A brief description of your command",
-	Long: `A longer description that spans multiple lines and likely contains examples
-and usage of using your command. For example:
-
-Cobra is a CLI library for Go that empowers applications.
-This application is a tool to generate the needed files
-to quickly create a Cobra application.`,
-	RunE: doVet,
-}
-
-func init() {
-	rootCmd.AddCommand(vetCmd)
+func newVetCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "vet",
+		Short: "validate CUE configurations",
+		RunE:  doVet,
+	}
+	return cmd
 }
 
 func doVet(cmd *cobra.Command, args []string) error {
-
 	instances := buildFromArgs(cmd, args)
 
 	var exprs []ast.Expr
-	for _, e := range *expressions {
+	for _, e := range flagExpression.StringArray(cmd) {
 		expr, err := parser.ParseExpr("<expression flag>", e)
 		if err != nil {
 			return err
@@ -62,7 +53,7 @@
 			cue.Hidden(true),
 		}
 		err := inst.Value().Validate(opt...)
-		if *fVerbose || err != nil {
+		if flagVerbose.Bool(cmd) || err != nil {
 			printHeader(w, inst.Dir)
 		}
 		exitIfErr(cmd, inst, err, false)
diff --git a/go.mod b/go.mod
index 8f75590..76019c9 100644
--- a/go.mod
+++ b/go.mod
@@ -13,6 +13,7 @@
 	github.com/pkg/errors v0.8.0 // indirect
 	github.com/retr0h/go-gilt v0.0.0-20190206215556-f73826b37af2
 	github.com/spf13/cobra v0.0.3
+	github.com/spf13/pflag v1.0.3
 	github.com/spf13/viper v1.3.1
 	golang.org/x/exp/errors v0.0.0-20181221233300-b68661188fbf
 	golang.org/x/sync v0.0.0-20181108010431-42b317875d0f