/*
* (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.commit;
import java.io.File;
import java.io.IOException;
import org.netbeans.lib.cvsclient.command.Builder;
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
*/
public class CommitBuilder implements Builder {
/**
* Parsing constants.
*/
public static final String UNKNOWN = "commit: nothing known about `"; // NOI18N
public static final String EXAM_DIR = ": Examining"; // NOI18N
public static final String REMOVING = "Removing "; // NOI18N
public static final String NEW_REVISION = "new revision:"; // NOI18N
public static final String INITIAL_REVISION = "initial revision:"; // NOI18N
public static final String DELETED_REVISION = "delete"; // NOI18N
public static final String DONE = "done"; // NOI18N
public static final String RCS_FILE = "RCS file: "; // NOI18N
public static final String ADD = "commit: use `cvs add' to create an entry for "; // NOI18N
public static final String COMMITTED = " <-- "; // NOI18N
/**
* The status object that is currently being built.
*/
private CommitInformation commitInformation;
/**
* The directory in which the file being processed lives. This is absolute inside the local directory
*/
private File fileDirectory;
/**
* The event manager to use.
*/
private final EventManager eventManager;
private final String localPath;
private final String repositoryRoot;
private boolean isAdding;
public CommitBuilder(EventManager eventManager, String localPath, String repositoryRoot) {
this.eventManager = eventManager;
this.localPath = localPath;
this.repositoryRoot = repositoryRoot;
}
@Override
public void outputDone() {
if (commitInformation != null) {
eventManager.fireCVSEvent(new FileInfoEvent(this, commitInformation));
commitInformation = null;
}
}
@Override
public void parseLine(String line, boolean isErrorMessage) {
int c;
if (line.indexOf(UNKNOWN) >= 0) {
outputDone();
processUnknownFile(line.substring(line.indexOf(UNKNOWN) + UNKNOWN.length()).trim());
} else if (line.indexOf(ADD) > 0) {
processToAddFile(line.substring(line.indexOf(ADD) + ADD.length()).trim());
} else if ((c = line.indexOf(COMMITTED)) > 0) {
outputDone();
String fileName = line.substring(c + COMMITTED.length()).trim();
int nameIndex = fileName.lastIndexOf('/');
if (nameIndex != -1) { // #73181 happens with 1.12 servers: /usr/cvsrepo/Java112/nbproject/project.properties,v <--
// nbproject/project.properties
fileName = fileName.substring(nameIndex + 1);
}
File file;
if (fileDirectory == null) {
String reposPath = line.substring(0, c).trim();
if (reposPath.startsWith(repositoryRoot)) {
reposPath = reposPath.substring(repositoryRoot.length());
if (reposPath.startsWith("/")) {
reposPath = reposPath.substring(1);
}
}
c = reposPath.lastIndexOf('/');
if (c > 0) {
reposPath = reposPath.substring(0, c); // remove the file name
}
file = findFile(fileName, reposPath);
} else {
file = new File(fileDirectory, fileName);
}
processFile(file);
if (isAdding) {
commitInformation.setType(CommitInformation.ADDED);
isAdding = false;
} else {
commitInformation.setType(CommitInformation.CHANGED);
}
} else if (line.startsWith(REMOVING)) {
outputDone();
processFile(line.substring(REMOVING.length(), line.length() - 1));
// - 1 means to cut the ';' character
commitInformation.setType(CommitInformation.REMOVED);
} else if (line.indexOf(EXAM_DIR) >= 0) {
fileDirectory = new File(localPath, line.substring(line.indexOf(EXAM_DIR) + EXAM_DIR.length()).trim());
} else if (line.startsWith(RCS_FILE)) {
isAdding = true;
} else if (line.startsWith(DONE)) {
outputDone();
} else if (line.startsWith(INITIAL_REVISION)) {
processRevision(line.substring(INITIAL_REVISION.length()));
commitInformation.setType(CommitInformation.ADDED);
} else if (line.startsWith(NEW_REVISION)) {
processRevision(line.substring(NEW_REVISION.length()));
}
}
private File createFile(String fileName) {
return new File(localPath, fileName);
}
private void processUnknownFile(String line) {
commitInformation = new CommitInformation();
commitInformation.setType(CommitInformation.UNKNOWN);
int index = line.indexOf('\'');
String fileName = line.substring(0, index).trim();
commitInformation.setFile(createFile(fileName));
outputDone();
}
private void processToAddFile(String line) {
commitInformation = new CommitInformation();
commitInformation.setType(CommitInformation.TO_ADD);
String fileName = line.trim();
if (fileName.endsWith(";")) { // NOI18N
fileName = fileName.substring(0, fileName.length() - 2);
}
commitInformation.setFile(createFile(fileName));
outputDone();
}
private void processFile(String filename) {
if (commitInformation == null) {
commitInformation = new CommitInformation();
}
if (filename.startsWith("no file")) { // NOI18N
filename = filename.substring(8);
}
commitInformation.setFile(createFile(filename));
}
private void processFile(File file) {
if (commitInformation == null) {
commitInformation = new CommitInformation();
}
commitInformation.setFile(file);
}
private void processRevision(String revision) {
int index = revision.indexOf(';');
if (index >= 0) {
revision = revision.substring(0, index);
}
revision = revision.trim();
if (DELETED_REVISION.equals(revision)) {
commitInformation.setType(CommitInformation.REMOVED);
}
commitInformation.setRevision(revision);
}
@Override
public void parseEnhancedMessage(String key, Object value) {
}
private File findFile(String fileName, String reposPath) {
File dir = new File(localPath);
// happens when adding a new file to a branch
if (reposPath.endsWith("/Attic")) {
reposPath = reposPath.substring(0, reposPath.length() - 6);
}
// use quick finder and fallback to original algorithm just in case
File file = quickFindFile(dir, fileName, reposPath);
if (file != null) {
return file;
}
return findFile(dir, fileName, reposPath);
}
private File findFile(File dir, String fileName, String reposPath) {
if (isWorkForRepository(dir, reposPath)) {
return new File(dir, fileName);
} else {
File file = null;
File[] subFiles = dir.listFiles();
if (subFiles != null) {
for (int i = 0; i < subFiles.length; i++) {
if (subFiles[i].isDirectory()) {
file = findFile(subFiles[i], fileName, reposPath);
if (file != null) {
break;
}
}
}
}
return file;
}
}
private File quickFindFile(File dir, String fileName, String reposPath) {
for (;;) {
File deepDir = new File(dir, reposPath);
if (isWorkForRepository(deepDir, reposPath)) {
return new File(deepDir, fileName);
}
dir = dir.getParentFile();
if (dir == null) {
return null;
}
}
}
private boolean isWorkForRepository(File dir, String reposPath) {
try {
String repository = eventManager.getClientServices().getRepositoryForDirectory(dir);
String root = eventManager.getClientServices().getRepository();
if (repository.startsWith(root)) {
repository = repository.substring(root.length() + 1);
}
return reposPath.equals(repository);
} catch (IOException e) {
return false;
}
}
}