Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1134)

Side by Side Diff: recipe_engine/fetch.py

Issue 2720853002: Fix GitBackend.checkout (Closed)
Patch Set: bug Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | recipe_engine/unittests/fetch_test.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2016 The LUCI Authors. All rights reserved. 1 # Copyright 2016 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 import base64 5 import base64
6 import httplib 6 import httplib
7 import json 7 import json
8 import logging 8 import logging
9 import os 9 import os
10 import re
10 import shutil 11 import shutil
11 import sys 12 import sys
12 import tarfile 13 import tarfile
13 import tempfile 14 import tempfile
14 15
15 # Add third party paths. 16 # Add third party paths.
16 from . import env 17 from . import env
17 from . import requests_ssl 18 from . import requests_ssl
18 from . import util 19 from . import util
19 from .requests_ssl import requests 20 from .requests_ssl import requests
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 subcommand = (args[0]) if args else ('') 113 subcommand = (args[0]) if args else ('')
113 is_remote = subcommand in self._REMOTE_SUBCOMMANDS 114 is_remote = subcommand in self._REMOTE_SUBCOMMANDS
114 raise GitError(is_remote, 'Git "%s" failed: %s' % ( 115 raise GitError(is_remote, 'Git "%s" failed: %s' % (
115 subcommand, e.message,)) 116 subcommand, e.message,))
116 117
117 def _execute(self, *args): 118 def _execute(self, *args):
118 """Runs a raw command. Separate so it's easily mockable.""" 119 """Runs a raw command. Separate so it's easily mockable."""
119 logging.info('Running: %s', args) 120 logging.info('Running: %s', args)
120 return subprocess42.check_output(args) 121 return subprocess42.check_output(args)
121 122
122
123 @property 123 @property
124 def repo_type(self): 124 def repo_type(self):
125 return package_pb2.DepSpec.GIT 125 return package_pb2.DepSpec.GIT
126 126
127 @staticmethod 127 @staticmethod
128 def branch_spec(branch): 128 def branch_spec(branch):
129 return 'origin/%s' % branch 129 return 'origin/%s' % branch
130 130
131 @util.exponential_retry(condition=GitError.is_remote_error) 131 @util.exponential_retry(condition=GitError.is_remote_error)
132 def checkout(self, repo, revision, checkout_dir, allow_fetch): 132 def checkout(self, repo_url, revision, checkout_dir, allow_fetch):
133 logging.info('Freshening repository %s in %s', repo, checkout_dir) 133 logging.info('Freshening repository %s in %s', repo_url, checkout_dir)
134 134
135 git = self.Git() 135 if revision.startswith('origin/'):
136 if not os.path.isdir(checkout_dir): 136 # Some clients pass "origin/master" when they actually mean "master".
137 if not allow_fetch: 137 # Strip "origin/"
138 raise FetchNotAllowedError( 138 # TODO(nodir): raise an exception http://crbug.com/696704
iannucci 2017/02/27 20:42:03 Let's use syntax `BUG(http://crbug.com/696704): ..
nodir 2017/02/27 21:23:31 Done
139 'need to clone %s but fetch not allowed' % repo) 139 revision = revision[len('origin/'):]
140 git('clone', '-q', repo, checkout_dir) 140
141 elif not os.path.isdir(os.path.join(checkout_dir, '.git')): 141 is_commit = re.match('^[a-z0-9]{40}$', revision)
142 raise UncleanFilesystemError(
143 '%s exists but is not a git repo' % checkout_dir)
144 142
145 git = self.Git(checkout_dir=checkout_dir) 143 git = self.Git(checkout_dir=checkout_dir)
146 git('config', 'remote.origin.url', repo) 144 if not os.path.isdir(checkout_dir):
147 try: 145 os.makedirs(checkout_dir)
148 git('rev-parse', '-q', '--verify', '%s^{commit}' % revision) 146 else:
149 except GitError as e: 147 if not os.path.isdir(os.path.join(checkout_dir, '.git')):
150 logging.warning('Revision %s is not available: %s', revision, e) 148 raise UncleanFilesystemError(
149 '%s exists but is not a git repo' % checkout_dir)
151 150
152 # Revision does not exist. If we can't fetch, then we fail here. 151 if is_commit:
153 if not allow_fetch: 152 # Avoid doing sever roundtrips if we already have the commit.
154 raise FetchNotAllowedError( 153 # Note: rev-parse is only safe if revision is a commit. If the revision
155 'need to fetch %s but fetch not allowed' % repo) 154 # is a ref, they may differ locally and remotely.
156 git('fetch') 155 try:
156 git('rev-parse', '-q', '--verify', '%s^{commit}' % revision)
157 except GitError as e:
158 logging.warning('Revision %s is not available: %s', revision, e)
iannucci 2017/02/27 20:42:03 Revision %s needs to be fetched: %s So that way t
nodir 2017/02/27 21:23:31 done
159 else:
160 git('checkout', '-q', '-f', revision)
161 return
157 162
158 git('reset', '-q', '--hard', revision) 163 if not allow_fetch:
164 # If revision is a commit hash, it is not present in the existing repo, so
165 # we have to fetch.
166 # If revision is a ref, what we have locally may be stale, so we have to
167 # fetch.
168 # We have to fetch anyway.
169 raise FetchNotAllowedError(
170 'need to fetch %s but fetch not allowed' % repo_url)
171
172 git('init') # Safe to call on an existing git repo.
173
174 # Typically we cannot fetch a commit, so we assume that remote master branch
175 # contains the requested commit. We will checkout the commit afterwards.
176 # Do not name the git remote to minimize repo state and to avoid making it
177 # work with invalid value of "origin/master".
178 # Do not map the fetched commit to anything to avoid checking out possibly
179 # stale refs.
180 git('fetch', repo_url, 'refs/heads/master' if is_commit else revision)
181
182 # FETCH_HEAD points to the fetched commit.
183
184 git('checkout', '-q', '-f', revision if is_commit else 'FETCH_HEAD')
159 185
160 @util.exponential_retry(condition=GitError.is_remote_error) 186 @util.exponential_retry(condition=GitError.is_remote_error)
161 def updates(self, repo, revision, checkout_dir, allow_fetch, 187 def updates(self, repo, revision, checkout_dir, allow_fetch,
162 other_revision, paths): 188 other_revision, paths):
163 self.checkout(repo, revision, checkout_dir, allow_fetch) 189 self.checkout(repo, revision, checkout_dir, allow_fetch)
164 190
165 git = self.Git(checkout_dir=checkout_dir) 191 git = self.Git(checkout_dir=checkout_dir)
166 if allow_fetch: 192 if allow_fetch:
167 git('fetch') 193 git('fetch')
168 194
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 logging.info('fetching %s', url) 357 logging.info('fetching %s', url)
332 358
333 resp = requests.get(url) 359 resp = requests.get(url)
334 if resp.status_code != httplib.OK: 360 if resp.status_code != httplib.OK:
335 raise GitilesFetchError(resp.status_code, resp.text) 361 raise GitilesFetchError(resp.status_code, resp.text)
336 362
337 if not resp.text.startswith(cls._GERRIT_XSRF_HEADER): 363 if not resp.text.startswith(cls._GERRIT_XSRF_HEADER):
338 raise GitilesFetchError(resp.status_code, 'Missing XSRF header') 364 raise GitilesFetchError(resp.status_code, 'Missing XSRF header')
339 365
340 return json.loads(resp.text[len(cls._GERRIT_XSRF_HEADER):]) 366 return json.loads(resp.text[len(cls._GERRIT_XSRF_HEADER):])
OLDNEW
« no previous file with comments | « no previous file | recipe_engine/unittests/fetch_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698