diff --git a/packages/@aws-cdk/core/lib/asset-staging.ts b/packages/@aws-cdk/core/lib/asset-staging.ts index c37d8d441d7c0..7010b6cbce6fc 100644 --- a/packages/@aws-cdk/core/lib/asset-staging.ts +++ b/packages/@aws-cdk/core/lib/asset-staging.ts @@ -1,6 +1,5 @@ import * as cxapi from '@aws-cdk/cx-api'; import * as fs from 'fs'; -import * as os from 'os'; import * as path from 'path'; import { AssetHashType, AssetOptions } from './assets'; import { BUNDLING_INPUT_DIR, BUNDLING_OUTPUT_DIR, BundlingOptions } from './bundling'; @@ -137,7 +136,7 @@ export class AssetStaging extends Construct { private bundle(options: BundlingOptions): string { // Create temporary directory for bundling - const bundleDir = fs.mkdtempSync(path.resolve(path.join(os.tmpdir(), 'cdk-asset-bundle-'))); + const bundleDir = FileSystem.mkdtemp('cdk-asset-bundle-'); // Always mount input and output dir const volumes = [ diff --git a/packages/@aws-cdk/core/lib/fs/index.ts b/packages/@aws-cdk/core/lib/fs/index.ts index 01c6d132956e2..4ecfea7c2471c 100644 --- a/packages/@aws-cdk/core/lib/fs/index.ts +++ b/packages/@aws-cdk/core/lib/fs/index.ts @@ -1,4 +1,6 @@ import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; import { copyDirectory } from './copy'; import { fingerprint } from './fingerprint'; import { CopyOptions, FingerprintOptions } from './options'; @@ -43,4 +45,27 @@ export class FileSystem { public static isEmpty(dir: string): boolean { return fs.readdirSync(dir).length === 0; } + + /** + * The real path of the system temp directory + */ + public static get tmpdir(): string { + if (FileSystem._tmpdir) { + return FileSystem._tmpdir; + } + FileSystem._tmpdir = fs.realpathSync(os.tmpdir()); + return FileSystem._tmpdir; + } + + /** + * Creates a unique temporary directory in the **system temp directory**. + * + * @param prefix A prefix for the directory name. Six random characters + * will be generated and appended behind this prefix. + */ + public static mkdtemp(prefix: string): string { + return fs.mkdtempSync(path.join(FileSystem.tmpdir, prefix)); + } + + private static _tmpdir?: string; } diff --git a/packages/@aws-cdk/core/test/fs/test.fs.ts b/packages/@aws-cdk/core/test/fs/test.fs.ts new file mode 100644 index 0000000000000..cc6d4898c922e --- /dev/null +++ b/packages/@aws-cdk/core/test/fs/test.fs.ts @@ -0,0 +1,48 @@ +import * as fs from 'fs'; +import { Test } from 'nodeunit'; +import * as os from 'os'; +import * as path from 'path'; +import * as sinon from 'sinon'; +import { FileSystem } from '../../lib/fs'; + +export = { + 'tearDown'(callback: any) { + sinon.restore(); + callback(); + }, + + 'tmpdir returns a real path and is cached'(test: Test) { + // Create symlink that points to /tmp + const symlinkTmp = path.join(__dirname, 'tmp-link'); + fs.symlinkSync(os.tmpdir(), symlinkTmp); + + // Now stub os.tmpdir() to return this link instead of /tmp + const tmpdirStub = sinon.stub(os, 'tmpdir').returns(symlinkTmp); + + test.ok(path.isAbsolute(FileSystem.tmpdir)); + + const p = path.join(FileSystem.tmpdir, 'tmpdir-test.txt'); + fs.writeFileSync(p, 'tmpdir-test'); + + test.equal(p, fs.realpathSync(p)); + test.equal(fs.readFileSync(p, 'utf8'), 'tmpdir-test'); + + test.ok(tmpdirStub.calledOnce); // cached result + + fs.unlinkSync(p); + fs.unlinkSync(symlinkTmp); + + test.done(); + }, + + 'mkdtemp creates a temporary directory in the system temp'(test: Test) { + const tmpdir = FileSystem.mkdtemp('cdk-mkdtemp-'); + + test.equal(path.dirname(tmpdir), FileSystem.tmpdir); + test.ok(fs.existsSync(tmpdir)); + + fs.rmdirSync(tmpdir); + + test.done(); + }, +};