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 the CVS Client Library.
 * The Initial Developer of the Original Code is Robert Greig.
 * Portions created by Robert Greig are Copyright (C) 2000.
 * All Rights Reserved.
 *
 * Contributor(s): Robert Greig.
 *****************************************************************************/
package org.netbeans.lib.cvsclient.command.commit;

import java.io.*;
import java.util.*;

import org.netbeans.lib.cvsclient.*;
import org.netbeans.lib.cvsclient.admin.*;
import org.netbeans.lib.cvsclient.command.*;
import org.netbeans.lib.cvsclient.connection.*;
import org.netbeans.lib.cvsclient.event.*;
import org.netbeans.lib.cvsclient.request.*;

/**
 * The command to commit any changes that have been made.
 * @author  Robert Greig
 */
public class CommitCommand extends BasicCommand {
    /**
     * The argument requests that must be added at the end.
     * These argument requests indicate the files to be committed
     */
    private final List argumentRequests = new LinkedList();

    /**
     * The log message used for the commit.
     */
    private String message;

    /**
     * Forces the commit of the file(s) even if no changes were done.
     * the standard behaviour is NOT-TO-BE recursive in this case.
     */
    private boolean forceCommit;

    /**
     * The filename for the file that defines the message.
     */
    private String logMessageFromFile;

    /**
     * Determines that no module program should run on the server.
     */
    private boolean noModuleProgram;

    /** Holds value of property toRevisionOrBranch. */
    private String toRevisionOrBranch;

    /**
     * Construct a CommitCommand.
     */
    public CommitCommand() {
        resetCVSCommand();
    }

    /**
     * Returns the commit message.
     */
    public String getMessage() {
        return message;
    }

    /**
     * Sets the commit message.
     */
    public void setMessage(String message) {
        this.message = message;
    }

    /**
     * Indicates whether the commit should be forced even if there are no
     * changes.
     */
    public boolean isForceCommit() {
        return forceCommit;
    }

    /**
     * Sets whether the commit should be forced even if there are no changes.
     */
    public void setForceCommit(boolean forceCommit) {
        this.forceCommit = forceCommit;
    }

    /**
     * Adds the appropriate requests for a given directory.
     * Sends a directory request followed by as many Entry and Modified requests
     * as required.
     * @param directory the directory to send requests for
     * @throws IOException if an error occurs constructing the requests
     */
    protected void addRequestsForDirectory(File directory)
            throws IOException {
        if (!directory.exists()) {
            return;
        }
        // remove localPath prefix from directory. If left with
        // nothing, use dot (".") in the directory request. Also remove the
        // trailing slash
        String dir = getRelativeToLocalPathInUnixStyle(directory);

        try {
            String repository = clientServices.getRepositoryForDirectory(
                    directory.getAbsolutePath());
            requests.add(new DirectoryRequest(dir, repository));
            String tag = clientServices.getStickyTagForDirectory(directory);
            if (tag != null) {
                requests.add(new StickyRequest(tag));
            }
        }
        catch (IOException ex) {
            System.err.println("An error occurred reading the respository " +
                               "for the directory " + dir + ": " + ex);
            ex.printStackTrace();
        }

        // Obtain a set of all files known to CVS. We union
        // this set with the set of files in the actual filesystem directory
        // to obtain a set of files to commit (or at least attempt to commit).
        Set set = clientServices.getAllFiles(directory);

        // We must add the local files (and directories) because the above
        // command does *not* return cvs controlled directories
        final File[] files = directory.listFiles();

        // get the union of the files in the directory and the files retrieved
        // from the Entries file.
        set.addAll(Arrays.asList(files));

        List subdirectories = null;
        if (isRecursive()) {
            subdirectories = new LinkedList();
        }

        for (Iterator it = set.iterator(); it.hasNext();) {
            File file = (File)it.next();
            if (file.getName().equals("CVS")) { //NOI18N
                continue;
            }

            try {
                final Entry entry = clientServices.getEntry(file);
                // a non-null entry means the file does exist in the
                // Entries file for this directory
                if (entry == null) {
                    continue;
                }

                // here file.isFile() is *not* used, because not existing
                // files (removed ones) should also be sent
                if (!file.isDirectory()) {
                    sendEntryAndModifiedRequests(entry, file);
                }
                else if (isRecursive() && file.isDirectory()) {
                    File cvsSubDir = new File(file, "CVS"); //NOI18N
                    if (cvsSubDir.exists()) {
                        subdirectories.add(file);
                    }
                }
            }
            catch (IOException ex) {
                System.err.println("An error occurred getting the " +
                                   "Entry for file " + file + ": " + ex);
                ex.printStackTrace();
            }
        }

        if (isRecursive()) {
            for (Iterator it = subdirectories.iterator(); it.hasNext();) {
                File subdirectory = (File)it.next();
                addRequestsForDirectory(subdirectory);
            }
        }
    }

