Skip to content

Commit

Permalink
Correct skipSubdirs option #77
Browse files Browse the repository at this point in the history
  • Loading branch information
gliviu committed May 4, 2024
1 parent e144d80 commit 01e0132
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 102 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ The [default](https://github.com/gliviu/dir-compare/blob/master/src/ResultBuilde
* [Visual Studio Code - Compare Folders](https://marketplace.visualstudio.com/items?itemName=moshfeu.compare-folders)

# Changelog
* v5.0.0
Breaking changes:
* `skipSubdirs` option has slightly different behavior. More details in [#77](https://github.com/gliviu/dir-compare/issues/77#issuecomment-2094375352)
* v4.2.0
* Updated dependencies
* Increased test coverage
Expand Down
1 change: 1 addition & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ image:

environment:
matrix:
- nodejs_version: 21
- nodejs_version: 20
- nodejs_version: 19
- nodejs_version: 18
Expand Down
112 changes: 60 additions & 52 deletions src/compareAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,72 +84,80 @@ export function compareAsync(rootEntry1: OptionalEntry, rootEntry2: OptionalEntr
// process entry
if (cmp === 0) {
// Both left/right exist and have the same name and type
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)
const skipEntry = options.skipSubdirs && type1 === 'directory'
if (!skipEntry) {
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)

if (permissionDeniedState === "access-ok") {
const compareEntryRes = EntryEquality.isEntryEqualAsync(entry1, entry2, type1, asyncDiffSet, options)
if (compareEntryRes.isSync) {
options.resultBuilder(entry1, entry2,
compareEntryRes.same ? 'equal' : 'distinct',
level, relativePath, options, statistics, asyncDiffSet as DiffSet,
compareEntryRes.reason, permissionDeniedState)
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, compareEntryRes.same, compareEntryRes.reason,
type1, permissionDeniedState, statistics, options)
if (permissionDeniedState === "access-ok") {
const compareEntryRes = EntryEquality.isEntryEqualAsync(entry1, entry2, type1, asyncDiffSet, options)
if (compareEntryRes.isSync) {
options.resultBuilder(entry1, entry2,
compareEntryRes.same ? 'equal' : 'distinct',
level, relativePath, options, statistics, asyncDiffSet as DiffSet,
compareEntryRes.reason, permissionDeniedState)
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, compareEntryRes.same, compareEntryRes.reason,
type1, permissionDeniedState, statistics, options)
} else {
fileEqualityAsyncPromises.push(compareEntryRes.fileEqualityAsyncPromise)
}
} else {
fileEqualityAsyncPromises.push(compareEntryRes.fileEqualityAsyncPromise)
const state = 'distinct'
const reason = "permission-denied"
const same = false
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, asyncDiffSet as DiffSet, reason, permissionDeniedState)
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
}
if (type1 === 'directory') {
const subDiffSet: AsyncDiffSet = []
if (!options.noDiffSet) {
asyncDiffSet.push(subDiffSet)
}
const comparePromise = limit(() => compareAsync(entry1, entry2, level + 1,
pathUtils.join(relativePath, entry1.name),
options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
comparePromises.push(comparePromise)
}
} else {
const state = 'distinct'
const reason = "permission-denied"
const same = false
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, asyncDiffSet as DiffSet, reason, permissionDeniedState)
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
}

i1++
i2++
if (!options.skipSubdirs && type1 === 'directory') {
const subDiffSet: AsyncDiffSet = []
if (!options.noDiffSet) {
asyncDiffSet.push(subDiffSet)
}
const comparePromise = limit(() => compareAsync(entry1, entry2, level + 1,
pathUtils.join(relativePath, entry1.name),
options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
comparePromises.push(comparePromise)
}
} else if (cmp < 0) {
// Right missing
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
i1++
if (type1 === 'directory' && !options.skipSubdirs) {
const subDiffSet: AsyncDiffSet = []
if (!options.noDiffSet) {
asyncDiffSet.push(subDiffSet)
const skipEntry = options.skipSubdirs && type1 === 'directory'
if (!skipEntry) {
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
if (type1 === 'directory') {
const subDiffSet: AsyncDiffSet = []
if (!options.noDiffSet) {
asyncDiffSet.push(subDiffSet)
}
const comparePromise = limit(() => compareAsync(entry1, undefined,
level + 1,
pathUtils.join(relativePath, entry1.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
comparePromises.push(comparePromise)
}
const comparePromise = limit(() => compareAsync(entry1, undefined,
level + 1,
pathUtils.join(relativePath, entry1.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
comparePromises.push(comparePromise)
}
i1++
} else {
// Left missing
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
i2++
if (type2 === 'directory' && !options.skipSubdirs) {
const subDiffSet: AsyncDiffSet = []
if (!options.noDiffSet) {
asyncDiffSet.push(subDiffSet)
const skipEntry = options.skipSubdirs && type2 === 'directory'
if (!skipEntry) {
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
options.resultBuilder(undefined, entry2, 'right', level, relativePath, options, statistics, asyncDiffSet as DiffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
if (type2 === 'directory') {
const subDiffSet: AsyncDiffSet = []
if (!options.noDiffSet) {
asyncDiffSet.push(subDiffSet)
}
const comparePromise = limit(() => compareAsync(undefined, entry2,
level + 1,
pathUtils.join(relativePath, entry2.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
comparePromises.push(comparePromise)
}
const comparePromise = limit(() => compareAsync(undefined, entry2,
level + 1,
pathUtils.join(relativePath, entry2.name), options, statistics, subDiffSet, LoopDetector.cloneSymlinkCache(symlinkCache)))
comparePromises.push(comparePromise)
}
i2++
}
}
return Promise.all(comparePromises)
Expand Down
67 changes: 38 additions & 29 deletions src/compareSync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,46 +66,55 @@ export function compareSync(rootEntry1: OptionalEntry, rootEntry2: OptionalEntry
// process entry
if (cmp === 0) {
// Both left/right exist and have the same name and type
let same, reason, state
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)
const skipEntry = options.skipSubdirs && type1 === 'directory'
if (!skipEntry) {
let same, reason, state
const permissionDeniedState = Permission.getPermissionDeniedState(entry1, entry2)

if (permissionDeniedState === "access-ok") {
const compareEntryRes = EntryEquality.isEntryEqualSync(entry1, entry2, type1, options)
state = compareEntryRes.same ? 'equal' : 'distinct'
same = compareEntryRes.same
reason = compareEntryRes.reason
} else {
state = 'distinct'
same = false
reason = "permission-denied"
}
if (permissionDeniedState === "access-ok") {
const compareEntryRes = EntryEquality.isEntryEqualSync(entry1, entry2, type1, options)
state = compareEntryRes.same ? 'equal' : 'distinct'
same = compareEntryRes.same
reason = compareEntryRes.reason
} else {
state = 'distinct'
same = false
reason = "permission-denied"
}


options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, diffSet, reason, permissionDeniedState)
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
options.resultBuilder(entry1, entry2, state, level, relativePath, options, statistics, diffSet, reason, permissionDeniedState)
StatisticsUpdate.updateStatisticsBoth(entry1, entry2, same, reason, type1, permissionDeniedState, statistics, options)
if (type1 === 'directory') {
compareSync(entry1, entry2, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
}
}
i1++
i2++
if (!options.skipSubdirs && type1 === 'directory') {
compareSync(entry1, entry2, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
}
} else if (cmp < 0) {
// Right missing
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
i1++
if (type1 === 'directory' && !options.skipSubdirs) {
compareSync(entry1, undefined, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
const skipEntry = options.skipSubdirs && type1 === 'directory'
if (!skipEntry) {
const permissionDeniedState = Permission.getPermissionDeniedStateWhenRightMissing(entry1)
options.resultBuilder(entry1, undefined, 'left', level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsLeft(entry1, type1, permissionDeniedState, statistics, options)
if (type1 === 'directory') {
compareSync(entry1, undefined, level + 1, pathUtils.join(relativePath, entry1.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
}
}
i1++
} else {
// Left missing
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
options.resultBuilder(undefined, entry2, "right", level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
i2++
if (type2 === 'directory' && !options.skipSubdirs) {
compareSync(undefined, entry2, level + 1, pathUtils.join(relativePath, entry2.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
const skipEntry = options.skipSubdirs && type2 === 'directory'
if (!skipEntry) {
const permissionDeniedState = Permission.getPermissionDeniedStateWhenLeftMissing(entry2)
options.resultBuilder(undefined, entry2, "right", level, relativePath, options, statistics, diffSet, undefined, permissionDeniedState)
StatisticsUpdate.updateStatisticsRight(entry2, type2, permissionDeniedState, statistics, options)
if (type2 === 'directory') {
compareSync(undefined, entry2, level + 1, pathUtils.join(relativePath, entry2.name), options, statistics, diffSet, LoopDetector.cloneSymlinkCache(symlinkCache))
}
}
i2++
}
}
}
Expand Down
8 changes: 0 additions & 8 deletions test/expected/test006_0.txt

This file was deleted.

8 changes: 1 addition & 7 deletions test/expected/test006_1.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
[/] A10 -> missing (directory)
[/] missing <- A11 (directory)
[/] A6 == A6 (directory)
[/] A7 -> missing (directory)
[/] missing <- A8 (directory)
[/] missing <- A9 (directory)
[/] A11 -> missing (file)
[/] a1.txt == a1.txt (file)
[/] a2.txt <> a2.txt (file)
[/] a3.txt -> missing (file)
[/] missing <- a4.txt (file)
[/] a5.txt -> missing (file)
Entries are different
total: 12, equal: 2, distinct: 1, only left: 5, only right: 4
total: 6, equal: 1, distinct: 1, only left: 3, only right: 1
2 changes: 1 addition & 1 deletion test/runTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import semver from 'semver'
import { join } from 'path'


// Usage: node runTests [unpacked] [test001_1] [showresult] [skipasync] [noReport]
// Usage: ts-node runTests.ts [unpacked] [test001_1] [showresult] [skipasync] [noReport]
interface RunOptions {
// Use ./testdir instead of testdir.tar as test data.
// Run 'node extract.js' to initialize ./testdir.
Expand Down
5 changes: 0 additions & 5 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,11 +541,6 @@ export function getTests(testDirPath: string): Partial<Test>[] {
////////////////////////////////////////////////////
// Skip subdirs //
////////////////////////////////////////////////////
{
name: 'test006_0', path1: 'd1', path2: 'd2',
options: { compareSize: true, skipSubdirs: true },
displayOptions: { showAll: true, },
},
{
name: 'test006_1', path1: 'd1', path2: 'd2',
options: { compareSize: true, skipSubdirs: true },
Expand Down

0 comments on commit 01e0132

Please sign in to comment.