github.com/btwiuse/jiri@v0.0.0-20191125065820-53353bcfef54/cmd/jiri/override.go (about) 1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "encoding/json" 9 "fmt" 10 "os" 11 "strings" 12 13 "github.com/btwiuse/jiri" 14 "github.com/btwiuse/jiri/cmdline" 15 "github.com/btwiuse/jiri/project" 16 ) 17 18 var overrideFlags struct { 19 // Flags configuring project attributes for overrides. 20 importManifest string 21 gerritHost string 22 path string 23 revision string 24 // Flags controlling the behavior of the command. 25 delete bool 26 list bool 27 JSONOutput string 28 } 29 30 func init() { 31 cmdOverride.Flags.StringVar(&overrideFlags.importManifest, "import-manifest", "", "The manifest of the import override.") 32 33 cmdOverride.Flags.StringVar(&overrideFlags.path, "path", "", `Path used to store the project locally.`) 34 cmdOverride.Flags.StringVar(&overrideFlags.revision, "revision", "", `Revision to check out for the remote (defaults to HEAD).`) 35 cmdOverride.Flags.StringVar(&overrideFlags.gerritHost, "gerrithost", "", `The project Gerrit host.`) 36 37 cmdOverride.Flags.BoolVar(&overrideFlags.delete, "delete", false, `Delete existing override. Override is matched using <name> and <remote>, <remote> is optional.`) 38 cmdOverride.Flags.BoolVar(&overrideFlags.list, "list", false, `List all the overrides from .jiri_manifest. This flag doesn't accept any arguments. -json-out flag can be used to specify json output file.`) 39 cmdOverride.Flags.StringVar(&overrideFlags.JSONOutput, "json-output", "", `JSON output file from -list flag.`) 40 } 41 42 var cmdOverride = &cmdline.Command{ 43 Runner: jiri.RunnerFunc(runOverride), 44 Name: "override", 45 Short: "Add overrides to .jiri_manifest file", 46 Long: `Add overrides to the .jiri_manifest file. This allows overriding project 47 definitions, including from transitively imported manifests. 48 49 Example: 50 $ jiri override project https://foo.com/bar.git 51 52 Run "jiri help manifest" for details on manifests. 53 `, 54 ArgsName: "<name> <remote>", 55 ArgsLong: ` 56 <name> is the project name. 57 58 <remote> is the project remote. 59 `, 60 } 61 62 type overrideInfo struct { 63 Import bool `json:"import,omitempty"` 64 ImportManifest string `json:"import-manifest,omitempty"` 65 Name string `json:"name"` 66 Path string `json:"path,omitempty"` 67 Remote string `json:"remote"` 68 Revision string `json:"revision,omitempty"` 69 GerritHost string `json:"gerrithost,omitempty"` 70 } 71 72 func runOverride(jirix *jiri.X, args []string) error { 73 if overrideFlags.delete && overrideFlags.list { 74 return jirix.UsageErrorf("cannot use -delete and -list together") 75 } 76 77 if overrideFlags.list && len(args) != 0 { 78 return jirix.UsageErrorf("wrong number of arguments for the list flag") 79 } else if overrideFlags.delete && len(args) != 1 && len(args) != 2 { 80 return jirix.UsageErrorf("wrong number of arguments for the delete flag") 81 } else if !overrideFlags.delete && !overrideFlags.list && len(args) != 2 { 82 return jirix.UsageErrorf("wrong number of arguments") 83 } 84 85 // Initialize manifest. 86 manifestExists, err := isFile(jirix.JiriManifestFile()) 87 if err != nil { 88 return err 89 } 90 if !manifestExists { 91 return fmt.Errorf("'%s' does not exist", jirix.JiriManifestFile()) 92 } 93 manifest, err := project.ManifestFromFile(jirix, jirix.JiriManifestFile()) 94 if err != nil { 95 return err 96 } 97 98 if overrideFlags.list { 99 overrides := make([]overrideInfo, 0) 100 for _, p := range manifest.ProjectOverrides { 101 overrides = append(overrides, overrideInfo{ 102 Name: p.Name, 103 Path: p.Path, 104 Remote: p.Remote, 105 Revision: p.Revision, 106 GerritHost: p.GerritHost, 107 }) 108 } 109 110 for _, p := range manifest.ImportOverrides { 111 overrides = append(overrides, overrideInfo{ 112 Import: true, 113 ImportManifest: p.Manifest, 114 Name: p.Name, 115 Remote: p.Remote, 116 Revision: p.Revision, 117 }) 118 } 119 120 if overrideFlags.JSONOutput == "" { 121 for _, o := range overrides { 122 fmt.Printf("* override %s\n", o.Name) 123 if o.Import { 124 fmt.Printf(" IsImport: %v\n", o.Import) 125 fmt.Printf(" ImportManifest: %s\n", o.ImportManifest) 126 } 127 fmt.Printf(" Name: %s\n", o.Name) 128 fmt.Printf(" Remote: %s\n", o.Remote) 129 if o.Path != "" { 130 fmt.Printf(" Path: %s\n", o.Path) 131 } 132 if o.Remote != "" { 133 fmt.Printf(" Revision: %s\n", o.Revision) 134 } 135 if o.GerritHost != "" { 136 fmt.Printf(" Gerrit Host: %s\n", o.GerritHost) 137 } 138 } 139 } else { 140 file, err := os.Create(overrideFlags.JSONOutput) 141 if err != nil { 142 return fmt.Errorf("failed to create output JSON file: %v\n", err) 143 } 144 defer file.Close() 145 encoder := json.NewEncoder(file) 146 encoder.SetIndent("", " ") 147 if err := encoder.Encode(overrides); err != nil { 148 return fmt.Errorf("failed to serialize JSON output: %v\n", err) 149 } 150 } 151 return nil 152 } 153 154 name := args[0] 155 if overrideFlags.delete { 156 var projectOverrides []project.Project 157 var importOverrides []project.Import 158 var deletedProjectOverrides []project.Project 159 var deletedImportOverrides []project.Import 160 for _, p := range manifest.ImportOverrides { 161 if overrideFlags.importManifest == "" || (len(args) == 2 && p.Remote != args[1]) || p.Name != name { 162 importOverrides = append(importOverrides, p) 163 continue 164 } 165 deletedImportOverrides = append(deletedImportOverrides, p) 166 } 167 168 for _, p := range manifest.ProjectOverrides { 169 if overrideFlags.importManifest != "" || (len(args) == 2 && p.Remote != args[1]) || p.Name != name { 170 projectOverrides = append(projectOverrides, p) 171 continue 172 } 173 deletedProjectOverrides = append(deletedProjectOverrides, p) 174 } 175 176 if len(deletedProjectOverrides)+len(deletedImportOverrides) > 1 { 177 return fmt.Errorf("more than one override matches") 178 } 179 var names []string 180 for _, p := range deletedProjectOverrides { 181 names = append(names, p.Name) 182 } 183 for _, p := range deletedImportOverrides { 184 names = append(names, p.Name) 185 } 186 jirix.Logger.Infof("Deleted overrides: %s\n", strings.Join(names, " ")) 187 188 manifest.ProjectOverrides = projectOverrides 189 manifest.ImportOverrides = importOverrides 190 } else { 191 remote := args[1] 192 overrideKeys := make(map[string]bool) 193 for _, p := range manifest.ProjectOverrides { 194 overrideKeys[string(p.Key())] = true 195 } 196 for _, p := range manifest.ImportOverrides { 197 overrideKeys[string(p.ProjectKey())] = true 198 } 199 if _, ok := overrideKeys[string(project.MakeProjectKey(name, remote))]; !ok { 200 if overrideFlags.importManifest != "" { 201 importOverride := project.Import{ 202 Name: name, 203 Remote: remote, 204 Manifest: overrideFlags.importManifest, 205 Revision: overrideFlags.revision, 206 } 207 manifest.ImportOverrides = append(manifest.ImportOverrides, importOverride) 208 } else { 209 projectOverride := project.Project{ 210 Name: name, 211 Remote: remote, 212 Path: overrideFlags.path, 213 Revision: overrideFlags.revision, 214 GerritHost: overrideFlags.gerritHost, 215 // We deliberately omit RemoteBranch, HistoryDepth and 216 // GitHooks. Those fields are effectively deprecated and 217 // will likely be removed in the future. 218 } 219 manifest.ProjectOverrides = append(manifest.ProjectOverrides, projectOverride) 220 } 221 } else { 222 jirix.Logger.Infof("Override \"%s:%s\" is already exist, no modification will be made.", name, remote) 223 } 224 } 225 226 // There's no error checking when writing the .jiri_manifest file; 227 // errors will be reported when "jiri update" is run. 228 return manifest.ToFile(jirix, jirix.JiriManifestFile()) 229 }