Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(s3-assets): cannot publish a file without extension (#30597)
### Issue # (if applicable) Closes #30471 ### ### Reason for this change Publishing a file with no extension using the `Asset` class with `BundlingOutput.SINGLE_FILE` and `AssetHashType.SOURCE`(default), as shown below, will result in an error `fail: EISDIR: illegal operation on a directory, read`, and publishing will fail. ```ts export class AssetTestStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const asset = new s3assets.Asset(this, 'asset', { path: path.join(__dirname, '../assets/main'), bundling: { image: DockerImage.fromRegistry('golang:1.21'), entrypoint: ["bash", "-c"], command: ["echo 123 > /asset-output/main"], // a file without extension outputType: BundlingOutput.SINGLE_FILE, }, }); new CfnOutput(this, 'AssetHash', { value: asset.assetHash }); } } ``` This is because the path in `*.asset.json` is different from the actual file path. The `*.asset.json` expects the file to be in `asset.bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0`, but when I check the `cdk.out` directory, I see that `asset.bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0` is a directory, not a file. ```json { "version": "36.0.0", "files": { "bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0": { "source": { "path": "asset.bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0", "packaging": "file" }, "destinations": { "current_account-us-east-1": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", "objectKey": "bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0.bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" } } } } ``` ```bash cdk.out ├── SampleStack.assets.json ├── SampleStack.template.json ├── asset.bead5b2c0d128650228f146d2326d5f3cbfb36738a9383fc6a09b1e9278803f0 │ └── main ├── cdk.out ├── manifest.json └── tree.json ``` If I change it to a file with an extension, as shown below, I see that the file with the extension is staged under `cdk.out` dir, and the asset is published successfully. ```ts export class AssetTestStack extends Stack { constructor(scope: Construct, id: string, props?: StackProps) { super(scope, id, props); const asset = new s3assets.Asset(this, 'asset', { path: path.join(__dirname, '../assets/main'), bundling: { image: DockerImage.fromRegistry('golang:1.21'), entrypoint: ["bash", "-c"], command: ["echo 123 > /asset-output/main.bin"], // a file with an extension outputType: BundlingOutput.SINGLE_FILE, }, }); new CfnOutput(this, 'AssetHash', { value: asset.assetHash }); } } ``` ```bash cdk.out ├── SampleStack.assets.json ├── SampleStack.template.json ├── asset.dc5ce447844d7490834e46df016edc7f671b4fae19ab55b6c78973dcb5af98f8 │ └── main.bin ├── asset.dc5ce447844d7490834e46df016edc7f671b4fae19ab55b6c78973dcb5af98f8.bin # !! staged file here !! ├── cdk.out ├── manifest.json └── tree.json ``` ```json { "version": "36.0.0", "files": { "dc5ce447844d7490834e46df016edc7f671b4fae19ab55b6c78973dcb5af98f8": { "source": { "path": "asset.dc5ce447844d7490834e46df016edc7f671b4fae19ab55b6c78973dcb5af98f8.bin", "packaging": "file" }, "destinations": { "current_account-us-east-1": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-us-east-1", "objectKey": "dc5ce447844d7490834e46df016edc7f671b4fae19ab55b6c78973dcb5af98f8.bin", "region": "us-east-1", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-us-east-1" } } } } ``` Files without extensions must be staged correctly in order to be published correctly. ### Description of changes The directory to write the bundling output is usually `cdk.out/asset.{asset hash}`. If the extension exists, it will be renamed from `cdk.out/asset.{asset hash}/{asset file name}` to `cdk.out/{asset hash}.{asset file extension}`. https://github.com/aws/aws-cdk/blob/c826d8faaeb310623eb9a1a1c82930b679768007/packages/aws-cdk-lib/core/lib/asset-staging.ts#L392 If the extension does not exist, the file name `cdk.out/asset.{asset hash}` (without extension) will be the same as the directory where bundling output is written. Therefore, the file is already considered staged and will not be staged correctly. https://github.com/aws/aws-cdk/blob/c826d8faaeb310623eb9a1a1c82930b679768007/packages/aws-cdk-lib/core/lib/asset-staging.ts#L383 Therefore, in such cases, I fix to change the file name by adding a suffix such as `noext` after the file name so that the file is correctly renamed. ### Description of how you validated changes unit tests and integ test. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information