public bool Run(string[] args, XtallStrategy strategy = null) { _args = args; _options = new Options(args); _strategy = strategy ?? new XtallStrategy(); try { _strategy.LogStatus("starting with command line: {0}", string.Join(" ", args)); if (_options.Keyed.Keys.Contains("uninstall:")) { Uninstall(_options.Keyed["uninstall:"]); return false; } if (_options.Loose.Count == 0) throw new ArgumentException("Site URL was not specified on the command line"); _strategy.InternalContext.Url = _options.Loose[0]; var @unsafe = true; // TODO get the strategy to handle this new Uri(_strategy.Context.Url).Scheme != "https"; // TODO: block unsafe unless environment is set up for it if (_options.Keyed.ContainsKey("debug:")) { _strategy.LogStatus("debug requested from the command line; no cache management will be used"); _strategy.InternalContext.Manifest = ManifestManager.Load(File.ReadAllText(_options.Keyed["debug:"])); _strategy.OnVerified(); _strategy.OnStatus("Debugging", 1.0); _strategy.OnSuccess(); } else { _strategy.OnStatus("Connecting and verifying", 0); if (!@unsafe) { _strategy.LogAction("setting the certificate validator"); ServicePointManager.CheckCertificateRevocationList = true; ServicePointManager.ServerCertificateValidationCallback = CheckServerCertificate; } else { _strategy.LogStatus("skipping server authentication checks"); } _strategy.LogAction("getting the manifest"); string manifestXml; using (var ms = new MemoryStream()) { _strategy.GetResource(_strategy.Context.Url + "/info", ms, t => t.StartsWith("text/xml")); ms.Seek(0, SeekOrigin.Begin); using (var sr = new StreamReader(ms)) manifestXml = sr.ReadToEnd(); } _strategy.LogAction("loading the manifest (first 100 characters are '{0}')", manifestXml.Substring(0, 100)); _strategy.InternalContext.Manifest = ManifestManager.Load(manifestXml); _strategy.LogAction("creating a code cache manager"); using (var cacheManager = new CodeCacheManager(_strategy)) { _strategy.LogAction("ensuring the boot package"); var candidate = Assembly.GetEntryAssembly().Location; var bootPath = cacheManager.EnsureBoot(candidate); if (bootPath == null) { _strategy.LogStatus("current process is the appropriate boot process"); _strategy.OnVerified(); _strategy.OnStatus("Loading", 0); UpdateInstall(cacheManager, candidate, _options.Keyed.Keys.Contains("install")); cacheManager.EnsureManifest(); _strategy.OnStatus("Loaded", 1.0); _strategy.OnSuccess(); } else { _strategy.LogStatus("current process is not executing the required image"); _strategy.LogAction("switching to image '{0}'", bootPath); _strategy.OnStatus("Transferring", 0); using (var p = Process.Start(bootPath, string.Join(" ", _args.Select(x => '"' + x + '"')))) { } _strategy.OnTransfer(); } } } } catch (Exception ex) { _strategy.OnFailure(ex); } return _strategy.WaitToProceed(); }
private void UpdateInstall(CodeCacheManager cacheManager, string sourceFile, bool installing) { _strategy.LogAction("ensuring site folder '{0}'", cacheManager.SiteFolder); Directory.CreateDirectory(cacheManager.SiteFolder); var linkBootPath = Path.Combine(cacheManager.SiteFolder, "start.exe"); _strategy.LogAction("copying boot file '{0}' to '{1}'", sourceFile, linkBootPath); try { File.Copy(sourceFile, linkBootPath, true); } catch (Exception x) { _strategy.LogStatus("failed to copy boot file: {0}", x.Message); // this is not completely unexpected; it will normally be because another // instance of the boot file is running from the site folder. It will end // up completing the copy as part of its update process. // TODO: only attempt the copy when the MD5 misses } var manifestPath = Path.Combine(cacheManager.SiteFolder, "manifest.xml"); _strategy.LogAction("writing current manifest to '{0}'", manifestPath); using (var xw = XmlWriter.Create(manifestPath)) ManifestManager.Write(xw, _strategy.Context.Manifest); if (installing) { var installName = _strategy.Context.Manifest.InstalledDisplayName; _strategy.LogAction("writing current manifest to '{0}'", manifestPath); var desktopLink = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), installName + ".lnk"); _strategy.LogAction("creating desktop link '{0}'", desktopLink); ShellLink.CreateShortcut(desktopLink, linkBootPath, args: _strategy.Context.Url); var menuPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), _strategy.Context.Manifest.ProductName); _strategy.LogAction("ensuring menu folder '{0}'", menuPath); Directory.CreateDirectory(menuPath); var menuLink = Path.Combine(menuPath, installName + ".lnk"); _strategy.LogAction("creating menu link '{0}'", menuLink); ShellLink.CreateShortcut(menuLink, linkBootPath, args: _strategy.Context.Url); _strategy.LogAction("writing ARP entries"); using (var arpKey = Registry.CurrentUser.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + cacheManager.UrlKey)) { arpKey.SetValue(Paths.ArpDisplayNameValueName, installName); arpKey.SetValue(Paths.ArpDisplayIconValueName, linkBootPath); arpKey.SetValue(Paths.ArpInstallDateValueName, DateTime.Now.ToString("yyyyMMdd")); // TODO: from subject attributes arpKey.SetValue(Paths.ArpDisplayVersionValueName, version.ToString(4)); // andeverytime // TODO: from subject attributes arpKey.SetValue(Paths.ArpPublisherValueName, "Thomson Reuters"); arpKey.SetValue(Paths.ArpUninstallStringValueName, string.Format("\"{0}\" -uninstall: \"{1}\"", linkBootPath, cacheManager.UrlKey)); arpKey.SetValue(Paths.ArpNoModifyValueName, 1); arpKey.SetValue(Paths.ArpNoRepairValueName, 1); arpKey.SetValue("XtallMenuLink", menuLink); arpKey.SetValue("XtallDesktopLink", desktopLink); arpKey.SetValue(Paths.ArpCommentsValueName, _strategy.Context.Url); } } }