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 |