Craig,
Here is my code, it just builds a command line and then 'exec's the ss tool:
-----------------------------------------------
package com.xms.antext.taskdefs;
import org.apache.tools.ant.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;
/**
* Task to interact with Microsoft Visual Source Safe. This task can take
the following
* arguments:
* <ul>
* <li>command
* <li>sourcedir
* <li>destdir
* <li>label
* <li>recursive
* </ul>
* Of these arguments, the <b>command</b>, <b>sourcedir</b> and
<b>destdir</b> are required.
*
*/
public class MSVSS extends Task {
private static final int BUFFER_SIZE = 512;
private String m_Command = null;
private String m_SrcDir = null;
private String m_DestDir = null;
private String m_Label = null;
private boolean m_Recursive = false;
/**
* Set the SourceSafe command to execute
*/
public void setCommand(String command) {
m_Command = command;
}
/**
* Set the source dir.
*/
public void setSrcdir(String srcDirName) {
if ( srcDirName.startsWith("vss://") ) {
m_SrcDir = srcDirName.substring(5);
} else {
m_SrcDir = project.translatePath(srcDirName);
}
}
/**
* Set the destination.
*/
public void setDestdir(String destDirName) {
if ( destDirName.startsWith("vss://") ) { // a VSS path leave alone
m_DestDir = destDirName.substring(5);
} else { // translate for platform
m_DestDir = project.translatePath(destDirName);
}
}
/**
* Set the labeled version to operate on in SourceSafe
*/
public void setLabel(String label) {
m_Label = label;
}
/**
* Set behaviour recursive or non-recursive
*/
public void setRecursive(String recursive) {
m_Recursive = Project.toBoolean(recursive);
}
/**
* Executes the task.
*/
public void execute() throws BuildException {
String commandLine = "";
Process ssProc = null;
int result = 0;
// first off, make sure that we've got a srcdir and destdir
if (m_Command == null || m_SrcDir == null || m_DestDir == null ) {
String msg = "command, srcDir and destDir attributes must be
set!";
throw new BuildException(msg);
}
// build the command line from what we got ...
commandLine = "ss ";
if (m_Command.equalsIgnoreCase("get")) {
// create the destination dir ...
File dir = project.resolveFile(m_DestDir);
if (!dir.exists()) {
boolean done = dir.mkdirs();
if (done == false) {
String msg = "Directory " + m_DestDir + " creation was
not " +
"succesful for an unknown reason";
throw new BuildException(msg);
}
project.log("Created dir: " + dir.getAbsolutePath());
}
// build the command line ...
commandLine += m_Command + " " +
"$" + m_SrcDir + " ";
if ( m_Recursive ) {
commandLine += "-r ";
}
if ( (m_Label != null) && (!m_Label.equals("")) ) {
commandLine += "-vl" + m_Label + " ";
}
commandLine += "-GL" + m_DestDir + " " +
"-I-";
} else {
String msg = "Unsupported vss command";
throw new BuildException(msg);
}
try {
project.log("Executing " + commandLine, Project.MSG_VERBOSE);
ssProc = Runtime.getRuntime().exec(commandLine);
// copy input and error to the output stream
StreamPumper inputPumper =
new StreamPumper(ssProc.getInputStream(), "vss", project,
null);
StreamPumper errorPumper =
new StreamPumper(ssProc.getErrorStream(), "vss:error",
project, null);
// starts pumping away the generated output/error
inputPumper.start();
errorPumper.start();
// Wait for everything to finish
ssProc.waitFor();
inputPumper.join();
errorPumper.join();
ssProc.destroy();
// check its exit value
int err = ssProc.exitValue();
if (err != 0) {
project.log("Result: " + err, "vss", Project.MSG_ERR);
}
} catch (java.io.IOException ioe) {
project.log("Failed to execute SourceSafe command");
} catch (InterruptedException ie) {
project.log("Interrupted waiting for ss to complete");
}
}
// Inner class for continually pumping the input stream during
// Process's runtime.
class StreamPumper extends Thread {
private BufferedReader din;
private String name;
private boolean endOfStream = false;
private int SLEEP_TIME = 5;
private Project project;
private PrintWriter fos;
public StreamPumper(InputStream is, String name, Project project,
PrintWriter fos) {
this.din = new BufferedReader(new InputStreamReader(is));
this.name = name;
this.project = project;
this.fos = fos;
}
public void pumpStream()
throws IOException
{
byte[] buf = new byte[BUFFER_SIZE];
if (!endOfStream) {
String line = din.readLine();
if (line != null) {
if (fos == null)
project.log(line, name, Project.MSG_INFO);
else
fos.println(line);
} else {
endOfStream = true;
}
}
}
public void run() {
try {
try {
while (!endOfStream) {
pumpStream();
sleep(SLEEP_TIME);
}
} catch (InterruptedException ie) {}
din.close();
} catch (IOException ioe) {}
}
} // finished class StreamPumper
}
------------------------------------------------
You would invoke it as follows:
<target name="init">
<taskdef name="vss" classname="com.xms.antext.taskdefs.MSVSS"/>
</target>
<vss command="get"
srcdir="vss://myproduct/com/xms/mypackage"
destdir="${basedir}/src/com/xms/mypackage"
recursive="true"
label="v1.0"/>
I have ideas of extending this to support more of the available commands but
don't need them yet so I haven't done it ;-). It borrows the StreamPumper
from the exec task written by James Davidson to get the output from ss.exe
onto the console.
How did you do it??
Cheers,
Andi.