Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: ensure_dependencies.py

Issue 29526588: Issue 5559 - include Node.js in ensure_dependencies.py (Closed)
Patch Set: Created Aug. 25, 2017, 10:05 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 2
3 # This Source Code Form is subject to the terms of the Mozilla Public 3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this 4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 6
7 import sys 7 import sys
8 import os 8 import os
9 import posixpath 9 import posixpath
10 import re 10 import re
11 import io 11 import io
12 import errno 12 import errno
13 import logging 13 import logging
14 import subprocess 14 import subprocess
15 import urlparse 15 import urlparse
16 import argparse 16 import argparse
17 import json
17 18
18 from collections import OrderedDict 19 from collections import OrderedDict
19 from ConfigParser import RawConfigParser 20 from ConfigParser import RawConfigParser
20 21
21 USAGE = ''' 22 USAGE = '''
22 A dependencies file should look like this: 23 A dependencies file should look like this:
23 24
24 # VCS-specific root URLs for the repositories 25 # VCS-specific root URLs for the repositories
25 _root = hg:https://hg.adblockplus.org/ git:https://github.com/adblockplus/ 26 _root = hg:https://hg.adblockplus.org/ git:https://github.com/adblockplus/
26 # File to update this script from (optional) 27 # File to update this script from (optional)
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
238 return os.path.join(path, *normpath.split(posixpath.sep)) 239 return os.path.join(path, *normpath.split(posixpath.sep))
239 240
240 241
241 def get_repo_type(repo): 242 def get_repo_type(repo):
242 for name, repotype in repo_types.iteritems(): 243 for name, repotype in repo_types.iteritems():
243 if repotype.istype(repo): 244 if repotype.istype(repo):
244 return name 245 return name
245 return 'hg' 246 return 'hg'
246 247
247 248
249 def resolve_npm_dependencies(target, vcs):
250 """Install Node.js production-only dependencies if necessary and desired.
251
252 When the target dependency has additional Node.js dependencies declared
253 run "npm install --only=production --loglevel=warn" to resolve the declared
254 dependencies.
255
256 Additionally, make sure that any VCS will ignore the installed files.
257
258 Requires Node.js to be installed locally.
259 """
260 try:
261 with open(os.path.join(target, 'package.json'), 'r') as fp:
262 package_data = json.load(fp)
263
264 # In case a package.json does not exist at all or if there are no
265 # production dependencies declared, we don't need to run npm and can
266 # bail out early
Vasily Kuznetsov 2017/08/25 18:37:40 Nit: please add periods to the comments that are c
tlucas 2017/08/28 06:53:16 Done.
267 if not package_data.get('dependencies', False):
268 return
269 except IOError:
270 return
271
272 try:
273 cmd = ['npm', 'install', '--only=production', '--loglevel=warn']
274 subprocess.check_output(cmd, cwd=target)
275
276 # Make sure Node.js related files / folders are ignored by the VCS in
Vasily Kuznetsov 2017/08/25 18:37:40 It seems that this comment is redundant given that
tlucas 2017/08/28 06:53:16 Done.
277 # use
278 repo_types[vcs].ignore(
Vasily Kuznetsov 2017/08/25 18:37:40 Wouldn't this be more readable as one line?
tlucas 2017/08/28 06:53:16 Done.
279 os.path.join(target, 'node_modules'), target
280 )
281 except OSError as e:
282 import errno
283 if e.errno == errno.ENOENT:
284 logging.error('Failed to install Node.js dependencies for %s,'
285 ' please ensure Node.js is installed.', target)
286 else:
287 raise
288
289
248 def ensure_repo(parentrepo, parenttype, target, type, root, sourcename): 290 def ensure_repo(parentrepo, parenttype, target, type, root, sourcename):
249 if os.path.exists(target): 291 if os.path.exists(target):
250 return 292 return False
251 293
252 if SKIP_DEPENDENCY_UPDATES: 294 if SKIP_DEPENDENCY_UPDATES:
253 logging.warning('SKIP_DEPENDENCY_UPDATES environment variable set, ' 295 logging.warning('SKIP_DEPENDENCY_UPDATES environment variable set, '
254 '%s not cloned', target) 296 '%s not cloned', target)
255 return 297 return False
256 298
257 postprocess_url = repo_types[type].postprocess_url 299 postprocess_url = repo_types[type].postprocess_url
258 root = postprocess_url(root) 300 root = postprocess_url(root)
259 sourcename = postprocess_url(sourcename) 301 sourcename = postprocess_url(sourcename)
260 302
261 if os.path.exists(root): 303 if os.path.exists(root):
262 url = os.path.join(root, sourcename) 304 url = os.path.join(root, sourcename)
263 else: 305 else:
264 url = urlparse.urljoin(root, sourcename) 306 url = urlparse.urljoin(root, sourcename)
265 307
266 logging.info('Cloning repository %s into %s' % (url, target)) 308 logging.info('Cloning repository %s into %s' % (url, target))
267 repo_types[type].clone(url, target) 309 repo_types[type].clone(url, target)
268 repo_types[parenttype].ignore(target, parentrepo) 310 repo_types[parenttype].ignore(target, parentrepo)
311 return True
269 312
270 313
271 def update_repo(target, type, revision): 314 def update_repo(target, type, revision):
272 resolved_revision = repo_types[type].get_revision_id(target, revision) 315 resolved_revision = repo_types[type].get_revision_id(target, revision)
273 current_revision = repo_types[type].get_revision_id(target) 316 current_revision = repo_types[type].get_revision_id(target)
274 317
275 if resolved_revision != current_revision: 318 if resolved_revision != current_revision:
276 if SKIP_DEPENDENCY_UPDATES: 319 if SKIP_DEPENDENCY_UPDATES:
277 logging.warning('SKIP_DEPENDENCY_UPDATES environment variable set, ' 320 logging.warning('SKIP_DEPENDENCY_UPDATES environment variable set, '
278 '%s not checked out to %s', target, revision) 321 '%s not checked out to %s', target, revision)
279 return 322 return False
280 323
281 if not resolved_revision: 324 if not resolved_revision:
282 logging.info('Revision %s is unknown, downloading remote changes' % revision) 325 logging.info('Revision %s is unknown, downloading remote changes' % revision)
283 repo_types[type].pull(target) 326 repo_types[type].pull(target)
284 resolved_revision = repo_types[type].get_revision_id(target, revisio n) 327 resolved_revision = repo_types[type].get_revision_id(target, revisio n)
285 if not resolved_revision: 328 if not resolved_revision:
286 raise Exception('Failed to resolve revision %s' % revision) 329 raise Exception('Failed to resolve revision %s' % revision)
287 330
288 logging.info('Updating repository %s to revision %s' % (target, resolved _revision)) 331 logging.info('Updating repository %s to revision %s' % (target, resolved _revision))
289 repo_types[type].update(target, resolved_revision, revision) 332 repo_types[type].update(target, resolved_revision, revision)
333 return True
334 return False
290 335
291 336
292 def resolve_deps(repodir, level=0, self_update=True, overrideroots=None, skipdep endencies=set()): 337 def resolve_deps(repodir, level=0, self_update=True, overrideroots=None, skipdep endencies=set()):
293 config = read_deps(repodir) 338 config = read_deps(repodir)
294 if config is None: 339 if config is None:
295 if level == 0: 340 if level == 0:
296 logging.warning('No dependencies file in directory %s, nothing to do ...\n%s' % (repodir, USAGE)) 341 logging.warning('No dependencies file in directory %s, nothing to do ...\n%s' % (repodir, USAGE))
297 return 342 return
298 if level >= 10: 343 if level >= 10:
299 logging.warning('Too much subrepository nesting, ignoring %s' % repo) 344 logging.warning('Too much subrepository nesting, ignoring %s' % repo)
(...skipping 13 matching lines...) Expand all
313 358
314 for key in sources.keys() + _root.keys(): 359 for key in sources.keys() + _root.keys():
315 if key == parenttype or key is None and vcs != '*': 360 if key == parenttype or key is None and vcs != '*':
316 vcs = key 361 vcs = key
317 source, rev = merge_seqs(sources.get('*'), sources.get(vcs)) 362 source, rev = merge_seqs(sources.get('*'), sources.get(vcs))
318 363
319 if not (vcs and source and rev): 364 if not (vcs and source and rev):
320 logging.warning('No valid source / revision found to create %s' % ta rget) 365 logging.warning('No valid source / revision found to create %s' % ta rget)
321 continue 366 continue
322 367
323 ensure_repo(repodir, parenttype, target, vcs, _root.get(vcs, ''), source ) 368 repo_cloned = ensure_repo(repodir, parenttype, target, vcs,
324 update_repo(target, vcs, rev) 369 _root.get(vcs, ''), source)
370 repo_updated = update_repo(target, vcs, rev)
371 if repo_cloned or repo_updated:
372 resolve_npm_dependencies(target, vcs)
325 resolve_deps(target, level + 1, self_update=False, 373 resolve_deps(target, level + 1, self_update=False,
326 overrideroots=overrideroots, skipdependencies=skipdependenc ies) 374 overrideroots=overrideroots, skipdependencies=skipdependenc ies)
327 375
328 if self_update and '_self' in config and '*' in config['_self']: 376 if self_update and '_self' in config and '*' in config['_self']:
329 source = safe_join(repodir, config['_self']['*']) 377 source = safe_join(repodir, config['_self']['*'])
330 try: 378 try:
331 with io.open(source, 'rb') as handle: 379 with io.open(source, 'rb') as handle:
332 sourcedata = handle.read() 380 sourcedata = handle.read()
333 except IOError as e: 381 except IOError as e:
334 if e.errno != errno.ENOENT: 382 if e.errno != errno.ENOENT:
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
371 args = parser.parse_args() 419 args = parser.parse_args()
372 420
373 if args.quiet: 421 if args.quiet:
374 logging.disable(logging.INFO) 422 logging.disable(logging.INFO)
375 423
376 repos = args.repos 424 repos = args.repos
377 if not len(repos): 425 if not len(repos):
378 repos = [os.path.dirname(__file__)] 426 repos = [os.path.dirname(__file__)]
379 for repo in repos: 427 for repo in repos:
380 resolve_deps(repo) 428 resolve_deps(repo)
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld