github.com/btwiuse/jiri@v0.0.0-20191125065820-53353bcfef54/cmd/jiri/import.go (about) 1 // Copyright 2015 The Vanadium 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 "encoding/xml" 10 "fmt" 11 "io/ioutil" 12 "os" 13 14 "github.com/btwiuse/jiri" 15 "github.com/btwiuse/jiri/cmdline" 16 "github.com/btwiuse/jiri/project" 17 ) 18 19 var ( 20 // Flags for configuring project attributes for remote imports. 21 flagImportName, flagImportRemoteBranch, flagImportRoot string 22 // Flags for controlling the behavior of the command. 23 flagImportOverwrite bool 24 flagImportOut string 25 flagImportDelete bool 26 flagImportRevision string 27 flagImportList bool 28 flagImportJsonOutput string 29 ) 30 31 func init() { 32 cmdImport.Flags.StringVar(&flagImportName, "name", "manifest", `The name of the remote manifest project.`) 33 cmdImport.Flags.StringVar(&flagImportRemoteBranch, "remote-branch", "master", `The branch of the remote manifest project to track, without the leading "origin/".`) 34 cmdImport.Flags.StringVar(&flagImportRevision, "revision", "", `Revision to check out for the remote.`) 35 cmdImport.Flags.StringVar(&flagImportRoot, "root", "", `Root to store the manifest project locally.`) 36 37 cmdImport.Flags.BoolVar(&flagImportOverwrite, "overwrite", false, `Write a new .jiri_manifest file with the given specification. If it already exists, the existing content will be ignored and the file will be overwritten.`) 38 cmdImport.Flags.StringVar(&flagImportOut, "out", "", `The output file. Uses <root>/.jiri_manifest if unspecified. Uses stdout if set to "-".`) 39 cmdImport.Flags.BoolVar(&flagImportDelete, "delete", false, `Delete existing import. Import is matched using <manifest>, <remote> and name. <remote> is optional.`) 40 cmdImport.Flags.BoolVar(&flagImportList, "list", false, `List all the imports from .jiri_manifest. This flag doesn't accept any arguments. -json-out flag can be used to specify json output file.`) 41 cmdImport.Flags.StringVar(&flagImportJsonOutput, "json-output", "", `Json output file from -list flag.`) 42 } 43 44 var cmdImport = &cmdline.Command{ 45 Runner: jiri.RunnerFunc(runImport), 46 Name: "import", 47 Short: "Adds imports to .jiri_manifest file", 48 Long: ` 49 Command "import" adds imports to the [root]/.jiri_manifest file, which specifies 50 manifest information for the jiri tool. The file is created if it doesn't 51 already exist, otherwise additional imports are added to the existing file. 52 53 An <import> element is added to the manifest representing a remote manifest 54 import. The manifest file path is relative to the root directory of the remote 55 import repository. 56 57 Example: 58 $ jiri import myfile https://foo.com/bar.git 59 60 Run "jiri help manifest" for details on manifests. 61 `, 62 ArgsName: "<manifest> <remote>", 63 ArgsLong: ` 64 <manifest> specifies the manifest file to use. 65 66 <remote> specifies the remote manifest repository. 67 `, 68 } 69 70 func isFile(file string) (bool, error) { 71 fileInfo, err := os.Stat(file) 72 if err != nil { 73 if os.IsNotExist(err) { 74 return false, nil 75 } 76 return false, err 77 } 78 return !fileInfo.IsDir(), nil 79 } 80 81 type Import struct { 82 Manifest string `json:"manifest"` 83 Name string `json:"name"` 84 Remote string `json:"remote"` 85 Revision string `json:"revision"` 86 RemoteBranch string `json:"remoteBranch"` 87 Root string `json:"root"` 88 } 89 90 func getListObject(imports []project.Import) []Import { 91 arr := []Import{} 92 for _, i := range imports { 93 i.RemoveDefaults() 94 obj := Import{ 95 Manifest: i.Manifest, 96 Name: i.Name, 97 Remote: i.Remote, 98 Revision: i.Revision, 99 RemoteBranch: i.RemoteBranch, 100 Root: i.Root, 101 } 102 arr = append(arr, obj) 103 } 104 return arr 105 } 106 107 func runImport(jirix *jiri.X, args []string) error { 108 if flagImportDelete && flagImportOverwrite { 109 return jirix.UsageErrorf("cannot use -delete and -overwrite together") 110 } 111 if flagImportList && flagImportOverwrite { 112 return jirix.UsageErrorf("cannot use -list and -overwrite together") 113 } 114 if flagImportDelete && flagImportList { 115 return jirix.UsageErrorf("cannot use -delete and -list together") 116 } 117 118 if flagImportList && len(args) != 0 { 119 return jirix.UsageErrorf("wrong number of arguments with list flag: %v", len(args)) 120 } 121 if flagImportDelete && len(args) != 1 && len(args) != 2 { 122 return jirix.UsageErrorf("wrong number of arguments with delete flag") 123 } else if !flagImportDelete && !flagImportList && len(args) != 2 { 124 return jirix.UsageErrorf("wrong number of arguments") 125 } 126 127 // Initialize manifest. 128 var manifest *project.Manifest 129 manifestExists, err := isFile(jirix.JiriManifestFile()) 130 if err != nil { 131 return err 132 } 133 if !flagImportOverwrite && manifestExists { 134 m, err := project.ManifestFromFile(jirix, jirix.JiriManifestFile()) 135 if err != nil { 136 return err 137 } 138 manifest = m 139 } 140 if manifest == nil { 141 manifest = &project.Manifest{} 142 } 143 144 if flagImportList { 145 imports := getListObject(manifest.Imports) 146 if flagImportJsonOutput == "" { 147 for _, i := range imports { 148 fmt.Printf("* import\t%s\n", i.Name) 149 fmt.Printf(" Manifest:\t%s\n", i.Manifest) 150 fmt.Printf(" Remote:\t%s\n", i.Remote) 151 fmt.Printf(" Revision:\t%s\n", i.Revision) 152 fmt.Printf(" RemoteBranch:\t%s\n", i.RemoteBranch) 153 fmt.Printf(" Root:\t%s\n", i.Root) 154 } 155 return nil 156 } else { 157 out, err := json.MarshalIndent(imports, "", " ") 158 if err != nil { 159 return fmt.Errorf("failed to serialize JSON output: %s\n", err) 160 } 161 return ioutil.WriteFile(flagImportJsonOutput, out, 0644) 162 } 163 } 164 165 if flagImportDelete { 166 var tempImports []project.Import 167 deletedImports := make(map[string]project.Import) 168 for _, imp := range manifest.Imports { 169 if imp.Manifest == args[0] && imp.Name == flagImportName { 170 match := true 171 if len(args) == 2 { 172 match = false 173 if imp.Remote == args[1] { 174 match = true 175 } 176 } 177 if match { 178 deletedImports[imp.Name+"~"+imp.Manifest+"~"+imp.Remote] = imp 179 continue 180 } 181 } 182 tempImports = append(tempImports, imp) 183 } 184 if len(deletedImports) > 1 { 185 return fmt.Errorf("More than 1 import meets your criteria. Please provide remote.") 186 } else if len(deletedImports) == 1 { 187 var data []byte 188 for _, i := range deletedImports { 189 data, err = xml.Marshal(i) 190 if err != nil { 191 return err 192 } 193 break 194 } 195 jirix.Logger.Infof("Deleted one import:\n%s", string(data)) 196 } 197 manifest.Imports = tempImports 198 } else { 199 for _, imp := range manifest.Imports { 200 if imp.Manifest == args[0] && imp.Remote == args[1] && imp.Name == flagImportName { 201 //Already exists, skip 202 jirix.Logger.Debugf("Skip import. Duplicate entry") 203 return nil 204 } 205 } 206 // There's not much error checking when writing the .jiri_manifest file; 207 // errors will be reported when "jiri update" is run. 208 manifest.Imports = append(manifest.Imports, project.Import{ 209 Manifest: args[0], 210 Name: flagImportName, 211 Remote: args[1], 212 RemoteBranch: flagImportRemoteBranch, 213 Revision: flagImportRevision, 214 Root: flagImportRoot, 215 }) 216 } 217 218 // Write output to stdout or file. 219 outFile := flagImportOut 220 if outFile == "" { 221 outFile = jirix.JiriManifestFile() 222 } 223 if outFile == "-" { 224 bytes, err := manifest.ToBytes() 225 if err != nil { 226 return err 227 } 228 _, err = os.Stdout.Write(bytes) 229 return err 230 } 231 return manifest.ToFile(jirix, outFile) 232 }