BUGFIX: tf online <path> shouldn't croak if <path> is an add awaiting
[tfs.git] / tools / opentf / Driver.cs
blob318bcbcd8616c321581f1d2150b9c5e0014c3bb7
1 //
2 // Driver.cs
3 //
4 // Authors:
5 // Joel Reed (joelwreed@gmail.com)
6 //
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System;
30 using System.Reflection;
31 using System.Collections.Generic;
32 using System.Collections.Specialized;
33 using System.Net;
34 using System.IO;
35 using System.Text;
36 using System.Security.Cryptography.X509Certificates;
37 using Mono.GetOptions;
38 using Microsoft.TeamFoundation;
39 using Microsoft.TeamFoundation.Client;
40 using Microsoft.TeamFoundation.VersionControl.Client;
41 using Microsoft.TeamFoundation.Server;
43 [assembly: AssemblyTitle ("tf.exe")]
44 [assembly: AssemblyVersion ("0.5.3")]
45 [assembly: AssemblyDescription ("Team Foundation Source Control Tool")]
46 [assembly: AssemblyCopyright ("(c) Joel W. Reed")]
48 [assembly: Mono.UsageComplement ("")]
50 [assembly: Mono.About("Team Foundation Source Control Tool")]
51 [assembly: Mono.Author ("Joel W. Reed")]
53 public partial class Driver : ICertificatePolicy, ICredentialsProvider
55 private CredentialCache credentialCache = new CredentialCache();
56 private TeamFoundationServer _tfs;
57 private VersionControlServer _versionControl;
58 private DriverOptions Options = new DriverOptions();
59 private string[] Arguments;
61 private string domain;
62 private string username;
63 private string password;
64 private string serverUrl;
65 private List<string> outputBuffer = null;
67 public void WriteLine(string x)
69 if (outputBuffer != null) outputBuffer.Add(x);
70 else Console.WriteLine(x);
73 public void WriteLine()
75 Console.WriteLine();
78 public string Domain
80 get {
81 GetUserCredentials();
82 return domain;
86 public string Username
88 get {
89 GetUserCredentials();
90 return username;
94 private string ServerNameToUrl(string server)
96 if (server.StartsWith("http://") || server.StartsWith("https://"))
97 return server;
98 else
99 return String.Format("http://{0}:8080/", server);
102 public string ServerUrl
104 get {
105 if (!String.IsNullOrEmpty(serverUrl)) return serverUrl;
107 if (!String.IsNullOrEmpty(Options.Server))
108 return ServerNameToUrl(Options.Server);
110 WorkspaceInfo info = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
111 if (info == null)
113 string server = Settings.Current.Get("Server.Default");
114 if (!String.IsNullOrEmpty(server))
115 return ServerNameToUrl(server);
117 Console.WriteLine("Unable to determine the team foundation server");
118 Console.WriteLine(" hint: try adding /server:<ip|name>");
119 Environment.Exit((int)ExitCode.Failure);
122 serverUrl = info.ServerUri.ToString();
123 return serverUrl;
127 private string GetLogin()
129 if (!String.IsNullOrEmpty(Options.Login))
130 return Options.Login;
132 // check the keyring
133 string login = TfsKeyring.GetCredentials(ServerUrl);
134 if (!String.IsNullOrEmpty(login)) return login;
136 // finally prompt if permitted
137 if (Options.NoPrompt) return String.Empty;
138 return PromptForLogin(ServerUrl);
141 private void GetUserCredentials()
143 if (! String.IsNullOrEmpty(username)) return;
145 string login = GetLogin();
146 string userinfo = "";
148 int comma = login.IndexOf(",");
149 if (comma != -1)
151 userinfo = login.Substring(0, comma);
152 password = login.Substring(comma+1);
154 else userinfo = login;
156 // try to find domain portion if given
157 int slash = userinfo.IndexOf('\\');
158 if (-1 != slash)
160 domain = userinfo.Substring(0, slash);
161 username = userinfo.Substring(slash+1);
162 return;
165 int atsign = userinfo.IndexOf('@');
166 if (-1 != atsign)
168 username = userinfo.Substring(0, atsign);
169 domain = userinfo.Substring(atsign+1);
170 return;
173 // no domain name
174 username = userinfo;
177 public TeamFoundationServer TeamFoundationServer
179 get
181 if (null != _tfs) return _tfs;
183 ICredentials credentials = GetCredentials(new Uri(ServerUrl), null);
184 _tfs = new TeamFoundationServer(ServerUrl, credentials);
186 return _tfs;
190 // ICredentialsProvider method
191 public ICredentials GetCredentials(Uri uri, ICredentials failedCredentials)
193 NetworkCredential creds = credentialCache.GetCredential(uri, "NTLM");
194 if (creds != null) return creds;
196 GetUserCredentials();
198 if (!(String.IsNullOrEmpty(username)) && String.IsNullOrEmpty(password)
199 && !Options.NoPrompt)
201 Console.Write("Password: ");
202 password = Console.ReadLine();
205 creds = new NetworkCredential(username, password, domain);
206 credentialCache.Add(uri, "NTLM", creds);
207 return creds;
210 // ICredentialsProvider method
211 public void NotifyCredentialsAuthenticated (Uri uri)
215 public VersionControlServer VersionControlServer
217 get
219 if (null != _versionControl) return _versionControl;
220 _versionControl = (VersionControlServer) TeamFoundationServer.GetService(typeof(VersionControlServer));
222 _versionControl.Conflict += ConflictEventHandler;
223 _versionControl.NonFatalError += ExceptionEventHandler;
225 // save credentials if passed
226 bool saveSetting = Settings.Current.GetAsBool("Credentials.Save");
227 if (saveSetting && !String.IsNullOrEmpty(Options.Login))
228 TfsKeyring.SetCredentials(ServerUrl, domain, username, password);
230 return _versionControl;
234 public Driver(string[] args)
236 Arguments = args;
237 Options.ProcessArgs(args);
240 static void ConflictEventHandler(Object sender, ConflictEventArgs e)
242 Console.Error.WriteLine(e.Message);
245 static void ExceptionEventHandler(Object sender, ExceptionEventArgs e)
247 // sometimes e.Failure is null, not sure why yet
248 if (e.Failure != null)
249 Console.Error.WriteLine(e.Failure.Message);
252 private bool IsOption(string arg)
254 if (String.IsNullOrEmpty(arg)) return false;
255 return (arg[0] == '-' || arg[0] == '/');
258 public void ProcessAllCommands()
260 List<string> cmdArgs = new List<string>();
262 for (int i=0; i < Arguments.Length; i++)
264 // a little padding between chained command output
265 if (i > 0) Console.WriteLine();
267 // unknown options are not sub commands
268 string scmd = Arguments[i].ToLower();
269 if (IsOption(scmd))
271 cmdArgs.Add(scmd);
272 continue;
275 if (outputBuffer != null)
277 foreach (string line in outputBuffer)
278 cmdArgs.Add(line);
279 outputBuffer = null;
282 // pull in the rest of the args for this subcommand
283 int j;
284 for (j=i+1; j < Arguments.Length; j++)
286 string arg = Arguments[j];
288 // command chaining options
289 if (arg == "%") break;
290 if (arg == "%%")
292 // buffered output across command chain
293 outputBuffer = new List<string>();
294 break;
297 // read more args from stdin
298 if (arg == "-")
300 string line;
301 if (Console.In.Peek() != -1)
303 while ( (line = Console.ReadLine()) != null )
304 cmdArgs.Add(line);
307 continue;
310 cmdArgs.Add(arg);
313 ProcessCommand(scmd, cmdArgs.ToArray());
314 cmdArgs.Clear();
315 i = j;
319 public void ProcessCommand(string cmd, string[] cmdArgs)
321 Type commandType = CommandRegistry.GetCommandType(cmd);
322 if (commandType == null)
324 Console.WriteLine("Unknown command: " + cmd);
325 Environment.Exit((int)ExitCode.UnrecognizedCommand);
328 Command command = (Command) Activator.CreateInstance(commandType, new object[]{ this, cmdArgs });
329 command.Run();
332 // ignoring certificate errors
333 public bool CheckValidationResult (ServicePoint sp,
334 X509Certificate certificate, WebRequest request, int error)
336 return true;
339 public static void Main(string[] args)
341 Driver driver = new Driver(args);
342 ServicePointManager.CertificatePolicy = driver;
344 if (args.Length == 0) {
345 HelpCommand cmd = new HelpCommand(driver, args);
346 cmd.Run();
347 return;
350 // basic auth doesn't seem to work well on mono when POSTing
351 // large data sets via a webservice.
352 AuthenticationManager.Unregister("Basic");
356 driver.ProcessAllCommands();
357 Environment.Exit((int)ExitCode.Success);
359 catch (TeamFoundationServerException e)
361 Console.Error.WriteLine(e.Message);
362 //Console.WriteLine(driver.Domain + "\\" + driver.Username);