diff --git a/git-try b/git-try index 8d8babd91..4a702e7de 100755 --- a/git-try +++ b/git-try @@ -15,9 +15,11 @@ import re import trychange -def Backquote(cmd): +def Backquote(cmd, cwd=None): """Like running `cmd` in a shell script.""" - return subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0].strip() + return subprocess.Popen(cmd, + cwd=cwd, + stdout=subprocess.PIPE).communicate()[0].strip() def GetTryServerConfig(): @@ -37,18 +39,18 @@ def GetTryServerConfig(): return locals -def GetBranchName(): +def GetBranchName(working_dir=None): """Return name of current git branch.""" - branch = Backquote(['git', 'symbolic-ref', 'HEAD']) + branch = Backquote(['git', 'symbolic-ref', 'HEAD'], working_dir) if not branch.startswith('refs/heads/'): raise "Couldn't figure out branch name" branch = branch[len('refs/heads/'):] return branch -def GetPatchName(): +def GetPatchName(working_dir=None): """Construct a name for this patch.""" - short_sha = Backquote(['git', 'rev-parse', '--short=4', 'HEAD']) + short_sha = Backquote(['git', 'rev-parse', '--short=4', 'HEAD'], working_dir) return GetBranchName() + '-' + short_sha @@ -61,26 +63,59 @@ def GetRietveldPatchsetNumber(): return Backquote(['git', 'config', 'branch.%s.rietveldpatchset' % GetBranchName()]) - -def GetMungedDiff(branch, prefix='src/'): - """Get the diff we'll send to the try server. We munge paths to match svn.""" +def GetSubRepWorkingDir(sub_rep_path): + """Computes the path to the sub repository""" + if sub_rep_path: + root_dir = os.path.abspath(Backquote(['git', 'rev-parse', '--show-cdup'])) + return os.path.join(root_dir, sub_rep_path) + return None + +def GetMungedDiff(branch, prefix, sub_rep_path): + """Get the diff we'll send to the try server. We munge paths to match svn. + We add the prefix that the try bot is expecting. If sub_rep_path is + provided, diff will be calculated in the sub repository.""" # Make the following changes: # - Prepend "src/" (or some other prefix) to paths as svn is expecting # - In the case of added files, replace /dev/null with the path to the file # being added. + + cwd = GetSubRepWorkingDir(sub_rep_path) + output = [] if not branch: # Try to guess the upstream branch. - branch = Backquote(['git', 'cl', 'upstream']) - diff = subprocess.Popen(['git', 'diff-tree', '-p', '--no-prefix', - branch, 'HEAD'], - stdout=subprocess.PIPE).stdout.readlines() + branch = Backquote(['git', 'cl', 'upstream'], cwd) + command = ['git', 'diff-tree', '-p'] + + new_cwd = None + if not sub_rep_path: + command.extend(['--no-prefix']) + else: + # Append / + sub_rep_path = os.path.join(sub_rep_path, '') + # Add the right prefix + command.extend(['--src-prefix=' + sub_rep_path]) + command.extend(['--dst-prefix=' + sub_rep_path]) + + command.extend([branch, 'HEAD']) + + # Run diff tree + diff = subprocess.Popen(command, + stdout=subprocess.PIPE, + cwd=cwd).stdout.readlines() + # Replace --- /dev/null with --- for i in range(len(diff)): line = diff[i] if line.startswith('--- /dev/null'): - line = '--- %s' % prefix + diff[i+1][4:] - elif line.startswith('--- ') or line.startswith('+++ '): - line = line[0:4] + prefix + line[4:] + line = '--- %s' % diff[i+1][4:] + output.append(line) + diff = output + + # Add root prefix + output = [] + for line in diff: + if line.startswith('--- ') or line.startswith('+++ '): + line = line[0:4] + os.path.join(prefix,line[4:]) output.append(line) munged_diff = ''.join(output) @@ -89,6 +124,20 @@ def GetMungedDiff(branch, prefix='src/'): return munged_diff +def OneRepositoryDiff(diff_file, patch_names, branch, prefix, sub_rep_path): + """Computes a diff for one git repository at a given path against a given + branch. Writes the diff into diff_file and appends a name to the + patch_names list.""" + + diff = GetMungedDiff(branch, prefix, sub_rep_path) + + # Write the diff out + diff_file.write(diff) + + # Add patch name to list of patches + patch_name = GetPatchName(GetSubRepWorkingDir(sub_rep_path)) + patch_names.extend([patch_name]) + def ValidEmail(email): return re.match(r"^[a-zA-Z0-9._%-+]+@[a-zA-Z0-9._%-]+.[a-zA-Z]{2,6}$", email) @@ -119,34 +168,63 @@ if __name__ == '__main__': help="Make the try run use be a clobber build") parser.add_option("-r", "--revision", help="Specify the SVN base revision to use") + parser.add_option("--root", default="src", metavar="PATH", + help="Specify the root prefix that is appended to paths " + "in the patch") + parser.add_option("--dry_run", action="store_true", + help="Print the diff but don't send it to the try bots") + parser.add_option("--sub_rep", nargs=2, action="append", default=[], + metavar="PATH BRANCH", + help="Specify a path to a git sub-repository and a branch " + "to diff with in order to simultanously try changes " + "in multiple git repositories. Option may be " + "specified multiple times.") + parser.add_option("--webkit", metavar="BRANCH", + help="Specify webkit branch. Syntactic sugar for " + "--sub_rep third_party/WebKit/ ") + (options, args) = parser.parse_args(sys.argv) + if options.webkit: + options.sub_rep.extend([('third_party/WebKit/', options.webkit)]) + branch = None if len(args) > 1: branch = args[1] + patch_names = [] - patch_name = GetPatchName() - diff = GetMungedDiff(branch) - - # Write the diff out to a temporary file + # Dump all diffs into one diff file. diff_file = tempfile.NamedTemporaryFile() - diff_file.write(diff) + + # Calculate diff for main git repository. + OneRepositoryDiff(diff_file, patch_names, branch, options.root, None) + + # Calculate diff for each extra git repository. + for path_and_branch in options.sub_rep: + OneRepositoryDiff(diff_file, + patch_names, + path_and_branch[1], + options.root, + path_and_branch[0]) + # Make diff file ready for reading. diff_file.flush() + # Concatenate patch names + # Prepare args for TryChange email = GetEmail() user = email.partition('@')[0] args = [ '-u', user, '-e', email, - '-n', patch_name, - '--diff', diff_file.name, + '-n', '-'.join(patch_names), + '--diff', diff_file.name, ] # Send to try server via HTTP if we can parse the config, otherwise # upload via SVN. config = GetTryServerConfig() if config is not None: - sendmsg = "Sending %s using HTTP..." % patch_name + sendmsg = "Sending %s using HTTP..." % '-'.join(patch_names) args.extend(['--use_http']) if config['try_server_http_host'] is not None: args.extend(['--host', config['try_server_http_host']]) @@ -174,5 +252,9 @@ if __name__ == '__main__': '--patchset', GetRietveldPatchsetNumber(), ]) + if options.dry_run: + print open(diff_file.name, 'r').read() + exit(0) + print sendmsg TryChange(args=args)