PR: MPCHANGELOG-49

Visual Source Safe changelog (patch reviewed but untested due to unavailability of VSS installation)


git-svn-id: https://svn.apache.org/repos/asf/maven/maven-1/plugins/trunk@179946 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
brett
2005-06-04 04:55:07 +00:00
parent 2f0acedd6d
commit f669b454b3
4 changed files with 751 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
* ===================================================================
*/
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Provides VSS specific instances of the ChangeLogGenerator and ChangeLogParser
* interfaces.
*
* @author Freddy Mallet
*/
public class VssChangeLogFactory implements
org.apache.maven.changelog.ChangeLogFactory {
/**
* Default no-arg constructor.
*/
public VssChangeLogFactory() {
}
/**
* Create a VSS specific ChangeLogGenerator.
*
* @return a VSS specific ChangeLogGenerator.
*/
public ChangeLogGenerator createGenerator() {
return new VssChangeLogGenerator();
}
/**
* Create a VSS specific ChangeLogParser.
*
* @return a VSS specific ChangeLogParser.
*/
public ChangeLogParser createParser() {
return new VssChangeLogParser();
}
}

View File

@@ -0,0 +1,192 @@
package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
* ====================================================================
*/
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.AbstractChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogGenerator;
import org.apache.maven.changelog.ChangeLogParser;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.types.Commandline;
/*******************************************************************************
* A Visual Source Safe implementation of the
* {@link org.apache.maven.changelog.ChangeLogGenerator}interface realized
* extending the {@link org.apache.maven.changelog.AbstractChangeLogGenerator}.
*
* The command line build by this class uses the <code>ss History</code> VSS
* command and formats the output in a way the VssChangeLogParser can
* understand. Due to this fact this implementations works only if used within a
* vss view.
*
* The command looks like this:
* <p>
* set ssdir=vssRepositoryPath ss History vssProject -YvssUserId,vssUserPassword
* -R -Vd01/12/04~23/11/04 -I-Y
*
* @author Freddy Mallet
*/
public class VssChangeLogGenerator extends AbstractChangeLogGenerator {
/**
* Log
*/
private static final Log LOG = LogFactory
.getLog(VssChangeLogGenerator.class);
/***************************************************************************
* Constructs the appropriate command line to execute the scm's log command.
* For Clearcase it's lshistory.
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmLogCommand()
* @return The command line to be executed.
*/
protected Commandline getScmLogCommand() {
VssConnection vssConnection = new VssConnection(getConnection());
Commandline command = new Commandline();
command.setExecutable("ss");
command.createArgument().setValue("History");
command.createArgument().setValue("$" + vssConnection.getVssProject());
//User identification to get access to vss repository
if(vssConnection.getVssUserInf() != null){
command.createArgument().setValue("-Y" + vssConnection.getVssUserInf());
}
//Display the history of an entire project list
command.createArgument().setValue("-R");
//Ignore: Do not ask for input under any circumstances.
command.createArgument().setValue("-I-");
//Display only versions that fall within specified data range.
if (dateRange != null) {
command.createArgument().setValue("-Vd" + dateRange);
}
return command;
}
/***************************************************************************
* Construct the command-line argument that is passed to the scm client to
* specify the appropriate date range.
*
* @param before
* The starting point.
* @param to
* The ending point.
* @return A string that can be used to specify a date to a scm system.
*
* @see org.apache.maven.changelog.AbstractChangeLogGenerator#getScmDateArgument(java.util.Date,
* java.util.Date)
*/
protected String getScmDateArgument(Date before, Date to) {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy",
Locale.ENGLISH);
String result = sdf.format(to) + "~" + sdf.format(before);
return result;
}
protected String getScmTagArgument( String tagStart, String tagEnd )
{
throw new UnsupportedOperationException( "Cannot presently use tags for SCM operations on VSS" );
}
/**
* Convert date range from 'number of days' format to 'date to date' format
*
* @param numDaysString
* String
*/
public void setDateRange(String numDaysString) {
int days = Integer.parseInt(numDaysString);
Date before = new Date(System.currentTimeMillis() - (long) days * 24
* 60 * 60 * 1000);
Date to = new Date(System.currentTimeMillis() + (long) 1 * 24 * 60 * 60
* 1000);
}
/***************************************************************************
* Execute vss client driving the given parser. This method has been
* overwritten to be able to set 'SSDIR' environment variable. This variable
* set the vss repository
*
* @param parser
* A {@link ChangeLogParser parser}to process the vss output.
* @return A collection of {@link ChangeLogEntry entries}parsed from the
* vss output.
* @throws IOException
* When there are issues executing vss.
* @see ChangeLogGenerator#getEntries(ChangeLogParser)
*/
public Collection getEntries(ChangeLogParser parser) throws IOException {
if (parser == null) {
throw new NullPointerException("parser cannot be null");
}
if (base == null) {
throw new NullPointerException("basedir must be set");
}
if (!base.exists()) {
throw new FileNotFoundException("Cannot find base dir "
+ base.getAbsolutePath());
}
clParser = parser;
try {
VssConnection vssConnection = new VssConnection(getConnection());
Execute exe = new Execute(this);
String[] env = exe.getEnvironment();
if (env == null) {
env = new String[0];
}
String[] newEnv = new String[env.length + 1];
for (int i = 0; i < env.length; i++) {
newEnv[i] = env[i];
}
newEnv[env.length] = "SSDIR=" + vssConnection.getVssDir();
exe.setEnvironment(newEnv);
exe.setCommandline(getScmLogCommand().getCommandline());
//exe.setVMLauncher(false);
exe.setWorkingDirectory(base);
logExecute(exe, base);
exe.execute();
// log messages from stderr
String errors = errorReader.toString().trim();
if (errors.length() > 0) {
LOG.error(errors);
}
} catch (IOException ioe) {
handleParserException(ioe);
}
return entries;
}
}

