// clMailMultiFlags extracts flags from the invocation of cl mail // that should be passed on to the sub invocations of cl mail when // operating across multiple repos. // These are: // -autosubmit, -cc, -d, -edit, -host, -m, -presubmit, remote-branch, -r, // -set-topic, -topic, -check-uncommitted and -verify, func clMailMultiFlags() []string { flags := []string{} stringFlag := func(name, value string) { if profilescmdline.IsFlagSet(cmdCLMail.ParsedFlags, name) { flags = append(flags, fmt.Sprintf("--%s=%s", name, value)) } } boolFlag := func(name string, value bool) { if profilescmdline.IsFlagSet(cmdCLMail.ParsedFlags, name) { flags = append(flags, fmt.Sprintf("--%s=%t", name, value)) } } // --edit is handled differently to other flags, if it is not // specifically set, the default is to run the editor once // and then reuse that message for the other parts of a multipart // CL - that is, set -edit=false for the other repos. If edit // is specifically set then that setting is used for all repos. // So using --edit=true allows for a different CL message in // each repo of a multipart CL. if profilescmdline.IsFlagSet(cmdCLMail.ParsedFlags, "edit") { // if --edit is set on the command line, use that value // for all subcommands flags = append(flags, fmt.Sprintf("--edit=%t", editFlag)) } else { // if --edit is not set on the command line, use --edit=false // for subcommands. flags = append(flags, "--edit=false") } boolFlag("autosubmit", autosubmitFlag) stringFlag("cc", ccsFlag) boolFlag("d", draftFlag) stringFlag("host", hostFlag) stringFlag("m", messageFlag) stringFlag("presubmit", presubmitFlag) stringFlag("remote-branch", remoteBranchFlag) stringFlag("r", reviewersFlag) boolFlag("set-topic", setTopicFlag) boolFlag("check-uncommitted", uncommittedFlag) boolFlag("verify", verifyFlag) return flags }
func runp(jirix *jiri.X, cmd *cmdline.Command, args []string) error { hasUntrackedSet := profilescmdline.IsFlagSet(cmd.ParsedFlags, "has-untracked") hasUncommitedSet := profilescmdline.IsFlagSet(cmd.ParsedFlags, "has-uncommitted") hasGerritSet := profilescmdline.IsFlagSet(cmd.ParsedFlags, "has-gerrit-message") if runpFlags.interactive { runpFlags.collateOutput = false } var keysRE, branchRE *regexp.Regexp var err error if profilescmdline.IsFlagSet(cmd.ParsedFlags, "projects") { re := "" for _, pre := range strings.Split(runpFlags.projectKeys, ",") { re += pre + "|" } re = strings.TrimRight(re, "|") keysRE, err = regexp.Compile(re) if err != nil { return fmt.Errorf("failed to compile projects regexp: %q: %v", runpFlags.projectKeys, err) } } if profilescmdline.IsFlagSet(cmd.ParsedFlags, "has-branch") { branchRE, err = regexp.Compile(runpFlags.hasBranch) if err != nil { return fmt.Errorf("failed to compile has-branch regexp: %q: %v", runpFlags.hasBranch, err) } } for _, f := range []string{"show-key-prefix", "show-name-prefix"} { if profilescmdline.IsFlagSet(cmd.ParsedFlags, f) { if runpFlags.interactive && profilescmdline.IsFlagSet(cmd.ParsedFlags, "interactive") { fmt.Fprintf(jirix.Stderr(), "WARNING: interactive mode being disabled because %s was set\n", f) } runpFlags.interactive = false runpFlags.collateOutput = true break } } git := gitutil.New(jirix.NewSeq()) homeBranch, err := git.CurrentBranchName() if err != nil { // jiri was run from outside of a project. Let's assume we'll // use all projects if none have been specified via the projects flag. if keysRE == nil { keysRE = regexp.MustCompile(".*") } } dirty := false if hasUntrackedSet || hasUncommitedSet { dirty = true } states, err := project.GetProjectStates(jirix, dirty) if err != nil { return err } mapInputs := map[project.ProjectKey]*mapInput{} var keys project.ProjectKeys for key, state := range states { if keysRE != nil { if !keysRE.MatchString(string(key)) { continue } } else { if state.CurrentBranch != homeBranch { continue } } if branchRE != nil { found := false for _, br := range state.Branches { if branchRE.MatchString(br.Name) { found = true break } } if !found { continue } } if hasUntrackedSet && (state.HasUntracked != runpFlags.hasUntracked) { continue } if hasUncommitedSet && (state.HasUncommitted != runpFlags.hasUncommitted) { continue } if hasGerritSet { hasMsg := false for _, br := range state.Branches { if (state.CurrentBranch == br.Name) && br.HasGerritMessage { hasMsg = true break } } if hasMsg != runpFlags.hasGerritMessage { continue } } mapInputs[key] = &mapInput{ ProjectState: state, jirix: jirix, key: key, } keys = append(keys, key) } total := len(mapInputs) index := 1 for _, mi := range mapInputs { mi.index = index mi.total = total index++ } if runpFlags.verbose { fmt.Fprintf(jirix.Stdout(), "Project Names: %s\n", strings.Join(stateNames(mapInputs), " ")) fmt.Fprintf(jirix.Stdout(), "Project Keys: %s\n", strings.Join(stateKeys(mapInputs), " ")) } reader, err := profilesreader.NewReader(jirix, runpFlags.ProfilesMode, runpFlags.DBFilename) runner := &runner{ reader: reader, args: args, } mr := simplemr.MR{} if runpFlags.interactive { // Run one mapper at a time. mr.NumMappers = 1 sort.Sort(keys) } in, out := make(chan *simplemr.Record, len(mapInputs)), make(chan *simplemr.Record, len(mapInputs)) sigch := make(chan os.Signal) signal.Notify(sigch, os.Interrupt) go func() { <-sigch; mr.Cancel() }() go mr.Run(in, out, runner, runner) for _, key := range keys { in <- &simplemr.Record{string(key), []interface{}{mapInputs[key]}} } close(in) <-out return mr.Error() }