alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.vcs.profiles.cvsprofiles.commands;

import java.lang.reflect.*;
import java.io.*;
import java.util.*;
import org.netbeans.api.vcs.VcsManager;
import org.netbeans.api.vcs.commands.Command;

import org.netbeans.modules.vcs.profiles.cvsprofiles.list.CvsListOffline;
import org.netbeans.modules.vcs.profiles.cvsprofiles.list.StatusFilePathsBuilder;
import org.netbeans.modules.vcs.profiles.cvsprofiles.visualizers.commit.CommitInformation;

import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.NbBundle;

import org.netbeans.modules.vcscore.Variables;
import org.netbeans.modules.vcscore.VcsFileSystem;
import org.netbeans.modules.vcscore.VcsAction;
import org.netbeans.modules.vcscore.commands.*;
import org.netbeans.modules.vcscore.cmdline.ExecuteCommand;
import org.netbeans.modules.vcscore.cmdline.UserCommand;
import org.netbeans.modules.vcscore.cmdline.VcsAdditionalCommand;
import org.netbeans.modules.vcscore.util.Table;
import org.netbeans.modules.vcscore.util.VcsUtilities;
import org.netbeans.spi.vcs.commands.CommandSupport;
import org.openide.ErrorManager;

/**
 * The cvs commit command wrapper. This class ensures, that only files, that should
 * be committed with the current template are actually committed. If files with
 * different template are to be committed, the commit is executed multiple times.
 *
 * @author  Martin Entlicher
 */
public class CvsCommit extends Object implements VcsAdditionalCommand {

    private static final String COMMITTING = "CVS: Committing in";
    private static final String PRE_FILE = "CVS: \t";

    private static final String TEMP_FILE_PREFIX = "tempCommit";
    private static final String TEMP_FILE_SUFFIX = "output";
    
    private static final String REPOSITORY_FILE_PATTERN = ",v  <-- "; // NOI18N
    private static final String NEW_REVISION = "new revision: "; // NOI18N
    private static final String PREVIOUS_REVISION = "; previous revision: "; // NOI18N
    private static final String INITIAL_REVISION = "initial revision: "; //NOI18N
    private static final String DELETED_REVISION = "delete"; //NOI18N
    
    private VcsFileSystem fileSystem = null;
    
    private FileStatusUpdater fileStatusUpdater;

    /** Creates new CvsCommit */
    public CvsCommit() {
    }

    public void setFileSystem(VcsFileSystem fileSystem) {
        this.fileSystem = fileSystem;
    }
    
    private static ArrayList getFilePaths(String commonParent, String paths, char ps) {
        ArrayList files = new ArrayList();
        if (paths != null && paths.length() > 0) {
            int len = paths.length();
            int begin = 0;
            do {
                int index = paths.indexOf(""+ps + ps, begin);
                if (index < 0) index = len;
                String file = paths.substring(begin, index);
                if (commonParent != null && commonParent.length() > 0) {
                    file = commonParent + "/" + file;
                }
                files.add(file.replace(ps, '/'));
                begin = index + 2;
            } while (begin < len);
        }
        return files;
    }

    static List getCommitedFiles(String fsRoot, String relativePath,
                                 String template, char ps) {
        //System.out.println("getCommitedFiles("+template+")");
        ArrayList list = new ArrayList();
        int beginPath = template.indexOf(COMMITTING);
        //System.out.println("beginPath = "+beginPath);
        Map cachedEntries = new HashMap();
    
        File root = new File(fsRoot);
        if (beginPath < 0) beginPath = template.length();
        do {
            String path;
            int eol;
            if (beginPath < template.length()) {
                beginPath += COMMITTING.length();
                eol = template.indexOf('\n', beginPath);
                path = template.substring(beginPath, eol).trim();
                path = path.replace(File.separatorChar, '/');
                //System.out.println("path = "+path);
                if (".".equals(path)) path = "";
                beginPath = template.indexOf(COMMITTING, eol);
                if (beginPath < 0) beginPath = template.length();
            } else {
                path = "";
                eol = 0;
            }
            if (relativePath != null) {
                path = relativePath + ((path.length() > 0) ? "/" + path : "");
            }
            do {
                int beginFile = template.indexOf(PRE_FILE, eol);
                //System.out.println("begin file = "+beginFile);
                if (beginFile < 0 || beginFile > beginPath) break;
                eol = template.indexOf('\n', beginFile);
                beginFile += PRE_FILE.length();
                String files = template.substring(beginFile, eol).trim();
                files = files.replace(File.separatorChar, '/');
                addFiles(list, root, path, files, ps, cachedEntries);
                //list.add(path + "/" + file);
            } while (true);
        } while (beginPath < template.length());
        return list;
    }
    
