IEnumerable <IAppSetup> findAppSetupsToRun(string appDirectory)
        {
            var allExeFiles = default(FileInfoBase[]);

            var directory = fileSystem.GetDirectoryInfo(appDirectory);

            if (!directory.Exists)
            {
                log.Warn("findAppSetupsToRun: the folder {0} does not exist", appDirectory);
                return(Enumerable.Empty <IAppSetup>());
            }

            try {
                allExeFiles = directory.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
                                   .Where(f => f.Exists)
                                   .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);
        }
Beispiel #2
0
        IObservable <UpdateInfo> determineUpdateInfo(IEnumerable <ReleaseEntry> localReleases, IEnumerable <ReleaseEntry> remoteReleases, bool ignoreDeltaUpdates)
        {
            localReleases = localReleases ?? Enumerable.Empty <ReleaseEntry>();

            if (remoteReleases == null)
            {
                log.Warn("Release information couldn't be determined due to remote corrupt RELEASES file");
                return(Observable.Throw <UpdateInfo>(new Exception("Corrupt remote RELEASES file")));
            }

            if (localReleases.Count() == remoteReleases.Count())
            {
                log.Info("No updates, remote and local are the same");
                return(Observable.Return <UpdateInfo>(null));
            }

            if (ignoreDeltaUpdates)
            {
                remoteReleases = remoteReleases.Where(x => !x.IsDelta);
            }

            if (!localReleases.Any())
            {
                log.Warn("First run or local directory is corrupt, starting from scratch");

                var latestFullRelease = findCurrentVersion(remoteReleases);
                return(Observable.Return(UpdateInfo.Create(findCurrentVersion(localReleases), new[] { latestFullRelease }, PackageDirectory, appFrameworkVersion)));
            }

            if (localReleases.Max(x => x.Version) > remoteReleases.Max(x => x.Version))
            {
                log.Warn("hwhat, local version is greater than remote version");

                var latestFullRelease = findCurrentVersion(remoteReleases);
                return(Observable.Return(UpdateInfo.Create(findCurrentVersion(localReleases), new[] { latestFullRelease }, PackageDirectory, appFrameworkVersion)));
            }

            return(Observable.Return(UpdateInfo.Create(findCurrentVersion(localReleases), remoteReleases, PackageDirectory, appFrameworkVersion)));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        Task <List <string> > executeInstall(
            string currentAssemblyDir,
            IPackage bundledPackageMetadata,
            bool ignoreDeltaUpdates  = false,
            IObserver <int> progress = null)
        {
            var fxVersion = bundledPackageMetadata.DetectFrameworkVersion();

            var eigenCheckProgress    = new Subject <int>();
            var eigenCopyFileProgress = new Subject <int>();
            var eigenApplyProgress    = new Subject <int>();

            var realCheckProgress    = new Subject <int>();
            var realCopyFileProgress = new Subject <int>();
            var realApplyProgress    = new Subject <int>();

            var eigenUpdateObs = Observable.Using(() => new UpdateManager(currentAssemblyDir, bundledPackageMetadata.Id, fxVersion, TargetRootDirectory), eigenUpdater => {
                // The real update takes longer than the eigenupdate because we're
                // downloading from the Internet instead of doing everything
                // locally, so give it more weight
                Observable.Concat(
                    Observable.Concat(eigenCheckProgress, eigenCopyFileProgress, eigenCopyFileProgress)
                    .Select(x => (x / 3.0) * 0.33),
                    Observable.Concat(realCheckProgress, realCopyFileProgress, realApplyProgress)
                    .Select(x => (x / 3.0) * 0.67))
                .Select(x => (int)x)
                .Subscribe(progress);

                var updateInfoObs = eigenUpdater.CheckForUpdate(ignoreDeltaUpdates, eigenCheckProgress);

                return(updateInfoObs.SelectMany(updateInfo => {
                    log.Info("The checking of releases completed - and there was much rejoicing");

                    if (!updateInfo.ReleasesToApply.Any())
                    {
                        var rootDirectory = TargetRootDirectory ?? Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

                        var version = updateInfo.CurrentlyInstalledVersion;
                        var releaseFolder = String.Format("app-{0}", version.Version);
                        var absoluteFolder = Path.Combine(rootDirectory, version.PackageName, releaseFolder);

                        if (!Directory.Exists(absoluteFolder))
                        {
                            log.Warn("executeInstall: the directory {0} doesn't exist - cannot find the current app?!!?");
                        }
                        else
                        {
                            return Observable.Return(
                                Directory.GetFiles(absoluteFolder, "*.exe", SearchOption.TopDirectoryOnly).ToList());
                        }
                    }

                    foreach (var u in updateInfo.ReleasesToApply)
                    {
                        log.Info("HEY! We should be applying update {0}", u.Filename);
                    }

                    return eigenUpdater.DownloadReleases(updateInfo.ReleasesToApply, eigenCopyFileProgress)
                    .Do(_ => log.Info("The downloading of releases completed - and there was much rejoicing"))
                    .SelectMany(_ => eigenUpdater.ApplyReleases(updateInfo, eigenApplyProgress))
                    .Do(_ => log.Info("The applying of releases completed - and there was much rejoicing"));
                }));
            });

            return(eigenUpdateObs.SelectMany(ret => {
                var updateUrl = bundledPackageMetadata.ProjectUrl != null ? bundledPackageMetadata.ProjectUrl.ToString() : null;
                updateUrl = null; //XXX REMOVE ME
                if (updateUrl == null)
                {
                    realCheckProgress.OnNext(100); realCheckProgress.OnCompleted();
                    realCopyFileProgress.OnNext(100); realCopyFileProgress.OnCompleted();
                    realApplyProgress.OnNext(100); realApplyProgress.OnCompleted();

                    return Observable.Return(ret);
                }

                return Observable.Using(() => new UpdateManager(updateUrl, bundledPackageMetadata.Id, fxVersion, TargetRootDirectory), realUpdater => {
                    return realUpdater.CheckForUpdate(progress: realCheckProgress)
                    .SelectMany(x => realUpdater.DownloadReleases(x.ReleasesToApply, realCopyFileProgress).Select(_ => x))
                    .SelectMany(x => realUpdater.ApplyReleases(x, realApplyProgress))
                    .Select(_ => ret)
                    .LoggedCatch(this, Observable.Return(new List <string>()), "Failed to update to latest remote version");
                });
            }).ToTask());
        }