Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # coding: utf-8 | 2 # coding: utf-8 |
3 | 3 |
4 # This Source Code Form is subject to the terms of the Mozilla Public | 4 # This Source Code Form is subject to the terms of the Mozilla Public |
5 # License, v. 2.0. If a copy of the MPL was not distributed with this | 5 # License, v. 2.0. If a copy of the MPL was not distributed with this |
6 # file, You can obtain one at http://mozilla.org/MPL/2.0/. | 6 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
7 | 7 |
8 import sys | 8 import sys |
9 import os | 9 import os |
10 import posixpath | 10 import posixpath |
11 import re | 11 import re |
12 import io | 12 import io |
13 import errno | 13 import errno |
14 import logging | 14 import logging |
15 import subprocess | 15 import subprocess |
16 import urlparse | 16 import urlparse |
17 import argparse | 17 import argparse |
18 | 18 |
19 from collections import OrderedDict | 19 from collections import OrderedDict |
20 from ConfigParser import RawConfigParser | 20 from ConfigParser import RawConfigParser |
21 | 21 |
22 USAGE = """ | 22 USAGE = """ |
23 A dependencies file should look like this: | 23 A dependencies file should look like this: |
24 | 24 |
25 # VCS-specific root URLs for the repositories | 25 # VCS-specific root URLs for the repositories |
26 _root = hg:https://hg.adblockplus.org/ git:https://github.com/adblockplus/ | 26 _root = hg:https://hg.adblockplus.org/ git:https://github.com/adblockplus/ |
27 # File to update this script from (optional) | 27 # File to update this script from (optional) |
28 _self = buildtools/ensure_dependencies.py | 28 _self = buildtools/ensure_dependencies.py |
29 # Check out elemhidehelper repository into extensions/elemhidehelper directory | 29 # Clone elemhidehelper repository into extensions/elemhidehelper directory at |
30 # at tag "1.2". | 30 # tag "1.2". |
31 extensions/elemhidehelper = elemhidehelper 1.2 | 31 extensions/elemhidehelper = elemhidehelper 1.2 |
32 # Check out buildtools repository into buildtools directory at VCS-specific | 32 # Clone buildtools repository into buildtools directory at VCS-specific |
33 # revision IDs. | 33 # revision IDs. |
34 buildtools = buildtools hg:016d16f7137b git:f3f8692f82e5 | 34 buildtools = buildtools hg:016d16f7137b git:f3f8692f82e5 |
35 # Check out the adblockplus repository into adblockplus directory, overwriting | 35 # Clone the adblockplus repository into adblockplus directory, overwriting the |
Sebastian Noack
2015/10/15 15:19:41
Nit: "Check out" isn't hg/git terminology.
kzar
2015/10/15 16:12:25
Done.
| |
36 # the usual source URL for Git repository and specifying VCS specific revision | 36 # usual source URL for Git repository and specifying VCS specific revision IDs . |
37 # IDs. | 37 adblockplus = adblockplus hg:893426c6a6ab git:git@github.com:user/adblockplus. git@b2ffd52b |
38 adblockplus = adblockplus hg:893426c6a6ab git:git@github.com:kzar/adblockplus. git@b2ffd52b | 38 # Clone the adblockpluschrome repository into the adblockpluschrome directory, |
39 # Check out the adblockpluschrome repository into the adblockpluschrome | 39 # from a specific Git repository, specifying the revision ID. |
40 # directory, from a specific Git repository, specifying the revision ID. | 40 adblockpluschrome = git:git@github.com:user/adblockpluschrome.git@1fad3a7 |
41 adblockpluschrome = git:git@github.com:kzar/adblockpluschrome.git@1fad3a7 | |
42 """ | 41 """ |
43 | 42 |
44 SKIP_DEPENDENCY_UPDATES = os.environ.get( | 43 SKIP_DEPENDENCY_UPDATES = os.environ.get( |
45 "SKIP_DEPENDENCY_UPDATES", "" | 44 "SKIP_DEPENDENCY_UPDATES", "" |
46 ).lower() not in ("", "0", "false") | 45 ).lower() not in ("", "0", "false") |
47 | 46 |
48 class Mercurial(): | 47 class Mercurial(): |
49 def istype(self, repodir): | 48 def istype(self, repodir): |
50 return os.path.exists(os.path.join(repodir, ".hg")) | 49 return os.path.exists(os.path.join(repodir, ".hg")) |
51 | 50 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
137 return "ssh://" + url.replace(":", "/", 1) | 136 return "ssh://" + url.replace(":", "/", 1) |
138 return url | 137 return url |
139 | 138 |
140 repo_types = OrderedDict(( | 139 repo_types = OrderedDict(( |
141 ("hg", Mercurial()), | 140 ("hg", Mercurial()), |
142 ("git", Git()), | 141 ("git", Git()), |
143 )) | 142 )) |
144 | 143 |
145 # [vcs:]value | 144 # [vcs:]value |
146 item_regexp = re.compile( | 145 item_regexp = re.compile( |
147 "^(?:(" + "|".join(repo_types.keys()) +"):)?" | 146 "^(?:(" + "|".join(map(re.escape, repo_types.keys())) +"):)?" |
148 "(.+)$" | 147 "(.+)$" |
149 ) | 148 ) |
150 | 149 |
151 # [url@]rev | 150 # [url@]rev |
152 source_regexp = re.compile( | 151 source_regexp = re.compile( |
153 "^(?:(.*)@)?" | 152 "^(?:(.*)@)?" |
154 "(.+)$" | 153 "(.+)$" |
155 ) | 154 ) |
156 | 155 |
157 def merge_tuples(tuple_1, tuple_2): | 156 def merge_seqs(seq1, seq2): |
158 """Return tuple containing any truthy values from the suplied tuples | 157 """Return a list of any truthy values from the suplied sequences |
159 | 158 |
160 (None, 2), (1,) => (1, 2) | 159 (None, 2), (1,) => [1, 2] |
161 None, (1, 2) => (1, 2) | 160 None, (1, 2) => [1, 2] |
162 (1, 2), (3, 4) => (3, 4) | 161 (1, 2), (3, 4) => [3, 4] |
163 """ | 162 """ |
164 return tuple(i2 or i1 for i1, i2 in map(None, tuple_1 or (), tuple_2 or ())) | 163 return map(lambda item1, item2: item2 or item1, seq1 or (), seq2 or ()) |
165 | 164 |
166 def parse_spec(path, line): | 165 def parse_spec(path, line): |
167 if "=" not in line: | 166 if "=" not in line: |
168 logging.warning("Invalid line in file %s: %s" % (path, line)) | 167 logging.warning("Invalid line in file %s: %s" % (path, line)) |
169 return None, None | 168 return None, None |
170 | 169 |
171 key, value = line.split("=", 1) | 170 key, value = line.split("=", 1) |
172 key = key.strip() | 171 key = key.strip() |
173 items = value.split() | 172 items = value.split() |
174 if not len(items): | 173 if not len(items): |
175 logging.warning("No value specified for key %s in file %s" % (key, path)) | 174 logging.warning("No value specified for key %s in file %s" % (key, path)) |
176 return key, None | 175 return key, None |
177 | 176 |
178 result = OrderedDict() | 177 result = OrderedDict() |
179 is_dependency_field = not key.startswith("_") | 178 is_dependency_field = not key.startswith("_") |
180 | 179 |
181 for i, item in enumerate(items): | 180 for i, item in enumerate(items): |
182 try: | 181 try: |
183 vcs, value = re.match(item_regexp, item).groups() | 182 vcs, value = re.search(item_regexp, item).groups() |
184 vcs = vcs or "*" | 183 vcs = vcs or "*" |
185 if is_dependency_field: | 184 if is_dependency_field: |
186 if i == 0 and vcs == "*": | 185 if i == 0 and vcs == "*": |
187 # In order to be backwards compatible we have to assume that the first | 186 # In order to be backwards compatible we have to assume that the first |
188 # source contains only a URL/path for the repo if it does not contain | 187 # source contains only a URL/path for the repo if it does not contain |
189 # the VCS part | 188 # the VCS part |
190 url_rev = (value, None) | 189 url_rev = (value, None) |
191 else: | 190 else: |
192 url_rev = re.match(source_regexp, value).groups() | 191 url_rev = re.search(source_regexp, value).groups() |
Sebastian Noack
2015/10/15 15:19:41
We decided a while ago to not use .match() anymore
kzar
2015/10/15 16:12:25
Done.
| |
193 result[vcs] = merge_tuples(result.get(vcs), url_rev) | 192 result[vcs] = merge_seqs(result.get(vcs), url_rev) |
194 else: | 193 else: |
195 if vcs in result: | 194 if vcs in result: |
196 logging.warning("Ignoring duplicate value for type %s" | 195 logging.warning("Ignoring duplicate value for type %r " |
197 "(key %s in file %s)" % (vcs, key, path)) | 196 "(key %r in file %r)" % (vcs, key, path)) |
198 result[vcs] = value | 197 result[vcs] = value |
199 except AttributeError: | 198 except AttributeError: |
200 logging.warning("Ignoring invalid item '%s' for type %s" | 199 logging.warning("Ignoring invalid item %r for type %r " |
Sebastian Noack
2015/10/15 15:19:41
How about using %r instead '%s'?
kzar
2015/10/15 16:12:25
(Some further testing showed it's clearer if all t
| |
201 "(key %s in file %s)" % (item, vcs, key, path)) | 200 "(key %r in file %r)" % (item, vcs, key, path)) |
202 continue | 201 continue |
203 return key, result | 202 return key, result |
204 | 203 |
205 def read_deps(repodir): | 204 def read_deps(repodir): |
206 result = {} | 205 result = {} |
207 deps_path = os.path.join(repodir, "dependencies") | 206 deps_path = os.path.join(repodir, "dependencies") |
208 try: | 207 try: |
209 with io.open(deps_path, "rt", encoding="utf-8") as handle: | 208 with io.open(deps_path, "rt", encoding="utf-8") as handle: |
210 for line in handle: | 209 for line in handle: |
211 # Remove comments and whitespace | 210 # Remove comments and whitespace |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
301 skipdependencies.intersection([s[0] for s in sources if s[0]])): | 300 skipdependencies.intersection([s[0] for s in sources if s[0]])): |
302 continue | 301 continue |
303 | 302 |
304 target = safe_join(repodir, dir) | 303 target = safe_join(repodir, dir) |
305 parenttype = get_repo_type(repodir) | 304 parenttype = get_repo_type(repodir) |
306 _root = config.get("_root", {}) | 305 _root = config.get("_root", {}) |
307 | 306 |
308 for key in sources.keys() + _root.keys(): | 307 for key in sources.keys() + _root.keys(): |
309 if key == parenttype or key is None and vcs != "*": | 308 if key == parenttype or key is None and vcs != "*": |
310 vcs = key | 309 vcs = key |
311 source, rev = merge_tuples(sources.get("*"), sources.get(vcs)) | 310 source, rev = merge_seqs(sources.get("*"), sources.get(vcs)) |
312 | 311 |
313 if not (vcs and source and rev): | 312 if not (vcs and source and rev): |
314 logging.warning("No valid source / revision found to create %s" % target) | 313 logging.warning("No valid source / revision found to create %s" % target) |
315 continue | 314 continue |
316 | 315 |
317 ensure_repo(repodir, parenttype, target, vcs, _root.get(vcs, ""), source) | 316 ensure_repo(repodir, parenttype, target, vcs, _root.get(vcs, ""), source) |
318 update_repo(target, vcs, rev) | 317 update_repo(target, vcs, rev) |
319 resolve_deps(target, level + 1, self_update=False, | 318 resolve_deps(target, level + 1, self_update=False, |
320 overrideroots=overrideroots, skipdependencies=skipdependencies) | 319 overrideroots=overrideroots, skipdependencies=skipdependencies) |
321 | 320 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
363 args = parser.parse_args() | 362 args = parser.parse_args() |
364 | 363 |
365 if args.quiet: | 364 if args.quiet: |
366 logging.disable(logging.INFO) | 365 logging.disable(logging.INFO) |
367 | 366 |
368 repos = args.repos | 367 repos = args.repos |
369 if not len(repos): | 368 if not len(repos): |
370 repos = [os.path.dirname(__file__)] | 369 repos = [os.path.dirname(__file__)] |
371 for repo in repos: | 370 for repo in repos: |
372 resolve_deps(repo) | 371 resolve_deps(repo) |
LEFT | RIGHT |