    private static void addFiles(List list, File root, String path, String files,
                                 char ps, Map cachedEntries) {
        int begin = 0;
        int end = files.indexOf(' ');
        if (end < 0) end = files.length();
        while (begin < end) {
            String name;
            if (end < files.length()) {
                name = getFileFromRow(files.substring(begin), root, path, ps, cachedEntries);
                end = begin + name.length();
            } else {
                name = files.substring(begin, end);
            }
            //System.out.println("addFiles(): name = "+name);
            String file = (path.length() == 0) ? name : path + "/" + name;
            list.add(file);
            //System.out.println("  adding file = '"+file+"'");
            begin = end + 1;
            if (end < files.length()) {
                end = files.indexOf(' ', end + 1);
                if (end < 0) end = files.length();
            }
        }
    }
    
    private static String getFileFromRow(String row, File root, String path,
                                         char ps, Map cachedEntries) {
        int index;
        //System.out.println("getFileFromRow("+row+")");
        for (index = row.indexOf(' '); index > 0 && index < row.length(); index = row.indexOf(' ', index + 1)) {
            String file = row.substring(0, index);
            int sepIndex = file.lastIndexOf('/');
            if (sepIndex > 0) {
                String fileName = file.substring(sepIndex + 1);
                String filePath = file.substring(0, sepIndex);
                if (isCVSFile(root, path + "/" + filePath, fileName, ps, cachedEntries)) break;
            } else {
                //System.out.println(" file = "+file);
                if (isCVSFile(root, path, file, ps, cachedEntries)) break;
                //System.out.println("   is not CVS file!");
            }
        }
        //System.out.println("   have CVS file = "+((index > 0 && index < row.length()) ? row.substring(0, index) : row));
        if (index > 0 && index < row.length()) return row.substring(0, index);
        else return row;
    }
    
    private static boolean isCVSFile(File root, String path, String name,
                                     char ps, Map cachedEntries) {
        path = path.replace('/', ps);
        File dir = new File(root, path);
        File entries = new File(dir, "CVS/Entries");
        if (!entries.exists() || !entries.canRead()) return true;
        return isFileInEntries(name, entries, cachedEntries);
    }
    
    private static boolean isFileInEntries(String name, File entries, Map cachedEntries) {
        List files = (List) cachedEntries.get(entries);
        if (files == null) {
            files = loadEntries(entries);
            cachedEntries.put(entries, files);
        }
        return files.contains(name);
    }
    
