From 4bd84533f5a2bb6c14bc7fb48e37590e9d26f5f6 Mon Sep 17 00:00:00 2001 From: Elad Ben-Israel Date: Thu, 30 Apr 2020 15:00:02 +0300 Subject: [PATCH] refactor(core): fold "assets" to "core" Fold the "assets" module, which includes the `Staging` construct that takes care of staging asset files into the cloud assembly during synthesis into "core". This is in order to allow implementing custom resources that leverage assets throughout the framework. A subsequent commit will add a mini-framework for custom resources that leverages this capability. --- package.json | 4 +- packages/@aws-cdk/assets/README.md | 10 +-- packages/@aws-cdk/assets/lib/api.ts | 11 --- .../@aws-cdk/assets/lib/fs/follow-mode.ts | 29 ------- packages/@aws-cdk/assets/lib/fs/index.ts | 4 - packages/@aws-cdk/assets/lib/fs/options.ts | 33 -------- packages/@aws-cdk/assets/lib/index.ts | 71 +++++++++++++++- packages/@aws-cdk/assets/package.json | 21 ++--- packages/@aws-cdk/aws-codebuild/package.json | 2 - .../aws-ecr-assets/lib/image-asset.ts | 9 +- packages/@aws-cdk/aws-ecr-assets/package.json | 2 - .../package.json | 2 - packages/@aws-cdk/aws-s3-assets/lib/asset.ts | 7 +- packages/@aws-cdk/aws-s3-assets/package.json | 2 - .../@aws-cdk/aws-s3-deployment/package.json | 1 - .../aws-stepfunctions-tasks/package.json | 2 - .../staging.ts => core/lib/asset-staging.ts} | 20 +++-- packages/@aws-cdk/core/lib/assets.ts | 12 +++ .../@aws-cdk/{assets => core}/lib/fs/copy.ts | 7 +- .../{assets => core}/lib/fs/fingerprint.ts | 5 +- packages/@aws-cdk/core/lib/fs/index.ts | 36 ++++++++ packages/@aws-cdk/core/lib/fs/options.ts | 63 ++++++++++++++ .../@aws-cdk/{assets => core}/lib/fs/utils.ts | 12 +-- packages/@aws-cdk/core/lib/index.ts | 3 + packages/@aws-cdk/core/package.json | 13 ++- packages/@aws-cdk/core/test/fs/.gitignore | 3 + .../@aws-cdk/core/test/fs/fixtures.tar.gz | Bin 0 -> 1328 bytes .../{assets => core}/test/fs/test.fs-copy.ts | 19 ++--- .../test/fs/test.fs-fingerprint.ts | 46 +++++------ .../{assets => core}/test/fs/test.utils.ts | 26 +++--- packages/@aws-cdk/core/test/test.staging.ts | 77 ++++++++++++++++++ packages/decdk/package.json | 1 - packages/monocdk-experiment/package.json | 1 - 33 files changed, 361 insertions(+), 193 deletions(-) delete mode 100644 packages/@aws-cdk/assets/lib/api.ts delete mode 100644 packages/@aws-cdk/assets/lib/fs/follow-mode.ts delete mode 100644 packages/@aws-cdk/assets/lib/fs/index.ts delete mode 100644 packages/@aws-cdk/assets/lib/fs/options.ts rename packages/@aws-cdk/{assets/lib/staging.ts => core/lib/asset-staging.ts} (81%) rename packages/@aws-cdk/{assets => core}/lib/fs/copy.ts (90%) rename packages/@aws-cdk/{assets => core}/lib/fs/fingerprint.ts (95%) create mode 100644 packages/@aws-cdk/core/lib/fs/index.ts create mode 100644 packages/@aws-cdk/core/lib/fs/options.ts rename packages/@aws-cdk/{assets => core}/lib/fs/utils.ts (83%) create mode 100644 packages/@aws-cdk/core/test/fs/.gitignore create mode 100644 packages/@aws-cdk/core/test/fs/fixtures.tar.gz rename packages/@aws-cdk/{assets => core}/test/fs/test.fs-copy.ts (84%) rename packages/@aws-cdk/{assets => core}/test/fs/test.fs-fingerprint.ts (76%) rename packages/@aws-cdk/{assets => core}/test/fs/test.utils.ts (84%) create mode 100644 packages/@aws-cdk/core/test/test.staging.ts diff --git a/package.json b/package.json index 3a486f40e72f4..3e686a785d6da 100644 --- a/package.json +++ b/package.json @@ -45,8 +45,8 @@ "**/jszip/**", "@aws-cdk/cdk-assets-schema/semver", "@aws-cdk/cdk-assets-schema/semver/**", - "@aws-cdk/assets/minimatch", - "@aws-cdk/assets/minimatch/**", + "@aws-cdk/core/minimatch", + "@aws-cdk/core/minimatch/**", "@aws-cdk/aws-codepipeline-actions/case", "@aws-cdk/aws-codepipeline-actions/case/**", "@aws-cdk/aws-ecr-assets/minimatch", diff --git a/packages/@aws-cdk/assets/README.md b/packages/@aws-cdk/assets/README.md index c7d1ae9654b5c..6ebca5ae0d9e6 100644 --- a/packages/@aws-cdk/assets/README.md +++ b/packages/@aws-cdk/assets/README.md @@ -2,15 +2,11 @@ --- -![cdk-constructs: Experimental](https://img.shields.io/badge/cdk--constructs-experimental-important.svg?style=for-the-badge) +![Deprecated](https://img.shields.io/badge/deprecated-critical.svg?style=for-the-badge) -> The APIs of higher level constructs in this module are experimental and under active development. They are subject to non-backward compatible changes or removal in any future version. These are not subject to the [Semantic Versioning](https://semver.org/) model and breaking changes will be announced in the release notes. This means that while you may use them, you may need to update your source code when upgrading to a newer version of this package. +> This API may emit warnings. Backward compatibility is not guaranteed. --- -This module includes core classes for to CDK assets, used for copying asset -files to a staging area. Most CDK users should not need to use the classes in -this package directly. - - +All types moved to @aws-cdk/core. \ No newline at end of file diff --git a/packages/@aws-cdk/assets/lib/api.ts b/packages/@aws-cdk/assets/lib/api.ts deleted file mode 100644 index 75966e57d5af8..0000000000000 --- a/packages/@aws-cdk/assets/lib/api.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Common interface for all assets. - */ -export interface IAsset { - /** - * A hash of the source of this asset, which is available at construction time. As this is a plain - * string, it can be used in construct IDs in order to enforce creation of a new resource when - * the content hash has changed. - */ - readonly sourceHash: string; -} diff --git a/packages/@aws-cdk/assets/lib/fs/follow-mode.ts b/packages/@aws-cdk/assets/lib/fs/follow-mode.ts deleted file mode 100644 index 81f81a36eac24..0000000000000 --- a/packages/@aws-cdk/assets/lib/fs/follow-mode.ts +++ /dev/null @@ -1,29 +0,0 @@ -export enum FollowMode { - /** - * Never follow symlinks. - */ - NEVER = 'never', - - /** - * Materialize all symlinks, whether they are internal or external to the source directory. - */ - ALWAYS = 'always', - - /** - * Only follows symlinks that are external to the source directory. - */ - EXTERNAL = 'external', - - // ----------------- TODO:::::::::::::::::::::::::::::::::::::::::::: - /** - * Forbids source from having any symlinks pointing outside of the source - * tree. - * - * This is the safest mode of operation as it ensures that copy operations - * won't materialize files from the user's file system. Internal symlinks are - * not followed. - * - * If the copy operation runs into an external symlink, it will fail. - */ - BLOCK_EXTERNAL = 'internal-only', -} diff --git a/packages/@aws-cdk/assets/lib/fs/index.ts b/packages/@aws-cdk/assets/lib/fs/index.ts deleted file mode 100644 index a1a4c68a83cef..0000000000000 --- a/packages/@aws-cdk/assets/lib/fs/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './copy'; -export * from './fingerprint'; -export * from './follow-mode'; -export * from './options'; diff --git a/packages/@aws-cdk/assets/lib/fs/options.ts b/packages/@aws-cdk/assets/lib/fs/options.ts deleted file mode 100644 index 727da36568502..0000000000000 --- a/packages/@aws-cdk/assets/lib/fs/options.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { FollowMode } from './follow-mode'; - -/** - * Obtains applied when copying directories into the staging location. - */ -export interface CopyOptions { - /** - * A strategy for how to handle symlinks. - * - * @default Never - */ - readonly follow?: FollowMode; - - /** - * Glob patterns to exclude from the copy. - * - * @default nothing is excluded - */ - readonly exclude?: string[]; -} - -/** - * Options related to calculating source hash. - */ -export interface FingerprintOptions extends CopyOptions { - /** - * Extra information to encode into the fingerprint (e.g. build instructions - * and other inputs) - * - * @default - hash is only based on source content - */ - readonly extraHash?: string; -} diff --git a/packages/@aws-cdk/assets/lib/index.ts b/packages/@aws-cdk/assets/lib/index.ts index e2a67003867bd..4b0d393ea8286 100644 --- a/packages/@aws-cdk/assets/lib/index.ts +++ b/packages/@aws-cdk/assets/lib/index.ts @@ -1,4 +1,67 @@ -export * from './api'; -export * from './fs/follow-mode'; -export * from './fs/options'; -export * from './staging'; +import * as core from '@aws-cdk/core'; + +/** + * Deprecated. + * @deprecated moved to `core.IAsset` + */ +export interface IAsset extends core.IAsset { } + +/** + * Deprecated. + * @deprecated moved to `core.StagingProps` + */ +export interface StagingProps extends core.AssetStagingProps { + +} + +/** + * Deprecated. + * @deprecated moved to `core.Staging` + */ +export class Staging extends core.AssetStaging { } + +/** + * Deprecated. + * @deprecated moved to `core.CopyOptions` + */ +export interface CopyOptions extends core.CopyOptions { } + +/** + * Deprecated. + * @deprecated moved to `core.CopyOptions` + */ +export interface FingerprintOptions extends core.FingerprintOptions { } + +/** + * Deprecated. + * @deprecated moved to `core.FollowMode` + */ +export enum FollowMode { + /** + * Never follow symlinks. + */ + NEVER = 'never', + + /** + * Materialize all symlinks, whether they are internal or external to the source directory. + */ + ALWAYS = 'always', + + /** + * Only follows symlinks that are external to the source directory. + */ + EXTERNAL = 'external', + + // ----------------- TODO:::::::::::::::::::::::::::::::::::::::::::: + /** + * Forbids source from having any symlinks pointing outside of the source + * tree. + * + * This is the safest mode of operation as it ensures that copy operations + * won't materialize files from the user's file system. Internal symlinks are + * not followed. + * + * If the copy operation runs into an external symlink, it will fail. + */ + BLOCK_EXTERNAL = 'internal-only', +} diff --git a/packages/@aws-cdk/assets/package.json b/packages/@aws-cdk/assets/package.json index 28386204806c3..8fe6ec084bab6 100644 --- a/packages/@aws-cdk/assets/package.json +++ b/packages/@aws-cdk/assets/package.json @@ -1,7 +1,7 @@ { "name": "@aws-cdk/assets", "version": "0.0.0", - "description": "Integration of CDK apps with local assets", + "description": "This module is deprecated. All types are now available under the core module", "main": "lib/index.js", "types": "lib/index.d.ts", "jsii": { @@ -64,7 +64,6 @@ "license": "Apache-2.0", "devDependencies": { "@aws-cdk/assert": "0.0.0", - "@types/minimatch": "^3.0.3", "@types/nodeunit": "^0.0.30", "@types/sinon": "^9.0.0", "aws-cdk": "0.0.0", @@ -78,7 +77,6 @@ "dependencies": { "@aws-cdk/core": "0.0.0", "@aws-cdk/cx-api": "0.0.0", - "minimatch": "^3.0.4", "constructs": "^3.0.2" }, "homepage": "https://github.com/aws/aws-cdk", @@ -90,19 +88,14 @@ "engines": { "node": ">= 10.12.0" }, - "bundledDependencies": [ - "minimatch" - ], - "stability": "experimental", - "maturity": "experimental", + "stability": "deprecated", + "maturity": "deprecated", + "awscdkio": { + "announce": false + }, "awslint": { "exclude": [ - "docs-public-apis:@aws-cdk/assets.StagingProps", - "docs-public-apis:@aws-cdk/assets.StagingProps.sourcePath", - "docs-public-apis:@aws-cdk/assets.FollowMode" + "construct-ctor-props-type:@aws-cdk/assets.Staging" ] - }, - "awscdkio": { - "announce": false } } diff --git a/packages/@aws-cdk/aws-codebuild/package.json b/packages/@aws-cdk/aws-codebuild/package.json index 56ce0fc3a65b0..ab3b9f719c5a8 100644 --- a/packages/@aws-cdk/aws-codebuild/package.json +++ b/packages/@aws-cdk/aws-codebuild/package.json @@ -78,7 +78,6 @@ "pkglint": "0.0.0" }, "dependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -95,7 +94,6 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-codecommit": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts index 6e84d63dad8d6..c9f04436cd0fa 100644 --- a/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts +++ b/packages/@aws-cdk/aws-ecr-assets/lib/image-asset.ts @@ -1,6 +1,5 @@ -import * as assets from '@aws-cdk/assets'; import * as ecr from '@aws-cdk/aws-ecr'; -import { Construct, Stack, Token } from '@aws-cdk/core'; +import { AssetStaging, Construct, FingerprintOptions, IAsset, Stack, Token } from '@aws-cdk/core'; import * as fs from 'fs'; import * as minimatch from 'minimatch'; import * as path from 'path'; @@ -8,7 +7,7 @@ import * as path from 'path'; /** * Options for DockerImageAsset */ -export interface DockerImageAssetOptions extends assets.FingerprintOptions { +export interface DockerImageAssetOptions extends FingerprintOptions { /** * ECR repository name * @@ -64,7 +63,7 @@ export interface DockerImageAssetProps extends DockerImageAssetOptions { * * The image will be created in build time and uploaded to an ECR repository. */ -export class DockerImageAsset extends Construct implements assets.IAsset { +export class DockerImageAsset extends Construct implements IAsset { /** * The full URI of the image (including a tag). Use this reference to pull * the asset. @@ -128,7 +127,7 @@ export class DockerImageAsset extends Construct implements assets.IAsset { // deletion of the ECR repository the app used). extraHash.version = '1.21.0'; - const staging = new assets.Staging(this, 'Staging', { + const staging = new AssetStaging(this, 'Staging', { ...props, exclude, sourcePath: dir, diff --git a/packages/@aws-cdk/aws-ecr-assets/package.json b/packages/@aws-cdk/aws-ecr-assets/package.json index 9f61e0ee0e8db..9a0510789ff50 100644 --- a/packages/@aws-cdk/aws-ecr-assets/package.json +++ b/packages/@aws-cdk/aws-ecr-assets/package.json @@ -71,7 +71,6 @@ "@aws-cdk/cloud-assembly-schema": "0.0.0" }, "dependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudformation": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", @@ -84,7 +83,6 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudformation": "0.0.0", "@aws-cdk/aws-ecr": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json index 59c960b04d919..f16785c90a67a 100644 --- a/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json +++ b/packages/@aws-cdk/aws-elasticloadbalancingv2-targets/package.json @@ -84,7 +84,6 @@ "pkglint": "0.0.0" }, "dependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", @@ -94,7 +93,6 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-elasticloadbalancingv2": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts index 68484fcc4d985..8de4f6a07e456 100644 --- a/packages/@aws-cdk/aws-s3-assets/lib/asset.ts +++ b/packages/@aws-cdk/aws-s3-assets/lib/asset.ts @@ -1,4 +1,3 @@ -import * as assets from '@aws-cdk/assets'; import * as iam from '@aws-cdk/aws-iam'; import * as s3 from '@aws-cdk/aws-s3'; import * as cdk from '@aws-cdk/core'; @@ -8,7 +7,7 @@ import * as path from 'path'; const ARCHIVE_EXTENSIONS = [ '.zip', '.jar' ]; -export interface AssetOptions extends assets.CopyOptions { +export interface AssetOptions extends cdk.CopyOptions { /** * A list of principals that should be able to read this asset from S3. @@ -50,7 +49,7 @@ export interface AssetProps extends AssetOptions { * An asset represents a local file or directory, which is automatically uploaded to S3 * and then can be referenced within a CDK application. */ -export class Asset extends cdk.Construct implements assets.IAsset { +export class Asset extends cdk.Construct implements cdk.IAsset { /** * Attribute that represents the name of the bucket this asset exists in. */ @@ -92,7 +91,7 @@ export class Asset extends cdk.Construct implements assets.IAsset { super(scope, id); // stage the asset source (conditionally). - const staging = new assets.Staging(this, 'Stage', { + const staging = new cdk.AssetStaging(this, 'Stage', { ...props, sourcePath: path.resolve(props.path), }); diff --git a/packages/@aws-cdk/aws-s3-assets/package.json b/packages/@aws-cdk/aws-s3-assets/package.json index 2419ca3247ba4..c4490614a2aeb 100644 --- a/packages/@aws-cdk/aws-s3-assets/package.json +++ b/packages/@aws-cdk/aws-s3-assets/package.json @@ -72,7 +72,6 @@ "ts-mock-imports": "^1.3.0" }, "dependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", @@ -81,7 +80,6 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-s3": "0.0.0", "@aws-cdk/core": "0.0.0", diff --git a/packages/@aws-cdk/aws-s3-deployment/package.json b/packages/@aws-cdk/aws-s3-deployment/package.json index 1f086360e16f9..10d6cc9b319a8 100644 --- a/packages/@aws-cdk/aws-s3-deployment/package.json +++ b/packages/@aws-cdk/aws-s3-deployment/package.json @@ -95,7 +95,6 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudformation": "0.0.0", "@aws-cdk/aws-cloudfront": "0.0.0", "@aws-cdk/aws-iam": "0.0.0", diff --git a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json index 5b81b8d3b3cdf..4f11e3319f17f 100644 --- a/packages/@aws-cdk/aws-stepfunctions-tasks/package.json +++ b/packages/@aws-cdk/aws-stepfunctions-tasks/package.json @@ -87,7 +87,6 @@ "pkglint": "0.0.0" }, "dependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", @@ -107,7 +106,6 @@ }, "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-batch": "0.0.0", "@aws-cdk/aws-cloudwatch": "0.0.0", "@aws-cdk/aws-ec2": "0.0.0", diff --git a/packages/@aws-cdk/assets/lib/staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts similarity index 81% rename from packages/@aws-cdk/assets/lib/staging.ts rename to packages/@aws-cdk/core/lib/asset-staging.ts index a95f7e26107a8..0fb9dc3da8265 100644 --- a/packages/@aws-cdk/assets/lib/staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -1,10 +1,16 @@ -import { Construct, ISynthesisSession } from '@aws-cdk/core'; import * as cxapi from '@aws-cdk/cx-api'; import * as fs from 'fs'; import * as path from 'path'; -import { copyDirectory, fingerprint, FingerprintOptions } from './fs'; +import { Construct, ISynthesisSession } from './construct-compat'; +import { FileSystem, FingerprintOptions } from './fs'; -export interface StagingProps extends FingerprintOptions { +/** + * Initialization properties for `AssetStaging`. + */ +export interface AssetStagingProps extends FingerprintOptions { + /** + * The source file or directory to copy from. + */ readonly sourcePath: string; } @@ -26,7 +32,7 @@ export interface StagingProps extends FingerprintOptions { * The file/directory are staged based on their content hash (fingerprint). This * means that only if content was changed, copy will happen. */ -export class Staging extends Construct { +export class AssetStaging extends Construct { /** * The path to the asset (stringinfied token). @@ -50,12 +56,12 @@ export class Staging extends Construct { private readonly relativePath?: string; - constructor(scope: Construct, id: string, props: StagingProps) { + constructor(scope: Construct, id: string, props: AssetStagingProps) { super(scope, id); this.sourcePath = props.sourcePath; this.fingerprintOptions = props; - this.sourceHash = fingerprint(this.sourcePath, props); + this.sourceHash = FileSystem.fingerprint(this.sourcePath, props); const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT); if (stagingDisabled) { @@ -84,7 +90,7 @@ export class Staging extends Construct { fs.copyFileSync(this.sourcePath, targetPath); } else if (stat.isDirectory()) { fs.mkdirSync(targetPath); - copyDirectory(this.sourcePath, targetPath, this.fingerprintOptions); + FileSystem.copyDirectory(this.sourcePath, targetPath, this.fingerprintOptions); } else { throw new Error(`Unknown file type: ${this.sourcePath}`); } diff --git a/packages/@aws-cdk/core/lib/assets.ts b/packages/@aws-cdk/core/lib/assets.ts index a397a8aa6624a..828033004f9a4 100644 --- a/packages/@aws-cdk/core/lib/assets.ts +++ b/packages/@aws-cdk/core/lib/assets.ts @@ -1,3 +1,15 @@ +/** + * Common interface for all assets. + */ +export interface IAsset { + /** + * A hash of the source of this asset, which is available at construction time. As this is a plain + * string, it can be used in construct IDs in order to enforce creation of a new resource when + * the content hash has changed. + */ + readonly sourceHash: string; +} + /** * Represents the source for a file asset. */ diff --git a/packages/@aws-cdk/assets/lib/fs/copy.ts b/packages/@aws-cdk/core/lib/fs/copy.ts similarity index 90% rename from packages/@aws-cdk/assets/lib/fs/copy.ts rename to packages/@aws-cdk/core/lib/fs/copy.ts index 01b6c19cc66a6..d4c2841feeb6b 100644 --- a/packages/@aws-cdk/assets/lib/fs/copy.ts +++ b/packages/@aws-cdk/core/lib/fs/copy.ts @@ -1,11 +1,10 @@ import * as fs from 'fs'; import * as path from 'path'; -import { FollowMode } from './follow-mode'; -import { CopyOptions } from './options'; +import { CopyOptions, SymlinkFollowMode } from './options'; import { shouldExclude, shouldFollow } from './utils'; export function copyDirectory(srcDir: string, destDir: string, options: CopyOptions = { }, rootDir?: string) { - const follow = options.follow !== undefined ? options.follow : FollowMode.EXTERNAL; + const follow = options.follow !== undefined ? options.follow : SymlinkFollowMode.EXTERNAL; const exclude = options.exclude || []; rootDir = rootDir || srcDir; @@ -24,7 +23,7 @@ export function copyDirectory(srcDir: string, destDir: string, options: CopyOpti const destFilePath = path.join(destDir, file); - let stat: fs.Stats | undefined = follow === FollowMode.ALWAYS + let stat: fs.Stats | undefined = follow === SymlinkFollowMode.ALWAYS ? fs.statSync(sourceFilePath) : fs.lstatSync(sourceFilePath); diff --git a/packages/@aws-cdk/assets/lib/fs/fingerprint.ts b/packages/@aws-cdk/core/lib/fs/fingerprint.ts similarity index 95% rename from packages/@aws-cdk/assets/lib/fs/fingerprint.ts rename to packages/@aws-cdk/core/lib/fs/fingerprint.ts index 1d75850a17e56..dcac8f5ba5fce 100644 --- a/packages/@aws-cdk/assets/lib/fs/fingerprint.ts +++ b/packages/@aws-cdk/core/lib/fs/fingerprint.ts @@ -1,8 +1,7 @@ import * as crypto from 'crypto'; import * as fs from 'fs'; import * as path from 'path'; -import { FollowMode } from './follow-mode'; -import { FingerprintOptions } from './options'; +import { FingerprintOptions, SymlinkFollowMode } from './options'; import { shouldExclude, shouldFollow } from './utils'; const BUFFER_SIZE = 8 * 1024; @@ -24,7 +23,7 @@ const CTRL_ETX = '\x03'; export function fingerprint(fileOrDirectory: string, options: FingerprintOptions = { }) { const hash = crypto.createHash('sha256'); _hashField(hash, 'options.extra', options.extraHash || ''); - const follow = options.follow || FollowMode.EXTERNAL; + const follow = options.follow || SymlinkFollowMode.EXTERNAL; _hashField(hash, 'options.follow', follow); const rootDirectory = fs.statSync(fileOrDirectory).isDirectory() diff --git a/packages/@aws-cdk/core/lib/fs/index.ts b/packages/@aws-cdk/core/lib/fs/index.ts new file mode 100644 index 0000000000000..ac7f3c9d0f8da --- /dev/null +++ b/packages/@aws-cdk/core/lib/fs/index.ts @@ -0,0 +1,36 @@ +import { copyDirectory } from './copy'; +import { fingerprint } from './fingerprint'; +import { CopyOptions, FingerprintOptions } from './options'; + +export * from './options'; + +/** + * File system utilities. + */ +export class FileSystem { + /** + * Copies an entire directory structure. + * @param srcDir Source directory + * @param destDir Destination directory + * @param options options + * @param rootDir Root directory to calculate exclusions from + */ + public static copyDirectory(srcDir: string, destDir: string, options: CopyOptions = { }, rootDir?: string) { + return copyDirectory(srcDir, destDir, options, rootDir); + } + + /** + * Produces fingerprint based on the contents of a single file or an entire directory tree. + * + * The fingerprint will also include: + * 1. An extra string if defined in `options.extra`. + * 2. The set of exclude patterns, if defined in `options.exclude` + * 3. The symlink follow mode value. + * + * @param fileOrDirectory The directory or file to fingerprint + * @param options Fingerprinting options + */ + public static fingerprint(fileOrDirectory: string, options: FingerprintOptions = { }) { + return fingerprint(fileOrDirectory, options); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/core/lib/fs/options.ts b/packages/@aws-cdk/core/lib/fs/options.ts new file mode 100644 index 0000000000000..eef3fcc499b08 --- /dev/null +++ b/packages/@aws-cdk/core/lib/fs/options.ts @@ -0,0 +1,63 @@ +/** + * Determines how symlinks are followed. + */ +export enum SymlinkFollowMode { + /** + * Never follow symlinks. + */ + NEVER = 'never', + + /** + * Materialize all symlinks, whether they are internal or external to the source directory. + */ + ALWAYS = 'always', + + /** + * Only follows symlinks that are external to the source directory. + */ + EXTERNAL = 'external', + + /** + * Forbids source from having any symlinks pointing outside of the source + * tree. + * + * This is the safest mode of operation as it ensures that copy operations + * won't materialize files from the user's file system. Internal symlinks are + * not followed. + * + * If the copy operation runs into an external symlink, it will fail. + */ + BLOCK_EXTERNAL = 'internal-only', +} + +/** + * Obtains applied when copying directories into the staging location. + */ +export interface CopyOptions { + /** + * A strategy for how to handle symlinks. + * + * @default SymlinkFollowMode.NEVER + */ + readonly follow?: SymlinkFollowMode; + + /** + * Glob patterns to exclude from the copy. + * + * @default - nothing is excluded + */ + readonly exclude?: string[]; +} + +/** + * Options related to calculating source hash. + */ +export interface FingerprintOptions extends CopyOptions { + /** + * Extra information to encode into the fingerprint (e.g. build instructions + * and other inputs) + * + * @default - hash is only based on source content + */ + readonly extraHash?: string; +} diff --git a/packages/@aws-cdk/assets/lib/fs/utils.ts b/packages/@aws-cdk/core/lib/fs/utils.ts similarity index 83% rename from packages/@aws-cdk/assets/lib/fs/utils.ts rename to packages/@aws-cdk/core/lib/fs/utils.ts index 4e58be4e09866..5624c3448f5ef 100644 --- a/packages/@aws-cdk/assets/lib/fs/utils.ts +++ b/packages/@aws-cdk/core/lib/fs/utils.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as minimatch from 'minimatch'; import * as path from 'path'; -import { FollowMode } from './follow-mode'; +import { SymlinkFollowMode } from './options'; /** * Determines whether a given file should be excluded or not based on given @@ -40,15 +40,15 @@ export function shouldExclude(exclude: string[], filePath: string): boolean { * * @returns true if the link should be followed. */ -export function shouldFollow(mode: FollowMode, sourceRoot: string, realPath: string): boolean { +export function shouldFollow(mode: SymlinkFollowMode, sourceRoot: string, realPath: string): boolean { switch (mode) { - case FollowMode.ALWAYS: + case SymlinkFollowMode.ALWAYS: return fs.existsSync(realPath); - case FollowMode.EXTERNAL: + case SymlinkFollowMode.EXTERNAL: return !_isInternal() && fs.existsSync(realPath); - case FollowMode.BLOCK_EXTERNAL: + case SymlinkFollowMode.BLOCK_EXTERNAL: return _isInternal() && fs.existsSync(realPath); - case FollowMode.NEVER: + case SymlinkFollowMode.NEVER: return false; default: throw new Error(`Unsupported FollowMode: ${mode}`); diff --git a/packages/@aws-cdk/core/lib/index.ts b/packages/@aws-cdk/core/lib/index.ts index 828d9eca25057..7f5a35678dd36 100644 --- a/packages/@aws-cdk/core/lib/index.ts +++ b/packages/@aws-cdk/core/lib/index.ts @@ -43,6 +43,9 @@ export * from './assets'; export * from './tree'; +export * from './asset-staging'; +export * from './fs'; + // WARNING: Should not be exported, but currently is because of a bug. See the // class description for more information. export * from './private/intrinsic'; diff --git a/packages/@aws-cdk/core/package.json b/packages/@aws-cdk/core/package.json index 57232866cdd3b..d25de822d7ae4 100644 --- a/packages/@aws-cdk/core/package.json +++ b/packages/@aws-cdk/core/package.json @@ -118,6 +118,11 @@ "build+test": "npm run build && npm test", "compat": "cdk-compat" }, + "cdk-build": { + "pre": [ + "rm -rf test/fs/fixtures && cd test/fs && tar -xzvf fixtures.tar.gz" + ] + }, "nyc": { "statements": 55, "lines": 55, @@ -139,18 +144,24 @@ "@types/lodash": "^4.14.150", "@types/node": "^10.17.21", "@types/nodeunit": "^0.0.30", + "@types/minimatch": "^3.0.3", "cdk-build-tools": "0.0.0", "cfn2ts": "0.0.0", "fast-check": "^1.24.2", "lodash": "^4.17.15", "nodeunit": "^0.11.3", - "pkglint": "0.0.0" + "pkglint": "0.0.0", + "ts-mock-imports": "^1.3.0" }, "dependencies": { + "minimatch": "^3.0.4", "@aws-cdk/cx-api": "0.0.0", "@aws-cdk/cloud-assembly-schema": "0.0.0", "constructs": "^3.0.2" }, + "bundledDependencies": [ + "minimatch" + ], "homepage": "https://github.com/aws/aws-cdk", "peerDependencies": { "@aws-cdk/cx-api": "0.0.0", diff --git a/packages/@aws-cdk/core/test/fs/.gitignore b/packages/@aws-cdk/core/test/fs/.gitignore new file mode 100644 index 0000000000000..b13de5858771b --- /dev/null +++ b/packages/@aws-cdk/core/test/fs/.gitignore @@ -0,0 +1,3 @@ +# codepipeline looses symlinks so we bundled fixtures into a tarball +# and unpack in pre-build script (yak) +fixtures/** diff --git a/packages/@aws-cdk/core/test/fs/fixtures.tar.gz b/packages/@aws-cdk/core/test/fs/fixtures.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..50f5ba0f4a259052109afd4e7aae10087655fec8 GIT binary patch literal 1328 zcmYk4eK=GJ6vih*zS>yDtacemNL$ltHnO`$3X2l0kEt+GR@!2VtnzSuE*YCAN(qbX zHk)ZF**+APXtgO5R^#JgFd0(17-PQfy=NzX?fLUO@AIB>e(#}k^(YA={7?#Yro1zD z$n%qIodh0lwB9Wu>is%KgI=MB!D^4RyIiedd$S_r+f%{U40VQI>!=)4&btQY{G08# zAv>E)xRMPl=rRRY@F^b_@wqHk))Wly(f8E=YW_UKI54YdA| zYfmeTxnVQ$ag{_gU_W@j&ZoTN^fpdO%_DB_k*2F1dq6(lQGp~Ax615d7CK$R`(k?+ z`MYuipr5cNUr~m)Uz^)nx0zz`8X>&uw>i!`S~UN9KW6%^Y#0r8+gZ#`;3I`#flbscjxaEao5&| z5ZsN$w}n8Hs_!8n4I`BuP6*-ad@R2OQht04caq8jE=TpNSplmFgrPl;1Y_{Sl9UmM zln11x0LM3jL}?B)9MANmq9^=>RHTR-UwERvv-6f5Y0b?7b;|{y36JCG2=Hcs61af* z%htal1^O4RgTS`v6uZ#%X7TlKtVrD-)MT){7Cb=^$2=X+dqMcS_bX6+$}GZgo=18U z5=mAz$TRXti<;&mb-<{$g^)fa$F|+xdh^Ea_7)k3>3q?Ny+#Z~TRA_rl28cnbOn~} zFGdfxL%4r8y0h;xy8y0O?Jk`Y1)W`Ix-^Z$YCdSQ(eA^Q)!J`a;d%{ZoA(RYjwFcNDs7Vn&=Qq&5;m*Xhi{Rxt%5E=Tt z6=hHR4vNv*E--t`$^{|s=$lhGz0sv*t4xaeeYPypGT++n^<&3(LL~cd9HnbbAOWut zd1fOScB8pHl?W+W*|LZih-1Ac^U5MeRY)=X^jx<=j(Be&r917xi;QDAi=nGN?N6fO zyBqt5!Ghr%XMUd)D3QXer52(nCkwiMGKA!f#1a{c|C|)^|lH%#d^m z9+$18GqUDEr8JraW2O>$DMd@H-HS;Ke~um2d`&!wIpBk87R^A3hU>{ldKtVlnpQD_ zu<6xS$q*g77KDa^S?C(O%*MdfeUzy9Aj{DhPC-s(H&`S#dJmDD;1r-n8(_$+`{Eb- zy(H0=Cx)7yYG;_}whfS?US?&f&2W_V0aZo{F1%<>Ca(>|m&owJZz;6DaJn?#O4E-U YcO-O8v?>3u=H(>Sn%Y=MsiaW;12WR+@Bjb+ literal 0 HcmV?d00001 diff --git a/packages/@aws-cdk/assets/test/fs/test.fs-copy.ts b/packages/@aws-cdk/core/test/fs/test.fs-copy.ts similarity index 84% rename from packages/@aws-cdk/assets/test/fs/test.fs-copy.ts rename to packages/@aws-cdk/core/test/fs/test.fs-copy.ts index 68cb3dc234d06..47b55842a90c4 100644 --- a/packages/@aws-cdk/assets/test/fs/test.fs-copy.ts +++ b/packages/@aws-cdk/core/test/fs/test.fs-copy.ts @@ -2,8 +2,7 @@ import * as fs from 'fs'; import { Test } from 'nodeunit'; import * as os from 'os'; import * as path from 'path'; -import { copyDirectory } from '../../lib/fs/copy'; -import { FollowMode } from '../../lib/fs/follow-mode'; +import { FileSystem, SymlinkFollowMode } from '../../lib/fs'; export = { 'Default: copies all files and subdirectories, with default follow mode is "External"'(test: Test) { @@ -11,7 +10,7 @@ export = { const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); // WHEN - copyDirectory(path.join(__dirname, 'fixtures', 'test1'), outdir); + FileSystem.copyDirectory(path.join(__dirname, 'fixtures', 'test1'), outdir); // THEN test.deepEqual(tree(outdir), [ @@ -34,8 +33,8 @@ export = { const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); // WHEN - copyDirectory(path.join(__dirname, 'fixtures', 'symlinks'), outdir, { - follow: FollowMode.ALWAYS, + FileSystem.copyDirectory(path.join(__dirname, 'fixtures', 'symlinks'), outdir, { + follow: SymlinkFollowMode.ALWAYS, }); // THEN @@ -59,8 +58,8 @@ export = { const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); // WHEN - copyDirectory(path.join(__dirname, 'fixtures', 'symlinks'), outdir, { - follow: FollowMode.NEVER, + FileSystem.copyDirectory(path.join(__dirname, 'fixtures', 'symlinks'), outdir, { + follow: SymlinkFollowMode.NEVER, }); // THEN @@ -82,8 +81,8 @@ export = { const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); // WHEN - copyDirectory(path.join(__dirname, 'fixtures', 'symlinks'), outdir, { - follow: FollowMode.EXTERNAL, + FileSystem.copyDirectory(path.join(__dirname, 'fixtures', 'symlinks'), outdir, { + follow: SymlinkFollowMode.EXTERNAL, }); // THEN @@ -107,7 +106,7 @@ export = { const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); // WHEN - copyDirectory(path.join(__dirname, 'fixtures', 'test1'), outdir, { + FileSystem.copyDirectory(path.join(__dirname, 'fixtures', 'test1'), outdir, { exclude: [ '*', '!subdir2', diff --git a/packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts b/packages/@aws-cdk/core/test/fs/test.fs-fingerprint.ts similarity index 76% rename from packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts rename to packages/@aws-cdk/core/test/fs/test.fs-fingerprint.ts index ea6b10ec250f6..7be40d4b31ad4 100644 --- a/packages/@aws-cdk/assets/test/fs/test.fs-fingerprint.ts +++ b/packages/@aws-cdk/core/test/fs/test.fs-fingerprint.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import { Test } from 'nodeunit'; import * as os from 'os'; import * as path from 'path'; -import * as libfs from '../../lib/fs'; +import { FileSystem, SymlinkFollowMode } from '../../lib/fs'; export = { files: { @@ -18,9 +18,9 @@ export = { fs.writeFileSync(input3, content + '.'); // add one character, hash should be different // WHEN - const hash1 = libfs.fingerprint(input1); - const hash2 = libfs.fingerprint(input2); - const hash3 = libfs.fingerprint(input3); + const hash1 = FileSystem.fingerprint(input1); + const hash2 = FileSystem.fingerprint(input2); + const hash3 = FileSystem.fingerprint(input3); // THEN test.deepEqual(hash1, hash2); @@ -37,8 +37,8 @@ export = { fs.writeFileSync(input2, ''); // WHEN - const hash1 = libfs.fingerprint(input1); - const hash2 = libfs.fingerprint(input2); + const hash1 = FileSystem.fingerprint(input1); + const hash2 = FileSystem.fingerprint(input2); // THEN test.deepEqual(hash1, hash2); @@ -51,11 +51,11 @@ export = { // GIVEN const srcdir = path.join(__dirname, 'fixtures', 'symlinks'); const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); - libfs.copyDirectory(srcdir, outdir); + FileSystem.copyDirectory(srcdir, outdir); // WHEN - const hashSrc = libfs.fingerprint(srcdir); - const hashCopy = libfs.fingerprint(outdir); + const hashSrc = FileSystem.fingerprint(srcdir); + const hashCopy = FileSystem.fingerprint(outdir); // THEN test.deepEqual(hashSrc, hashCopy); @@ -66,13 +66,13 @@ export = { // GIVEN const srcdir = path.join(__dirname, 'fixtures', 'symlinks'); const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); - libfs.copyDirectory(srcdir, outdir); + FileSystem.copyDirectory(srcdir, outdir); // WHEN - const hashSrc = libfs.fingerprint(srcdir, { exclude: ['*.ignoreme'] }); + const hashSrc = FileSystem.fingerprint(srcdir, { exclude: ['*.ignoreme'] }); fs.writeFileSync(path.join(outdir, `${hashSrc}.ignoreme`), 'Ignore me!'); - const hashCopy = libfs.fingerprint(outdir, { exclude: ['*.ignoreme'] }); + const hashCopy = FileSystem.fingerprint(outdir, { exclude: ['*.ignoreme'] }); // THEN test.deepEqual(hashSrc, hashCopy); @@ -83,14 +83,14 @@ export = { // GIVEN const srcdir = path.join(__dirname, 'fixtures', 'symlinks'); const cpydir = fs.mkdtempSync(path.join(os.tmpdir(), 'fingerprint-tests')); - libfs.copyDirectory(srcdir, cpydir); + FileSystem.copyDirectory(srcdir, cpydir); // be careful not to break a symlink fs.renameSync(path.join(cpydir, 'normal-dir', 'file-in-subdir.txt'), path.join(cpydir, 'move-me.txt')); // WHEN - const hashSrc = libfs.fingerprint(srcdir); - const hashCopy = libfs.fingerprint(cpydir); + const hashSrc = FileSystem.fingerprint(srcdir); + const hashCopy = FileSystem.fingerprint(cpydir); // THEN test.notDeepEqual(hashSrc, hashCopy); @@ -111,15 +111,15 @@ export = { // now dir2 contains a symlink to a file in dir1 // WHEN - const original = libfs.fingerprint(dir2); + const original = FileSystem.fingerprint(dir2); // now change the contents of the target fs.writeFileSync(target, 'changning you!'); - const afterChange = libfs.fingerprint(dir2); + const afterChange = FileSystem.fingerprint(dir2); // revert the content to original and expect hash to be reverted fs.writeFileSync(target, content); - const afterRevert = libfs.fingerprint(dir2); + const afterRevert = FileSystem.fingerprint(dir2); // THEN test.notDeepEqual(original, afterChange); @@ -139,15 +139,15 @@ export = { // now dir2 contains a symlink to a file in dir1 // WHEN - const original = libfs.fingerprint(dir2, { follow: libfs.FollowMode.NEVER }); + const original = FileSystem.fingerprint(dir2, { follow: SymlinkFollowMode.NEVER }); // now change the contents of the target fs.writeFileSync(target, 'changning you!'); - const afterChange = libfs.fingerprint(dir2, { follow: libfs.FollowMode.NEVER }); + const afterChange = FileSystem.fingerprint(dir2, { follow: SymlinkFollowMode.NEVER }); // revert the content to original and expect hash to be reverted fs.writeFileSync(target, content); - const afterRevert = libfs.fingerprint(dir2, { follow: libfs.FollowMode.NEVER }); + const afterRevert = FileSystem.fingerprint(dir2, { follow: SymlinkFollowMode.NEVER }); // THEN test.deepEqual(original, afterChange); @@ -163,8 +163,8 @@ export = { const options2 = {path: dir, exclude: ['**', '!otherfile.py'], sourcePath: dir}; // WHEN - const f1 = libfs.fingerprint(dir, options1); - const f2 = libfs.fingerprint(dir, options2); + const f1 = FileSystem.fingerprint(dir, options1); + const f2 = FileSystem.fingerprint(dir, options2); // THEN test.notDeepEqual(f1, f2); diff --git a/packages/@aws-cdk/assets/test/fs/test.utils.ts b/packages/@aws-cdk/core/test/fs/test.utils.ts similarity index 84% rename from packages/@aws-cdk/assets/test/fs/test.utils.ts rename to packages/@aws-cdk/core/test/fs/test.utils.ts index 3fe6ab55ab0ac..c8962c7f4022f 100644 --- a/packages/@aws-cdk/assets/test/fs/test.utils.ts +++ b/packages/@aws-cdk/core/test/fs/test.utils.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import { Test } from 'nodeunit'; import * as path from 'path'; import { ImportMock } from 'ts-mock-imports'; -import { FollowMode } from '../../lib/fs'; +import { SymlinkFollowMode } from '../../lib/fs'; import * as util from '../../lib/fs/utils'; export = { @@ -34,7 +34,7 @@ export = { const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', true); try { - test.ok(util.shouldFollow(FollowMode.ALWAYS, sourceRoot, linkTarget)); + test.ok(util.shouldFollow(SymlinkFollowMode.ALWAYS, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -47,7 +47,7 @@ export = { const linkTarget = path.join('alternate', 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', true); try { - test.ok(util.shouldFollow(FollowMode.ALWAYS, sourceRoot, linkTarget)); + test.ok(util.shouldFollow(SymlinkFollowMode.ALWAYS, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -60,7 +60,7 @@ export = { const linkTarget = path.join(sourceRoot, 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', false); try { - test.ok(!util.shouldFollow(FollowMode.ALWAYS, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.ALWAYS, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -73,7 +73,7 @@ export = { const linkTarget = path.join('alternate', 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', false); try { - test.ok(!util.shouldFollow(FollowMode.ALWAYS, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.ALWAYS, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -88,7 +88,7 @@ export = { const linkTarget = path.join(sourceRoot, 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync'); try { - test.ok(!util.shouldFollow(FollowMode.EXTERNAL, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.EXTERNAL, sourceRoot, linkTarget)); test.ok(mockFsExists.notCalled); test.done(); } finally { @@ -101,7 +101,7 @@ export = { const linkTarget = path.join('alternate', 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', true); try { - test.ok(util.shouldFollow(FollowMode.EXTERNAL, sourceRoot, linkTarget)); + test.ok(util.shouldFollow(SymlinkFollowMode.EXTERNAL, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -114,7 +114,7 @@ export = { const linkTarget = path.join('alternate', 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', false); try { - test.ok(!util.shouldFollow(FollowMode.EXTERNAL, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.EXTERNAL, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -129,7 +129,7 @@ export = { const linkTarget = path.join(sourceRoot, 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', true); try { - test.ok(util.shouldFollow(FollowMode.BLOCK_EXTERNAL, sourceRoot, linkTarget)); + test.ok(util.shouldFollow(SymlinkFollowMode.BLOCK_EXTERNAL, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -142,7 +142,7 @@ export = { const linkTarget = path.join(sourceRoot, 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync', false); try { - test.ok(!util.shouldFollow(FollowMode.BLOCK_EXTERNAL, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.BLOCK_EXTERNAL, sourceRoot, linkTarget)); test.ok(mockFsExists.calledOnceWith(linkTarget)); test.done(); } finally { @@ -155,7 +155,7 @@ export = { const linkTarget = path.join('alternate', 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync'); try { - test.ok(!util.shouldFollow(FollowMode.BLOCK_EXTERNAL, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.BLOCK_EXTERNAL, sourceRoot, linkTarget)); test.ok(mockFsExists.notCalled); test.done(); } finally { @@ -170,7 +170,7 @@ export = { const linkTarget = path.join(sourceRoot, 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync'); try { - test.ok(!util.shouldFollow(FollowMode.NEVER, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.NEVER, sourceRoot, linkTarget)); test.ok(mockFsExists.notCalled); test.done(); } finally { @@ -183,7 +183,7 @@ export = { const linkTarget = path.join('alternate', 'referent'); const mockFsExists = ImportMock.mockFunction(fs, 'existsSync'); try { - test.ok(!util.shouldFollow(FollowMode.NEVER, sourceRoot, linkTarget)); + test.ok(!util.shouldFollow(SymlinkFollowMode.NEVER, sourceRoot, linkTarget)); test.ok(mockFsExists.notCalled); test.done(); } finally { diff --git a/packages/@aws-cdk/core/test/test.staging.ts b/packages/@aws-cdk/core/test/test.staging.ts new file mode 100644 index 0000000000000..5e1f49ef38cf2 --- /dev/null +++ b/packages/@aws-cdk/core/test/test.staging.ts @@ -0,0 +1,77 @@ +import * as cxapi from '@aws-cdk/cx-api'; +import * as fs from 'fs'; +import { Test } from 'nodeunit'; +import * as path from 'path'; +import { App, Stack, AssetStaging } from '../lib'; + +export = { + 'base case'(test: Test) { + // GIVEN + const stack = new Stack(); + const sourcePath = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + const staging = new AssetStaging(stack, 's1', { sourcePath }); + + test.deepEqual(staging.sourceHash, '2f37f937c51e2c191af66acf9b09f548926008ec68c575bd2ee54b6e997c0e00'); + test.deepEqual(staging.sourcePath, sourcePath); + test.deepEqual(stack.resolve(staging.stagedPath), 'asset.2f37f937c51e2c191af66acf9b09f548926008ec68c575bd2ee54b6e997c0e00'); + test.done(); + }, + + 'staging can be disabled through context'(test: Test) { + // GIVEN + const stack = new Stack(); + stack.node.setContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT, true); + const sourcePath = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + const staging = new AssetStaging(stack, 's1', { sourcePath }); + + test.deepEqual(staging.sourceHash, '2f37f937c51e2c191af66acf9b09f548926008ec68c575bd2ee54b6e997c0e00'); + test.deepEqual(staging.sourcePath, sourcePath); + test.deepEqual(stack.resolve(staging.stagedPath), sourcePath); + test.done(); + }, + + 'files are copied to the output directory during synth'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + const file = path.join(__dirname, 'fs', 'fixtures.tar.gz'); + + // WHEN + new AssetStaging(stack, 's1', { sourcePath: directory }); + new AssetStaging(stack, 'file', { sourcePath: file }); + + // THEN + const assembly = app.synth(); + test.deepEqual(fs.readdirSync(assembly.directory), [ + 'asset.2f37f937c51e2c191af66acf9b09f548926008ec68c575bd2ee54b6e997c0e00', + 'asset.af10ac04b3b607b0f8659c8f0cee8c343025ee75baf0b146f10f0e5311d2c46b.gz', + 'cdk.out', + 'manifest.json', + 'stack.template.json', + 'tree.json', + ]); + test.done(); + }, + + 'allow specifying extra data to include in the source hash'(test: Test) { + // GIVEN + const app = new App(); + const stack = new Stack(app, 'stack'); + const directory = path.join(__dirname, 'fs', 'fixtures', 'test1'); + + // WHEN + const withoutExtra = new AssetStaging(stack, 'withoutExtra', { sourcePath: directory }); + const withExtra = new AssetStaging(stack, 'withExtra', { sourcePath: directory, extraHash: 'boom' }); + + // THEN + test.notEqual(withoutExtra.sourceHash, withExtra.sourceHash); + test.deepEqual(withoutExtra.sourceHash, '2f37f937c51e2c191af66acf9b09f548926008ec68c575bd2ee54b6e997c0e00'); + test.deepEqual(withExtra.sourceHash, 'c95c915a5722bb9019e2c725d11868e5a619b55f36172f76bcbcaa8bb2d10c5f'); + test.done(); + }, +}; diff --git a/packages/decdk/package.json b/packages/decdk/package.json index c117d39aefecc..8bf2cf585f311 100644 --- a/packages/decdk/package.json +++ b/packages/decdk/package.json @@ -29,7 +29,6 @@ "dependencies": { "@aws-cdk/alexa-ask": "0.0.0", "@aws-cdk/app-delivery": "0.0.0", - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-accessanalyzer": "0.0.0", "@aws-cdk/aws-acmpca": "0.0.0", "@aws-cdk/aws-amazonmq": "0.0.0", diff --git a/packages/monocdk-experiment/package.json b/packages/monocdk-experiment/package.json index 34e48d31bb95b..c77eba87c7dd4 100644 --- a/packages/monocdk-experiment/package.json +++ b/packages/monocdk-experiment/package.json @@ -49,7 +49,6 @@ "constructs": "^3.0.2", "@aws-cdk/alexa-ask": "0.0.0", "@aws-cdk/app-delivery": "0.0.0", - "@aws-cdk/assets": "0.0.0", "@aws-cdk/aws-accessanalyzer": "0.0.0", "@aws-cdk/aws-acmpca": "0.0.0", "@aws-cdk/aws-amazonmq": "0.0.0",