Skip to content

Commit 75d0180

Browse files
committed
cmd/cue/cmd: simplify parseArgs in preparation of proto support
The parseArgs code had some pretty complicated logic. This now separates out the cases for normal instances and user-selected files to avoid at least one level of comingling. The goal of this refactoring is to ultimately allow schema and value files to be separated early on, which, in turn, will allow schema values to be computed early. Such schema will then allow value formats to be interpreted by the type of which they will ultimately land in CUE. This is necessary to parse protobuf, which cannot be parsed without a schema. Issue #5 Change-Id: I2046948a8cf9bc5425ed437247dc89416d0fff76 Reviewed-on: https://cue-review.googlesource.com/c/cue/+/9304 Reviewed-by: Marcel van Lohuizen <[email protected]> Reviewed-by: CUE cueckoo <[email protected]>
1 parent dea3c5d commit 75d0180

File tree

2 files changed

+65
-51
lines changed

2 files changed

+65
-51
lines changed

cmd/cue/cmd/common.go

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,12 @@ type buildPlan struct {
139139
expressions []ast.Expr // only evaluate these expressions within results
140140
schema ast.Expr // selects schema in instance for orphaned values
141141

142+
// orphan placement flags.
143+
perFile bool
144+
useList bool
145+
path []string
146+
useContext bool
147+
142148
// outFile defines the file to output to. Default is CUE stdout.
143149
outFile *build.File
144150

@@ -388,41 +394,41 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
388394
return nil, errors.Newf(token.NoPos, "invalid args")
389395
}
390396

