001: /**
002: *
003: */package net.sourceforge.cruisecontrol.bootstrappers;
004:
005: import net.sourceforge.cruisecontrol.Bootstrapper;
006: import net.sourceforge.cruisecontrol.CruiseControlException;
007: import net.sourceforge.cruisecontrol.util.Commandline;
008: import net.sourceforge.cruisecontrol.util.ValidationHelper;
009:
010: import org.apache.log4j.Logger;
011:
012: /**
013: * Bootstrapper for Microsoft Visual Studio Team Foundation Server.
014: *
015: * The TFS Bootstrapper will perform a get latest for a single ItemSpec before the build process is run.
016: *
017: * This relies on there being an existing TFS workspace and a working folder mapping existing between the local
018: * bootstrap location and the server location for that
019: *
020: * @author <a href="http://www.woodwardweb.com">Martin Woodward</a>
021: */
022: public class TFSBootstrapper implements Bootstrapper {
023: private static final Logger LOG = Logger
024: .getLogger(TFSBootstrapper.class);
025:
026: /** Configuration parameters */
027:
028: private String itemSpec;
029: private String username;
030: private String password;
031: private String tfPath = "tf";
032: private String options;
033: private boolean recursive = false;
034: private boolean force = false;
035:
036: /**
037: * @see net.sourceforge.cruisecontrol.Bootstrapper#bootstrap()
038: */
039: public void bootstrap() throws CruiseControlException {
040: buildGetCommand().executeAndWait(LOG);
041: }
042:
043: /**
044: * Generate the tf get command in the format
045: *
046: * tf get -noprompt c:\cc\projects\connectfour\build.xml -recursive -login:DOMAIN\name,password
047: *
048: * For more details on get command syntax see
049: *
050: * <a href="http://msdn2.microsoft.com/en-us/library/fx7sdeyf(VS.80).aspx">
051: * http://msdn2.microsoft.com/en-us/library/fx7sdeyf(VS.80).aspx </a>
052: *
053: * @return a tfs get CommandLine instance
054: * @throws CruiseControlException
055: */
056: protected Commandline buildGetCommand()
057: throws CruiseControlException {
058: Commandline command = new Commandline();
059: command.setExecutable(tfPath);
060: command.createArgument().setValue("get");
061: command.createArgument().setValue("-noprompt");
062: command.createArgument().setValue(itemSpec);
063: if (recursive) {
064: command.createArgument().setValue("-recursive");
065: }
066: if (force) {
067: command.createArgument().setValue("-force");
068: }
069: if (username != null && password != null) {
070: command.createArgument().setValue(
071: "-login:" + username + "," + password + "");
072: }
073: if (options != null) {
074: command.createArgument().setValue(options);
075: }
076:
077: LOG.debug("Executing command: " + command);
078: return command;
079: }
080:
081: /**
082: * @see net.sourceforge.cruisecontrol.Bootstrapper#validate()
083: */
084: public void validate() throws CruiseControlException {
085: ValidationHelper.assertIsSet(itemSpec, "itemSpec", this
086: .getClass());
087: }
088:
089: // --- Property setters
090:
091: /**
092: * Mandatory The path to issue a get for
093: *
094: * @param itemSpec
095: */
096: public void setItemSpec(String itemSpec) {
097: this .itemSpec = itemSpec;
098: }
099:
100: /**
101: * The username to use when talking to TFS. This should be in the format DOMAIN\name or name@DOMAIN if the domain
102: * portion is required. Note that name@DOMAIN is the easiest format to use from Unix based systems. If the username
103: * contains characters likely to cause problems when passed to the command line then they can be escaped in quotes
104: * by passing the following into the config.xml:- <code>&quot;name&quot;</code>
105: *
106: * If the username or password is not supplied, then none will be passed to the command. On windows system using the
107: * Microsoft tf.exe command line client, the credential of that the CruiseControl process is running as will be used
108: * for the connection to the server.
109: *
110: * @param username
111: * the username to set
112: */
113: public void setUsername(String username) {
114: this .username = username;
115: }
116:
117: /**
118: * If the username or password is not supplied, then none will be passed to the command. On windows system using the
119: * Microsoft tf.exe command line client, the credential of that the CruiseControl process is running as will be used
120: * for the connection to the server.
121: *
122: * @param password
123: * the password to set
124: */
125: public void setPassword(String password) {
126: this .password = password;
127: }
128:
129: /**
130: * The path to the tf command. Either the "tf.exe" command provided by Microsoft in the <a
131: * href="http://download.microsoft.com/download/2/a/d/2ad44873-8ccb-4a1b-9c0d-23224b3ba34c/VSTFClient.img"> Team
132: * Explorer Client</a> can be used or the "tf" command line client provided by <a
133: * href="http://www.teamprise.com">Teamprise</a> can be used. The Teamprise client works cross-platform. Both
134: * clients are free to use provided the developers using CruiseControl have a TFS Client Access License (and in the
135: * case of Teamprise a license to the Teamprise command line client).
136: *
137: * If not supplied then the command "tf" will be called and CruiseControl will rely on that command being able to be
138: * found in the path.
139: *
140: * @param tfPath
141: * the path where the tf command resides
142: */
143: public void setTfPath(String tfPath) {
144: this .tfPath = tfPath;
145: }
146:
147: /**
148: * Flag to indicate if the tf get should be performed recursively or not. In the usual bootstrapper scenario, the
149: * bootstrapper would be located in a single file (build.xml) or at one level in the bootstrapper directory.
150: * Therefore, if not passed, recursive will default to false, i.e. not recursive.
151: *
152: * @param recursive
153: */
154: public void setRecursive(boolean recursive) {
155: this .recursive = recursive;
156: }
157:
158: /**
159: * Flag to indicate of the tf get command should be performed using the /force switch. By default, TFS will only
160: * download files that the server thinks have changed since the last time you told it you were modifying or geting
161: * files into your local TFS workspace. It will also not overwrite locally writable files. Setting the force option
162: * will make TFS always download the files and overwrite any that happen to be locally writable - however this has
163: * the expense of significantly increasing the network traffice and increaing the time to perform the bootstrap
164: * process.
165: *
166: * @param force
167: */
168: public void setForce(boolean force) {
169: this .force = force;
170: }
171:
172: /**
173: * An optional argument to add to the end of the tf get command that is generated.
174: *
175: * @param options
176: * the options to set
177: */
178: public void setOptions(String options) {
179: this.options = options;
180: }
181:
182: }
|