ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Brynjar Glesnes" <brynjar.gles...@entragroup.com>
Subject Proposition to handle getting
Date Wed, 17 Oct 2001 08:25:33 GMT
Due to needs in my project I have modified
org.apache.tools.ant.taskdefs.optional.vss.MSVSS and
org.apache.tools.ant.taskdefs.optional.vss.MSVSSGET to handle the folloing
scenario:

I am getting the latest version of my project from MS SourceSafe to my
development directory in which some files are checked out. When using
MSVSSGET (version 1.4.1) the build fails, with:

   [vssget] $/MyProject/mypackage:
   [vssget]
   [vssget] A writable copy of C:\projects\myproject\mypackage\A.java
already exists

I am using JDK 1.3.1 and MS SourceSafe 6.0.

>From MSDN I have found an overview of options for ss GET
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ssusexp98/
html/cmdline_switchg.asp). There are four options to specify how local
writable copies are handled:

-GWA Displays a dialog box asking the user to choose between replacing,
skipping, or merging write-only files on Get Latest Version and Check Out
operations.
-GWM Merges write-only files on certain operations (Get and Check Out).
-GWR Replaces write-only files on certain operations (Get and Check Out).
-GWS Skips write-only files on certain operations (Get and Check Out).

Thus I have made the following proposition to
org.apache.tools.ant.taskdefs.optional.vss.MSVSS and
org.apache.tools.ant.taskdefs.optional.vss.MSVSSGET that handles these
options:

MSVSS:

public abstract class MSVSS extends Task {

    private String m_SSDir = "";
    private String m_vssLogin = null;
    private String m_vssPath = null;
    private String m_serverPath = null;

    /**
     * Set the directory where ss.exe is located
     *
     * @param dir the directory containing ss.exe
     */
    public final void setSsdir(String dir) {
        m_SSDir = project.translatePath(dir);
    }

    /**
     * Builds and returns the command string to execute ss.exe
     */
    public final String getSSCommand() {
        String toReturn = m_SSDir;
        if ( !toReturn.equals("") && !toReturn.endsWith("\\") ) {
            toReturn += "\\";
        }
        toReturn += SS_EXE;

        return toReturn;
    }

    /**
     * Set the login to use when accessing vss.
     * <p>
     * Should be formatted as username,password
     *
     * @param login the login string to use
     */
    public final void setLogin(String login) {
        m_vssLogin = login;
    }

    /**
     * @return the appropriate login command if the 'login' attribute was
specified, otherwise an empty string
     */
    public void getLoginCommand(Commandline cmd) {
        if ( m_vssLogin == null ) {
            return;
        } else {
            cmd.createArgument().setValue(FLAG_LOGIN + m_vssLogin);
        }
    }

    /**
     * Set the path to the item in vss to operate on
     * <p>
     * Ant can't cope with a '$' sign in an attribute so we have to add it
here.
     * Also we strip off any 'vss://' prefix which is an XMS special and
should probably be removed!
     *
     * @param vssPath
     */
    public final void setVsspath(String vssPath) {
        if ( vssPath.startsWith("vss://") ) {
            m_vssPath= PROJECT_PREFIX + vssPath.substring(5);
        } else {
            m_vssPath = PROJECT_PREFIX + vssPath;
        }
    }

    /**
     * @return m_vssPath
     */
    public String getVsspath() {
        return m_vssPath;
    }

    /**
     * Set the path to the location of the ss.ini
     *
     * @param serverPath
     */
    public final void setServerpath(String serverPath) {
        m_serverPath = serverPath;
    }

    protected int run(Commandline cmd) {
        try {
            Execute exe = new Execute(new LogStreamHandler(this,
                                                           Project.MSG_INFO,

Project.MSG_WARN));

            // If location of ss.ini is specified we need to set the
            // environment-variable SSDIR to this value
            if (m_serverPath != null) {
                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=" + m_serverPath;

                exe.setEnvironment(newEnv);
            }

            exe.setAntRun(project);
            exe.setWorkingDirectory(project.getBaseDir());
            exe.setCommandline(cmd.getCommandline());
            return exe.execute();
        } catch (java.io.IOException e) {
            throw new BuildException(e, location);
        }
    }

