/**
*
*/
package alma.acs.releasedoc;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import alma.acs.releasedoc.Cvs2clXmlEntry.EntryFile;
import alma.acs.util.CmdLineArgs;
import alma.acs.util.CmdLineRegisteredOption;
/**
* This class bundles the other classes of this package and provides a command line tool.
* @author jschwarz, hsommer
*/
public class ProcessCvs2clOutput
{
public static enum SortBy {
time,
user,
file
}
private SortBy sortBy;
private List<File> subtractFiles = new ArrayList<File>();
private Set<String> retainFiles;
public static void main(String[] args) {
try {
(new ProcessCvs2clOutput()).run(args);
} catch (Exception ex) {
ex.printStackTrace();
}
}
void run(String[] args) throws Exception {
if (args.length < 1) {
throw new IllegalArgumentException("At least the xml file name must be given.");
}
File xmlFile1 = new File(args[args.length-1]);
if (!xmlFile1.exists()) {
System.err.println("File "+xmlFile1.getAbsolutePath()+" does not exist.");
}
setOptions(args);
Cvs2clXmlParser parser = new Cvs2clXmlParser();
Document doc = parser.parseXml(xmlFile1);
Set<Cvs2clXmlEntry> entries1 = new HashSet<Cvs2clXmlEntry>();
storeEntries(doc, entries1);
// optionally subtract entry sets
for (File subtractFile : subtractFiles) {
Document doc2 = parser.parseXml(subtractFile);
Set<Cvs2clXmlEntry> entries2 = new HashSet<Cvs2clXmlEntry>();
storeEntries(doc2, entries2);
entries1.removeAll(entries2);
System.out.println("Subtracted cvs entries from file " + subtractFile.getAbsolutePath());
}
TWikiFormatter formatter = new TWikiFormatter();
// sorting
List<Cvs2clXmlEntry> entries2 = null;
switch (sortBy) {
case time:
entries2 = formatter.sortByDate(entries1);
// formatting
formatter.printTwiki(entries2);
break;
case user:
entries2 = formatter.sortByAuthor(entries1);
TWikiFormatter.HeadingInserter hi = new TWikiFormatter.HeadingInserter() {
boolean needsHeading(Cvs2clXmlEntry entry) {
return (lastEntry == null || !lastEntry.getAuthor().equals(entry.getAuthor()));
}
String headingText(Cvs2clXmlEntry entry) {
return entry.getAuthor();
}
};
formatter.setHeadingInserter(hi);
// formatting
formatter.printTwiki(entries2);
break;
case file:
// A separate Cvs2clXmlEntry gets created for every file, and all entries for the same file are put in a map.
Map<String, List<Cvs2clXmlEntry>> entriesByFileName = new HashMap<String, List<Cvs2clXmlEntry>>();
// Iterate over all entries, some of which represent a related change on many files which needs to be broken up
for (Cvs2clXmlEntry compositeEntry : entries1) {
// Iterate over all files of this entry. We don't care about the common dir, because every file is given with the full path anyway.
for (Cvs2clXmlEntry.EntryFile file : compositeEntry.getFiles()) {
String pathName = file.getPathName();
List<Cvs2clXmlEntry> currentFileEntries = null;
if (entriesByFileName.containsKey(pathName)) {
// reuse entry list, add Cvs2clXmlEntry
currentFileEntries = entriesByFileName.get(pathName);
}
else {
currentFileEntries = new ArrayList<Cvs2clXmlEntry>();
entriesByFileName.put(pathName, currentFileEntries);
}
// create a separate Cvs2clXmlEntry for this file
Cvs2clXmlEntry singleFileEntry = new Cvs2clXmlEntry(compositeEntry);
List<EntryFile> singleFileList = new ArrayList<EntryFile>(1);
singleFileList.add(file);
singleFileEntry.setFiles(singleFileList);
currentFileEntries.add(singleFileEntry);
}
}
List<String> fileNames = new ArrayList<String>(entriesByFileName.keySet());
Collections.sort(fileNames);
//
if (retainFiles != null) {
int oldSize = fileNames.size();
fileNames.retainAll(retainFiles);
System.out.println("Reduced file list from " + oldSize + " to " + fileNames.size());
}
hi = new TWikiFormatter.HeadingInserter() {
boolean needsHeading(Cvs2clXmlEntry entry) {
if (lastEntry == null) {
return true;
}
String nameThis = getRelevantFileName(entry.getFiles().get(0).getPathName());
String nameLast = getRelevantFileName(lastEntry.getFiles().get(0).getPathName());
return !nameThis.equals(nameLast);
}
String headingText(Cvs2clXmlEntry entry) {
return getRelevantFileName(entry.getFiles().get(0).getPathName());
}
private String getRelevantFileName(String pathName) {
int relevantLevels = ( pathName.startsWith("ACS/LGPL/CommonSoftware/") ? 4 : 2 );
String[] nameParts = pathName.split("/");
String ret = "";
for (int i = 0; i < relevantLevels; i++) {
ret += nameParts[i] + "/";
}
return ret;
}
};
formatter.setHeadingInserter(hi);
for (String fileName : fileNames) {
List<Cvs2clXmlEntry> currentFileEntries = formatter.sortByDate(entriesByFileName.get(fileName));
// @TODO construct a fixed-ordered map first and then pass everything in one call to the formatter
formatter.printTwikiByFile(fileName, currentFileEntries);
}
break;
default: // should never happen, unless someone adds new enum literals
throw new IllegalStateException("Need to fix this switch statement!");
}
}
void storeEntries(Document doc, Set<Cvs2clXmlEntry> entries) throws XPathExpressionException, ParseException {
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList entryNodes = (NodeList) xpath.evaluate("//entry", doc, XPathConstants.NODESET);
System.out.println("Number of entries: " + entryNodes.getLength());
for (int i = 0; i < entryNodes.getLength(); i++) {
Element entryElem = (Element) entryNodes.item(i);
Cvs2clXmlEntry entry = new Cvs2clXmlEntry(entryElem);
boolean wasNewEntry = entries.add(entry);
if (!wasNewEntry) {
System.out.println("**** Multiple entry " + entry.getDate() + " author = " + entry.getAuthor());
}
}
}
void setOptions(String[] args) throws IOException {
// -- prepare arg parser
CmdLineArgs cmdArgs = new CmdLineArgs();
// optionally subtract other sets of cvs logs
CmdLineRegisteredOption optSubtract = new CmdLineRegisteredOption("-subtract", 1);
cmdArgs.registerOption(optSubtract);
// sort by time or by path (module, file,...) and time
CmdLineRegisteredOption optSortBy = new CmdLineRegisteredOption("-sortBy", 1);
cmdArgs.registerOption(optSortBy);
// sort by time or by path (module, file,...) and time
CmdLineRegisteredOption optRetainFiles = new CmdLineRegisteredOption("-retainFiles", 1);
cmdArgs.registerOption(optRetainFiles);
// -- parse and set args
cmdArgs.parseArgs(args);
// -- subtract
subtractFiles.clear();
if (cmdArgs.isSpecified(optSubtract)) {
String subtractFileNames = cmdArgs.getValues(optSubtract)[0].trim();
for (String fileName : subtractFileNames.split(File.pathSeparator)) {
File file = new File(fileName);
if (file.exists() && file.isFile()) {
subtractFiles.add(file);
}
else {
System.err.println("Will ignore non-existing subtract file " + file.getAbsolutePath());
}
}
}
// -- sort by
if (cmdArgs.isSpecified(optSortBy)) {
String sortByString = cmdArgs.getValues(optSortBy)[0].trim();
try {
sortBy = SortBy.valueOf(sortByString);
} catch (IllegalArgumentException ex) {
System.err.println("Will ignore illegal sort option '" + sortByString + "'.");
}
}
else {
sortBy = SortBy.time;
}
// -- retain files
if (cmdArgs.isSpecified(optRetainFiles)) {
File retainFilesFile = new File(cmdArgs.getValues(optRetainFiles)[0].trim());
if (sortBy != SortBy.file) {
System.err.println("Ignoring retain-files file '" + retainFilesFile.getAbsolutePath() + "' because 'sortBy' is not set to 'file'.");
}
else if (!retainFilesFile.exists() || !retainFilesFile.isFile()) {
System.err.println("Ignoring invalid retain-files file '" + retainFilesFile.getAbsolutePath() + "'");
}
BufferedReader reader = new BufferedReader(new FileReader(retainFilesFile));
retainFiles = new HashSet<String>();
String line = null;
// System.out.println("Will only consider the following files given in " + retainFilesFile.getAbsolutePath() + ":");
while ((line=reader.readLine()) != null) {
retainFiles.add(line);
// System.out.println(line);
}
reader.close();
}
}
}