ui: s/npm/pnpm pnpm is alternative to npm which is faster and more robust clean install-build-deps: >1min -> 10s incremental install-build-deps: >1min -> 1s In the same CL upgrade a few packages and fix some issues this exposed. Before: $ rm -rf ui/node_modules/ $ time ./tools/install-build-deps --ui ...snip... ________________________________________________________ Executed in 54.28 secs fish external usr time 47.01 secs 0.23 millis 47.01 secs sys time 9.37 secs 1.89 millis 9.37 secs $ time ./tools/install-build-deps --ui ________________________________________________________ Executed in 55.84 secs fish external usr time 47.39 secs 0.22 millis 47.39 secs sys time 12.10 secs 2.63 millis 12.10 secs After: $ rm -rf ui/node_modules/ $ time ./tools/install-build-deps --ui ________________________________________________________ Executed in 9.32 secs fish external usr time 3.09 secs 0.24 millis 3.09 secs sys time 11.04 secs 3.03 millis 11.04 secs $ time ./tools/install-build-deps --ui INFO:root:Running `pnpm install --frozen-lockfile` in /Users/hjd/src/perfetto/ui Lockfile is up to date, resolution step is skipped Packages: +1 + Progress: resolved 1, reused 0, downloaded 1, added 1, done Done in 365ms ________________________________________________________ Executed in 1.08 secs fish external usr time 1.06 secs 0.25 millis 1.06 secs sys time 0.81 secs 2.95 millis 0.81 secs Change-Id: I7db03ab99132a2f34307051eba301d8ad6d59d2f
diff --git a/tools/install-build-deps b/tools/install-build-deps index 50cb1ae..adcf3e5 100755 --- a/tools/install-build-deps +++ b/tools/install-build-deps
@@ -383,7 +383,28 @@ Dependency( 'buildtools/typefaces.tgz', 'https://storage.googleapis.com/perfetto/typefaces-%s.tar.gz' % - TYPEFACES_SHA256, TYPEFACES_SHA256, 'all', 'all') + TYPEFACES_SHA256, TYPEFACES_SHA256, 'all', 'all'), + + Dependency( + 'third_party/pnpm/pnpm', + 'https://storage.googleapis.com/perfetto/pnpm-linux-arm64-8.6.3', + 'ac76e9ab6a770479f93c1a2bf978d72636dbcb02608554378cf30075a78a22ac', + 'linux', 'arm64'), + Dependency( + 'third_party/pnpm/pnpm', + 'https://storage.googleapis.com/perfetto/pnpm-linux-x64-8.6.3', + '5a58ccd78d44faac138d901976a7a8917c0f2a2f83743cfdd895fcd0bb6aa135', + 'linux', 'x64'), + Dependency( + 'third_party/pnpm/pnpm', + 'https://storage.googleapis.com/perfetto/pnpm-macos-arm64-8.6.3', + 'f527713d3183e30cfbfd7fd6403ceed730831c53649e50c979961eab3b2cf866', + 'darwin', 'arm64'), + Dependency( + 'third_party/pnpm/pnpm', + 'https://storage.googleapis.com/perfetto/pnpm-macos-x64-8.6.3', + '6b425f7f0342341e9ee9427a9a2be2c89936c4a04efe6125f7af667eb02b10c1', + 'darwin', 'x64'), ] # Dependencies to build gRPC. @@ -538,29 +559,35 @@ logging.info('Clearing %s', node_modules) subprocess.check_call(['git', 'clean', '-qxffd', node_modules], cwd=ROOT_DIR) - logging.info("Running `npm ci` in {0}".format(UI_DIR)) - # `npm ci` is like `npm install` but respects package-lock.json. - subprocess.check_call([os.path.join(TOOLS_DIR, 'npm'), 'ci'], cwd=UI_DIR) + logging.info("Running `pnpm install --frozen-lockfile` in {0}".format(UI_DIR)) + + # Some node modules have postinstall scripts (already bad) but worse + # sometimes they are in the form: "postinstall: 'node ./scripts/foo'" + # so here we need to ensure that our hermetic node is available in + # PATH. + env = os.environ.copy() + env['PATH'] = TOOLS_DIR + ':' + env['PATH'] + + subprocess.check_call([os.path.join(TOOLS_DIR, 'pnpm'), 'install', '--frozen-lockfile'], cwd=UI_DIR, env=env) # pbjs has the bad habit of installing extra packages on its first run. Run # it here, so we avoid fetches while building. - node_bin = os.path.join(TOOLS_DIR, 'node') - pbjs = [node_bin, 'node_modules/.bin/pbjs', '/dev/null', '-o', '/dev/null'] - subprocess.call(pbjs, cwd=UI_DIR) + pbjs = ['node_modules/.bin/pbjs', '/dev/null', '-o', '/dev/null'] + subprocess.call(pbjs, cwd=UI_DIR, env=env) with open(NODE_MODULES_STATUS_FILE, 'w') as f: - f.write(HashLocalFile(os.path.join(UI_DIR, 'package-lock.json'))) + f.write(HashLocalFile(os.path.join(UI_DIR, 'pnpm-lock.yaml'))) def CheckNodeModules(): """Returns True if the modules are up-to-date. There doesn't seem to be an easy way to check node modules versions. Instead - just check if package-lock.json changed since the last `npm install` call. + just check if pnpm-lock.json changed since the last `pnpm install` call. """ if not os.path.exists(NODE_MODULES_STATUS_FILE): return False with open(NODE_MODULES_STATUS_FILE, 'r') as f: actual = f.read() - expected = HashLocalFile(os.path.join(UI_DIR, 'package-lock.json')) + expected = HashLocalFile(os.path.join(UI_DIR, 'pnpm-lock.yaml')) return expected == actual
diff --git a/tools/pnpm b/tools/pnpm new file mode 100755 index 0000000..34fce7f --- /dev/null +++ b/tools/pnpm
@@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import sys + +ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.append(ROOT_DIR) +__package__ = 'tools' +from .run_buildtools_binary import run_buildtools_binary +run_buildtools_binary(['pnpm'] + sys.argv[1:])