Skip to content

Commit a735b52

Browse files
Elad Ben-IsraelNetaNir
authored andcommitted
fix(core): ENOTDIR invalid cwd on "cdk deploy" (#13145)
This commit reverts two recent changes to the asset system (#12258 and ##13076) which introduced a regression in 1.90.0. Fixes #13131 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 7edba31 commit a735b52

File tree

8 files changed

+42
-274
lines changed

8 files changed

+42
-274
lines changed

allowed-breaking-changes.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,10 @@ incompatible-argument:@aws-cdk/aws-ecs.TaskDefinition.addVolume
5656
# We made properties optional and it's really fine but our differ doesn't think so.
5757
weakened:@aws-cdk/cloud-assembly-schema.DockerImageSource
5858
weakened:@aws-cdk/cloud-assembly-schema.FileSource
59+
60+
# https://github.com/aws/aws-cdk/pull/13145
61+
removed:@aws-cdk/core.AssetStaging.isArchive
62+
removed:@aws-cdk/core.AssetStaging.packaging
63+
removed:@aws-cdk/core.BundlingOutput
64+
removed:@aws-cdk/core.BundlingOptions.outputType
65+

packages/@aws-cdk/aws-s3-assets/README.md

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -124,27 +124,6 @@ new assets.Asset(this, 'BundledAsset', {
124124
Although optional, it's recommended to provide a local bundling method which can
125125
greatly improve performance.
126126

127-
If the bundling output contains a single archive file (zip or jar) it will be
128-
uploaded to S3 as-is and will not be zipped. Otherwise the contents of the
129-
output directory will be zipped and the zip file will be uploaded to S3. This
130-
is the default behavior for `bundling.outputType` (`BundlingOutput.AUTO_DISCOVER`).
131-
132-
Use `BundlingOutput.NOT_ARCHIVED` if the bundling output must always be zipped:
133-
134-
```ts
135-
const asset = new assets.Asset(this, 'BundledAsset', {
136-
path: '/path/to/asset',
137-
bundling: {
138-
image: BundlingDockerImage.fromRegistry('alpine'),
139-
command: ['command-that-produces-an-archive.sh'],
140-
outputType: BundlingOutput.NOT_ARCHIVED, // Bundling output will be zipped even though it produces a single archive file.
141-
},
142-
});
143-
```
144-
145-
Use `BundlingOutput.ARCHIVED` if the bundling output contains a single archive file and
146-
you don't want it to be zippped.
147-
148127
## CloudFormation Resource Metadata
149128

150129
> NOTE: This section is relevant for authors of AWS Resource Constructs.

packages/@aws-cdk/aws-s3-assets/lib/asset.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as fs from 'fs';
12
import * as path from 'path';
23
import * as assets from '@aws-cdk/assets';
34
import * as iam from '@aws-cdk/aws-iam';
@@ -12,6 +13,8 @@ import { toSymlinkFollow } from './compat';
1213
// eslint-disable-next-line no-duplicate-imports, import/order
1314
import { Construct as CoreConstruct } from '@aws-cdk/core';
1415

16+
const ARCHIVE_EXTENSIONS = ['.zip', '.jar'];
17+
1518
export interface AssetOptions extends assets.CopyOptions, cdk.AssetOptions {
1619
/**
1720
* A list of principals that should be able to read this asset from S3.
@@ -136,12 +139,17 @@ export class Asset extends CoreConstruct implements cdk.IAsset {
136139

137140
this.assetPath = staging.relativeStagedPath(stack);
138141

139-
this.isFile = staging.packaging === cdk.FileAssetPackaging.FILE;
142+
const packaging = determinePackaging(staging.sourcePath);
143+
144+
this.isFile = packaging === cdk.FileAssetPackaging.FILE;
140145

141-
this.isZipArchive = staging.isArchive;
146+
// sets isZipArchive based on the type of packaging and file extension
147+
this.isZipArchive = packaging === cdk.FileAssetPackaging.ZIP_DIRECTORY
148+
? true
149+
: ARCHIVE_EXTENSIONS.some(ext => staging.sourcePath.toLowerCase().endsWith(ext));
142150

143151
const location = stack.synthesizer.addFileAsset({
144-
packaging: staging.packaging,
152+
packaging,
145153
sourceHash: this.sourceHash,
146154
fileName: this.assetPath,
147155
});
@@ -202,3 +210,19 @@ export class Asset extends CoreConstruct implements cdk.IAsset {
202210
this.bucket.grantRead(grantee);
203211
}
204212
}
213+
214+
function determinePackaging(assetPath: string): cdk.FileAssetPackaging {
215+
if (!fs.existsSync(assetPath)) {
216+
throw new Error(`Cannot find asset at ${assetPath}`);
217+
}
218+
219+
if (fs.statSync(assetPath).isDirectory()) {
220+
return cdk.FileAssetPackaging.ZIP_DIRECTORY;
221+
}
222+
223+
if (fs.statSync(assetPath).isFile()) {
224+
return cdk.FileAssetPackaging.FILE;
225+
}
226+
227+
throw new Error(`Asset ${assetPath} is expected to be either a directory or a regular file`);
228+
}

packages/@aws-cdk/core/lib/asset-staging.ts

Lines changed: 5 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import * as cxapi from '@aws-cdk/cx-api';
55
import { Construct } from 'constructs';
66
import * as fs from 'fs-extra';
77
import * as minimatch from 'minimatch';
8-
import { AssetHashType, AssetOptions, FileAssetPackaging } from './assets';
9-
import { BundlingOptions, BundlingOutput } from './bundling';
8+
import { AssetHashType, AssetOptions } from './assets';
9+
import { BundlingOptions } from './bundling';
1010
import { FileSystem, FingerprintOptions } from './fs';
1111
import { Names } from './names';
1212
import { Cache } from './private/cache';
@@ -17,8 +17,6 @@ import { Stage } from './stage';
1717
// eslint-disable-next-line
1818
import { Construct as CoreConstruct } from './construct-compat';
1919

20-
const ARCHIVE_EXTENSIONS = ['.zip', '.jar'];
21-
2220
/**
2321
* A previously staged asset
2422
*/
@@ -140,9 +138,6 @@ export class AssetStaging extends CoreConstruct {
140138

141139
private readonly cacheKey: string;
142140

143-
private _packaging = FileAssetPackaging.ZIP_DIRECTORY;
144-
private _isArchive = true;
145-
146141
constructor(scope: Construct, id: string, props: AssetStagingProps) {
147142
super(scope, id);
148143

@@ -208,20 +203,6 @@ export class AssetStaging extends CoreConstruct {
208203
return this.assetHash;
209204
}
210205

211-
/**
212-
* How this asset should be packaged.
213-
*/
214-
public get packaging(): FileAssetPackaging {
215-
return this._packaging;
216-
}
217-
218-
/**
219-
* Whether this asset is an archive (zip or jar).
220-
*/
221-
public get isArchive(): boolean {
222-
return this._isArchive;
223-
}
224-
225206
/**
226207
* Return the path to the staged asset, relative to the Cloud Assembly (manifest) directory of the given stack
227208
*
@@ -300,16 +281,11 @@ export class AssetStaging extends CoreConstruct {
300281
const bundleDir = this.determineBundleDir(this.assetOutdir, assetHash);
301282
this.bundle(bundling, bundleDir);
302283

303-
// Check bundling output content and determine if we will need to archive
304-
const bundlingOutputType = bundling.outputType ?? BundlingOutput.AUTO_DISCOVER;
305-
const bundledAsset = determineBundledAsset(bundleDir, bundlingOutputType);
306-
this._packaging = bundledAsset.packaging;
307-
308284
// Calculate assetHash afterwards if we still must
309-
assetHash = assetHash ?? this.calculateHash(this.hashType, bundling, bundledAsset.path);
310-
const stagedPath = path.resolve(this.assetOutdir, renderAssetFilename(assetHash, bundledAsset.extension));
285+
assetHash = assetHash ?? this.calculateHash(this.hashType, bundling, bundleDir);
286+
const stagedPath = path.resolve(this.assetOutdir, renderAssetFilename(assetHash));
311287

312-
this.stageAsset(bundledAsset.path, stagedPath, 'move');
288+
this.stageAsset(bundleDir, stagedPath, 'move');
313289
return { assetHash, stagedPath };
314290
}
315291

@@ -347,8 +323,6 @@ export class AssetStaging extends CoreConstruct {
347323
const stat = fs.statSync(sourcePath);
348324
if (stat.isFile()) {
349325
fs.copyFileSync(sourcePath, targetPath);
350-
this._packaging = FileAssetPackaging.FILE;
351-
this._isArchive = ARCHIVE_EXTENSIONS.includes(path.extname(sourcePath).toLowerCase());
352326
} else if (stat.isDirectory()) {
353327
fs.mkdirSync(targetPath);
354328
FileSystem.copyDirectory(sourcePath, targetPath, this.fingerprintOptions);
@@ -528,57 +502,3 @@ function sortObject(object: { [key: string]: any }): { [key: string]: any } {
528502
}
529503
return ret;
530504
}
531-
532-
/**
533-
* Returns the single archive file of a directory or undefined
534-
*/
535-
function singleArchiveFile(directory: string): string | undefined {
536-
if (!fs.existsSync(directory)) {
537-
throw new Error(`Directory ${directory} does not exist.`);
538-
}
539-
540-
if (!fs.statSync(directory).isDirectory()) {
541-
throw new Error(`${directory} is not a directory.`);
542-
}
543-
544-
const content = fs.readdirSync(directory);
545-
if (content.length === 1) {
546-
const file = path.join(directory, content[0]);
547-
const extension = path.extname(content[0]).toLowerCase();
548-
if (fs.statSync(file).isFile() && ARCHIVE_EXTENSIONS.includes(extension)) {
549-
return file;
550-
}
551-
}
552-
553-
return undefined;
554-
}
555-
556-
interface BundledAsset {
557-
path: string,
558-
packaging: FileAssetPackaging,
559-
extension?: string
560-
}
561-
562-
/**
563-
* Returns the bundled asset to use based on the content of the bundle directory
564-
* and the type of output.
565-
*/
566-
function determineBundledAsset(bundleDir: string, outputType: BundlingOutput): BundledAsset {
567-
const archiveFile = singleArchiveFile(bundleDir);
568-
569-
// auto-discover means that if there is an archive file, we take it as the
570-
// bundle, otherwise, we will archive here.
571-
if (outputType === BundlingOutput.AUTO_DISCOVER) {
572-
outputType = archiveFile ? BundlingOutput.ARCHIVED : BundlingOutput.NOT_ARCHIVED;
573-
}
574-
575-
switch (outputType) {
576-
case BundlingOutput.NOT_ARCHIVED:
577-
return { path: bundleDir, packaging: FileAssetPackaging.ZIP_DIRECTORY };
578-
case BundlingOutput.ARCHIVED:
579-
if (!archiveFile) {
580-
throw new Error('Bundling output directory is expected to include only a single .zip or .jar file when `output` is set to `ARCHIVED`');
581-
}
582-
return { path: archiveFile, packaging: FileAssetPackaging.FILE, extension: path.extname(archiveFile) };
583-
}
584-
}

packages/@aws-cdk/core/lib/bundling.ts

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -79,41 +79,6 @@ export interface BundlingOptions {
7979
* @experimental
8080
*/
8181
readonly local?: ILocalBundling;
82-
83-
/**
84-
* The type of output that this bundling operation is producing.
85-
*
86-
* @default BundlingOutput.AUTO_DISCOVER
87-
*
88-
* @experimental
89-
*/
90-
readonly outputType?: BundlingOutput;
91-
}
92-
93-
/**
94-
* The type of output that a bundling operation is producing.
95-
*
96-
* @experimental
97-
*/
98-
export enum BundlingOutput {
99-
/**
100-
* The bundling output directory includes a single .zip or .jar file which
101-
* will be used as the final bundle. If the output directory does not
102-
* include exactly a single archive, bundling will fail.
103-
*/
104-
ARCHIVED = 'archived',
105-
106-
/**
107-
* The bundling output directory contains one or more files which will be
108-
* archived and uploaded as a .zip file to S3.
109-
*/
110-
NOT_ARCHIVED = 'not-archived',
111-
112-
/**
113-
* If the bundling output directory contains a single archive file (zip or jar)
114-
* it will not be zipped. Otherwise the bundling output will be zipped.
115-
*/
116-
AUTO_DISCOVER = 'auto-discover',
11782
}
11883

11984
/**

packages/@aws-cdk/core/test/archive/archive.zip

Whitespace-only changes.

packages/@aws-cdk/core/test/docker-stub.sh

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,5 @@ if echo "$@" | grep "DOCKER_STUB_SUCCESS"; then
2424
exit 0
2525
fi
2626

27-
if echo "$@" | grep "DOCKER_STUB_MULTIPLE_FILES"; then
28-
outdir=$(echo "$@" | xargs -n1 | grep "/asset-output" | head -n1 | cut -d":" -f1)
29-
touch ${outdir}/test1.txt
30-
touch ${outdir}/test2.txt
31-
exit 0
32-
fi
33-
34-
if echo "$@" | grep "DOCKER_STUB_SINGLE_ARCHIVE"; then
35-
outdir=$(echo "$@" | xargs -n1 | grep "/asset-output" | head -n1 | cut -d":" -f1)
36-
touch ${outdir}/test.zip
37-
exit 0
38-
fi
39-
40-
echo "Docker mock only supports one of the following commands: DOCKER_STUB_SUCCESS_NO_OUTPUT,DOCKER_STUB_FAIL,DOCKER_STUB_SUCCESS,DOCKER_STUB_MULTIPLE_FILES,DOCKER_SINGLE_ARCHIVE"
27+
echo "Docker mock only supports one of the following commands: DOCKER_STUB_SUCCESS_NO_OUTPUT,DOCKER_STUB_FAIL,DOCKER_STUB_SUCCESS"
4128
exit 1

0 commit comments

Comments
 (0)