github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/review/git-review/mail.go (about) 1 // Copyright 2014 The Go 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 "fmt" 9 "os" 10 "regexp" 11 "strings" 12 ) 13 14 func mail(args []string) { 15 var ( 16 diff = flags.Bool("diff", false, "show change commit diff and don't upload or mail") 17 force = flags.Bool("f", false, "mail even if there are staged changes") 18 rList = new(stringList) // installed below 19 ccList = new(stringList) // installed below 20 ) 21 flags.Var(rList, "r", "comma-separated list of reviewers") 22 flags.Var(ccList, "cc", "comma-separated list of people to CC:") 23 24 flags.Usage = func() { 25 fmt.Fprintf(os.Stderr, "Usage: %s mail %s [-r reviewer,...] [-cc mail,...]\n", os.Args[0], globalFlags) 26 } 27 flags.Parse(args) 28 if len(flags.Args()) != 0 { 29 flags.Usage() 30 os.Exit(2) 31 } 32 33 b := CurrentBranch() 34 if b.ChangeID() == "" { 35 dief("no pending change; can't mail.") 36 } 37 38 if *diff { 39 run("git", "diff", "HEAD^..HEAD") 40 return 41 } 42 43 if !*force && HasStagedChanges() { 44 dief("there are staged changes; aborting.\n" + 45 "Use 'review change' to include them or 'review mail -f' to force it.") 46 } 47 48 refSpec := "HEAD:refs/for/master" 49 start := "%" 50 if *rList != "" { 51 refSpec += mailList(start, "r", string(*rList)) 52 start = "," 53 } 54 if *ccList != "" { 55 refSpec += mailList(start, "cc", string(*ccList)) 56 } 57 run("git", "push", "-q", "origin", refSpec) 58 } 59 60 // mailAddressRE matches the mail addresses we admit. It's restrictive but admits 61 // all the addresses in the Go CONTRIBUTORS file at time of writing (tested separately). 62 var mailAddressRE = regexp.MustCompile(`^[a-zA-Z0-9][-_.a-zA-Z0-9]*@[-_.a-zA-Z0-9]+$`) 63 64 // mailList turns the list of mail addresses from the flag value into the format 65 // expected by gerrit. The start argument is a % or , depending on where we 66 // are in the processing sequence. 67 func mailList(start, tag string, flagList string) string { 68 spec := start 69 for i, addr := range strings.Split(flagList, ",") { 70 if !mailAddressRE.MatchString(addr) { 71 dief("%q is not a valid reviewer mail address", addr) 72 } 73 if i > 0 { 74 spec += "," 75 } 76 spec += tag + "=" + addr 77 } 78 return spec 79 } 80 81 // stringList is a flag.Value that is like flag.String, but if repeated 82 // keeps appending to the old value, inserting commas as separators. 83 // This allows people to write -r rsc,adg (like the old hg command) 84 // but also -r rsc -r adg (like standard git commands). 85 // This does change the meaning of -r rsc -r adg (it used to mean just adg). 86 type stringList string 87 88 func (x *stringList) String() string { 89 return string(*x) 90 } 91 92 func (x *stringList) Set(s string) error { 93 if *x != "" && s != "" { 94 *x += "," 95 } 96 *x += stringList(s) 97 return nil 98 }