Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2014 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2014 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """This module contains functions for using git.""" | 6 """This module contains functions for using git.""" |
| 7 | 7 |
| 8 | 8 import os |
| 9 import re | 9 import re |
| 10 import shell_utils | 10 import shell_utils |
| 11 import shutil | |
| 12 import subprocess | |
| 13 import tempfile | |
| 11 | 14 |
| 12 | 15 |
| 13 def _FindGit(): | 16 def _FindGit(): |
| 14 """Find the git executable. | 17 """Find the git executable. |
| 15 | 18 |
| 16 Returns: | 19 Returns: |
| 17 A string suitable for passing to subprocess functions, or None. | 20 A string suitable for passing to subprocess functions, or None. |
| 18 """ | 21 """ |
| 19 def test_git_executable(git): | 22 def test_git_executable(git): |
| 20 """Test the git executable. | 23 """Test the git executable. |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 def __exit__(self, exc_type, _value, _traceback): | 140 def __exit__(self, exc_type, _value, _traceback): |
| 138 if self._upload: | 141 if self._upload: |
| 139 # Only upload if no error occurred. | 142 # Only upload if no error occurred. |
| 140 try: | 143 try: |
| 141 if exc_type is None: | 144 if exc_type is None: |
| 142 self.commit_and_upload(use_commit_queue=self._commit_queue) | 145 self.commit_and_upload(use_commit_queue=self._commit_queue) |
| 143 finally: | 146 finally: |
| 144 shell_utils.run([GIT, 'checkout', 'master']) | 147 shell_utils.run([GIT, 'checkout', 'master']) |
| 145 if self._delete_when_finished: | 148 if self._delete_when_finished: |
| 146 shell_utils.run([GIT, 'branch', '-D', self._branch_name]) | 149 shell_utils.run([GIT, 'branch', '-D', self._branch_name]) |
| 150 | |
| 151 | |
| 152 class NewGitCheckout(object): | |
| 153 """Creates a new local checkout of a Git repository.""" | |
| 154 | |
| 155 def __init__(self, repository, refspec=None, subdir=None, | |
| 156 containing_dir=None): | |
|
rmistry
2014/08/13 20:13:20
I think it makes sense to have this default to tem
rmistry
2014/08/13 20:14:20
Ah I just saw your documentation update, so if dir
epoger
2014/08/13 21:03:45
Yup, you got it.
| |
| 157 """Check out a new local copy of the repository. | |
| 158 | |
| 159 Because this is a new checkout, rather than a reference to an existing | |
| 160 checkout on disk, it is safe to assume that the calling thread is the | |
| 161 only thread manipulating the checkout. | |
| 162 | |
| 163 You can use the 'with' statement to create this object in such a way that | |
| 164 it cleans up after itself: | |
| 165 | |
| 166 with NewGitCheckout(*args) as checkout: | |
| 167 # use checkout instance | |
| 168 # the checkout is automatically cleaned up here | |
| 169 | |
| 170 Args: | |
| 171 repository: name of the remote repository | |
| 172 refspec: an arbitrary remote ref (e.g., the name of a branch); | |
| 173 if None, allow the git command to pick a default | |
| 174 subdir: if specified, the caller only wants access to files within this | |
| 175 subdir in the repository. | |
| 176 For now, we check out the entire repository regardless of this param, | |
| 177 and just hide the rest of the repository; but later on we may | |
| 178 optimize performance by only checking out this part of the repo. | |
| 179 containing_dir: if specified, the new checkout will be created somewhere | |
| 180 within this directory; otherwise, a system-dependent default location | |
| 181 will be used, as determined by tempfile.mkdtemp() | |
| 182 """ | |
| 183 # _git_root points to the tree holding the git checkout in its entirety; | |
| 184 # _file_root points to the files the caller wants to look at | |
| 185 self._git_root = tempfile.mkdtemp(dir=containing_dir) | |
| 186 if subdir: | |
| 187 self._file_root = os.path.join(self._git_root, subdir) | |
| 188 else: | |
| 189 self._file_root = self._git_root | |
| 190 | |
| 191 pull_cmd = [GIT, 'pull', repository] | |
| 192 if refspec: | |
| 193 pull_cmd.append(refspec) | |
| 194 self._run_in_git_root(args=[GIT, 'init']) | |
| 195 self._run_in_git_root(args=pull_cmd) | |
| 196 | |
| 197 @property | |
| 198 def root(self): | |
| 199 """Returns the root directory containing the checked-out files. | |
| 200 | |
| 201 If you specified the subdir parameter in the constructor, this directory | |
| 202 will point at just the subdir you requested. | |
| 203 """ | |
| 204 return self._file_root | |
| 205 | |
| 206 def commithash(self): | |
| 207 """Returns the commithash of the local checkout.""" | |
| 208 return self._run_in_git_root( | |
| 209 args=[GIT, 'rev-parse', 'HEAD']).strip() | |
| 210 | |
| 211 def __enter__(self): | |
| 212 return self | |
| 213 | |
| 214 # pylint: disable=W0622 | |
| 215 def __exit__(self, type, value, traceback): | |
| 216 shutil.rmtree(self._git_root) | |
| 217 | |
| 218 def _run_in_git_root(self, args): | |
| 219 """Run an external command with cwd set to self._git_root. | |
| 220 | |
| 221 Returns the command's output as a byte string. | |
| 222 | |
| 223 Raises an Exception if the command fails. | |
| 224 """ | |
| 225 return subprocess.check_output(args=args, cwd=self._git_root) | |
| OLD | NEW |