From 51797b1d8f24a26aa7f9c23212e06ed2b6cfc0e9 Mon Sep 17 00:00:00 2001 From: "iannucci@chromium.org" Date: Wed, 6 Apr 2016 17:33:24 +0000 Subject: [PATCH] Add (another) argument to break git locks in gclient. This will clean up index.lock and refs/heads/master.lock-style locks when invoked as part of the update_scripts step on the bots. R=dpranke@chromium.org, estaab@chromium.org, pgervais@chromium.org BUG=421769 Review URL: https://codereview.chromium.org/1862943002 git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@299737 0039d316-1c4b-4281-b951-d872f2087c98 --- gclient.py | 5 +++++ gclient_scm.py | 23 +++++++++++++++++++++++ tests/gclient_scm_test.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/gclient.py b/gclient.py index 5a40321f19..a31491e893 100755 --- a/gclient.py +++ b/gclient.py @@ -2050,6 +2050,11 @@ def CMDsync(parser, args): help='Don\'t bootstrap from Google Storage.') parser.add_option('--ignore_locks', action='store_true', help='GIT ONLY - Ignore cache locks.') + parser.add_option('--break_repo_locks', action='store_true', + help='GIT ONLY - Forcibly remove repo locks (e.g. ' + 'index.lock). This should only be used if you know for ' + 'certain that this invocation of gclient is the only ' + 'thing operating on the git repos (e.g. on a bot).') parser.add_option('--lock_timeout', type='int', default=5000, help='GIT ONLY - Deadline (in seconds) to wait for git ' 'cache lock to become available. Default is %default.') diff --git a/gclient_scm.py b/gclient_scm.py index 1aeb69dbf7..9a6f512341 100644 --- a/gclient_scm.py +++ b/gclient_scm.py @@ -327,6 +327,27 @@ class GitWrapper(SCMWrapper): os.remove(disabled_hook_path) os.rename(os.path.join(hook_dir, f), disabled_hook_path) + def _maybe_break_locks(self, options): + """This removes all .lock files from this repo's .git directory, if the + user passed the --break_repo_locks command line flag. + + In particular, this will cleanup index.lock files, as well as ref lock + files. + """ + if options.break_repo_locks: + git_dir = os.path.join(self.checkout_path, '.git') + for path, _, filenames in os.walk(git_dir): + for filename in filenames: + if filename.endswith('.lock'): + to_break = os.path.join(path, filename) + self.Print('breaking lock: %s' % (to_break,)) + try: + os.remove(to_break) + except OSError as ex: + self.Print('FAILED to break lock: %s: %s' % (to_break, ex)) + raise + + def update(self, options, args, file_list): """Runs git to update or transparently checkout the working copy. @@ -433,6 +454,8 @@ class GitWrapper(SCMWrapper): self.Print('________ unmanaged solution; skipping %s' % self.relpath) return self._Capture(['rev-parse', '--verify', 'HEAD']) + self._maybe_break_locks(options) + if mirror: self._UpdateMirror(mirror, options) diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py index d3fdc684f5..00592244c9 100755 --- a/tests/gclient_scm_test.py +++ b/tests/gclient_scm_test.py @@ -133,6 +133,7 @@ class BaseGitWrapperTestCase(GCBaseTestCase, StdoutCheck, TestCaseUtils, self.cache_dir = None self.merge = False self.jobs = 1 + self.break_repo_locks = False self.delete_unversioned_trees = False sample_git_import = """blob @@ -501,6 +502,36 @@ class ManagedGitWrapperTestCase(BaseGitWrapperTestCase): sys.stdout.getvalue() sys.stdout.close() + def testUpdateLocked(self): + if not self.enabled: + return + options = self.Options() + scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir, + relpath=self.relpath) + file_path = join(self.base_path, '.git', 'index.lock') + with open(file_path, 'w'): + pass + with self.assertRaisesRegexp(subprocess2.CalledProcessError, + 'Unable to create.*/index.lock'): + scm.update(options, (), []) + sys.stdout.close() + + def testUpdateLockedBreak(self): + if not self.enabled: + return + options = self.Options() + options.break_repo_locks = True + scm = gclient_scm.CreateSCM(url=self.url, root_dir=self.root_dir, + relpath=self.relpath) + file_path = join(self.base_path, '.git', 'index.lock') + with open(file_path, 'w'): + pass + scm.update(options, (), []) + self.assertRegexpMatches(sys.stdout.getvalue(), + "breaking lock.*\.git/index\.lock") + self.assertFalse(os.path.exists(file_path)) + sys.stdout.close() + def testUpdateConflict(self): if not self.enabled: return @@ -542,6 +573,7 @@ class ManagedGitWrapperTestCaseMox(BaseTestCase): self.force = force self.reset = False self.nohooks = False + self.break_repo_locks = False # TODO(maruel): Test --jobs > 1. self.jobs = 1