Home | History | Annotate | Download | only in push-to-trunk
      1 #!/usr/bin/env python
      2 # Copyright 2014 the V8 project authors. All rights reserved.
      3 # Redistribution and use in source and binary forms, with or without
      4 # modification, are permitted provided that the following conditions are
      5 # met:
      6 #
      7 #     * Redistributions of source code must retain the above copyright
      8 #       notice, this list of conditions and the following disclaimer.
      9 #     * Redistributions in binary form must reproduce the above
     10 #       copyright notice, this list of conditions and the following
     11 #       disclaimer in the documentation and/or other materials provided
     12 #       with the distribution.
     13 #     * Neither the name of Google Inc. nor the names of its
     14 #       contributors may be used to endorse or promote products derived
     15 #       from this software without specific prior written permission.
     16 #
     17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 import re
     30 
     31 
     32 class GitFailedException(Exception):
     33   pass
     34 
     35 
     36 def Strip(f):
     37   def new_f(*args, **kwargs):
     38     return f(*args, **kwargs).strip()
     39   return new_f
     40 
     41 
     42 def MakeArgs(l):
     43   """['-a', '', 'abc', ''] -> '-a abc'"""
     44   return " ".join(filter(None, l))
     45 
     46 
     47 def Quoted(s):
     48   return "\"%s\"" % s
     49 
     50 
     51 class GitRecipesMixin(object):
     52   def GitIsWorkdirClean(self):
     53     return self.Git("status -s -uno").strip() == ""
     54 
     55   @Strip
     56   def GitBranch(self):
     57     return self.Git("branch")
     58 
     59   def GitCreateBranch(self, name, branch=""):
     60     assert name
     61     self.Git(MakeArgs(["checkout -b", name, branch]))
     62 
     63   def GitDeleteBranch(self, name):
     64     assert name
     65     self.Git(MakeArgs(["branch -D", name]))
     66 
     67   def GitReset(self, name):
     68     assert name
     69     self.Git(MakeArgs(["reset --hard", name]))
     70 
     71   def GitRemotes(self):
     72     return map(str.strip, self.Git(MakeArgs(["branch -r"])).splitlines())
     73 
     74   def GitCheckout(self, name):
     75     assert name
     76     self.Git(MakeArgs(["checkout -f", name]))
     77 
     78   def GitCheckoutFile(self, name, branch_or_hash):
     79     assert name
     80     assert branch_or_hash
     81     self.Git(MakeArgs(["checkout -f", branch_or_hash, "--", name]))
     82 
     83   def GitCheckoutFileSafe(self, name, branch_or_hash):
     84     try:
     85       self.GitCheckoutFile(name, branch_or_hash)
     86     except GitFailedException:  # pragma: no cover
     87       # The file doesn't exist in that revision.
     88       return False
     89     return True
     90 
     91   def GitChangedFiles(self, git_hash):
     92     assert git_hash
     93     try:
     94       files = self.Git(MakeArgs(["diff --name-only",
     95                                  git_hash,
     96                                  "%s^" % git_hash]))
     97       return map(str.strip, files.splitlines())
     98     except GitFailedException:  # pragma: no cover
     99       # Git fails using "^" at branch roots.
    100       return []
    101 
    102 
    103   @Strip
    104   def GitCurrentBranch(self):
    105     for line in self.Git("status -s -b -uno").strip().splitlines():
    106       match = re.match(r"^## (.+)", line)
    107       if match: return match.group(1)
    108     raise Exception("Couldn't find curent branch.")  # pragma: no cover
    109 
    110   @Strip
    111   def GitLog(self, n=0, format="", grep="", git_hash="", parent_hash="",
    112              branch="", reverse=False):
    113     assert not (git_hash and parent_hash)
    114     args = ["log"]
    115     if n > 0:
    116       args.append("-%d" % n)
    117     if format:
    118       args.append("--format=%s" % format)
    119     if grep:
    120       args.append("--grep=\"%s\"" % grep.replace("\"", "\\\""))
    121     if reverse:
    122       args.append("--reverse")
    123     if git_hash:
    124       args.append(git_hash)
    125     if parent_hash:
    126       args.append("%s^" % parent_hash)
    127     args.append(branch)
    128     return self.Git(MakeArgs(args))
    129 
    130   def GitGetPatch(self, git_hash):
    131     assert git_hash
    132     return self.Git(MakeArgs(["log", "-1", "-p", git_hash]))
    133 
    134   # TODO(machenbach): Unused? Remove.
    135   def GitAdd(self, name):
    136     assert name
    137     self.Git(MakeArgs(["add", Quoted(name)]))
    138 
    139   def GitApplyPatch(self, patch_file, reverse=False):
    140     assert patch_file
    141     args = ["apply --index --reject"]
    142     if reverse:
    143       args.append("--reverse")
    144     args.append(Quoted(patch_file))
    145     self.Git(MakeArgs(args))
    146 
    147   def GitUpload(self, reviewer="", author="", force=False):
    148     args = ["cl upload --send-mail"]
    149     if author:
    150       args += ["--email", Quoted(author)]
    151     if reviewer:
    152       args += ["-r", Quoted(reviewer)]
    153     if force:
    154       args.append("-f")
    155     # TODO(machenbach): Check output in forced mode. Verify that all required
    156     # base files were uploaded, if not retry.
    157     self.Git(MakeArgs(args), pipe=False)
    158 
    159   def GitCommit(self, message="", file_name=""):
    160     assert message or file_name
    161     args = ["commit"]
    162     if file_name:
    163       args += ["-aF", Quoted(file_name)]
    164     if message:
    165       args += ["-am", Quoted(message)]
    166     self.Git(MakeArgs(args))
    167 
    168   def GitPresubmit(self):
    169     self.Git("cl presubmit", "PRESUBMIT_TREE_CHECK=\"skip\"")
    170 
    171   def GitDCommit(self):
    172     self.Git("cl dcommit -f --bypass-hooks", retry_on=lambda x: x is None)
    173 
    174   def GitDiff(self, loc1, loc2):
    175     return self.Git(MakeArgs(["diff", loc1, loc2]))
    176 
    177   def GitPull(self):
    178     self.Git("pull")
    179 
    180   def GitSVNFetch(self):
    181     self.Git("svn fetch")
    182 
    183   # TODO(machenbach): Unused? Remove.
    184   @Strip
    185   def GitSVNLog(self):
    186     return self.Git("svn log -1 --oneline")
    187 
    188   @Strip
    189   def GitSVNFindGitHash(self, revision, branch=""):
    190     assert revision
    191     return self.Git(MakeArgs(["svn find-rev", "r%s" % revision, branch]))
    192 
    193   @Strip
    194   def GitSVNFindSVNRev(self, git_hash, branch=""):
    195     return self.Git(MakeArgs(["svn find-rev", git_hash, branch]))
    196 
    197   def GitSVNDCommit(self):
    198     return self.Git("svn dcommit 2>&1", retry_on=lambda x: x is None)
    199 
    200   def GitSVNTag(self, version):
    201     self.Git(("svn tag %s -m \"Tagging version %s\"" % (version, version)),
    202              retry_on=lambda x: x is None)
    203