/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo 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 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.netbeans.lib.cvsclient.command.edit;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.EOFException;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.netbeans.lib.cvsclient.ClientServices;
import org.netbeans.lib.cvsclient.admin.Entry;
import org.netbeans.lib.cvsclient.command.BasicCommand;
import org.netbeans.lib.cvsclient.command.CommandException;
import org.netbeans.lib.cvsclient.command.Watch;
import org.netbeans.lib.cvsclient.connection.AuthenticationException;
import org.netbeans.lib.cvsclient.event.EventManager;
import org.netbeans.lib.cvsclient.event.TerminationEvent;
import org.netbeans.lib.cvsclient.file.FileUtils;
import org.netbeans.lib.cvsclient.request.CommandRequest;
import org.netbeans.lib.cvsclient.request.NotifyRequest;
/**
* @author Thomas Singer
*/
public class EditCommand extends BasicCommand {
/**
* Returns the file used for backup the specified file in the edit command.
*/
public static File getEditBackupFile(File file) {
return new File(file.getParent(), "CVS/Base/" + file.getName()); // NOI18N
}
private boolean checkThatUnedited;
private boolean forceEvenIfEdited;
private Watch temporaryWatch;
private transient ClientServices clientServices;
/**
* Construct a new editors command.
*/
public EditCommand() {
resetCVSCommand();
}
/**
* Executes this command.
*
* @param client
* the client services object that provides any necessary services to this command, including the ability to actually process
* all the requests.
*/
@Override
public void execute(ClientServices clientServices, EventManager eventManager) throws CommandException {
this.clientServices = clientServices;
try {
clientServices.ensureConnection();
super.execute(clientServices, eventManager);
addArgumentRequest(isCheckThatUnedited(), "-c"); // NOI18N
addArgumentRequest(isForceEvenIfEdited(), "-f"); // NOI18N
// now add the request that indicates the working directory for the
// command
addRequestForWorkingDirectory(clientServices);
addRequest(CommandRequest.NOOP);
clientServices.processRequests(requests);
} catch (AuthenticationException ex) {
// TODO: handle case, where connection wasn't possible to establish
} catch (CommandException ex) {
throw ex;
} catch (EOFException ex) {
throw new CommandException(ex, CommandException.getLocalMessage("CommandException.EndOfFile", null)); // NOI18N
} catch (Exception ex) {
throw new CommandException(ex, ex.getLocalizedMessage());
} finally {
requests.clear();
this.clientServices = null;
}
}
@Override
protected void addRequestForFile(File file, Entry entry) {
String temporaryWatch = Watch.getWatchString(getTemporaryWatch());
requests.add(new NotifyRequest(file, "E", temporaryWatch)); // NOI18N
try {
editFile(clientServices, file);
} catch (IOException ex) {
// ignore
}
}
/**
* Called when server responses with "ok" or "error", (when the command finishes).
*/
@Override
public void commandTerminated(TerminationEvent e) {
if (builder != null) {
builder.outputDone();
}
}
/**
* This method returns how the tag command would looklike when typed on the command line.
*/
@Override
public String getCVSCommand() {
StringBuffer cvsCommandLine = new StringBuffer("edit "); // NOI18N
cvsCommandLine.append(getCVSArguments());
appendFileArguments(cvsCommandLine);
return cvsCommandLine.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
*/
@Override
public boolean setCVSCommand(char opt, String optArg) {
if (opt == 'R') {
setRecursive(true);
} else if (opt == 'l') {
setRecursive(false);
} else {
return false;
}
return true;
}
/**
* String returned by this method defines which options are available for this command.
*/
@Override
public String getOptString() {
return "Rl"; // NOI18N
}
/**
* Resets all switches in the command. After calling this method, the command should have no switches defined and should behave
* defaultly.
*/
@Override
public void resetCVSCommand() {
setRecursive(true);
setCheckThatUnedited(false);
setForceEvenIfEdited(true);
setTemporaryWatch(null);
}
/**
* Returns the arguments of the command in the command-line style. Similar to getCVSCommand() however without the files and command's
* name
*/
@Override
public String getCVSArguments() {
StringBuffer cvsArguments = new StringBuffer();
if (!isRecursive()) {
cvsArguments.append("-l "); // NOI18N
}
return cvsArguments.toString();
}
/**
* Returns whether to check for unedited files.
*/
public boolean isCheckThatUnedited() {
return checkThatUnedited;
}
/**
* Sets whether to check for unedited files. This is cvs' -c option.
*/
public void setCheckThatUnedited(boolean checkThatUnedited) {
this.checkThatUnedited = checkThatUnedited;
}
/**
* Returns whether the edit is forces even if the files are edited.
*/
public boolean isForceEvenIfEdited() {
return forceEvenIfEdited;
}
/**
* Sets whether the edit is forces even if the files are edited. This is cvs' -f option.
*/
public void setForceEvenIfEdited(boolean forceEvenIfEdited) {
this.forceEvenIfEdited = forceEvenIfEdited;
}
/**
* Returns the temporary watch.
*/
public Watch getTemporaryWatch() {
return temporaryWatch;
}
/**
* Sets the temporary watch. This is cvs' -a option.
*/
public void setTemporaryWatch(Watch temporaryWatch) {
this.temporaryWatch = temporaryWatch;
}
private void editFile(ClientServices clientServices, File file) throws IOException {
addBaserevEntry(clientServices, file);
FileUtils.copyFile(file, EditCommand.getEditBackupFile(file));
FileUtils.setFileReadOnly(file, false);
}
/**
* Create file CVS/Baserev with entries like BEntry.java/1.2/
*/
private void addBaserevEntry(ClientServices clientServices, File file) throws IOException {
final Entry entry = clientServices.getEntry(file);
if (entry == null || entry.getRevision() == null || entry.isNewUserFile() || entry.isUserFileToBeRemoved()) {
throw new IllegalArgumentException("File does not have an Entry or Entry is invalid!"); // NOI18N
}
File baserevFile = new File(file.getParentFile(), "CVS/Baserev"); // NOI18N
File backupFile = new File(baserevFile.getAbsolutePath() + '~');
BufferedReader reader = null;
BufferedWriter writer = null;
boolean append = true;
boolean writeFailed = true;
final String entryStart = 'B' + file.getName() + '/';
try {
writer = new BufferedWriter(new FileWriter(backupFile));
writeFailed = false;
reader = new BufferedReader(new FileReader(baserevFile));
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
if (line.startsWith(entryStart)) {
append = false;
}
writeFailed = true;
writer.write(line);
writer.newLine();
writeFailed = false;
}
} catch (IOException ex) {
if (writeFailed) {
throw ex;
}
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
// ignore
}
}
if (writer != null) {
try {
if (append && !writeFailed) {
writer.write(entryStart + entry.getRevision() + '/');
writer.newLine();
}
} finally {
try {
writer.close();
} catch (IOException ex) {
// ignore
}
}
}
}
baserevFile.delete();
backupFile.renameTo(baserevFile);
}
}