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  }