1// Copyright 2018 The CUE Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package cmd
16
17import (
18	"github.com/spf13/cobra"
19
20	"cuelang.org/go/cue/ast"
21	"cuelang.org/go/cue/build"
22	"cuelang.org/go/cue/errors"
23	"cuelang.org/go/cue/format"
24	"cuelang.org/go/cue/load"
25	"cuelang.org/go/cue/token"
26	"cuelang.org/go/internal/encoding"
27	"cuelang.org/go/tools/fix"
28)
29
30func newFmtCmd(c *Command) *cobra.Command {
31	cmd := &cobra.Command{
32		Use:   "fmt [-s] [inputs]",
33		Short: "formats CUE configuration files",
34		Long: `Fmt formats the given files or the files for the given packages in place
35`,
36		RunE: mkRunE(c, func(cmd *Command, args []string) error {
37			plan, err := newBuildPlan(cmd, args, &config{loadCfg: &load.Config{
38				Tests:       true,
39				Tools:       true,
40				AllCUEFiles: true,
41				Package:     "*",
42			}})
43			exitOnErr(cmd, err, true)
44
45			builds := loadFromArgs(cmd, args, plan.cfg.loadCfg)
46			if builds == nil {
47				exitOnErr(cmd, errors.Newf(token.NoPos, "invalid args"), true)
48			}
49
50			opts := []format.Option{}
51			if flagSimplify.Bool(cmd) {
52				opts = append(opts, format.Simplify())
53			}
54
55			cfg := *plan.encConfig
56			cfg.Format = opts
57			cfg.Force = true
58
59			for _, inst := range builds {
60				if inst.Err != nil {
61					var p *load.PackageError
62					switch {
63					case errors.As(inst.Err, &p):
64					default:
65						exitOnErr(cmd, inst.Err, false)
66						continue
67					}
68				}
69				for _, file := range inst.BuildFiles {
70					files := []*ast.File{}
71					d := encoding.NewDecoder(file, &cfg)
72					defer d.Close()
73					for ; !d.Done(); d.Next() {
74						f := d.File()
75
76						if file.Encoding == build.CUE {
77							f = fix.File(f)
78						}
79
80						files = append(files, f)
81					}
82
83					e, err := encoding.NewEncoder(file, &cfg)
84					exitOnErr(cmd, err, true)
85
86					for _, f := range files {
87						err := e.EncodeFile(f)
88						exitOnErr(cmd, err, false)
89					}
90					e.Close()
91				}
92			}
93			return nil
94		}),
95	}
96	return cmd
97}
98