diff --git a/packages/aws-cdk/lib/archive.ts b/packages/aws-cdk/lib/archive.ts index a5994ea035369..e149ac287b5b2 100644 --- a/packages/aws-cdk/lib/archive.ts +++ b/packages/aws-cdk/lib/archive.ts @@ -5,7 +5,7 @@ import glob = require('glob'); import path = require('path'); export function zipDirectory(directory: string, outputFile: string): Promise { - return new Promise((ok, fail) => { + return new Promise(async (ok, fail) => { // The below options are needed to support following symlinks when building zip files: // - nodir: This will prevent symlinks themselves from being copied into the zip. // - follow: This will follow symlinks and copy the files within. @@ -24,12 +24,16 @@ export function zipDirectory(directory: string, outputFile: string): Promise { // Append files serially to ensure file order - archive.append(fs.createReadStream(path.join(directory, file)), { + // Append files serially to ensure file order + for (const file of files) { + const fullPath = path.join(directory, file); + const [data, stat] = await Promise.all([fs.readFile(fullPath), fs.stat(fullPath)]); + archive.append(data, { name: file, date: new Date('1980-01-01T00:00:00.000Z'), // reset dates to get the same hash for the same content + mode: stat.mode, }); - }); + } archive.finalize(); diff --git a/packages/aws-cdk/test/test-archive/executable.txt b/packages/aws-cdk/test/test-archive/executable.txt new file mode 100755 index 0000000000000..e69de29bb2d1d diff --git a/packages/aws-cdk/test/test.archive.ts b/packages/aws-cdk/test/test.archive.ts index c709cce749765..8eda93cd28465 100644 --- a/packages/aws-cdk/test/test.archive.ts +++ b/packages/aws-cdk/test/test.archive.ts @@ -32,6 +32,12 @@ export = { test.equal(dates[0], '1980-01-01T00:00:00.000Z', 'Dates are not reset'); test.equal(new Set(dates).size, 1, 'Dates are not equal'); + // check that mode is preserved + const stat = await fs.stat(path.join(extractDir, 'executable.txt')); + // tslint:disable-next-line:no-bitwise + const isExec = (stat.mode & fs.constants.S_IXUSR) || (stat.mode & fs.constants.S_IXGRP) || (stat.mode & fs.constants.S_IXOTH); + test.ok(isExec, 'File is not executable'); + await fs.remove(stagingDir); await fs.remove(extractDir); test.done();