    private static List loadEntries(File entries) {
        ArrayList entriesFiles = new ArrayList();
        if (entries.exists() && entries.canRead() && entries.canWrite()) {
            int fileIndex = -1;
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(entries));
                String line;
                while ((line = reader.readLine()) != null) {
                    if (line.startsWith("/")) {
                        int end = line.indexOf('/', 1);
                        if (end > 0) entriesFiles.add(line.substring(1, end));
                    }
                }
            } catch (FileNotFoundException fnfExc) {
                // ignore
            } catch (IOException ioExc) {
                // ignore
            } finally {
                try {
                    if (reader != null) reader.close();
                } catch (IOException exc) {}
            }
        }
        return entriesFiles;
    }
    
    //private void setProcessingFiles(ArrayList files, Hashtable vars) {
    //}

    private Table getFiles(List filesList) {
        Table files = new Table();
        for (Iterator it = filesList.iterator(); it.hasNext(); ) {
            String file = (String) it.next();
            if (".".equals(file)) file = ""; // cvs ci . will fail on Windows !!
            files.put(file, fileSystem.findResource(file));
        }
        return files;
    }

    /**
     * Run the commit and return the appropriate task IDs.
     */
    private long[] doCommit(CommandsPool cpool, VcsCommand cmdCommit, List filesList,
                            Hashtable vars, CommandOutputListener stderrNRListener,
                            CommandDataOutputListener stderrListener,
                            VcsCommandExecutor[][] executorsRet) {
        Table files = getFiles(filesList);
        VcsCommandExecutor[] executors = VcsAction.doCommand(files, cmdCommit, vars, fileSystem, fileStatusUpdater, stderrNRListener, null, stderrListener);
        //VcsCommandExecutor commit = fileSystem.getVcsFactory().getCommandExecutor(cmdCommit, vars);
        //int preprocessStatus = cpool.preprocessCommand(commit, vars);
        //cpool.startExecutor(commit);
        //return preprocessStatus;
        long[] IDs = new long[executors.length];
        for (int i = 0; i < executors.length; i++) {
            IDs[i] = cpool.getCommandID(executors[i]);
        }
        executorsRet[0] = executors;
        return IDs;
    }
    
    public boolean exec(Hashtable vars, String[] args,
                        CommandOutputListener stdoutNRListener, CommandOutputListener stderrNRListener,
                        CommandDataOutputListener stdoutListener, String dataRegex,
                        CommandDataOutputListener stderrListener, String errorRegex) {
        if (args.length < 1) {
            stderrNRListener.outputLine("The cvs commit command is expected as an arguments");
            return false;
        }
        String psStr = (String) vars.get("PS");
        if (psStr != null) {
            psStr = Variables.expand(vars, psStr, true);
        }
        char ps = (psStr == null || psStr.length() < 1) ? java.io.File.pathSeparatorChar : psStr.charAt(0);
        String relativeMountPoint = fileSystem.getRelativeMountPoint();
        String fsRoot = (String) vars.get("ROOTDIR");
        if (relativeMountPoint != null && relativeMountPoint.length() > 0) {
            fsRoot += ps + relativeMountPoint;//vars.get("MODULE");
        }
        String relativePath = (String) vars.get("COMMON_PARENT");
        if ("".equals(vars.get("MULTIPLE_FILES")) && !"".equals(vars.get("FILE_IS_FOLDER"))) {
            if (relativePath != null) {
                relativePath = relativePath + "/" + (String) vars.get("PATH");
            } else {
                relativePath = (String) vars.get("PATH");
                if (".".equals(relativePath)) relativePath = null;
            }
        }
        File updatedFileRoot;
        if (relativePath != null) {
            relativePath = relativePath.replace(File.separatorChar, '/');
            updatedFileRoot = new File(fsRoot, relativePath);
        } else {
            updatedFileRoot = new File(fsRoot);
        }
        fileStatusUpdater = new FileStatusUpdater(updatedFileRoot, relativePath, (String) vars.get("CVS_REPOSITORY"), stdoutNRListener, stdoutListener);
        fsRoot = fsRoot.replace('/', ps);
        //final StringBuffer buff = new StringBuffer();
        ArrayList filePaths = getFilePaths((String) vars.get("COMMON_PARENT"), (String) vars.get("PATHS"), ps);
        CommandsPool cpool = fileSystem.getCommandsPool();
        //Hashtable varsOriginal = new Hashtable(vars);
        //boolean committed = false;
        String committedStr = (String) vars.get("IS_COMMITTED");
        boolean committed = committedStr != null && committedStr.length() > 0;
        List alreadyCommittedFiles;
        String alreadyCommittedFilesStr = (String) vars.get("ALREADY_COMMITTED_FILES");
        if (alreadyCommittedFilesStr == null) {
            alreadyCommittedFiles = new ArrayList();
        } else {
            try {
                alreadyCommittedFiles = (List) VcsUtilities.decodeValue(alreadyCommittedFilesStr);
            } catch (IOException ioex) {
                alreadyCommittedFiles = new ArrayList();
            }
        }
        //do {
            //VcsCommand cmdTemplate = fileSystem.getCommand(args[0]);
            VcsCommand cmdCommit1 = fileSystem.getCommand(args[0]);
            VcsCommand cmdCommit = new UserCommand();
            ((UserCommand) cmdCommit).copyFrom(cmdCommit1);
            cmdCommit.setDisplayName(NbBundle.getMessage(CvsCommit.class, "CvsCommit.commitCommandName"));
            //buff.delete(0, buff.length());
            String templateContent = (String) vars.get("ORIGINAL_TEMPLATE_CONTENT");
            if (templateContent == null) templateContent = "";
            List filesCommited = null;
            if ("-f".equals(vars.get("FORCE"))) {
                filesCommited = new ArrayList(filePaths);
            } else {
                if (filePaths.size() == 1) {
                    FileObject fo = fileSystem.findResource((String) filePaths.get(0));
                    if (fo != null && fo.isData()) {
                        filesCommited = new ArrayList(filePaths);
                    }
                }
                if (filesCommited == null) {
                    filesCommited = getCommitedFiles(fsRoot, relativePath, templateContent, ps);
                }
            }
            //buffered = addMessageComment(vars, buffered);
            //vars.put("FILE_TEMPLATE", fileOutput(buffered));
            // commit all remaining files if they can not be retrieved from the template
            if (filesCommited == null || filesCommited.size() == 0) {
                if (committed) return true;//break;
                filesCommited = new ArrayList(filePaths);
            }
            filesCommited.removeAll(alreadyCommittedFiles);
            if (filesCommited.size() == 0) return true;//break ;
            //setProcessingFiles(filesCommited, vars);
            VcsCommandExecutor[][] executors = new VcsCommandExecutor[1][];
            long[] IDs = doCommit(cpool, cmdCommit, filesCommited, vars,
                                  stderrNRListener, stderrListener, executors);
            //cmdCommit1.setProperty(CommandCustomizationSupport.INPUT_DESCRIPTOR_PARSED,
            //    cmdCommit.getProperty(CommandCustomizationSupport.INPUT_DESCRIPTOR_PARSED));
            if (IDs.length == 0) {
                return true;//break;
            }
            vars.put("IS_COMMITTED", "true");
            committed = true;
            alreadyCommittedFiles.addAll(filesCommited);
            filePaths.removeAll(filesCommited);
            //vars = new Hashtable(varsOriginal);
            StringBuffer IDBuff = new StringBuffer();
            for (int i = 0; i < IDs.length; i++) {
                if (i > 0) IDBuff.append(" ,");
                IDBuff.append(Long.toString(IDs[i]));
            }
            final String IDStr = IDBuff.toString();
            if (filePaths.size() > 0) {
                vars.put("TEMPLATE_FILE_PLEASE_WAIT_TEXT", NbBundle.getMessage(CvsCommit.class, "CvsCommit.templateFileCheck"));
                vars.put("COMMIT_COMMANDS_IDS", IDStr);
                try {
                    vars.put("ALREADY_COMMITTED_FILES", VcsUtilities.encodeValue(alreadyCommittedFiles));
                } catch (IOException ioex) {}
                CommandSupport cmdSupport = fileSystem.getCommandSupport("COMMIT"); // Myself
                Command cmd = cmdSupport.createCommand();
                if (cmd instanceof VcsDescribedCommand) {
                    ((VcsDescribedCommand) cmd).setAdditionalVariables(vars);
                }
                if (VcsManager.getDefault().showCustomizer(cmd)) {
                    cmd.execute();
                }
            }
            boolean status = true;
            for(int i = 0; i < executors[0].length; i++) {
                try {
                    cpool.waitToFinish(executors[0][i]);
                } catch (InterruptedException iexc) {
                    for (int j = i; j < executors[0].length; j++) {
                        cpool.kill(executors[0][j]);
                    }
                    Thread.currentThread().interrupt();
                    break;
                }
                status = status && (executors[0][i].getExitStatus() == VcsCommandExecutor.SUCCEEDED);
            }
            fileStatusUpdater.flushElements();
        //cpool.preprocessCommand(vce, vars);
        return status;
    }
    
    private static String fileOutput(String buffer) {
        File outputFile;
        Writer writer = null;
        try {
            outputFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX);
            outputFile.deleteOnExit();
            writer = new BufferedWriter(new FileWriter(outputFile));
            writer.write(buffer);
        } catch (IOException ioexc) {
            ErrorManager.getDefault().notify(ioexc);
            return null;
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException ioexc) {
                    ErrorManager.getDefault().notify(ioexc);
                }
            }
        }
        return outputFile.getAbsolutePath();
    }
    
    /** Gets the output of "cvs commit" command and updates the status of committed files. */
    private static class FileStatusUpdater extends Object implements CommandOutputListener {
        
        private StatusFilePathsBuilder pathsBuilder;
        private File workingDir;
        private int workPathLength;
        private String relativePath;
        private CommandOutputListener stdoutNRListener; // The listener to propagate the standard output to
        private CommandDataOutputListener fileUpdateListener; // The listener to send data output to
        private String lastFilePath;
        private String lastFileDir;
        private List elementsToSend;
        
        public FileStatusUpdater(File workingDir, String relativePath, String cvsRepository,
                                 CommandOutputListener stdoutNRListener,
                                 CommandDataOutputListener fileUpdateListener) {
            this.stdoutNRListener = stdoutNRListener;
            this.fileUpdateListener = fileUpdateListener;
            this.pathsBuilder = new StatusFilePathsBuilder(workingDir, cvsRepository);
            this.workingDir = workingDir;
            workPathLength = workingDir.getAbsolutePath().length();
            if (relativePath != null && relativePath.length() > 0) {
                this.relativePath = relativePath + "/";
            } else {
                this.relativePath = "";
            }
            elementsToSend = new ArrayList();
        }
        
        public void outputLine(String line) {
            stdoutNRListener.outputLine(line);
            int reposFileIndex = line.indexOf(REPOSITORY_FILE_PATTERN);
            if (reposFileIndex > 0) {
                String reposFile = line.substring(0, reposFileIndex);
                int fileIndex = reposFile.lastIndexOf('/');
                String file = reposFile.substring(fileIndex + 1);
                lastFilePath = pathsBuilder.getStatusFilePath(file, reposFile);
                if (lastFilePath != null) {
                    lastFilePath = lastFilePath.replace(File.separatorChar, '/');
                }
            } else if (line.startsWith(NEW_REVISION) && lastFilePath != null) {
                int endRevision = line.indexOf(';', NEW_REVISION.length());
                if (endRevision <= 0) return ;
                String revision = line.substring(NEW_REVISION.length(), endRevision).trim();
                if (DELETED_REVISION.equals(revision)) {
                    endRevision += PREVIOUS_REVISION.length();
                    if (endRevision < line.length()) {
                        revision = line.substring(endRevision).trim();
                    }
                    revision(revision, CommitInformation.REMOVED);
                } else {
                    revision(revision, CommitInformation.CHANGED);
                }
            } else if (line.startsWith(INITIAL_REVISION) && lastFilePath != null) {
                String revision = line.substring(INITIAL_REVISION.length()).trim();
                revision(revision, CommitInformation.ADDED);
            }
        }
        
        private void revision(String revision, String operationType) {
            int fileIndex = lastFilePath.lastIndexOf('/');
            String fileDir;
            if (fileIndex <= 0) fileDir = "";
            else fileDir = lastFilePath.substring(0, fileIndex);
            if (!fileDir.equals(lastFileDir)) {
                // Do that asynchronously for all files in a given folder,
                // after there's a chance that the CVS/Entries file is updated and closed.
                flushElements();
                lastFileDir = fileDir;
            }
            String[] elements = new String[9];
            elements[0] = relativePath + lastFilePath;
            elements[1] = "Up-to-date";
            elements[2] = revision;
            elements[3] = ""; // time
            elements[4] = ""; // date
            elements[5] = null;// findSticky(lastFilePath); - load it asynchronously in flushElements()
            elements[6] = ""; // lockers
            if (CommitInformation.REMOVED == operationType) {
                elements[7] = relativePath + lastFilePath; // removed file
            } else {
                elements[7] = null; // removed file
            }
            elements[8] = operationType; // information for the visualizer
            //fileUpdateListener.outputData(elements);
            elementsToSend.add(elements);
            lastFilePath = null;
        }
        
        public void flushElements() {
            if (lastFileDir == null) return ;
            File folder = new File(workingDir, lastFileDir);
            File entries = new File(folder, "CVS/Entries"); // NOI18N
            Map entriesByFiles = CvsListOffline.createEntriesByFiles(CvsListOffline.loadEntries(entries));
            for (Iterator it = elementsToSend.iterator(); it.hasNext(); ) {
                String[] elements = (String[]) it.next();
                elements[5] = findSticky(elements[0], entriesByFiles);
                fileUpdateListener.outputData(elements);
            }
            elementsToSend.clear();
        }
        
        private String findSticky(String filePath, Map entriesByFiles) {
            int fileIndex = filePath.lastIndexOf('/');
            String fileName;
            if (fileIndex <= 0) fileName = filePath;
            else fileName = filePath.substring(fileIndex + 1);
            String entry = (String) entriesByFiles.get(fileName);
            if (entry == null) return "";
            String[] entryItems = CvsListOffline.parseEntry(entry);
            String sticky;
            if (entryItems.length > 4) {
                sticky = entryItems[4];
                if (sticky.length() > 0) sticky = sticky.substring(1, sticky.length());
            } else {
                sticky = "";
            }
            return sticky;
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.