Hi,

a while ago I posted some functionality for synchronising a maven project with a 
cvs repository.  I've migrated this funcionality so it can be used directly 
within maven.

brief summary of what CvsSynch does:
1) gets your file system in synch with modifications in cvs
2) performs a full clean build and runs all tests
3) if all tests pass, modifies cvs to bring in synch with modifications on your 
file system


*********************************************
2 new classes
org.apache.maven.cvsutil.CvsSynch
org.apache.maven.util.ToStringUtil

add them to jakarta-turbine-maven/src/java/org.........

build the classes
jakarta-turbine-maven>ant maven:install-jar
***************************************************

add this target to {maven.home}/build-maven.xml

     <target name="cvs-synch" depends="local-init,env">

         <taskdef name="cvssynch" classname="org.apache.maven.cvsutil.CvsSynch">
             <classpath refid="maven-classpath"/>
         </taskdef>

         <cvssynch projectDescriptor="project.xml">
                 <!-- some nested ant call to perform build / tests etc -->
         </cvssynch>
     </target>

***************************************************

add this target to your project build.xml


     <target name="maven:cvs-synch">
       <ant antfile="${maven.home}/build-maven.xml" target="cvs-synch"/>
     </target>


*******************************************************************

to execute
my.project.home>ant maven:cvs-synch

BEWARE.  If you are using a username / password in project.xml that has write 
access to your cvs repository, this will modify the cvs repository.

*****************************************************************

package org.apache.maven.cvsutil;

import org.apache.tools.ant.taskdefs.Cvs;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;
import org.apache.maven.project.Project;
import org.apache.tools.ant.types.Commandline;
import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.taskdefs.Ant;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.maven.util.ToStringUtil;
import java.util.Collection;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.HashMap;
import org.apache.maven.executor.ProjectExecutor;
import org.apache.tools.ant.taskdefs.ExecuteStreamHandler;

/**
 *
 * Task to manage synchronisation of filesystem with cvs. The Filesystem
 * is brought up to date with changes in cvs This is done by performing a 
 * update -n .  the output file of this command is parsed to identify what has 
 * to be done.  If the file contains a 'C' the build is failed as cvs is unable
 * to reconcile the differences between the filesystem and cvs. Files requiring
 * updating from CVS are identified by 'M'. Files in cvs but absent ('U') from the file
 * system could either added to cvs or removed from the filesystem.  The difference
 * is identified by parsing the appropriate CVS/Entries file. Files added to cvs
 * are brought to the fs.  The fs is now in synch with cvs.  the project is built
 * and tested via the nested ant task.  If the build and all tests suceed. 
 * New files are added to CVS, removed files are removed and all chages are
 * committed.
 * @author [EMAIL PROTECTED]
 * todo back up current fs prior to making modifications in order to rollback.
 * this functionality could be used just for reporting purposes to remind developer
 * of cvs tasks to perform.
 */

