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 import os | 8 import os |
9 import re | 9 import re |
10 import shell_utils | 10 import shell_utils |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 self.commit_and_upload(use_commit_queue=self._commit_queue) | 145 self.commit_and_upload(use_commit_queue=self._commit_queue) |
146 finally: | 146 finally: |
147 shell_utils.run([GIT, 'checkout', 'master']) | 147 shell_utils.run([GIT, 'checkout', 'master']) |
148 if self._delete_when_finished: | 148 if self._delete_when_finished: |
149 shell_utils.run([GIT, 'branch', '-D', self._branch_name]) | 149 shell_utils.run([GIT, 'branch', '-D', self._branch_name]) |
150 | 150 |
151 | 151 |
152 class NewGitCheckout(object): | 152 class NewGitCheckout(object): |
153 """Creates a new local checkout of a Git repository.""" | 153 """Creates a new local checkout of a Git repository.""" |
154 | 154 |
155 def __init__(self, repository, refspec=None, subdir=None, | 155 def __init__(self, repository, branch='master', commithash='HEAD', |
156 containing_dir=None): | 156 subdir=None, containing_dir=None): |
157 """Check out a new local copy of the repository. | 157 """Check out a new local copy of the repository. |
158 | 158 |
159 Because this is a new checkout, rather than a reference to an existing | 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 | 160 checkout on disk, it is safe to assume that the calling thread is the |
161 only thread manipulating the checkout. | 161 only thread manipulating the checkout. |
162 | 162 |
163 You can use the 'with' statement to create this object in such a way that | 163 You can use the 'with' statement to create this object in such a way that |
164 it cleans up after itself: | 164 it cleans up after itself: |
165 | 165 |
166 with NewGitCheckout(*args) as checkout: | 166 with NewGitCheckout(*args) as checkout: |
167 # use checkout instance | 167 # use checkout instance |
168 # the checkout is automatically cleaned up here | 168 # the checkout is automatically cleaned up here |
169 | 169 |
170 Args: | 170 Args: |
171 repository: name of the remote repository | 171 repository: URL of the remote repository (e.g., |
172 refspec: an arbitrary remote ref (e.g., the name of a branch); | 172 'https://skia.googlesource.com/common') or path to a local repository |
173 if None, allow the git command to pick a default | 173 (e.g., '/path/to/repo/.git') to check out a copy of |
174 branch: which branch to fetch from the repository | |
175 commithash: rewind the local checkout to a particular commithash (which | |
176 must be present along the branch specified above) | |
174 subdir: if specified, the caller only wants access to files within this | 177 subdir: if specified, the caller only wants access to files within this |
175 subdir in the repository. | 178 subdir in the repository. |
176 For now, we check out the entire repository regardless of this param, | 179 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 | 180 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. | 181 optimize performance by only checking out this part of the repo. |
179 containing_dir: if specified, the new checkout will be created somewhere | 182 containing_dir: if specified, the new checkout will be created somewhere |
180 within this directory; otherwise, a system-dependent default location | 183 within this directory; otherwise, a system-dependent default location |
181 will be used, as determined by tempfile.mkdtemp() | 184 will be used, as determined by tempfile.mkdtemp() |
182 """ | 185 """ |
183 # _git_root points to the tree holding the git checkout in its entirety; | 186 # _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 | 187 # _file_root points to the files the caller wants to look at |
185 self._git_root = tempfile.mkdtemp(dir=containing_dir) | 188 self._git_root = tempfile.mkdtemp(dir=containing_dir) |
186 if subdir: | 189 if subdir: |
187 self._file_root = os.path.join(self._git_root, subdir) | 190 self._file_root = os.path.join(self._git_root, subdir) |
188 else: | 191 else: |
189 self._file_root = self._git_root | 192 self._file_root = self._git_root |
190 | 193 |
191 pull_cmd = [GIT, 'pull', repository] | 194 local_branch_name = 'local' |
192 if refspec: | |
193 pull_cmd.append(refspec) | |
194 self._run_in_git_root(args=[GIT, 'init']) | 195 self._run_in_git_root(args=[GIT, 'init']) |
195 self._run_in_git_root(args=pull_cmd) | 196 self._run_in_git_root(args=[GIT, 'fetch', repository, branch]) |
197 self._run_in_git_root(args=[GIT, 'merge', 'FETCH_HEAD']) | |
198 self._run_in_git_root(args=[GIT, 'branch', local_branch_name, commithash]) | |
199 self._run_in_git_root(args=[GIT, 'checkout', local_branch_name]) | |
borenet
2014/08/19 14:30:31
Why not just do:
$ git clone <repository>
$ git ch
epoger
2014/08/19 15:16:03
Seems to work (with some adjustments). I think th
borenet
2014/08/19 15:24:28
What repository are we checking out? I think Skia
epoger
2014/08/19 15:42:05
The primary use case is indeed the Skia repo. Per
borenet
2014/08/19 15:50:20
SGTM. You're welcome to change it back if you wan
| |
200 | |
196 | 201 |
197 @property | 202 @property |
198 def root(self): | 203 def root(self): |
199 """Returns the root directory containing the checked-out files. | 204 """Returns the root directory containing the checked-out files. |
200 | 205 |
201 If you specified the subdir parameter in the constructor, this directory | 206 If you specified the subdir parameter in the constructor, this directory |
202 will point at just the subdir you requested. | 207 will point at just the subdir you requested. |
203 """ | 208 """ |
204 return self._file_root | 209 return self._file_root |
205 | 210 |
206 def commithash(self): | 211 def commithash(self): |
207 """Returns the commithash of the local checkout.""" | 212 """Returns the commithash of the local checkout.""" |
208 return self._run_in_git_root( | 213 return self._run_in_git_root( |
209 args=[GIT, 'rev-parse', 'HEAD']).strip() | 214 args=[GIT, 'rev-parse', 'HEAD']).strip() |
210 | 215 |
211 def __enter__(self): | 216 def __enter__(self): |
212 return self | 217 return self |
borenet
2014/08/19 14:30:31
Shouldn't the bulk of the work be done in __enter_
epoger
2014/08/19 15:16:03
Done.
| |
213 | 218 |
214 # pylint: disable=W0622 | 219 # pylint: disable=W0622 |
215 def __exit__(self, type, value, traceback): | 220 def __exit__(self, type, value, traceback): |
216 shutil.rmtree(self._git_root) | 221 shutil.rmtree(self._git_root) |
217 | 222 |
218 def _run_in_git_root(self, args): | 223 def _run_in_git_root(self, args): |
219 """Run an external command with cwd set to self._git_root. | 224 """Run an external command with cwd set to self._git_root. |
220 | 225 |
221 Returns the command's output as a byte string. | 226 Returns the command's output as a byte string. |
222 | 227 |
223 Raises an Exception if the command fails. | 228 Raises an Exception if the command fails. |
224 """ | 229 """ |
225 return subprocess.check_output(args=args, cwd=self._git_root) | 230 return subprocess.check_output(args=args, cwd=self._git_root) |
OLD | NEW |