    /**
     * Constant for the thing to execute
     */
    private static final String SS_EXE = "ss";
    /** */
    public static final String PROJECT_PREFIX = "$";

    /**
     * The 'Get' command
     */
    public static final String COMMAND_GET = "Get";
    /**
     * The 'Checkout' command
     */
    public static final String COMMAND_CHECKOUT = "Checkout";
    /**
     * The 'Checkin' command
     */
    public static final String COMMAND_CHECKIN = "Checkin";
    /**
     * The 'Label' command
     */
    public static final String COMMAND_LABEL = "Label";
    /**
     * The 'History' command
     */
    public static final String COMMAND_HISTORY = "History";

    /** */
    public static final String FLAG_LOGIN = "-Y";
    /** */
    public static final String FLAG_OVERRIDE_WORKING_DIR = "-GL";
    /** */
    public static final String FLAG_AUTORESPONSE_DEF = "-I-";
    /** */
    public static final String FLAG_AUTORESPONSE_YES = "-I-Y";
    /** */
    public static final String FLAG_AUTORESPONSE_NO = "-I-N";
    /** */
    public static final String FLAG_RECURSION = "-R";
    /** */
    public static final String FLAG_VERSION = "-V";
    /** */
    public static final String FLAG_VERSION_DATE = "-Vd";
    /** */
    public static final String FLAG_VERSION_LABEL = "-VL";
    /** */
    public static final String FLAG_WRITABLE = "-W";
    /** */
    public static final String VALUE_NO = "-N";
    /** */
    public static final String VALUE_YES = "-Y";
    /** */
    public static final String FLAG_QUIET = "-O-";
    /** */
    public static final String FLAG_REPLACEWRITABLE_ASK = "-GWA";
    /** */
    public static final String FLAG_REPLACEWRITABLE_MERGE = "-GWM";
    /** */
    public static final String FLAG_REPLACEWRITABLE_REPLACE = "-GWR";
    /** */
    public static final String FLAG_REPLACEWRITABLE_SKIP = "-GWS";
}

The code added is the four flags at the bottom to handle the new options.

MSVSSGET:

public class MSVSSGET extends MSVSS {

    private String m_LocalPath = null;
    private boolean m_Recursive = false;
    private boolean m_Writable = false;
    private String m_Version = null;
    private String m_Date = null;
    private String m_Label = null;
    private String m_AutoResponse = null;
    private boolean m_Quiet = false;
    private String m_ReplaceWritable = null;

    /**
     * Executes the task.
     * <p>
     * Builds a command line to execute ss and then calls Exec's run method
     * to execute the command line.
     */
    public void execute() throws BuildException {
        Commandline commandLine = new Commandline();
        int result = 0;

        // first off, make sure that we've got a command and a vssdir ...
        if (getVsspath() == null) {
            String msg = "vsspath attribute must be set!";
            throw new BuildException(msg, location);
        }

        // now look for illegal combinations of things ...

        // build the command line from what we got the format is
        // ss Get VSS items [-G] [-H] [-I-] [-N] [-O] [-R] [-V] [-W] [-Y]
[-?]
        // as specified in the SS.EXE help
        commandLine.setExecutable(getSSCommand());
        commandLine.createArgument().setValue(COMMAND_GET);

        // VSS items
        commandLine.createArgument().setValue(getVsspath());
        // -GL
        getLocalpathCommand(commandLine);
        // -GWA or -GWM or -GWR or -GWS
        getReplaceWritableCommand(commandLine);
        // -I- or -I-Y or -I-N
        getAutoresponse(commandLine);
        // -O-
        getQuietCommand(commandLine);
        // -R
        getRecursiveCommand(commandLine);
        // -V
        getVersionCommand(commandLine);
        // -W
        getWritableCommand(commandLine);
        // -Y
        getLoginCommand(commandLine);

        result = run(commandLine);
        if ( result != 0 ) {
            String msg = "Failed executing: " + commandLine.toString();
            throw new BuildException(msg, location);
        }
    }

