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 :
+ *
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 Listtrue 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 :
+ * 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 extends VCSHandler> 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();
+ }
+}