    /**
     * Add the appropriate requests for a single file.
     * A directory request is sent, followed by an Entry and Modified request.
     * @param file the file to send requests for
     * @throws IOException if an error occurs constructing the requests
     */
    protected void addRequestsForFile(File file)
            throws IOException {
        final File parentDirectory = file.getParentFile();
        // remove localPath prefix from directory. If left with
        // nothing, use dot (".") in the directory request
        String dir = getRelativeToLocalPathInUnixStyle(parentDirectory);

        try {
            // send a argument request indicating the file to update
            requests.add(new DirectoryRequest(dir, clientServices.
                                                   getRepositoryForDirectory(parentDirectory.
                                                                             getAbsolutePath())));
            String tag = clientServices.getStickyTagForDirectory(parentDirectory);
            if (tag != null) {
                requests.add(new StickyRequest(tag));
            }
        }
        catch (IOException ex) {
            System.err.println("An error occurred reading the respository " +
                               "for the directory " + dir + ": " + ex);
            ex.printStackTrace();
        }

        try {
            final Entry entry = clientServices.getEntry(file);
            // a non-null entry means the file does exist in the
            // Entries file for this directory
            if (entry != null) {
                sendEntryAndModifiedRequests(entry, file);
            }
        }
        catch (IOException ex) {
            System.err.println("An error occurred getting the Entry " +
                               "for file " + file + ": " + ex);
            ex.printStackTrace();
        }
    }

    /**
     * Should return true if unchanged files should not be sent to server.
     * If false is returned, all files will be sent to server
     * This method is used by sendEntryAndModifiedRequests.
     */
    protected boolean doesCheckFileTime() {
        return !isForceCommit();
    }

    /**
     * Execute the command.
     * @param client the client services object that provides any necessary
     *               services to this command, including the ability to actually
     *               process all the requests
     */
    public void execute(ClientServices client, EventManager em)
            throws CommandException, AuthenticationException {
        client.ensureConnection();

        super.execute(client, em);

        try {
            // add arguments.
            if (isForceCommit()) {
                requests.add(1, new ArgumentRequest("-f")); //NOI18N
                if (isRecursive()) {
                    requests.add(1, new ArgumentRequest("-R")); //NOI18N
                }
            }
            if (isNoModuleProgram()) {
                requests.add(1, new ArgumentRequest("-n")); //NOI18N
            }
            if (getToRevisionOrBranch() != null) {
                requests.add(1, new ArgumentRequest("-r")); //NOI18N
                requests.add(2, new ArgumentRequest(getToRevisionOrBranch()));
            }

            // build the message to send
            String message = getMessage();
            if (getLogMessageFromFile() != null) {
                message = loadLogFile(getLogMessageFromFile());
            }
            if (message != null) {
                message = message.trim();
            }
            if (message == null
                    || message.length() == 0) {
                message = "no message"; //NOI18N
            }
            addMessageRequest(message);

            addRequestForWorkingDirectory(client);
            requests.addAll(argumentRequests);
            argumentRequests.clear(); // MK sanity check.
            addArgumentRequests();
            requests.add(CommandRequest.COMMIT);

            client.processRequests(requests);
        }
        catch (CommandException ex) {
            throw ex;
        }
        catch (Exception ex) {
            throw new CommandException(ex, ex.getLocalizedMessage());
        }
        finally {
            requests.clear();
        }
    }

    protected void addArgumentRequests() {
        if (isForceCommit()) {
            Iterator it = requests.iterator();
            String directory = "";
            List args = new LinkedList();
            while (it.hasNext()) {
                Object req = it.next();
                if (req instanceof org.netbeans.lib.cvsclient.request.DirectoryRequest) {
                    org.netbeans.lib.cvsclient.request.DirectoryRequest dirReq = (org.netbeans.lib.cvsclient.request.DirectoryRequest)req;
                    // haven't checked but I'm almost sure that within the Argument request always the local directory is used.
                    directory = dirReq.getLocalDirectory();
                }
                else if (req instanceof org.netbeans.lib.cvsclient.request.EntryRequest) {
                    org.netbeans.lib.cvsclient.request.EntryRequest entReq = (org.netbeans.lib.cvsclient.request.EntryRequest)req;
                    String argument = null;
                    if (directory.length() == 0) {
                        argument = entReq.getEntry().getName();
                    }
                    else {
                        argument = directory + '/' + entReq.getEntry().getName();
                    }
                    args.add(new ArgumentRequest(argument));
                }
            }
            it = args.iterator();
            while (it.hasNext()) {
                requests.add(it.next());
            }
        }
        else {
            super.addArgumentRequests();
        }
    }

    /**
     * This method returns how the command would looklike when typed on the command line.
     * Example: checkout -p CvsCommand.java
     * @returns  [] files/dirs
     */
    public String getCVSCommand() {
        StringBuffer toReturn = new StringBuffer("commit "); //NOI18N
        toReturn.append(getCVSArguments());
        File[] files = getFiles();
        if (files != null) {
            for (int index = 0; index < files.length; index++) {
                toReturn.append(files[index].getName() + " "); //NOI18N
            }
        }
        return toReturn.toString();
    }