View File

@@ -0,0 +1,398 @@
package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
* ===================================================================
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.changelog.ChangeLog;
import org.apache.maven.changelog.ChangeLogEntry;
import org.apache.maven.changelog.ChangeLogFile;
import org.apache.maven.changelog.ChangeLogParser;
/**
* Visual Source Safe specific implementation of ChangeLogParser interface.
*
* @author Freddy Mallet
*/
public class VssChangeLogParser implements
org.apache.maven.changelog.ChangeLogParser {
/** * Log */
private static final Log LOG = LogFactory.getLog(VssChangeLogParser.class);
/**
* Custom date/time formatter. Rounds ChangeLogEntry times to the nearest
* minute.
*/
private static final SimpleDateFormat ENTRY_KEY_TIMESTAMP_FORMAT = new SimpleDateFormat(
"yyyyMMddHHmm");
/**
* rcs entries, in reverse (date, time, author, comment) order
*/
private Map entries = new TreeMap(Collections.reverseOrder());
// state machine constants for reading Starteam output
/** * expecting file information */
private static final int GET_FILE = 1;
/** * expecting file path information */
private static final int GET_FILE_PATH = 2;
/** * expecting date */
private static final int GET_AUTHOR = 3;
/** * expecting comments */
private static final int GET_COMMENT = 4;
/** * expecting revision */
private static final int GET_REVISION = 5;
/** * unknown vss history line status */
private static final int GET_UNKNOWN = 6;
/** * Marks start of file data */
private static final String START_FILE = "****";
/** * Marks start of file data */
private static String START_FILE_PATH = "$/";
/** * Marks start of revision */
private static final String START_REVISION = "Version";
/** * Marks author data */
private static final String START_AUTHOR = "User: ";
/** * Marks comment data */
private static final String START_COMMENT = "Comment: ";
/** * last status of the parser */
private int lastStatus = GET_FILE;
/** * the current log entry being processed by the parser */
private ChangeLogEntry currentLogEntry = null;
/** * the current file being processed by the parser */
private ChangeLogFile currentFile = null;
/** * the bean representation of the vss connection string */
private VssConnection vssConnection;
/**
* Create a new ChangeLogParser.
*/
public VssChangeLogParser() {
}
/**
* initialize the parser from the change log
*
* @param changeLog
* the controlling task
* @see ChangeLogParser#init(ChangeLog)
*/
public void init(ChangeLog changeLog) {
String connection = changeLog.getRepositoryConnection();
try {
vssConnection = new VssConnection(connection);
} catch (Exception e) {
String message = "Unable to parse vss connection string : "
+ connection;
throw new IllegalArgumentException(message);
}
}
/**
* Parse the input stream into a collection.
*
* @param anInputStream
* an input stream containing clearcase log output
* @return a collection of ChangeLogEntry's
* @throws IOException
* when there are errors reading the provided stream
*/
public Collection parse(InputStream inputStream) throws IOException {
BufferedReader stream = new BufferedReader(new InputStreamReader(
inputStream));
String line;
while ((line = stream.readLine()) != null) {
switch (getLineStatus(line)) {
case GET_FILE:
processGetFile(line);
break;
case GET_REVISION:
processGetRevision(line);
break;
case GET_AUTHOR:
processGetAuthor(line);
break;
case GET_FILE_PATH:
processGetFilePath(line);
break;
case GET_COMMENT:
processGetComment(line);
break;
default:
break;
}
}
return entries.values();
}
/**
* Process the current input line in the Get Comment state.
*
* @param line
* a line of text from the VSS log output
*/
private void processGetComment(String line) {
String[] commentLine = line.split(":");
if (commentLine.length == 2) {
getCurrentLogEntry().setComment(commentLine[1]);
}
//Comment suite on a new line
else {
String comment = getCurrentLogEntry().getComment();
comment = comment + " " + line;
getCurrentLogEntry().setComment(comment);
}
}
/**
* Process the current input line in the Get Author state.
*
* @param line
* a line of text from the VSS log output
*/
private void processGetAuthor(String line) {
String[] result = line.split("\\s");
Vector vector = new Vector();
for (int i = 0; i < result.length; i++) {
if (!result[i].equals("")) {
vector.add(result[i]);
}
}
ChangeLogEntry entry = getCurrentLogEntry();
entry.setAuthor((String) vector.get(1));
entry.setDate(parseDate((String) vector.get(3) + " "
+ (String) vector.get(5)));
}
/**
* Process the current input line in the Get File state.
*
* @param line
* a line of text from the VSS log output
*/
private void processGetFile(String line) {
setCurrentLogEntry(new ChangeLogEntry());
String[] fileLine = line.split(" ");
setCurrentFile(new ChangeLogFile(fileLine[2]));
}
/**
* Process the current input line in the Get File Path state.
*
* @param line
* a line of text from the VSS log output
*/
private void processGetFilePath(String line) {
if (getCurrentFile() != null) {
String fileName = getCurrentFile().getName();
String path = line.substring(line.indexOf("$"), line.length());
String longPath = path.substring(vssConnection.getVssProject()
.length() + 1, path.length())
+ "/" + fileName;
getCurrentFile().setName(longPath);
addEntry(getCurrentLogEntry(), getCurrentFile());
}
}
/**
* Process the current input line in the Get Revision state.
*
* @param line
* a line of text from the VSS log output
*/
private void processGetRevision(String line) {
String[] revisionLine = line.split(" ");
getCurrentFile().setRevision(revisionLine[1]);
}
/**
* Identify the status of a vss history line
*
* @param the
* line to process
* @return status
*/
private int getLineStatus(String line) {
int argument = GET_UNKNOWN;
if (line.startsWith(START_FILE)) {
argument = GET_FILE;
} else if (line.startsWith(START_REVISION)) {
argument = GET_REVISION;
} else if (line.startsWith(START_AUTHOR)) {
argument = GET_AUTHOR;
} else if (line.indexOf(START_FILE_PATH) != -1) {
argument = GET_FILE_PATH;
} else if (line.startsWith(START_COMMENT)) {
argument = GET_COMMENT;
} else if (getLastStatus() == GET_COMMENT) {
//Comment suite on a new line
argument = getLastStatus();
}
setLastStatus(argument);
return argument;
}
/**
* Add a change log entry to the list (if it's not already there) with the
* given file.
*
* @param entry
* a {@link ChangeLogEntry}to be added to the list if another
* with the same key doesn't exist already. If the entry's author
* is null, the entry wont be added
* @param file
* a {@link ChangeLogFile}to be added to the entry
*/
private void addEntry(ChangeLogEntry entry, ChangeLogFile file) {
// do not add if entry is not populated
if (entry.getAuthor() == null) {
return;
}
String key = ENTRY_KEY_TIMESTAMP_FORMAT.format(entry.getDate())
+ entry.getAuthor() + entry.getComment();
if (!entries.containsKey(key)) {
entry.addFile(file);
entries.put(key, entry);
} else {
ChangeLogEntry existingEntry = (ChangeLogEntry) entries.get(key);
existingEntry.addFile(file);
}
}
/**
* Converts the date timestamp from the svn output into a date object.
*
* @return A date representing the timestamp of the log entry.
*/
private Date parseDate(String dateString) {
try {
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yy HH:mm");
Date date = format.parse(dateString);
return date;
} catch (ParseException e) {
LOG.error("ParseException Caught", e);
return null;
}
}
/**
* Getter for property currentFile.
*
* @return Value of property currentFile.
*/
private ChangeLogFile getCurrentFile() {
return currentFile;
}
/**
* Setter for property currentFile.
*
* @param currentFile
* New value of property currentFile.
*/
private void setCurrentFile(ChangeLogFile currentFile) {
this.currentFile = currentFile;
}
/**
* Getter for property currentLogEntry.
*
* @return Value of property currentLogEntry.
*/
private ChangeLogEntry getCurrentLogEntry() {
return currentLogEntry;
}
/**
* Setter for property currentLogEntry.
*
* @param currentLogEntry
* New value of property currentLogEntry.
*/
private void setCurrentLogEntry(ChangeLogEntry currentLogEntry) {
this.currentLogEntry = currentLogEntry;
}
/**
* Getter for property status.
*
* @return Value of property status.
*/
private int getLastStatus() {
return lastStatus;
}
/**
* Setter for property status.
*
* @param status
* New value of property status.
*/
private void setLastStatus(int status) {
this.lastStatus = status;
}
/**
* Clean up any parser resources
*
* @see ChangeLogParser#cleanup()
*/
public void cleanup() {
}
/**
* Defined in ChangeLogParser interface
*
* @see ChangeLogParser
*/
public void setDateFormatInFile(String s) {
}
}

