|
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();
}
}
|