Skip to content

Commit 01e0132

Browse files
committedMay 4, 2024·
Correct skipSubdirs option #77
1 parent e144d80 commit 01e0132

8 files changed

+104
-102
lines changed
 

‎README.md

+3
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,9 @@ The [default](https://github.com/gliviu/dir-compare/blob/master/src/ResultBuilde
307307
* [Visual Studio Code - Compare Folders](https://marketplace.visualstudio.com/items?itemName=moshfeu.compare-folders)
308308

309309
# Changelog
310+
* v5.0.0
311+
Breaking changes:
312+
* `skipSubdirs` option has slightly different behavior. More details in [#77](https://github.com/gliviu/dir-compare/issues/77#issuecomment-2094375352)
310313
* v4.2.0
311314
* Updated dependencies
312315
* Increased test coverage

‎appveyor.yml

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ image:
88

99
environment:
1010
matrix:
11+
- nodejs_version: 21
1112
- nodejs_version: 20
1213
- nodejs_version: 19
1314
- nodejs_version: 18

‎src/compareAsync.ts

+60-52
Original file line numberDiff line numberDiff line change
@@ -84,72 +84,80 @@ export function compareAsync(rootEntry1: OptionalEntry, rootEntry2: OptionalEntr
8484
// process entry
8585
if (cmp === 0) {
8686
// Both left/right exist and have the same name and type
87-
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)
87+
const skipEntry = options.skipSubdirs && type1 === 'directory'
88+
if (!skipEntry) {
89+
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)
8890

89-
if (permissionDeniedState === "access-ok") {
90-
const compareEntryRes = EntryEquality.isEntryEqualAsync(entry1, entry2, type1, asyncDiffSet, options)
91-
if (compareEntryRes.isSync) {
92-
options.resultBuilder(entry1, entry2,
93-
compareEntryRes.same ? 'equal' : 'distinct',
94-
level, relativePath, options, statistics, asyncDiffSet as DiffSet,
95-
compareEntryRes.reason, permissionDeniedState)
96-
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, compareEntryRes.same, compareEntryRes.reason,
97-
type1, permissionDeniedState, statistics, options)
91+
if (permissionDeniedState === "access-ok") {
92+
const compareEntryRes = EntryEquality.isEntryEqualAsync(entry1, entry2, type1, asyncDiffSet, options)
93+
if (compareEntryRes.isSync) {
94+
options.resultBuilder(entry1, entry2,
95+
compareEntryRes.same ? 'equal' : 'distinct',
96+
level, relativePath, options, statistics, asyncDiffSet as DiffSet,
97+
compareEntryRes.reason, permissionDeniedState)
98+
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, compareEntryRes.same, compareEntryRes.reason,
99+
type1, permissionDeniedState, statistics, options)
100+
} else {
101+
fileEqualityAsyncPromises.push(compareEntryRes.fileEqualityAsyncPromise)
102+
}
98103
} else {
99-
fileEqualityAsyncPromises.push(compareEntryRes.fileEqualityAsyncPromise)
104+
const state = 'distinct'
105+
const reason = "permission-denied"
106+
const same = false
107+
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, asyncDiffSet as DiffSet, reason, permissionDeniedState)
108+
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
109+
}
110+
if (type1 === 'directory') {
111+
const subDiffSet: AsyncDiffSet = []
112+
if (!options.noDiffSet) {
113+
asyncDiffSet.push(subDiffSet)
114+
}
115+
const comparePromise = limit(() => compareAsync(entry1, entry2, level + 1,
116+
pathUtils.join(relativePath, entry1.name),
117+
options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
118+
comparePromises.push(comparePromise)
100119
}
101-
} else {
102-
const state = 'distinct'
103-
const reason = "permission-denied"
104-
const same = false
105-
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, asyncDiffSet as DiffSet, reason, permissionDeniedState)
106-
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
107120
}
108-
109121
i1++
110122
i2++
111-
if (!options.skipSubdirs && type1 === 'directory') {
112-
const subDiffSet: AsyncDiffSet = []
113-
if (!options.noDiffSet) {
114-
asyncDiffSet.push(subDiffSet)
115-
}
116-
const comparePromise = limit(() => compareAsync(entry1, entry2, level + 1,
117-
pathUtils.join(relativePath, entry1.name),
118-
options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
119-
comparePromises.push(comparePromise)
120-
}
121123
} else if (cmp < 0) {
122124
// Right missing
123-
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
124-
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
125-
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
126-
i1++
127-
if (type1 === 'directory' && !options.skipSubdirs) {
128-
const subDiffSet: AsyncDiffSet = []
129-
if (!options.noDiffSet) {
130-
asyncDiffSet.push(subDiffSet)
125+
const skipEntry = options.skipSubdirs && type1 === 'directory'
126+
if (!skipEntry) {
127+
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
128+
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
129+
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
130+
if (type1 === 'directory') {
131+
const subDiffSet: AsyncDiffSet = []
132+
if (!options.noDiffSet) {
133+
asyncDiffSet.push(subDiffSet)
134+
}
135+
const comparePromise = limit(() => compareAsync(entry1, undefined,
136+
level + 1,
137+
pathUtils.join(relativePath, entry1.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
138+
comparePromises.push(comparePromise)
131139
}
132-
const comparePromise = limit(() => compareAsync(entry1, undefined,
133-
level + 1,
134-
pathUtils.join(relativePath, entry1.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
135-
comparePromises.push(comparePromise)
136140
}
141+
i1++
137142
} else {
138143
// Left missing
139-
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
140-
options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
141-
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
142-
i2++
143-
if (type2 === 'directory' && !options.skipSubdirs) {
144-
const subDiffSet: AsyncDiffSet = []
145-
if (!options.noDiffSet) {
146-
asyncDiffSet.push(subDiffSet)
144+
const skipEntry = options.skipSubdirs && type2 === 'directory'
145+
if (!skipEntry) {
146+
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
147+
options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
148+
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
149+
if (type2 === 'directory') {
150+
const subDiffSet: AsyncDiffSet = []
151+
if (!options.noDiffSet) {
152+
asyncDiffSet.push(subDiffSet)
153+
}
154+
const comparePromise = limit(() => compareAsync(undefined, entry2,
155+
level + 1,
156+
pathUtils.join(relativePath, entry2.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
157+
comparePromises.push(comparePromise)
147158
}
148-
const comparePromise = limit(() => compareAsync(undefined, entry2,
149-
level + 1,
150-
pathUtils.join(relativePath, entry2.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
151-
comparePromises.push(comparePromise)
152159
}
160+
i2++
153161
}
154162
}
155163
return Promise.all(comparePromises)

‎src/compareSync.ts

+38-29
Original file line numberDiff line numberDiff line change
@@ -66,46 +66,55 @@ export function compareSync(rootEntry1: OptionalEntry, rootEntry2: OptionalEntry
6666
// process entry
6767
if (cmp === 0) {
6868
// Both left/right exist and have the same name and type
69-
let same, reason, state
70-
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)
69+
const skipEntry = options.skipSubdirs && type1 === 'directory'
70+
if (!skipEntry) {
71+
let same, reason, state
72+
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)
7173

72-
if (permissionDeniedState === "access-ok") {
73-
const compareEntryRes = EntryEquality.isEntryEqualSync(entry1, entry2, type1, options)
74-
state = compareEntryRes.same ? 'equal' : 'distinct'
75-
same = compareEntryRes.same
76-
reason = compareEntryRes.reason
77-
} else {
78-
state = 'distinct'
79-
same = false
80-
reason = "permission-denied"
81-
}
74+
if (permissionDeniedState === "access-ok") {
75+
const compareEntryRes = EntryEquality.isEntryEqualSync(entry1, entry2, type1, options)
76+
state = compareEntryRes.same ? 'equal' : 'distinct'
77+
same = compareEntryRes.same
78+
reason = compareEntryRes.reason
79+
} else {
80+
state = 'distinct'
81+
same = false
82+
reason = "permission-denied"
83+
}
8284

8385

84-
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, diffSet, reason, permissionDeniedState)
85-
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
86+
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, diffSet, reason, permissionDeniedState)
87+
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
88+
if (type1 === 'directory') {
89+
compareSync(entry1, entry2, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
90+
}
91+
}
8692
i1++
8793
i2++
88-
if (!options.skipSubdirs && type1 === 'directory') {
89-
compareSync(entry1, entry2, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
90-
}
9194
} else if (cmp < 0) {
9295
// Right missing
93-
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
94-
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
95-
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
96-
i1++
97-
if (type1 === 'directory' && !options.skipSubdirs) {
98-
compareSync(entry1, undefined, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
96+
const skipEntry = options.skipSubdirs && type1 === 'directory'
97+
if (!skipEntry) {
98+
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
99+
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
100+
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
101+
if (type1 === 'directory') {
102+
compareSync(entry1, undefined, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
103+
}
99104
}
105+
i1++
100106
} else {
101107
// Left missing
102-
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
103-
options.resultBuilder(undefined, entry2, "right", level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
104-
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
105-
i2++
106-
if (type2 === 'directory' && !options.skipSubdirs) {
107-
compareSync(undefined, entry2, level + 1, pathUtils.join(relativePath, entry2.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
108+
const skipEntry = options.skipSubdirs && type2 === 'directory'
109+
if (!skipEntry) {
110+
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
111+
options.resultBuilder(undefined, entry2, "right", level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
112+
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
113+
if (type2 === 'directory') {
114+
compareSync(undefined, entry2, level + 1, pathUtils.join(relativePath, entry2.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
115+
}
108116
}
117+
i2++
109118
}
110119
}
111120
}

‎test/expected/test006_0.txt

-8
This file was deleted.

‎test/expected/test006_1.txt

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
1-
[/] A10 -> missing (directory)
2-
[/] missing <- A11 (directory)
3-
[/] A6 == A6 (directory)
4-
[/] A7 -> missing (directory)
5-
[/] missing <- A8 (directory)
6-
[/] missing <- A9 (directory)
71
[/] A11 -> missing (file)
82
[/] a1.txt == a1.txt (file)
93
[/] a2.txt <> a2.txt (file)
104
[/] a3.txt -> missing (file)
115
[/] missing <- a4.txt (file)
126
[/] a5.txt -> missing (file)
137
Entries are different
14-
total: 12, equal: 2, distinct: 1, only left: 5, only right: 4
8+
total: 6, equal: 1, distinct: 1, only left: 3, only right: 1

‎test/runTests.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import semver from 'semver'
1111
import { join } from 'path'
1212

1313

14-
// Usage: node runTests [unpacked] [test001_1] [showresult] [skipasync] [noReport]
14+
// Usage: ts-node runTests.ts [unpacked] [test001_1] [showresult] [skipasync] [noReport]
1515
interface RunOptions {
1616
// Use ./testdir instead of testdir.tar as test data.
1717
// Run 'node extract.js' to initialize ./testdir.

‎test/tests.ts

-5
Original file line numberDiff line numberDiff line change
@@ -541,11 +541,6 @@ export function getTests(testDirPath: string): Partial<Test>[] {
541541
////////////////////////////////////////////////////
542542
// Skip subdirs //
543543
////////////////////////////////////////////////////
544-
{
545-
name: 'test006_0', path1: 'd1', path2: 'd2',
546-
options: { compareSize: true, skipSubdirs: true },
547-
displayOptions: { showAll: true, },
548-
},
549544
{
550545
name: 'test006_1', path1: 'd1', path2: 'd2',
551546
options: { compareSize: true, skipSubdirs: true },

0 commit comments

Comments
 (0)
Please sign in to comment.