    /**
     * Set the local path.
     */
    public void setLocalpath(Path localPath) {
        m_LocalPath = localPath.toString();
    }

    /**
     * Builds and returns the -GL flag command if required
     * <p>
     * The localpath is created if it didn't exist
     */
    public void getLocalpathCommand(Commandline cmd) {
        if (m_LocalPath == null) {
            return;
        } else {
            // make sure m_LocalDir exists, create it if it doesn't
            File dir = project.resolveFile(m_LocalPath);
            if (!dir.exists()) {
                boolean done = dir.mkdirs();
                if (done == false) {
                    String msg = "Directory " + m_LocalPath + " creation was
not " +
                        "successful for an unknown reason";
                    throw new BuildException(msg, location);
                }
                project.log("Created dir: " + dir.getAbsolutePath());
            }

            cmd.createArgument().setValue(FLAG_OVERRIDE_WORKING_DIR +
m_LocalPath);
        }
    }

    /**
     * Set behaviour recursive or non-recursive
     */
    public void setRecursive(boolean recursive) {
        m_Recursive = recursive;
    }

    /**
     * @return the 'recursive' command if the attribute was 'true',
otherwise an empty string
     */
    public void getRecursiveCommand(Commandline cmd) {
        if ( !m_Recursive ) {
            return;
        } else {
            cmd.createArgument().setValue(FLAG_RECURSION);
        }
    }

    /**
     * Sets/clears quiet mode
     */
    public final void setQuiet (boolean quiet) {
        this.m_Quiet=quiet;
    }

    public void getQuietCommand (Commandline cmd) {
        if (m_Quiet) {
            cmd.createArgument().setValue (FLAG_QUIET);
        }
    }

    /**
     * Set behaviour, used in get command to make files that are 'got'
writable
     */
    public final void setWritable(boolean argWritable) {
        m_Writable = argWritable;
    }

    /**
     * @return the 'make writable' command if the attribute was 'true',
otherwise an empty string
     */
    public void getWritableCommand(Commandline cmd) {
        if ( !m_Writable ) {
            return;
        } else {
            cmd.createArgument().setValue(FLAG_WRITABLE);
        }
    }

    /**
     * Set the stored version string
     * <p>
     * Note we assume that if the supplied string has the value "null" that
something
     * went wrong and that the string value got populated from a null
object. This
     * happens if a ant variable is used e.g. version="${ver_server}" when
ver_server
     * has not been defined to ant!
     */
    public void setVersion(String version) {
        if (version.equals("") || version.equals("null") ) {
            m_Version = null;
        } else {
            m_Version = version;
        }
    }

    /**
     * Set the stored date string
     * <p>
     * Note we assume that if the supplied string has the value "null" that
something
     * went wrong and that the string value got populated from a null
object. This
     * happens if a ant variable is used e.g. date="${date}" when date
     * has not been defined to ant!
     */
    public void setDate(String date) {
        if (date.equals("") || date.equals("null") ) {
            m_Date = null;
        } else {
            m_Date = date;
        }
    }

    /**
     * Set the labeled version to operate on in SourceSafe
     * <p>
     * Note we assume that if the supplied string has the value "null" that
something
     * went wrong and that the string value got populated from a null
object. This
     * happens if a ant variable is used e.g. label="${label_server}" when
label_server
     * has not been defined to ant!
     */
    public void setLabel(String label) {
        if ( label.equals("") || label.equals("null") ) {
            m_Label = null;
        } else {
            m_Label = label;
        }
    }

    /**
     * Simple order of priority. Returns the first specified of version,
date, label
     * If none of these was specified returns ""
     */
    public void getVersionCommand(Commandline cmd) {

        if ( m_Version != null) {
            cmd.createArgument().setValue(FLAG_VERSION + m_Version);
        } else if ( m_Date != null) {
            cmd.createArgument().setValue(FLAG_VERSION_DATE + m_Date);
        } else if (m_Label != null) {
            cmd.createArgument().setValue(FLAG_VERSION_LABEL + m_Label);
        }
    }

