Skip to content

Commit 0bd038c

Browse files
committed
cmd/cue: fix all "flag used without being added" bugs
Most commands call parseArgs, which ends up calling other methods like parseFlags and parsePlacementFlags, which always consulted flag values even when those flags did not exist for the current command. This was harmless in practice, as we would get their zero value which resulted in no change in behavior. Still, it was confusing, and using flags without declaring them should not be allowed. The panic assertion is our guide here, as all flag names are global. Teach methods like buildPlan.parseFlags to not consume undeclared flags based on what the current mode is, via fields like outMode or importing. No change in behavior should happen here; all tests continue to pass. As suggested by Matthew, rename outMode to mode as well, since the mode is not just about output files, and internal/encoding.Config calls it Mode as well. Signed-off-by: Daniel Martí <[email protected]> Change-Id: Ib4cfedaef3590e56d00b1c6aefc5cb6a75336782 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1198854 TryBot-Result: CUEcueckoo <[email protected]> Reviewed-by: Matthew Sackman <[email protected]>
1 parent 0d9d541 commit 0bd038c

File tree

6 files changed

+49
-62
lines changed

6 files changed

+49
-62
lines changed

cmd/cue/cmd/common.go

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ func (i *expressionIter) value() cue.Value {
333333
}
334334

335335
type config struct {
336-
outMode filetypes.Mode
336+
mode filetypes.Mode
337337

338338
fileFilter string
339339
reFile *regexp.Regexp
@@ -458,7 +458,7 @@ func (p *buildPlan) getDecoders(b *build.Instance) (schemas, values []*decoderIn
458458
}
459459
d := encoding.NewDecoder(p.cmd.ctx, f, &c)
460460

461-
fi, err := filetypes.FromFile(f, p.cfg.outMode)
461+
fi, err := filetypes.FromFile(f, p.cfg.mode)
462462
if err != nil {
463463
return schemas, values, err
464464
}
@@ -651,31 +651,46 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
651651
func (b *buildPlan) parseFlags() (err error) {
652652
b.mergeData = !b.cfg.noMerge && flagMerge.Bool(b.cmd)
653653

654-
out := flagOut.String(b.cmd)
655-
outFile := flagOutFile.String(b.cmd)
656-
657-
if strings.Contains(out, ":") && strings.Contains(outFile, ":") {
658-
return errors.Newf(token.NoPos,
659-
"cannot specify qualifier in both --out and --outfile")
660-
}
661-
if outFile == "" {
662-
outFile = "-"
663-
}
664-
if out != "" {
665-
outFile = out + ":" + outFile
666-
}
667-
b.outFile, err = filetypes.ParseFile(outFile, b.cfg.outMode)
668-
if err != nil {
669-
return err
654+
b.encConfig = &encoding.Config{
655+
Mode: b.cfg.mode,
656+
Stdin: b.cmd.InOrStdin(),
657+
Stdout: b.cmd.OutOrStdout(),
658+
ProtoPath: flagProtoPath.StringArray(b.cmd),
659+
AllErrors: flagAllErrors.Bool(b.cmd),
660+
PkgName: flagPackage.String(b.cmd),
661+
Strict: flagStrict.Bool(b.cmd),
670662
}
671663

672-
for _, e := range flagExpression.StringArray(b.cmd) {
673-
expr, err := parser.ParseExpr("--expression", e)
664+
// For commands with an output mode, like `cue export` or `cue def`.
665+
if b.cfg.mode != filetypes.Input {
666+
out := flagOut.String(b.cmd)
667+
outFile := flagOutFile.String(b.cmd)
668+
669+
if strings.Contains(out, ":") && strings.Contains(outFile, ":") {
670+
return errors.Newf(token.NoPos,
671+
"cannot specify qualifier in both --out and --outfile")
672+
}
673+
if outFile == "" {
674+
outFile = "-"
675+
}
676+
if out != "" {
677+
outFile = out + ":" + outFile
678+
}
679+
b.outFile, err = filetypes.ParseFile(outFile, b.cfg.mode)
674680
if err != nil {
675681
return err
676682
}
677-
b.expressions = append(b.expressions, expr)
683+
684+
for _, e := range flagExpression.StringArray(b.cmd) {
685+
expr, err := parser.ParseExpr("--expression", e)
686+
if err != nil {
687+
return err
688+
}
689+
b.expressions = append(b.expressions, expr)
690+
}
691+
b.encConfig.Force = flagForce.Bool(b.cmd)
678692
}
693+
679694
if s := flagSchema.String(b.cmd); s != "" {
680695
b.schema, err = parser.ParseExpr("--schema", s)
681696
if err != nil {
@@ -686,17 +701,12 @@ func (b *buildPlan) parseFlags() (err error) {
686701
// Set a default file filter to only include json and yaml files
687702
b.cfg.fileFilter = s
688703
}
689-
b.encConfig = &encoding.Config{
690-
Force: flagForce.Bool(b.cmd),
691-
Mode: b.cfg.outMode,
692-
Stdin: b.cmd.InOrStdin(),
693-
Stdout: b.cmd.OutOrStdout(),
694-
ProtoPath: flagProtoPath.StringArray(b.cmd),
695-
AllErrors: flagAllErrors.Bool(b.cmd),
696-
PkgName: flagPackage.String(b.cmd),
697-
Strict: flagStrict.Bool(b.cmd),
698-
InlineImports: flagInlineImports.Bool(b.cmd),
699-
EscapeHTML: flagEscape.Bool(b.cmd),
704+
// These flags exist only in specific output modes.
705+
switch b.cfg.mode {
706+
case filetypes.Export:
707+
b.encConfig.EscapeHTML = flagEscape.Bool(b.cmd)
708+
case filetypes.Def:
709+
b.encConfig.InlineImports = flagInlineImports.Bool(b.cmd)
700710
}
701711
return nil
702712
}

cmd/cue/cmd/def.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ The --expression flag is used to only print parts of a configuration.
5252
}
5353

5454
func runDef(cmd *Command, args []string) error {
55-
b, err := parseArgs(cmd, args, &config{outMode: filetypes.Def})
55+
b, err := parseArgs(cmd, args, &config{mode: filetypes.Def})
5656
if err != nil {
5757
return err
5858
}

cmd/cue/cmd/eval.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const (
8585
)
8686

8787
func runEval(cmd *Command, args []string) error {
88-
b, err := parseArgs(cmd, args, &config{outMode: filetypes.Eval})
88+
b, err := parseArgs(cmd, args, &config{mode: filetypes.Eval})
8989
if err != nil {
9090
return err
9191
}

cmd/cue/cmd/export.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ The following formats are recognized:
110110
}
111111

112112
func runExport(cmd *Command, args []string) error {
113-
b, err := parseArgs(cmd, args, &config{outMode: filetypes.Export})
113+
b, err := parseArgs(cmd, args, &config{mode: filetypes.Export})
114114
if err != nil {
115115
return err
116116
}

cmd/cue/cmd/flags.go

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -121,38 +121,12 @@ type unaddedFlagUse struct {
121121
flag flagName
122122
}
123123

124-
// TODO(ms) consider each of these in turn and either remove their
125-
// use, or add the flag to the flagset.
126-
var todoUnaddedFlagUse = map[unaddedFlagUse]struct{}{
127-
{cmd: "def", flag: flagEscape}: {},
128-
{cmd: "def", flag: flagFiles}: {},
129-
{cmd: "eval", flag: flagEscape}: {},
130-
{cmd: "eval", flag: flagFiles}: {},
131-
{cmd: "eval", flag: flagInlineImports}: {},
132-
{cmd: "export", flag: flagFiles}: {},
133-
{cmd: "export", flag: flagInlineImports}: {},
134-
{cmd: "import", flag: flagEscape}: {},
135-
{cmd: "import", flag: flagExpression}: {},
136-
{cmd: "import", flag: flagInlineImports}: {},
137-
{cmd: "import", flag: flagOut}: {},
138-
{cmd: "vet", flag: flagEscape}: {},
139-
{cmd: "vet", flag: flagExpression}: {},
140-
{cmd: "vet", flag: flagFiles}: {},
141-
{cmd: "vet", flag: flagForce}: {},
142-
{cmd: "vet", flag: flagInlineImports}: {},
143-
{cmd: "vet", flag: flagOut}: {},
144-
{cmd: "vet", flag: flagOutFile}: {},
145-
}
146-
147124
// ensureAdded detects if a flag is being used without it first being
148125
// added to the flagSet. Because flagNames are global, it is quite
149126
// easy to accidentally use a flag in a command without adding it to
150127
// the flagSet.
151128
func (f flagName) ensureAdded(cmd *Command) {
152129
if cmd.Flags().Lookup(string(f)) == nil {
153-
if _, found := todoUnaddedFlagUse[unaddedFlagUse{cmd.Name(), f}]; found {
154-
return
155-
}
156130
panic(fmt.Sprintf("Cmd %q uses flag %q without adding it", cmd.Name(), f))
157131
}
158132
}

cmd/cue/cmd/orphans.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ func (b *buildPlan) usePlacement() bool {
4040

4141
func (b *buildPlan) parsePlacementFlags() error {
4242
cmd := b.cmd
43-
b.perFile = flagFiles.Bool(cmd)
43+
// Flags which only exist for `cue import`.
44+
if b.importing {
45+
b.perFile = flagFiles.Bool(cmd)
46+
}
4447
b.useList = flagList.Bool(cmd)
4548
b.useContext = flagWithContext.Bool(cmd)
4649

0 commit comments

Comments
 (0)