public CodeCacheManager(XtallStrategy strategy) { if (strategy == null) throw new ArgumentNullException("strategy"); if (strategy.Context.Url == null) throw new ArgumentNullException("strategy.Context.Url"); if (strategy.Context.Manifest == null) throw new ArgumentNullException("strategy.Context.Manifest"); _strategy = strategy; var manifest = _strategy.Context.Manifest; if (manifest.ProductName == null) throw new ArgumentNullException("The manifest must specify a product name"); UrlKey = Uri.EscapeDataString(strategy.Context.Url.ToLower()); _strategy.LogAction("determining the product folder"); ProductFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), manifest.ProductName); _strategy.LogStatus("assigned the product folder as '{0}'", ProductFolder); _strategy.LogAction("determining the site folder"); SiteFolder = Path.Combine(ProductFolder, "Sites", UrlKey); _strategy.LogStatus("assigned the site folder as '{0}'", SiteFolder); _strategy.LogAction("determining the cache folder"); CacheFolder = Path.Combine(ProductFolder, "Cache"); _strategy.LogStatus("assigned the cache folder as '{0}'", CacheFolder); _strategy.LogAction("determining the run folder"); RunFolder = Path.Combine(ProductFolder, "Run", manifest.Md5Hash); _strategy.LogStatus("assigned the run folder as '{0}'", RunFolder); _strategy.LogAction("creating a mutex to guard the cache"); _mutex = new Mutex(false, "XtallCacheGuard:" + manifest.ProductName); _strategy.LogAction("acquiring the mutex to guard the cache"); try { _strategy.LogAction("waiting for access to the cache"); if (!_mutex.WaitOne(TimeSpan.FromSeconds(5))) { _mutex.Dispose(); _mutex = null; throw new Exception("Another instance of this application is currently updating your computer. You may retry after it has finished."); } } catch (AbandonedMutexException) { // suppressed; this is OK (for us...prolly not for the poor sot that died) } _strategy.LogStatus("acquired access to the cache"); }
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(); }