    public void setAutoresponse(String response){
        if ( response.equals("") || response.equals("null") ) {
            m_AutoResponse = null;
        } else {
            m_AutoResponse = response;
        }
    }

    /**
     * Checks the value set for the autoResponse.
     * if it equals "Y" then we return -I-Y
     * if it equals "N" then we return -I-N
     * otherwise we return -I
     */
    public void getAutoresponse(Commandline cmd) {

        if ( m_AutoResponse == null) {
            cmd.createArgument().setValue(FLAG_AUTORESPONSE_DEF);
        } else if ( m_AutoResponse.equalsIgnoreCase("Y")) {
            cmd.createArgument().setValue(FLAG_AUTORESPONSE_YES);

        } else if ( m_AutoResponse.equalsIgnoreCase("N")) {
            cmd.createArgument().setValue(FLAG_AUTORESPONSE_NO);
        }else {
            cmd.createArgument().setValue(FLAG_AUTORESPONSE_DEF);
        } // end of else

    }

    public void setReplaceWritable(String replace) {
        if ( replace.equals("") || replace.equals("null") ) {
            m_ReplaceWritable = null;
        } else {
            m_ReplaceWritable = replace;
        }
    }

    /**
     * Checks the value for replacewritable.
     * if it equals "ask" then we return -GWA
     * if it equals "merge" then we return -GWM
     * if it equals "replace" then we return -GWR
     * if it equals "skip" then we return -GWS
     * otherwise we return ""
     */
    public void getReplaceWritableCommand(Commandline cmd) {

        if ( m_ReplaceWritable == null ) {
            return;
        }

        if ( m_ReplaceWritable.equalsIgnoreCase("ask") ) {
            cmd.createArgument().setValue(FLAG_REPLACEWRITABLE_ASK);
        } else if ( m_ReplaceWritable.equalsIgnoreCase("merge") )

            cmd.createArgument().setValue(FLAG_REPLACEWRITABLE_MERGE);
        } else if ( m_ReplaceWritable.equalsIgnoreCase("replace") ) {
            cmd.createArgument().setValue(FLAG_REPLACEWRITABLE_REPLACE);
        } else if ( m_ReplaceWritable.equalsIgnoreCase("skip") ) {
            cmd.createArgument().setValue(FLAG_REPLACEWRITABLE_SKIP);
        }

    }

}

...with the following addition to the javadoc:

 *   <tr>
 *      <td>replaceWritable</td>
 *      <td>How to treat a local writable version of a file. By default,
 *      this isn't treated. When set -GWA (ask), -GWM (merge), -GMR
(replace)
 *      or -GWS (skip) is added to the command.
 *      <td>No<td>
 *   </tr>

The code added is a new instance variable m_ReplaceWritable, the new methods
public void setReplaceWritable(String replace) and public void
getReplaceWritableCommand(Commandline cmd) and calling
getReplaceWritableCommand from within execute().

I have tested the added code in my environment (repeated: JDK 1.3.1, Ant
1.4.1, MS VSS 6.0) with the following results:

Property replaceWritable not specified: No change to before (i.e. no option
added to the command).
Property replaceWritable="ask": Works only when autoresponse="Y", when it
works the same way as replace. When autoresponse="N" the build fails just
like before. This probably should be removed. I have left it for reference
though!
Property replaceWritable="merge": In my environment the local copy is left
unchanged, which is what I would expect from skip. This appears to be a bug
with MS VSS - works fine otherwise.
Property replaceWritable="replace": The local copy is replaced as expected -
works fine!
Property replaceWritable="skip": The build fails as before with the same
message. Since I have a far lesser understanding of the inner workings of
Ant than you, I have left the code - because as I understand ss GET returns
a warning and not an error in this case and you may have good ways of
treating such a situation.

I hope that this is useful:)

Regards
Brynjar Glesnes


Mime
View raw message