View File

@@ -0,0 +1,105 @@
package org.apache.maven.vsslib;
/*
* ====================================================================
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
* ====================================================================
*/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Bean representation of the vss connection string
*
* @author Freddy Mallet
*/
public class VssConnection {
/** Log */
private static final Log LOG = LogFactory
.getLog(VssChangeLogGenerator.class);
/**
* VSS repository path
*/
private String vssDir;
/**
* VSS user information
*/
private String vssUserInf;
/**
* VSS project
*/
private String vssProject;
/**
* Create a new VssConnection objet according to the provided vss connection
* string. Here is an example:
* scm:vss:\\lancelot\Vss_EApplications\:guest,password:/Security/LOSCProduction
* the password is not madatory
*
* @param connection
* the vss connection string
*/
public VssConnection(String connection) {
if (!connection.startsWith("scm:vss")) {
throw new IllegalArgumentException(
"repositoy connection string does not specify 'vss' as the scm");
}
try {
String[] splitedConnection = connection.split(":");
vssDir = splitedConnection[2];
if(!splitedConnection[3].equals("")){
vssUserInf = splitedConnection[3];
}
vssProject = splitedConnection[4];
} catch (Exception e) {
String message = "Unable to parse VSS connection string :"
+ connection;
LOG.error(message, e);
throw new IllegalArgumentException(message);
}
}
/**
* Get the vss directory
*
* @return vss directory
*/
public String getVssDir() {
return vssDir;
}
/**
* Get the vss project
*
* @return vss project
*/
public String getVssProject() {
return vssProject;
}
/**
* Get the vss user information
*
* @return vss user information
*/
public String getVssUserInf() {
return vssUserInf;
}
}