    /**
     * Takes the arguments and sets the command.
     * To be mainly used for automatic settings (like parsing the .cvsrc file).
     * @return true if the option (switch) was recognized and set
     */
    public boolean setCVSCommand(char opt, String optArg) {
        if (opt == 'm') {
            setMessage(optArg);
        }
        else if (opt == 'l') {
            setRecursive(false);
        }
        else if (opt == 'R') {
            setRecursive(true);
        }
        else if (opt == 'f') {
            setForceCommit(true);
        }
        else if (opt == 'F') {
            setLogMessageFromFile(optArg);
        }
        else if (opt == 'r') {
            setToRevisionOrBranch(optArg);
        }
        else if (opt == 'n') {
            setNoModuleProgram(true);
        }
        else {
            return false;
        }
        return true;
    }

    /**
     * Returns a String defining which options are available for this command.
     */
    public String getOptString() {
        return "m:flRnF:r:"; //NOI18N
    }

    /**
     * Method that is called while the command is being executed.
     * Descendants can override this method to return a Builder instance
     * that will parse the server's output and create data structures.
     */
    public Builder createBuilder(EventManager eventMan) {
        return new CommitBuilder(eventMan, getLocalDirectory());
    }

    /**
     * Generates the Argument/Argumentx series of requests depending
     * on the number of lines in the message request.
     */
    private void addMessageRequest(String message) {
        requests.add(new ArgumentRequest("-m")); //NOI18N
        StringTokenizer token = new StringTokenizer(message, "\n", false); //NOI18N
        boolean first = true;
        while (token.hasMoreTokens()) {
            if (first) {
                requests.add(new ArgumentRequest(token.nextToken()));
                first = false;
            }
            else {
                requests.add(new ArgumentxRequest(token.nextToken()));
            }
        }
    }

    /**
     * Returns the filename for the file that defines the message.
     */
    public String getLogMessageFromFile() {
        return logMessageFromFile;
    }

    /**
     * Sets the filename for the file that defines the message.
     */
    public void setLogMessageFromFile(String logMessageFromFile) {
        this.logMessageFromFile = logMessageFromFile;
    }

    /**
     * Returns whether no module program should be executed on the server.
     */
    public boolean isNoModuleProgram() {
        return noModuleProgram;
    }

    /**
     * Sets whether no module program should run on the server
     */
    public void setNoModuleProgram(boolean noModuleProgram) {
        this.noModuleProgram = noModuleProgram;
    }

    /** Getter for property toRevisionOrBranch.
     * @return Value of property toRevisionOrBranch.
     */
    public String getToRevisionOrBranch() {
        return toRevisionOrBranch;
    }

    /** Setter for property toRevisionOrBranch.
     * @param toRevisionOrBranch New value of property toRevisionOrBranch.
     */
    public void setToRevisionOrBranch(String toRevBranch) {
        this.toRevisionOrBranch = toRevBranch;
    }

    private String loadLogFile(String fileName)
            throws CommandException {
        StringBuffer buffer = new StringBuffer();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(fileName));
            String line;
            while ((line = reader.readLine()) != null) {
                buffer.append(line + "\n"); //NOI18N
            }
        }
        catch (FileNotFoundException ex) {
            throw new CommandException(ex,
                                       CommandException.getLocalMessage("CommitCommand.logInfoFileNotExists", new Object[]{fileName})); //NOI18N
        }
        catch (IOException ex) {
            throw new CommandException(ex,
                                       CommandException.getLocalMessage("CommitCommand.errorReadingLogFile", new Object[]{fileName})); //NOI18N
        }
        finally {
            if (reader != null) {
                try {
                    reader.close();
                }
                catch (IOException exc) {
                }
            }
        }
        return buffer.toString();
    }

    /**
     * Resets all switches in the command.
     * After calling this method, the command should have no switches defined
     * and should behave defaultly.
     */
    public void resetCVSCommand() {
        setMessage(null);
        setRecursive(true);
        setForceCommit(false);
        setLogMessageFromFile(null);
        setNoModuleProgram(false);
        setToRevisionOrBranch(null);
    }

    /**
     * Returns the arguments of the command in the command-line style.
     * Similar to getCVSCommand() however without the files and command's name.
     */
    public String getCVSArguments() {
        StringBuffer toReturn = new StringBuffer();
        if (!isRecursive()) {
            toReturn.append("-l "); //NOI18N
        }
        if (isForceCommit()) {
            toReturn.append("-f "); //NOI18N
            if (isRecursive()) {
                toReturn.append("-R ");
            }
        }
        if (isNoModuleProgram()) {
            toReturn.append("-n "); //NOI18N
        }
        if (getToRevisionOrBranch() != null) {
            toReturn.append("-r "); //NOI18N
            toReturn.append(getToRevisionOrBranch() + " "); //NOI18N
        }
        if (getLogMessageFromFile() != null) {
            toReturn.append("-F "); //NOI18N
            toReturn.append(getLogMessageFromFile());
            toReturn.append(" "); //NOI18N
        }
        if (getMessage() != null) {
            toReturn.append("-m \""); //NOI18N
            toReturn.append(getMessage());
            toReturn.append("\" "); //NOI18N
        }
        return toReturn.toString();
    }
}
... 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.