-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: add --compress flag to cdk migrate (#27184)
This also updates some of the aliases used because they clashed with other flags. We'll just remove these. The archive file is shamelessly ripped off from the cdk-assets package. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information
1 parent
e15d0c0
commit 3d6d042
Showing
7 changed files
with
249 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import { error } from 'console'; | ||
import { createWriteStream, promises as fs } from 'fs'; | ||
import * as path from 'path'; | ||
import * as glob from 'glob'; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-require-imports | ||
const archiver = require('archiver'); | ||
|
||
// Adapted from cdk-assets | ||
export async function zipDirectory(directory: string, outputFile: string): Promise<void> { | ||
// We write to a temporary file and rename at the last moment. This is so that if we are | ||
// interrupted during this process, we don't leave a half-finished file in the target location. | ||
const temporaryOutputFile = `${outputFile}.${randomString()}._tmp`; | ||
await writeZipFile(directory, temporaryOutputFile); | ||
await moveIntoPlace(temporaryOutputFile, outputFile); | ||
} | ||
|
||
function writeZipFile(directory: string, outputFile: string): Promise<void> { | ||
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. | ||
const globOptions = { | ||
dot: true, | ||
nodir: true, | ||
follow: true, | ||
cwd: directory, | ||
}; | ||
const files = glob.sync('**', globOptions); // The output here is already sorted | ||
|
||
const output = createWriteStream(outputFile); | ||
|
||
const archive = archiver('zip'); | ||
archive.on('warning', fail); | ||
archive.on('error', fail); | ||
|
||
// archive has been finalized and the output file descriptor has closed, resolve promise | ||
// this has to be done before calling `finalize` since the events may fire immediately after. | ||
// see https://www.npmjs.com/package/archiver | ||
output.once('close', ok); | ||
|
||
archive.pipe(output); | ||
|
||
// Append files serially to ensure file order | ||
for (const file of files) { | ||
const fullPath = path.resolve(directory, file); | ||
const [data, stat] = await Promise.all([fs.readFile(fullPath), fs.stat(fullPath)]); | ||
archive.append(data, { | ||
name: file, | ||
mode: stat.mode, | ||
}); | ||
} | ||
|
||
await archive.finalize(); | ||
}); | ||
} | ||
|
||
/** | ||
* Rename the file to the target location, taking into account: | ||
* | ||
* - That we may see EPERM on Windows while an Antivirus scanner still has the | ||
* file open, so retry a couple of times. | ||
* - This same function may be called in parallel and be interrupted at any point. | ||
*/ | ||
async function moveIntoPlace(source: string, target: string) { | ||
let delay = 100; | ||
let attempts = 5; | ||
while (true) { | ||
try { | ||
// 'rename' is guaranteed to overwrite an existing target, as long as it is a file (not a directory) | ||
await fs.rename(source, target); | ||
return; | ||
} catch (e: any) { | ||
if (e.code !== 'EPERM' || attempts-- <= 0) { | ||
throw e; | ||
} | ||
error(e.message); | ||
await sleep(Math.floor(Math.random() * delay)); | ||
delay *= 2; | ||
} | ||
} | ||
} | ||
|
||
function sleep(ms: number) { | ||
return new Promise(ok => setTimeout(ok, ms)); | ||
} | ||
|
||
function randomString() { | ||
return Math.random().toString(36).replace(/[^a-z0-9]+/g, ''); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.