Skip to content

Commit dda6f13

Browse files
authored
fix: Created matchAll function wrapper for minimatch so dir globs are properly ignored (#432)
1 parent 964fa6e commit dda6f13

File tree

5 files changed

+61
-15
lines changed

5 files changed

+61
-15
lines changed

src/model.ts

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import * as fs from "fs";
2-
import { Minimatch } from "minimatch";
32
import * as path from "path";
43
import {
54
commands,
65
Disposable,
76
Event,
87
EventEmitter,
9-
SourceControlResourceGroup,
108
Uri,
119
window,
1210
workspace,
@@ -19,7 +17,7 @@ import {
1917
RepositoryState,
2018
Status
2119
} from "./common/types";
22-
import { debounce, sequentialize } from "./decorators";
20+
import { debounce } from "./decorators";
2321
import { configuration } from "./helpers/configuration";
2422
import { RemoteRepository } from "./remoteRepository";
2523
import { Repository } from "./repository";
@@ -33,6 +31,7 @@ import {
3331
isDescendant,
3432
normalizePath
3533
} from "./util";
34+
import { matchAll } from "./util/globMatch";
3635

3736
export class Model implements IDisposable {
3837
private _onDidOpenRepository = new EventEmitter<Repository>();
@@ -319,15 +318,14 @@ export class Model implements IDisposable {
319318
return;
320319
}
321320

322-
const mm = new Minimatch("*");
323321
const newLevel = level + 1;
324322
if (newLevel <= this.maxDepth) {
325323
for (const file of fs.readdirSync(path)) {
326324
const dir = path + "/" + file;
327325

328326
if (
329327
fs.statSync(dir).isDirectory() &&
330-
!mm.matchOne([dir], this.ignoreList, false)
328+
!matchAll(dir, this.ignoreList, { dot: true })
331329
) {
332330
await this.tryOpenRepository(dir, newLevel);
333331
}

src/repository.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Minimatch } from "minimatch";
21
import * as path from "path";
32
import { clearInterval, setInterval } from "timers";
43
import {
@@ -46,6 +45,7 @@ import {
4645
timeout,
4746
toDisposable
4847
} from "./util";
48+
import { match, matchAll } from "./util/globMatch";
4949

5050
function shouldShowProgress(operation: Operation): boolean {
5151
switch (operation) {
@@ -351,9 +351,7 @@ export class Repository implements IRemoteRepository {
351351
"delete.ignoredRulesForDeletedFiles",
352352
[]
353353
);
354-
const rules = ignoredRulesForDeletedFiles.map(
355-
ignored => new Minimatch(ignored)
356-
);
354+
const rules = ignoredRulesForDeletedFiles.map(ignored => match(ignored));
357355

358356
if (rules.length) {
359357
uris = uris.filter(uri => {
@@ -529,8 +527,7 @@ export class Repository implements IRemoteRepository {
529527
continue;
530528
}
531529

532-
const mm = new Minimatch("*");
533-
if (mm.matchOne([status.path], excludeList, false)) {
530+
if (matchAll(status.path, excludeList, { dot: true })) {
534531
continue;
535532
}
536533

src/test/extension.test.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ suite("Extension Tests", () => {
3535
// tslint:disable-next-line: only-arrow-functions
3636
test("should be able to activate the extension", function(done) {
3737
this.timeout(60 * 1000);
38-
const extension = vscode.extensions.getExtension("johnstoncode.svn-scm");
38+
const extension = vscode.extensions.getExtension(
39+
"johnstoncode.svn-scm"
40+
) as vscode.Extension<any>;
3941

4042
if (!extension) {
41-
done("Extension not found");
42-
return;
43+
assert.fail("Extension not found");
4344
}
4445

4546
if (!extension.isActive) {
@@ -48,7 +49,7 @@ suite("Extension Tests", () => {
4849
done();
4950
},
5051
() => {
51-
done("Failed to activate extension");
52+
assert.fail("Failed to activate extension");
5253
}
5354
);
5455
} else {

src/test/globMatch.test.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as assert from "assert";
2+
import { matchAll, match } from "../util/globMatch";
3+
4+
suite("Glob match testing", () => {
5+
test("Test single match", () => {
6+
const matcher = match("**/*.js");
7+
8+
assert.ok(matcher.match("test/tester.js"));
9+
assert.ok(matcher.match("tester/testing/test/tester.js"));
10+
});
11+
12+
test("Test Multiple Matches", () => {
13+
const patterns = ["**/.git", "**/.hg", "**/vendor", "**/node_modules"];
14+
15+
assert.strictEqual(matchAll(".git/test", patterns), false);
16+
assert.strictEqual(matchAll(".hg/test", patterns), false);
17+
assert.strictEqual(matchAll("vendor/test", patterns), false);
18+
assert.strictEqual(
19+
matchAll("project/test/node_modules/test/index.js", patterns),
20+
false
21+
);
22+
});
23+
});

src/util/globMatch.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as minimatch from "minimatch";
2+
3+
export function matchAll(
4+
path: string,
5+
patterns: string[],
6+
opts: minimatch.IOptions = {}
7+
): boolean {
8+
let match = false;
9+
10+
patterns.forEach(pattern => {
11+
const isExclusion = pattern[0] === "!";
12+
13+
// If we've got a match, only re-test for exclusions.
14+
// if we don't have a match, only re-test for inclusions.
15+
if (match !== isExclusion) {
16+
return;
17+
}
18+
19+
match = minimatch(path, pattern, opts);
20+
});
21+
22+
return match;
23+
}
24+
25+
export function match(pattern: string) {
26+
return new minimatch.Minimatch(pattern);
27+
}

0 commit comments

Comments
 (0)