From ec56ad9e70635e94206f7035c81378c8bd820201 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 3 Oct 2019 18:47:56 +0200 Subject: [PATCH 1/3] chore: use new parallel build feature of jsii Improve build times by using the new "build-all-at-once" feature of jsii-pacmak. Goes together with https://github.com/aws/jsii/pull/849. --- pack.sh | 34 ++++++++++++++++++++++++++-------- package.json | 1 + scripts/list-packages | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 8 deletions(-) create mode 100755 scripts/list-packages diff --git a/pack.sh b/pack.sh index bf3daa10097c4..e0f5e36124d64 100755 --- a/pack.sh +++ b/pack.sh @@ -2,7 +2,7 @@ # Runs "npm package" in all modules. This will produce a "dist/" directory in each module. # Then, calls pack-collect.sh to merge all outputs into a root ./pack directory, which is # later read by bundle-beta.sh. -set -e +set -eu export PATH=$PWD/node_modules/.bin:$PATH export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" root=$PWD @@ -11,15 +11,33 @@ distdir="$PWD/dist" rm -fr ${distdir} mkdir -p ${distdir} -scopes=$(lerna ls 2>/dev/null | grep -v "(private)" | cut -d" " -f1 | xargs -n1 -I{} echo "--scope {}" | tr "\n" " ") +# Split out jsii and non-jsii packages. Jsii packages will be built all at once. +# Non-jsii packages will be run individually. +echo "Collecting package list..." >&2 +scripts/list-packages $TMPDIR/jsii.txt $TMPDIR/nonjsii.txt -# Run the "cdk-package" script in all modules. For jsii modules, this invokes jsii-pacmak which generates and builds multi-language -# outputs. For non-jsii module, it will just run "npm pack" and place the output in dist/npm -# (which is similar to how pacmak outputs it). -lerna run ${scopes} --sort --concurrency=1 --stream package +# Return lerna scopes from a package list +function lerna_scopes() { + while [[ "${1:-}" != "" ]]; do + echo "--scope $1 " + shift + done +} + +echo "Packaging jsii modules" >&2 + +# Jsii packaging (all at once using jsii-pacmak) +jsii-pacmak \ + --verbose \ + --outdir $distdir/ \ + $(cat $TMPDIR/jsii.txt) + +# Non-jsii packaging, which means running 'package' in every individual +# module and rsync'ing the result to the shared dist directory. +echo "Packaging non-jsii modules" >&2 +lerna run $(lerna_scopes $(cat $TMPDIR/nonjsii.txt)) --sort --concurrency=1 --stream package -# Collect dist/ from all modules into the root dist/ -for dir in $(find packages -name dist | grep -v node_modules); do +for dir in $(find packages -name dist | grep -v node_modules | grep -v run-wrappers); do echo "Merging ${dir} into ${distdir}" rsync -av $dir/ ${distdir}/ done diff --git a/package.json b/package.json index e911d1660136a..606d3842d66a3 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "fs-extra": "^8.1.0", "jest": "^24.9.0", "jsii-diff": "^0.17.1", + "jsii-pacmak": "^0.17.1", "lerna": "^3.16.4", "nodeunit": "^0.11.3", "nyc": "^14.1.1", diff --git a/scripts/list-packages b/scripts/list-packages new file mode 100755 index 0000000000000..cd4e5a897b054 --- /dev/null +++ b/scripts/list-packages @@ -0,0 +1,36 @@ +#!/usr/bin/env node +/** + * Collects all packages in the repository in a way that makes it + * easy to process for packaging. + */ +const child_process = require('child_process'); +const fs = require('fs-extra'); +const path = require('path'); + +if (process.argv.length < 4) { + process.stderr.write('Usage: list-packages \n'); + process.exit(1); +} + +child_process.exec('lerna ls --json', { shell: true }, (error, stdout) => { + if (error) { + console.error('Error: ', error); + process.exit(-1); + } + const modules = JSON.parse(stdout.toString('utf8')); + + const jsiiDirectories = []; + const nonJsiiNames = []; + + for (const module of modules) { + const pkgJson = require(path.join(module.location, 'package.json')); + if (pkgJson.jsii) { + jsiiDirectories.push(module.location); + } else { + nonJsiiNames.push(pkgJson.name); + } + } + + fs.writeFileSync(process.argv[2], jsiiDirectories.join('\n')); + fs.writeFileSync(process.argv[3], nonJsiiNames.join('\n')); +}); From d8377d98c006101bd0401e1f896070ec3ec17071 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 31 Oct 2019 17:08:57 +0100 Subject: [PATCH 2/3] Default TMPDIR to the right directory --- pack.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/pack.sh b/pack.sh index e0f5e36124d64..2bc4335b5c155 100755 --- a/pack.sh +++ b/pack.sh @@ -7,6 +7,7 @@ export PATH=$PWD/node_modules/.bin:$PATH export NODE_OPTIONS="--max-old-space-size=4096 ${NODE_OPTIONS:-}" root=$PWD +TMPDIR=${TMPDIR:-$(dirname $(mktemp -u))} distdir="$PWD/dist" rm -fr ${distdir} mkdir -p ${distdir} From 4e67326706293fb03d24ece6e52460a2dff7759e Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 31 Oct 2019 17:25:58 +0100 Subject: [PATCH 3/3] Speed up API compatibility check --- scripts/check-api-compatibility.sh | 69 +++++++++++++++++++----------- 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/scripts/check-api-compatibility.sh b/scripts/check-api-compatibility.sh index 1b3921021e68d..f73702b61c639 100755 --- a/scripts/check-api-compatibility.sh +++ b/scripts/check-api-compatibility.sh @@ -9,38 +9,56 @@ package_name() { node -pe "require('$1/package.json').name" } +# Determine whether an NPM package exists on NPM +# +# Doesn't use 'npm view' as that is slow. Direct curl'ing npmjs is better +package_exists_on_npm() { + curl -I 2>/dev/null https://registry.npmjs.org/$1 | head -n 1 | grep 200 >/dev/null +} + + #---------------------------------------------------------------------- -echo "Listing packages..." >&2 -package_dirs=() -package_names=() -for dir in $(npx lerna ls -p); do - if [[ -f $dir/.jsii ]]; then - package_dirs+=("$dir") - package_names+=("$(package_name $dir)") - fi -done +list_jsii_packages() { + echo "Listing jsii packages..." >&2 + for dir in $(npx lerna ls -p); do + if [[ -f $dir/.jsii ]]; then + echo "$dir" + fi + done +} +jsii_package_dirs=$(list_jsii_packages) #---------------------------------------------------------------------- +# Input a directory, output the package name IF it exists on GitHub +dirs_to_existing_names() { + local dir="$1" + local name=$(package_name "$dir") + if package_exists_on_npm $name; then + echo "$name" + echo -n "." >&2 + else + echo -n "x" >&2 + fi +} + +export -f package_name +export -f package_exists_on_npm +export -f dirs_to_existing_names + + if ! ${SKIP_DOWNLOAD:-false}; then echo "Filtering on existing packages on NPM..." >&2 - for i in ${!package_dirs[@]}; do - echo -n "${package_names[$i]}... " - if npm view --loglevel silent ${package_names[$i]} > /dev/null; then - echo "Exists." - else - echo "NEW." - unset 'package_names[i]' - unset 'package_dirs[i]' - fi - done + # In parallel + existing_names=$(echo "$jsii_package_dirs" | xargs -n1 -P4 -I {} bash -c 'dirs_to_existing_names "$@"' _ {}) + echo " Done." >&2 rm -rf $tmpdir mkdir -p $tmpdir echo "Installing from NPM..." >&2 - (cd $tmpdir && npm install --prefix $tmpdir ${package_names[@]}) + (cd $tmpdir && npm install --prefix $tmpdir $existing_names) fi #---------------------------------------------------------------------- @@ -50,14 +68,15 @@ current_version=$(npx lerna ls -pl | head -n 1 | cut -d ':' -f 3) echo "Checking compatibility..." >&2 success=true -for i in ${!package_dirs[*]}; do - if [[ ! -d $tmpdir/node_modules/${package_names[$i]} ]]; then continue; fi - echo -n "${package_names[$i]}... " +for dir in $jsii_package_dirs; do + name=$(package_name "$dir") + if [[ ! -d $tmpdir/node_modules/$name ]]; then continue; fi + echo -n "$name... " if npx jsii-diff \ --keys \ --ignore-file ${repo_root}/allowed-breaking-changes.txt \ - $tmpdir/node_modules/${package_names[$i]} \ - ${package_dirs[$i]} \ + $tmpdir/node_modules/$name \ + $dir \ 2>$tmpdir/output.txt; then echo "OK." else