// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/util/wanderer/OneWaySync.java,v $ // $RCSfile: OneWaySync.java,v $ // $Revision: 1.3 $ // $Date: 2005/08/09 18:41:09 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.util.wanderer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Iterator; import java.util.LinkedList; import java.util.logging.Level; import java.util.logging.Logger; import com.bbn.openmap.util.ArgParser; /** * The OneWaySync is a class that copies files from one directory to another, * skipping specified extensions or only copying files and directories with * specified extensions. It's used by the OpenMap team to keep the internal CVS * tree in sync with the external one. The main() function has the avoid/limit * suffixes hard-coded, you can extend or change the settings in a different * class. */ public class OneWaySync extends Wanderer implements WandererCallback { /** The source directory. */ protected File src; /** The target directory. */ protected File tgt; /** The suffixes to skip over for directories. */ public String[] dirSuffixAvoids = null; /** The suffixes to skip over for files. */ public String[] fileSuffixAvoids = null; /** The suffixes to limit copying to for directories. */ public String[] dirSuffixLimits = null; /** The suffixes to limit copying to for files. */ public String[] fileSuffixLimits = null; /** The list of stuff skipped over. */ protected LinkedList<File> notCopiedList = new LinkedList<File>(); /** Flag for printing out activities. */ protected boolean verbose = false; /** Flag for not doing the changes, just saying what would happen. */ protected boolean fakeit = false; /** Flag to not have files that exist overwritten. */ protected boolean overwrite = true; public OneWaySync(String srcDirName, String targetDirName) { super(); setCallback(this); src = new File(srcDirName); tgt = new File(targetDirName); } /** * Check to see if a source directory name should be skipped, based on the * avoid and limit list. */ protected boolean checkToSkipDirectory(String name) { if (dirSuffixAvoids != null) { for (int i = 0; i < dirSuffixAvoids.length; i++) { if (name.endsWith(dirSuffixAvoids[i])) { // Was on avoid list, skip it. return true; } } } if (dirSuffixLimits != null) { for (int i = 0; i < dirSuffixLimits.length; i++) { if (name.endsWith(dirSuffixLimits[i])) { return false; } } // Wasn't on limit list, skip it. return true; } return false; } /** * Check to see if a source file name should be skipped, based on the avoid * and limit list. */ protected boolean checkToSkipFile(String name) { if (fileSuffixAvoids != null) { for (int i = 0; i < fileSuffixAvoids.length; i++) { if (name.endsWith(fileSuffixAvoids[i])) { // Was on avoid list, skip it. return true; } } } if (fileSuffixLimits != null) { for (int i = 0; i < fileSuffixLimits.length; i++) { if (name.endsWith(fileSuffixLimits[i])) { return false; } } // Wasn't on limit list, skip it. return true; } return false; } /** * Wanderer method handing directories. */ public boolean handleDirectory(File directory, String[] contentNames) { String newDirName = getRelativePathFromSource(directory); if (newDirName == null) { if (directory != src) { notCopiedList.add(directory); } super.handleDirectory(directory, contentNames); return true; } if (!checkToSkipDirectory(newDirName)) { File newDir = getTargetFile(newDirName); if (!newDir.exists()) { if (verbose) { getLogger().info("Creating " + newDir); } if (!fakeit && overwrite) newDir.mkdir(); } super.handleDirectory(directory, contentNames); } else { notCopiedList.add(directory); } return true; } /** * WandererCallback method handing directories, not used. */ public boolean handleDirectory(File file) { return true; } /** * WandererCallback method handing files, check and copy those that fit the * avoid and limit parameters. */ public boolean handleFile(File file) { String newFileName = getRelativePathFromSource(file); if (!checkToSkipFile(newFileName)) { File newFile = getTargetFile(newFileName); if (verbose) { getLogger().info("Copying " + file + " to " + newFile); } if (!fakeit && overwrite) copy(file, newFile); } else { notCopiedList.add(file); } return true; } /** * Copy files. */ public void copy(File fromFile, File toFile) { try { FileInputStream fis = new FileInputStream(fromFile); FileOutputStream fos = new FileOutputStream(toFile); int num = 0; byte[] stuff = new byte[4096]; while ((num = fis.read(stuff)) > 0) { fos.write(stuff, 0, num); } fis.close(); fos.close(); } catch (IOException ioe) { getLogger().warning("Exception reading from " + fromFile + " and writing to " + toFile); } } /** * Strip the source directory part of the path from the file, return what * remains. */ public String getRelativePathFromSource(File file) { return subtractPathFromDirectory(src, file); } /** * Strip the target directory part of the path from the file, return what * remains. */ public String getRelativePathFromTarget(File file) { return subtractPathFromDirectory(tgt, file); } /** * Tack the file path onto the source directory. */ public File getSourceFile(String relativePath) { return new File(src, relativePath); } /** * Tack the file path onto the target directory. */ public File getTargetFile(String relativePath) { return new File(tgt, relativePath); } /** * Print out the files/directories not copied. */ public void writeUnsynched() { for (Iterator<File> it = notCopiedList.iterator(); it.hasNext();) { getLogger().info(" " + it.next()); } } /** * Create a BackCheck object that looks to see what files are in the target * but not in the source. */ public void checkTargetSolos() { new BackCheck(tgt.getPath(), src.getPath()); } /** * Take the source directory out of the path to the directory. */ protected String subtractPathFromDirectory(File dir, File file) { String name = file.getPath(); String dirName = dir.getPath(); if (name.equals(dirName)) { if (verbose) { getLogger().info("OneWaySync avoiding subtraction operation on top-level directory"); } return null; } int index = name.indexOf(dirName); if (index != -1) { try { String relative = name.substring(index + dirName.length() + 1); if (verbose) { getLogger().info("From " + file + ", returning " + relative); } return relative; } catch (StringIndexOutOfBoundsException sioobe) { getLogger().warning("Problem clipping first " + (dirName.length() + 1) + " characters off " + file); return null; } } else { getLogger().warning("File " + file + " is not in directory " + dir); return null; } } /** * Start copying files from the source directory to the target directory. */ public void start() { String errorMessage = null; if (src == null) { errorMessage = "OneWaySync: Source directory unspecified"; } else if (!src.exists()) { errorMessage = "OneWaySync: Source directory (" + src + ") doesn't exist!"; } if (tgt != null) { if (!tgt.exists()) { if (verbose) { getLogger().info("OneWaySync: target directory (" + tgt + ") doesn't exist, creating..."); } try { if (!fakeit && !tgt.mkdir()) { errorMessage = "OneWaySync: target directory (" + tgt + ") can't be created."; } } catch (SecurityException se) { errorMessage = "OneWaySync: creating target directory (" + tgt + ") isn't allowed, Security Exception: " + se.getMessage(); se.printStackTrace(); } } } else { errorMessage = "OneWaySync: target directory unspecified"; } if (errorMessage != null) { getLogger().warning(errorMessage); System.exit(0); } handleEntry(src); } public void setVerbose(boolean val) { verbose = val; } public boolean getVerbose() { return verbose; } public void setFakeit(boolean val) { fakeit = val; } public boolean getFakeit() { return fakeit; } public void setDirSuffixAvoids(String[] avoids) { dirSuffixAvoids = avoids; } public void setFileSuffixAvoids(String[] avoids) { fileSuffixAvoids = avoids; } public void setDirSuffixLimits(String[] limits) { dirSuffixLimits = limits; } public void setFileSuffixLimits(String[] limits) { fileSuffixLimits = limits; } // <editor-fold defaultstate="collapsed" desc="Logger Code"> /** * Holder for this class's Logger. This allows for lazy initialization of * the logger. */ private static final class LoggerHolder { /** * The logger for this class */ private static final Logger LOGGER = Logger.getLogger(OneWaySync.class.getName()); /** * Prevent instantiation */ private LoggerHolder() { throw new AssertionError("The LoggerHolder should never be instantiated"); } } /** * Get the logger for this class. * * @return logger for this class */ private static Logger getLogger() { return LoggerHolder.LOGGER; } // </editor-fold> /** */ public static void main(String[] argv) { ArgParser ap = new ArgParser("OneWaySync"); ap.add("source", "The source directory to copy files and directories from.", 1); ap.add("target", "The target directory to receive the updated files and directories.", 1); ap.add("verbose", "Announce all changes, failures will still be reported."); ap.add("fakeit", "Just print what would happen, don't really do anything."); ap.add("report", "Print out what didn't get copied, and what files exist only on the target side."); if (argv.length < 4) { ap.bail("", true); } ap.parse(argv); boolean verbose = false; String[] verb = ap.getArgValues("verbose"); if (verb != null) { verbose = true; } boolean fakeit = false; verb = ap.getArgValues("fakeit"); if (verb != null) { verbose = true; fakeit = true; } boolean report = false; verb = ap.getArgValues("report"); if (verb != null) { report = true; } String[] sourceDir; sourceDir = ap.getArgValues("source"); if (sourceDir != null && sourceDir.length >= 1) { if (verbose) { getLogger().info("Source directory is " + sourceDir[0]); } } else { ap.bail("OneWaySync needs path to source directory", false); } String[] targetDir; targetDir = ap.getArgValues("target"); if (targetDir != null && targetDir.length >= 1) { if (verbose) { getLogger().info("Target directory is " + targetDir[0]); } } else { ap.bail("OneWaySync needs path to source directory", false); } // Should be 'since' instead of 'if' if (sourceDir != null && targetDir != null) { OneWaySync cc = new OneWaySync(sourceDir[0], targetDir[0]); cc.setVerbose(verbose); cc.setFakeit(fakeit); cc.setDirSuffixAvoids(new String[] { "CVS" }); cc.setFileSuffixLimits(new String[] { ".java", "Makefile", ".cvsignore", ".html", ".properties", ".txt", ".c", ".h", ".png" }); cc.start(); if (report) { getLogger().info("-------- Not Copied --------"); cc.writeUnsynched(); getLogger().info("----------------------------"); cc.checkTargetSolos(); } } } public static class BackCheck extends OneWaySync { public BackCheck(String targetDirName, String srcDirName) { super(targetDirName, srcDirName); fakeit = true; overwrite = false; if (getLogger().isLoggable(Level.FINE)) { verbose = true; } start(); getLogger().info("-------- Only In Target Directory--------"); writeUnsynched(); getLogger().info("-----------------------------------------"); } public boolean handleDirectory(File directory, String[] contentNames) { String newDirName = getRelativePathFromSource(directory); if (newDirName == null) { return super.handleDirectory(directory, contentNames); } File newDir = getTargetFile(newDirName); if (!newDir.exists()) { notCopiedList.add(directory); } return super.handleDirectory(directory, contentNames); } public boolean handleFile(File file) { if (!getTargetFile(getRelativePathFromSource(file)).exists()) { notCopiedList.add(file); } return true; } } }