Skip to content

Commit

Permalink
feat(core): move all types from "assets" to "core" (#7708)
Browse files Browse the repository at this point in the history
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.

NOTE: since interfaces in @aws-cdk/assets are used as based types for stable APIs, we are unable to fully deprecate this module within the codebase, so these types are left in tact and a compatibility layer was added.

A subsequent commit will add a mini-framework for custom resources that leverages this capability.
  • Loading branch information
Elad Ben-Israel committed May 1, 2020
1 parent 5861d18 commit 4a84c96
Show file tree
Hide file tree
Showing 26 changed files with 416 additions and 174 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,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",
Expand Down
10 changes: 3 additions & 7 deletions packages/@aws-cdk/assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,11 @@
<!--BEGIN STABILITY BANNER-->
---

![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.
---
<!--END STABILITY BANNER-->

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.
17 changes: 17 additions & 0 deletions packages/@aws-cdk/assets/lib/compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { SymlinkFollowMode } from '@aws-cdk/core';
import { FollowMode } from './fs/follow-mode';

export function toSymlinkFollow(follow?: FollowMode): SymlinkFollowMode | undefined {
if (!follow) {
return undefined;
}

switch (follow) {
case FollowMode.NEVER: return SymlinkFollowMode.NEVER;
case FollowMode.ALWAYS: return SymlinkFollowMode.ALWAYS;
case FollowMode.BLOCK_EXTERNAL: return SymlinkFollowMode.BLOCK_EXTERNAL;
case FollowMode.EXTERNAL: return SymlinkFollowMode.EXTERNAL;
default:
throw new Error(`unknown follow mode: ${follow}`);
}
}
4 changes: 4 additions & 0 deletions packages/@aws-cdk/assets/lib/fs/follow-mode.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* Symlink follow mode.
* @deprecated see `core.SymlinkFollowMode`
*/
export enum FollowMode {
/**
* Never follow symlinks.
Expand Down
4 changes: 0 additions & 4 deletions packages/@aws-cdk/assets/lib/fs/index.ts

This file was deleted.

2 changes: 2 additions & 0 deletions packages/@aws-cdk/assets/lib/fs/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { FollowMode } from './follow-mode';

/**
* Obtains applied when copying directories into the staging location.
* @deprecated see `core.CopyOptions`
*/
export interface CopyOptions {
/**
Expand All @@ -21,6 +22,7 @@ export interface CopyOptions {

/**
* Options related to calculating source hash.
* @deprecated see `core.FingerprintOptions`
*/
export interface FingerprintOptions extends CopyOptions {
/**
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assets/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './api';
export * from './fs/follow-mode';
export * from './fs/options';
export * from './staging';
export * from './staging';
101 changes: 19 additions & 82 deletions packages/@aws-cdk/assets/lib/staging.ts
Original file line number Diff line number Diff line change
@@ -1,92 +1,29 @@
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 { AssetStaging, Construct } from '@aws-cdk/core';
import { toSymlinkFollow } from './compat';
import { FingerprintOptions } from './fs/options';

/**
* Deprecated
* @deprecated use `core.AssetStagingProps`
*/
export interface StagingProps extends FingerprintOptions {
/**
* Local file or directory to stage.
*/
readonly sourcePath: string;
}

/**
* Stages a file or directory from a location on the file system into a staging
* directory.
*
* This is controlled by the context key 'aws:cdk:asset-staging' and enabled
* by the CLI by default in order to ensure that when the CDK app exists, all
* assets are available for deployment. Otherwise, if an app references assets
* in temporary locations, those will not be available when it exists (see
* https://github.com/aws/aws-cdk/issues/1716).
*
* The `stagedPath` property is a stringified token that represents the location
* of the file or directory after staging. It will be resolved only during the
* "prepare" stage and may be either the original path or the staged path
* depending on the context setting.
*
* The file/directory are staged based on their content hash (fingerprint). This
* means that only if content was changed, copy will happen.
* Deprecated
* @deprecated use `core.AssetStaging`
*/
export class Staging extends Construct {

/**
* The path to the asset (stringinfied token).
*
* If asset staging is disabled, this will just be the original path.
* If asset staging is enabled it will be the staged path.
*/
public readonly stagedPath: string;

/**
* The path of the asset as it was referenced by the user.
*/
public readonly sourcePath: string;

/**
* A cryptographic hash of the source document(s).
*/
public readonly sourceHash: string;

private readonly fingerprintOptions: FingerprintOptions;

private readonly relativePath?: string;

export class Staging extends AssetStaging {
constructor(scope: Construct, id: string, props: StagingProps) {
super(scope, id);

this.sourcePath = props.sourcePath;
this.fingerprintOptions = props;
this.sourceHash = fingerprint(this.sourcePath, props);

const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
if (stagingDisabled) {
this.stagedPath = this.sourcePath;
} else {
this.relativePath = 'asset.' + this.sourceHash + path.extname(this.sourcePath);
this.stagedPath = this.relativePath; // always relative to outdir
}
}

protected synthesize(session: ISynthesisSession) {
if (!this.relativePath) {
return;
}

const targetPath = path.join(session.assembly.outdir, this.relativePath);

// asset already staged
if (fs.existsSync(targetPath)) {
return;
}

// copy file/directory to staging directory
const stat = fs.statSync(this.sourcePath);
if (stat.isFile()) {
fs.copyFileSync(this.sourcePath, targetPath);
} else if (stat.isDirectory()) {
fs.mkdirSync(targetPath);
copyDirectory(this.sourcePath, targetPath, this.fingerprintOptions);
} else {
throw new Error(`Unknown file type: ${this.sourcePath}`);
}
super(scope, id, {
sourcePath: props.sourcePath,
exclude: props.exclude,
extraHash: props.extraHash,
follow: toSymlinkFollow(props.follow),
});
}
}
18 changes: 3 additions & 15 deletions packages/@aws-cdk/assets/package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -90,18 +88,8 @@
"engines": {
"node": ">= 10.12.0"
},
"bundledDependencies": [
"minimatch"
],
"stability": "experimental",
"maturity": "experimental",
"awslint": {
"exclude": [
"docs-public-apis:@aws-cdk/assets.StagingProps",
"docs-public-apis:@aws-cdk/assets.StagingProps.sourcePath",
"docs-public-apis:@aws-cdk/assets.FollowMode"
]
},
"stability": "deprecated",
"maturity": "deprecated",
"awscdkio": {
"announce": false
}
Expand Down
15 changes: 15 additions & 0 deletions packages/@aws-cdk/assets/test/test.compat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SymlinkFollowMode } from '@aws-cdk/core';
import { Test } from 'nodeunit';
import { FollowMode } from '../lib';
import { toSymlinkFollow } from '../lib/compat';

export = {
'FollowMode compatibility'(test: Test) {
test.equal(toSymlinkFollow(undefined), null);
test.equal(toSymlinkFollow(FollowMode.ALWAYS), SymlinkFollowMode.ALWAYS);
test.equal(toSymlinkFollow(FollowMode.BLOCK_EXTERNAL), SymlinkFollowMode.BLOCK_EXTERNAL);
test.equal(toSymlinkFollow(FollowMode.EXTERNAL), SymlinkFollowMode.EXTERNAL);
test.equal(toSymlinkFollow(FollowMode.NEVER), SymlinkFollowMode.NEVER);
test.done();
},
};
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
98 changes: 98 additions & 0 deletions packages/@aws-cdk/core/lib/asset-staging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import * as cxapi from '@aws-cdk/cx-api';
import * as fs from 'fs';
import * as path from 'path';
import { Construct, ISynthesisSession } from './construct-compat';
import { FileSystem, FingerprintOptions } from './fs';

/**
* Initialization properties for `AssetStaging`.
*/
export interface AssetStagingProps extends FingerprintOptions {
/**
* The source file or directory to copy from.
*/
readonly sourcePath: string;
}

/**
* Stages a file or directory from a location on the file system into a staging
* directory.
*
* This is controlled by the context key 'aws:cdk:asset-staging' and enabled
* by the CLI by default in order to ensure that when the CDK app exists, all
* assets are available for deployment. Otherwise, if an app references assets
* in temporary locations, those will not be available when it exists (see
* https://github.com/aws/aws-cdk/issues/1716).
*
* The `stagedPath` property is a stringified token that represents the location
* of the file or directory after staging. It will be resolved only during the
* "prepare" stage and may be either the original path or the staged path
* depending on the context setting.
*
* The file/directory are staged based on their content hash (fingerprint). This
* means that only if content was changed, copy will happen.
*/
export class AssetStaging extends Construct {

/**
* The path to the asset (stringinfied token).
*
* If asset staging is disabled, this will just be the original path.
* If asset staging is enabled it will be the staged path.
*/
public readonly stagedPath: string;

/**
* The path of the asset as it was referenced by the user.
*/
public readonly sourcePath: string;

/**
* A cryptographic hash of the source document(s).
*/
public readonly sourceHash: string;

private readonly fingerprintOptions: FingerprintOptions;

private readonly relativePath?: string;

constructor(scope: Construct, id: string, props: AssetStagingProps) {
super(scope, id);

this.sourcePath = props.sourcePath;
this.fingerprintOptions = props;
this.sourceHash = FileSystem.fingerprint(this.sourcePath, props);

const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
if (stagingDisabled) {
this.stagedPath = this.sourcePath;
} else {
this.relativePath = 'asset.' + this.sourceHash + path.extname(this.sourcePath);
this.stagedPath = this.relativePath; // always relative to outdir
}
}

protected synthesize(session: ISynthesisSession) {
if (!this.relativePath) {
return;
}

const targetPath = path.join(session.assembly.outdir, this.relativePath);

// asset already staged
if (fs.existsSync(targetPath)) {
return;
}

// copy file/directory to staging directory
const stat = fs.statSync(this.sourcePath);
if (stat.isFile()) {
fs.copyFileSync(this.sourcePath, targetPath);
} else if (stat.isDirectory()) {
fs.mkdirSync(targetPath);
FileSystem.copyDirectory(this.sourcePath, targetPath, this.fingerprintOptions);
} else {
throw new Error(`Unknown file type: ${this.sourcePath}`);
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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);

Expand Down

0 comments on commit 4a84c96

Please sign in to comment.