package org.jboss.fresh.io;
import java.util.*;
import java.util.regex.*;
import java.io.*;
import org.jboss.fresh.naming.CompositeName;
import org.jboss.fresh.io.IOUtils;
public class CompareDirs {
/*
//
// haha*/
int depth=0;
CompositeName root = new CompositeName("/");
List exlist;
Callback cb;
public CompareDirs() {}
public CompareDirs(Collection ls) {
if(ls == null) return;
exlist = new ArrayList();
Iterator it = ls.iterator();
while(it.hasNext()) {
String str = (String) it.next();
exlist.add(Pattern.compile(str));
}
}
public void registerCallback(Callback cb) {
this.cb = cb;
}
/** Compare one single directory */
public HashMap compareDirs(File dir1, File dir2) throws IOException {
String [] dir1ls = dir1.list();
if(dir1ls == null) return new HashMap();
TreeSet srcset=new TreeSet(Arrays.asList(dir1ls));
String [] dir2ls = dir2.list();
if(dir2ls == null) return new HashMap();
TreeSet destset=new TreeSet(Arrays.asList(dir2ls));
//System.out.println("srcSet: " + srcset);
//System.out.println("destSet: " + destset);
int fl;
HashMap chlist=new HashMap();
Collection col=destset; // you get a TreeMap back
Iterator it=col.iterator();
Collection col0=srcset;
Iterator it0=col0.iterator();
String name1, name2;
if(it0.hasNext()) {
name1=(String)it0.next();
} else {
name1=null;
}
if(it.hasNext()) {
name2=(String)it.next();
} else {
name2=null;
}
while (true) {
//System.out.println("*** name1 = " + name1);
//System.out.println("*** name2 = " + name2);
File f1, f2;
if(name1==null) {
if(name2==null)
break; // it's over
else
fl=1;
} else if(name2==null) {
if(name1==null)
break; // it's over
else
fl=-1;
} else {
fl=0;
}
if(fl > 0) {
//System.out.println("**** File added found: " + name2);
// file added
chlist.put(new File(name2).getName(), new FileComparison(FileComparison.NEWFILE));
// read field2
if(it.hasNext()) {
name2=(String)it.next();
} else {
name2=null;
}
} else if(fl < 0) {
//System.out.println("**** File missing found: " + name1);
// file removed
chlist.put(new File(name1).getName(), new FileComparison(FileComparison.FILEMISSING));
// read field1
if(it0.hasNext()) {
name1=(String)it0.next();
} else {
name1=null;
}
} else {
// compare to see if changed
//System.out.println("**** We have both files we must see if they are the same: ");
// if these are 2 different files then we must determine which one is smaller
// we process the smaller one and then read-in the next value from that collection
int same=compareFiles(chlist, new File(dir1, name1), new File(dir2, name2));
// read field1
// read field2
if(same<=0) {
if(it0.hasNext()) {
name1=(String)it0.next();
} else {
name1=null;
}
}
if(same>=0) {
if(it.hasNext()) {
name2=(String)it.next();
} else {
name2=null;
}
}
}
}
//System.out.println("Changes: " + chlist);
return chlist;
}
/** Comparison only works properly if both files exist */
int compareFiles(HashMap chlist, File f1, File f2) throws IOException {
//System.out.println("name1: " + f1);
//System.out.println(" lastModified=" + DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(f1.lastModified())));
//System.out.println(" length=" + f1.length());
//System.out.println("name2: " + f2);
//System.out.println(" lastModified=" + DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(new Date(f2.lastModified())));
//System.out.println(" length=" + f2.length());
FileComparison fc;
int cmp=f1.getName().compareTo(f2.getName());
if(cmp<0) { // means the file is missing
//System.out.println("***** File missing found: " + f1.getName());
chlist.put(f1.getName(), new FileComparison(FileComparison.FILEMISSING | (f1.isDirectory() ? FileComparison.DIRECTORY : 0)));
} else if(cmp>0) { // means file added
//System.out.println("***** File added found: " + f2.getName());
chlist.put(f2.getName(), new FileComparison(FileComparison.NEWFILE | (f2.isDirectory() ? FileComparison.DIRECTORY : 0)));
} else {
if(f1.isDirectory() && f2.isFile()) {
// oznacili bomo NEWFILE in hkrati FILEMISSING - to pomeni, da direktorij s tem imenom manjka
fc=new FileComparison(FileComparison.NEWFILE | FileComparison.FILEMISSING);
// we don't store the whole path
chlist.put(f1.getName(), fc);
} else if(f2.isDirectory() && f1.isFile()) {
// oznacili bomo DIRECTORY, NEWFILE in hkrati FILEMISSING - to pomeni, da file s tem imenom manjka
fc=new FileComparison(FileComparison.DIRECTORY | FileComparison.NEWFILE | FileComparison.FILEMISSING);
// we don't store the whole path
chlist.put(f1.getName(), fc);
} else if(f1.isDirectory()) { // f2 is certainly a directory in this case
// we can set it to DIRECTORY - which means needs to be compared further
chlist.put(f1.getName(), new FileComparison(FileComparison.DIRECTORY));
} else {
//System.out.println("We've got 2 files.");
fc=new FileComparison(0);
//System.out.println("f1.lastMod: " + new Date(f1.lastModified()));
//System.out.println("f2.lastMod: " + new Date(f2.lastModified()));
fc.setCompareLastModified((int)(f2.lastModified()-f1.lastModified()));
//System.out.println("Compare lastMod: " + fc.compareLastModified());
fc.setCompareLength((int)(f2.length()-f1.length()));
// TODO here you check options and depending on them do the appropriate file comparison
// tukaj bi v primeru, da je in eno in drugo enako lahko ce binary comparison naredili, ampak mislim, da bi to bilo insane - to bi gromozansko upocasnilo operacijo
// sample files to determine if they are binaries
if(IOUtils.isBinary(f1) || IOUtils.isBinary(f2)) {
if(IOUtils.calcAdler32(f1) != IOUtils.calcAdler32(f2)) fc.setContentDiff(true);
} else {
FileDiff diff = new FileDiff();
try {
diff.diff(f1, f2);
} catch(IOException ex) {
throw new RuntimeException(ex);
}
List ls = diff.getDiffs();
if(ls.size() > 0) fc.setContentDiff(true);
if((fc.compareLength()!=0) || (fc.compareLastModified()!=0))
chlist.put(f1.getName(), fc);
}
}
}
return cmp;
}
public void indent() {
for(int i=0; i<depth; i++) {
System.out.print(" ");
}
}
public boolean patternMatch(String str) {
if(exlist == null) return false;
Iterator it = exlist.iterator();
while(it.hasNext()) {
Pattern p = (Pattern) it.next();
if(p.matcher(str).matches()) return true;
}
return false;
}
public void processDir(File src, File dest) throws IOException {
String [] srcList=src.list();
String [] destList=dest.list();
/*
indent();
System.out.println("Source dir files:");
indent();
System.out.println("=========");
for(int i=0; i<srcList.length; i++) {
indent();
System.out.println(srcList[i]);
}
indent();
System.out.println("Destination dir files:");
indent();
System.out.println("=========");
for(int i=0; i<destList.length; i++) {
indent();
System.out.println(destList[i]);
}
*/
// non recursive comparison - don't go into subdir. We however can proces return and go
HashMap map=compareDirs(src, dest);
//indent();
// System.out.println("Number of changes: " + map.size());
Collection col=map.entrySet();
Iterator it=col.iterator();
//LinkedList dirList = new LinkedList();
while(it.hasNext()) {
Map.Entry entry=(Map.Entry)it.next();
String fname=(String)entry.getKey();
if(patternMatch(fname)) continue;
//indent();
//System.out.print(root.absolutize(fname));
//System.out.print("\t\t");
StringBuffer head = new StringBuffer();
FileComparison fc=(FileComparison)entry.getValue();
if(fc.isDirectory()) head.append("D");
else head.append(" ");
if(fc.isNew()) {
CompositeName absname = root.absolutize(fname);
head.append("+ ").append(absname);
if(cb!=null) cb.fileAdded(absname, fc);
System.out.println(head);
//System.out.print("+");
//if(fc.isMissing())
// System.out.print("-");
//if(fc.isDirectory()) {
// System.out.println("D");
//} else {
// System.out.println();
//}
} else if(fc.isMissing()) {
//System.out.print("-");
CompositeName absname = root.absolutize(fname);
head.append("- ").append(absname);
if(cb!=null) cb.fileRemoved(absname, fc);
System.out.println(head);
//if(fc.isDirectory()) {
// System.out.println("D");
//} else {
// System.out.println();
//}
} else {
//if(fc.isDirectory())
// System.out.print("D");
CompositeName absname = root.absolutize(fname);
head.append(fc.isContentDiff() ? " C " : " ");
int mod=fc.compareLastModified();
//if(mod<0) System.out.print(" < lastModified ");
//else if(mod>0) System.out.print(" > lastModified ");
//else System.out.print(" = lastModified ");
if(mod<0) head.append(" < lmod ");
else if(mod>0) head.append(" > lmod ");
else head.append(" = lmod ");
boolean ignoreDir = fc.isDirectory() && mod==0;
if(!fc.isDirectory()) {
mod=fc.compareLength();
//if(mod<0) System.out.print(" < length ");
//else if(mod>0) System.out.print(" > length ");
//else System.out.print(" = length ");
if(mod<0) head.append(" < len ");
else if(mod>0) head.append(" > len ");
else head.append(" = len ");
}
if(!ignoreDir) {
head.append(absname);
if(cb!=null) cb.fileChanged(absname, fc);
System.out.println(head);
}
depth++;
if(fc.isDirectory()) {
root = absname;
processDir(new File(src, fname), new File(dest, fname));
root = root.absolutize("..");
//dirList.add(fname);
}
depth--;
}
}
// process subdirectories
/*
it = dirList.iterator();
while(it.hasNext()) {
String fname = (String) it.next();
root = root.absolutize(fname);
processDir(new File(src, fname), new File(dest, fname));
root = root.absolutize("..");
}
*/
}
public static void main(String [] args) throws IOException {
if(args.length!=2) {
System.out.println("Usage: java compare <path1> <path2>");
System.exit(1);
}
File src=new File(args[0]);
File dest=new File(args[1]);
if(!src.isDirectory()) {
System.out.println("Source directory does not exist: " + src.toString());
System.exit(2);
}
if(!dest.isDirectory()) {
System.out.println("Destination directory does not exist: " + src.toString());
System.exit(3);
}
if(src.equals(dest)) {
System.out.println("Destination directory and source directory can not be the same.");
System.exit(3);
}
// process one dir
List excludeList = new LinkedList();
File xlf = new File("excludelist.ini");
if(xlf.isFile()) {
BufferedReader br = new BufferedReader(new FileReader(xlf));
String line = br.readLine();
while(line!=null) {
excludeList.add(line);
line = br.readLine();
}
}
// now compare
new CompareDirs(excludeList).processDir(src, dest);
}
public interface Callback {
public void fileAdded(CompositeName name, FileComparison fc);
public void fileRemoved(CompositeName name, FileComparison fc);
public void fileChanged(CompositeName name, FileComparison fc);
}
}