Skip to content

Commit 6cee01c

Browse files
committed
fix: excludes the passed path for purposes of matching inclusion/exclusion folders
The same folder accessed from a different working directory will include/exclude in the same way
1 parent d3df702 commit 6cee01c

2 files changed

Lines changed: 46 additions & 16 deletions

File tree

index.js

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ function prep(fs) {
4949

5050
function hashElement(name, dir, options, callback) {
5151
callback = arguments[arguments.length - 1];
52+
const base = name;
5253

5354
return parseParameters(arguments)
5455
.then(({ basename, dir, options }) => {
@@ -60,7 +61,7 @@ function prep(fs) {
6061
stats.name = basename;
6162
return stats;
6263
})
63-
.then(stats => hashElementPromise(stats, dir, options, true));
64+
.then(stats => hashElementPromise(stats, dir, base, options, true));
6465
})
6566
.then(result => {
6667
if (isFunction(callback)) {
@@ -82,18 +83,19 @@ function prep(fs) {
8283
/**
8384
* @param {fs.Stats} stats folder element, can also be of type fs.Dirent
8485
* @param {string} dirname
86+
* @param {string} base
8587
* @param {Options} options
8688
* @param {boolean} isRootElement
8789
*/
88-
function hashElementPromise(stats, dirname, options, isRootElement = false) {
90+
function hashElementPromise(stats, dirname, base, options, isRootElement = false) {
8991
const name = stats.name;
9092
let promise = undefined;
9193
if (stats.isDirectory()) {
92-
promise = hashFolderPromise(name, dirname, options, isRootElement);
94+
promise = hashFolderPromise(name, dirname, base, options, isRootElement);
9395
} else if (stats.isFile()) {
94-
promise = hashFilePromise(name, dirname, options, isRootElement);
96+
promise = hashFilePromise(name, dirname, base, options, isRootElement);
9597
} else if (stats.isSymbolicLink()) {
96-
promise = hashSymLinkPromise(name, dirname, options, isRootElement);
98+
promise = hashSymLinkPromise(name, dirname, base, options, isRootElement);
9799
} else {
98100
log.err('hashElementPromise cannot handle ', stats);
99101
return Promise.resolve({ name, hash: 'Error: unknown element type' });
@@ -106,7 +108,7 @@ function prep(fs) {
106108
const promise = new Promise((resolve, reject) => {
107109
queue.push(() => {
108110
log.queue(`Will processs queued ${dirname}/${name}`);
109-
return hashElementPromise(stats, dirname, options, isRootElement)
111+
return hashElementPromise(stats, dirname, base, options, isRootElement)
110112
.then(ok => resolve(ok))
111113
.catch(err => reject(err));
112114
});
@@ -129,7 +131,7 @@ function prep(fs) {
129131
runnables.forEach(run => run());
130132
}
131133

132-
async function hashFolderPromise(name, dir, options, isRootElement = false) {
134+
async function hashFolderPromise(name, dir, base, options, isRootElement = false) {
133135
const folderPath = path.join(dir, name);
134136
let ignoreBasenameOnce = options.ignoreBasenameOnce;
135137
delete options.ignoreBasenameOnce;
@@ -138,30 +140,30 @@ function prep(fs) {
138140
// this is currently only used for the root folder
139141
log.match(`skipped '${folderPath}'`);
140142
delete options.skipMatching;
141-
} else if (ignore(name, folderPath, options.folders)) {
143+
} else if (ignore(name, folderPath, base, options.folders)) {
142144
return undefined;
143145
}
144146

145147
const files = await fs.promises.readdir(folderPath, { withFileTypes: true });
146148
const children = await Promise.all(
147149
files
148150
.sort((a, b) => a.name.localeCompare(b.name))
149-
.map(child => hashElementPromise(child, folderPath, options)),
151+
.map(child => hashElementPromise(child, folderPath, base, options)),
150152
);
151153

152154
if (ignoreBasenameOnce) options.ignoreBasenameOnce = true;
153155
const hash = new HashedFolder(name, children.filter(notUndefined), options, isRootElement);
154156
return hash;
155157
}
156158

157-
function hashFilePromise(name, dir, options, isRootElement = false) {
159+
function hashFilePromise(name, dir, base, options, isRootElement = false) {
158160
const filePath = path.join(dir, name);
159161

160162
if (options.skipMatching) {
161163
// this is currently only used for the root folder
162164
log.match(`skipped '${filePath}'`);
163165
delete options.skipMatching;
164-
} else if (ignore(name, filePath, options.files)) {
166+
} else if (ignore(name, filePath, base, options.files)) {
165167
return Promise.resolve(undefined);
166168
}
167169

@@ -195,14 +197,14 @@ function prep(fs) {
195197
});
196198
}
197199

198-
async function hashSymLinkPromise(name, dir, options, isRootElement = false) {
200+
async function hashSymLinkPromise(name, dir, base, options, isRootElement = false) {
199201
const target = await fs.promises.readlink(path.join(dir, name));
200202
log.symlink(`handling symbolic link ${name} -> ${target}`);
201203
if (options.symbolicLinks.include) {
202204
if (options.symbolicLinks.ignoreTargetContent) {
203205
return symLinkIgnoreTargetContent(name, target, options, isRootElement);
204206
} else {
205-
return symLinkResolve(name, dir, target, options, isRootElement);
207+
return symLinkResolve(name, dir, base, target, options, isRootElement);
206208
}
207209
} else {
208210
log.symlink('skipping symbolic link');
@@ -225,7 +227,7 @@ function prep(fs) {
225227
return Promise.resolve(new HashedFile(name, hash, options.encoding));
226228
}
227229

228-
async function symLinkResolve(name, dir, target, options, isRootElement) {
230+
async function symLinkResolve(name, dir, base, target, options, isRootElement) {
229231
delete options.skipMatching; // only used for the root level
230232
if (options.symbolicLinks.ignoreBasename) {
231233
options.ignoreBasenameOnce = true;
@@ -234,7 +236,7 @@ function prep(fs) {
234236
try {
235237
const stats = await fs.promises.stat(path.join(dir, name));
236238
stats.name = name;
237-
const temp = await hashElementPromise(stats, dir, options, isRootElement);
239+
const temp = await hashElementPromise(stats, dir, base, options, isRootElement);
238240

239241
if (!options.symbolicLinks.ignoreTargetPath) {
240242
const hash = crypto.createHash(options.algo);
@@ -265,7 +267,10 @@ function prep(fs) {
265267
}
266268
}
267269

268-
function ignore(name, path, rules) {
270+
function ignore(name, path, root, rules) {
271+
path = path.replace(root, '');
272+
if (path.startsWith('/')) path = path.substring(1);
273+
269274
if (rules.exclude) {
270275
if (rules.matchBasename && rules.exclude(name)) {
271276
log.match(`exclude basename '${name}'`);

test/folders.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,31 @@ describe('Generating a hash over a folder, it', function () {
5555
return hashElement('abc', options).then(checkChildren);
5656
});
5757

58+
it('ignores base directory for purposes of exclude function', function () {
59+
const hashElement = prep(
60+
Volume.fromJSON({
61+
'abc/def': 'abc/def',
62+
'abc/ghi/jkl/file.js': 'content',
63+
'abc/ghi/jkl/file2.js': 'content',
64+
'abc/ghi/folder/data.json': 'content',
65+
'abc/ghi/folder/subfolder/today.log': 'content',
66+
}),
67+
);
68+
69+
const options = {
70+
folders: {
71+
exclude: ['jkl'],
72+
},
73+
};
74+
75+
const checkChildren = current => {
76+
current.children.length.should.equal(1);
77+
current.children[0].name.should.equal('folder');
78+
};
79+
80+
return hashElement('abc/ghi', options).then(checkChildren);
81+
});
82+
5883
it('generates different hashes if the folders have the same content but different names', function () {
5984
const hashElement = prep(
6085
Volume.fromJSON({

0 commit comments

Comments
 (0)