rework credcache for multiple repo support
[tfs.git] / tools / opentf / Driver.cs
blob59f64e9079a57e78e4fc35528fef4596554efc2e
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.Net.Security;
37 using System.Security.Cryptography.X509Certificates;
38 using Mono.GetOptions;
39 using Microsoft.TeamFoundation;
40 using Microsoft.TeamFoundation.Client;
41 using Microsoft.TeamFoundation.VersionControl.Client;
42 using Microsoft.TeamFoundation.Server;
43 using OpenTF.Common;
45 [assembly: AssemblyTitle ("tf.exe")]
46 [assembly: AssemblyVersion ("0.6.0")]
47 [assembly: AssemblyDescription ("Team Foundation Source Control Tool")]
48 [assembly: AssemblyCopyright ("(c) Joel W. Reed")]
50 [assembly: Mono.UsageComplement ("")]
52 [assembly: Mono.About("Team Foundation Source Control Tool")]
53 [assembly: Mono.Author ("Joel W. Reed")]
55 public partial class Driver : ICertificatePolicy, ICredentialsProvider
57 private TeamFoundationServer _tfs;
58 private VersionControlServer _versionControl;
59 private DriverOptions Options = new DriverOptions();
60 private string[] Arguments;
62 private CredentialCache credentialCache = new CredentialCache();
63 private List<string> outputBuffer = null;
65 public void WriteLine(string x)
67 if (outputBuffer != null) outputBuffer.Add(x);
68 else Console.WriteLine(x);
71 public void WriteLine()
73 Console.WriteLine();
76 public string Username
78 get {
79 string serverUrl = GetServerUrl();
80 NetworkCredential creds = credentialCache.GetCredential(new Uri(serverUrl), "NTLM");
81 if (creds == null) return String.Empty;
82 return creds.UserName;
86 public string Domain
88 get {
89 string serverUrl = GetServerUrl();
90 NetworkCredential creds = credentialCache.GetCredential(new Uri(serverUrl), "NTLM");
91 if (creds == null) return String.Empty;
92 return creds.Domain;
96 private string ServerNameToUrl(string server)
98 if (server.StartsWith("http://") || server.StartsWith("https://"))
99 return server;
100 else
101 return String.Format("http://{0}:8080/", server);
104 public string GetServerUrl()
106 if (!String.IsNullOrEmpty(Options.Server))
107 return ServerNameToUrl(Options.Server);
109 WorkspaceInfo info = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
110 if (info == null)
112 string server = Settings.Current.Get("Server.Default");
113 if (!String.IsNullOrEmpty(server))
114 return ServerNameToUrl(server);
116 Console.WriteLine("Unable to determine the team foundation server");
117 Console.WriteLine(" hint: try adding /server:<ip|name>");
118 Environment.Exit((int)ExitCode.Failure);
121 return info.ServerUri.ToString();
124 private string GetLogin(string url)
126 if (!String.IsNullOrEmpty(Options.Login))
127 return Options.Login;
129 // check the keyring
130 string login = Keyring.GetCredentials(url);
131 if (!String.IsNullOrEmpty(login)) return login;
133 // finally prompt if permitted
134 if (Options.NoPrompt) return String.Empty;
135 return PromptForLogin(url);
138 public TeamFoundationServer TeamFoundationServer
140 get
142 if (null != _tfs) return _tfs;
144 string url = GetServerUrl();
145 ICredentials credentials = GetCredentials(new Uri(url), null);
146 _tfs = new TeamFoundationServer(url, credentials);
148 return _tfs;
152 // ICredentialsProvider method
153 public ICredentials GetCredentials(Uri uri, ICredentials failedCredentials)
155 NetworkCredential creds = credentialCache.GetCredential(uri, "NTLM");
156 if (creds != null) return creds;
158 string url = uri.ToString();
159 creds = new TFCredential(GetLogin(url));
161 if (!(String.IsNullOrEmpty(creds.UserName)) &&
162 String.IsNullOrEmpty(creds.Password) && !Options.NoPrompt)
164 Console.Write("Password: ");
165 creds.Password = Console.ReadLine();
168 // save credentials if passed
169 bool saveSetting = Settings.Current.GetAsBool("Credentials.Save");
170 if (saveSetting && !String.IsNullOrEmpty(Options.Login))
171 Keyring.SetCredentials(url, creds.Domain, creds.UserName, creds.Password);
173 credentialCache.Add(uri, "NTLM", creds);
174 return creds;
177 // ICredentialsProvider method
178 public void NotifyCredentialsAuthenticated (Uri uri)
182 public VersionControlServer VersionControlServer
184 get
186 if (null != _versionControl) return _versionControl;
187 _versionControl = (VersionControlServer) TeamFoundationServer.GetService(typeof(VersionControlServer));
189 _versionControl.Conflict += ConflictEventHandler;
190 _versionControl.NonFatalError += ExceptionEventHandler;
192 return _versionControl;
196 public Driver(string[] args)
198 Arguments = args;
199 Options.ProcessArgs(args);
202 static void ConflictEventHandler(Object sender, ConflictEventArgs e)
204 Console.Error.WriteLine(e.Message);
207 static void ExceptionEventHandler(Object sender, ExceptionEventArgs e)
209 // sometimes e.Failure is null, not sure why yet
210 if (e.Failure != null)
211 Console.Error.WriteLine(e.Failure.Message);
214 private bool IsOption(string arg)
216 if (String.IsNullOrEmpty(arg)) return false;
217 return (arg[0] == '-' || arg[0] == '/');
220 public void ProcessAllCommands()
222 List<string> cmdArgs = new List<string>();
224 for (int i=0; i < Arguments.Length; i++)
226 // a little padding between chained command output
227 if (i > 0) Console.WriteLine();
229 // unknown options are not sub commands
230 string scmd = Arguments[i].ToLower();
231 if (IsOption(scmd))
233 cmdArgs.Add(scmd);
234 continue;
237 if (outputBuffer != null)
239 foreach (string line in outputBuffer)
240 cmdArgs.Add(line);
241 outputBuffer = null;
244 // pull in the rest of the args for this subcommand
245 int j;
246 for (j=i+1; j < Arguments.Length; j++)
248 string arg = Arguments[j];
250 // command chaining options
251 if (arg == "%") break;
252 if (arg == "%%")
254 // buffered output across command chain
255 outputBuffer = new List<string>();
256 break;
259 // read more args from stdin
260 if (arg == "-")
262 string line;
263 if (Console.In.Peek() != -1)
265 while ( (line = Console.ReadLine()) != null )
266 cmdArgs.Add(line);
269 continue;
272 cmdArgs.Add(arg);
275 ProcessCommand(scmd, cmdArgs.ToArray());
276 cmdArgs.Clear();
277 i = j;
281 public void ProcessCommand(string cmd, string[] cmdArgs)
283 Type commandType = CommandRegistry.GetCommandType(cmd);
284 if (commandType == null)
286 Console.WriteLine("Unknown command: " + cmd);
287 Environment.Exit((int)ExitCode.UnrecognizedCommand);
290 Command command = (Command) Activator.CreateInstance(commandType, new object[]{ this, cmdArgs });
291 command.Run();
294 // ignoring certificate errors
295 public bool CheckValidationResult (ServicePoint sp,
296 X509Certificate certificate, WebRequest request,
297 int error)
299 return true;
302 public static void Main(string[] args)
304 Driver driver = new Driver(args);
305 ServicePointManager.CertificatePolicy = driver;
307 if (args.Length == 0) {
308 HelpCommand cmd = new HelpCommand(driver, args);
309 cmd.Run();
310 return;
313 // basic auth doesn't seem to work well on mono when POSTing
314 // large data sets via a webservice.
315 AuthenticationManager.Unregister("Basic");
319 driver.ProcessAllCommands();
320 Environment.Exit((int)ExitCode.Success);
322 catch (TeamFoundationServerException e)
324 Console.Error.WriteLine(e.Message);