/* JMeld is a visual diff and merge tool. Copyright (C) 2007 Kees Kuip This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.jmeld.util.file; import org.apache.jmeld.tools.ant.*; import org.jmeld.settings.*; import org.jmeld.settings.util.*; import org.jmeld.ui.*; import org.jmeld.util.*; import org.jmeld.util.node.*; import org.jmeld.vc.util.VcCmd; import java.io.*; import java.util.*; public class DirectoryDiff extends FolderDiff { private File rightDirectory; private File leftDirectory; private JMDiffNode rootNode; private Map<String, JMDiffNode> nodes; private Filter filter; public DirectoryDiff(File leftDirectory, File rightDirectory, Filter filter, Mode mode) { super(mode); this.leftDirectory = leftDirectory; this.rightDirectory = rightDirectory; this.filter = filter; try { setLeftFolderShortName(leftDirectory.getName()); setRightFolderShortName(rightDirectory.getName()); setLeftFolderName(leftDirectory.getCanonicalPath()); setRightFolderName(rightDirectory.getCanonicalPath()); } catch (Exception ex) { ex.printStackTrace(); } } public JMDiffNode getRootNode() { return rootNode; } public Collection<JMDiffNode> getNodes() { return nodes.values(); } public void diff() { DirectoryScanner ds; JMDiffNode node; StopWatch stopWatch; int numberOfNodes; int currentNumber; FileNode fn; stopWatch = new StopWatch(); stopWatch.start(); StatusBar.getInstance().start(); StatusBar.getInstance().setState("Start scanning directories..."); rootNode = new JMDiffNode("<root>", false); nodes = new HashMap<String, JMDiffNode>(); ds = new DirectoryScanner(); ds.setShowStateOn(true); ds.setBasedir(leftDirectory); if (filter != null) { ds.setIncludes(filter.getIncludes()); ds.setExcludes(filter.getExcludes()); } ds.setCaseSensitive(true); ds.scan(); for (FileNode fileNode : ds.getIncludedFilesMap().values()) { node = addNode(fileNode.getName()); node.setBufferNodeLeft(fileNode); } ds = new DirectoryScanner(); ds.setShowStateOn(true); ds.setBasedir(rightDirectory); if (filter != null) { ds.setIncludes(filter.getIncludes()); ds.setExcludes(filter.getExcludes()); } ds.setCaseSensitive(true); ds.scan(); for (FileNode fileNode : ds.getIncludedFilesMap().values()) { node = addNode(fileNode.getName()); node.setBufferNodeRight(fileNode); } StatusBar.getInstance().setState("Comparing nodes..."); numberOfNodes = nodes.size(); currentNumber = 0; for (JMDiffNode n : nodes.values()) { // Make sure that each node has it's opposite. // This makes the following copying actions possible : // - copy 'left' to 'not existing' // - copy 'right' to 'not existing' if (n.getBufferNodeRight() == null || n.getBufferNodeLeft() == null) { if (n.getBufferNodeRight() == null) { fn = (FileNode) n.getBufferNodeLeft(); fn = new FileNode(fn.getName(), new File(rightDirectory, fn.getName())); n.setBufferNodeRight(fn); } else { fn = (FileNode) n.getBufferNodeRight(); fn = new FileNode(fn.getName(), new File(leftDirectory, fn.getName())); n.setBufferNodeLeft(fn); } } n.compareContents(); StatusBar.getInstance().setProgress(++currentNumber, numberOfNodes); } StatusBar.getInstance().setState( "Ready comparing directories (took " + (stopWatch.getElapsedTime() / 1000) + " seconds)"); StatusBar.getInstance().stop(); } private JMDiffNode addNode(String name) { JMDiffNode node; node = nodes.get(name); if (node == null) { node = addNode(new JMDiffNode(name, true)); } return node; } private JMDiffNode addNode(JMDiffNode node) { String parentName; JMDiffNode parent; File file; nodes.put(node.getName(), node); parentName = node.getParentName(); if (StringUtil.isEmpty(parentName)) { parent = rootNode; } else { parent = nodes.get(parentName); if (parent == null) { parent = addNode(new JMDiffNode(parentName, false)); parent.setBufferNodeRight(new FileNode(parentName, new File( rightDirectory, parentName))); parent.setBufferNodeLeft(new FileNode(parentName, new File( leftDirectory, parentName))); } } parent.addChild(node); return node; } public void print() { rootNode.print(""); } public static void main(String[] args) { DirectoryDiff diff; StopWatch stopWatch; File file = parseDirectory(args, 0); if (file == null) { return; } File file2 = parseDirectory(args, 1); if (file2 == null) { return; } diff = new DirectoryDiff(file, file2, JMeldSettings.getInstance().getFilter().getFilter("default"), DirectoryDiff.Mode.TWO_WAY); stopWatch = new StopWatch(); stopWatch.start(); diff.diff(); System.out.println("diff took " + stopWatch.getElapsedTime() + " msec."); diff.print(); } private static File parseDirectory(String[] args, int pos) { File file = VcCmd.parseFile(args, pos); if (file == null) { return null; } if (!file.isDirectory()) { System.err.println(file.getName()+" is not a directory"); return null; } return file; } }