|
|
|
@ -8,9 +8,9 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
|
|
|
|
|
|
|
|
|
public class TreeDiff {
|
|
|
|
|
|
|
|
|
|
public static final String VERSION = "1.0";
|
|
|
|
|
public static final String VERSION = "1.1";
|
|
|
|
|
|
|
|
|
|
private ObjectMapper objectMapper
|
|
|
|
|
private static ObjectMapper objectMapper = new ObjectMapper()
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
|
|
|
@ -18,8 +18,8 @@ public class TreeDiff {
|
|
|
|
|
'h': [longName: 'help'],
|
|
|
|
|
'v': [longName: 'version'],
|
|
|
|
|
'g': [longName: 'gui'],
|
|
|
|
|
'i': [longName: 'analysis-in'],
|
|
|
|
|
'o': [longName: 'analysis-out'],
|
|
|
|
|
'i': [longName: 'analysis-in', arguments: 2],
|
|
|
|
|
'o': [longName: 'analysis-out', arguments: 1],
|
|
|
|
|
's': [longName: 'same'],
|
|
|
|
|
'S': [longName: 'exclude-same'],
|
|
|
|
|
'c': [longName: 'content-mismatch'],
|
|
|
|
@ -30,6 +30,7 @@ public class TreeDiff {
|
|
|
|
|
'L': [longName: 'exclude-left-only'],
|
|
|
|
|
'r': [longName: 'right-only'],
|
|
|
|
|
'R': [longName: 'exclude-right-only'],
|
|
|
|
|
'q': [longName: 'quiet'],
|
|
|
|
|
'rd': [longName: 'directory', arguments: 1]
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
@ -47,11 +48,16 @@ public class TreeDiff {
|
|
|
|
|
|
|
|
|
|
public static void cli(def opts) {
|
|
|
|
|
|
|
|
|
|
File rootDir, leftFile, rightFile
|
|
|
|
|
|
|
|
|
|
if (opts.rd) rootDir = new File(opts.rd[0] ?: '.')
|
|
|
|
|
else rootDir = new File('.')
|
|
|
|
|
|
|
|
|
|
def show = [ same: false, content: false, path: false,
|
|
|
|
|
left: false, right: false]
|
|
|
|
|
|
|
|
|
|
// If none of the explicit selectors are given, assume all are expeced.
|
|
|
|
|
if (!opts.s && !opts.c && !opts.p && !opts.l && !opts.r) {
|
|
|
|
|
if (!opts.s && !opts.c && !opts.p && !opts.l && !opts.r && !opts.q) {
|
|
|
|
|
show = [ same: true, content: true, path: true,
|
|
|
|
|
left: true, right: true] }
|
|
|
|
|
|
|
|
|
@ -61,33 +67,34 @@ public class TreeDiff {
|
|
|
|
|
if (opts.l) show.left = true; if (opts.L) show.left = false
|
|
|
|
|
if (opts.r) show.right = true; if (opts.R) show.right = false
|
|
|
|
|
|
|
|
|
|
if (opts.args.size() < 2) {
|
|
|
|
|
/* TODO: print usage */
|
|
|
|
|
println "TreeDiff v${VERSION}: exactly two directory paths are required to compare."
|
|
|
|
|
System.exit(1) }
|
|
|
|
|
DirAnalysis left, right;
|
|
|
|
|
|
|
|
|
|
if (opts.i) {
|
|
|
|
|
leftFile = resolvePath(opts.i[0], rootDir)
|
|
|
|
|
rightFile = resolvePath(opts.i[1], rootDir)
|
|
|
|
|
left = objectMapper.readValue(leftFile, DirAnalysis)
|
|
|
|
|
right = objectMapper.readValue(rightFile, DirAnalysis)
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
File rootDir, leftDir, rightDir
|
|
|
|
|
if (opts.args.size() < 2) {
|
|
|
|
|
/* TODO: print usage */
|
|
|
|
|
println "TreeDiff v${VERSION}: exactly two directory paths are required to compare."
|
|
|
|
|
System.exit(1) }
|
|
|
|
|
|
|
|
|
|
if (opts.rd) rootDir = new File(opts.rd[0] ?: '.')
|
|
|
|
|
else rootDir = new File('.')
|
|
|
|
|
leftFile = resolvePath(opts.args[0], rootDir)
|
|
|
|
|
rightFile = resolvePath(opts.args[0], rootDir)
|
|
|
|
|
|
|
|
|
|
if (opts.args[0].startsWith('/')) leftDir = new File(opts.args[0])
|
|
|
|
|
else leftDir = new File(rootDir, opts.args[0])
|
|
|
|
|
if (!leftFile.isDirectory()) {
|
|
|
|
|
println "TreeDiff v${VERSION}: '${opts.args[1]}' is not a directory"
|
|
|
|
|
System.exit(2) }
|
|
|
|
|
|
|
|
|
|
if (opts.args[1].startsWith('/')) rightDir = new File(opts.args[1])
|
|
|
|
|
else rightDir = new File(rootDir, opts.args[1])
|
|
|
|
|
if (!rightFile.isDirectory()) {
|
|
|
|
|
println "TreeDiff v${VERSION}: '${opts.args[1]}' is not a directory"
|
|
|
|
|
System.exit(2) }
|
|
|
|
|
|
|
|
|
|
if (!leftDir.exists() || !leftDir.isDirectory()) {
|
|
|
|
|
println "TreeDiff v${VERSION}: '${opts.args[0]}' cannot be found or is not a directory"
|
|
|
|
|
System.exit(2) }
|
|
|
|
|
left = analyzeDir(leftFile)
|
|
|
|
|
right = analyzeDir(rightFile) }
|
|
|
|
|
|
|
|
|
|
if (!rightDir.exists() || !rightDir.isDirectory()) {
|
|
|
|
|
println "TreeDiff v${VERSION}: '${opts.args[1]}' cannot be found or is not a directory"
|
|
|
|
|
System.exit(2) }
|
|
|
|
|
|
|
|
|
|
DirAnalysis left = analyzeDir(leftDir)
|
|
|
|
|
DirAnalysis right = analyzeDir(rightDir)
|
|
|
|
|
|
|
|
|
|
if (show.same) same(left, right).each {
|
|
|
|
|
println "same: ${it.relativePath}" }
|
|
|
|
@ -104,6 +111,19 @@ public class TreeDiff {
|
|
|
|
|
if (show.right) firstSideOnly(right, left).each {
|
|
|
|
|
println "right only: ${it.relativePath}" }
|
|
|
|
|
|
|
|
|
|
if (opts.o) {
|
|
|
|
|
String rootName = opts.o[0]
|
|
|
|
|
File leftOut, rightOut
|
|
|
|
|
|
|
|
|
|
if (rootName.startsWith('/')) leftOut = new File(rootName + '.left')
|
|
|
|
|
else leftOut = new File(rootDir, rootName + '.left')
|
|
|
|
|
|
|
|
|
|
if (rootName.startsWith('/')) rightOut = new File(rootName + '.right')
|
|
|
|
|
else rightOut = new File(rootDir, rootName + '.right')
|
|
|
|
|
|
|
|
|
|
objectMapper.writeValue(leftOut, left)
|
|
|
|
|
objectMapper.writeValue(rightOut, right)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static gui(def opts) {
|
|
|
|
@ -182,4 +202,15 @@ public class TreeDiff {
|
|
|
|
|
if (b != parentPath.length) return ""
|
|
|
|
|
return (['.'] + childPath[b..<childPath.length]).join('/') }
|
|
|
|
|
|
|
|
|
|
public static File resolvePath(String path, File rootDir) {
|
|
|
|
|
File f
|
|
|
|
|
if (path.startsWith('/')) f = new File(path)
|
|
|
|
|
else f = new File(rootDir, path)
|
|
|
|
|
|
|
|
|
|
if (!f.exists()) {
|
|
|
|
|
println "TreeDiff v${VERSION}: '${f.canonicalPath}' cannot be found"
|
|
|
|
|
System.exit(2) }
|
|
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|