this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cmd/cue: add mod edit command

This command allows some automatic editing of the module.cue file.
The design is patterned after the `go mod edit` command.

For #3017.

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: Ia46be7fa6cdfd84aff131f2196e052268cdc3b03
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1193116
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>

+252
+1
cmd/cue/cmd/mod.go
··· 52 52 }), 53 53 } 54 54 55 + cmd.AddCommand(newModEditCmd(c)) 55 56 cmd.AddCommand(newModGetCmd(c)) 56 57 cmd.AddCommand(newModInitCmd(c)) 57 58 cmd.AddCommand(newModRegistryCmd(c))
+210
cmd/cue/cmd/modedit.go
··· 1 + // Copyright 2024 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 + 15 + package cmd 16 + 17 + import ( 18 + "bytes" 19 + "fmt" 20 + "os" 21 + "path/filepath" 22 + "strconv" 23 + 24 + "cuelang.org/go/mod/modfile" 25 + "cuelang.org/go/mod/module" 26 + "github.com/spf13/cobra" 27 + "github.com/spf13/pflag" 28 + ) 29 + 30 + func newModEditCmd(c *Command) *cobra.Command { 31 + editCmd := &modEditCmd{} 32 + cmd := &cobra.Command{ 33 + Use: "edit", 34 + Short: "edit cue.mod/module.cue", 35 + Long: `WARNING: THIS COMMAND IS EXPERIMENTAL. 36 + 37 + Edit provides a command-line interface for editing cue.mod/module.cue. 38 + It reads only that file; it does not look up information about the modules 39 + involved. 40 + 41 + The editing flags specify a sequence of editing operations. 42 + 43 + The -require=path@version and -drop-require=path@majorversion flags add 44 + and drop a requirement on the given module path and version. Note that 45 + -require overrides any existing requirements on path. These flags are 46 + mainly for tools that understand the module graph. Users should prefer 47 + 'cue get path@version' which makes other go.mod adjustments as needed 48 + to satisfy constraints imposed by other modules. 49 + 50 + The --module flag changes the module's path (the module.cue file's module field). 51 + The --source flag changes the module's declared source. 52 + The --drop-source flag removes the source field. 53 + 54 + Note: you must enable the modules experiment with: 55 + export CUE_EXPERIMENT=modules 56 + for this command to work. 57 + `, 58 + RunE: mkRunE(c, editCmd.run), 59 + Args: cobra.ExactArgs(0), 60 + } 61 + addFlagVar(cmd, flagFunc(editCmd.flagSource), "source", "set the source field") 62 + addFlagVar(cmd, boolFlagFunc(editCmd.flagDropSource), "drop-source", "remove the source field") 63 + addFlagVar(cmd, flagFunc(editCmd.flagModule), "module", "set the module path") 64 + addFlagVar(cmd, flagFunc(editCmd.flagRequire), "require", "add a required module@version") 65 + addFlagVar(cmd, flagFunc(editCmd.flagDropRequire), "drop-require", "remove a requirement") 66 + 67 + return cmd 68 + } 69 + 70 + type modEditCmd struct { 71 + edits []func(*modfile.File) error 72 + } 73 + 74 + func (c *modEditCmd) run(cmd *Command, args []string) error { 75 + modRoot, err := findModuleRoot() 76 + if err != nil { 77 + return err 78 + } 79 + modPath := filepath.Join(modRoot, "cue.mod", "module.cue") 80 + data, err := os.ReadFile(modPath) 81 + if err != nil { 82 + return err 83 + } 84 + mf, err := modfile.Parse(data, modPath) 85 + if err != nil { 86 + return err 87 + } 88 + for _, edit := range c.edits { 89 + if err := edit(mf); err != nil { 90 + return err 91 + } 92 + } 93 + newData, err := mf.Format() 94 + if err != nil { 95 + return fmt.Errorf("internal error: invalid module.cue file generated: %v", err) 96 + } 97 + if bytes.Equal(newData, data) { 98 + return nil 99 + } 100 + if err := os.WriteFile(modPath, newData, 0o666); err != nil { 101 + return err 102 + } 103 + return nil 104 + } 105 + 106 + func (c *modEditCmd) addEdit(f func(*modfile.File) error) { 107 + c.edits = append(c.edits, f) 108 + } 109 + 110 + func (c *modEditCmd) flagSource(arg string) error { 111 + if arg != "git" && arg != "none" { 112 + return fmt.Errorf("unrecognized source kind %q", arg) 113 + } 114 + c.addEdit(func(f *modfile.File) error { 115 + if f.Source == nil { 116 + f.Source = &modfile.Source{} 117 + } 118 + f.Source.Kind = arg 119 + return nil 120 + }) 121 + return nil 122 + } 123 + 124 + func (c *modEditCmd) flagDropSource(arg bool) error { 125 + if !arg { 126 + return fmt.Errorf("cannot set --drop-source to false") 127 + } 128 + c.addEdit(func(f *modfile.File) error { 129 + f.Source = nil 130 + return nil 131 + }) 132 + return nil 133 + } 134 + 135 + func (c *modEditCmd) flagModule(arg string) error { 136 + if err := module.CheckPath(arg); err != nil { 137 + return err 138 + } 139 + c.addEdit(func(f *modfile.File) error { 140 + f.Module = arg 141 + return nil 142 + }) 143 + return nil 144 + } 145 + 146 + func (c *modEditCmd) flagRequire(arg string) error { 147 + v, err := module.ParseVersion(arg) 148 + if err != nil { 149 + return err 150 + } 151 + c.addEdit(func(f *modfile.File) error { 152 + if f.Deps == nil { 153 + f.Deps = make(map[string]*modfile.Dep) 154 + } 155 + vm := v.Path() 156 + dep := f.Deps[vm] 157 + if dep == nil { 158 + dep = &modfile.Dep{} 159 + f.Deps[vm] = dep 160 + } 161 + dep.Version = v.Version() 162 + return nil 163 + }) 164 + return nil 165 + } 166 + 167 + func (c *modEditCmd) flagDropRequire(arg string) error { 168 + if err := module.CheckPath(arg); err != nil { 169 + return err 170 + } 171 + // TODO allow dropping a requirement without specifying 172 + // the major version - we can use the default field to disambiguate. 173 + c.addEdit(func(f *modfile.File) error { 174 + delete(f.Deps, arg) 175 + return nil 176 + }) 177 + return nil 178 + } 179 + 180 + func addFlagVar(cmd *cobra.Command, v pflag.Value, name string, usage string) { 181 + flags := cmd.Flags() 182 + flags.Var(v, name, usage) 183 + // This works around https://github.com/spf13/pflag/issues/281 184 + if v, ok := v.(interface{ IsBoolFlag() bool }); ok && v.IsBoolFlag() { 185 + flags.Lookup(name).NoOptDefVal = "true" 186 + } 187 + } 188 + 189 + type flagFunc func(string) error 190 + 191 + func (f flagFunc) String() string { return "" } 192 + func (f flagFunc) Set(s string) error { return f(s) } 193 + func (f flagFunc) Type() string { 194 + return "string" 195 + } 196 + 197 + type boolFlagFunc func(bool) error 198 + 199 + func (f boolFlagFunc) String() string { return "" } 200 + func (f boolFlagFunc) Set(s string) error { 201 + b, err := strconv.ParseBool(s) 202 + if err != nil { 203 + return err 204 + } 205 + return f(b) 206 + } 207 + func (f boolFlagFunc) Type() string { 208 + return "bool" 209 + } 210 + func (f boolFlagFunc) IsBoolFlag() bool { return true }
+41
cmd/cue/cmd/testdata/script/modedit_initial.txtar
··· 1 + exec cue mod edit --source git 2 + cmp cue.mod/module.cue want-module-1 3 + 4 + exec cue mod edit --drop-source 5 + cmp cue.mod/module.cue want-module-2 6 + 7 + exec cue mod edit --require foo.bar@v0.2.3 8 + cmp cue.mod/module.cue want-module-3 9 + 10 + ! exec cue mod edit --require bad-module! 11 + cmp stderr want-stderr 12 + 13 + exec cue mod edit --drop-require foo.bar@v0 14 + cmp cue.mod/module.cue want-module-4 15 + 16 + exec cue mod edit --module othermain.org@v1 17 + cmp cue.mod/module.cue want-module-5 18 + 19 + 20 + -- cue.mod/module.cue -- 21 + module: "main.org@v0" 22 + -- want-module-1 -- 23 + module: "main.org@v0" 24 + source: { 25 + kind: "git" 26 + } 27 + -- want-module-2 -- 28 + module: "main.org@v0" 29 + -- want-module-3 -- 30 + module: "main.org@v0" 31 + deps: { 32 + "foo.bar@v0": { 33 + v: "v0.2.3" 34 + } 35 + } 36 + -- want-stderr -- 37 + invalid argument "bad-module!" for "--require" flag: invalid module path@version "bad-module!" 38 + -- want-module-4 -- 39 + module: "main.org@v0" 40 + -- want-module-5 -- 41 + module: "othermain.org@v1"