Index: lutinutil/src/java/org/codelutin/vcs/VCSState.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSState.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSState.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,155 @@ +package org.codelutin.vcs; + +import org.codelutin.i18n.I18n; +import static org.codelutin.vcs.VCSAction.ADD; +import static org.codelutin.vcs.VCSAction.CHANGELOG; +import static org.codelutin.vcs.VCSAction.COMMIT; +import static org.codelutin.vcs.VCSAction.DELETE; +import static org.codelutin.vcs.VCSAction.DIFF; +import static org.codelutin.vcs.VCSAction.OVERWRITE_AND_UPDATE; +import static org.codelutin.vcs.VCSAction.REVERT; +import static org.codelutin.vcs.VCSAction.UPDATE; + +/** + * This constants represents all states for a file. + * Should contains all static data concerning file state (libelle, actions, + * icon link, color,...). + * We associate for each state, all VCSActions authorized for this state. + */ +public enum VCSState { + + /** + * when a local file matches the latest remote copy. + *
+ * The only action for this state is to delete the file, nothing else. + */ + UP_TO_DATE("uptodate", I18n._("lutinutil.vcs.state.uptodate"), DELETE), + + /** + * when a local file matches a remote copy but not the latest one. + *
+ * This state owns 3 actions : + * + */ + OUT_OF_DATE("outofdate", I18n._("lutinutil.vcs.state.outofdate"), + UPDATE, DIFF, CHANGELOG), + + /** + * when a local file does not matches his remote latest copy, but is based + * on. + * This state owns 4 actions : + * + */ + MODIFIED("modified", I18n._("lutinutil.vcs.state.modified"), + COMMIT, OVERWRITE_AND_UPDATE, REVERT, DIFF), + + /** + * when a local file does not match the working version remote copy and + * there is also new yougest version on remote : this is the worse case + * (conflict). + * This state owns 4 actions : + * + */ + OUT_OF_DATE_AND_MODIFIED("outofdateAndModified", + I18n._("lutinutil.vcs.state.outofdateAndModified"), + OVERWRITE_AND_UPDATE, REVERT, DIFF, CHANGELOG), + + /** + * when a local file does not exist on remote repository. + * * This state owns 1 action : + * + */ + UNVERSIONNED("unversionned", I18n._("lutinutil.vcs.state.unversionned"), ADD), + + /** + * when a file exists on remote repository but not locally. + * * This state owns 1 action : + * + */ + MISSING("missing", I18n._("lutinutil.vcs.state.missing"), UPDATE), + + /** + * when a file is unversionned or missing : this special and durty state + * correspond for exemple when you want to add a file under a no checked + * directory... + *
+ * This state needs special add and update operation to create unchecked + * directories). + * This state owns 2 action : + * + */ + UNVERSIONNED_OR_MISSING("unversionnedOrMissing", + I18n._("lutinutil.vcs.state.unversionnedOrMissing"), ADD, UPDATE), + + /** to deal with other cases (...) */ + UNKNOWN("unknown", I18n._("lutinutil.vcs.state.unknown")); + + /** libelle to be used */ + private final String libelle; + /** key of the state */ + private final String key; + + /** VCSAction associated with this state */ + private final VCSAction[] actions; + + VCSState(String key, String libelle, VCSAction... actions) { + this.libelle = libelle; + this.actions = actions; + this.key = key; + } + + public String libelle() { + return libelle; + } + + public VCSAction[] getActions() { + return actions; + } + + public String getKey() { + return key; + } + + public boolean authorizeAction(VCSAction... actions) { + java.util.List acts = java.util.Arrays.asList(actions); + for (VCSAction vcsAction : this.actions) { + if (acts.contains(vcsAction)) { + return true; + } + } + return false; + } + + /** + * @param key key of required state + * @return the VCSState with key as key value, + * or null if no state found. + */ + public static VCSState valueOfKey(String key) { + for (VCSState state : VCSState.values()) + if (state.key.equals(key)) return state; + return null; + } +} \ No newline at end of file Index: lutinutil/src/java/org/codelutin/vcs/AbstractVCSHandler.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/AbstractVCSHandler.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/AbstractVCSHandler.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,134 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.util.FileUtil; + +import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * abstract VCSHandler base with usefull methods that does not need vcs specific code. + * + * @author chemit + */ +public abstract class AbstractVCSHandler implements VCSHandler { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory.getLog(AbstractVCSHandler.class); + + /** + * FilenameFilter to detect all files in a vcs working copy all files and directories that must be handled by vcs + * + * @see org.codelutin.vcs.VCSHandler#getVersionnableFilenameFilter() + */ + protected final FilenameFilter versionnableFilenameFilter; + protected final FileFilter versionnableFileFilter; + protected final String confLocalDirName; + protected final String confLocalEntriesFilename; + protected final VCSConfig config; + + protected AbstractVCSHandler(VCSConfig config, final String vCSConfLocalDirName, String vCSConfLocalEntriesFilename) { + this.config = config; + this.confLocalDirName = vCSConfLocalDirName; + this.confLocalEntriesFilename = vCSConfLocalEntriesFilename; + this.versionnableFilenameFilter = new FilenameFilter() { + public boolean accept(File dir, String name) { + return !vCSConfLocalDirName.equals(name) && !"CVS".equals(name); + } + }; + this.versionnableFileFilter = new FileFilter() { + public boolean accept(File dir) { + return dir.isFile() || (!vCSConfLocalDirName.equals(dir.getName()) && !"CVS".equals(dir.getName())); + } + }; + } + + public VCSConfig getConfig() { + return config; + } + + public File getLocalDatabaseFile() { + return config.getLocalDatabaseFile(); + } + + public void deleteWorkingCopy() { + if (getLocalDatabaseFile().exists()) { + FileUtil.deleteRecursively(getLocalDatabaseFile()); + getLocalDatabaseFile().delete(); + } + } + + public FilenameFilter getVersionnableFilenameFilter() { + return versionnableFilenameFilter; + } + + public FileFilter getVersionnableFileFilter() { + return versionnableFileFilter; + } + + public String getConfLocalDirname() { + return confLocalDirName; + } + + public String getConfLocalEntriesFilename() { + return confLocalEntriesFilename; + } + + public boolean isVersionnableFile(File file) { + assertFileExists(file, "file is empty or non existant"); + return !confLocalDirName.equalsIgnoreCase(file.getName()); + } + + public List getLocalStorageNames(File directory) { + List result = new ArrayList(); + if (directory.exists()) { + getFiles0(directory, result, ""); + } + Collections.sort(result); + return result; + } + + protected void getFiles0(File directory, List result, String prefix) { + //TODO put the hardcored value in a property!!! + if (directory.getName().equals("data")) return; + final String[] strings = directory.list(versionnableFilenameFilter); + boolean first = prefix.equals(""); + final String newPrefix = (first ? "" : prefix + File.separator); + + for (String filename : strings) { + final File dir = new File(directory, filename); + if (dir.isDirectory()) + getFiles0(dir, result, newPrefix + dir.getName()); + else result.add(newPrefix + dir.getName()); + } + } + + protected void assertFileExists(File file, String msg) { + if (file == null || !file.exists()) + throw new VCSRuntimeException(msg + " (file passed : [" + file + "])"); + } +} Index: lutinutil/src/java/org/codelutin/vcs/VCSUIAction.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSUIAction.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSUIAction.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,27 @@ +package org.codelutin.vcs; + +import org.codelutin.vcs.VCSException; +import org.codelutin.vcs.VCSHandler; +import org.codelutin.vcs.VCSFileState; + +import javax.swing.JDialog; +import java.util.List; + +/** + * a IsisVCSUIAction represents an action to realize on a file in working copy + * or on remote repository with an possible ui interaction. + * + * This is the highest api level for vcs using + *

+ * The method {@link #doAction(JDialog, org.codelutin.vcs.VCSHandler , List)} fired the action + * on a list of states + */ +public interface VCSUIAction { + /** + * @param dialog the dialog where action was asked + * @param handler vcshandler to use + * @param states list of VCSFileState to treate + * @throws VCSException if any exception while operation + */ + void doAction(JDialog dialog, VCSHandler handler,List states) throws VCSException; +} Index: lutinutil/src/java/org/codelutin/vcs/VCSHandlerFactory.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSHandlerFactory.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSHandlerFactory.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,89 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import static org.codelutin.i18n.I18n._; + +/** + * TODO This doc is not up to date and must be redone... + * + * @author chemit + * @see VCSConfig + * @see VCSHandler + */ +public class VCSHandlerFactory { + + private static VCSConfig config; + + private static VCSHandler handler; + + public static VCSConfig getConfig() { + assertConfigIsNotNull(config); + return config; + } + + public static void setConfig(VCSConfig value) { + config =value; + } + + public static VCSHandler getHandler() { + if (handler == null) { + synchronized (VCSHandlerFactory.class) { + handler = newHandler(getConfig()); + } + } + return handler; + } + + /** + * instanciate a new handler, using a previously instanciate handler config. + *

+ * the method will produce a runtime exception if config is null and not init. + * + * @param config config to use + * @return the new handler instance + */ + protected static VCSHandler newHandler(VCSConfig config) { + assertConfigIsInit(config); + try { + Class aClass = getConfig().getHandlerClass(); + return aClass.getConstructor(VCSConfig.class).newInstance(getConfig()); + } catch (Exception e) { + throw new VCSRuntimeException(e); + } + } + + private static void assertConfigIsNotNull(VCSConfig vcsConfig) { + if (vcsConfig == null) { + throw new VCSRuntimeException(_("lutinutil.error.init.no.config", VCSHandlerFactory.class.getName())); + } + } + + private static void assertConfigIsInit(VCSConfig config) { + assertConfigIsNotNull(config); + if (!config.isInit()) { + throw new VCSRuntimeException(_("lutinutil.error.init.config", config)); + } + } + + protected VCSHandlerFactory() { + // singleton idiom + } +} Index: lutinutil/src/java/org/codelutin/vcs/VCSException.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSException.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSException.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,51 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + + +/** + * A generic vcs exception. + * + * @author chemit + */ + +public class VCSException extends Exception { + + private static final long serialVersionUID = -2665066202505740998L; + + public VCSException() { + super(); + } + + public VCSException(String message) { + super(message); + } + + public VCSException(String message, Throwable cause) { + super(message, cause); + } + + public VCSException(Throwable cause) { + super(cause); + } + +} + + Index: lutinutil/src/java/org/codelutin/vcs/VCSFileState.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSFileState.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSFileState.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,265 @@ +package org.codelutin.vcs; + +import org.codelutin.vcs.VCSAction; +import org.codelutin.vcs.VCSException; +import org.codelutin.vcs.VCSRuntimeException; +import org.codelutin.vcs.VCSHelper; +import org.codelutin.vcs.VCSState; +import org.codelutin.vcs.VCSHandler; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; + +/** + * This class represents the vcs state of a file in a working copy or on remote + * repository. + *
+ * For a defined file in a working copy, we only use a instance of the + * class, {@link VCSFileStateManager} is responsible of instanciate thoses + * objects and store them in a cache. + *
+ * use method {@link #doSynch(VCSHandler,long)} to doSynch whatever + * local file state. + * use method {@link #doSynch(VCSHandler,long,boolean)} to doSynch only + * if local file state changed (with true value) + * + * @see VCSState + * @see VCSFileStateManager + */ +public class VCSFileState implements Serializable, Cloneable { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory.getLog(VCSFileState.class); + + /** + * working copy file to deal with (could not exists in file only exists + * on remote repository) + */ + protected File file; + /** a optional module name (if defined, will change getModuleRelativeFileName behavior) */ + protected String moduleName; + /** + * relative path on local file system (use File.separator) to root of local + * working copy + */ + protected String localPath; + /** + * relative path on remote repository (use '/' (should be Remote.separator) + * to root of this repository + */ + protected String remotePath; + /** timestamp of last doSynch or -1 if no doSynch was previously done */ + protected long timestamp; + /** state of the file */ + protected VCSState state; + /** + * index used to identify uniquely each instance (hashcode of + * file.getAbsolutePath()) + */ + protected int key; + /** revision of this file, or null if unversionned */ + protected Long rev; + /** changeLog of the file */ + protected String changeLog; + /** diff of the file */ + protected String diff; + /** action to be programmed for this state */ + protected VCSAction action; + + private static final long serialVersionUID = -815443990862836772L; + + /** + * protected access restriction : you should not instanciate directly + * this class, but use {@link VCSFileStateManager} to do it. + * + * @param handler the vcs handler used with this working copy + * @param file file to be handled + */ + protected VCSFileState(VCSHandler handler, File file) { + this.file = file; + this.key = file.getAbsolutePath().hashCode(); + String path = file.getAbsolutePath(); + String rootPath = handler.getLocalDatabaseFile().getAbsolutePath(); + + if (!path.startsWith(rootPath)) { + throw new VCSRuntimeException("could not create a VCSFileState " + + "for a file not in the root working copy registered in " + + "vcsHandler, but was : [" + file + " ::" + + handler.getLocalDatabaseFile() + " ]"); + } + this.localPath = path.substring(rootPath.length() + 1); + // by default moduleName is the first dir of localpath (if any) + int index = this.localPath.indexOf(File.separator); + if (index == -1) { + // this is a module directory + this.moduleName = this.localPath; + this.localPath = ""; + } else { + this.moduleName = this.localPath.substring(0, index); + } + + resetState(); + } + + public boolean existLocally() { + return file.exists(); + } + + public String getLocalPath() { + return localPath; + } + + public String getModuleName() { + return moduleName; + } + + public String getModuleRelativeFileName() { + return "".equals(moduleName) ? getLocalPath() : + "".equals(localPath) ? "" : localPath.substring(moduleName.length() + 1); + } + + public String[] getFileNamePath() { + // TODO Should use File.separator + return getModuleRelativeFileName().split(File.separator); + } + + public String getRemotePath() { + if (remotePath == null) + remotePath = VCSHelper.convertToRemoteName(localPath); + return remotePath; + } + + public VCSState getState() { + return state; + } + + public long getTimestamp() { + return timestamp; + } + + public File getFile() { + return file; + } + + public String getChangeLog() { + return changeLog; + } + + public Long getRev() { + return rev; + } + + public VCSAction getAction() { + return action; + } + + /** + * reset synch for this instance : after this invocation, + * the method {@link #wasSynch()} will return true to means + * that no synch info are available. + */ + public void resetState() { + state = null; + timestamp = -1; + } + + /** + * @return true if there at least one invocation of + * {@link #doSynch(VCSHandler,long)} or + * {@link #doSynch(VCSHandler,long,boolean)} + * was made and no invocation of {@link #resetState()} + * was made after. + */ + public boolean wasSynch() { + return state != null && timestamp != -1; + } + + /** + * @return true if this instance wasSynch and + * the file was not modified since last synch. + */ + public boolean isLocallySynch() { + return wasSynch() && timestamp <= file.lastModified(); + } + + /** + * doSynch this instance with remote repository and put a new timestamp + * the one passed as parameter. + * + * @param handler vcs handler to use + * @param timestamp the new synch timestamp + */ + public void doSynch(VCSHandler handler, long timestamp) { + doSynch(handler, timestamp, false); + } + + /** + * doSynch this instance with remote repository and put a new timestamp + * the one passed as parameter. + * Do not doSynch if ifFileChanged is true + * and file was not modify since last synch. + * + * @param handler vcs handler to use + * @param timestamp the new synch timestamp + * @param ifFileChanged if true will doSynch only if file + * was locally modified after last doSynch + */ + public void doSynch(VCSHandler handler, long timestamp, + boolean ifFileChanged) { + //TODO should deal with possibility of file existed but no more... + boolean needSynch = !wasSynch() || + !ifFileChanged || timestamp <= file.lastModified(); + + try { + if (needSynch) { + this.timestamp = timestamp; + Collection tmp = new ArrayList(); + this.state = handler.getState(file, tmp); + if (!tmp.isEmpty()) this.rev = (Long) tmp.iterator().next(); + log.info(" new synch " + this); + } + } catch (VCSException e) { + log.warn("could not acquire state for " + this + " : " + e.getMessage()); + resetState(); + } + } + + @Override + public boolean equals(Object o) { + return this == o || !(o == null || getClass() != o.getClass()) && + localPath.equals(((VCSFileState) o).localPath); + } + + @Override + public int hashCode() { + return localPath.hashCode(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(localPath).append('(').append(key).append(')'). + append('|').append(state).append('|').append(timestamp); + return sb.toString(); + } + + @Override + public VCSFileState clone() throws CloneNotSupportedException { + return (VCSFileState) super.clone(); + } + + + public void setChangeLog(String changeLog) { + this.changeLog = changeLog; + } + + public void setAction(VCSAction action) { + this.action = action; + } +} + Index: lutinutil/src/java/org/codelutin/vcs/VCSAction.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSAction.java:1.1 --- /dev/null Fri Jan 4 09:58:56 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSAction.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,90 @@ +/* ##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import static org.codelutin.i18n.I18n._; + +/** + * a VCSAction represents an action that can be realized on a file in working + * copy or on remote repository. + *

+ * Each VCSAction has 4 properties : + *

    + *
  • libelle : i18n to be used for this action
  • + *
  • visible : flag to say if action should be visible in ui
  • + *
  • backup : flag to say if this action need backup
  • + *
  • write : flag to say if this action need write access to repository
  • + *
+ * + * @author chemit + */ +public enum VCSAction { + + /** to add an unversionned file on repository */ + ADD(_("lutinutil.vcs.action.add"), true, false, true, true), + /** to delete locally and from repository */ + DELETE(_("lutinutil.vcs.action.delete"), true, true, true, true), + /** to get another version from repository */ + UPDATE(_("lutinutil.vcs.action.update"), true, true, false, false), + /** to get a clean copy from repository */ + OVERWRITE_AND_UPDATE(_("lutinutil.vcs.action.overwriteAndUpdate"), true, true, false, false), + /** commit a modification to repository */ + COMMIT(_("lutinutil.vcs.action.commit"), true, false, true, true), + /** to rollback to working base revision */ + REVERT(_("lutinutil.vcs.action.revert"), true, true, false, false), + /** to acquire a file from repository */ + CHECKOUT(_("lutinutil.vcs.action.checkout"), true, false, false, false), + /** to obtain the changelog of a file */ + CHANGELOG(_("lutinutil.vcs.action.changeLog"), false, false, false, false), + /** to obtain diif */ + DIFF(_("lutinutil.vcs.action.diff"), false, false, false, false); + + /** libelle of the action */ + private final String libelle; + /** flag to say if action should be visible in ui */ + private final boolean visible; + /** flag to say if this action need backup */ + private final boolean backup; + /** flag to say if this action need write access to repository */ + private final boolean write; + + VCSAction(String libelle, boolean visible, boolean backup, boolean commit, boolean write) { + this.libelle = libelle; + this.visible = visible; + this.backup = backup; + this.write = write; + } + + public String getLibelle() { + return libelle; + } + + public boolean isVisible() { + return visible; + } + + public boolean isBackup() { + return backup; + } + + public boolean isWrite() { + return write; + } +} Index: lutinutil/src/java/org/codelutin/vcs/VCSRepositoryState.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSRepositoryState.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSRepositoryState.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,201 @@ +/* ##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.vcs.ui.FileStateTableModel; + +import java.io.File; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +/** + * Permet de rechercher et conserve les differences entre le repository local et + * distant. + * + * @author poussin + * @author chemit + */ +public class VCSRepositoryState { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory.getLog(VCSRepositoryState.class); + + /** liste des états des fichiers scannés */ + protected List states = new ArrayList(); + + /** tableau des model de table (un par état VCSState) */ + protected FileStateTableModel[] models; + + /** le répertoire racine du working copy local */ + protected File root; + + /** vcs states to be authorized in this model */ + protected VCSState[] acceptedStates; + + /** vcs actions to be authorized in this model */ + protected EnumSet acceptedActions; + + /** vcs handler to use (lazy instanciation) */ + protected VCSHandler handler; + + public static final VCSState[] UPDATE_STATES = { + org.codelutin.vcs.VCSState.OUT_OF_DATE, + org.codelutin.vcs.VCSState.MODIFIED, + org.codelutin.vcs.VCSState.OUT_OF_DATE_AND_MODIFIED, + org.codelutin.vcs.VCSState.UNVERSIONNED, + org.codelutin.vcs.VCSState.MISSING + }; + + /** + * @param root directory of root local working copy + * @param actions accepted actions + * @param modules la liste des modules a traiter + * @throws VCSException if any problem while building + */ + protected VCSRepositoryState(File root, EnumSet actions, File... modules) throws VCSException { + this.acceptedActions = actions; + this.root = root; + this.acceptedStates = UPDATE_STATES; + // scan all modules + for (File mod : modules) { + states.addAll(doScan(mod, acceptedStates)); + } + } + + public VCSHandler getHandler() { + if (handler == null) { + handler = VCSHandlerFactory.getHandler(); + } + return handler; + } + + /** + * @param handler vcs handler to use for synch operation + * @throws VCSException if any problem while synchro + */ + public void doSynch(VCSHandler handler) throws VCSException { + long timestamp = System.nanoTime(); + for (VCSFileState fileState : states) { + fileState.doSynch(handler, timestamp); + } + } + + public File getRoot() { + return root; + } + + public List getStates() { + return states; + } + + public VCSState[] getAcceptedStates() { + return acceptedStates; + } + + public FileStateTableModel getModel(VCSState state) { + return getModels()[state.ordinal()]; + } + + + protected FileStateTableModel[] getModels() { + if (models == null) { + models = new FileStateTableModel[VCSState.values().length]; + } + return models; + } + + public void createUIModels() { + for (VCSState state : acceptedStates) { + getModels()[state.ordinal()] = new FileStateTableModel(VCSFileStateManager.filter(states, state), acceptedActions); + } + } + + public List selected(VCSState... wanted) { + if (wanted.length == 0) { + wanted = acceptedStates; + } + List result = new ArrayList(); + for (VCSState state : wanted) { + FileStateTableModel tableModel = getModel(state); + if (tableModel != null) { + result.addAll(tableModel.getSelected()); + } + } + return result; + } + + public void checkAll(boolean toUse, VCSState... wanted) { + if (wanted.length == 0) wanted = acceptedStates; + for (VCSState state : wanted) { + FileStateTableModel tableModel = getModel(state); + if (tableModel != null) { + tableModel.checkAll(0, toUse); + } + } + } + + public boolean isModelEmpty() { + for (VCSState state : acceptedStates) { + FileStateTableModel tableModel = getModel(state); + if (tableModel != null && tableModel.getRowCount() > 0) { + return false; + } + } + return true; + } + + public int getModelSelectedSize() { + int result = 0; + for (VCSState state : acceptedStates) { + result += getModelSelectedSize(state); + } + return result; + } + + public boolean isModelEmpty(VCSState state) { + FileStateTableModel tableModel = getModel(state); + return !(tableModel != null && tableModel.getRowCount() > 0); + } + + public int getModelSize(VCSState state) { + FileStateTableModel tableModel = getModel(state); + return tableModel == null ? 0 : tableModel.getRowCount(); + } + + public int getModelSelectedSize(VCSState state) { + FileStateTableModel tableModel = getModel(state); + return tableModel == null ? 0 : tableModel.getSelectedSize(); + } + + private List doScan(File module, VCSState... acceptedStates) + throws VCSException { + // obtain list of all VCSFileState found in module directory + List states; + states = VCSFileStateManager.doScan(getHandler(), module, true, acceptedStates); + return states; + } + + public EnumSet getAcceptedActions() { + return acceptedActions; + } +} Index: lutinutil/src/java/org/codelutin/vcs/VCSHandler.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSHandler.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSHandler.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,316 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import java.io.File; +import java.io.FileFilter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.Collection; +import java.util.List; + +/** + * Contract of an VCS handler + * + * @author chemit + */ + +public interface VCSHandler { + + File getLocalDatabaseFile(); + + /** + * init working copy, says if it is the first we use it it, we will checkout + * the databaseDirectory directory + * + * @throws VCSException if any exception while init + */ + void initWorkingCopy() throws VCSException; + + /** delete the local working copy with all his files */ + void deleteWorkingCopy(); + + /** @return the complete remote url to acces repository */ + String getRemoteUrl(); + + /** @return the config used by this handler */ + VCSConfig getConfig(); + + /** + * @return a + * FilenameFilter to detect all files and directories in a vcs working copy that + * must be handled by vcs + */ + FilenameFilter getVersionnableFilenameFilter(); + + /** + * @return a + * FileFilter to detect all files and directories in a vcs working copy that + * must be handled by vcs + */ + FileFilter getVersionnableFileFilter(); + + /** + * @return name of directory used by vcs to store in working copy, a data's + * directory configuration (e.g CVS for cvs and .svn for svn) + */ + String getConfLocalDirname(); + + /** + * @return name of the file used by vcs to store in working copy + * configuration directory entries of data's directory (e.g Entries + * for cvs and entries for svn) + */ + String getConfLocalEntriesFilename(); + + VCSState getState(File fileState, Collection tmp) throws VCSException; + + VCSState getState(File file, Collection tmp, boolean noremote) throws VCSException; + + /** + * @param file file to test + * @return true if file is on remote + * repository, false otherwise. + */ + boolean isOnRemote(File file); + + /** + * @param file file to test + * @return true if file is uptodate,false + * otherwise. + * @throws VCSException if any exception while operation + */ + boolean isUpToDate(File file) throws VCSException; + + /** + * @param file file to test + * @return true if file is handled by VCS,false + * otherwise. + */ + boolean isVersionnableFile(File file); + + /** + * add on remote repository somes directories + * + * @param commitMessage commit message + * @param dirNames names of the directories to create on remote repository (could + * used multi-level directories) + * @throws VCSException if any exception while operation + */ + void makeRemoteDir(String commitMessage, String... dirNames) + throws VCSException; + + /** + * delete on remote repository somes directories + * + * @param commitMessage commit message + * @param dirNames names of the directories to delete on remote repository (could + * used multi-level directories) + * @throws VCSException if any exception while operation + */ + void deleteRemoteDir(String commitMessage, String... dirNames) + throws VCSException; + + /** + * add a list of files into repository + * + * @param files files to add + * @param msg message for VCS commit, if null then no commit + * is performed + * @return revision of the operation + * @throws VCSException if any exception while operation + */ + long add(List files, String msg) throws VCSException; + + // void add(File file, String msg) throws VCSException; + + /** + * delete a list of files from repository + * + * @param files files to delete + * @param msg message for VCS commit, if null then no commit + * is performed + * @throws VCSException if any exception while operation + */ + void delete(List files, String msg) throws VCSException; + + /** + * revert a list of files from repository + * + * @param files files to revert + * @throws VCSException if any exception while operation + */ + void revert(List files) throws VCSException; + + /** + * commit a list of files into repository + * + * @param files files to commit + * @param msg message for VCS commit + * @return revision of the operation + * @throws VCSException if any exception while operation + */ + long commit(List files, String msg) throws VCSException; + + /** + * update a file to repository to a certain revision + * + * @param file file to update + * @param revision object representing a revision for the current VCS + * @throws VCSException if any exception while operation + */ + void update(File file, Object revision) throws VCSException; + + /** + * update a file to repository + * + * @param file file to update + * @throws VCSException if any exception while operation + */ + void update(File file) throws VCSException; + + /** + * checkout a module from repository to a local file + * + * @param destDir local file where to checkout + * @param module module's name to checkout + * @param recurse flag to say to recurse checkout or not. + * @throws VCSException if any exception while operation + */ + void checkout(File destDir, String module, boolean recurse) + throws VCSException; + + void checkoutFile(File destDir, String module) throws VCSException; + + long checkoutOnlyTheDirectory(File root, Object revision) throws VCSException; + + /** + * TODO This is not the good place : VCS != Storage + * + * @param directory directory to treate + * @return TODO + * @throws VCSException + * TODO + */ + List getRemoteStorageNames(File directory) throws VCSException; + + /** + * TODO This is not the good place : VCS != Storage + * + * @param directory directory to treate + * @return TODO + */ + List getLocalStorageNames(File directory); + + /** + * @param f local file to treate + * @return current local revision of a file + * @throws VCSException TODO + */ + Object getRevision(File f) throws VCSException; + + /** + * Obtain the list of log entries for the file + * + * @param startRevision TODO + * @param endRevision TODO + * @param file file to treate + * @return list of log entries for this file between two revisions + * @throws VCSException if any exception while grabbing infos + */ + List getLog(Object startRevision, Object endRevision, File file) + throws VCSException; + + /** + * obtain the content of a file for a specific revision + * + * @param file file to obtain + * @param revision revision treated + * @return the content of the file on repository for the specific revision + * passed as arguement. + * @throws VCSException if any exception while operation + * @throws java.io.IOException TODO + */ + String getFileContent(File file, Object revision) throws VCSException, IOException; + + /** + * Build the changelog for file from current revision of this + * local file against head repository head version. For each revision + * between current revision and head revision of this file, we give the + * following informations : + *
    + *
  • revision number
  • + *
  • author
  • + *
  • date
  • + *
  • commit message
  • + *
+ * + * @param file file to treate + * @return a string representation of change log for the local file to the + * head ? + * @throws VCSException if any exception while building changelog + */ + String getChangeLog(File file) throws VCSException; + + /** + * Generate in the ouputstream the diff between the current revision of the + * local file against headest revision on repository.
+ * If file is uptodate, then does nothing. + * + * @param file the file to treate + * @return the diff + * @throws VCSException inf any exception while building diff, such as : + *
    + *
  • unversionned file
  • + *
  • unexistant file locally
  • + *
  • locally modified file ?
  • + *
  • ...
  • + *
+ * @throws java.io.IOException if io problem with streams + */ + String getDiff(File file) throws VCSException, IOException; + + /** + * Generate in the ouputstream the diff between the current revision of the + * local file against another revision (againstRevision) on + * repository.
+ * If file is uptodate, then does nothing. + * + * @param file the file to treate + * @param againstRevision the against revision to use + * @return the diff + * @throws VCSException inf any exception while building diff, such as : + *
    + *
  • unversionned file
  • + *
  • unexistant file locally
  • + *
  • locally modified file ?
  • + *
  • ...
  • + *
+ * @throws java.io.IOException if problem with streams + */ + String getDiff(File file, Object againstRevision) throws VCSException, IOException; + + /** + * test if connection is ok + * + * @throws VCSException if any problem + */ + void testConnection() throws VCSException; +} \ No newline at end of file Index: lutinutil/src/java/org/codelutin/vcs/VCSStatus.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSStatus.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSStatus.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,32 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +public enum VCSStatus { + NORMAL, + ADDED, + MODIFIED, + DELETED, + UNVERSIONED, + MISSING, + IGNORED, + CONFLICTED, + NONE +} Index: lutinutil/src/java/org/codelutin/vcs/VCSConfig.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSConfig.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSConfig.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,66 @@ +/* +* \#\#% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Code Lutin, +* Tony Chemit +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +* \#\#% */ +package org.codelutin.vcs; + +import java.io.File; + +/** + * Contract to be realised by a VCS config used in VCSHandler + * + * @author chemit + */ +public interface VCSConfig { + VCSType getType(); + + boolean isUseSshConnexion(); + + String getHostName(); + + File getKeyFile(); + + String getUserName(); + + boolean isNoPassPhrase(); + + //char[] getPassphrase(); + + String getRemotePath(); + + String getRemoteDatabase(); + + String getRemoteDatabasePath(); + + File getLocalPath(); + + String getLocalDatabase(); + + File getLocalDatabaseFile(); + + VCSTypeRepo getTypeRepo(); + + Class getHandlerClass(); + + boolean isOffline(); + + boolean isReadOnly(); + + boolean isInit(); + + void validate(); +} Index: lutinutil/src/java/org/codelutin/vcs/VCSTypeRepo.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSTypeRepo.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSTypeRepo.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,55 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +/** + * type of repository to used, if no typeRepo (for CVS, use {@link #NONE} + * + * @author chemit + */ +public enum VCSTypeRepo { + /** head repo : is writable */ + HEAD("trunk", false), + /** tag repo : readonly */ + TAG("tags", true), + /** branch repo : should be writable ? */ + BRANCH("branches", false), + /** no type of repo : readonly */ + NONE(null, true); + + /** the path of the type of repo */ + final String path; + + /** flag to say this type of repo is readonly or not. */ + final boolean readonly; + + VCSTypeRepo(String path, boolean readOnly) { + this.path = path; + this.readonly = readOnly; + } + + public String getPath() { + return path; + } + + public boolean isReadonly() { + return readonly; + } +} Index: lutinutil/src/java/org/codelutin/vcs/VCSRuntimeException.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSRuntimeException.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSRuntimeException.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,51 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + + +/** + * A generic runtime vcs exception. + * + * @author chemit + */ + +public class VCSRuntimeException extends RuntimeException { + + private static final long serialVersionUID = -2665066202505740998L; + + public VCSRuntimeException() { + super(); + } + + public VCSRuntimeException(String message) { + super(message); + } + + public VCSRuntimeException(String message, Throwable cause) { + super(message, cause); + } + + public VCSRuntimeException(Throwable cause) { + super(cause); + } + +} + + Index: lutinutil/src/java/org/codelutin/vcs/package.html diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/package.html:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/package.html Fri Jan 4 09:58:51 2008 @@ -0,0 +1,11 @@ + + +

Lutin vcs

+Ensemble de l'api de base pour gérer des Versionning Concurrent System (aka +vcs) tel que CVS ou SVN. +
+On retrouve ici des interfaces, des classes génériques et les objets liés aux vcs. +
+Auncune implémentation n'est fournit actuellement ici. + + \ No newline at end of file Index: lutinutil/src/java/org/codelutin/vcs/VCSFileStateManager.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSFileStateManager.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSFileStateManager.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,293 @@ +/* ##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import org.apache.commons.collections.map.ReferenceMap; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.codelutin.vcs.VCSException; +import org.codelutin.vcs.VCSHandler; +import org.codelutin.vcs.VCSHandlerFactory; +import org.codelutin.vcs.VCSState; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Classe responsable de la gestion des {@link VCSFileState}. + *

+ * Elle permet leur instanciation, et gère un cache de ces objets, la politique + * étant de n'instancier qu'une seule fois et ensuite d'utiliser les methodes de + * synchronisations. + *
+ * TODO Doc + * {@link #doSynch()} + * {@link #getState(long,File)} ()} + * {@link #doAdd(VCSHandler,File)} + * {@link #doDelete(File)} + * {@link #doClear()} + * {@link #doReset()} + * + * @author chemit + */ +public class VCSFileStateManager { + + protected static VCSHandler getVCSHanler() { + return VCSHandlerFactory.getHandler(); + } + + static public List doScan(VCSHandler handler, File root, + boolean changeLog, + VCSState... states) throws VCSException { + return doScan(handler, root, changeLog, false, states); + + } + + static public List doScan(VCSHandler handler, File root, boolean changeLog, boolean rev, + VCSState... states) throws VCSException { + // TODO on devrait changer l'algorithme, pour ne recuperer + // TODO que ce qui est reellement est necessaire + + // recupereration des fichier locaux + List localFileNames = handler.getLocalStorageNames(root); + + // recuperation des fichiers distants + List remoteFileNames = handler.getRemoteStorageNames(root); + + //System.out.println("remote storages found for root [" + root.getName() + // + "]: " + remoteFileNames); + + // recuperation des fichiers uniquement presents sur le repository + // distant + List newRemoteName = new ArrayList(remoteFileNames); + newRemoteName.removeAll(localFileNames); + + List vcsstates = new ArrayList(); + + long timestamp = System.nanoTime(); + + for (String filePath : localFileNames) { + File f = new File(root, filePath); + vcsstates.add(getState(timestamp, f)); + } + + for (String filePath : newRemoteName) { + File f = new File(root, filePath); + vcsstates.add(getState(timestamp, f)); + } + + final List result = filter(vcsstates, states); + if (changeLog) { + // compute all change log for selected files + for (VCSFileState vcsFileState : result) + vcsFileState.setChangeLog(handler.getChangeLog(vcsFileState.getFile())); + } + return result; + } + + // ///////////////////////////////////////////////////////////////////////// + // / methodes getState(XXX) pour obtenir des etats du cache (avec creation + // / si besoin est) + // ///////////////////////////////////////////////////////////////////////// + + static public VCSFileState getState(long timestamp, File f) { + return getState(getVCSHanler(), timestamp, f); + } + + static public VCSFileState getState(boolean synch, File f) { + return getState(getVCSHanler(), synch, f); + } + + static public VCSFileState getState(VCSHandler handler, boolean synch, + File f) { + VCSFileState result; + synchronized (cache) { + final int key = getKey(f); + result = cache.get(key); + if (result == null) { + result = doAdd(handler, f); + } + if (synch) { + result.doSynch(handler, System.nanoTime()); + } + } + return result; + } + + static public VCSFileState getState(VCSHandler handler, long timestamp, File f) { + VCSFileState result; + synchronized (cache) { + final int key = getKey(f); + result = cache.get(key); + if (result == null) { + result = doAdd(handler, f); + } + result.doSynch(handler, timestamp); + } + return result; + } + + static public VCSFileState[] getState(VCSHandler handler, boolean synch, + Collection f) { + VCSFileState[] result = new VCSFileState[f.size()]; + + int index = 0; + for (File file : f) { + result[index] = getState(handler, synch, file); + index++; + } + return result; + } + + // ///////////////////////////////////////////////////////////////////////// + // / methodes doSynch(XXX) pour synchroniser les états du cache + // ///////////////////////////////////////////////////////////////////////// + + static public void doSynch() { + doSynch(getVCSHanler(), false, System.nanoTime()); + } + + static public void doSynch(VCSHandler handler, boolean ifFileChanged, + long timestamp) { + synchronized (cache) { + for (Integer hashcode : cache.keySet()) { + cache.get(hashcode).doSynch(handler, timestamp, ifFileChanged); + } + } + } + + static public void doSynch(VCSHandler handler, Collection files) { + doSynch(handler, false, System.nanoTime(), files); + } + + static public void doSynch(VCSHandler handler, boolean ifFileChanged, + long timestamp, Collection files) { + synchronized (cache) { + for (File file : files) { + VCSFileState vcsFileState = cache.get(getKey(file)); + if (vcsFileState == null) + vcsFileState = doAdd(getVCSHanler(), file); + vcsFileState.doSynch(handler, timestamp, ifFileChanged); + } + } + } + + // ///////////////////////////////////////////////////////////////////////// + // methodes protected doAdd(XXX) pour ajouter directement des etats au cache + // ///////////////////////////////////////////////////////////////////////// + + static protected VCSFileState doAdd(VCSHandler handler, File f) { + VCSFileState result; + synchronized (cache) { + final int key = getKey(f); + cache.put(key, result = new VCSFileState(handler, f)); + log.debug("[cache size:" + cache.size() + "] : " + result); + } + return result; + } + + // //////////////////////////////////////////////////////////////////////// + // methodes doDelete(XXX) pour supprimer des etats du cache + // //////////////////////////////////////////////////////////////////////// + + static public void doDelete(File file) { + synchronized (cache) { + cache.remove(getKey(file)); + } + } + + // ///////////////////////////////////////////////////////////////////////// + // / clean cache methods + // ///////////////////////////////////////////////////////////////////////// + + static public void doReset() { + synchronized (cache) { + for (Integer hashcode : cache.keySet()) { + cache.get(hashcode).resetState(); + } + } + } + + static public void doClear() { + synchronized (cache) { + cache.clear(); + } + } + + protected VCSFileStateManager() { + } + + static private int getKey(File file) { + return file.getAbsolutePath().hashCode(); + } + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static protected final Log log = LogFactory + .getLog(VCSFileStateManager.class); + + /** cache of VCSFileState, keys are relativePath.hashCode of each entry */ + @SuppressWarnings({"unchecked"}) + static final protected java.util.Map cache = + (java.util.Map) new ReferenceMap(); + + // ///////////////////////////////////////////////////////////////////////// + // / utils methods (filter and explode from VCSAction and VCSState) + // ///////////////////////////////////////////////////////////////////////// + @SuppressWarnings({"unchecked"}) + static public List[] explode(List source, + VCSState... wanted) { + if (wanted.length == 0) + wanted = VCSState.values(); + int nbState = wanted.length; + List[] result = new List[nbState]; + for (int i = 0; i < nbState; i++) { + result[i] = new ArrayList(); + } + List states = java.util.Arrays.asList(wanted); + VCSState state; + int index; + for (VCSFileState fileState : source) { + state = fileState.getState(); + if ((index = states.indexOf(state)) > -1) { + result[index].add(fileState); + } + } + return result; + } + + static public List filter(List source, + VCSState... wanted) { + List result = new ArrayList(); + List states = java.util.Arrays.asList(wanted); + + if (wanted.length == 0) { + return result; + } + for (VCSFileState fileState : source) { + VCSState currentState = fileState.getState(); + if (states.contains(currentState)) { + result.add(fileState); + } + } + return result; + } +} Index: lutinutil/src/java/org/codelutin/vcs/VCSType.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSType.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSType.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,31 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +/** + * This type-safe class representing a type of vcs (SVN,CVS,...) + * + * @author chemit + */ +public enum VCSType { + + CVS, SVN + +} Index: lutinutil/src/java/org/codelutin/vcs/VCSHelper.java diff -u /dev/null lutinutil/src/java/org/codelutin/vcs/VCSHelper.java:1.1 --- /dev/null Fri Jan 4 09:58:57 2008 +++ lutinutil/src/java/org/codelutin/vcs/VCSHelper.java Fri Jan 4 09:58:51 2008 @@ -0,0 +1,211 @@ +/* *##% +* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin, +* Benjamin Poussin, Tony Chemit +* +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* as published by the Free Software Foundation; either version 2 +* of the License, or (at your option) any later version. +* +* This program 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 General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*##%*/ +package org.codelutin.vcs; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import static org.codelutin.i18n.I18n._; + +import java.io.File; +import java.util.EnumSet; + +public class VCSHelper { + + private static final String LOCAL_SEP = File.separator; + private static final String LOCAL_SEP_PATTERN = "\\".equals(LOCAL_SEP) ? + LOCAL_SEP + LOCAL_SEP : LOCAL_SEP; + private static final String REMOTE_SEP = "/"; + private static final String REMOTE_SEP_PATTERN = "/"; + + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(VCSHelper.class); + + public static boolean isFileInWorkingCopy(File parent, String name, VCSHandler handler, boolean underVCS) { + if (parent == null || name == null) + throw new RuntimeException(VCSHelper.class.getName() + + "#isFileInWorkingCopy can not be invoked with some " + + "null parameter but was. [" + parent + "," + name + "," + + handler + "]"); + return isFileInWorkingCopy(new File(parent, name), handler, underVCS); + } + + public static boolean isFileInWorkingCopy(File file, VCSHandler handler, boolean underVCS) { + if (file == null || handler == null) + throw new RuntimeException(VCSHelper.class.getName() + + "#isFileInWorkingCopy can not be invoked with some " + + "null parameter but was. [" + file + "," + handler + "]"); + String rootPath = VCSHandlerFactory.getConfig().getLocalDatabaseFile().getAbsolutePath(); + String localPath = file.getAbsolutePath(); + if (localPath.startsWith(rootPath) && !underVCS) { + return true; + } + final File realDir = file.isDirectory() ? file : file.getParentFile(); + return isFileInCheckedDir(realDir, handler); + } + + public static boolean isFileInCheckedDir(File file, VCSHandler handler) { + if (file == null || handler == null) + throw new RuntimeException(VCSHelper.class.getName() + + "#isFileInCheckedDir can not be invoked with some " + + "null parameter but was. [" + file + "," + handler + "]"); + final File realDir = file.isDirectory() ? file : file.getParentFile(); + return (new File(realDir, handler.getConfLocalDirname()).exists()); + + } + + public static void assertFileInWC(File file, VCSHandler handler) { + if (!isFileInWorkingCopy(file, handler, false)) + throw new VCSRuntimeException("the file [" + file + + "] is not in the working copy [" + + handler.getLocalDatabaseFile() + "]"); + } + + public static String getRemoteRelativePath(File f, VCSHandler handler) { + if (!isFileInWorkingCopy(f, handler, false)) return null; + //System.out.println("file on vcs working copy : "+f); + String rootPath = handler.getConfig().getLocalDatabaseFile().getAbsolutePath(); + String localPath = f.getAbsolutePath(); + if (!localPath.startsWith(rootPath)) return null; + localPath = localPath.substring(rootPath.length() + 1); + return convertToRemoteName(localPath); + } + + public static String getLocalRelativePath(String remoteRelativePath, VCSHandler handler) { + String localPath = convertToLocalName(remoteRelativePath); + final File file = new File(handler.getConfig().getLocalDatabaseFile(), localPath); + if (!isFileInWorkingCopy(file, handler, false)) return null; + return localPath; + } + + public static String convertToRemoteName(String txt) { + return txt.replaceAll(LOCAL_SEP_PATTERN, REMOTE_SEP); + } + + public static String convertToLocalName(String txt) { + return txt.replaceAll(REMOTE_SEP_PATTERN, LOCAL_SEP); + } + + public static void doCheckoutDir(VCSHandler handler, File... dirs) { + for (File dir : dirs) { + try { + if (!dir.exists() || !isFileInWorkingCopy(dir, handler, true)) { + handler.checkoutOnlyTheDirectory(dir, null); + } + } catch (Exception eee) { + log.warn(_("lutinutil.error.checkout.dir", dir), eee); + break; + } + } + } + + /** + * @param typeRepo the type of repo to used + * @param remotePath the unclean remote path to use + * @return the remote path from the old one according to given type repo + */ + public static String getRemotePath(VCSTypeRepo typeRepo, String remotePath) { + String result = cleanRemotePath(remotePath); + switch (typeRepo) { + case BRANCH: + case TAG: + result = remotePath + '/' + typeRepo.getPath(); + break; + case HEAD: + result = remotePath; + break; + } + return result; + } + + /** + * @param typeRepo the type of repo to use + * @param version the version to use + * @return the remoteDatabase according to type of repo and version + */ + public static String getRemoteDatabase(VCSTypeRepo typeRepo, String version) { + String result = null; + switch (typeRepo) { + case BRANCH: + case TAG: + result = version; + break; + case HEAD: + result = VCSTypeRepo.HEAD.getPath(); + break; + } + return result; + } + + /** + * to clean a remote path from typeRepo suffix. + *

+ * For example, having a url svn://XXX/trunk then remove /trunk. + *

+ * Or if having svn://XXX/branches/YYY then remove /branches/YYY + * Or if having svn://XXX/tags/YYY then remove /tags/YYY + * + * @param remotePath the remote path to clean + * @return the cleaned remote path + */ + public static String cleanRemotePath(String remotePath) { + int pos = remotePath.indexOf(VCSTypeRepo.BRANCH.getPath()); + if (pos > -1) { + // found a branch + remotePath = remotePath.substring(0, pos - 1); + } else { + pos = remotePath.indexOf(VCSTypeRepo.HEAD.getPath()); + if (pos > -1) { + // found a branch + remotePath = remotePath.substring(0, pos - 1); + } else { + pos = remotePath.indexOf(VCSTypeRepo.TAG.getPath()); + if (pos > -1) { + // found a tag + remotePath = remotePath.substring(0, pos - 1); + } else { + // remote path was clean + } + } + } + return remotePath; + } + + + /** + * Obtain the set of permitted vcs actions. + * + * @return the EnumSet of authorized action according to current vcs config + */ + public static EnumSet getAuthorizedActions() { + boolean canWrite = hasWriteAccess(); + EnumSet result= EnumSet.noneOf(VCSAction.class); + for (VCSAction vcsAction : VCSAction.values()) { + if (!vcsAction.isWrite() || canWrite) { + result.add(vcsAction); + } + } + return result; + } + + public static boolean hasWriteAccess() { + return !VCSHandlerFactory.getConfig().isReadOnly(); + } +}