From fdc3b36cb2c1c0093a9d38505d11692dab3ea29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danilo=20B=C3=BCrger?= Date: Mon, 12 Sep 2022 14:06:03 +0200 Subject: [PATCH] fix(core): make sure ignore strategies receive directories with trailing slash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ignore strategies like git, expect directories to be passed in with a trailing slash in order to properly match. consider a source tree: ├── hello │   └── index.html ├── index.html now we want to exclude everything except all html files (including all subdirectories). this can be done with a gitignore of: * !*/ !*.html in order for the git ignore strategy to properly match this, it needs to know that hello is a directory. this patch just does that by appending a trailing slash for the ignore strategies. --- packages/@aws-cdk/core/lib/fs/copy.ts | 9 +++++---- packages/@aws-cdk/core/lib/fs/fingerprint.ts | 7 ++++--- packages/@aws-cdk/core/lib/fs/ignore.ts | 3 +++ .../core/test/fs/fs-fingerprint.test.ts | 17 ++++++++++++++++- .../@aws-cdk/core/test/fs/fs-ignore.test.ts | 15 +++++++++++++++ 5 files changed, 43 insertions(+), 8 deletions(-) diff --git a/packages/@aws-cdk/core/lib/fs/copy.ts b/packages/@aws-cdk/core/lib/fs/copy.ts index 627dc2aa988dc..01565b19d70f5 100644 --- a/packages/@aws-cdk/core/lib/fs/copy.ts +++ b/packages/@aws-cdk/core/lib/fs/copy.ts @@ -15,15 +15,16 @@ export function copyDirectory(srcDir: string, destDir: string, options: CopyOpti throw new Error(`${srcDir} is not a directory`); } - const files = fs.readdirSync(srcDir); + const files = fs.readdirSync(srcDir, { withFileTypes: true }); for (const file of files) { - const sourceFilePath = path.join(srcDir, file); + const sourceFilePath = path.join(srcDir, file.name); - if (ignoreStrategy.ignores(sourceFilePath)) { + const ignorePath = sourceFilePath + (file.name && file.isDirectory() ? path.sep : ''); + if (ignoreStrategy.ignores(ignorePath)) { continue; } - const destFilePath = path.join(destDir, file); + const destFilePath = path.join(destDir, file.name); let stat: fs.Stats | undefined = follow === SymlinkFollowMode.ALWAYS ? fs.statSync(sourceFilePath) diff --git a/packages/@aws-cdk/core/lib/fs/fingerprint.ts b/packages/@aws-cdk/core/lib/fs/fingerprint.ts index 58dd602cc1590..113c22ebd2356 100644 --- a/packages/@aws-cdk/core/lib/fs/fingerprint.ts +++ b/packages/@aws-cdk/core/lib/fs/fingerprint.ts @@ -65,12 +65,13 @@ export function fingerprint(fileOrDirectory: string, options: FingerprintOptions return hash.digest('hex'); function _processFileOrDirectory(symbolicPath: string, isRootDir: boolean = false, realPath = symbolicPath) { - if (!isRootDir && ignoreStrategy.ignores(symbolicPath)) { + const stat = fs.lstatSync(realPath); + + const ignorePath = symbolicPath + (stat.isDirectory() ? path.sep : ''); + if (!isRootDir && ignoreStrategy.ignores(ignorePath)) { return; } - const stat = fs.lstatSync(realPath); - // Use relative path as hash component. Normalize it with forward slashes to ensure // same hash on Windows and Linux. const hashComponent = path.relative(fileOrDirectory, symbolicPath).replace(/\\/g, '/'); diff --git a/packages/@aws-cdk/core/lib/fs/ignore.ts b/packages/@aws-cdk/core/lib/fs/ignore.ts index 24a7114fb4707..eca694fe806d0 100644 --- a/packages/@aws-cdk/core/lib/fs/ignore.ts +++ b/packages/@aws-cdk/core/lib/fs/ignore.ts @@ -174,6 +174,9 @@ export class GitIgnoreStrategy extends IgnoreStrategy { } let relativePath = path.relative(this.absoluteRootPath, absoluteFilePath); + if (relativePath) { + relativePath += absoluteFilePath.endsWith(path.sep) ? path.sep : ''; + } return this.ignore.ignores(relativePath); } diff --git a/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts b/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts index c2f5106e416a8..a3f9bdb5239aa 100644 --- a/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts +++ b/packages/@aws-cdk/core/test/fs/fs-fingerprint.test.ts @@ -1,7 +1,7 @@ import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; -import { FileSystem, SymlinkFollowMode } from '../../lib/fs'; +import { FileSystem, IgnoreMode, SymlinkFollowMode } from '../../lib/fs'; import { contentFingerprint } from '../../lib/fs/fingerprint'; describe('fs fingerprint', () => { @@ -79,6 +79,21 @@ describe('fs fingerprint', () => { }); + test('does not ignore requested files with negate modifier', () => { + // GIVEN + const srcdir = path.join(__dirname, 'fixtures', 'test1'); + const outdir = fs.mkdtempSync(path.join(os.tmpdir(), 'copy-tests')); + FileSystem.copyDirectory(srcdir, outdir); + + // WHEN + const hashSrc = FileSystem.fingerprint(srcdir, { exclude: ['*', '!*/', '!*.*'], ignoreMode: IgnoreMode.GIT }); + const hashCopy = FileSystem.fingerprint(outdir, { ignoreMode: IgnoreMode.GIT }); + + // THEN + expect(hashSrc).toEqual(hashCopy); + + }); + test('changes with file names', () => { // GIVEN const srcdir = path.join(__dirname, 'fixtures', 'symlinks'); diff --git a/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts b/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts index a24dab6afdc05..94780c9505fb5 100644 --- a/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts +++ b/packages/@aws-cdk/core/test/fs/fs-ignore.test.ts @@ -87,6 +87,21 @@ describe('GitIgnoreStrategy', () => { expect(strategyPermits(strategy, permits)).toEqual(permits); }); + + test('does not exclude allow listed files in subdirectories after excluding everything', () => { + const strategy = IgnoreStrategy.git('/tmp', ['*', '!*/', '!*.html']); + const ignores = [ + '/tmp/file.ignored', + '/tmp/some/file.ignored', + ]; + const permits = [ + '/tmp/*.html', + '/tmp/some/*.html', + ]; + + expect(strategyIgnores(strategy, ignores)).toEqual(ignores); + expect(strategyPermits(strategy, permits)).toEqual(permits); + }); }); describe('DockerIgnoreStrategy', () => {