397+
if err := p.parsePlacementFlags(); err != nil {
398+
return nil, err
399+
}
400+
391401
for _, b := range builds {
392402
if b.Err != nil {
393403
return nil, b.Err
394404
}
395-
var ok bool
396-
if b.User || p.importing {
397-
ok, err = p.placeOrphans(b)
398-
if err != nil {
399-
return nil, err
405+
switch {
406+
case !b.User:
407+
if p.importing {
408+
if err = p.placeOrphans(b); err != nil {
409+
return nil, err
410+
}
400411
}
401-
}
402-
if !b.User {
403412
p.insts = append(p.insts, b)
404-
continue
405-
}
406-
addedUser := false
407-
if len(b.BuildFiles) > 0 {
408-
addedUser = true
409-
p.insts = append(p.insts, b)
410-
}
411-
if ok {
412-
continue
413-
}
414-
415-
if len(b.OrphanedFiles) == 0 {
416-
continue
417-
}
418413

419-
if p.orphanInstance != nil {
414+
case p.orphanInstance != nil:
420415
return nil, errors.Newf(token.NoPos,
421416
"builds contain two file packages")
417+
418+
default:
419+
p.orphanInstance = b
422420
}
423-
p.orphanInstance = b
424-
p.encConfig.Stream = true
421+
}
425422

423+
switch b := p.orphanInstance; {
424+
case b == nil:
425+
case p.usePlacement() || p.importing:
426+
p.insts = append(p.insts, b)
427+
if err = p.placeOrphans(b); err != nil {
428+
return nil, err
429+
}
430+
431+
default:
426432
for _, f := range b.OrphanedFiles {
427433
switch f.Encoding {
428434
case build.Protobuf, build.YAML, build.JSON, build.Text:
@@ -466,7 +472,7 @@ func parseArgs(cmd *Command, args []string, cfg *config) (p *buildPlan, err erro
466472
}
467473
}
468474

469-
if !addedUser && len(b.Files) > 0 {
475+
if len(b.Files) > 0 {
470476
p.insts = append(p.insts, b)
471477
} else if len(p.orphaned) == 0 {
472478
// Instance with only a single build: just print the file.

cmd/cue/cmd/orphans.go

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,32 +33,40 @@ import (
3333

3434
// This file contains logic for placing orphan files within a CUE namespace.
3535

36-
func (b *buildPlan) placeOrphans(i *build.Instance) (ok bool, err error) {
37-
var (
38-
perFile = flagFiles.Bool(b.cmd)
39-
useList = flagList.Bool(b.cmd)
40-
path = flagPath.StringArray(b.cmd)
41-
useContext = flagWithContext.Bool(b.cmd)
42-
)
43-
if !b.importing && !perFile && !useList && len(path) == 0 {
44-
if useContext {
45-
return false, fmt.Errorf(
36+
func (b *buildPlan) usePlacement() bool {
37+
return b.perFile || b.useList || len(b.path) > 0
38+
}
39+
40+
func (b *buildPlan) parsePlacementFlags() error {
41+
cmd := b.cmd
42+
b.perFile = flagFiles.Bool(cmd)
43+
b.useList = flagList.Bool(cmd)
44+
b.path = flagPath.StringArray(cmd)
45+
b.useContext = flagWithContext.Bool(cmd)
46+
47+
if !b.importing && !b.perFile && !b.useList && len(b.path) == 0 {
48+
if b.useContext {
49+
return fmt.Errorf(
4650
"flag %q must be used with at least one of flag %q, %q, or %q",
4751
flagWithContext, flagPath, flagList, flagFiles,
4852
)
4953
}
50-
// TODO: should we remove this optimization? This is really added as a
51-
// conversion safety.
52-
if len(i.OrphanedFiles)+len(i.BuildFiles) <= 1 || b.cfg.noMerge {
53-
return false, err
54-
}
54+
} else if b.schema != nil {
55+
return fmt.Errorf(
56+
"cannot combine --%s flag with flag %q, %q, or %q",
57+
flagSchema, flagPath, flagList, flagFiles,
58+
)
5559
}
60+
return nil
61+
}
62+
63+
func (b *buildPlan) placeOrphans(i *build.Instance) error {
5664

5765
pkg := b.encConfig.PkgName
5866
if pkg == "" {
5967
pkg = i.PkgName
6068
} else if pkg != "" && i.PkgName != "" && i.PkgName != pkg && !flagForce.Bool(b.cmd) {
61-
return false, fmt.Errorf(
69+
return fmt.Errorf(
6270
"%q flag clashes with existing package name (%s vs %s)",
6371
flagPackage, pkg, i.PkgName,
6472
)
@@ -68,7 +76,7 @@ func (b *buildPlan) placeOrphans(i *build.Instance) (ok bool, err error) {
6876

6977
re, err := regexp.Compile(b.cfg.fileFilter)
7078
if err != nil {
71-
return false, err
79+
return err
7280
}
7381

7482
for _, f := range i.OrphanedFiles {
@@ -95,14 +103,14 @@ func (b *buildPlan) placeOrphans(i *build.Instance) (ok bool, err error) {
95103
}
96104
}
97105
if err := d.Err(); err != nil {
98-
return false, err
106+
return err
99107
}
100108

101-
if perFile {
109+
if b.perFile {
102110
for i, obj := range objs {
103111
f, err := placeOrphans(b.cmd, d.Filename(), pkg, obj)
104112
if err != nil {
105-
return false, err
113+
return err
106114
}
107115
f.Filename = newName(d.Filename(), i)
108116
files = append(files, f)
@@ -112,13 +120,13 @@ func (b *buildPlan) placeOrphans(i *build.Instance) (ok bool, err error) {
112120
// TODO: consider getting rid of this requirement. It is important that
113121
// import will catch conflicts ahead of time then, though, and report
114122
// this messages as a possible solution if there are conflicts.
115-
if b.importing && len(objs) > 1 && len(path) == 0 && !useList {
116-
return false, fmt.Errorf(
123+
if b.importing && len(objs) > 1 && len(b.path) == 0 && !b.useList {
124+
return fmt.Errorf(
117125
"%s, %s, or %s flag needed to handle multiple objects in file %s",
118126
flagPath, flagList, flagFiles, shortFile(i.Root, f))
119127
}
120128

121-
if !useList && len(path) == 0 && !useContext {
129+
if !b.useList && len(b.path) == 0 && !b.useContext {
122130
for _, f := range objs {
123131
if pkg := c.PkgName; pkg != "" {
124132
internal.SetPackage(f, pkg, false)
@@ -129,7 +137,7 @@ func (b *buildPlan) placeOrphans(i *build.Instance) (ok bool, err error) {
129137
// TODO: handle imports correctly, i.e. for proto.
130138
f, err := placeOrphans(b.cmd, d.Filename(), pkg, objs...)
131139
if err != nil {
132-
return false, err
140+
return err
133141
}
134142
f.Filename = newName(d.Filename(), 0)
135143
files = append(files, f)
@@ -139,15 +147,15 @@ func (b *buildPlan) placeOrphans(i *build.Instance) (ok bool, err error) {
139147
b.imported = append(b.imported, files...)
140148
for _, f := range files {
141149
if err := i.AddSyntax(f); err != nil {
142-
return false, err
150+
return err
143151
}
144152
i.BuildFiles = append(i.BuildFiles, &build.File{
145153
Filename: f.Filename,
146154
Encoding: build.CUE,
147155
Source: f,
148156
})
149157
}
150-
return true, nil
158+
return nil
151159
}
152160

153161
func placeOrphans(cmd *Command, filename, pkg string, objs ...*ast.File) (*ast.File, error) {

0 commit comments

Comments
 (0)