public class CvsSynch extends ProjectExecutor
 //   implements ExecuteStreamHandler
{

    private Cvs mCvs = null;

    private Ant mAntTask = null;

    /**
     * the package/module to check out.
     */
//    private String mPackage = null;
//    private File mComponentsDirectory;
//    private File mComponentDirectory;
    private File mUpdateLog = null;
    private Collection mFilesToAdd = null;
    private Collection mFilesToRemove = null;
    private Collection mFilesToMerge = null;
    private Collection mFilesToGet = null;
    private Collection mFilesWithConflicts = null;
    private HashMap mEntriesMap = null;

    public CvsSynch(){
        mCvs = new Cvs();
        mCvs.setFailOnError(true);
        mEntriesMap = new HashMap();
    }


    public void doExecute() throws BuildException {
        
        Project project = getMavenProject();
        mCvs.setCvsRoot(project.getCvsRoot());
        mCvs.setPackage(project.getCvsModule());
        mCvs.setProject(getProject());
        mCvs.setDest(getParentDirectory());

        try{
            //does nothing at the moment
            backupCode();
            //performs an update to identify what needs doing to which files
            doNoexecUpdate();
            //merge changed files
            doMerge();
            //get missing files
            doGet();
            //do any nested test - responsible for performing the build
            if(mAntTask != null){
                System.out.println("performing nested test task");
                mAntTask.execute();
            }
            // if tests pass add missing files to cvs
            doAddition();
            // remove any files from cvs removed from filesystem
            doRemove();
            // commit all changes
            doCommit();
        }
        catch(IOException e){
            e.printStackTrace();
            throw new BuildException(e);
        }
    }

    //todo
    private void backupCode(){

    }
    
    /**
     * writes output of update to /components/mycomponent/cvsupdate/cvsupdate.log
     */
    private void doNoexecUpdate(){
        System.out.println("generating the synch log file");
        mCvs.setNoexec(true);
        mCvs.setCommand("update");
        File updateLog = getUpdateLog();
        mCvs.setOutput(updateLog);
        System.out.println("generating the synch log file: " + updateLog);
        mCvs.execute();
    }


    private void parseUpdateLog() throws IOException{
            
        BufferedReader br = new BufferedReader(new FileReader(getUpdateLog()));
        ArrayList missingFiles = new ArrayList();
        String str = null;
        mFilesToAdd = new ArrayList();
        mFilesToRemove = new ArrayList();
        mFilesToMerge = new ArrayList();
        mFilesToGet = new ArrayList();
        mFilesWithConflicts = new ArrayList();
        while((str = br.readLine()) != null){
            
            if(str.startsWith("? ")){
                addToCollection(str,mFilesToAdd);
            }
            else if(str.startsWith("M ")){
                addToCollection(str,mFilesToMerge);
            }
            else if(str.startsWith("U ")){
                if(isRemoved(str)){
                    addToCollection(str,mFilesToRemove);
                }
                else{
                    addToCollection(str,mFilesToGet);
                }
            }
            else if(str.startsWith("C ")){
                addToCollection(str,mFilesWithConflicts);
            }
        }
        if(mFilesWithConflicts.size() > 0){
            throw new BuildException("The following files have conflicts, please 
resolve before proceeding.\n" + 
                                        ToStringUtil.toString(mFilesWithConflicts));
        }
    }

    private File getUpdateLog(){
        if(mUpdateLog == null){
            File buildDir = getBuildDirectory();
            mUpdateLog = new File(buildDir, "cvsupdate.log");
        }
        return mUpdateLog;
    }

    private File getBuildDirectory() {
        String buildDirName = (String) 
getProject().getProperties().get("maven.build.dir");
        return new File(buildDirName);
    }

    private File getParentDirectory(){
        return new File(getProject().getBaseDir(),"..");
    }
 /*   private File getComponentDirectory(){
        if(mComponentDirectory == null){
            File componentDirectory = new File(mComponentsDirectory,mPackage);
            if(!componentDirectory.exists()){
                if(!componentDirectory.mkdir()){
                    throw new BuildException("unable to create the component 
directory: " + componentDirectory.toString());
                }
            }
            mComponentDirectory = componentDirectory; 
        }
        return mComponentDirectory;
    }*/

    private boolean isRemoved(String str)
        throws IOException
    {
        System.out.println("checking if " + str + " has been removed");
        str = str.substring(2);
        int idx = str.lastIndexOf("/");
        String directory = str.substring(0,idx);
        String filename = str.substring(idx) + "/";
        System.out.println("dir = " + directory + " filename = " + filename);
        String entries = getEntriesFile(directory);
        return (entries.indexOf(filename) != -1);
    }
    
    private String getEntriesFile(String directory)
            throws IOException
    {
        if('/' != File.separatorChar){
            directory = directory.replace('/', File.separatorChar);
        }
    
        directory = directory + File.separator + "CVS";
        System.out.println("directory = " + directory);
        String entries = (String) mEntriesMap.get(directory);
        if(entries == null){
            File cvsDir = new File(getProject().getBaseDir(), directory);
            StringBuffer sb = new StringBuffer();
            if(cvsDir.exists()){
                System.out.println("directory exists");
                File entriesFile = new File(cvsDir,"Entries");
                FileReader fr = new FileReader(entriesFile);
                BufferedReader br = new BufferedReader(fr);
                try{
    
                    String str = null;
                    while((str = br.readLine()) != null){
                        sb.append(str);
                    }
                }
                finally{
                    closeReader(fr);
                    closeReader(br);
                }
            }
            entries = sb.toString();
            mEntriesMap.put(directory,entries);
        }
        return entries;
    }

    private static void addToCollection(String str, Collection col){
        str = str.substring(2);
        str = str.trim();
        col.add(str);
    }


    /**
     * update files on fs that have been modified in cvs
     */
    private void doMerge() throws IOException {
        System.out.println("files to merge");
        Collection col = getFilesToMerge();
        ToStringUtil.toStdOut(col);     
        Iterator it = col.iterator();
        mCvs.setNoexec(false);
        mCvs.setCommand("update");
        mCvs.setOutput(null);
        while(it.hasNext()){
            String module = (String) it.next();
            System.out.println("updating component: " + module);
            mCvs.setPackage(module);
            mCvs.execute();
        }
    }

    private Collection getFilesToMerge() throws IOException {
        if(mFilesToMerge == null){
            parseUpdateLog();
        }
        return mFilesToMerge;
    }
    
    /**
     * gets missing files onto filesystem from cvs - doesnt get files 
     * removed from fs, these will be schedulded for removal.
     */
    private void doGet() throws IOException {
        System.out.println("files to get");
        Collection col = getFilesToGet();
        ToStringUtil.toStdOut(col);     
        Iterator it = col.iterator();
        mCvs.setNoexec(false);
        mCvs.setCommand("checkout");
        mCvs.setOutput(null);
        while(it.hasNext()){
            String module = (String) it.next();
            mCvs.setPackage(module);
            mCvs.execute();
        }       
    }

    private Collection getFilesToGet() throws IOException {
        if(mFilesToGet == null){
            parseUpdateLog();
        }
        return mFilesToGet;
    }

    /**
     * adds new files to cvs after successful nested ant task
     */

    private void doAddition() throws IOException {
        System.out.println("files to add");
        Collection col = getFilesToAdd();
        ToStringUtil.toStdOut(col);     
        Iterator it = col.iterator();
        mCvs.setNoexec(false);
        mCvs.setCommand("add");
        mCvs.setOutput(null);
        while(it.hasNext()){
            String module = (String) it.next();
            String filename = module.substring(module.lastIndexOf("/") + 1);
            File dir = getDirectoryFromFile(module);
            System.out.println("changing dir to " + dir);
            mCvs.setDest(dir);
            mCvs.setPackage(filename);
            mCvs.execute();
        }

        mCvs.setDest(getParentDirectory());
    }


    private Collection getFilesToAdd() throws IOException {
        if(mFilesToAdd == null){
            parseUpdateLog();
        }
        return mFilesToAdd;
    }

    /**
     * removes files from cvs after successful nested ant task
     */
    private void doRemove() throws IOException {
        System.out.println("files to remove");
        
        Collection col = getFilesToRemove();
        ToStringUtil.toStdOut(col);     
        Iterator it = col.iterator();
        mCvs.setNoexec(false);
        mCvs.setCommand("remove");
        mCvs.setOutput(null);
        while(it.hasNext()){
            String module = (String) it.next();
            mCvs.setPackage(module);
            mCvs.execute();
            System.out.println("trying to remove " + module);
        }
    }

    private Collection getFilesToRemove() throws IOException {
        if(mFilesToRemove == null){
            parseUpdateLog();
        }
        return mFilesToRemove;
    }

    /**
     * commit all additions, removals and modifications to cvs
     */
    private void doCommit() throws IOException {
        System.out.println("commiting");
        mCvs.setNoexec(false);
        mCvs.setCommand("commit -m 'automatic checkin from RepositorySynch task'");
        mCvs.setOutput(null);
        mCvs.setPackage(getMavenProject().getCvsModule());
        File parent = getParentDirectory();
        System.out.println("setting component directory to " + parent);

        mCvs.setDest(parent);
        mCvs.execute();
        System.out.println("attempting to commit to central repository");
    }

    private File getDirectoryFromFile(String file){
        String directory = file.substring(0,file.lastIndexOf("/"));
        if(File.separatorChar != '/'){
            directory = directory.replace('/',File.separatorChar);
        }
        return new File(getParentDirectory(),directory);
    }

    // ant task set methods.
/*    public void setProject(Project project){
        super.setProject(project);
        mCvs.setProject(project);
    }*/

    public void addAnt(Ant antTask){
        mAntTask = antTask;
    }
    

/*    public void setPort(int port){
        System.out.println("setport");
        mCvs.setPort(port);
    }

    public void setPassfile(File passFile){
               System.out.println("set passfile");
        mCvs.setPassfile(passFile);
    }

    public void setPackage(String p) {
        System.out.println("setPackage");
        mPackage = p;
        mCvs.setPackage(p);
    }
/*
    public void setComponentsDirectory(File componentsDirectory){
        mComponentsDirectory = componentsDirectory;
        mCvs.setDest(mComponentsDirectory);
        System.out.println("setting components directory to " + componentsDirectory);
    }*/

    
    private static final void closeReader(Reader reader){
        if(reader != null){
            try{
                reader.close();
            }
            catch(IOException e){
                e.printStackTrace();
            }
        }
    }

    public void setProcessInputStream(OutputStream is){

    }

    public void setProcessErrorStream(InputStream is) {}

    /**
     * Install a handler for the output stream of the subprocess.
     *
     * @param is input stream to read from the error stream from the subprocess
     */
    public void setProcessOutputStream(InputStream is) {}

    /**
     * Start handling of the streams.
     */
    public void start() throws IOException{}
    

    /**
     * Stop handling of the streams - will not be restarted.
     */
    public void stop(){
    }


}
package org.apache.maven.util;

