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

Side by Side Diff: recipe_engine/fetch.py

Issue 2071443003: Introduce different repo types (git and gitiles) (Closed) Base URL: https://github.com/luci/recipes-py.git@master
Patch Set: rename Created 4 years, 6 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/package.proto » ('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 json 6 import json
7 import logging 7 import logging
8 import os 8 import os
9 import shutil 9 import shutil
10 import sys 10 import sys
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 cmd = ['git'] 42 cmd = ['git']
43 43
44 if checkout_dir is not None: 44 if checkout_dir is not None:
45 cmd += ['-C', checkout_dir] 45 cmd += ['-C', checkout_dir]
46 cmd += list(args) 46 cmd += list(args)
47 47
48 logging.info('Running: %s', cmd) 48 logging.info('Running: %s', cmd)
49 return subprocess42.check_output(cmd) 49 return subprocess42.check_output(cmd)
50 50
51 51
52 def ensure_git_checkout(repo, revision, checkout_dir, allow_fetch): 52 class Backend(object):
53 """Fetches given |repo| at |revision| to |checkout_dir| using git. 53 def checkout(self, repo, revision, checkout_dir, allow_fetch):
54 """Checks out given |repo| at |revision| to |checkout_dir|.
54 55
55 Network operations are performed only if |allow_fetch| is True. 56 Network operations are performed only if |allow_fetch| is True.
56 """ 57 """
57 logging.info('Freshening repository %s in %s', repo, checkout_dir) 58 raise NotImplementedError()
58 59
59 if not os.path.isdir(checkout_dir): 60
61 class GitBackend(Backend):
62 """GitBackend uses a local git checkout."""
63
64 def checkout(self, repo, revision, checkout_dir, allow_fetch):
65 logging.info('Freshening repository %s in %s', repo, checkout_dir)
66
67 if not os.path.isdir(checkout_dir):
68 if not allow_fetch:
69 raise FetchNotAllowedError(
70 'need to clone %s but fetch not allowed' % repo)
71 _run_git(None, 'clone', '-q', repo, checkout_dir)
72 elif not os.path.isdir(os.path.join(checkout_dir, '.git')):
73 raise UncleanFilesystemError(
74 '%s exists but is not a git repo' % checkout_dir)
75
76 actual_origin = _run_git(
77 checkout_dir, 'config', 'remote.origin.url').strip()
78 if actual_origin != repo:
79 raise UncleanFilesystemError(
80 ('workdir %r exists but uses a different origin url %r '
81 'than requested %r') % (checkout_dir, actual_origin, repo))
82
83 try:
84 _run_git(checkout_dir, 'rev-parse', '-q', '--verify',
85 '%s^{commit}' % revision)
86 except subprocess42.CalledProcessError:
87 if not allow_fetch:
88 raise FetchNotAllowedError(
89 'need to fetch %s but fetch not allowed' % repo)
90 _run_git(checkout_dir, 'fetch')
91 _run_git(checkout_dir, 'reset', '-q', '--hard', revision)
92
93
94 class GitilesBackend(Backend):
95 """GitilesBackend uses a repo served by Gitiles."""
96
97 def checkout(self, repo, revision, checkout_dir, allow_fetch):
98 logging.info('Freshening repository %s in %s', repo, checkout_dir)
99
100 # TODO(phajdan.jr): implement caching.
60 if not allow_fetch: 101 if not allow_fetch:
61 raise FetchNotAllowedError( 102 raise FetchNotAllowedError(
62 'need to clone %s but fetch not allowed' % repo) 103 'need to download %s from gitiles but fetch not allowed' % repo)
63 _run_git(None, 'clone', '-q', repo, checkout_dir)
64 elif not os.path.isdir(os.path.join(checkout_dir, '.git')):
65 raise UncleanFilesystemError(
66 '%s exists but is not a git repo' % checkout_dir)
67 104
68 actual_origin = _run_git(checkout_dir, 'config', 'remote.origin.url').strip() 105 rev_url = '%s/+/%s?format=JSON' % (repo, requests.utils.quote(revision))
69 if actual_origin != repo: 106 logging.info('fetching %s', rev_url)
70 raise UncleanFilesystemError( 107 rev_raw = requests.get(rev_url).text
71 ('workdir %r exists but uses a different origin url %r ' 108 if not rev_raw.startswith(')]}\'\n'):
72 'than requested %r') % (checkout_dir, actual_origin, repo)) 109 raise FetchError('Unexpected gitiles response: %s' % rev_raw)
110 rev_json = json.loads(rev_raw.split('\n', 1)[1])
111 orig_revision = revision
112 revision = rev_json['commit']
113 logging.info('resolved %s to %s', orig_revision, revision)
73 114
74 try: 115 shutil.rmtree(checkout_dir, ignore_errors=True)
75 _run_git(checkout_dir, 'rev-parse', '-q', '--verify',
76 '%s^{commit}' % revision)
77 except subprocess42.CalledProcessError:
78 if not allow_fetch:
79 raise FetchNotAllowedError(
80 'need to fetch %s but fetch not allowed' % repo)
81 _run_git(checkout_dir, 'fetch')
82 _run_git(checkout_dir, 'reset', '-q', '--hard', revision)
83 116
117 recipes_cfg_url = '%s/+/%s/infra/config/recipes.cfg?format=TEXT' % (
118 repo, requests.utils.quote(revision))
119 logging.info('fetching %s' % recipes_cfg_url)
120 recipes_cfg_request = requests.get(recipes_cfg_url)
121 recipes_cfg_text = base64.b64decode(recipes_cfg_request.text)
122 recipes_cfg_proto = package_pb2.Package()
123 text_format.Merge(recipes_cfg_text, recipes_cfg_proto)
124 recipes_path_rel = recipes_cfg_proto.recipes_path
84 125
85 def ensure_gitiles_checkout(repo, revision, checkout_dir, allow_fetch): 126 # Re-create recipes.cfg in |checkout_dir| so that the repo's recipes.py
86 """Fetches given |repo| at |revision| to |checkout_dir| using gitiles. 127 # can look it up.
128 recipes_cfg_path = os.path.join(
129 checkout_dir, 'infra', 'config', 'recipes.cfg')
130 os.makedirs(os.path.dirname(recipes_cfg_path))
131 with open(recipes_cfg_path, 'w') as f:
132 f.write(recipes_cfg_text)
87 133
88 Network operations are performed only if |allow_fetch| is True. 134 recipes_path = os.path.join(checkout_dir, recipes_path_rel)
89 """ 135 os.makedirs(recipes_path)
90 logging.info('Freshening repository %s in %s', repo, checkout_dir)
91 136
92 # TODO(phajdan.jr): implement caching. 137 archive_url = '%s/+archive/%s/%s.tar.gz' % (
93 if not allow_fetch: 138 repo, requests.utils.quote(revision), recipes_path_rel)
94 raise FetchNotAllowedError( 139 logging.info('fetching %s' % archive_url)
95 'need to download %s from gitiles but fetch not allowed' % repo) 140 archive_request = requests.get(archive_url)
96 141 with tempfile.NamedTemporaryFile() as f:
97 rev_url = '%s/+/%s?format=JSON' % (repo, requests.utils.quote(revision)) 142 f.write(archive_request.content)
98 logging.info('fetching %s', rev_url) 143 f.flush()
99 rev_raw = requests.get(rev_url).text 144 with tarfile.open(f.name) as archive_tarfile:
100 if not rev_raw.startswith(')]}\'\n'): 145 archive_tarfile.extractall(recipes_path)
101 raise FetchError('Unexpected gitiles response: %s' % rev_raw)
102 rev_json = json.loads(rev_raw.split('\n', 1)[1])
103 orig_revision = revision
104 revision = rev_json['commit']
105 logging.info('resolved %s to %s', orig_revision, revision)
106
107 shutil.rmtree(checkout_dir, ignore_errors=True)
108
109 recipes_cfg_url = '%s/+/%s/infra/config/recipes.cfg?format=TEXT' % (
110 repo, requests.utils.quote(revision))
111 logging.info('fetching %s' % recipes_cfg_url)
112 recipes_cfg_request = requests.get(recipes_cfg_url)
113 recipes_cfg_text = base64.b64decode(recipes_cfg_request.text)
114 recipes_cfg_proto = package_pb2.Package()
115 text_format.Merge(recipes_cfg_text, recipes_cfg_proto)
116 recipes_path_rel = recipes_cfg_proto.recipes_path
117
118 # Re-create recipes.cfg in |checkout_dir| so that the repo's recipes.py
119 # can look it up.
120 recipes_cfg_path = os.path.join(
121 checkout_dir, 'infra', 'config', 'recipes.cfg')
122 os.makedirs(os.path.dirname(recipes_cfg_path))
123 with open(recipes_cfg_path, 'w') as f:
124 f.write(recipes_cfg_text)
125
126 recipes_path = os.path.join(checkout_dir, recipes_path_rel)
127 os.makedirs(recipes_path)
128
129 archive_url = '%s/+archive/%s/%s.tar.gz' % (
130 repo, requests.utils.quote(revision), recipes_path_rel)
131 logging.info('fetching %s' % archive_url)
132 archive_request = requests.get(archive_url)
133 with tempfile.NamedTemporaryFile() as f:
134 f.write(archive_request.content)
135 f.flush()
136 with tarfile.open(f.name) as archive_tarfile:
137 archive_tarfile.extractall(recipes_path)
OLDNEW
« no previous file with comments | « no previous file | recipe_engine/package.proto » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698