/*
* (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.update;
import java.io.File;
import org.netbeans.lib.cvsclient.command.Builder;
import org.netbeans.lib.cvsclient.command.DefaultFileInfoContainer;
import org.netbeans.lib.cvsclient.event.EnhancedMessageEvent;
import org.netbeans.lib.cvsclient.event.EventManager;
import org.netbeans.lib.cvsclient.event.FileInfoEvent;
/**
* Handles the building of update information object and the firing of events when complete objects are built.
*
* @author Milos Kleint, Thomas Singer
*/
public class UpdateBuilder implements Builder {
/**
* Parsing constants..
*/
public static final String UNKNOWN = ": nothing known about"; // NOI18N
public static final String EXAM_DIR = ": Updating"; // NOI18N
public static final String TO_ADD = ": use `cvs add' to create an entry for"; // NOI18N
public static final String STATES = "U P A R M C ? "; // NOI18N
public static final String WARNING = ": warning: "; // NOI18N
public static final String SERVER = "server: "; // NOI18N
public static final String PERTINENT = "is not (any longer) pertinent"; // NOI18N
public static final String REMOVAL = "for removal"; // NOI18N
public static final String SERVER_SCHEDULING = "server: scheduling"; // NOI18N
public static final String CONFLICTS = "rcsmerge: warning: conflicts during merge"; // NOI18N
public static final String NOT_IN_REPOSITORY = "is no longer in the repository"; // NOI18N;
// cotacao/src/client/net/riobranco/common/client/gui/BaseDialogThinlet.java already contains the differences between 1.17 and 1.18
private static final String MERGE_SAME = " already contains the differences between";
private static final String MERGED = "Merging differences between"; // NOI18N;
/**
* The status object that is currently being built.
*/
private DefaultFileInfoContainer fileInfoContainer;
/**
* The event manager to use.
*/
private EventManager eventManager;
/**
* The local path the command run in.
*/
private final String localPath;
private String diagnostics;
/**
* Holds 'G' or 'C' if the current file was merged or conflicted, respectively.
*/
private String fileMergedOrConflict;
public UpdateBuilder(EventManager eventManager, String localPath) {
this.eventManager = eventManager;
this.localPath = localPath;
}
@Override
public void outputDone() {
fileMergedOrConflict = null;
if (fileInfoContainer != null) {
if (fileInfoContainer.getFile() == null) {
System.err.println("#65387 CVS: firing invalid event while processing: " + diagnostics);
}
eventManager.fireCVSEvent(new FileInfoEvent(this, fileInfoContainer));
fileInfoContainer = null;
}
}
@Override
public void parseLine(String line, boolean isErrorMessage) {
diagnostics = line;
if (line.indexOf(UNKNOWN) >= 0) {
processUnknownFile(line, line.indexOf(UNKNOWN) + UNKNOWN.length());
} else if (line.indexOf(TO_ADD) >= 0) {
processUnknownFile(line, line.indexOf(TO_ADD) + TO_ADD.length());
} else if (line.indexOf(EXAM_DIR) >= 0) { // never comes with :local; connection method
return;
} else if (line.startsWith(CONFLICTS)) {
if (fileInfoContainer != null) {
fileInfoContainer.setType("C"); // NOI18N
// fire from Merged response which follows
}
fileMergedOrConflict = "C";
} else if (line.indexOf(WARNING) >= 0) {
if (line.indexOf(PERTINENT) > 0) {
String filename = line.substring(line.indexOf(WARNING) + WARNING.length(), line.indexOf(PERTINENT)).trim();
processNotPertinent(filename);
}
} else if (line.indexOf(SERVER_SCHEDULING) >= 0) {
if (line.indexOf(REMOVAL) > 0) {
String filename = line.substring(line.indexOf(SERVER_SCHEDULING) + SERVER_SCHEDULING.length(), line.indexOf(REMOVAL))
.trim();
processNotPertinent(filename);
}
} else if (line.indexOf(MERGE_SAME) >= 0) { // not covered by parseEnhancedMessage
ensureExistingFileInfoContainer();
fileInfoContainer.setType(DefaultFileInfoContainer.MERGED_FILE);
String path = line.substring(0, line.indexOf(MERGE_SAME));
fileInfoContainer.setFile(createFile(path));
outputDone();
} else if (line.startsWith(MERGED)) { // not covered by parseEnhancedMessage
outputDone();
fileMergedOrConflict = "G";
} else if (line.indexOf(NOT_IN_REPOSITORY) > 0) {
String filename = line.substring(line.indexOf(SERVER) + SERVER.length(), line.indexOf(NOT_IN_REPOSITORY)).trim();
processNotPertinent(filename);
return;
} else {
// otherwise
if (line.length() > 2) {
String firstChar = line.substring(0, 2);
if (STATES.indexOf(firstChar) >= 0) {
processFile(line);
return;
}
}
}
}
private File createFile(String fileName) {
return new File(localPath, fileName);
}
private void ensureExistingFileInfoContainer() {
if (fileInfoContainer != null) {
return;
}
fileInfoContainer = new DefaultFileInfoContainer();
}
private void processUnknownFile(String line, int index) {
outputDone();
fileInfoContainer = new DefaultFileInfoContainer();
fileInfoContainer.setType("?"); // NOI18N
String fileName = line.substring(index).trim();
fileInfoContainer.setFile(createFile(fileName));
}
private void processFile(String line) {
String fileName = line.substring(2).trim();
if (fileName.startsWith("no file")) { // NOI18N
fileName = fileName.substring(8);
}
if (fileName.startsWith("./")) { // NOI18N
fileName = fileName.substring(2);
}
File file = createFile(fileName);
if (fileInfoContainer != null) {
// sometimes (when locally modified.. the merged response is followed by mesage M <file> or C <file>..
// check the file.. if equals.. it's the same one.. don't send again.. the prior type has preference
if (fileInfoContainer.getFile() == null) {
// is null in case the global switch -n is used - then no Enhanced message is sent, and no
// file is assigned the merged file..
fileInfoContainer.setFile(file);
}
if (file.equals(fileInfoContainer.getFile())) {
// if the previous information does not say anything, prefer newer one
if (fileInfoContainer.getType().equals("?")) {
fileInfoContainer = null;
} else {
outputDone();
return;
}
}
}
if (fileMergedOrConflict != null && line.charAt(0) == 'M') {
line = fileMergedOrConflict; // can be done this way, see below
}
outputDone();
ensureExistingFileInfoContainer();
fileInfoContainer.setType(line.substring(0, 1));
fileInfoContainer.setFile(file);
}
private void processLog(String line) {
ensureExistingFileInfoContainer();
}
private void processNotPertinent(String fileName) {
outputDone();
File fileToDelete = createFile(fileName);
ensureExistingFileInfoContainer();
// HACK - will create a non-cvs status in order to be able to have consistent info format
fileInfoContainer.setType(DefaultFileInfoContainer.PERTINENT_STATE);
fileInfoContainer.setFile(fileToDelete);
}
/** <tt>Merged</tt> response handler. */
@Override
public void parseEnhancedMessage(String key, Object value) {
if (key.equals(EnhancedMessageEvent.MERGED_PATH)) {
ensureExistingFileInfoContainer();
String path = value.toString();
File newFile = new File(path);
// #70106 Merged responce must not rewrite CONFLICTS
if (newFile.equals(fileInfoContainer.getFile()) == false) {
fileInfoContainer.setFile(newFile);
fileInfoContainer.setType(DefaultFileInfoContainer.MERGED_FILE);
if (fileMergedOrConflict != null) {
fileInfoContainer.setType(fileMergedOrConflict);
}
}
outputDone();
}
}
}