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

Unified Diff: ensure_dependencies.py

Issue 29526588: Issue 5559 - include Node.js in ensure_dependencies.py (Closed)
Patch Set: Created Aug. 24, 2017, 11:04 a.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ensure_dependencies.py
diff --git a/ensure_dependencies.py b/ensure_dependencies.py
index 127e300d213dc13d2888e3ccbaa46fabf83e9990..4b2d3463003f34e131153ec70edc05d195e76ee6 100755
--- a/ensure_dependencies.py
+++ b/ensure_dependencies.py
@@ -14,6 +14,7 @@ import logging
import subprocess
import urlparse
import argparse
+import json
from collections import OrderedDict
from ConfigParser import RawConfigParser
@@ -245,6 +246,72 @@ def get_repo_type(repo):
return 'hg'
+def resolve_npm_dependencies(target, vcs):
+ """Install Node.js production-only dependencies if necessary and desired.
+
+ When the target dependency has additional Node.js dependencies declared
+ and when those are outdated (or not installed), run
+ "npm install --only=production" to resolve the declared dependencies.
+
+ Additionally, make sure that any VCS will ignore the installed files
+ from any dependency.
+ Do nothing when the SKIP_DEPENDENCY_UPDATES environment variable is set.
Wladimir Palant 2017/08/24 11:38:12 SKIP_DEPENDENCY_UPDATES should be handled implicit
tlucas 2017/08/24 13:27:54 Acknowledged.
tlucas 2017/08/25 09:55:03 Done.
+
+ Requires Node.js to be installed locally.
+ """
+ try:
+ with open(os.path.join(target, 'package.json'), 'r') as fp:
+ package_data = json.load(fp)
+
+ # In case a package.json does not exist at all or if there are no
+ # production-dependencies declared, we don't need to run npm and can
Wladimir Palant 2017/08/24 11:38:12 Nit: "production dependencies"
tlucas 2017/08/24 13:27:54 Acknowledged.
tlucas 2017/08/25 09:55:03 Done.
+ # bail out early
+ if not package_data.get('dependencies', False):
+ return
+ except IOError:
+ return
+
+ try:
+ subprocess_kwargs = {
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.PIPE,
+ 'cwd': target,
+ }
Wladimir Palant 2017/08/24 11:38:12 I'd rather have the arguments specified in the act
tlucas 2017/08/24 13:27:54 Acknowledged.
tlucas 2017/08/25 09:55:02 Done.
+
+ if subprocess.call(['npm', 'outdated'], **subprocess_kwargs) == 0:
Wladimir Palant 2017/08/24 11:38:12 Given that `npm outdated` hits the network, I'd ra
tlucas 2017/08/24 13:27:54 What do you think about looking for the desired de
Wladimir Palant 2017/08/25 08:10:42 I don't have a packages-lock.json file. There is p
Wladimir Palant 2017/08/25 08:16:58 And that reason is an outdated npm version (was ob
tlucas 2017/08/25 09:55:02 Fair enough - Done
+ return
+
+ if SKIP_DEPENDENCY_UPDATES:
+ logging.warning('SKIP_DEPENDENCY_UPDATES environment variable '
+ 'set, not ensuring Node.js dependencies in %s',
+ target)
+ return
+
+ cmd = ['npm', 'install', '--only=production']
+ npm_process = subprocess.Popen(cmd, **subprocess_kwargs)
+ output, error = npm_process.communicate()
Wladimir Palant 2017/08/24 11:38:12 Better use subprocess.check_output() - this will s
tlucas 2017/08/24 13:27:54 Acknowledged, it should be check_output. Regardi
Wladimir Palant 2017/08/25 08:10:42 npm documentation could definitely be better, but
tlucas 2017/08/25 09:55:03 Yes, this is sufficient (as discussed in irc, stat
+ logging.info('Node.js: ' + output)
Wladimir Palant 2017/08/24 11:38:12 It's npm output, not Node.js. Besides, I doubt tha
tlucas 2017/08/24 13:27:54 Acknowledged.
tlucas 2017/08/25 09:55:02 Done.
+
+ if npm_process.returncode != 0:
+ raise Exception(error)
+
+ # Make sure Node.js related files / folders are ignored by the VCS in
+ # use
+ repo_types[vcs].ignore(
+ os.path.join(target, 'package-lock.json'), target
+ )
Wladimir Palant 2017/08/25 08:16:58 It seems that this file should indeed be committed
tlucas 2017/08/25 09:55:03 Done.
+ repo_types[vcs].ignore(
+ os.path.join(target, 'node_modules'), target
+ )
+ except OSError as e:
+ import errno
+ if e.errno == errno.ENOENT:
+ logging.error('Failed to install Node.js dependencies for %s,'
+ ' please ensure Node.js is installed.', target)
+ else:
+ raise
+
+
def ensure_repo(parentrepo, parenttype, target, type, root, sourcename):
if os.path.exists(target):
return
@@ -322,6 +389,7 @@ def resolve_deps(repodir, level=0, self_update=True, overrideroots=None, skipdep
ensure_repo(repodir, parenttype, target, vcs, _root.get(vcs, ''), source)
update_repo(target, vcs, rev)
+ resolve_npm_dependencies(target, vcs)
Wladimir Palant 2017/08/24 11:38:12 This will be called every time, not merely when th
tlucas 2017/08/24 13:27:54 I thought about this too - but this would require
Wladimir Palant 2017/08/25 08:10:42 The way I see it, this wouldn't normally be an iss
tlucas 2017/08/25 09:55:03 Yes, that sounds reasonable. Done.
resolve_deps(target, level + 1, self_update=False,
overrideroots=overrideroots, skipdependencies=skipdependencies)
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld