@aws-cdk-testing/cli-integ 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +9 -0
- package/LICENSE +202 -0
- package/NOTICE +16 -0
- package/README.md +205 -0
- package/bin/apply-patches +22 -0
- package/bin/download-and-run-old-tests +52 -0
- package/bin/query-github +2 -0
- package/bin/query-github.d.ts +1 -0
- package/bin/query-github.js +54 -0
- package/bin/query-github.ts +56 -0
- package/bin/run-suite +2 -0
- package/bin/run-suite.d.ts +1 -0
- package/bin/run-suite.js +131 -0
- package/bin/run-suite.ts +140 -0
- package/bin/stage-distribution +2 -0
- package/bin/stage-distribution.d.ts +1 -0
- package/bin/stage-distribution.js +217 -0
- package/bin/stage-distribution.ts +267 -0
- package/bin/test-root +2 -0
- package/bin/test-root.d.ts +1 -0
- package/bin/test-root.js +6 -0
- package/bin/test-root.ts +3 -0
- package/entrypoints/test-cli-regression-against-current-code.sh +11 -0
- package/entrypoints/test-cli-regression-against-latest-release.sh +11 -0
- package/entrypoints/test-cli-regression.bash +83 -0
- package/entrypoints/test.sh +12 -0
- package/lib/aws.d.ts +51 -0
- package/lib/aws.js +206 -0
- package/lib/aws.ts +263 -0
- package/lib/corking.d.ts +12 -0
- package/lib/corking.js +35 -0
- package/lib/corking.ts +33 -0
- package/lib/eventually.d.ts +20 -0
- package/lib/eventually.js +34 -0
- package/lib/eventually.ts +42 -0
- package/lib/files.d.ts +15 -0
- package/lib/files.js +80 -0
- package/lib/files.ts +80 -0
- package/lib/github.d.ts +4 -0
- package/lib/github.js +43 -0
- package/lib/github.ts +43 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +30 -0
- package/lib/index.ts +13 -0
- package/lib/integ-test.d.ts +10 -0
- package/lib/integ-test.js +70 -0
- package/lib/integ-test.ts +81 -0
- package/lib/lists.d.ts +1 -0
- package/lib/lists.js +11 -0
- package/lib/lists.ts +9 -0
- package/lib/memoize.d.ts +6 -0
- package/lib/memoize.js +18 -0
- package/lib/memoize.ts +14 -0
- package/lib/npm.d.ts +8 -0
- package/lib/npm.js +38 -0
- package/lib/npm.ts +41 -0
- package/lib/package-sources/release-source.d.ts +23 -0
- package/lib/package-sources/release-source.js +71 -0
- package/lib/package-sources/release-source.ts +81 -0
- package/lib/package-sources/repo-source.d.ts +30 -0
- package/lib/package-sources/repo-source.js +97 -0
- package/lib/package-sources/repo-source.ts +111 -0
- package/lib/package-sources/repo-tools/npm +2 -0
- package/lib/package-sources/repo-tools/npm.d.ts +1 -0
- package/lib/package-sources/repo-tools/npm.js +43 -0
- package/lib/package-sources/repo-tools/npm.ts +48 -0
- package/lib/package-sources/source.d.ts +28 -0
- package/lib/package-sources/source.js +3 -0
- package/lib/package-sources/source.ts +35 -0
- package/lib/package-sources/subprocess.d.ts +3 -0
- package/lib/package-sources/subprocess.js +17 -0
- package/lib/package-sources/subprocess.ts +15 -0
- package/lib/resource-pool.d.ts +50 -0
- package/lib/resource-pool.js +117 -0
- package/lib/resource-pool.ts +140 -0
- package/lib/resources.d.ts +1 -0
- package/lib/resources.js +6 -0
- package/lib/resources.ts +4 -0
- package/lib/shell.d.ts +56 -0
- package/lib/shell.js +123 -0
- package/lib/shell.ts +168 -0
- package/lib/staging/codeartifact.d.ts +44 -0
- package/lib/staging/codeartifact.js +281 -0
- package/lib/staging/codeartifact.ts +387 -0
- package/lib/staging/maven.d.ts +5 -0
- package/lib/staging/maven.js +91 -0
- package/lib/staging/maven.ts +95 -0
- package/lib/staging/npm.d.ts +4 -0
- package/lib/staging/npm.js +55 -0
- package/lib/staging/npm.ts +62 -0
- package/lib/staging/nuget.d.ts +4 -0
- package/lib/staging/nuget.js +69 -0
- package/lib/staging/nuget.ts +75 -0
- package/lib/staging/parallel-shell.d.ts +5 -0
- package/lib/staging/parallel-shell.js +45 -0
- package/lib/staging/parallel-shell.ts +51 -0
- package/lib/staging/pypi.d.ts +4 -0
- package/lib/staging/pypi.js +48 -0
- package/lib/staging/pypi.ts +50 -0
- package/lib/staging/usage-dir.d.ts +31 -0
- package/lib/staging/usage-dir.js +87 -0
- package/lib/staging/usage-dir.ts +99 -0
- package/lib/with-aws.d.ts +14 -0
- package/lib/with-aws.js +60 -0
- package/lib/with-aws.ts +67 -0
- package/lib/with-cdk-app.d.ts +210 -0
- package/lib/with-cdk-app.js +539 -0
- package/lib/with-cdk-app.ts +742 -0
- package/lib/with-cli-lib.d.ts +17 -0
- package/lib/with-cli-lib.js +123 -0
- package/lib/with-cli-lib.ts +134 -0
- package/lib/with-packages.d.ts +5 -0
- package/lib/with-packages.js +13 -0
- package/lib/with-packages.ts +15 -0
- package/lib/with-sam.d.ts +33 -0
- package/lib/with-sam.js +258 -0
- package/lib/with-sam.ts +288 -0
- package/lib/with-temporary-directory.d.ts +5 -0
- package/lib/with-temporary-directory.js +31 -0
- package/lib/with-temporary-directory.ts +35 -0
- package/lib/with-timeout.d.ts +19 -0
- package/lib/with-timeout.js +34 -0
- package/lib/with-timeout.ts +33 -0
- package/lib/xpmutex.d.ts +43 -0
- package/lib/xpmutex.js +207 -0
- package/lib/xpmutex.ts +218 -0
- package/package.json +111 -0
- package/resources/bootstrap-templates/session-tags.all-roles-deny-all.yaml +703 -0
- package/resources/bootstrap-templates/session-tags.deploy-role-deny-sqs.yaml +700 -0
- package/resources/cdk-apps/app/app.js +926 -0
- package/resources/cdk-apps/app/appsync.hotswap.graphql +3 -0
- package/resources/cdk-apps/app/cdk.json +7 -0
- package/resources/cdk-apps/app/docker/Dockerfile +2 -0
- package/resources/cdk-apps/app/docker/Dockerfile.Custom +2 -0
- package/resources/cdk-apps/app/lambda/index.js +4 -0
- package/resources/cdk-apps/app/lambda/response.json +3 -0
- package/resources/cdk-apps/app/nested-stack.js +65 -0
- package/resources/cdk-apps/cfn-include-app/cdk.json +4 -0
- package/resources/cdk-apps/cfn-include-app/cfn-include-app.js +21 -0
- package/resources/cdk-apps/cfn-include-app/example-template.json +13 -0
- package/resources/cdk-apps/rollback-test-app/app.js +110 -0
- package/resources/cdk-apps/rollback-test-app/cdk.json +7 -0
- package/resources/cdk-apps/sam_cdk_integ_app/bin/test-app.js +11 -0
- package/resources/cdk-apps/sam_cdk_integ_app/cdk.json +6 -0
- package/resources/cdk-apps/sam_cdk_integ_app/lib/nested-stack.js +19 -0
- package/resources/cdk-apps/sam_cdk_integ_app/lib/test-stack.js +134 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/docker/DockerImageFunctionConstruct/.no-packagejson-validator +0 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/docker/DockerImageFunctionConstruct/Dockerfile +9 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/docker/DockerImageFunctionConstruct/app.js +22 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/docker/DockerImageFunctionConstruct/package.json +18 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/go/GoFunctionConstruct/go.mod +5 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/go/GoFunctionConstruct/go.sum +17 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/go/GoFunctionConstruct/main.go +17 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/nodejs/NodeJsFunctionConstruct/.no-packagejson-validator +0 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/nodejs/NodeJsFunctionConstruct/app.ts +16 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/nodejs/NodeJsFunctionConstruct/package-lock.json +12 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/nodejs/NodeJsFunctionConstruct/package.json +5 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/python/Function/app.py +15 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/python/Function/requirements.txt +1 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/python/Layer/layer_version_dependency.py +5 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/python/Layer/requirements.txt +1 -0
- package/resources/cdk-apps/sam_cdk_integ_app/src/rest-api-definition.yaml +12 -0
- package/resources/cdk-apps/simple-app/app.js +26 -0
- package/resources/cdk-apps/simple-app/cdk.json +7 -0
- package/resources/cli-regression-patches/v1.119.0/NOTES.md +5 -0
- package/resources/cli-regression-patches/v1.119.0/cli.integtest.js +659 -0
- package/resources/cli-regression-patches/v1.130.0/NOTES.md +12 -0
- package/resources/cli-regression-patches/v1.130.0/app/app.js +378 -0
- package/resources/cli-regression-patches/v1.130.0/bootstrapping.integtest.js +220 -0
- package/resources/cli-regression-patches/v1.44.0/NOTES.md +18 -0
- package/resources/cli-regression-patches/v1.44.0/bootstrapping.integtest.js +126 -0
- package/resources/cli-regression-patches/v1.44.0/test.sh +26 -0
- package/resources/cli-regression-patches/v1.61.1/NOTES.md +2 -0
- package/resources/cli-regression-patches/v1.61.1/skip-tests.txt +16 -0
- package/resources/cli-regression-patches/v1.62.0/NOTES.md +2 -0
- package/resources/cli-regression-patches/v1.62.0/aws-helpers.js +245 -0
- package/resources/cli-regression-patches/v1.63.0/NOTES.md +1 -0
- package/resources/cli-regression-patches/v1.63.0/skip-tests.txt +7 -0
- package/resources/cli-regression-patches/v1.64.0/NOTES.md +3 -0
- package/resources/cli-regression-patches/v1.64.0/cdk-helpers.js +325 -0
- package/resources/cli-regression-patches/v1.64.0/cli.integtest.js +599 -0
- package/resources/cli-regression-patches/v1.64.1/NOTES.md +3 -0
- package/resources/cli-regression-patches/v1.64.1/cdk-helpers.js +324 -0
- package/resources/cli-regression-patches/v1.64.1/cli.integtest.js +599 -0
- package/resources/cli-regression-patches/v1.67.0/NOTES.md +2 -0
- package/resources/cli-regression-patches/v1.67.0/cdk-helpers.js +331 -0
- package/resources/cli-regression-patches/v2.130.0/NOTES.md +1 -0
- package/resources/cli-regression-patches/v2.130.0/node_modules/@aws-cdk-testing/cli-integ/resources/cdk-apps/sam_cdk_integ_app/lib/nested-stack.js +19 -0
- package/resources/cli-regression-patches/v2.130.0/node_modules/@aws-cdk-testing/cli-integ/resources/cdk-apps/sam_cdk_integ_app/lib/test-stack.js +134 -0
- package/resources/cli-regression-patches/v2.130.0/skip-tests.txt +5 -0
- package/resources/cli-regression-patches/v2.132.0/NOTES.md +1 -0
- package/resources/cli-regression-patches/v2.132.0/skip-tests.txt +4 -0
- package/resources/cli-regression-patches/v2.142.0/NOTES.md +1 -0
- package/resources/cli-regression-patches/v2.142.0/skip-tests.txt +4 -0
- package/resources/cli-regression-patches/v2.160.0/skip-tests.txt +2 -0
- package/resources/cli-regression-patches/v2.161.0/NOTES.md +1 -0
- package/resources/cli-regression-patches/v2.161.0/skip-tests.txt +5 -0
- package/resources/cli-regression-patches/v2.166.0/NOTES.md +1 -0
- package/resources/cli-regression-patches/v2.166.0/skip-tests.txt +2 -0
- package/resources/cloud-assemblies/0.36.0/InitStack.template.json +1 -0
- package/resources/cloud-assemblies/0.36.0/cdk.out +1 -0
- package/resources/cloud-assemblies/0.36.0/manifest.json +19 -0
- package/resources/cloud-assemblies/1.10.0-lookup-default-vpc/InitStack.template.json +2 -0
- package/resources/cloud-assemblies/1.10.0-lookup-default-vpc/cdk.out +1 -0
- package/resources/cloud-assemblies/1.10.0-lookup-default-vpc/manifest.json.js +37 -0
- package/resources/cloud-assemblies/1.10.0-request-azs/InitStack.template.json +2 -0
- package/resources/cloud-assemblies/1.10.0-request-azs/cdk.out +1 -0
- package/resources/cloud-assemblies/1.10.0-request-azs/manifest.json.js +34 -0
- package/resources/integ.jest.config.js +25 -0
- package/resources/templates/sqs-template.json +36 -0
- package/skip-tests.txt +8 -0
- package/tests/cli-integ-tests/README.md +47 -0
- package/tests/cli-integ-tests/bootstrapping.integtest.d.ts +1 -0
- package/tests/cli-integ-tests/bootstrapping.integtest.js +412 -0
- package/tests/cli-integ-tests/bootstrapping.integtest.ts +493 -0
- package/tests/cli-integ-tests/cli-lib.integtest.d.ts +1 -0
- package/tests/cli-integ-tests/cli-lib.integtest.js +62 -0
- package/tests/cli-integ-tests/cli-lib.integtest.ts +90 -0
- package/tests/cli-integ-tests/cli.integtest.d.ts +1 -0
- package/tests/cli-integ-tests/cli.integtest.js +2104 -0
- package/tests/cli-integ-tests/cli.integtest.ts +2874 -0
- package/tests/cli-integ-tests/garbage-collection.integtest.d.ts +1 -0
- package/tests/cli-integ-tests/garbage-collection.integtest.js +314 -0
- package/tests/cli-integ-tests/garbage-collection.integtest.ts +392 -0
- package/tests/init-csharp/init-csharp.integtest.d.ts +1 -0
- package/tests/init-csharp/init-csharp.integtest.js +14 -0
- package/tests/init-csharp/init-csharp.integtest.ts +15 -0
- package/tests/init-fsharp/init-fsharp.integtest.d.ts +1 -0
- package/tests/init-fsharp/init-fsharp.integtest.js +14 -0
- package/tests/init-fsharp/init-fsharp.integtest.ts +15 -0
- package/tests/init-go/init-go.integtest.d.ts +1 -0
- package/tests/init-go/init-go.integtest.js +21 -0
- package/tests/init-go/init-go.integtest.ts +23 -0
- package/tests/init-java/init-java.integtest.d.ts +1 -0
- package/tests/init-java/init-java.integtest.js +14 -0
- package/tests/init-java/init-java.integtest.ts +14 -0
- package/tests/init-javascript/init-javascript.integtest.d.ts +1 -0
- package/tests/init-javascript/init-javascript.integtest.js +53 -0
- package/tests/init-javascript/init-javascript.integtest.ts +59 -0
- package/tests/init-python/init-python.integtest.d.ts +1 -0
- package/tests/init-python/init-python.integtest.js +19 -0
- package/tests/init-python/init-python.integtest.ts +20 -0
- package/tests/init-typescript-app/init-typescript-app.integtest.d.ts +1 -0
- package/tests/init-typescript-app/init-typescript-app.integtest.js +54 -0
- package/tests/init-typescript-app/init-typescript-app.integtest.ts +66 -0
- package/tests/init-typescript-lib/init-typescript-lib.integtest.d.ts +1 -0
- package/tests/init-typescript-lib/init-typescript-lib.integtest.js +13 -0
- package/tests/init-typescript-lib/init-typescript-lib.integtest.ts +13 -0
- package/tests/tool-integrations/amplify.integtest.d.ts +1 -0
- package/tests/tool-integrations/amplify.integtest.js +39 -0
- package/tests/tool-integrations/amplify.integtest.ts +43 -0
- package/tests/tool-integrations/with-tool-context.d.ts +9 -0
- package/tests/tool-integrations/with-tool-context.js +13 -0
- package/tests/tool-integrations/with-tool-context.ts +14 -0
- package/tests/uberpackage/uberpackage.integtest.d.ts +1 -0
- package/tests/uberpackage/uberpackage.integtest.js +11 -0
- package/tests/uberpackage/uberpackage.integtest.ts +11 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { LoginInformation } from './codeartifact';
|
|
4
|
+
import { parallelShell } from './parallel-shell';
|
|
5
|
+
import { UsageDir } from './usage-dir';
|
|
6
|
+
import { updateIniKey, loadLines, writeLines } from '../files';
|
|
7
|
+
import { shell } from '../shell';
|
|
8
|
+
|
|
9
|
+
export async function npmLogin(login: LoginInformation, usageDir: UsageDir) {
|
|
10
|
+
// Creating an ~/.npmrc that references an envvar is what you're supposed to do. (https://docs.npmjs.com/private-modules/ci-server-config)
|
|
11
|
+
await writeNpmLoginToken(usageDir, login.npmEndpoint, '${NPM_TOKEN}');
|
|
12
|
+
|
|
13
|
+
// Add variables to env file
|
|
14
|
+
await usageDir.addToEnv(npmEnv(usageDir, login));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function npmEnv(usageDir: UsageDir, login: LoginInformation) {
|
|
18
|
+
return {
|
|
19
|
+
npm_config_userconfig: path.join(usageDir.directory, '.npmrc'),
|
|
20
|
+
npm_config_registry: login.npmEndpoint,
|
|
21
|
+
npm_config_always_auth: 'true', // Necessary for NPM 6, otherwise it will sometimes not pass the token
|
|
22
|
+
NPM_TOKEN: login.authToken,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function uploadNpmPackages(packages: string[], login: LoginInformation, usageDir: UsageDir) {
|
|
27
|
+
await parallelShell(packages, async (pkg, output) => {
|
|
28
|
+
console.log(`⏳ ${pkg}`);
|
|
29
|
+
|
|
30
|
+
// path.resolve() is required -- if the filename ends up looking like `js/bla.tgz` then NPM thinks it's a short form GitHub name.
|
|
31
|
+
await shell(['node', require.resolve('npm'), 'publish', path.resolve(pkg)], {
|
|
32
|
+
modEnv: npmEnv(usageDir, login),
|
|
33
|
+
show: 'error',
|
|
34
|
+
outputs: [output],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
console.log(`✅ ${pkg}`);
|
|
38
|
+
}, (pkg, output) => {
|
|
39
|
+
if (output.toString().includes('code EPUBLISHCONFLICT')) {
|
|
40
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
41
|
+
return 'skip';
|
|
42
|
+
}
|
|
43
|
+
if (output.toString().includes('code EPRIVATE')) {
|
|
44
|
+
console.log(`❌ ${pkg}: is private. Skipped.`);
|
|
45
|
+
return 'skip';
|
|
46
|
+
}
|
|
47
|
+
return 'fail';
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function writeNpmLoginToken(usageDir: UsageDir, endpoint: string, token: string) {
|
|
52
|
+
const rcFile = path.join(usageDir.directory, '.npmrc');
|
|
53
|
+
const lines = await loadLines(rcFile);
|
|
54
|
+
|
|
55
|
+
const key = `${endpoint.replace(/^https:/, '')}:_authToken`;
|
|
56
|
+
updateIniKey(lines, key, token);
|
|
57
|
+
|
|
58
|
+
await writeLines(rcFile, lines);
|
|
59
|
+
return rcFile;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Environment variable, .npmrc in same directory as package.json or in home dir
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { LoginInformation } from './codeartifact';
|
|
2
|
+
import { UsageDir } from './usage-dir';
|
|
3
|
+
export declare function nugetLogin(login: LoginInformation, usageDir: UsageDir): Promise<void>;
|
|
4
|
+
export declare function uploadDotnetPackages(packages: string[], usageDir: UsageDir): Promise<void>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nugetLogin = nugetLogin;
|
|
4
|
+
exports.uploadDotnetPackages = uploadDotnetPackages;
|
|
5
|
+
const parallel_shell_1 = require("./parallel-shell");
|
|
6
|
+
const files_1 = require("../files");
|
|
7
|
+
const shell_1 = require("../shell");
|
|
8
|
+
async function nugetLogin(login, usageDir) {
|
|
9
|
+
// NuGet.Config MUST live in the current directory or in the home directory, and there is no environment
|
|
10
|
+
// variable to configure its location.
|
|
11
|
+
await writeNuGetConfigFile(usageDir.cwdFile('NuGet.Config'), login);
|
|
12
|
+
}
|
|
13
|
+
async function uploadDotnetPackages(packages, usageDir) {
|
|
14
|
+
await usageDir.copyCwdFileHere('NuGet.Config');
|
|
15
|
+
await (0, parallel_shell_1.parallelShell)(packages, async (pkg, output) => {
|
|
16
|
+
console.log(`⏳ ${pkg}`);
|
|
17
|
+
await (0, shell_1.shell)(['dotnet', 'nuget', 'push',
|
|
18
|
+
pkg,
|
|
19
|
+
'--source', 'CodeArtifact',
|
|
20
|
+
'--no-symbols',
|
|
21
|
+
'--force-english-output',
|
|
22
|
+
'--disable-buffering',
|
|
23
|
+
'--timeout', '600',
|
|
24
|
+
'--skip-duplicate'], {
|
|
25
|
+
outputs: [output],
|
|
26
|
+
});
|
|
27
|
+
console.log(`✅ ${pkg}`);
|
|
28
|
+
}, (pkg, output) => {
|
|
29
|
+
if (output.toString().includes('Conflict')) {
|
|
30
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
31
|
+
return 'skip';
|
|
32
|
+
}
|
|
33
|
+
if (output.includes('System.Threading.AbandonedMutexException')) {
|
|
34
|
+
console.log(`♻️ ${pkg}: AbandonedMutexException. Probably a sign of throttling, retrying.`);
|
|
35
|
+
return 'retry';
|
|
36
|
+
}
|
|
37
|
+
if (output.includes('Too Many Requests')) {
|
|
38
|
+
console.log(`♻️ ${pkg}: Too many requests. Retrying.`);
|
|
39
|
+
return 'retry';
|
|
40
|
+
}
|
|
41
|
+
if (output.includes('System.IO.IOException: The system cannot open the device or file specified.')) {
|
|
42
|
+
console.log(`♻️ ${pkg}: Some error that we've seen before as a result of throttling. Retrying.`);
|
|
43
|
+
return 'retry';
|
|
44
|
+
}
|
|
45
|
+
return 'fail';
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async function writeNuGetConfigFile(filename, login) {
|
|
49
|
+
// `dotnet nuget push` has an `--api-key` parameter, but CodeArtifact
|
|
50
|
+
// does not support that. We must authenticate with Basic auth.
|
|
51
|
+
await (0, files_1.writeFile)(filename, `<?xml version="1.0" encoding="utf-8"?>
|
|
52
|
+
<configuration>
|
|
53
|
+
<packageSources>
|
|
54
|
+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
|
55
|
+
<add key="CodeArtifact" value="${login.nugetEndpoint}v3/index.json" />
|
|
56
|
+
</packageSources>
|
|
57
|
+
<activePackageSource>
|
|
58
|
+
<add key="CodeArtifact" value="${login.nugetEndpoint}v3/index.json" />
|
|
59
|
+
</activePackageSource>
|
|
60
|
+
<packageSourceCredentials>
|
|
61
|
+
<CodeArtifact>
|
|
62
|
+
<add key="Username" value="aws" />
|
|
63
|
+
<add key="ClearTextPassword" value="${login.authToken}" />
|
|
64
|
+
</CodeArtifact>
|
|
65
|
+
</packageSourceCredentials>
|
|
66
|
+
</configuration>`);
|
|
67
|
+
}
|
|
68
|
+
// NuGet.Config in current directory
|
|
69
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibnVnZXQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJudWdldC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU9BLGdDQUlDO0FBRUQsb0RBc0NDO0FBakRELHFEQUFpRDtBQUVqRCxvQ0FBcUM7QUFDckMsb0NBQWlDO0FBRTFCLEtBQUssVUFBVSxVQUFVLENBQUMsS0FBdUIsRUFBRSxRQUFrQjtJQUMxRSx3R0FBd0c7SUFDeEcsc0NBQXNDO0lBQ3RDLE1BQU0sb0JBQW9CLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztBQUN0RSxDQUFDO0FBRU0sS0FBSyxVQUFVLG9CQUFvQixDQUFDLFFBQWtCLEVBQUUsUUFBa0I7SUFDL0UsTUFBTSxRQUFRLENBQUMsZUFBZSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBRS9DLE1BQU0sSUFBQSw4QkFBYSxFQUFDLFFBQVEsRUFBRSxLQUFLLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ2xELE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBRXhCLE1BQU0sSUFBQSxhQUFLLEVBQUMsQ0FBQyxRQUFRLEVBQUUsT0FBTyxFQUFFLE1BQU07WUFDcEMsR0FBRztZQUNILFVBQVUsRUFBRSxjQUFjO1lBQzFCLGNBQWM7WUFDZCx3QkFBd0I7WUFDeEIscUJBQXFCO1lBQ3JCLFdBQVcsRUFBRSxLQUFLO1lBQ2xCLGtCQUFrQixDQUFDLEVBQUU7WUFDckIsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDO1NBQ2xCLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQzFCLENBQUMsRUFDRCxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNkLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzNDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLDRCQUE0QixDQUFDLENBQUM7WUFDbEQsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQztRQUNELElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQywwQ0FBMEMsQ0FBQyxFQUFFLENBQUM7WUFDaEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEdBQUcscUVBQXFFLENBQUMsQ0FBQztZQUM1RixPQUFPLE9BQU8sQ0FBQztRQUNqQixDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLG1CQUFtQixDQUFDLEVBQUUsQ0FBQztZQUN6QyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxnQ0FBZ0MsQ0FBQyxDQUFDO1lBQ3ZELE9BQU8sT0FBTyxDQUFDO1FBQ2pCLENBQUM7UUFDRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsNkVBQTZFLENBQUMsRUFBRSxDQUFDO1lBQ25HLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLDBFQUEwRSxDQUFDLENBQUM7WUFDakcsT0FBTyxPQUFPLENBQUM7UUFDakIsQ0FBQztRQUNELE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELEtBQUssVUFBVSxvQkFBb0IsQ0FBQyxRQUFnQixFQUFFLEtBQXVCO0lBQzNFLHFFQUFxRTtJQUNyRSwrREFBK0Q7SUFDL0QsTUFBTSxJQUFBLGlCQUFTLEVBQUMsUUFBUSxFQUFFOzs7O3FDQUlTLEtBQUssQ0FBQyxhQUFhOzs7cUNBR25CLEtBQUssQ0FBQyxhQUFhOzs7Ozs4Q0FLVixLQUFLLENBQUMsU0FBUzs7O2lCQUc1QyxDQUFDLENBQUM7QUFDbkIsQ0FBQztBQUVELG9DQUFvQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cbmltcG9ydCB7IExvZ2luSW5mb3JtYXRpb24gfSBmcm9tICcuL2NvZGVhcnRpZmFjdCc7XG5pbXBvcnQgeyBwYXJhbGxlbFNoZWxsIH0gZnJvbSAnLi9wYXJhbGxlbC1zaGVsbCc7XG5pbXBvcnQgeyBVc2FnZURpciB9IGZyb20gJy4vdXNhZ2UtZGlyJztcbmltcG9ydCB7IHdyaXRlRmlsZSB9IGZyb20gJy4uL2ZpbGVzJztcbmltcG9ydCB7IHNoZWxsIH0gZnJvbSAnLi4vc2hlbGwnO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbnVnZXRMb2dpbihsb2dpbjogTG9naW5JbmZvcm1hdGlvbiwgdXNhZ2VEaXI6IFVzYWdlRGlyKSB7XG4gIC8vIE51R2V0LkNvbmZpZyBNVVNUIGxpdmUgaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5IG9yIGluIHRoZSBob21lIGRpcmVjdG9yeSwgYW5kIHRoZXJlIGlzIG5vIGVudmlyb25tZW50XG4gIC8vIHZhcmlhYmxlIHRvIGNvbmZpZ3VyZSBpdHMgbG9jYXRpb24uXG4gIGF3YWl0IHdyaXRlTnVHZXRDb25maWdGaWxlKHVzYWdlRGlyLmN3ZEZpbGUoJ051R2V0LkNvbmZpZycpLCBsb2dpbik7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGxvYWREb3RuZXRQYWNrYWdlcyhwYWNrYWdlczogc3RyaW5nW10sIHVzYWdlRGlyOiBVc2FnZURpcikge1xuICBhd2FpdCB1c2FnZURpci5jb3B5Q3dkRmlsZUhlcmUoJ051R2V0LkNvbmZpZycpO1xuXG4gIGF3YWl0IHBhcmFsbGVsU2hlbGwocGFja2FnZXMsIGFzeW5jIChwa2csIG91dHB1dCkgPT4ge1xuICAgIGNvbnNvbGUubG9nKGDij7MgJHtwa2d9YCk7XG5cbiAgICBhd2FpdCBzaGVsbChbJ2RvdG5ldCcsICdudWdldCcsICdwdXNoJyxcbiAgICAgIHBrZyxcbiAgICAgICctLXNvdXJjZScsICdDb2RlQXJ0aWZhY3QnLFxuICAgICAgJy0tbm8tc3ltYm9scycsXG4gICAgICAnLS1mb3JjZS1lbmdsaXNoLW91dHB1dCcsXG4gICAgICAnLS1kaXNhYmxlLWJ1ZmZlcmluZycsXG4gICAgICAnLS10aW1lb3V0JywgJzYwMCcsXG4gICAgICAnLS1za2lwLWR1cGxpY2F0ZSddLCB7XG4gICAgICBvdXRwdXRzOiBbb3V0cHV0XSxcbiAgICB9KTtcblxuICAgIGNvbnNvbGUubG9nKGDinIUgJHtwa2d9YCk7XG4gIH0sXG4gIChwa2csIG91dHB1dCkgPT4ge1xuICAgIGlmIChvdXRwdXQudG9TdHJpbmcoKS5pbmNsdWRlcygnQ29uZmxpY3QnKSkge1xuICAgICAgY29uc29sZS5sb2coYOKdjCAke3BrZ306IGFscmVhZHkgZXhpc3RzLiBTa2lwcGVkLmApO1xuICAgICAgcmV0dXJuICdza2lwJztcbiAgICB9XG4gICAgaWYgKG91dHB1dC5pbmNsdWRlcygnU3lzdGVtLlRocmVhZGluZy5BYmFuZG9uZWRNdXRleEV4Y2VwdGlvbicpKSB7XG4gICAgICBjb25zb2xlLmxvZyhg4pm777iPICR7cGtnfTogQWJhbmRvbmVkTXV0ZXhFeGNlcHRpb24uIFByb2JhYmx5IGEgc2lnbiBvZiB0aHJvdHRsaW5nLCByZXRyeWluZy5gKTtcbiAgICAgIHJldHVybiAncmV0cnknO1xuICAgIH1cbiAgICBpZiAob3V0cHV0LmluY2x1ZGVzKCdUb28gTWFueSBSZXF1ZXN0cycpKSB7XG4gICAgICBjb25zb2xlLmxvZyhg4pm777iPICR7cGtnfTogVG9vIG1hbnkgcmVxdWVzdHMuIFJldHJ5aW5nLmApO1xuICAgICAgcmV0dXJuICdyZXRyeSc7XG4gICAgfVxuICAgIGlmIChvdXRwdXQuaW5jbHVkZXMoJ1N5c3RlbS5JTy5JT0V4Y2VwdGlvbjogVGhlIHN5c3RlbSBjYW5ub3Qgb3BlbiB0aGUgZGV2aWNlIG9yIGZpbGUgc3BlY2lmaWVkLicpKSB7XG4gICAgICBjb25zb2xlLmxvZyhg4pm777iPICR7cGtnfTogU29tZSBlcnJvciB0aGF0IHdlJ3ZlIHNlZW4gYmVmb3JlIGFzIGEgcmVzdWx0IG9mIHRocm90dGxpbmcuIFJldHJ5aW5nLmApO1xuICAgICAgcmV0dXJuICdyZXRyeSc7XG4gICAgfVxuICAgIHJldHVybiAnZmFpbCc7XG4gIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiB3cml0ZU51R2V0Q29uZmlnRmlsZShmaWxlbmFtZTogc3RyaW5nLCBsb2dpbjogTG9naW5JbmZvcm1hdGlvbikge1xuICAvLyBgZG90bmV0IG51Z2V0IHB1c2hgIGhhcyBhbiBgLS1hcGkta2V5YCBwYXJhbWV0ZXIsIGJ1dCBDb2RlQXJ0aWZhY3RcbiAgLy8gZG9lcyBub3Qgc3VwcG9ydCB0aGF0LiBXZSBtdXN0IGF1dGhlbnRpY2F0ZSB3aXRoIEJhc2ljIGF1dGguXG4gIGF3YWl0IHdyaXRlRmlsZShmaWxlbmFtZSwgYDw/eG1sIHZlcnNpb249XCIxLjBcIiBlbmNvZGluZz1cInV0Zi04XCI/PlxuPGNvbmZpZ3VyYXRpb24+XG4gIDxwYWNrYWdlU291cmNlcz5cbiAgICA8YWRkIGtleT1cIm51Z2V0Lm9yZ1wiIHZhbHVlPVwiaHR0cHM6Ly9hcGkubnVnZXQub3JnL3YzL2luZGV4Lmpzb25cIiBwcm90b2NvbFZlcnNpb249XCIzXCIgLz5cbiAgICA8YWRkIGtleT1cIkNvZGVBcnRpZmFjdFwiIHZhbHVlPVwiJHtsb2dpbi5udWdldEVuZHBvaW50fXYzL2luZGV4Lmpzb25cIiAvPlxuICA8L3BhY2thZ2VTb3VyY2VzPlxuICA8YWN0aXZlUGFja2FnZVNvdXJjZT5cbiAgICA8YWRkIGtleT1cIkNvZGVBcnRpZmFjdFwiIHZhbHVlPVwiJHtsb2dpbi5udWdldEVuZHBvaW50fXYzL2luZGV4Lmpzb25cIiAvPlxuICA8L2FjdGl2ZVBhY2thZ2VTb3VyY2U+XG4gIDxwYWNrYWdlU291cmNlQ3JlZGVudGlhbHM+XG4gICAgPENvZGVBcnRpZmFjdD5cbiAgICAgICAgPGFkZCBrZXk9XCJVc2VybmFtZVwiIHZhbHVlPVwiYXdzXCIgLz5cbiAgICAgICAgPGFkZCBrZXk9XCJDbGVhclRleHRQYXNzd29yZFwiIHZhbHVlPVwiJHtsb2dpbi5hdXRoVG9rZW59XCIgLz5cbiAgICAgIDwvQ29kZUFydGlmYWN0PlxuICA8L3BhY2thZ2VTb3VyY2VDcmVkZW50aWFscz5cbjwvY29uZmlndXJhdGlvbj5gKTtcbn1cblxuLy8gTnVHZXQuQ29uZmlnIGluIGN1cnJlbnQgZGlyZWN0b3J5XG4iXX0=
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import { LoginInformation } from './codeartifact';
|
|
3
|
+
import { parallelShell } from './parallel-shell';
|
|
4
|
+
import { UsageDir } from './usage-dir';
|
|
5
|
+
import { writeFile } from '../files';
|
|
6
|
+
import { shell } from '../shell';
|
|
7
|
+
|
|
8
|
+
export async function nugetLogin(login: LoginInformation, usageDir: UsageDir) {
|
|
9
|
+
// NuGet.Config MUST live in the current directory or in the home directory, and there is no environment
|
|
10
|
+
// variable to configure its location.
|
|
11
|
+
await writeNuGetConfigFile(usageDir.cwdFile('NuGet.Config'), login);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function uploadDotnetPackages(packages: string[], usageDir: UsageDir) {
|
|
15
|
+
await usageDir.copyCwdFileHere('NuGet.Config');
|
|
16
|
+
|
|
17
|
+
await parallelShell(packages, async (pkg, output) => {
|
|
18
|
+
console.log(`⏳ ${pkg}`);
|
|
19
|
+
|
|
20
|
+
await shell(['dotnet', 'nuget', 'push',
|
|
21
|
+
pkg,
|
|
22
|
+
'--source', 'CodeArtifact',
|
|
23
|
+
'--no-symbols',
|
|
24
|
+
'--force-english-output',
|
|
25
|
+
'--disable-buffering',
|
|
26
|
+
'--timeout', '600',
|
|
27
|
+
'--skip-duplicate'], {
|
|
28
|
+
outputs: [output],
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
console.log(`✅ ${pkg}`);
|
|
32
|
+
},
|
|
33
|
+
(pkg, output) => {
|
|
34
|
+
if (output.toString().includes('Conflict')) {
|
|
35
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
36
|
+
return 'skip';
|
|
37
|
+
}
|
|
38
|
+
if (output.includes('System.Threading.AbandonedMutexException')) {
|
|
39
|
+
console.log(`♻️ ${pkg}: AbandonedMutexException. Probably a sign of throttling, retrying.`);
|
|
40
|
+
return 'retry';
|
|
41
|
+
}
|
|
42
|
+
if (output.includes('Too Many Requests')) {
|
|
43
|
+
console.log(`♻️ ${pkg}: Too many requests. Retrying.`);
|
|
44
|
+
return 'retry';
|
|
45
|
+
}
|
|
46
|
+
if (output.includes('System.IO.IOException: The system cannot open the device or file specified.')) {
|
|
47
|
+
console.log(`♻️ ${pkg}: Some error that we've seen before as a result of throttling. Retrying.`);
|
|
48
|
+
return 'retry';
|
|
49
|
+
}
|
|
50
|
+
return 'fail';
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function writeNuGetConfigFile(filename: string, login: LoginInformation) {
|
|
55
|
+
// `dotnet nuget push` has an `--api-key` parameter, but CodeArtifact
|
|
56
|
+
// does not support that. We must authenticate with Basic auth.
|
|
57
|
+
await writeFile(filename, `<?xml version="1.0" encoding="utf-8"?>
|
|
58
|
+
<configuration>
|
|
59
|
+
<packageSources>
|
|
60
|
+
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
|
61
|
+
<add key="CodeArtifact" value="${login.nugetEndpoint}v3/index.json" />
|
|
62
|
+
</packageSources>
|
|
63
|
+
<activePackageSource>
|
|
64
|
+
<add key="CodeArtifact" value="${login.nugetEndpoint}v3/index.json" />
|
|
65
|
+
</activePackageSource>
|
|
66
|
+
<packageSourceCredentials>
|
|
67
|
+
<CodeArtifact>
|
|
68
|
+
<add key="Username" value="aws" />
|
|
69
|
+
<add key="ClearTextPassword" value="${login.authToken}" />
|
|
70
|
+
</CodeArtifact>
|
|
71
|
+
</packageSourceCredentials>
|
|
72
|
+
</configuration>`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// NuGet.Config in current directory
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type ErrorResponse = 'fail' | 'skip' | 'retry';
|
|
2
|
+
/**
|
|
3
|
+
* Run a function in parallel with cached output
|
|
4
|
+
*/
|
|
5
|
+
export declare function parallelShell<A>(inputs: A[], block: (x: A, output: NodeJS.WritableStream) => Promise<void>, swallowError?: (x: A, output: string) => ErrorResponse): Promise<void>;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parallelShell = parallelShell;
|
|
4
|
+
const p_queue_1 = require("p-queue");
|
|
5
|
+
const aws_1 = require("../aws");
|
|
6
|
+
const corking_1 = require("../corking");
|
|
7
|
+
/**
|
|
8
|
+
* Run a function in parallel with cached output
|
|
9
|
+
*/
|
|
10
|
+
async function parallelShell(inputs, block, swallowError) {
|
|
11
|
+
// Limit to 10 for now, too many instances of Maven exhaust the CodeBuild instance memory
|
|
12
|
+
const q = new p_queue_1.default({ concurrency: Number(process.env.CONCURRENCY) || 10 });
|
|
13
|
+
await q.addAll(inputs.map(input => async () => {
|
|
14
|
+
let attempts = 10;
|
|
15
|
+
let sleepMs = 500;
|
|
16
|
+
while (true) {
|
|
17
|
+
const output = new corking_1.MemoryStream();
|
|
18
|
+
try {
|
|
19
|
+
await block(input, output);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
switch (swallowError === null || swallowError === void 0 ? void 0 : swallowError(input, output.toString())) {
|
|
24
|
+
case 'skip':
|
|
25
|
+
return;
|
|
26
|
+
case 'retry':
|
|
27
|
+
if (--attempts > 0) {
|
|
28
|
+
await (0, aws_1.sleep)(Math.floor(Math.random() * sleepMs));
|
|
29
|
+
sleepMs *= 2;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case 'fail':
|
|
34
|
+
case undefined:
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.error(output.toString());
|
|
39
|
+
throw e;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}));
|
|
43
|
+
await q.onEmpty();
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyYWxsZWwtc2hlbGwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJwYXJhbGxlbC1zaGVsbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQVNBLHNDQXlDQztBQWxERCxxQ0FBNkI7QUFDN0IsZ0NBQStCO0FBQy9CLHdDQUEwQztBQUkxQzs7R0FFRztBQUNJLEtBQUssVUFBVSxhQUFhLENBQ2pDLE1BQVcsRUFDWCxLQUE2RCxFQUM3RCxZQUFzRDtJQUV0RCx5RkFBeUY7SUFDekYsTUFBTSxDQUFDLEdBQUcsSUFBSSxpQkFBTSxDQUFDLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDN0UsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLElBQUksRUFBRTtRQUM1QyxJQUFJLFFBQVEsR0FBRyxFQUFFLENBQUM7UUFDbEIsSUFBSSxPQUFPLEdBQUcsR0FBRyxDQUFDO1FBQ2xCLE9BQU8sSUFBSSxFQUFFLENBQUM7WUFDWixNQUFNLE1BQU0sR0FBRyxJQUFJLHNCQUFZLEVBQUUsQ0FBQztZQUNsQyxJQUFJLENBQUM7Z0JBQ0gsTUFBTSxLQUFLLENBQUMsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2dCQUMzQixPQUFPO1lBQ1QsQ0FBQztZQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7Z0JBQ1gsUUFBUSxZQUFZLGFBQVosWUFBWSx1QkFBWixZQUFZLENBQUcsS0FBSyxFQUFFLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxFQUFFLENBQUM7b0JBQ2pELEtBQUssTUFBTTt3QkFDVCxPQUFPO29CQUVULEtBQUssT0FBTzt3QkFDVixJQUFJLEVBQUUsUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDOzRCQUNuQixNQUFNLElBQUEsV0FBSyxFQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUM7NEJBQ2pELE9BQU8sSUFBSSxDQUFDLENBQUM7NEJBQ2IsU0FBUzt3QkFDWCxDQUFDO3dCQUNELE1BQU07b0JBRVIsS0FBSyxNQUFNLENBQUM7b0JBQ1osS0FBSyxTQUFTO3dCQUNaLE1BQU07Z0JBQ1YsQ0FBQztnQkFFRCxzQ0FBc0M7Z0JBQ3RDLE9BQU8sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQ2pDLE1BQU0sQ0FBQyxDQUFDO1lBQ1YsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRUosTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7QUFDcEIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBQUXVldWUgZnJvbSAncC1xdWV1ZSc7XG5pbXBvcnQgeyBzbGVlcCB9IGZyb20gJy4uL2F3cyc7XG5pbXBvcnQgeyBNZW1vcnlTdHJlYW0gfSBmcm9tICcuLi9jb3JraW5nJztcblxuZXhwb3J0IHR5cGUgRXJyb3JSZXNwb25zZSA9ICdmYWlsJyB8ICdza2lwJyB8ICdyZXRyeSc7XG5cbi8qKlxuICogUnVuIGEgZnVuY3Rpb24gaW4gcGFyYWxsZWwgd2l0aCBjYWNoZWQgb3V0cHV0XG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwYXJhbGxlbFNoZWxsPEE+KFxuICBpbnB1dHM6IEFbXSxcbiAgYmxvY2s6ICh4OiBBLCBvdXRwdXQ6IE5vZGVKUy5Xcml0YWJsZVN0cmVhbSkgPT4gUHJvbWlzZTx2b2lkPixcbiAgc3dhbGxvd0Vycm9yPzogKHg6IEEsIG91dHB1dDogc3RyaW5nKSA9PiBFcnJvclJlc3BvbnNlLFxuKSB7XG4gIC8vIExpbWl0IHRvIDEwIGZvciBub3csIHRvbyBtYW55IGluc3RhbmNlcyBvZiBNYXZlbiBleGhhdXN0IHRoZSBDb2RlQnVpbGQgaW5zdGFuY2UgbWVtb3J5XG4gIGNvbnN0IHEgPSBuZXcgUFF1ZXVlKHsgY29uY3VycmVuY3k6IE51bWJlcihwcm9jZXNzLmVudi5DT05DVVJSRU5DWSkgfHwgMTAgfSk7XG4gIGF3YWl0IHEuYWRkQWxsKGlucHV0cy5tYXAoaW5wdXQgPT4gYXN5bmMgKCkgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IDEwO1xuICAgIGxldCBzbGVlcE1zID0gNTAwO1xuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICBjb25zdCBvdXRwdXQgPSBuZXcgTWVtb3J5U3RyZWFtKCk7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCBibG9jayhpbnB1dCwgb3V0cHV0KTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBzd2l0Y2ggKHN3YWxsb3dFcnJvcj8uKGlucHV0LCBvdXRwdXQudG9TdHJpbmcoKSkpIHtcbiAgICAgICAgICBjYXNlICdza2lwJzpcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICAgIGNhc2UgJ3JldHJ5JzpcbiAgICAgICAgICAgIGlmICgtLWF0dGVtcHRzID4gMCkge1xuICAgICAgICAgICAgICBhd2FpdCBzbGVlcChNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBzbGVlcE1zKSk7XG4gICAgICAgICAgICAgIHNsZWVwTXMgKj0gMjtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcblxuICAgICAgICAgIGNhc2UgJ2ZhaWwnOlxuICAgICAgICAgIGNhc2UgdW5kZWZpbmVkOlxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZVxuICAgICAgICBjb25zb2xlLmVycm9yKG91dHB1dC50b1N0cmluZygpKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9XG4gIH0pKTtcblxuICBhd2FpdCBxLm9uRW1wdHkoKTtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import PQueue from 'p-queue';
|
|
2
|
+
import { sleep } from '../aws';
|
|
3
|
+
import { MemoryStream } from '../corking';
|
|
4
|
+
|
|
5
|
+
export type ErrorResponse = 'fail' | 'skip' | 'retry';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Run a function in parallel with cached output
|
|
9
|
+
*/
|
|
10
|
+
export async function parallelShell<A>(
|
|
11
|
+
inputs: A[],
|
|
12
|
+
block: (x: A, output: NodeJS.WritableStream) => Promise<void>,
|
|
13
|
+
swallowError?: (x: A, output: string) => ErrorResponse,
|
|
14
|
+
) {
|
|
15
|
+
// Limit to 10 for now, too many instances of Maven exhaust the CodeBuild instance memory
|
|
16
|
+
const q = new PQueue({ concurrency: Number(process.env.CONCURRENCY) || 10 });
|
|
17
|
+
await q.addAll(inputs.map(input => async () => {
|
|
18
|
+
let attempts = 10;
|
|
19
|
+
let sleepMs = 500;
|
|
20
|
+
while (true) {
|
|
21
|
+
const output = new MemoryStream();
|
|
22
|
+
try {
|
|
23
|
+
await block(input, output);
|
|
24
|
+
return;
|
|
25
|
+
} catch (e) {
|
|
26
|
+
switch (swallowError?.(input, output.toString())) {
|
|
27
|
+
case 'skip':
|
|
28
|
+
return;
|
|
29
|
+
|
|
30
|
+
case 'retry':
|
|
31
|
+
if (--attempts > 0) {
|
|
32
|
+
await sleep(Math.floor(Math.random() * sleepMs));
|
|
33
|
+
sleepMs *= 2;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
break;
|
|
37
|
+
|
|
38
|
+
case 'fail':
|
|
39
|
+
case undefined:
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// eslint-disable-next-line no-console
|
|
44
|
+
console.error(output.toString());
|
|
45
|
+
throw e;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
await q.onEmpty();
|
|
51
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { LoginInformation } from './codeartifact';
|
|
2
|
+
import { UsageDir } from './usage-dir';
|
|
3
|
+
export declare function pypiLogin(login: LoginInformation, usageDir: UsageDir): Promise<void>;
|
|
4
|
+
export declare function uploadPythonPackages(packages: string[], login: LoginInformation): Promise<void>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pypiLogin = pypiLogin;
|
|
4
|
+
exports.uploadPythonPackages = uploadPythonPackages;
|
|
5
|
+
/* eslint-disable no-console */
|
|
6
|
+
const path = require("path");
|
|
7
|
+
const parallel_shell_1 = require("./parallel-shell");
|
|
8
|
+
const files_1 = require("../files");
|
|
9
|
+
const shell_1 = require("../shell");
|
|
10
|
+
async function pypiLogin(login, usageDir) {
|
|
11
|
+
// Write pip config file and set environment var
|
|
12
|
+
await (0, files_1.writeFile)(path.join(usageDir.directory, 'pip.conf'), [
|
|
13
|
+
'[global]',
|
|
14
|
+
`index-url = https://aws:${login.authToken}@${login.pypiEndpoint.replace(/^https:\/\//, '')}simple/`,
|
|
15
|
+
].join('\n'));
|
|
16
|
+
await usageDir.addToEnv({
|
|
17
|
+
PIP_CONFIG_FILE: `${usageDir.directory}/pip.conf`,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
async function uploadPythonPackages(packages, login) {
|
|
21
|
+
await (0, shell_1.shell)(['pip', 'install', 'twine'], { show: 'error' });
|
|
22
|
+
// Even though twine supports uploading all packages in one go, we have to upload them
|
|
23
|
+
// individually since CodeArtifact does not support Twine's `--skip-existing`. Fun beans.
|
|
24
|
+
await (0, parallel_shell_1.parallelShell)(packages, async (pkg, output) => {
|
|
25
|
+
console.log(`⏳ ${pkg}`);
|
|
26
|
+
await (0, shell_1.shell)(['twine', 'upload', '--verbose', pkg], {
|
|
27
|
+
modEnv: {
|
|
28
|
+
TWINE_USERNAME: 'aws',
|
|
29
|
+
TWINE_PASSWORD: login.authToken,
|
|
30
|
+
TWINE_REPOSITORY_URL: login.pypiEndpoint,
|
|
31
|
+
},
|
|
32
|
+
show: 'error',
|
|
33
|
+
outputs: [output],
|
|
34
|
+
});
|
|
35
|
+
console.log(`✅ ${pkg}`);
|
|
36
|
+
}, (pkg, output) => {
|
|
37
|
+
if (output.toString().includes('This package is configured to block new versions') || output.toString().includes('409 Conflict')) {
|
|
38
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
39
|
+
return 'skip';
|
|
40
|
+
}
|
|
41
|
+
if (output.includes('429 Too Many Requests ')) {
|
|
42
|
+
console.log(`♻️ ${pkg}: 429 Too Many Requests. Retrying.`);
|
|
43
|
+
return 'retry';
|
|
44
|
+
}
|
|
45
|
+
return 'fail';
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHlwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInB5cGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFRQSw4QkFTQztBQUVELG9EQThCQztBQWpERCwrQkFBK0I7QUFDL0IsNkJBQTZCO0FBRTdCLHFEQUFpRDtBQUVqRCxvQ0FBcUM7QUFDckMsb0NBQWlDO0FBRTFCLEtBQUssVUFBVSxTQUFTLENBQUMsS0FBdUIsRUFBRSxRQUFrQjtJQUN6RSxnREFBZ0Q7SUFDaEQsTUFBTSxJQUFBLGlCQUFTLEVBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLFVBQVUsQ0FBQyxFQUFFO1FBQ3pELFVBQVU7UUFDViwyQkFBMkIsS0FBSyxDQUFDLFNBQVMsSUFBSSxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDLFNBQVM7S0FDckcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNkLE1BQU0sUUFBUSxDQUFDLFFBQVEsQ0FBQztRQUN0QixlQUFlLEVBQUUsR0FBRyxRQUFRLENBQUMsU0FBUyxXQUFXO0tBQ2xELENBQUMsQ0FBQztBQUNMLENBQUM7QUFFTSxLQUFLLFVBQVUsb0JBQW9CLENBQUMsUUFBa0IsRUFBRSxLQUF1QjtJQUNwRixNQUFNLElBQUEsYUFBSyxFQUFDLENBQUMsS0FBSyxFQUFFLFNBQVMsRUFBRSxPQUFPLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBRTVELHNGQUFzRjtJQUN0Rix5RkFBeUY7SUFDekYsTUFBTSxJQUFBLDhCQUFhLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDbEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFFeEIsTUFBTSxJQUFBLGFBQUssRUFBQyxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLEdBQUcsQ0FBQyxFQUFFO1lBQ2pELE1BQU0sRUFBRTtnQkFDTixjQUFjLEVBQUUsS0FBSztnQkFDckIsY0FBYyxFQUFFLEtBQUssQ0FBQyxTQUFTO2dCQUMvQixvQkFBb0IsRUFBRSxLQUFLLENBQUMsWUFBWTthQUN6QztZQUNELElBQUksRUFBRSxPQUFPO1lBQ2IsT0FBTyxFQUFFLENBQUMsTUFBTSxDQUFDO1NBQ2xCLENBQUMsQ0FBQztRQUVILE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0lBQzFCLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxNQUFNLEVBQUUsRUFBRTtRQUNqQixJQUFJLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsa0RBQWtELENBQUMsSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsUUFBUSxDQUFDLGNBQWMsQ0FBQyxFQUFFLENBQUM7WUFDakksT0FBTyxDQUFDLEdBQUcsQ0FBQyxLQUFLLEdBQUcsNEJBQTRCLENBQUMsQ0FBQztZQUNsRCxPQUFPLE1BQU0sQ0FBQztRQUNoQixDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLHdCQUF3QixDQUFDLEVBQUUsQ0FBQztZQUM5QyxPQUFPLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxvQ0FBb0MsQ0FBQyxDQUFDO1lBQzNELE9BQU8sT0FBTyxDQUFDO1FBQ2pCLENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgTG9naW5JbmZvcm1hdGlvbiB9IGZyb20gJy4vY29kZWFydGlmYWN0JztcbmltcG9ydCB7IHBhcmFsbGVsU2hlbGwgfSBmcm9tICcuL3BhcmFsbGVsLXNoZWxsJztcbmltcG9ydCB7IFVzYWdlRGlyIH0gZnJvbSAnLi91c2FnZS1kaXInO1xuaW1wb3J0IHsgd3JpdGVGaWxlIH0gZnJvbSAnLi4vZmlsZXMnO1xuaW1wb3J0IHsgc2hlbGwgfSBmcm9tICcuLi9zaGVsbCc7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBweXBpTG9naW4obG9naW46IExvZ2luSW5mb3JtYXRpb24sIHVzYWdlRGlyOiBVc2FnZURpcikge1xuICAvLyBXcml0ZSBwaXAgY29uZmlnIGZpbGUgYW5kIHNldCBlbnZpcm9ubWVudCB2YXJcbiAgYXdhaXQgd3JpdGVGaWxlKHBhdGguam9pbih1c2FnZURpci5kaXJlY3RvcnksICdwaXAuY29uZicpLCBbXG4gICAgJ1tnbG9iYWxdJyxcbiAgICBgaW5kZXgtdXJsID0gaHR0cHM6Ly9hd3M6JHtsb2dpbi5hdXRoVG9rZW59QCR7bG9naW4ucHlwaUVuZHBvaW50LnJlcGxhY2UoL15odHRwczpcXC9cXC8vLCAnJyl9c2ltcGxlL2AsXG4gIF0uam9pbignXFxuJykpO1xuICBhd2FpdCB1c2FnZURpci5hZGRUb0Vudih7XG4gICAgUElQX0NPTkZJR19GSUxFOiBgJHt1c2FnZURpci5kaXJlY3Rvcnl9L3BpcC5jb25mYCxcbiAgfSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGxvYWRQeXRob25QYWNrYWdlcyhwYWNrYWdlczogc3RyaW5nW10sIGxvZ2luOiBMb2dpbkluZm9ybWF0aW9uKSB7XG4gIGF3YWl0IHNoZWxsKFsncGlwJywgJ2luc3RhbGwnLCAndHdpbmUnXSwgeyBzaG93OiAnZXJyb3InIH0pO1xuXG4gIC8vIEV2ZW4gdGhvdWdoIHR3aW5lIHN1cHBvcnRzIHVwbG9hZGluZyBhbGwgcGFja2FnZXMgaW4gb25lIGdvLCB3ZSBoYXZlIHRvIHVwbG9hZCB0aGVtXG4gIC8vIGluZGl2aWR1YWxseSBzaW5jZSBDb2RlQXJ0aWZhY3QgZG9lcyBub3Qgc3VwcG9ydCBUd2luZSdzIGAtLXNraXAtZXhpc3RpbmdgLiBGdW4gYmVhbnMuXG4gIGF3YWl0IHBhcmFsbGVsU2hlbGwocGFja2FnZXMsIGFzeW5jIChwa2csIG91dHB1dCkgPT4ge1xuICAgIGNvbnNvbGUubG9nKGDij7MgJHtwa2d9YCk7XG5cbiAgICBhd2FpdCBzaGVsbChbJ3R3aW5lJywgJ3VwbG9hZCcsICctLXZlcmJvc2UnLCBwa2ddLCB7XG4gICAgICBtb2RFbnY6IHtcbiAgICAgICAgVFdJTkVfVVNFUk5BTUU6ICdhd3MnLFxuICAgICAgICBUV0lORV9QQVNTV09SRDogbG9naW4uYXV0aFRva2VuLFxuICAgICAgICBUV0lORV9SRVBPU0lUT1JZX1VSTDogbG9naW4ucHlwaUVuZHBvaW50LFxuICAgICAgfSxcbiAgICAgIHNob3c6ICdlcnJvcicsXG4gICAgICBvdXRwdXRzOiBbb3V0cHV0XSxcbiAgICB9KTtcblxuICAgIGNvbnNvbGUubG9nKGDinIUgJHtwa2d9YCk7XG4gIH0sIChwa2csIG91dHB1dCkgPT4ge1xuICAgIGlmIChvdXRwdXQudG9TdHJpbmcoKS5pbmNsdWRlcygnVGhpcyBwYWNrYWdlIGlzIGNvbmZpZ3VyZWQgdG8gYmxvY2sgbmV3IHZlcnNpb25zJykgfHwgb3V0cHV0LnRvU3RyaW5nKCkuaW5jbHVkZXMoJzQwOSBDb25mbGljdCcpKSB7XG4gICAgICBjb25zb2xlLmxvZyhg4p2MICR7cGtnfTogYWxyZWFkeSBleGlzdHMuIFNraXBwZWQuYCk7XG4gICAgICByZXR1cm4gJ3NraXAnO1xuICAgIH1cbiAgICBpZiAob3V0cHV0LmluY2x1ZGVzKCc0MjkgVG9vIE1hbnkgUmVxdWVzdHMgJykpIHtcbiAgICAgIGNvbnNvbGUubG9nKGDimbvvuI8gJHtwa2d9OiA0MjkgVG9vIE1hbnkgUmVxdWVzdHMuIFJldHJ5aW5nLmApO1xuICAgICAgcmV0dXJuICdyZXRyeSc7XG4gICAgfVxuICAgIHJldHVybiAnZmFpbCc7XG4gIH0pO1xufVxuIl19
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { LoginInformation } from './codeartifact';
|
|
4
|
+
import { parallelShell } from './parallel-shell';
|
|
5
|
+
import { UsageDir } from './usage-dir';
|
|
6
|
+
import { writeFile } from '../files';
|
|
7
|
+
import { shell } from '../shell';
|
|
8
|
+
|
|
9
|
+
export async function pypiLogin(login: LoginInformation, usageDir: UsageDir) {
|
|
10
|
+
// Write pip config file and set environment var
|
|
11
|
+
await writeFile(path.join(usageDir.directory, 'pip.conf'), [
|
|
12
|
+
'[global]',
|
|
13
|
+
`index-url = https://aws:${login.authToken}@${login.pypiEndpoint.replace(/^https:\/\//, '')}simple/`,
|
|
14
|
+
].join('\n'));
|
|
15
|
+
await usageDir.addToEnv({
|
|
16
|
+
PIP_CONFIG_FILE: `${usageDir.directory}/pip.conf`,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function uploadPythonPackages(packages: string[], login: LoginInformation) {
|
|
21
|
+
await shell(['pip', 'install', 'twine'], { show: 'error' });
|
|
22
|
+
|
|
23
|
+
// Even though twine supports uploading all packages in one go, we have to upload them
|
|
24
|
+
// individually since CodeArtifact does not support Twine's `--skip-existing`. Fun beans.
|
|
25
|
+
await parallelShell(packages, async (pkg, output) => {
|
|
26
|
+
console.log(`⏳ ${pkg}`);
|
|
27
|
+
|
|
28
|
+
await shell(['twine', 'upload', '--verbose', pkg], {
|
|
29
|
+
modEnv: {
|
|
30
|
+
TWINE_USERNAME: 'aws',
|
|
31
|
+
TWINE_PASSWORD: login.authToken,
|
|
32
|
+
TWINE_REPOSITORY_URL: login.pypiEndpoint,
|
|
33
|
+
},
|
|
34
|
+
show: 'error',
|
|
35
|
+
outputs: [output],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
console.log(`✅ ${pkg}`);
|
|
39
|
+
}, (pkg, output) => {
|
|
40
|
+
if (output.toString().includes('This package is configured to block new versions') || output.toString().includes('409 Conflict')) {
|
|
41
|
+
console.log(`❌ ${pkg}: already exists. Skipped.`);
|
|
42
|
+
return 'skip';
|
|
43
|
+
}
|
|
44
|
+
if (output.includes('429 Too Many Requests ')) {
|
|
45
|
+
console.log(`♻️ ${pkg}: 429 Too Many Requests. Retrying.`);
|
|
46
|
+
return 'retry';
|
|
47
|
+
}
|
|
48
|
+
return 'fail';
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const DEFAULT_USAGE_DIR: string;
|
|
2
|
+
/**
|
|
3
|
+
* The usage directory is where we write per-session config files to access the CodeArtifact repository.
|
|
4
|
+
*
|
|
5
|
+
* Some config files may be written in a system-global location, but they will not be active unless the
|
|
6
|
+
* contents of this directory have been sourced/copied into the current terminal.
|
|
7
|
+
*
|
|
8
|
+
* CONTRACT
|
|
9
|
+
*
|
|
10
|
+
* There are two special entries:
|
|
11
|
+
*
|
|
12
|
+
* - `env`, a file with `key=value` entries for environment variables to set.
|
|
13
|
+
* - `cwd/`, a directory with files that need to be copied into the current directory before each command.
|
|
14
|
+
*
|
|
15
|
+
* Other than these, code may write tempfiles to this directory if it wants, but there is no meaning
|
|
16
|
+
* implied for other files.
|
|
17
|
+
*/
|
|
18
|
+
export declare class UsageDir {
|
|
19
|
+
readonly directory: string;
|
|
20
|
+
static default(): UsageDir;
|
|
21
|
+
readonly envFile: string;
|
|
22
|
+
readonly cwdDir: string;
|
|
23
|
+
private constructor();
|
|
24
|
+
clean(): Promise<void>;
|
|
25
|
+
addToEnv(settings: Record<string, string>): Promise<void>;
|
|
26
|
+
currentEnv(): Promise<Record<string, string>>;
|
|
27
|
+
cwdFile(filename: string): string;
|
|
28
|
+
activateInCurrentProcess(): Promise<void>;
|
|
29
|
+
copyCwdFileHere(...filenames: string[]): Promise<void>;
|
|
30
|
+
advertise(): void;
|
|
31
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UsageDir = exports.DEFAULT_USAGE_DIR = void 0;
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const fs = require("fs-extra");
|
|
6
|
+
const files_1 = require("../files");
|
|
7
|
+
exports.DEFAULT_USAGE_DIR = path.join((0, files_1.homeDir)(), '.codeartifact/usage');
|
|
8
|
+
/**
|
|
9
|
+
* The usage directory is where we write per-session config files to access the CodeArtifact repository.
|
|
10
|
+
*
|
|
11
|
+
* Some config files may be written in a system-global location, but they will not be active unless the
|
|
12
|
+
* contents of this directory have been sourced/copied into the current terminal.
|
|
13
|
+
*
|
|
14
|
+
* CONTRACT
|
|
15
|
+
*
|
|
16
|
+
* There are two special entries:
|
|
17
|
+
*
|
|
18
|
+
* - `env`, a file with `key=value` entries for environment variables to set.
|
|
19
|
+
* - `cwd/`, a directory with files that need to be copied into the current directory before each command.
|
|
20
|
+
*
|
|
21
|
+
* Other than these, code may write tempfiles to this directory if it wants, but there is no meaning
|
|
22
|
+
* implied for other files.
|
|
23
|
+
*/
|
|
24
|
+
class UsageDir {
|
|
25
|
+
static default() {
|
|
26
|
+
return new UsageDir(exports.DEFAULT_USAGE_DIR);
|
|
27
|
+
}
|
|
28
|
+
constructor(directory) {
|
|
29
|
+
this.directory = directory;
|
|
30
|
+
this.envFile = path.join(this.directory, 'env');
|
|
31
|
+
this.cwdDir = path.join(this.directory, 'cwd');
|
|
32
|
+
}
|
|
33
|
+
async clean() {
|
|
34
|
+
await fs.rm(this.directory, { recursive: true, force: true });
|
|
35
|
+
await fs.mkdirp(path.join(this.directory, 'cwd'));
|
|
36
|
+
await fs.writeFile(path.join(this.directory, 'env'), '', { encoding: 'utf-8' });
|
|
37
|
+
await this.addToEnv({
|
|
38
|
+
CWD_FILES_DIR: path.join(this.directory, 'cwd'),
|
|
39
|
+
});
|
|
40
|
+
// Write a bash helper to load these settings
|
|
41
|
+
await fs.writeFile(path.join(this.directory, 'activate.bash'), [
|
|
42
|
+
`while read -u10 line; do [[ -z $line ]] || export "$line"; done 10<${this.directory}/env`,
|
|
43
|
+
'cp -R $CWD_FILES_DIR/ .', // Copy files from directory even if it is empty
|
|
44
|
+
].join('\n'), { encoding: 'utf-8' });
|
|
45
|
+
}
|
|
46
|
+
async addToEnv(settings) {
|
|
47
|
+
const lines = await (0, files_1.loadLines)(this.envFile);
|
|
48
|
+
for (const [k, v] of Object.entries(settings)) {
|
|
49
|
+
(0, files_1.updateIniKey)(lines, k, v);
|
|
50
|
+
}
|
|
51
|
+
await (0, files_1.writeLines)(this.envFile, lines);
|
|
52
|
+
}
|
|
53
|
+
async currentEnv() {
|
|
54
|
+
const lines = await (0, files_1.loadLines)(this.envFile);
|
|
55
|
+
const splitter = /^([a-zA-Z0-9_-]+)\s*=\s*(.*)$/;
|
|
56
|
+
const ret = {};
|
|
57
|
+
for (const line of lines) {
|
|
58
|
+
const m = line.match(splitter);
|
|
59
|
+
if (m) {
|
|
60
|
+
ret[m[1]] = m[2];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return ret;
|
|
64
|
+
}
|
|
65
|
+
cwdFile(filename) {
|
|
66
|
+
return path.join(this.cwdDir, filename);
|
|
67
|
+
}
|
|
68
|
+
async activateInCurrentProcess() {
|
|
69
|
+
for (const [k, v] of Object.entries(await this.currentEnv())) {
|
|
70
|
+
process.env[k] = v;
|
|
71
|
+
}
|
|
72
|
+
await (0, files_1.copyDirectoryContents)(this.cwdDir, '.');
|
|
73
|
+
}
|
|
74
|
+
async copyCwdFileHere(...filenames) {
|
|
75
|
+
for (const file of filenames) {
|
|
76
|
+
await fs.copyFile(path.join(this.cwdDir, file), file);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
advertise() {
|
|
80
|
+
// eslint-disable-next-line no-console
|
|
81
|
+
console.log('To activate these settings in the current terminal:');
|
|
82
|
+
// eslint-disable-next-line no-console
|
|
83
|
+
console.log(` source ${this.directory}/activate.bash`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
exports.UsageDir = UsageDir;
|
|
87
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNhZ2UtZGlyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidXNhZ2UtZGlyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZCQUE2QjtBQUM3QiwrQkFBK0I7QUFDL0Isb0NBQStGO0FBRWxGLFFBQUEsaUJBQWlCLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFBLGVBQU8sR0FBRSxFQUFFLHFCQUFxQixDQUFDLENBQUM7QUFFN0U7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBYSxRQUFRO0lBQ1osTUFBTSxDQUFDLE9BQU87UUFDbkIsT0FBTyxJQUFJLFFBQVEsQ0FBQyx5QkFBaUIsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFLRCxZQUFvQyxTQUFpQjtRQUFqQixjQUFTLEdBQVQsU0FBUyxDQUFRO1FBQ25ELElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ2pELENBQUM7SUFFTSxLQUFLLENBQUMsS0FBSztRQUNoQixNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDOUQsTUFBTSxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO1FBQ2xELE1BQU0sRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFFaEYsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDO1lBQ2xCLGFBQWEsRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDO1NBQ2hELENBQUMsQ0FBQztRQUVILDZDQUE2QztRQUM3QyxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLGVBQWUsQ0FBQyxFQUFFO1lBQzdELHNFQUFzRSxJQUFJLENBQUMsU0FBUyxNQUFNO1lBQzFGLHlCQUF5QixFQUFFLGdEQUFnRDtTQUM1RSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7SUFFTSxLQUFLLENBQUMsUUFBUSxDQUFDLFFBQWdDO1FBQ3BELE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBQSxpQkFBUyxFQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1QyxLQUFLLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1lBQzlDLElBQUEsb0JBQVksRUFBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQzVCLENBQUM7UUFDRCxNQUFNLElBQUEsa0JBQVUsRUFBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQ3hDLENBQUM7SUFFTSxLQUFLLENBQUMsVUFBVTtRQUNyQixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUEsaUJBQVMsRUFBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFNUMsTUFBTSxRQUFRLEdBQUcsK0JBQStCLENBQUM7UUFFakQsTUFBTSxHQUFHLEdBQTJCLEVBQUUsQ0FBQztRQUN2QyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDL0IsSUFBSSxDQUFDLEVBQUUsQ0FBQztnQkFDTixHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ25CLENBQUM7UUFDSCxDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRU0sT0FBTyxDQUFDLFFBQWdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFTSxLQUFLLENBQUMsd0JBQXdCO1FBQ25DLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLEVBQUUsQ0FBQztZQUM3RCxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNyQixDQUFDO1FBRUQsTUFBTSxJQUFBLDZCQUFxQixFQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVNLEtBQUssQ0FBQyxlQUFlLENBQUMsR0FBRyxTQUFtQjtRQUNqRCxLQUFLLE1BQU0sSUFBSSxJQUFJLFNBQVMsRUFBRSxDQUFDO1lBQzdCLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDeEQsQ0FBQztJQUNILENBQUM7SUFFTSxTQUFTO1FBQ2Qsc0NBQXNDO1FBQ3RDLE9BQU8sQ0FBQyxHQUFHLENBQUMscURBQXFELENBQUMsQ0FBQztRQUNuRSxzQ0FBc0M7UUFDdEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLElBQUksQ0FBQyxTQUFTLGdCQUFnQixDQUFDLENBQUM7SUFDNUQsQ0FBQztDQUNGO0FBNUVELDRCQTRFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgeyBjb3B5RGlyZWN0b3J5Q29udGVudHMsIGhvbWVEaXIsIGxvYWRMaW5lcywgdXBkYXRlSW5pS2V5LCB3cml0ZUxpbmVzIH0gZnJvbSAnLi4vZmlsZXMnO1xuXG5leHBvcnQgY29uc3QgREVGQVVMVF9VU0FHRV9ESVIgPSBwYXRoLmpvaW4oaG9tZURpcigpLCAnLmNvZGVhcnRpZmFjdC91c2FnZScpO1xuXG4vKipcbiAqIFRoZSB1c2FnZSBkaXJlY3RvcnkgaXMgd2hlcmUgd2Ugd3JpdGUgcGVyLXNlc3Npb24gY29uZmlnIGZpbGVzIHRvIGFjY2VzcyB0aGUgQ29kZUFydGlmYWN0IHJlcG9zaXRvcnkuXG4gKlxuICogU29tZSBjb25maWcgZmlsZXMgbWF5IGJlIHdyaXR0ZW4gaW4gYSBzeXN0ZW0tZ2xvYmFsIGxvY2F0aW9uLCBidXQgdGhleSB3aWxsIG5vdCBiZSBhY3RpdmUgdW5sZXNzIHRoZVxuICogY29udGVudHMgb2YgdGhpcyBkaXJlY3RvcnkgaGF2ZSBiZWVuIHNvdXJjZWQvY29waWVkIGludG8gdGhlIGN1cnJlbnQgdGVybWluYWwuXG4gKlxuICogQ09OVFJBQ1RcbiAqXG4gKiBUaGVyZSBhcmUgdHdvIHNwZWNpYWwgZW50cmllczpcbiAqXG4gKiAtIGBlbnZgLCBhIGZpbGUgd2l0aCBga2V5PXZhbHVlYCBlbnRyaWVzIGZvciBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gIHNldC5cbiAqIC0gYGN3ZC9gLCBhIGRpcmVjdG9yeSB3aXRoIGZpbGVzIHRoYXQgbmVlZCB0byBiZSBjb3BpZWQgaW50byB0aGUgY3VycmVudCBkaXJlY3RvcnkgYmVmb3JlIGVhY2ggY29tbWFuZC5cbiAqXG4gKiBPdGhlciB0aGFuIHRoZXNlLCBjb2RlIG1heSB3cml0ZSB0ZW1wZmlsZXMgdG8gdGhpcyBkaXJlY3RvcnkgaWYgaXQgd2FudHMsIGJ1dCB0aGVyZSBpcyBubyBtZWFuaW5nXG4gKiBpbXBsaWVkIGZvciBvdGhlciBmaWxlcy5cbiAqL1xuZXhwb3J0IGNsYXNzIFVzYWdlRGlyIHtcbiAgcHVibGljIHN0YXRpYyBkZWZhdWx0KCkge1xuICAgIHJldHVybiBuZXcgVXNhZ2VEaXIoREVGQVVMVF9VU0FHRV9ESVIpO1xuICB9XG5cbiAgcHVibGljIHJlYWRvbmx5IGVudkZpbGU6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IGN3ZERpcjogc3RyaW5nO1xuXG4gIHByaXZhdGUgY29uc3RydWN0b3IocHVibGljIHJlYWRvbmx5IGRpcmVjdG9yeTogc3RyaW5nKSB7XG4gICAgdGhpcy5lbnZGaWxlID0gcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCAnZW52Jyk7XG4gICAgdGhpcy5jd2REaXIgPSBwYXRoLmpvaW4odGhpcy5kaXJlY3RvcnksICdjd2QnKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjbGVhbigpIHtcbiAgICBhd2FpdCBmcy5ybSh0aGlzLmRpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIGF3YWl0IGZzLm1rZGlycChwYXRoLmpvaW4odGhpcy5kaXJlY3RvcnksICdjd2QnKSk7XG4gICAgYXdhaXQgZnMud3JpdGVGaWxlKHBhdGguam9pbih0aGlzLmRpcmVjdG9yeSwgJ2VudicpLCAnJywgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcblxuICAgIGF3YWl0IHRoaXMuYWRkVG9FbnYoe1xuICAgICAgQ1dEX0ZJTEVTX0RJUjogcGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCAnY3dkJyksXG4gICAgfSk7XG5cbiAgICAvLyBXcml0ZSBhIGJhc2ggaGVscGVyIHRvIGxvYWQgdGhlc2Ugc2V0dGluZ3NcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5qb2luKHRoaXMuZGlyZWN0b3J5LCAnYWN0aXZhdGUuYmFzaCcpLCBbXG4gICAgICBgd2hpbGUgcmVhZCAtdTEwIGxpbmU7IGRvIFtbIC16ICRsaW5lIF1dIHx8IGV4cG9ydCBcIiRsaW5lXCI7IGRvbmUgMTA8JHt0aGlzLmRpcmVjdG9yeX0vZW52YCxcbiAgICAgICdjcCAtUiAkQ1dEX0ZJTEVTX0RJUi8gLicsIC8vIENvcHkgZmlsZXMgZnJvbSBkaXJlY3RvcnkgZXZlbiBpZiBpdCBpcyBlbXB0eVxuICAgIF0uam9pbignXFxuJyksIHsgZW5jb2Rpbmc6ICd1dGYtOCcgfSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgYWRkVG9FbnYoc2V0dGluZ3M6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4pIHtcbiAgICBjb25zdCBsaW5lcyA9IGF3YWl0IGxvYWRMaW5lcyh0aGlzLmVudkZpbGUpO1xuICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHNldHRpbmdzKSkge1xuICAgICAgdXBkYXRlSW5pS2V5KGxpbmVzLCBrLCB2KTtcbiAgICB9XG4gICAgYXdhaXQgd3JpdGVMaW5lcyh0aGlzLmVudkZpbGUsIGxpbmVzKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjdXJyZW50RW52KCk6IFByb21pc2U8UmVjb3JkPHN0cmluZywgc3RyaW5nPj4ge1xuICAgIGNvbnN0IGxpbmVzID0gYXdhaXQgbG9hZExpbmVzKHRoaXMuZW52RmlsZSk7XG5cbiAgICBjb25zdCBzcGxpdHRlciA9IC9eKFthLXpBLVowLTlfLV0rKVxccyo9XFxzKiguKikkLztcblxuICAgIGNvbnN0IHJldDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICAgIGZvciAoY29uc3QgbGluZSBvZiBsaW5lcykge1xuICAgICAgY29uc3QgbSA9IGxpbmUubWF0Y2goc3BsaXR0ZXIpO1xuICAgICAgaWYgKG0pIHtcbiAgICAgICAgcmV0W21bMV1dID0gbVsyXTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIHB1YmxpYyBjd2RGaWxlKGZpbGVuYW1lOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKHRoaXMuY3dkRGlyLCBmaWxlbmFtZSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgYWN0aXZhdGVJbkN1cnJlbnRQcm9jZXNzKCkge1xuICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKGF3YWl0IHRoaXMuY3VycmVudEVudigpKSkge1xuICAgICAgcHJvY2Vzcy5lbnZba10gPSB2O1xuICAgIH1cblxuICAgIGF3YWl0IGNvcHlEaXJlY3RvcnlDb250ZW50cyh0aGlzLmN3ZERpciwgJy4nKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjb3B5Q3dkRmlsZUhlcmUoLi4uZmlsZW5hbWVzOiBzdHJpbmdbXSkge1xuICAgIGZvciAoY29uc3QgZmlsZSBvZiBmaWxlbmFtZXMpIHtcbiAgICAgIGF3YWl0IGZzLmNvcHlGaWxlKHBhdGguam9pbih0aGlzLmN3ZERpciwgZmlsZSksIGZpbGUpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyBhZHZlcnRpc2UoKSB7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICBjb25zb2xlLmxvZygnVG8gYWN0aXZhdGUgdGhlc2Ugc2V0dGluZ3MgaW4gdGhlIGN1cnJlbnQgdGVybWluYWw6Jyk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGVcbiAgICBjb25zb2xlLmxvZyhgICAgIHNvdXJjZSAke3RoaXMuZGlyZWN0b3J5fS9hY3RpdmF0ZS5iYXNoYCk7XG4gIH1cbn1cbiJdfQ==
|