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  }