def Main(): parser = optparse.OptionParser() parser.add_option('--skia_revision', help=('Desired revision of Skia. Defaults to the most ' 'recent revision.')) parser.add_option('--chrome_revision', help=('Desired revision of Chrome. Defaults to the most ' 'recent revision.')) parser.add_option('--destination', help=('Where to sync the code. Defaults to the current ' 'directory.'), default=os.curdir) parser.add_option('--fetch_target', help=('Calls the fetch tool in depot_tools with the ' 'specified target.'), default=DEFAULT_FETCH_TARGET) (options, _) = parser.parse_args() dest_dir = os.path.abspath(options.destination) with misc.ChDir(dest_dir): actual_skia_rev, actual_chrome_rev = Sync( skia_revision=options.skia_revision or SKIA_REV_MASTER, chrome_revision=options.chrome_revision or CHROME_REV_MASTER, fetch_target=options.fetch_target) print 'Chrome synced to %s' % actual_chrome_rev print 'Skia synced to %s' % actual_skia_rev
def GetCheckedOutHash(): """ Determine what commit we actually got. If there are local modifications, raise an exception. """ checkout_root, config_dict = _GetLocalConfig() # Get the checked-out commit hash for the first gclient solution. with misc.ChDir(os.path.join(checkout_root, config_dict[0]['name'])): # First, print out the remote from which we synced, just for debugging. cmd = [GIT, 'remote', '-v'] try: shell_utils.run(cmd) except shell_utils.CommandFailedException as e: print e # "git rev-parse HEAD" returns the commit hash for HEAD. return shell_utils.run([GIT, 'rev-parse', 'HEAD'], log_in_real_time=False).rstrip('\n')
def Sync(skia_revision=SKIA_REV_MASTER, chrome_revision=CHROME_REV_LKGR, fetch_target=DEFAULT_FETCH_TARGET, gyp_defines=None, gyp_generators=None): """ Create and sync a checkout of Skia inside a checkout of Chrome. Returns a tuple containing the actually-obtained revision of Skia and the actually- obtained revision of Chrome. skia_revision: revision of Skia to sync. Should be a commit hash or one of (SKIA_REV_DEPS, SKIA_REV_MASTER). chrome_revision: revision of Chrome to sync. Should be a commit hash or one of (CHROME_REV_LKGR, CHROME_REV_MASTER). fetch_target: string; Calls the fetch tool in depot_tools with the specified argument. Default is DEFAULT_FETCH_TARGET. gyp_defines: optional string; GYP_DEFINES to be passed to Gyp. gyp_generators: optional string; which GYP_GENERATORS to use. """ # Figure out what revision of Skia we should use. if skia_revision == SKIA_REV_MASTER: output = GetRemoteMasterHash(SKIA_GIT_URL) if output: skia_revision = shlex.split(output)[0] if not skia_revision: raise Exception('Could not determine current Skia revision!') skia_revision = str(skia_revision) # Use Chrome LKGR, since gclient_utils will force a sync to origin/master. if chrome_revision == CHROME_REV_LKGR: chrome_revision = urllib2.urlopen(CHROME_LKGR_URL).read() elif chrome_revision == CHROME_REV_MASTER: chrome_revision = shlex.split( GetRemoteMasterHash(CHROME_GIT_URL))[0] # Run "fetch chromium". The initial run is allowed to fail after it does some # work. At the least, we expect the .gclient file to be present when it # finishes. if not os.path.isfile(GCLIENT_FILE): try: shell_utils.run([FETCH, fetch_target, '--nosvn=True']) except shell_utils.CommandFailedException: pass if not os.path.isfile(GCLIENT_FILE): raise Exception('Could not fetch %s!' % fetch_target) # Run "gclient sync" revisions = [('src', chrome_revision)] if skia_revision != SKIA_REV_DEPS: revisions.append(('src/third_party/skia', skia_revision)) try: # Hack: We have to set some GYP_DEFINES, or upstream scripts will complain. os.environ['GYP_DEFINES'] = os.environ.get('GYP_DEFINES') or '' gclient_utils.Sync( revisions=revisions, jobs=1, no_hooks=True, force=True) except shell_utils.CommandFailedException as e: # We frequently see sync failures because a lock file wasn't deleted. In # that case, delete the lock file and try again. pattern = r".*fatal: Unable to create '(\S+)': File exists\..*" match = re.search(pattern, e.output) if not match: raise e file_to_delete = match.groups()[0] try: print 'Attempting to remove %s' % file_to_delete os.remove(file_to_delete) except OSError: # If the file no longer exists, just try again. pass gclient_utils.Sync( revisions=revisions, jobs=1, no_hooks=True, force=True) # Find the actually-obtained Chrome revision. os.chdir('src') actual_chrome_rev = shell_utils.run([GIT, 'rev-parse', 'HEAD'], log_in_real_time=False).rstrip() # Find the actually-obtained Skia revision. with misc.ChDir(os.path.join('third_party', 'skia')): actual_skia_rev = shell_utils.run([GIT, 'rev-parse', 'HEAD'], log_in_real_time=False).rstrip() # Run gclient hooks gclient_utils.RunHooks(gyp_defines=gyp_defines, gyp_generators=gyp_generators) # Fix the submodules so that they don't show up in "git status" # This fails on Windows... if os.name != 'nt': submodule_cmd = ('\'git config -f ' '$toplevel/.git/config submodule.$name.ignore all\'') shell_utils.run(' '.join([GIT, 'submodule', 'foreach', submodule_cmd]), shell=True) # Verify that we got the requested revisions of Chrome and Skia. if (skia_revision != actual_skia_rev[:len(skia_revision)] and skia_revision != SKIA_REV_DEPS): raise Exception('Requested Skia revision %s but got %s!' % ( skia_revision, actual_skia_rev)) if (chrome_revision and chrome_revision != actual_chrome_rev[:len(chrome_revision)]): raise Exception('Requested Chrome revision %s but got %s!' % ( chrome_revision, actual_chrome_rev)) return (actual_skia_rev, actual_chrome_rev)
def Sync(revisions=None, force=False, delete_unversioned_trees=False, verbose=False, jobs=None, no_hooks=False, extra_args=None): """ Update the local checkout using gclient. Args: revisions: optional list of (branch, revision) tuples indicating which projects to sync to which revisions. force: whether to run with --force. delete_unversioned_trees: whether to run with --delete-unversioned-trees. verbose: whether to run with --verbose. jobs: optional argument for the --jobs flag. no_hooks: whether to run with --nohooks. extra_args: optional list; any additional arguments. """ for branch, _ in (revisions or []): # Do whatever it takes to get up-to-date with origin/master. if os.path.exists(branch): with misc.ChDir(branch): # First, fix the git identity if needed. maybe_fix_identity() # If there are local changes, "git checkout" will fail. shell_utils.run([GIT, 'reset', '--hard', 'HEAD']) # In case HEAD is detached... shell_utils.run([GIT, 'checkout', 'master']) # Always fetch, in case we're unmanaged. shell_utils.run_retry([GIT, 'fetch'], attempts=5) # This updates us to origin/master even if master has diverged. shell_utils.run([GIT, 'reset', '--hard', 'origin/master']) cmd = ['sync', '--no-nag-max'] if verbose: cmd.append('--verbose') if force: cmd.append('--force') if delete_unversioned_trees: cmd.append('--delete_unversioned_trees') if jobs: cmd.append('-j%d' % jobs) if no_hooks: cmd.append('--nohooks') for branch, revision in (revisions or []): if revision: cmd.extend(['--revision', '%s@%s' % (branch, revision)]) if extra_args: cmd.extend(extra_args) output = _RunCmd(cmd) # "gclient sync" just downloads all of the commits. In order to actually sync # to the desired commit, we have to "git reset" to that commit. for branch, revision in (revisions or []): with misc.ChDir(branch): if revision: shell_utils.run([GIT, 'reset', '--hard', revision]) else: shell_utils.run([GIT, 'reset', '--hard', 'origin/master']) return output