| Index: scripts/slave/bot_update.py
|
| diff --git a/scripts/slave/bot_update.py b/scripts/slave/bot_update.py
|
| index 63de04e334e1155436e81d828a866ef11fd86fb0..ee9488379492835c1d1f8e3f63bc0da7c0634454 100755
|
| --- a/scripts/slave/bot_update.py
|
| +++ b/scripts/slave/bot_update.py
|
| @@ -264,11 +264,16 @@ class SVNRevisionNotFound(Exception):
|
| pass
|
|
|
|
|
| +class InvalidDiff(Exception):
|
| + pass
|
| +
|
| +
|
| def call(*args, **kwargs):
|
| """Interactive subprocess call."""
|
| kwargs['stdout'] = subprocess.PIPE
|
| kwargs['stderr'] = subprocess.STDOUT
|
| stdin_data = kwargs.pop('stdin_data', None)
|
| + tries = kwargs.pop('tries', RETRIES)
|
| if stdin_data:
|
| kwargs['stdin'] = subprocess.PIPE
|
| out = cStringIO.StringIO()
|
| @@ -276,7 +281,7 @@ def call(*args, **kwargs):
|
| env = copy.copy(os.environ)
|
| env.update(new_env)
|
| kwargs['env'] = env
|
| - for attempt in xrange(RETRIES):
|
| + for attempt in range(tries):
|
| attempt_msg = ' (retry #%d)' % attempt if attempt else ''
|
| if new_env:
|
| print '===Injecting Environment Variables==='
|
| @@ -314,7 +319,7 @@ def call(*args, **kwargs):
|
| print
|
|
|
| raise SubprocessFailed('%s failed with code %d in %s after %d attempts.' %
|
| - (' '.join(args), code, os.getcwd(), RETRIES), code)
|
| + (' '.join(args), code, os.getcwd(), tries), code)
|
|
|
|
|
| def git(*args, **kwargs):
|
| @@ -550,12 +555,16 @@ def _last_commit_for_file(filename, repo_base):
|
| def need_to_run_deps2git(repo_base, deps_file, deps_git_file):
|
| """Checks to see if we need to run deps2git.
|
|
|
| - Returns True if there was a DEPS change after the last .DEPS.git update.
|
| + Returns True if there was a DEPS change after the last .DEPS.git update
|
| + or if DEPS has local modifications.
|
| """
|
| print 'Checking if %s exists' % deps_git_file
|
| if not path.isfile(deps_git_file):
|
| # .DEPS.git doesn't exist but DEPS does? We probably want to generate one.
|
| - print 'it exists!'
|
| + print 'it doesn\'t exist!'
|
| + return True
|
| +
|
| + if git('diff', deps_file, cwd=repo_base).strip():
|
| return True
|
|
|
| last_known_deps_ref = _last_commit_for_file(deps_file, repo_base)
|
| @@ -623,10 +632,10 @@ def ensure_deps2git(sln_dir, shallow):
|
| repo_base = path.join(os.getcwd(), sln_dir)
|
| deps_file = path.join(repo_base, 'DEPS')
|
| deps_git_file = path.join(repo_base, '.DEPS.git')
|
| - print 'Checking if %s is newer than %s' % (deps_file, deps_git_file)
|
| if not path.isfile(deps_file):
|
| return
|
|
|
| + print 'Checking if %s is newer than %s' % (deps_file, deps_git_file)
|
| if not need_to_run_deps2git(repo_base, deps_file, deps_git_file):
|
| return
|
|
|
| @@ -786,24 +795,103 @@ def _download(url):
|
| raise
|
|
|
|
|
| -def apply_issue_svn(root, patch_url):
|
| +def parse_diff(diff):
|
| + """Takes a unified diff and returns a list of diffed files and their diffs.
|
| +
|
| + The return format is a list of pairs of:
|
| + (<filename>, <diff contents>)
|
| + <diff contents> is inclusive of the diff line.
|
| + """
|
| + result = []
|
| + current_diff = ''
|
| + current_header = None
|
| + for line in diff.splitlines():
|
| + # "diff" is for git style patches, and "Index: " is for SVN style patches.
|
| + if line.startswith('diff') or line.startswith('Index: '):
|
| + if current_header:
|
| + # If we are in a diff portion, then save the diff.
|
| + result.append((current_header, '%s\n' % current_diff))
|
| + git_header_match = re.match(r'diff (?:--git )?(\S+) (\S+)', line)
|
| + svn_header_match = re.match(r'Index: (.*)', line)
|
| +
|
| + if git_header_match:
|
| + # First, see if its a git style header.
|
| + from_file = git_header_match.group(1)
|
| + to_file = git_header_match.group(2)
|
| + if from_file != to_file and from_file.startswith('a/'):
|
| + # Sometimes git prepends 'a/' and 'b/' in front of file paths.
|
| + from_file = from_file[2:]
|
| + current_header = from_file
|
| +
|
| + elif svn_header_match:
|
| + # Otherwise, check if its an SVN style header.
|
| + current_header = svn_header_match.group(1)
|
| +
|
| + else:
|
| + # Otherwise... I'm not really sure what to do with this.
|
| + raise InvalidDiff('Can\'t process header: %s\nFull diff:\n%s' %
|
| + (line, diff))
|
| +
|
| + current_diff = ''
|
| + current_diff += '%s\n' % line
|
| + if current_header:
|
| + # We hit EOF, gotta save the last diff.
|
| + result.append((current_header, current_diff))
|
| + return result
|
| +
|
| +
|
| +def get_svn_patch(patch_url):
|
| + """Fetch patch from patch_url, return list of (filename, diff)"""
|
| patch_data = call('svn', 'cat', patch_url)
|
| - call(PATCH_TOOL, '-p0', '--remove-empty-files', '--force', '--forward',
|
| - stdin_data=patch_data, cwd=root)
|
| + return parse_diff(patch_data)
|
| +
|
| +
|
| +def apply_svn_patch(patch_root, patches, whitelist=None, blacklist=None):
|
| + """Expects a list of (filename, diff), applies it on top of patch_root."""
|
| + if whitelist:
|
| + patches = [(name, diff) for name, diff in patches if name in whitelist]
|
| + elif blacklist:
|
| + patches = [(name, diff) for name, diff in patches if name not in blacklist]
|
| + diffs = [diff for _, diff in patches]
|
| + patch = ''.join(diffs)
|
|
|
| + if patch:
|
| + print '===Patching files==='
|
| + for filename, _ in patches:
|
| + print 'Patching %s' % filename
|
| + call(PATCH_TOOL, '-p0', '--remove-empty-files', '--force', '--forward',
|
| + stdin_data=patch, cwd=patch_root, tries=1)
|
|
|
| -def apply_issue_rietveld(issue, patchset, root, server, rev_map, revision):
|
| +
|
| +def apply_rietveld_issue(issue, patchset, root, server, rev_map, revision,
|
| + whitelist=None, blacklist=None):
|
| apply_issue_bin = ('apply_issue.bat' if sys.platform.startswith('win')
|
| else 'apply_issue')
|
| - call(apply_issue_bin,
|
| - '--root_dir', root,
|
| - '--issue', issue,
|
| - '--patchset', patchset,
|
| - '--no-auth',
|
| - '--server', server,
|
| - '--base_ref', revision,
|
| - '--force',
|
| - '--ignore_deps')
|
| + cmd = [apply_issue_bin,
|
| + # The patch will be applied on top of this directory.
|
| + '--root_dir', root,
|
| + # Tell apply_issue how to fetch the patch.
|
| + '--issue', issue,
|
| + '--patchset', patchset,
|
| + '--no-auth',
|
| + '--server', server,
|
| + # Always run apply_issue.py, otherwise it would see update.flag
|
| + # and then bail out.
|
| + '--force',
|
| + # Don't run gclient sync when it sees a DEPS change.
|
| + '--ignore_deps',
|
| + # Don't commit the patch or add it to the index.
|
| + '--no_commit',
|
| + ]
|
| + if whitelist:
|
| + for item in whitelist:
|
| + cmd.extend(['--whitelist', item])
|
| + elif blacklist:
|
| + for item in blacklist:
|
| + cmd.extend(['--blacklist', item])
|
| +
|
| + # Only try once, since subsequent failures hide the real failure.
|
| + call(*cmd, tries=1)
|
|
|
|
|
| def check_flag(flag_file):
|
| @@ -824,14 +912,6 @@ def emit_flag(flag_file):
|
| f.write('Success!')
|
|
|
|
|
| -def get_real_git_hash(git_hash, dir_name):
|
| - """Return git_hash or the parent of git_hash if its a patched hash."""
|
| - log = git('log', '-1', '--format=%B', cwd=dir_name).strip()
|
| - if 'committed patch' in log.lower():
|
| - return git('log', '-1', '--format=%H', 'HEAD^', cwd=dir_name).strip()
|
| - return git_hash
|
| -
|
| -
|
| def parse_got_revision(gclient_output, got_revision_mapping, use_svn_revs):
|
| """Translate git gclient revision mapping to build properties.
|
|
|
| @@ -897,21 +977,23 @@ def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only,
|
| print 'Fetching Git checkout'
|
| git_ref = git_checkout(solutions, revisions, shallow)
|
|
|
| - # If either patch_url or issue is passed in, then we need to apply a patch.
|
| + patches = None
|
| if patch_url:
|
| - # patch_url takes precidence since its only passed in on gcl try/git try.
|
| - apply_issue_svn(root, patch_url)
|
| - elif issue:
|
| - apply_issue_rietveld(issue, patchset, root, rietveld_server,
|
| - revision_mapping, git_ref)
|
| + patches = get_svn_patch(patch_url)
|
| +
|
| + if root == first_sln:
|
| + # Only top level DEPS patching is supported right now.
|
| + if patches:
|
| + apply_svn_patch(root, patches, whitelist=['DEPS'])
|
| + elif issue:
|
| + apply_rietveld_issue(issue, patchset, root, rietveld_server,
|
| + revision_mapping, git_ref, whitelist=['DEPS'])
|
| +
|
|
|
| if buildspec_name:
|
| buildspecs2git(root, buildspec_name)
|
| - elif first_sln == root:
|
| - # Run deps2git if there is a DEPS commit after the last .DEPS.git commit.
|
| - # We only need to ensure deps2git if the root is not overridden, since
|
| - # if the root is overridden, it means we are working with a sub repository
|
| - # patch, which means its impossible for it to touch DEPS.
|
| + else:
|
| + # Run deps2git if there is a DEPS change after the last .DEPS.git commit.
|
| ensure_deps2git(root, shallow)
|
|
|
| # Ensure our build/ directory is set up with the correct .gclient file.
|
| @@ -929,6 +1011,13 @@ def ensure_checkout(solutions, revisions, first_sln, target_os, target_os_only,
|
| dir_names = [sln['name'] for sln in solutions]
|
| ensure_deps_revisions(gclient_output.get('solutions', {}),
|
| dir_names, revisions)
|
| + # Apply the rest of the patch here (sans DEPS)
|
| + if patches:
|
| + apply_svn_patch(root, patches, blacklist=['DEPS'])
|
| + elif issue:
|
| + apply_rietveld_issue(issue, patchset, root, rietveld_server,
|
| + revision_mapping, git_ref, blacklist=['DEPS'])
|
| +
|
| return gclient_output
|
|
|
|
|
|
|