Skip to content

Commit

Permalink
cmd/cue/cmd: add fix command for new-style definitions
Browse files Browse the repository at this point in the history
This adds a new fix command. As converting configurations to
new-style defintions can no longer be done syntactically and is
not guaranteed to succeed, this could no longer be piggybacked
on fmt.

This changes adds the implementation of converting new-style
definitions. The conversion is not complete. Firstly, not all
old configurations can be converted to new-style definitions.
The converter detects this and suggests changes to the user.

Also, due to API limitations, not all convertable cases are
handled by the converter. These cases are also detected and
reported.

Change-Id: I88c4010b15ea07250dc456fd84b2603b473ae5c1
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6067
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
  • Loading branch information
mpvl committed May 19, 2020
1 parent f395f12 commit a846fcc
Show file tree
Hide file tree
Showing 19 changed files with 1,279 additions and 4 deletions.
105 changes: 105 additions & 0 deletions cmd/cue/cmd/fix.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,120 @@ package cmd

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"

"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/ast/astutil"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/load"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"cuelang.org/go/internal"
"github.com/spf13/cobra"
)

func newFixCmd(c *Command) *cobra.Command {
cmd := &cobra.Command{
Use: "fix [packages]",
Short: "rewrite packages to latest standards",
Long: `Fix finds CUE programs that use old syntax and old APIs and rewrites them to use newer ones.
After you update to a new CUE release, fix helps make the necessary changes
to your program.
Without any packages, fix applies to all files within a module.
`,
RunE: mkRunE(c, runFixAll),
}

cmd.Flags().BoolP(string(flagForce), "f", false,
"rewrite even when there are errors")

return cmd
}

func runFixAll(cmd *Command, args []string) error {
dir, err := os.Getwd()
if err != nil {
return err
}

if len(args) == 0 {
args = []string{"./..."}

for {
if fi, err := os.Stat(filepath.Join(dir, "cue.mod")); err == nil {
if fi.IsDir() {
args = appendDirs(args, filepath.Join(dir, "cue.mod", "gen"))
args = appendDirs(args, filepath.Join(dir, "cue.mod", "pkg"))
args = appendDirs(args, filepath.Join(dir, "cue.mod", "usr"))
} else {
args = appendDirs(args, filepath.Join(dir, "pkg"))
}
break
}

dir = filepath.Dir(dir)
if info, _ := os.Stat(dir); !info.IsDir() {
return errors.Newf(token.NoPos, "no module root found")
}
}
}

instances := load.Instances(args, &load.Config{})

for _, i := range instances {
if i.Err != nil {
return i.Err
}
}

errs := fixAll(instances)

if errs != nil && flagForce.Bool(cmd) {
return errs
}

done := map[*ast.File]bool{}

for _, i := range instances {
for _, f := range i.Files {
if done[f] || !strings.HasSuffix(f.Filename, ".cue") {
continue
}
done[f] = true

b, err := format.Node(f)
if err != nil {
errs = errors.Append(errs, errors.Promote(err, "format"))
}

err = ioutil.WriteFile(f.Filename, b, 0644)
if err != nil {
errs = errors.Append(errs, errors.Promote(err, "write"))
}
}
}

return errs
}

func appendDirs(a []string, base string) []string {
_ = filepath.Walk(base, func(path string, fi os.FileInfo, err error) error {
if err == nil && fi.IsDir() && path != base {
short := filepath.ToSlash(path[len(base)+1:])
if strings.ContainsAny(short, "/") {
a = append(a, short)
}
}
return nil
})
return a
}

func fix(f *ast.File) *ast.File {
// Isolate bulk optional fields into a single struct.
ast.Walk(f, func(n ast.Node) bool {
Expand Down

0 comments on commit a846fcc

Please sign in to comment.