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 29import re 30 31 32class GitFailedException(Exception): 33 pass 34 35 36def Strip(f): 37 def new_f(*args, **kwargs): 38 return f(*args, **kwargs).strip() 39 return new_f 40 41 42def MakeArgs(l): 43 """['-a', '', 'abc', ''] -> '-a abc'""" 44 return " ".join(filter(None, l)) 45 46 47def Quoted(s): 48 return "\"%s\"" % s 49 50 51class 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