IEnumerable <IAppSetup> findAppSetupsToRun(string appDirectory) { var allExeFiles = default(FileInfoBase[]); try { allExeFiles = fileSystem.GetDirectoryInfo(appDirectory).GetFiles("*.exe"); } catch (UnauthorizedAccessException ex) { // NB: This can happen if we run into a MoveFileEx'd directory, // where we can't even get the list of files in it. log.WarnException("Couldn't search directory for IAppSetups: " + appDirectory, ex); throw; } var locatedAppSetups = allExeFiles .Select(x => loadAssemblyOrWhine(x.FullName)).Where(x => x != null) .SelectMany(x => x.GetModules()) .SelectMany(x => { try { return(x.GetTypes().Where(y => typeof(IAppSetup).IsAssignableFrom(y))); } catch (ReflectionTypeLoadException ex) { log.WarnException("Couldn't load types from module", ex); return(Enumerable.Empty <Type>()); } }) .Select(createInstanceOrWhine).Where(x => x != null) .ToArray(); return(locatedAppSetups.Length > 0 ? locatedAppSetups : allExeFiles.Select(x => new DidntFollowInstructionsAppSetup(x.FullName)).ToArray()); }
IObservable <UpdateInfo> checkForUpdate(bool ignoreDeltaUpdates = false, IObserver <int> progress = null) { IEnumerable <ReleaseEntry> localReleases = Enumerable.Empty <ReleaseEntry>(); progress = progress ?? new Subject <int>(); try { var file = fileSystem.GetFileInfo(LocalReleaseFile).OpenRead(); // NB: sr disposes file using (var sr = new StreamReader(file, Encoding.UTF8)) { localReleases = ReleaseEntry.ParseReleaseFile(sr.ReadToEnd()); } } catch (Exception ex) { // Something has gone wrong, we'll start from scratch. log.WarnException("Failed to load local release list", ex); initializeClientAppDirectory(); } IObservable <string> releaseFile; // Fetch the remote RELEASES file, whether it's a local dir or an // HTTP URL try { if (isHttpUrl(updateUrlOrPath)) { log.Info("Downloading RELEASES file from {0}", updateUrlOrPath); releaseFile = urlDownloader.DownloadUrl(String.Format("{0}/{1}", updateUrlOrPath, "RELEASES"), progress); } else { log.Info("Reading RELEASES file from {0}", updateUrlOrPath); var fi = fileSystem.GetFileInfo(Path.Combine(updateUrlOrPath, "RELEASES")); using (var sr = new StreamReader(fi.OpenRead(), Encoding.UTF8)) { var text = sr.ReadToEnd(); releaseFile = Observable.Return(text); } progress.OnNext(100); progress.OnCompleted(); } } catch (Exception ex) { progress.OnCompleted(); return(Observable.Throw <UpdateInfo>(ex)); } var ret = releaseFile .Select(ReleaseEntry.ParseReleaseFile) .SelectMany(releases => determineUpdateInfo(localReleases, releases, ignoreDeltaUpdates)) .PublishLast(); ret.Connect(); return(ret); }
public IObservable <List <string> > ExecuteInstall(string currentAssemblyDir, IPackage bundledPackageMetadata, IObserver <int> progress = null) { progress = progress ?? new Subject <int>(); // NB: This bit of code is a bit clever. The binaries that WiX // has installed *itself* meets the qualifications for being a // Squirrel update directory (a RELEASES file and the corresponding // NuGet packages). // // So, in order to reuse some code and not write the same things // twice we're going to "Eigenupdate" from our own directory; // UpdateManager will operate in bootstrap mode and create a // local directory for us. // // Then, we create a *new* UpdateManager whose target is the normal // update URL - we can then apply delta updates against the bundled // NuGet package to get up to vCurrent. The reason we go through // this rigamarole is so that developers don't have to rebuild the // installer as often (never, technically). var updateUsingDeltas = executeInstall(currentAssemblyDir, bundledPackageMetadata, progress: progress) .ToObservable() .ObserveOn(RxApp.DeferredScheduler) .Catch <List <string>, Exception>(ex => { log.WarnException("Updating using deltas has failed", ex); return(executeInstall(currentAssemblyDir, bundledPackageMetadata, true, progress) .ToObservable()); }); return(updateUsingDeltas); }
IEnumerable <IAppSetup> findAppSetupsToRun(string appDirectory) { var allExeFiles = default(FileInfoBase[]); try { allExeFiles = fileSystem.GetDirectoryInfo(appDirectory).GetFiles("*.exe"); } catch (UnauthorizedAccessException ex) { // NB: This can happen if we run into a MoveFileEx'd directory, // where we can't even get the list of files in it. log.WarnException("Couldn't search directory for IAppSetups: " + appDirectory, ex); return(Enumerable.Empty <IAppSetup>()); } var locatedAppSetups = allExeFiles .Select(x => loadAssemblyOrWhine(x.FullName)).Where(x => x != null) .SelectMany(x => x.GetModules()) .SelectMany(x => { try { return(x.GetTypes().Where(y => typeof(IAppSetup).IsAssignableFrom(y))); } catch (ReflectionTypeLoadException ex) { var message = String.Format("Couldn't load types from module {0}", x.FullyQualifiedName); log.WarnException(message, ex); ex.LoaderExceptions.ForEach(le => log.WarnException("LoaderException found", le)); return(Enumerable.Empty <Type>()); } }) .Select(createInstanceOrWhine).Where(x => x != null) .ToArray(); if (!locatedAppSetups.Any()) { log.Warn("Could not find any AppSetup instances"); allExeFiles.ForEach(f => log.Info("We have an exe: {0}", f.FullName)); return(allExeFiles.Select(x => new DidntFollowInstructionsAppSetup(x.FullName)) .ToArray()); } return(locatedAppSetups); }
IObservable <UpdateInfo> checkForUpdate(bool ignoreDeltaUpdates = false, IObserver <int> progress = null) { var localReleases = Enumerable.Empty <ReleaseEntry>(); progress = progress ?? new Subject <int>(); try { var file = fileSystem.GetFileInfo(LocalReleaseFile).OpenRead(); // NB: sr disposes file using (var sr = new StreamReader(file, Encoding.UTF8)) { localReleases = ReleaseEntry.ParseReleaseFile(sr.ReadToEnd()); } } catch (Exception ex) { // Something has gone wrong, we'll start from scratch. log.WarnException("Failed to load local release list", ex); initializeClientAppDirectory(); } IObservable <string> releaseFile; // Fetch the remote RELEASES file, whether it's a local dir or an // HTTP URL try { if (isHttpUrl(updateUrlOrPath)) { log.Info("Downloading RELEASES file from {0}", updateUrlOrPath); releaseFile = urlDownloader.DownloadUrl(String.Format("{0}/{1}", updateUrlOrPath, "RELEASES"), progress) .Catch <string, TimeoutException>(ex => { log.Info("Download timed out (returning blank release list)"); return(Observable.Return(String.Empty)); }) .Catch <string, WebException>(ex => { log.InfoException("Download resulted in WebException (returning blank release list)", ex); return(Observable.Return(String.Empty)); }); } else { log.Info("Reading RELEASES file from {0}", updateUrlOrPath); if (!fileSystem.GetDirectoryInfo(updateUrlOrPath).Exists) { var message = String.Format( "The directory {0} does not exist, something is probably broken with your application", updateUrlOrPath); var ex = new SquirrelConfigurationException(message); return(Observable.Throw <UpdateInfo>(ex)); } var fi = fileSystem.GetFileInfo(Path.Combine(updateUrlOrPath, "RELEASES")); if (!fi.Exists) { var message = String.Format( "The file {0} does not exist, something is probably broken with your application", fi.FullName); log.Warn(message); var packages = fileSystem.GetDirectoryInfo(updateUrlOrPath).GetFiles("*.nupkg"); if (packages.Length == 0) { var ex = new SquirrelConfigurationException(message); return(Observable.Throw <UpdateInfo>(ex)); } // NB: Create a new RELEASES file since we've got a directory of packages ReleaseEntry.WriteReleaseFile( packages.Select(x => ReleaseEntry.GenerateFromFile(x.FullName)), fi.FullName); } using (var sr = new StreamReader(fi.OpenRead(), Encoding.UTF8)) { var text = sr.ReadToEnd(); releaseFile = Observable.Return(text); } progress.OnNext(100); progress.OnCompleted(); } } catch (Exception ex) { progress.OnCompleted(); return(Observable.Throw <UpdateInfo>(ex)); } // Return null if no updates found var ret = releaseFile .Select(ReleaseEntry.ParseReleaseFile) .SelectMany(releases => releases.Any() ? determineUpdateInfo(localReleases, releases, ignoreDeltaUpdates) : Observable.Return <UpdateInfo>(null)) .PublishLast(); ret.Connect(); return(ret); }