import java.util.Iterator;
import java.util.Collection;
import java.io.PrintStream;

import java.beans.PropertyDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.BeanInfo;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

public class ToStringUtil{

    private static HashMap sDescriptorsCache;

    static{
        sDescriptorsCache = new HashMap();
    }

    public static final String toString(Iterator it){
        StringBuffer sb = new StringBuffer();
        while(it.hasNext()){
            sb.append(it.next().toString());
            sb.append("\n");
        }
        return sb.toString();
    }

    public static final String toString(Collection col){
        return toString(col.iterator());
    }

/*    public static final void toStdOut(Iterator it){

    }*/

    public static final void toStdOut(Collection col){
        toPrintStream(col,System.out);
    }

/*    public static final void toStream(Iterator it, OutputStream os){

    }*/

 /*   public static final void toStream(Collection col, OutputStream os){

    }*/

    public static final void toPrintStream(Collection col, PrintStream ps){
        toPrintStream(col.iterator(),ps);
    }

    //does not use toString(Iterator) for possible performance reasons if big 
    //collections are in use.
    public static final void toPrintStream(Iterator it, PrintStream ps){
        while (it.hasNext()) {
            Object obj = it.next();
            ps.println(obj.toString());
        }
    }

    public static final String propertiesToString(Object obj){
        PropertyDescriptor[] descriptors = getPropertyDescriptors(obj);
        final Object[] params = new Object[0];
        StringBuffer sb = new StringBuffer();
        String name = obj.getClass().getName();
        sb.append(name.substring(name.lastIndexOf(".") + 1));
        sb.append(":: ");
        boolean first = true;
        for (int i = 0; i < descriptors.length; i++) {
            Method method = descriptors[i].getReadMethod();
            if(method != null) {
                name = descriptors[i].getName();
                if(!name.equals("class")) {
                    if(!first) {
                        sb.append(", ");
                    }
                    first = false;
                    sb.append(name);
                    sb.append("=");
                    try {   
                        sb.append(method.invoke(obj, params));
                    }
                    catch(IllegalAccessException e) {
                        //sLog.error("exception caught", e);
                    }
                    catch(IllegalArgumentException e) {
                        //sLog.error("exception caught", e);
                    }
                    catch(InvocationTargetException e) {
                        //sLog.error("exception caught", e);
                    }
                }
            }
        }
        return sb.toString();    
    }

    private static PropertyDescriptor[] getPropertyDescriptors(Object bean) 
    {
        if (bean == null)
            throw new IllegalArgumentException("No bean specified");

        // Look up any cached descriptors for this bean class
        String beanClassName = bean.getClass().getName();
        PropertyDescriptor descriptors[] = null;
        descriptors =
            (PropertyDescriptor[]) sDescriptorsCache.get(beanClassName);
        if (descriptors != null)
            return (descriptors);

        // Introspect the bean and cache the generated descriptors
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(bean.getClass());
        } catch (IntrospectionException e) {
            return (new PropertyDescriptor[0]);
        }
        descriptors = beanInfo.getPropertyDescriptors();
        if (descriptors == null)
            descriptors = new PropertyDescriptor[0];
        sDescriptorsCache.put(beanClassName, descriptors);
        return (descriptors);
    }
}

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to