blob: 02dcdeaf97ca8f86211d1d4ac770434c497ed47a [file] [log] [blame]
Liviu Rau3f146242022-02-23 11:48:281#!/usr/bin/env vpython3
Mathias Bynens8555df02020-04-27 14:19:062#
Yang Guo4fd355c2019-09-19 08:59:033# Copyright 2019 The Chromium Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""
Alex Rudenko2e1b8ab2024-04-16 19:23:327Use this script to update node_modules instead of
Peter Marshall9c4cbce2020-07-06 07:36:548running npm install manually. To upgrade a dependency, change the version
Alex Rudenko2e1b8ab2024-04-16 19:23:329number in package.json below and run this script, which can be done with `npm run
Jack Franklincc58dfa2022-11-29 10:08:1410install-deps` locally.
Yang Guo4fd355c2019-09-19 08:59:0311"""
12
13import os
14import os.path as path
Yang Guo4fd355c2019-09-19 08:59:0315import json
Yang Guo91178352019-10-31 07:50:1916import subprocess
17import sys
Tim van der Lippe6d109a92021-02-16 16:00:3218from collections import OrderedDict
Yang Guo91178352019-10-31 07:50:1919
20scripts_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
21sys.path.append(scripts_path)
22
23import devtools_paths
Yang Guo4fd355c2019-09-19 08:59:0324
Paul Lewise184c4c2019-12-02 12:30:1525LICENSES = [
26 "MIT",
27 "Apache-2.0",
28 "BSD",
29 "BSD-2-Clause",
30 "BSD-3-Clause",
31 "CC0-1.0",
32 "CC-BY-3.0",
Mathias Bynens79e2cf02020-05-29 14:46:1733 "CC-BY-4.0",
Paul Lewise184c4c2019-12-02 12:30:1534 "ISC",
Tim van der Lippe1fe7f952021-01-05 12:41:0635 "MPL-2.0",
Tim van der Lippe6d109a92021-02-16 16:00:3236 "Python-2.0",
Johan Bay0c881d52022-02-01 19:42:4437 "W3C",
Paul Lewise184c4c2019-12-02 12:30:1538]
39
Alex Rudenkod04dd452024-02-27 08:25:3540
Tim van der Lippe6d109a92021-02-16 16:00:3241def load_json_file(location):
42 # By default, json load uses a standard Python dictionary, which is not ordered.
43 # To prevent subsequent invocations of this script to erroneously alter the order
44 # of keys defined in package.json files, we should use an `OrderedDict`. This
45 # ensures not only that we use a strict ordering, it will also make sure we maintain
46 # the order defined by the NPM packages themselves. That in turn is important, since
47 # NPM packages can define `exports`, where the order of entrypoints is crucial for
48 # how an NPM package is loaded. If you would change the order, it could break loading
49 # that package.
50 return json.load(location, object_pairs_hook=OrderedDict)
51
Alex Rudenkod04dd452024-02-27 08:25:3552
Alex Rudenko2e05f8f2024-04-04 10:36:5953DEPS = {}
54
Philip Pfaffe3b208212024-07-31 07:59:1655pkg_file = path.join(devtools_paths.devtools_root_path(), 'package.json')
Alex Rudenko2e05f8f2024-04-04 10:36:5956with open(pkg_file, 'r+') as pkg_file:
57 DEPS = load_json_file(pkg_file)["devDependencies"]
58
Alex Rudenko2e05f8f2024-04-04 10:36:5959
Paul Lewis66e12062019-12-02 12:04:5460def exec_command(cmd):
Yang Guo4fd355c2019-09-19 08:59:0361 try:
Peter Marshall9c4cbce2020-07-06 07:36:5462 new_env = os.environ.copy()
Philip Pfaffe3b208212024-07-31 07:59:1663 cmd_proc_result = subprocess.check_call(
64 cmd, cwd=devtools_paths.devtools_root_path(), env=new_env)
Tim van der Lippe35cca412020-04-06 12:03:3865 except Exception as error:
66 print(error)
Paul Lewis66e12062019-12-02 12:04:5467 return True
68
69 return False
Yang Guo4fd355c2019-09-19 08:59:0370
71
Paul Lewise184c4c2019-12-02 12:30:1572def ensure_licenses():
73 cmd = [
74 devtools_paths.node_path(),
Alex Rudenkod04dd452024-02-27 08:25:3575 devtools_paths.license_checker_path(), '--onlyAllow',
Paul Lewise184c4c2019-12-02 12:30:1576 ('%s' % (';'.join(LICENSES)))
77 ]
78
79 return exec_command(cmd)
80
81
Yang Guo4fd355c2019-09-19 08:59:0382def strip_private_fields():
83 # npm adds private fields which need to be stripped.
Yang Guo4fd355c2019-09-19 08:59:0384 packages = []
Liviu Rau3f146242022-02-23 11:48:2885 for root, _, filenames in os.walk(devtools_paths.node_modules_path()):
86 if 'package.json' in filenames:
87 packages.append(path.join(root, 'package.json'))
Yang Guo4fd355c2019-09-19 08:59:0388
89 for pkg in packages:
90 with open(pkg, 'r+') as pkg_file:
Yang Guo4fd355c2019-09-19 08:59:0391 try:
Tim van der Lippe6d109a92021-02-16 16:00:3292 pkg_data = load_json_file(pkg_file)
Tim van der Lippeece3c512022-03-08 15:07:2893 updated_pkg_data = pkg_data.copy()
Yang Guo4fd355c2019-09-19 08:59:0394
95 # Remove anything that begins with an underscore, as these are
96 # the private fields in a package.json
97 for key in pkg_data.keys():
Liviu Rau3f146242022-02-23 11:48:2898 if key.find('_') == 0:
Tim van der Lippeece3c512022-03-08 15:07:2899 updated_pkg_data.pop(key)
Yang Guo4fd355c2019-09-19 08:59:03100
101 pkg_file.truncate(0)
102 pkg_file.seek(0)
Alex Rudenkod04dd452024-02-27 08:25:35103 json.dump(updated_pkg_data,
104 pkg_file,
105 indent=2,
106 separators=(',', ': '))
Mathias Bynens8604a982020-06-23 06:41:44107 pkg_file.write('\n')
Yang Guo4fd355c2019-09-19 08:59:03108 except:
Tim van der Lippeece3c512022-03-08 15:07:28109 print('Unable to fix: %s, %s' % (pkg, sys.exc_info()))
Yang Guo4fd355c2019-09-19 08:59:03110 return True
111
112 return False
113
114
Paul Lewis75090cf2019-10-25 13:13:11115def remove_package_json_entries():
116 with open(devtools_paths.package_json_path(), 'r+') as pkg_file:
117 try:
Tim van der Lippe6d109a92021-02-16 16:00:32118 pkg_data = load_json_file(pkg_file)
Paul Lewis75090cf2019-10-25 13:13:11119
120 # Remove the dependencies and devDependencies from the root package.json
121 # so that they can't be used to overwrite the node_modules managed by this file.
122 for key in pkg_data.keys():
Alex Rudenko2e05f8f2024-04-04 10:36:59123 if key.find('dependencies') == 0:
Paul Lewis75090cf2019-10-25 13:13:11124 pkg_data.pop(key)
125
126 pkg_file.truncate(0)
127 pkg_file.seek(0)
Tim van der Lippe6d109a92021-02-16 16:00:32128 json.dump(pkg_data, pkg_file, indent=2, separators=(',', ': '))
Mathias Bynens8604a982020-06-23 06:41:44129 pkg_file.write('\n')
Paul Lewis75090cf2019-10-25 13:13:11130 except:
131 print('Unable to fix: %s' % pkg)
132 return True
133 return False
134
135
Tim van der Lippe1511efc2020-03-20 11:57:11136def addClangFormat():
Alex Rudenkod04dd452024-02-27 08:25:35137 with open(path.join(devtools_paths.node_modules_path(), '.clang-format'),
138 'w+') as clang_format_file:
Tim van der Lippe1511efc2020-03-20 11:57:11139 try:
Tim van der Lippe6541ce62020-10-28 10:24:26140 clang_format_file.write('DisableFormat: true\n')
Tim van der Lippe1511efc2020-03-20 11:57:11141 except:
142 print('Unable to write .clang-format file')
143 return True
144 return False
145
146
Tim van der Lipped79d79b2020-05-27 14:55:46147def addOwnersFile():
148 with open(path.join(devtools_paths.node_modules_path(), 'OWNERS'),
149 'w+') as owners_file:
150 try:
Tim van der Lippe2e143872021-04-08 11:56:40151 owners_file.write('file://config/owner/INFRA_OWNERS\n')
Tim van der Lipped79d79b2020-05-27 14:55:46152 except:
153 print('Unable to write OWNERS file')
154 return True
155 return False
156
Alex Rudenkod04dd452024-02-27 08:25:35157
Tim van der Lippe6541ce62020-10-28 10:24:26158def addChromiumReadme():
159 with open(path.join(devtools_paths.node_modules_path(), 'README.chromium'),
160 'w+') as readme_file:
161 try:
Alex Rudenkod04dd452024-02-27 08:25:35162 readme_file.write(
163 'This directory hosts all packages downloaded from NPM that are used in either the build system or infrastructure scripts.\n'
164 )
165 readme_file.write(
166 'If you want to make any changes to this directory, please see "scripts/deps/manage_node_deps.py".\n'
167 )
Tim van der Lippe6541ce62020-10-28 10:24:26168 except:
169 print('Unable to write README.chromium file')
170 return True
171 return False
172
Tim van der Lipped79d79b2020-05-27 14:55:46173
Alex Rudenko2e1b8ab2024-04-16 19:23:32174def run_npm_command():
Paul Lewis66e12062019-12-02 12:04:54175 for (name, version) in DEPS.items():
Liviu Rau3f146242022-02-23 11:48:28176 if (version.find('^') == 0):
Alex Rudenkod04dd452024-02-27 08:25:35177 print(
178 'Versions must be locked to a specific version; remove ^ from the start of the version.'
179 )
Paul Lewis66e12062019-12-02 12:04:54180 return True
Yang Guo4fd355c2019-09-19 08:59:03181
Alex Rudenko2e1b8ab2024-04-16 19:23:32182 # Modern npm versions do not cause extra updates so it is not necessary to run clean install.
183 if exec_command([
184 'npm',
185 'install',
186 ]):
Paul Lewisd9039092019-11-27 17:06:23187 return True
188
Alex Rudenko2e1b8ab2024-04-16 19:23:32189 # To minimize disk usage for Chrome DevTools node_modules, always try to dedupe dependencies.
190 # We need to perform this every time, as the order of dependencies added could lead to a
191 # non-optimal dependency tree, resulting in unnecessary disk usage.
192 if exec_command([
193 'npm',
194 'dedupe',
195 ]):
196 return True
Tim van der Lippe35cca412020-04-06 12:03:38197
198 if remove_package_json_entries():
199 return True
200
Paul Lewis66e12062019-12-02 12:04:54201 if strip_private_fields():
Paul Lewis75090cf2019-10-25 13:13:11202 return True
203
Tim van der Lippe1511efc2020-03-20 11:57:11204 if addClangFormat():
205 return True
206
Tim van der Lipped79d79b2020-05-27 14:55:46207 if addOwnersFile():
208 return True
209
Tim van der Lippe6541ce62020-10-28 10:24:26210 if addChromiumReadme():
211 return True
212
Paul Lewise184c4c2019-12-02 12:30:15213 return ensure_licenses()
Yang Guo4fd355c2019-09-19 08:59:03214
215
Alex Rudenko2e1b8ab2024-04-16 19:23:32216npm_errors_found = run_npm_command()
Yang Guo4fd355c2019-09-19 08:59:03217
218if npm_errors_found:
Tim van der Lippe35cca412020-04-06 12:03:38219 print('npm command failed')
220 exit(1)