sst 2.23.15 → 2.24.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/cdk/deployments.d.ts +1 -1
- package/cdk/deployments.js +1 -1
- package/cli/ui/deploy.js +1 -1
- package/constructs/App.d.ts +1 -1
- package/constructs/Function.d.ts +1 -1
- package/node/auth/session.js +1 -1
- package/node/future/auth/session.js +1 -1
- package/node/websocket-api/index.js +1 -1
- package/package.json +13 -13
- package/support/java-runtime/install.sh +2 -2
- package/cdk/asset-publishing.d.ts +0 -74
- package/cdk/asset-publishing.js +0 -147
- package/cdk-assets/private/asset-handler.d.ts +0 -29
- package/cdk-assets/private/asset-handler.js +0 -1
- package/cdk-assets/private/docker.d.ts +0 -94
- package/cdk-assets/private/docker.js +0 -237
- package/cdk-assets/private/handlers/container-images.d.ts +0 -22
- package/cdk-assets/private/handlers/container-images.js +0 -231
- package/cdk-assets/private/handlers/index.d.ts +0 -3
- package/cdk-assets/private/handlers/index.js +0 -18
- package/cdk-assets/publishing.d.ts +0 -113
- package/cdk-assets/publishing.js +0 -194
package/cdk/deployments.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as cxapi from "@aws-cdk/cx-api";
|
|
2
2
|
import { AssetManifest, IManifestEntry } from "cdk-assets";
|
|
3
3
|
import { Tag } from "sst-aws-cdk/lib/cdk-toolkit.js";
|
|
4
|
-
import { BuildAssetsOptions, PublishAssetsOptions } from "
|
|
4
|
+
import { BuildAssetsOptions, PublishAssetsOptions } from "sst-aws-cdk/lib/util/asset-publishing.js";
|
|
5
5
|
import { Mode } from "sst-aws-cdk/lib/api/aws-auth/credentials.js";
|
|
6
6
|
import { ISDK } from "sst-aws-cdk/lib/api/aws-auth/sdk.js";
|
|
7
7
|
import { SdkProvider } from "sst-aws-cdk/lib/api/aws-auth/sdk-provider.js";
|
package/cdk/deployments.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as cxapi from "@aws-cdk/cx-api";
|
|
|
3
3
|
import * as cdk_assets from "cdk-assets";
|
|
4
4
|
import { AssetManifest } from "cdk-assets";
|
|
5
5
|
import { debug, warning } from "sst-aws-cdk/lib/logging.js";
|
|
6
|
-
import { buildAssets, publishAssets, PublishingAws, EVENT_TO_LOGGER, } from "
|
|
6
|
+
import { buildAssets, publishAssets, PublishingAws, EVENT_TO_LOGGER, } from "sst-aws-cdk/lib/util/asset-publishing.js";
|
|
7
7
|
import { Mode } from "sst-aws-cdk/lib/api/aws-auth/credentials.js";
|
|
8
8
|
import { deployStack, destroyStack, makeBodyParameterAndUpload, } from "./deploy-stack.js";
|
|
9
9
|
import { loadCurrentTemplateWithNestedStacks, loadCurrentTemplate, } from "sst-aws-cdk/lib/api/nested-stack-helpers.js";
|
package/cli/ui/deploy.js
CHANGED
|
@@ -155,7 +155,7 @@ function getApiAccessLogPermissionsHelper(error) {
|
|
|
155
155
|
// note: this should be handled in SST as access log group names are now
|
|
156
156
|
// hardcoded with /aws/vendedlogs/apis prefix.
|
|
157
157
|
if (error.indexOf("Insufficient permissions to enable logging") > -1) {
|
|
158
|
-
return `This is a common deploy error. Check out this GitHub issue for more details - https://github.com/
|
|
158
|
+
return `This is a common deploy error. Check out this GitHub issue for more details - https://github.com/sst/sst/issues/125`;
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
function getAppSyncMultiResolverHelper(error) {
|
package/constructs/App.d.ts
CHANGED
|
@@ -77,7 +77,7 @@ export declare class App extends CDKApp {
|
|
|
77
77
|
defaultFunctionProps: (FunctionProps | ((stack: Stack) => FunctionProps))[];
|
|
78
78
|
private _defaultRemovalPolicy?;
|
|
79
79
|
/** @internal */
|
|
80
|
-
get defaultRemovalPolicy(): "destroy" | "retain" | "snapshot" | undefined;
|
|
80
|
+
get defaultRemovalPolicy(): "destroy" | "retain" | "snapshot" | "retain-on-update-or-delete" | undefined;
|
|
81
81
|
/**
|
|
82
82
|
* @internal
|
|
83
83
|
*/
|
package/constructs/Function.d.ts
CHANGED
|
@@ -268,7 +268,7 @@ export interface FunctionProps extends Omit<FunctionOptions, "functionName" | "m
|
|
|
268
268
|
*
|
|
269
269
|
* Note that, if a Layer is created in a stack (say `stackA`) and is referenced in another stack (say `stackB`), SST automatically creates an SSM parameter in `stackA` with the Layer's ARN. And in `stackB`, SST reads the ARN from the SSM parameter, and then imports the Layer.
|
|
270
270
|
*
|
|
271
|
-
* This is to get around the limitation that a Lambda Layer ARN cannot be referenced across stacks via a stack export. The Layer ARN contains a version number that is incremented everytime the Layer is modified. When you refer to a Layer's ARN across stacks, a CloudFormation export is created. However, CloudFormation does not allow an exported value to be updated. Once exported, if you try to deploy the updated layer, the CloudFormation update will fail. You can read more about this issue here - https://github.com/
|
|
271
|
+
* This is to get around the limitation that a Lambda Layer ARN cannot be referenced across stacks via a stack export. The Layer ARN contains a version number that is incremented everytime the Layer is modified. When you refer to a Layer's ARN across stacks, a CloudFormation export is created. However, CloudFormation does not allow an exported value to be updated. Once exported, if you try to deploy the updated layer, the CloudFormation update will fail. You can read more about this issue here - https://github.com/sst/sst/issues/549.
|
|
272
272
|
*
|
|
273
273
|
* @default no layers
|
|
274
274
|
*
|
package/node/auth/session.js
CHANGED
|
@@ -14,7 +14,7 @@ const SessionMemo = /* @__PURE__ */ Context.memo(() => {
|
|
|
14
14
|
if (cookie)
|
|
15
15
|
token = cookie;
|
|
16
16
|
// WebSocket may also set the token in the protocol header
|
|
17
|
-
// TODO: Once https://github.com/
|
|
17
|
+
// TODO: Once https://github.com/sst/sst/pull/2838 is merged,
|
|
18
18
|
// then we should no longer need to check both casing for the header.
|
|
19
19
|
const wsProtocol = ctxType === "ws"
|
|
20
20
|
? useHeader("sec-websocket-protocol") ||
|
|
@@ -15,7 +15,7 @@ const SessionMemo = /* @__PURE__ */ Context.memo(() => {
|
|
|
15
15
|
if (cookie)
|
|
16
16
|
token = cookie;
|
|
17
17
|
// WebSocket may also set the token in the protocol header
|
|
18
|
-
// TODO: Once https://github.com/
|
|
18
|
+
// TODO: Once https://github.com/sst/sst/pull/2838 is merged,
|
|
19
19
|
// then we should no longer need to check both casing for the header.
|
|
20
20
|
const wsProtocol = ctxType === "ws"
|
|
21
21
|
? useHeader("sec-websocket-protocol") ||
|
|
@@ -16,7 +16,7 @@ export const WebSocketApi =
|
|
|
16
16
|
export function WebSocketApiHandler(cb) {
|
|
17
17
|
return Handler("ws", async (evt, ctx) => {
|
|
18
18
|
const result = await cb(evt, ctx);
|
|
19
|
-
// TODO: Once https://github.com/
|
|
19
|
+
// TODO: Once https://github.com/sst/sst/pull/2838 is merged,
|
|
20
20
|
// then we should no longer need to check both casing for the header.
|
|
21
21
|
const token = useHeader("Sec-WebSocket-Protocol") ||
|
|
22
22
|
useHeader("sec-websocket-protocol");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sideEffects": false,
|
|
3
3
|
"name": "sst",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.24.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"sst": "cli/sst.js"
|
|
7
7
|
},
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"repository": {
|
|
12
12
|
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/
|
|
13
|
+
"url": "git+https://github.com/sst/sst.git",
|
|
14
14
|
"directory": "packages/cli"
|
|
15
15
|
},
|
|
16
16
|
"exports": {
|
|
@@ -25,12 +25,12 @@
|
|
|
25
25
|
},
|
|
26
26
|
"homepage": "https://sst.dev",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@aws-cdk/aws-apigatewayv2-alpha": "^2.
|
|
29
|
-
"@aws-cdk/aws-apigatewayv2-authorizers-alpha": "^2.
|
|
30
|
-
"@aws-cdk/aws-apigatewayv2-integrations-alpha": "^2.
|
|
31
|
-
"@aws-cdk/cloud-assembly-schema": "2.
|
|
32
|
-
"@aws-cdk/cloudformation-diff": "2.
|
|
33
|
-
"@aws-cdk/cx-api": "2.
|
|
28
|
+
"@aws-cdk/aws-apigatewayv2-alpha": "^2.91.0-alpha.0",
|
|
29
|
+
"@aws-cdk/aws-apigatewayv2-authorizers-alpha": "^2.91.0-alpha.0",
|
|
30
|
+
"@aws-cdk/aws-apigatewayv2-integrations-alpha": "^2.91.0-alpha.0",
|
|
31
|
+
"@aws-cdk/cloud-assembly-schema": "2.91.0",
|
|
32
|
+
"@aws-cdk/cloudformation-diff": "2.91.0",
|
|
33
|
+
"@aws-cdk/cx-api": "2.91.0",
|
|
34
34
|
"@aws-crypto/sha256-js": "^5.0.0",
|
|
35
35
|
"@aws-sdk/client-cloudformation": "^3.279.0",
|
|
36
36
|
"@aws-sdk/client-ecs": "^3.279.0",
|
|
@@ -55,17 +55,17 @@
|
|
|
55
55
|
"@smithy/signature-v4": "^2.0.1",
|
|
56
56
|
"@trpc/server": "9.16.0",
|
|
57
57
|
"adm-zip": "^0.5.10",
|
|
58
|
-
"aws-cdk-lib": "2.
|
|
58
|
+
"aws-cdk-lib": "2.91.0",
|
|
59
59
|
"aws-iot-device-sdk": "^2.2.12",
|
|
60
60
|
"aws-sdk": "^2.1326.0",
|
|
61
61
|
"builtin-modules": "3.2.0",
|
|
62
|
-
"cdk-assets": "2.
|
|
62
|
+
"cdk-assets": "2.91.0",
|
|
63
63
|
"chalk": "^5.2.0",
|
|
64
64
|
"chokidar": "^3.5.3",
|
|
65
65
|
"ci-info": "^3.7.0",
|
|
66
66
|
"colorette": "^2.0.19",
|
|
67
67
|
"conf": "^10.2.0",
|
|
68
|
-
"constructs": "10.
|
|
68
|
+
"constructs": "10.2.69",
|
|
69
69
|
"cross-spawn": "^7.0.3",
|
|
70
70
|
"dendriform-immer-patch-optimiser": "^2.1.0",
|
|
71
71
|
"dotenv": "^16.0.3",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
"ora": "^6.1.2",
|
|
88
88
|
"react": "18.2.0",
|
|
89
89
|
"remeda": "^1.3.0",
|
|
90
|
-
"sst-aws-cdk": "2.
|
|
90
|
+
"sst-aws-cdk": "2.91.0",
|
|
91
91
|
"tree-kill": "^1.2.2",
|
|
92
92
|
"undici": "^5.12.0",
|
|
93
93
|
"uuid": "^9.0.0",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
"bugs": {
|
|
134
|
-
"url": "https://github.com/
|
|
134
|
+
"url": "https://github.com/sst/sst/issues"
|
|
135
135
|
},
|
|
136
136
|
"main": "index.js",
|
|
137
137
|
"directories": {
|
|
@@ -18,8 +18,8 @@ mv build/target/dependency/aws-lambda-java-serialization-1.0.0.jar release/
|
|
|
18
18
|
# - AWS_LAMBDA_RUNTIME_API has to be of the format "host:port", subpath is not support (ie. "host:port/path")
|
|
19
19
|
# - official JAR uses NativeClient that cannot be run on user's machine
|
|
20
20
|
rm -rf aws-lambda-java-libs
|
|
21
|
-
git clone https://github.com/
|
|
21
|
+
git clone https://github.com/sst/aws-lambda-java-libs.git
|
|
22
22
|
cd aws-lambda-java-libs/aws-lambda-java-runtime-interface-client
|
|
23
23
|
mvn -Dmaven.test.skip=true install
|
|
24
24
|
cd ../..
|
|
25
|
-
mv aws-lambda-java-libs/aws-lambda-java-runtime-interface-client/target/aws-lambda-java-runtime-interface-client-1.1.0.jar release/
|
|
25
|
+
mv aws-lambda-java-libs/aws-lambda-java-runtime-interface-client/target/aws-lambda-java-runtime-interface-client-1.1.0.jar release/
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import * as cxapi from "@aws-cdk/cx-api";
|
|
2
|
-
import * as AWS from "aws-sdk";
|
|
3
|
-
import * as cdk_assets from "cdk-assets";
|
|
4
|
-
import { SdkProvider } from "sst-aws-cdk/lib/api/aws-auth/sdk-provider.js";
|
|
5
|
-
export interface PublishAssetsOptions {
|
|
6
|
-
/**
|
|
7
|
-
* Print progress at 'debug' level
|
|
8
|
-
*/
|
|
9
|
-
readonly quiet?: boolean;
|
|
10
|
-
/**
|
|
11
|
-
* Whether to build assets before publishing.
|
|
12
|
-
*
|
|
13
|
-
* @default true To remain backward compatible.
|
|
14
|
-
*/
|
|
15
|
-
readonly buildAssets?: boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Whether to build/publish assets in parallel
|
|
18
|
-
*
|
|
19
|
-
* @default true To remain backward compatible.
|
|
20
|
-
*/
|
|
21
|
-
readonly parallel?: boolean;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Use cdk-assets to publish all assets in the given manifest.
|
|
25
|
-
*/
|
|
26
|
-
export declare function publishAssets(manifest: cdk_assets.AssetManifest, sdk: SdkProvider, targetEnv: cxapi.Environment, options?: PublishAssetsOptions): Promise<void>;
|
|
27
|
-
export interface BuildAssetsOptions {
|
|
28
|
-
/**
|
|
29
|
-
* Print progress at 'debug' level
|
|
30
|
-
*/
|
|
31
|
-
readonly quiet?: boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Build assets in parallel
|
|
34
|
-
*
|
|
35
|
-
* @default true
|
|
36
|
-
*/
|
|
37
|
-
readonly parallel?: boolean;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Use cdk-assets to build all assets in the given manifest.
|
|
41
|
-
*/
|
|
42
|
-
export declare function buildAssets(manifest: cdk_assets.AssetManifest, sdk: SdkProvider, targetEnv: cxapi.Environment, options?: BuildAssetsOptions): Promise<void>;
|
|
43
|
-
export declare class PublishingAws implements cdk_assets.IAws {
|
|
44
|
-
/**
|
|
45
|
-
* The base SDK to work with
|
|
46
|
-
*/
|
|
47
|
-
private readonly aws;
|
|
48
|
-
/**
|
|
49
|
-
* Environment where the stack we're deploying is going
|
|
50
|
-
*/
|
|
51
|
-
private readonly targetEnv;
|
|
52
|
-
private sdkCache;
|
|
53
|
-
constructor(
|
|
54
|
-
/**
|
|
55
|
-
* The base SDK to work with
|
|
56
|
-
*/
|
|
57
|
-
aws: SdkProvider,
|
|
58
|
-
/**
|
|
59
|
-
* Environment where the stack we're deploying is going
|
|
60
|
-
*/
|
|
61
|
-
targetEnv: cxapi.Environment);
|
|
62
|
-
discoverPartition(): Promise<string>;
|
|
63
|
-
discoverDefaultRegion(): Promise<string>;
|
|
64
|
-
discoverCurrentAccount(): Promise<cdk_assets.Account>;
|
|
65
|
-
discoverTargetAccount(options: cdk_assets.ClientOptions): Promise<cdk_assets.Account>;
|
|
66
|
-
s3Client(options: cdk_assets.ClientOptions): Promise<AWS.S3>;
|
|
67
|
-
ecrClient(options: cdk_assets.ClientOptions): Promise<AWS.ECR>;
|
|
68
|
-
secretsManagerClient(options: cdk_assets.ClientOptions): Promise<AWS.SecretsManager>;
|
|
69
|
-
/**
|
|
70
|
-
* Get an SDK appropriate for the given client options
|
|
71
|
-
*/
|
|
72
|
-
private sdk;
|
|
73
|
-
}
|
|
74
|
-
export declare const EVENT_TO_LOGGER: Record<cdk_assets.EventType, (x: string) => void>;
|
package/cdk/asset-publishing.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import * as cxapi from "@aws-cdk/cx-api";
|
|
2
|
-
import * as cdk_assets from "cdk-assets";
|
|
3
|
-
// TODO: remove after PR is merged
|
|
4
|
-
import { AssetPublishing } from "../cdk-assets/publishing.js";
|
|
5
|
-
import { Mode } from "sst-aws-cdk/lib/api/aws-auth/credentials.js";
|
|
6
|
-
import { debug, error, print } from "sst-aws-cdk/lib/logging.js";
|
|
7
|
-
/**
|
|
8
|
-
* Use cdk-assets to publish all assets in the given manifest.
|
|
9
|
-
*/
|
|
10
|
-
export async function publishAssets(manifest, sdk, targetEnv, options = {}) {
|
|
11
|
-
// This shouldn't really happen (it's a programming error), but we don't have
|
|
12
|
-
// the types here to guide us. Do an runtime validation to be super super sure.
|
|
13
|
-
if (targetEnv.account === undefined ||
|
|
14
|
-
targetEnv.account === cxapi.UNKNOWN_ACCOUNT ||
|
|
15
|
-
targetEnv.region === undefined ||
|
|
16
|
-
targetEnv.account === cxapi.UNKNOWN_REGION) {
|
|
17
|
-
throw new Error(`Asset publishing requires resolved account and region, got ${JSON.stringify(targetEnv)}`);
|
|
18
|
-
}
|
|
19
|
-
const publisher = new AssetPublishing(manifest, {
|
|
20
|
-
aws: new PublishingAws(sdk, targetEnv),
|
|
21
|
-
progressListener: new PublishingProgressListener(options.quiet ?? false),
|
|
22
|
-
throwOnError: false,
|
|
23
|
-
publishInParallel: options.parallel ?? true,
|
|
24
|
-
buildAssets: options.buildAssets ?? true,
|
|
25
|
-
publishAssets: true,
|
|
26
|
-
// TODO: remove after PR is merged
|
|
27
|
-
quiet: options.quiet,
|
|
28
|
-
});
|
|
29
|
-
await publisher.publish();
|
|
30
|
-
if (publisher.hasFailures) {
|
|
31
|
-
console.log(publisher.failures);
|
|
32
|
-
throw new Error("Failed to publish one or more assets. See the error messages above for more information.");
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Use cdk-assets to build all assets in the given manifest.
|
|
37
|
-
*/
|
|
38
|
-
export async function buildAssets(manifest, sdk, targetEnv, options = {}) {
|
|
39
|
-
// This shouldn't really happen (it's a programming error), but we don't have
|
|
40
|
-
// the types here to guide us. Do an runtime validation to be super super sure.
|
|
41
|
-
if (targetEnv.account === undefined ||
|
|
42
|
-
targetEnv.account === cxapi.UNKNOWN_ACCOUNT ||
|
|
43
|
-
targetEnv.region === undefined ||
|
|
44
|
-
targetEnv.account === cxapi.UNKNOWN_REGION) {
|
|
45
|
-
throw new Error(`Asset building requires resolved account and region, got ${JSON.stringify(targetEnv)}`);
|
|
46
|
-
}
|
|
47
|
-
const publisher = new cdk_assets.AssetPublishing(manifest, {
|
|
48
|
-
aws: new PublishingAws(sdk, targetEnv),
|
|
49
|
-
progressListener: new PublishingProgressListener(options.quiet ?? false),
|
|
50
|
-
throwOnError: false,
|
|
51
|
-
publishInParallel: options.parallel ?? true,
|
|
52
|
-
buildAssets: true,
|
|
53
|
-
publishAssets: false,
|
|
54
|
-
});
|
|
55
|
-
await publisher.publish();
|
|
56
|
-
if (publisher.hasFailures) {
|
|
57
|
-
throw new Error("Failed to build one or more assets. See the error messages above for more information.");
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
export class PublishingAws {
|
|
61
|
-
aws;
|
|
62
|
-
targetEnv;
|
|
63
|
-
sdkCache = new Map();
|
|
64
|
-
constructor(
|
|
65
|
-
/**
|
|
66
|
-
* The base SDK to work with
|
|
67
|
-
*/
|
|
68
|
-
aws,
|
|
69
|
-
/**
|
|
70
|
-
* Environment where the stack we're deploying is going
|
|
71
|
-
*/
|
|
72
|
-
targetEnv) {
|
|
73
|
-
this.aws = aws;
|
|
74
|
-
this.targetEnv = targetEnv;
|
|
75
|
-
}
|
|
76
|
-
async discoverPartition() {
|
|
77
|
-
return ((await this.aws.baseCredentialsPartition(this.targetEnv, Mode.ForWriting)) ?? "aws");
|
|
78
|
-
}
|
|
79
|
-
async discoverDefaultRegion() {
|
|
80
|
-
return this.targetEnv.region;
|
|
81
|
-
}
|
|
82
|
-
async discoverCurrentAccount() {
|
|
83
|
-
const account = await this.aws.defaultAccount();
|
|
84
|
-
return (account ?? {
|
|
85
|
-
accountId: "<unknown account>",
|
|
86
|
-
partition: "aws",
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
async discoverTargetAccount(options) {
|
|
90
|
-
return (await this.sdk(options)).currentAccount();
|
|
91
|
-
}
|
|
92
|
-
async s3Client(options) {
|
|
93
|
-
return (await this.sdk(options)).s3();
|
|
94
|
-
}
|
|
95
|
-
async ecrClient(options) {
|
|
96
|
-
return (await this.sdk(options)).ecr();
|
|
97
|
-
}
|
|
98
|
-
async secretsManagerClient(options) {
|
|
99
|
-
return (await this.sdk(options)).secretsManager();
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Get an SDK appropriate for the given client options
|
|
103
|
-
*/
|
|
104
|
-
async sdk(options) {
|
|
105
|
-
const env = {
|
|
106
|
-
...this.targetEnv,
|
|
107
|
-
region: options.region ?? this.targetEnv.region, // Default: same region as the stack
|
|
108
|
-
};
|
|
109
|
-
const cacheKey = JSON.stringify({
|
|
110
|
-
env,
|
|
111
|
-
assumeRuleArn: options.assumeRoleArn,
|
|
112
|
-
assumeRoleExternalId: options.assumeRoleExternalId,
|
|
113
|
-
quiet: options.quiet,
|
|
114
|
-
});
|
|
115
|
-
const maybeSdk = this.sdkCache.get(cacheKey);
|
|
116
|
-
if (maybeSdk) {
|
|
117
|
-
return maybeSdk;
|
|
118
|
-
}
|
|
119
|
-
const sdk = (await this.aws.forEnvironment(env, Mode.ForWriting, {
|
|
120
|
-
assumeRoleArn: options.assumeRoleArn,
|
|
121
|
-
assumeRoleExternalId: options.assumeRoleExternalId,
|
|
122
|
-
}, options.quiet)).sdk;
|
|
123
|
-
this.sdkCache.set(cacheKey, sdk);
|
|
124
|
-
return sdk;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
export const EVENT_TO_LOGGER = {
|
|
128
|
-
build: debug,
|
|
129
|
-
cached: debug,
|
|
130
|
-
check: debug,
|
|
131
|
-
debug,
|
|
132
|
-
fail: error,
|
|
133
|
-
found: debug,
|
|
134
|
-
start: print,
|
|
135
|
-
success: print,
|
|
136
|
-
upload: debug,
|
|
137
|
-
};
|
|
138
|
-
class PublishingProgressListener {
|
|
139
|
-
quiet;
|
|
140
|
-
constructor(quiet) {
|
|
141
|
-
this.quiet = quiet;
|
|
142
|
-
}
|
|
143
|
-
onPublishEvent(type, event) {
|
|
144
|
-
const handler = this.quiet && type !== "fail" ? debug : EVENT_TO_LOGGER[type];
|
|
145
|
-
handler(`[${event.percentComplete}%] ${type}: ${event.message}`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { DockerFactory } from "./docker.js";
|
|
2
|
-
import { IAws } from "cdk-assets/lib/aws.js";
|
|
3
|
-
import { EventType } from "cdk-assets/lib/progress.js";
|
|
4
|
-
/**
|
|
5
|
-
* Handler for asset building and publishing.
|
|
6
|
-
*/
|
|
7
|
-
export interface IAssetHandler {
|
|
8
|
-
/**
|
|
9
|
-
* Build the asset.
|
|
10
|
-
*/
|
|
11
|
-
build(): Promise<void>;
|
|
12
|
-
/**
|
|
13
|
-
* Publish the asset.
|
|
14
|
-
*/
|
|
15
|
-
publish(): Promise<void>;
|
|
16
|
-
/**
|
|
17
|
-
* Return whether the asset already exists
|
|
18
|
-
*/
|
|
19
|
-
isPublished(): Promise<boolean>;
|
|
20
|
-
}
|
|
21
|
-
export interface IHandlerHost {
|
|
22
|
-
readonly aws: IAws;
|
|
23
|
-
readonly aborted: boolean;
|
|
24
|
-
readonly dockerFactory: DockerFactory;
|
|
25
|
-
emitMessage(type: EventType, m: string): void;
|
|
26
|
-
}
|
|
27
|
-
export interface IHandlerOptions {
|
|
28
|
-
readonly quiet?: boolean;
|
|
29
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Logger } from "cdk-assets/lib/private/shell.js";
|
|
2
|
-
interface BuildOptions {
|
|
3
|
-
readonly directory: string;
|
|
4
|
-
/**
|
|
5
|
-
* Tag the image with a given repoName:tag combination
|
|
6
|
-
*/
|
|
7
|
-
readonly tag: string;
|
|
8
|
-
readonly target?: string;
|
|
9
|
-
readonly file?: string;
|
|
10
|
-
readonly buildArgs?: Record<string, string>;
|
|
11
|
-
readonly buildSecrets?: Record<string, string>;
|
|
12
|
-
readonly networkMode?: string;
|
|
13
|
-
readonly platform?: string;
|
|
14
|
-
readonly outputs?: string[];
|
|
15
|
-
readonly cacheFrom?: DockerCacheOption[];
|
|
16
|
-
readonly cacheTo?: DockerCacheOption;
|
|
17
|
-
readonly quiet?: boolean;
|
|
18
|
-
}
|
|
19
|
-
interface PushOptions {
|
|
20
|
-
readonly tag: string;
|
|
21
|
-
readonly quiet?: boolean;
|
|
22
|
-
}
|
|
23
|
-
export interface DockerCredentialsConfig {
|
|
24
|
-
readonly version: string;
|
|
25
|
-
readonly domainCredentials: Record<string, DockerDomainCredentials>;
|
|
26
|
-
}
|
|
27
|
-
export interface DockerDomainCredentials {
|
|
28
|
-
readonly secretsManagerSecretId?: string;
|
|
29
|
-
readonly ecrRepository?: string;
|
|
30
|
-
}
|
|
31
|
-
export interface DockerCacheOption {
|
|
32
|
-
readonly type: string;
|
|
33
|
-
readonly params?: {
|
|
34
|
-
[key: string]: string;
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
export declare class Docker {
|
|
38
|
-
private readonly logger?;
|
|
39
|
-
private configDir;
|
|
40
|
-
constructor(logger?: Logger | undefined);
|
|
41
|
-
/**
|
|
42
|
-
* Whether an image with the given tag exists
|
|
43
|
-
*/
|
|
44
|
-
exists(tag: string): Promise<boolean>;
|
|
45
|
-
build(options: BuildOptions): Promise<void>;
|
|
46
|
-
/**
|
|
47
|
-
* Get credentials from ECR and run docker login
|
|
48
|
-
*/
|
|
49
|
-
login(ecr: AWS.ECR): Promise<void>;
|
|
50
|
-
tag(sourceTag: string, targetTag: string): Promise<void>;
|
|
51
|
-
push(options: PushOptions): Promise<void>;
|
|
52
|
-
/**
|
|
53
|
-
* If a CDK Docker Credentials file exists, creates a new Docker config directory.
|
|
54
|
-
* Sets up `docker-credential-cdk-assets` to be the credential helper for each domain in the CDK config.
|
|
55
|
-
* All future commands (e.g., `build`, `push`) will use this config.
|
|
56
|
-
*
|
|
57
|
-
* See https://docs.docker.com/engine/reference/commandline/login/#credential-helpers for more details on cred helpers.
|
|
58
|
-
*
|
|
59
|
-
* @returns true if CDK config was found and configured, false otherwise
|
|
60
|
-
*/
|
|
61
|
-
configureCdkCredentials(): boolean;
|
|
62
|
-
/**
|
|
63
|
-
* Removes any configured Docker config directory.
|
|
64
|
-
* All future commands (e.g., `build`, `push`) will use the default config.
|
|
65
|
-
*
|
|
66
|
-
* This is useful after calling `configureCdkCredentials` to reset to default credentials.
|
|
67
|
-
*/
|
|
68
|
-
resetAuthPlugins(): void;
|
|
69
|
-
private execute;
|
|
70
|
-
private cacheOptionToFlag;
|
|
71
|
-
}
|
|
72
|
-
export interface DockerFactoryOptions {
|
|
73
|
-
readonly repoUri: string;
|
|
74
|
-
readonly ecr: AWS.ECR;
|
|
75
|
-
readonly logger: (m: string) => void;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Helps get appropriately configured Docker instances during the container
|
|
79
|
-
* image publishing process.
|
|
80
|
-
*/
|
|
81
|
-
export declare class DockerFactory {
|
|
82
|
-
private enterLoggedInDestinationsCriticalSection;
|
|
83
|
-
private loggedInDestinations;
|
|
84
|
-
/**
|
|
85
|
-
* Gets a Docker instance for building images.
|
|
86
|
-
*/
|
|
87
|
-
forBuild(options: DockerFactoryOptions): Promise<Docker>;
|
|
88
|
-
/**
|
|
89
|
-
* Gets a Docker instance for pushing images to ECR.
|
|
90
|
-
*/
|
|
91
|
-
forEcrPush(options: DockerFactoryOptions): Promise<Docker>;
|
|
92
|
-
private loginOncePerDestination;
|
|
93
|
-
}
|
|
94
|
-
export {};
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
import * as fs from "fs";
|
|
2
|
-
import * as os from "os";
|
|
3
|
-
import * as path from "path";
|
|
4
|
-
import { cdkCredentialsConfig, obtainEcrCredentials, } from "cdk-assets/lib/private/docker-credentials.js";
|
|
5
|
-
import { shell, } from "cdk-assets/lib/private/shell.js";
|
|
6
|
-
import { createCriticalSection } from "cdk-assets/lib/private/util.js";
|
|
7
|
-
var InspectImageErrorCode;
|
|
8
|
-
(function (InspectImageErrorCode) {
|
|
9
|
-
InspectImageErrorCode[InspectImageErrorCode["Docker"] = 1] = "Docker";
|
|
10
|
-
InspectImageErrorCode[InspectImageErrorCode["Podman"] = 125] = "Podman";
|
|
11
|
-
})(InspectImageErrorCode || (InspectImageErrorCode = {}));
|
|
12
|
-
export class Docker {
|
|
13
|
-
logger;
|
|
14
|
-
configDir = undefined;
|
|
15
|
-
constructor(logger) {
|
|
16
|
-
this.logger = logger;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Whether an image with the given tag exists
|
|
20
|
-
*/
|
|
21
|
-
async exists(tag) {
|
|
22
|
-
try {
|
|
23
|
-
await this.execute(["inspect", tag], { quiet: true });
|
|
24
|
-
return true;
|
|
25
|
-
}
|
|
26
|
-
catch (e) {
|
|
27
|
-
const error = e;
|
|
28
|
-
/**
|
|
29
|
-
* The only error we expect to be thrown will have this property and value.
|
|
30
|
-
* If it doesn't, it's unrecognized so re-throw it.
|
|
31
|
-
*/
|
|
32
|
-
if (error.code !== "PROCESS_FAILED") {
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* If we know the shell command above returned an error, check to see
|
|
37
|
-
* if the exit code is one we know to actually mean that the image doesn't
|
|
38
|
-
* exist.
|
|
39
|
-
*/
|
|
40
|
-
switch (error.exitCode) {
|
|
41
|
-
case InspectImageErrorCode.Docker:
|
|
42
|
-
case InspectImageErrorCode.Podman:
|
|
43
|
-
// Docker and Podman will return this exit code when an image doesn't exist, return false
|
|
44
|
-
// context: https://github.com/aws/aws-cdk/issues/16209
|
|
45
|
-
return false;
|
|
46
|
-
default:
|
|
47
|
-
// This is an error but it's not an exit code we recognize, throw.
|
|
48
|
-
throw error;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
async build(options) {
|
|
53
|
-
const buildCommand = [
|
|
54
|
-
"build",
|
|
55
|
-
...flatten(Object.entries(options.buildArgs || {}).map(([k, v]) => [
|
|
56
|
-
"--build-arg",
|
|
57
|
-
`${k}=${v}`,
|
|
58
|
-
])),
|
|
59
|
-
...flatten(Object.entries(options.buildSecrets || {}).map(([k, v]) => [
|
|
60
|
-
"--secret",
|
|
61
|
-
`id=${k},${v}`,
|
|
62
|
-
])),
|
|
63
|
-
"--tag",
|
|
64
|
-
options.tag,
|
|
65
|
-
...(options.target ? ["--target", options.target] : []),
|
|
66
|
-
...(options.file ? ["--file", options.file] : []),
|
|
67
|
-
...(options.networkMode ? ["--network", options.networkMode] : []),
|
|
68
|
-
...(options.platform ? ["--platform", options.platform] : []),
|
|
69
|
-
...(options.outputs
|
|
70
|
-
? options.outputs.map((output) => [`--output=${output}`])
|
|
71
|
-
: []),
|
|
72
|
-
...(options.cacheFrom
|
|
73
|
-
? [
|
|
74
|
-
...options.cacheFrom
|
|
75
|
-
.map((cacheFrom) => [
|
|
76
|
-
"--cache-from",
|
|
77
|
-
this.cacheOptionToFlag(cacheFrom),
|
|
78
|
-
])
|
|
79
|
-
.flat(),
|
|
80
|
-
]
|
|
81
|
-
: []),
|
|
82
|
-
...(options.cacheTo
|
|
83
|
-
? ["--cache-to", this.cacheOptionToFlag(options.cacheTo)]
|
|
84
|
-
: []),
|
|
85
|
-
".",
|
|
86
|
-
];
|
|
87
|
-
await this.execute(buildCommand, {
|
|
88
|
-
cwd: options.directory,
|
|
89
|
-
// TODO: remove after PR is merged
|
|
90
|
-
quiet: options.quiet,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* Get credentials from ECR and run docker login
|
|
95
|
-
*/
|
|
96
|
-
async login(ecr) {
|
|
97
|
-
const credentials = await obtainEcrCredentials(ecr);
|
|
98
|
-
// Use --password-stdin otherwise docker will complain. Loudly.
|
|
99
|
-
await this.execute([
|
|
100
|
-
"login",
|
|
101
|
-
"--username",
|
|
102
|
-
credentials.username,
|
|
103
|
-
"--password-stdin",
|
|
104
|
-
credentials.endpoint,
|
|
105
|
-
], {
|
|
106
|
-
input: credentials.password,
|
|
107
|
-
// Need to quiet otherwise Docker will complain
|
|
108
|
-
// 'WARNING! Your password will be stored unencrypted'
|
|
109
|
-
// doesn't really matter since it's a token.
|
|
110
|
-
quiet: true,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
async tag(sourceTag, targetTag) {
|
|
114
|
-
await this.execute(["tag", sourceTag, targetTag]);
|
|
115
|
-
}
|
|
116
|
-
// TODO: remove after PR is merged
|
|
117
|
-
async push(options) {
|
|
118
|
-
await this.execute(["push", options.tag], { quiet: options.quiet });
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* If a CDK Docker Credentials file exists, creates a new Docker config directory.
|
|
122
|
-
* Sets up `docker-credential-cdk-assets` to be the credential helper for each domain in the CDK config.
|
|
123
|
-
* All future commands (e.g., `build`, `push`) will use this config.
|
|
124
|
-
*
|
|
125
|
-
* See https://docs.docker.com/engine/reference/commandline/login/#credential-helpers for more details on cred helpers.
|
|
126
|
-
*
|
|
127
|
-
* @returns true if CDK config was found and configured, false otherwise
|
|
128
|
-
*/
|
|
129
|
-
configureCdkCredentials() {
|
|
130
|
-
const config = cdkCredentialsConfig();
|
|
131
|
-
if (!config) {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
this.configDir = fs.mkdtempSync(path.join(os.tmpdir(), "cdkDockerConfig"));
|
|
135
|
-
const domains = Object.keys(config.domainCredentials);
|
|
136
|
-
const credHelpers = domains.reduce((map, domain) => {
|
|
137
|
-
map[domain] = "cdk-assets"; // Use docker-credential-cdk-assets for this domain
|
|
138
|
-
return map;
|
|
139
|
-
}, {});
|
|
140
|
-
fs.writeFileSync(path.join(this.configDir, "config.json"), JSON.stringify({ credHelpers }), { encoding: "utf-8" });
|
|
141
|
-
return true;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Removes any configured Docker config directory.
|
|
145
|
-
* All future commands (e.g., `build`, `push`) will use the default config.
|
|
146
|
-
*
|
|
147
|
-
* This is useful after calling `configureCdkCredentials` to reset to default credentials.
|
|
148
|
-
*/
|
|
149
|
-
resetAuthPlugins() {
|
|
150
|
-
this.configDir = undefined;
|
|
151
|
-
}
|
|
152
|
-
async execute(args, options = {}) {
|
|
153
|
-
const configArgs = this.configDir ? ["--config", this.configDir] : [];
|
|
154
|
-
// TODO: remove after PR is merged
|
|
155
|
-
//const pathToCdkAssets = path.resolve(__dirname, "..", "..", "bin");
|
|
156
|
-
const pathToCdkAssets = "";
|
|
157
|
-
try {
|
|
158
|
-
await shell([getDockerCmd(), ...configArgs, ...args], {
|
|
159
|
-
logger: this.logger,
|
|
160
|
-
...options,
|
|
161
|
-
env: {
|
|
162
|
-
...process.env,
|
|
163
|
-
...options.env,
|
|
164
|
-
PATH: `${pathToCdkAssets}${path.delimiter}${options.env?.PATH ?? process.env.PATH}`,
|
|
165
|
-
},
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
catch (e) {
|
|
169
|
-
if (e.code === "ENOENT") {
|
|
170
|
-
throw new Error("Unable to execute 'docker' in order to build a container asset. Please install 'docker' and try again.");
|
|
171
|
-
}
|
|
172
|
-
throw e;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
cacheOptionToFlag(option) {
|
|
176
|
-
let flag = `type=${option.type}`;
|
|
177
|
-
if (option.params) {
|
|
178
|
-
flag +=
|
|
179
|
-
"," +
|
|
180
|
-
Object.entries(option.params)
|
|
181
|
-
.map(([k, v]) => `${k}=${v}`)
|
|
182
|
-
.join(",");
|
|
183
|
-
}
|
|
184
|
-
return flag;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
/**
|
|
188
|
-
* Helps get appropriately configured Docker instances during the container
|
|
189
|
-
* image publishing process.
|
|
190
|
-
*/
|
|
191
|
-
export class DockerFactory {
|
|
192
|
-
enterLoggedInDestinationsCriticalSection = createCriticalSection();
|
|
193
|
-
loggedInDestinations = new Set();
|
|
194
|
-
/**
|
|
195
|
-
* Gets a Docker instance for building images.
|
|
196
|
-
*/
|
|
197
|
-
async forBuild(options) {
|
|
198
|
-
const docker = new Docker(options.logger);
|
|
199
|
-
// Default behavior is to login before build so that the Dockerfile can reference images in the ECR repo
|
|
200
|
-
// However, if we're in a pipelines environment (for example),
|
|
201
|
-
// we may have alternative credentials to the default ones to use for the build itself.
|
|
202
|
-
// If the special config file is present, delay the login to the default credentials until the push.
|
|
203
|
-
// If the config file is present, we will configure and use those credentials for the build.
|
|
204
|
-
let cdkDockerCredentialsConfigured = docker.configureCdkCredentials();
|
|
205
|
-
if (!cdkDockerCredentialsConfigured) {
|
|
206
|
-
await this.loginOncePerDestination(docker, options);
|
|
207
|
-
}
|
|
208
|
-
return docker;
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* Gets a Docker instance for pushing images to ECR.
|
|
212
|
-
*/
|
|
213
|
-
async forEcrPush(options) {
|
|
214
|
-
const docker = new Docker(options.logger);
|
|
215
|
-
await this.loginOncePerDestination(docker, options);
|
|
216
|
-
return docker;
|
|
217
|
-
}
|
|
218
|
-
async loginOncePerDestination(docker, options) {
|
|
219
|
-
// Changes: 012345678910.dkr.ecr.us-west-2.amazonaws.com/tagging-test
|
|
220
|
-
// To this: 012345678910.dkr.ecr.us-west-2.amazonaws.com
|
|
221
|
-
const repositoryDomain = options.repoUri.split("/")[0];
|
|
222
|
-
// Ensure one-at-a-time access to loggedInDestinations.
|
|
223
|
-
await this.enterLoggedInDestinationsCriticalSection(async () => {
|
|
224
|
-
if (this.loggedInDestinations.has(repositoryDomain)) {
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
await docker.login(options.ecr);
|
|
228
|
-
this.loggedInDestinations.add(repositoryDomain);
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
function getDockerCmd() {
|
|
233
|
-
return process.env.CDK_DOCKER ?? "docker";
|
|
234
|
-
}
|
|
235
|
-
function flatten(x) {
|
|
236
|
-
return Array.prototype.concat([], ...x);
|
|
237
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { DockerImageManifestEntry } from "cdk-assets/lib/asset-manifest.js";
|
|
2
|
-
import { IAssetHandler, IHandlerHost, IHandlerOptions } from "../asset-handler.js";
|
|
3
|
-
export declare class ContainerImageAssetHandler implements IAssetHandler {
|
|
4
|
-
private readonly workDir;
|
|
5
|
-
private readonly asset;
|
|
6
|
-
private readonly host;
|
|
7
|
-
private readonly options;
|
|
8
|
-
private init?;
|
|
9
|
-
constructor(workDir: string, asset: DockerImageManifestEntry, host: IHandlerHost, options: IHandlerOptions);
|
|
10
|
-
build(): Promise<void>;
|
|
11
|
-
isPublished(): Promise<boolean>;
|
|
12
|
-
publish(): Promise<void>;
|
|
13
|
-
private initOnce;
|
|
14
|
-
/**
|
|
15
|
-
* Check whether the image already exists in the ECR repo
|
|
16
|
-
*
|
|
17
|
-
* Use the fields from the destination to do the actual check. The imageUri
|
|
18
|
-
* should correspond to that, but is only used to print Docker image location
|
|
19
|
-
* for user benefit (the format is slightly different).
|
|
20
|
-
*/
|
|
21
|
-
private destinationAlreadyExists;
|
|
22
|
-
}
|
|
@@ -1,231 +0,0 @@
|
|
|
1
|
-
import * as path from "path";
|
|
2
|
-
import { EventType } from "cdk-assets/lib/progress.js";
|
|
3
|
-
import { replaceAwsPlaceholders } from "cdk-assets/lib/private/placeholders.js";
|
|
4
|
-
import { shell } from "cdk-assets/lib/private/shell.js";
|
|
5
|
-
export class ContainerImageAssetHandler {
|
|
6
|
-
workDir;
|
|
7
|
-
asset;
|
|
8
|
-
host;
|
|
9
|
-
options;
|
|
10
|
-
init;
|
|
11
|
-
constructor(workDir, asset, host,
|
|
12
|
-
// TODO: remove after PR is merged
|
|
13
|
-
options) {
|
|
14
|
-
this.workDir = workDir;
|
|
15
|
-
this.asset = asset;
|
|
16
|
-
this.host = host;
|
|
17
|
-
this.options = options;
|
|
18
|
-
}
|
|
19
|
-
async build() {
|
|
20
|
-
const initOnce = await this.initOnce();
|
|
21
|
-
if (initOnce.destinationAlreadyExists) {
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (this.host.aborted) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const dockerForBuilding = await this.host.dockerFactory.forBuild({
|
|
28
|
-
repoUri: initOnce.repoUri,
|
|
29
|
-
logger: (m) => this.host.emitMessage(EventType.DEBUG, m),
|
|
30
|
-
ecr: initOnce.ecr,
|
|
31
|
-
});
|
|
32
|
-
const builder = new ContainerImageBuilder(dockerForBuilding, this.workDir, this.asset, this.host,
|
|
33
|
-
// TODO: remove after PR is merged
|
|
34
|
-
{
|
|
35
|
-
quiet: this.options.quiet,
|
|
36
|
-
});
|
|
37
|
-
const localTagName = await builder.build();
|
|
38
|
-
if (localTagName === undefined || this.host.aborted) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
if (this.host.aborted) {
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
await dockerForBuilding.tag(localTagName, initOnce.imageUri);
|
|
45
|
-
}
|
|
46
|
-
async isPublished() {
|
|
47
|
-
try {
|
|
48
|
-
const initOnce = await this.initOnce({ quiet: true });
|
|
49
|
-
return initOnce.destinationAlreadyExists;
|
|
50
|
-
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
this.host.emitMessage(EventType.DEBUG, `${e.message}`);
|
|
53
|
-
}
|
|
54
|
-
return false;
|
|
55
|
-
}
|
|
56
|
-
async publish() {
|
|
57
|
-
const initOnce = await this.initOnce();
|
|
58
|
-
if (initOnce.destinationAlreadyExists) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (this.host.aborted) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
const dockerForPushing = await this.host.dockerFactory.forEcrPush({
|
|
65
|
-
repoUri: initOnce.repoUri,
|
|
66
|
-
logger: (m) => this.host.emitMessage(EventType.DEBUG, m),
|
|
67
|
-
ecr: initOnce.ecr,
|
|
68
|
-
});
|
|
69
|
-
if (this.host.aborted) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
this.host.emitMessage(EventType.UPLOAD, `Push ${initOnce.imageUri}`);
|
|
73
|
-
// TODO: remove after PR is merged
|
|
74
|
-
await dockerForPushing.push({
|
|
75
|
-
tag: initOnce.imageUri,
|
|
76
|
-
quiet: this.options.quiet,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
async initOnce(options = {}) {
|
|
80
|
-
if (this.init) {
|
|
81
|
-
return this.init;
|
|
82
|
-
}
|
|
83
|
-
const destination = await replaceAwsPlaceholders(this.asset.destination, this.host.aws);
|
|
84
|
-
const ecr = await this.host.aws.ecrClient({
|
|
85
|
-
...destination,
|
|
86
|
-
quiet: options.quiet,
|
|
87
|
-
});
|
|
88
|
-
const account = async () => (await this.host.aws.discoverCurrentAccount())?.accountId;
|
|
89
|
-
const repoUri = await repositoryUri(ecr, destination.repositoryName);
|
|
90
|
-
if (!repoUri) {
|
|
91
|
-
throw new Error(`No ECR repository named '${destination.repositoryName}' in account ${await account()}. Is this account bootstrapped?`);
|
|
92
|
-
}
|
|
93
|
-
const imageUri = `${repoUri}:${destination.imageTag}`;
|
|
94
|
-
this.init = {
|
|
95
|
-
imageUri,
|
|
96
|
-
ecr,
|
|
97
|
-
repoUri,
|
|
98
|
-
destinationAlreadyExists: await this.destinationAlreadyExists(ecr, destination, imageUri),
|
|
99
|
-
};
|
|
100
|
-
return this.init;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Check whether the image already exists in the ECR repo
|
|
104
|
-
*
|
|
105
|
-
* Use the fields from the destination to do the actual check. The imageUri
|
|
106
|
-
* should correspond to that, but is only used to print Docker image location
|
|
107
|
-
* for user benefit (the format is slightly different).
|
|
108
|
-
*/
|
|
109
|
-
async destinationAlreadyExists(ecr, destination, imageUri) {
|
|
110
|
-
this.host.emitMessage(EventType.CHECK, `Check ${imageUri}`);
|
|
111
|
-
if (await imageExists(ecr, destination.repositoryName, destination.imageTag)) {
|
|
112
|
-
this.host.emitMessage(EventType.FOUND, `Found ${imageUri}`);
|
|
113
|
-
return true;
|
|
114
|
-
}
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
class ContainerImageBuilder {
|
|
119
|
-
docker;
|
|
120
|
-
workDir;
|
|
121
|
-
asset;
|
|
122
|
-
host;
|
|
123
|
-
options;
|
|
124
|
-
constructor(docker, workDir, asset, host,
|
|
125
|
-
// TODO: remove after PR is merged
|
|
126
|
-
options) {
|
|
127
|
-
this.docker = docker;
|
|
128
|
-
this.workDir = workDir;
|
|
129
|
-
this.asset = asset;
|
|
130
|
-
this.host = host;
|
|
131
|
-
this.options = options;
|
|
132
|
-
}
|
|
133
|
-
async build() {
|
|
134
|
-
return this.asset.source.executable
|
|
135
|
-
? this.buildExternalAsset(this.asset.source.executable)
|
|
136
|
-
: this.buildDirectoryAsset();
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Build a (local) Docker asset from a directory with a Dockerfile
|
|
140
|
-
*
|
|
141
|
-
* Tags under a deterministic, unique, local identifier wich will skip
|
|
142
|
-
* the build if it already exists.
|
|
143
|
-
*/
|
|
144
|
-
async buildDirectoryAsset() {
|
|
145
|
-
const localTagName = `cdkasset-${this.asset.id.assetId.toLowerCase()}`;
|
|
146
|
-
if (!(await this.isImageCached(localTagName))) {
|
|
147
|
-
if (this.host.aborted) {
|
|
148
|
-
return undefined;
|
|
149
|
-
}
|
|
150
|
-
await this.buildImage(localTagName);
|
|
151
|
-
}
|
|
152
|
-
return localTagName;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Build a (local) Docker asset by running an external command
|
|
156
|
-
*
|
|
157
|
-
* External command is responsible for deduplicating the build if possible,
|
|
158
|
-
* and is expected to return the generated image identifier on stdout.
|
|
159
|
-
*/
|
|
160
|
-
async buildExternalAsset(executable, cwd) {
|
|
161
|
-
const assetPath = cwd ?? this.workDir;
|
|
162
|
-
this.host.emitMessage(EventType.BUILD, `Building Docker image using command '${executable}'`);
|
|
163
|
-
if (this.host.aborted) {
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
return (await shell(executable, { cwd: assetPath, quiet: true })).trim();
|
|
167
|
-
}
|
|
168
|
-
async buildImage(localTagName) {
|
|
169
|
-
const source = this.asset.source;
|
|
170
|
-
if (!source.directory) {
|
|
171
|
-
throw new Error(`'directory' is expected in the DockerImage asset source, got: ${JSON.stringify(source)}`);
|
|
172
|
-
}
|
|
173
|
-
const fullPath = path.resolve(this.workDir, source.directory);
|
|
174
|
-
this.host.emitMessage(EventType.BUILD, `Building Docker image at ${fullPath}`);
|
|
175
|
-
await this.docker.build({
|
|
176
|
-
directory: fullPath,
|
|
177
|
-
tag: localTagName,
|
|
178
|
-
buildArgs: source.dockerBuildArgs,
|
|
179
|
-
buildSecrets: source.dockerBuildSecrets,
|
|
180
|
-
target: source.dockerBuildTarget,
|
|
181
|
-
file: source.dockerFile,
|
|
182
|
-
networkMode: source.networkMode,
|
|
183
|
-
platform: source.platform,
|
|
184
|
-
outputs: source.dockerOutputs,
|
|
185
|
-
cacheFrom: source.cacheFrom,
|
|
186
|
-
cacheTo: source.cacheTo,
|
|
187
|
-
// TODO: remove after PR is merged
|
|
188
|
-
quiet: this.options.quiet,
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
async isImageCached(localTagName) {
|
|
192
|
-
if (await this.docker.exists(localTagName)) {
|
|
193
|
-
this.host.emitMessage(EventType.CACHED, `Cached ${localTagName}`);
|
|
194
|
-
return true;
|
|
195
|
-
}
|
|
196
|
-
return false;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
async function imageExists(ecr, repositoryName, imageTag) {
|
|
200
|
-
try {
|
|
201
|
-
await ecr
|
|
202
|
-
.describeImages({ repositoryName, imageIds: [{ imageTag }] })
|
|
203
|
-
.promise();
|
|
204
|
-
return true;
|
|
205
|
-
}
|
|
206
|
-
catch (e) {
|
|
207
|
-
if (e.code !== "ImageNotFoundException") {
|
|
208
|
-
throw e;
|
|
209
|
-
}
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Return the URI for the repository with the given name
|
|
215
|
-
*
|
|
216
|
-
* Returns undefined if the repository does not exist.
|
|
217
|
-
*/
|
|
218
|
-
async function repositoryUri(ecr, repositoryName) {
|
|
219
|
-
try {
|
|
220
|
-
const response = await ecr
|
|
221
|
-
.describeRepositories({ repositoryNames: [repositoryName] })
|
|
222
|
-
.promise();
|
|
223
|
-
return (response.repositories || [])[0]?.repositoryUri;
|
|
224
|
-
}
|
|
225
|
-
catch (e) {
|
|
226
|
-
if (e.code !== "RepositoryNotFoundException") {
|
|
227
|
-
throw e;
|
|
228
|
-
}
|
|
229
|
-
return undefined;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { AssetManifest, IManifestEntry } from "cdk-assets/lib/asset-manifest.js";
|
|
2
|
-
import { IAssetHandler, IHandlerHost, IHandlerOptions } from "../asset-handler.js";
|
|
3
|
-
export declare function makeAssetHandler(manifest: AssetManifest, asset: IManifestEntry, host: IHandlerHost, options: IHandlerOptions): IAssetHandler;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { ContainerImageAssetHandler } from "./container-images.js";
|
|
2
|
-
import { FileAssetHandler } from "cdk-assets/lib/private/handlers/files.js";
|
|
3
|
-
import { DockerImageManifestEntry, FileManifestEntry, } from "cdk-assets/lib/asset-manifest.js";
|
|
4
|
-
export function makeAssetHandler(manifest, asset, host,
|
|
5
|
-
// TODO: remove after PR is merged
|
|
6
|
-
options) {
|
|
7
|
-
if (asset instanceof FileManifestEntry) {
|
|
8
|
-
// TODO: remove after PR is merged
|
|
9
|
-
// @ts-ignore
|
|
10
|
-
return new FileAssetHandler(manifest.directory, asset, host);
|
|
11
|
-
}
|
|
12
|
-
if (asset instanceof DockerImageManifestEntry) {
|
|
13
|
-
return new ContainerImageAssetHandler(manifest.directory, asset, host,
|
|
14
|
-
// TODO: remove after PR is merged
|
|
15
|
-
options);
|
|
16
|
-
}
|
|
17
|
-
throw new Error(`Unrecognized asset type: '${asset}'`);
|
|
18
|
-
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { AssetManifest, IManifestEntry } from "cdk-assets/lib/asset-manifest.js";
|
|
2
|
-
import { IAws } from "cdk-assets/lib/aws.js";
|
|
3
|
-
import { IPublishProgress, IPublishProgressListener } from "cdk-assets/lib/progress.js";
|
|
4
|
-
export interface AssetPublishingOptions {
|
|
5
|
-
/**
|
|
6
|
-
* Entry point for AWS client
|
|
7
|
-
*/
|
|
8
|
-
readonly aws: IAws;
|
|
9
|
-
/**
|
|
10
|
-
* Listener for progress events
|
|
11
|
-
*
|
|
12
|
-
* @default No listener
|
|
13
|
-
*/
|
|
14
|
-
readonly progressListener?: IPublishProgressListener;
|
|
15
|
-
/**
|
|
16
|
-
* Whether to throw at the end if there were errors
|
|
17
|
-
*
|
|
18
|
-
* @default true
|
|
19
|
-
*/
|
|
20
|
-
readonly throwOnError?: boolean;
|
|
21
|
-
/**
|
|
22
|
-
* Whether to publish in parallel, when 'publish()' is called
|
|
23
|
-
*
|
|
24
|
-
* @default false
|
|
25
|
-
*/
|
|
26
|
-
readonly publishInParallel?: boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Whether to build assets, when 'publish()' is called
|
|
29
|
-
*
|
|
30
|
-
* @default true
|
|
31
|
-
*/
|
|
32
|
-
readonly buildAssets?: boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Whether to publish assets, when 'publish()' is called
|
|
35
|
-
*
|
|
36
|
-
* @default true
|
|
37
|
-
*/
|
|
38
|
-
readonly publishAssets?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Whether to print publishing logs
|
|
41
|
-
*
|
|
42
|
-
* @default true
|
|
43
|
-
*/
|
|
44
|
-
readonly quiet?: boolean;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* A failure to publish an asset
|
|
48
|
-
*/
|
|
49
|
-
export interface FailedAsset {
|
|
50
|
-
/**
|
|
51
|
-
* The asset that failed to publish
|
|
52
|
-
*/
|
|
53
|
-
readonly asset: IManifestEntry;
|
|
54
|
-
/**
|
|
55
|
-
* The failure that occurred
|
|
56
|
-
*/
|
|
57
|
-
readonly error: Error;
|
|
58
|
-
}
|
|
59
|
-
export declare class AssetPublishing implements IPublishProgress {
|
|
60
|
-
private readonly manifest;
|
|
61
|
-
private readonly options;
|
|
62
|
-
/**
|
|
63
|
-
* The message for the IPublishProgress interface
|
|
64
|
-
*/
|
|
65
|
-
message: string;
|
|
66
|
-
/**
|
|
67
|
-
* The current asset for the IPublishProgress interface
|
|
68
|
-
*/
|
|
69
|
-
currentAsset?: IManifestEntry;
|
|
70
|
-
readonly failures: FailedAsset[];
|
|
71
|
-
private readonly assets;
|
|
72
|
-
private readonly totalOperations;
|
|
73
|
-
private completedOperations;
|
|
74
|
-
private aborted;
|
|
75
|
-
private readonly handlerHost;
|
|
76
|
-
private readonly publishInParallel;
|
|
77
|
-
private readonly buildAssets;
|
|
78
|
-
private readonly publishAssets;
|
|
79
|
-
private readonly handlerCache;
|
|
80
|
-
constructor(manifest: AssetManifest, options: AssetPublishingOptions);
|
|
81
|
-
/**
|
|
82
|
-
* Publish all assets from the manifest
|
|
83
|
-
*/
|
|
84
|
-
publish(): Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Build a single asset from the manifest
|
|
87
|
-
*/
|
|
88
|
-
buildEntry(asset: IManifestEntry): Promise<boolean>;
|
|
89
|
-
/**
|
|
90
|
-
* Publish a single asset from the manifest
|
|
91
|
-
*/
|
|
92
|
-
publishEntry(asset: IManifestEntry): Promise<boolean>;
|
|
93
|
-
/**
|
|
94
|
-
* Return whether a single asset is published
|
|
95
|
-
*/
|
|
96
|
-
isEntryPublished(asset: IManifestEntry): Promise<boolean>;
|
|
97
|
-
/**
|
|
98
|
-
* publish an asset (used by 'publish()')
|
|
99
|
-
* @param asset The asset to publish
|
|
100
|
-
* @returns false when publishing should stop
|
|
101
|
-
*/
|
|
102
|
-
private publishAsset;
|
|
103
|
-
get percentComplete(): number;
|
|
104
|
-
abort(): void;
|
|
105
|
-
get hasFailures(): boolean;
|
|
106
|
-
/**
|
|
107
|
-
* Publish a progress event to the listener, if present.
|
|
108
|
-
*
|
|
109
|
-
* Returns whether an abort is requested. Helper to get rid of repetitive code in publish().
|
|
110
|
-
*/
|
|
111
|
-
private progressEvent;
|
|
112
|
-
private assetHandler;
|
|
113
|
-
}
|
package/cdk-assets/publishing.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { DockerFactory } from "./private/docker.js";
|
|
2
|
-
import { makeAssetHandler } from "./private/handlers/index.js";
|
|
3
|
-
import { EventType, } from "cdk-assets/lib/progress.js";
|
|
4
|
-
export class AssetPublishing {
|
|
5
|
-
manifest;
|
|
6
|
-
options;
|
|
7
|
-
/**
|
|
8
|
-
* The message for the IPublishProgress interface
|
|
9
|
-
*/
|
|
10
|
-
message = "Starting";
|
|
11
|
-
/**
|
|
12
|
-
* The current asset for the IPublishProgress interface
|
|
13
|
-
*/
|
|
14
|
-
currentAsset;
|
|
15
|
-
failures = new Array();
|
|
16
|
-
assets;
|
|
17
|
-
totalOperations;
|
|
18
|
-
completedOperations = 0;
|
|
19
|
-
aborted = false;
|
|
20
|
-
handlerHost;
|
|
21
|
-
publishInParallel;
|
|
22
|
-
buildAssets;
|
|
23
|
-
publishAssets;
|
|
24
|
-
handlerCache = new Map();
|
|
25
|
-
constructor(manifest, options) {
|
|
26
|
-
this.manifest = manifest;
|
|
27
|
-
this.options = options;
|
|
28
|
-
this.assets = manifest.entries;
|
|
29
|
-
this.totalOperations = this.assets.length;
|
|
30
|
-
this.publishInParallel = options.publishInParallel ?? false;
|
|
31
|
-
this.buildAssets = options.buildAssets ?? true;
|
|
32
|
-
this.publishAssets = options.publishAssets ?? true;
|
|
33
|
-
const self = this;
|
|
34
|
-
this.handlerHost = {
|
|
35
|
-
aws: this.options.aws,
|
|
36
|
-
get aborted() {
|
|
37
|
-
return self.aborted;
|
|
38
|
-
},
|
|
39
|
-
emitMessage(t, m) {
|
|
40
|
-
self.progressEvent(t, m);
|
|
41
|
-
},
|
|
42
|
-
dockerFactory: new DockerFactory(),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Publish all assets from the manifest
|
|
47
|
-
*/
|
|
48
|
-
async publish() {
|
|
49
|
-
if (this.publishInParallel) {
|
|
50
|
-
await Promise.all(this.assets.map(async (asset) => this.publishAsset(asset)));
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
for (const asset of this.assets) {
|
|
54
|
-
if (!(await this.publishAsset(asset))) {
|
|
55
|
-
break;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if ((this.options.throwOnError ?? true) && this.failures.length > 0) {
|
|
60
|
-
throw new Error(`Error publishing: ${this.failures.map((e) => e.error.message)}`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Build a single asset from the manifest
|
|
65
|
-
*/
|
|
66
|
-
async buildEntry(asset) {
|
|
67
|
-
try {
|
|
68
|
-
if (this.progressEvent(EventType.START, `Building ${asset.id}`)) {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
const handler = this.assetHandler(asset);
|
|
72
|
-
await handler.build();
|
|
73
|
-
if (this.aborted) {
|
|
74
|
-
throw new Error("Aborted");
|
|
75
|
-
}
|
|
76
|
-
this.completedOperations++;
|
|
77
|
-
if (this.progressEvent(EventType.SUCCESS, `Built ${asset.id}`)) {
|
|
78
|
-
return false;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
catch (e) {
|
|
82
|
-
this.failures.push({ asset, error: e });
|
|
83
|
-
this.completedOperations++;
|
|
84
|
-
if (this.progressEvent(EventType.FAIL, e.message)) {
|
|
85
|
-
return false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
return true;
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Publish a single asset from the manifest
|
|
92
|
-
*/
|
|
93
|
-
async publishEntry(asset) {
|
|
94
|
-
try {
|
|
95
|
-
if (this.progressEvent(EventType.START, `Publishing ${asset.id}`)) {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
const handler = this.assetHandler(asset);
|
|
99
|
-
await handler.publish();
|
|
100
|
-
if (this.aborted) {
|
|
101
|
-
throw new Error("Aborted");
|
|
102
|
-
}
|
|
103
|
-
this.completedOperations++;
|
|
104
|
-
if (this.progressEvent(EventType.SUCCESS, `Published ${asset.id}`)) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
catch (e) {
|
|
109
|
-
this.failures.push({ asset, error: e });
|
|
110
|
-
this.completedOperations++;
|
|
111
|
-
if (this.progressEvent(EventType.FAIL, e.message)) {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return true;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Return whether a single asset is published
|
|
119
|
-
*/
|
|
120
|
-
isEntryPublished(asset) {
|
|
121
|
-
const handler = this.assetHandler(asset);
|
|
122
|
-
return handler.isPublished();
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* publish an asset (used by 'publish()')
|
|
126
|
-
* @param asset The asset to publish
|
|
127
|
-
* @returns false when publishing should stop
|
|
128
|
-
*/
|
|
129
|
-
async publishAsset(asset) {
|
|
130
|
-
try {
|
|
131
|
-
if (this.progressEvent(EventType.START, `Publishing ${asset.id}`)) {
|
|
132
|
-
return false;
|
|
133
|
-
}
|
|
134
|
-
const handler = this.assetHandler(asset);
|
|
135
|
-
if (this.buildAssets) {
|
|
136
|
-
await handler.build();
|
|
137
|
-
}
|
|
138
|
-
if (this.publishAssets) {
|
|
139
|
-
await handler.publish();
|
|
140
|
-
}
|
|
141
|
-
if (this.aborted) {
|
|
142
|
-
throw new Error("Aborted");
|
|
143
|
-
}
|
|
144
|
-
this.completedOperations++;
|
|
145
|
-
if (this.progressEvent(EventType.SUCCESS, `Published ${asset.id}`)) {
|
|
146
|
-
return false;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (e) {
|
|
150
|
-
this.failures.push({ asset, error: e });
|
|
151
|
-
this.completedOperations++;
|
|
152
|
-
if (this.progressEvent(EventType.FAIL, e.message)) {
|
|
153
|
-
return false;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return true;
|
|
157
|
-
}
|
|
158
|
-
get percentComplete() {
|
|
159
|
-
if (this.totalOperations === 0) {
|
|
160
|
-
return 100;
|
|
161
|
-
}
|
|
162
|
-
return Math.floor((this.completedOperations / this.totalOperations) * 100);
|
|
163
|
-
}
|
|
164
|
-
abort() {
|
|
165
|
-
this.aborted = true;
|
|
166
|
-
}
|
|
167
|
-
get hasFailures() {
|
|
168
|
-
return this.failures.length > 0;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Publish a progress event to the listener, if present.
|
|
172
|
-
*
|
|
173
|
-
* Returns whether an abort is requested. Helper to get rid of repetitive code in publish().
|
|
174
|
-
*/
|
|
175
|
-
progressEvent(event, message) {
|
|
176
|
-
this.message = message;
|
|
177
|
-
if (this.options.progressListener) {
|
|
178
|
-
this.options.progressListener.onPublishEvent(event, this);
|
|
179
|
-
}
|
|
180
|
-
return this.aborted;
|
|
181
|
-
}
|
|
182
|
-
assetHandler(asset) {
|
|
183
|
-
const existing = this.handlerCache.get(asset);
|
|
184
|
-
if (existing) {
|
|
185
|
-
return existing;
|
|
186
|
-
}
|
|
187
|
-
const ret = makeAssetHandler(this.manifest, asset, this.handlerHost, {
|
|
188
|
-
// TODO: remove after PR is merged
|
|
189
|
-
quiet: this.options.quiet,
|
|
190
|
-
});
|
|
191
|
-
this.handlerCache.set(asset, ret);
|
|
192
|
-
return ret;
|
|
193
|
-
}
|
|
194
|
-
}
|