示例#1
0
            public void UpdateLocalReleasesSmokeTest()
            {
                string tempDir;

                using (Utility.WithTempDirectory(out tempDir)) {
                    var packageDir = Directory.CreateDirectory(Path.Combine(tempDir, "theApp", "packages"));

                    new[] {
                        "Squirrel.Core.1.0.0.0-full.nupkg",
                        "Squirrel.Core.1.1.0.0-delta.nupkg",
                        "Squirrel.Core.1.1.0.0-full.nupkg",
                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath("fixtures", x), Path.Combine(tempDir, "theApp", "packages", x)));

                    var urlDownloader = new Mock <IUrlDownloader>();
                    var fixture       = new UpdateManager("http://lol", "theApp", FrameworkVersion.Net40, tempDir, null, urlDownloader.Object);

                    using (fixture) {
                        fixture.UpdateLocalReleasesFile().Last();
                    }

                    var releasePath = Path.Combine(packageDir.FullName, "RELEASES");
                    File.Exists(releasePath).ShouldBeTrue();

                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));
                    entries.Count().ShouldEqual(3);
                }
            }
示例#2
0
        static int Main(string[] args)
        {
            var optParams = ParseCommands.ParseOptions(args);

            if (optParams == null)
            {
                return(-1);
            }

            var targetDir  = optParams["target"];
            var package    = new ReleasePackage(optParams["input"]);
            var targetFile = Path.Combine(targetDir, package.SuggestedReleaseFileName);

            string fullRelease;

            try {
                fullRelease = package.CreateReleasePackage(targetFile,
                                                           optParams["pkgdir"] != "" ? optParams["pkgdir"] : null,
                                                           input => (new Markdown()).Transform(input));
            }
            catch (Exception ex) {
                Console.Error.WriteLine();
                Console.Error.WriteLine("Unexpected exception occurred creating package:");
                Console.Error.WriteLine(ex);
                Console.Error.WriteLine();
                Console.Error.WriteLine();
                return(-4);
            }

            Console.WriteLine("{0};", fullRelease);

            var releaseFile = Path.Combine(targetDir, "RELEASES");

            if (File.Exists(releaseFile))
            {
                var releasesText   = File.ReadAllText(releaseFile, Encoding.UTF8);
                var releaseEntries = ReleaseEntry.ParseReleaseFile(releasesText);

                var previousFullRelease = ReleaseEntry.GetPreviousRelease(releaseEntries, package, targetDir);

                if (previousFullRelease != null &&
                    File.Exists(previousFullRelease.ReleasePackageFile))
                {
                    var deltaFile = Path.Combine(targetDir, package.SuggestedReleaseFileName.Replace("full", "delta"));
                    Console.WriteLine("{0}; {1}", previousFullRelease.InputPackageFile, deltaFile);

                    if (File.Exists(deltaFile))
                    {
                        File.Delete(deltaFile);
                    }

                    var deltaBuilder = new DeltaPackageBuilder();
                    deltaBuilder.CreateDeltaPackage(previousFullRelease, package, deltaFile);
                }
            }

            ReleaseEntry.BuildReleasesFile(targetDir);

            return(0);
        }
示例#3
0
        public async Task Install(bool silentInstall, ProgressSource progressSource, string sourceDirectory = null)
        {
            sourceDirectory = sourceDirectory ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var releasesPath = Path.Combine(sourceDirectory, "RELEASES");

            this.Log().Info("Starting install, writing to {0}", sourceDirectory);

            if (!File.Exists(releasesPath))
            {
                this.Log().Info("RELEASES doesn't exist, creating it at " + releasesPath);
                var nupkgs = (new DirectoryInfo(sourceDirectory)).GetFiles()
                             .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase))
                             .Select(x => ReleaseEntry.GenerateFromFile(x.FullName));

                ReleaseEntry.WriteReleaseFile(nupkgs, releasesPath);
            }

            var ourAppName = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesPath, Encoding.UTF8))
                             .First().PackageName;

            var rootDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

            using (var mgr = new UpdateManager(sourceDirectory, ourAppName, FrameworkVersion.Net45, rootDir)) {
                Directory.CreateDirectory(mgr.RootAppDirectory);

                var updateTarget = Path.Combine(mgr.RootAppDirectory, "Update.exe");
                this.ErrorIfThrows(() => File.Copy(Assembly.GetExecutingAssembly().Location, updateTarget, true),
                                   "Failed to copy Update.exe to " + updateTarget);

                await mgr.FullInstall(silentInstall, progressSource.Raise);

                await this.ErrorIfThrows(() => mgr.CreateUninstallerRegistryEntry(),
                                         "Failed to create uninstaller registry entry");
            }
        }
示例#4
0
        public void WhenReleasesAreOutOfOrderSortByVersion()
        {
            var path          = Path.GetTempFileName();
            var firstVersion  = new Version("1.0.0");
            var secondVersion = new Version("1.1.0");
            var thirdVersion  = new Version("1.2.0");

            var releaseEntries = new[] {
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-delta.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-delta.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.0-full.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-full.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.0.0-full.nupkg"))
            };

            ReleaseEntry.WriteReleaseFile(releaseEntries, path);

            var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();

            Assert.Equal(firstVersion, releases[0].Version);
            Assert.Equal(secondVersion, releases[1].Version);
            Assert.Equal(true, releases[1].IsDelta);
            Assert.Equal(secondVersion, releases[2].Version);
            Assert.Equal(false, releases[2].IsDelta);
            Assert.Equal(thirdVersion, releases[3].Version);
            Assert.Equal(true, releases[3].IsDelta);
            Assert.Equal(thirdVersion, releases[4].Version);
            Assert.Equal(false, releases[4].IsDelta);
        }
        ReleaseEntry readBundledReleasesFile()
        {
            var release = fileSystem.GetFileInfo(Path.Combine(currentAssemblyDir, "RELEASES"));

            if (!release.Exists)
            {
                UserError.Throw("This installer is incorrectly configured, please contact the author",
                                new FileNotFoundException(release.FullName));
                return(null);
            }

            ReleaseEntry ret;

            try {
                var fileText = fileSystem
                               .GetFile(release.FullName)
                               .ReadAllText(release.FullName, Encoding.UTF8);
                ret = ReleaseEntry
                      .ParseReleaseFile(fileText)
                      .Where(x => !x.IsDelta)
                      .OrderByDescending(x => x.Version)
                      .First();
            } catch (Exception ex) {
                this.Log().ErrorException("Couldn't read bundled RELEASES file", ex);
                UserError.Throw("This installer is incorrectly configured, please contact the author", ex);
                return(null);
            }

            return(ret);
        }
            public async Task UpdateLocalReleasesSmokeTest()
            {
                string tempDir;

                using (Utility.WithTempDirectory(out tempDir)) {
                    var appDir     = Path.Combine(tempDir, "theApp");
                    var packageDir = Directory.CreateDirectory(Path.Combine(appDir, "packages"));

                    new[] {
                        "Squirrel.Core.1.0.0.0-full.nupkg",
                        "Squirrel.Core.1.1.0.0-delta.nupkg",
                        "Squirrel.Core.1.1.0.0-full.nupkg",
                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath("fixtures", x), Path.Combine(tempDir, "theApp", "packages", x)));

                    var fixture = new UpdateManager.ApplyReleasesImpl(appDir);

                    await fixture.updateLocalReleasesFile();

                    var releasePath = Path.Combine(packageDir.FullName, "RELEASES");
                    File.Exists(releasePath).ShouldBeTrue();

                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));
                    entries.Count().ShouldEqual(3);
                }
            }
        public void WhenPreReleasesAreOutOfOrderSortByNumericSuffix()
        {
            var path          = Path.GetTempFileName();
            var firstVersion  = new SemanticVersion("1.1.9-beta105");
            var secondVersion = new SemanticVersion("1.2.0-beta9");
            var thirdVersion  = new SemanticVersion("1.2.0-beta10");
            var fourthVersion = new SemanticVersion("1.2.0-beta100");

            var releaseEntries = new[] {
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta1-full.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta9-full.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta100-full.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.1.9-beta105-full.nupkg")),
                ReleaseEntry.ParseReleaseEntry(MockReleaseEntry("Espera-1.2.0-beta10-full.nupkg"))
            };

            ReleaseEntry.WriteReleaseFile(releaseEntries, path);

            var releases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(path)).ToArray();

            Assert.Equal(firstVersion, releases[0].Version);
            Assert.Equal(secondVersion, releases[2].Version);
            Assert.Equal(thirdVersion, releases[3].Version);
            Assert.Equal(fourthVersion, releases[4].Version);
        }
            public async Task InitialInstallSmokeTest()
            {
                string tempDir;

                using (Utility.WithTempDirectory(out tempDir)) {
                    var remotePackageDir = Directory.CreateDirectory(Path.Combine(tempDir, "remotePackages"));
                    var localAppDir      = Path.Combine(tempDir, "theApp");

                    new[] {
                        "Squirrel.Core.1.0.0.0-full.nupkg",
                    }.ForEach(x => File.Copy(IntegrationTestHelper.GetPath("fixtures", x), Path.Combine(remotePackageDir.FullName, x)));

                    using (var fixture = new UpdateManager(remotePackageDir.FullName, "theApp", tempDir)) {
                        await fixture.FullInstall(false, new ProgressSource());
                    }

                    var releasePath = Path.Combine(localAppDir, "packages", "RELEASES");
                    File.Exists(releasePath).ShouldBeTrue();

                    var entries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasePath, Encoding.UTF8));
                    entries.Count().ShouldEqual(1);

                    new[] {
                        "ReactiveUI.dll",
                        "NSync.Core.dll",
                    }.ForEach(x => File.Exists(Path.Combine(localAppDir, "app-1.0.0.0", x)).ShouldBeTrue());
                }
            }
示例#9
0
        private static void ReleasifyElectron(string package, string targetDir = null, string baseUrl = null)
        {
            // check that package is valid
            new ZipPackage(package).GetType();

            if (baseUrl != null)
            {
                if (!Utility.IsHttpUrl(baseUrl))
                {
                    throw new Exception($"Invalid --baseUrl '{baseUrl}'. A base URL must start with http or https and be a valid URI.");
                }

                if (!baseUrl.EndsWith("/"))
                {
                    baseUrl += "/";
                }
            }

            targetDir = targetDir ?? Path.Combine(".", "Releases");

            var di = new DirectoryInfo(targetDir);

            var releaseFilePath  = Path.Combine(di.FullName, "RELEASES");
            var previousReleases = new List <ReleaseEntry>();

            if (File.Exists(releaseFilePath))
            {
                previousReleases.AddRange(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8)));
            }

            var processed = new List <string>();
            var rp        = new ReleasePackage(package, true);

            processed.Add(package);

            var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);

            if (prev != null)
            {
                var deltaBuilder = new DeltaPackageBuilder();

                var dp = deltaBuilder.CreateDeltaPackage(prev, rp,
                                                         Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta")));
                processed.Insert(0, dp.InputPackageFile);
            }

            var newReleaseEntries = processed
                                    .Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl))
                                    .ToList();
            var distinctPreviousReleases = previousReleases
                                           .Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version));
            var releaseEntries = distinctPreviousReleases.Concat(newReleaseEntries).ToList();

            ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);

            var newestFullRelease = releaseEntries.MaxBy(x => x.Version).First(x => !x.IsDelta);

            Console.Out.WriteLine(ReleaseEntry.GenerateFromFile(Path.Combine(di.FullName, newestFullRelease.Filename)).EntryAsString);
        }
示例#10
0
        public void ProcessStart(string exeName, string arguments, bool shouldWait)
        {
            if (String.IsNullOrWhiteSpace(exeName))
            {
                ShowHelp();
                return;
            }

            // Find the latest installed version's app dir
            var appDir   = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var releases = ReleaseEntry.ParseReleaseFile(
                File.ReadAllText(Utility.LocalReleaseFileForAppDir(appDir), Encoding.UTF8));

            // NB: We add the hacked up version in here to handle a migration
            // issue, where versions of Squirrel pre PR #450 will not understand
            // prerelease tags, so it will end up writing the release name sans
            // tags. However, the RELEASES file _will_ have them, so we need to look
            // for directories that match both the real version, and the sanitized
            // version, giving priority to the former.
            var latestAppDir = releases
                               .OrderByDescending(x => x.Version)
                               .SelectMany(x => new[] {
                Utility.AppDirForRelease(appDir, x),
                Utility.AppDirForVersion(appDir, new SemanticVersion(x.Version.Version.Major, x.Version.Version.Minor, x.Version.Version.Build, ""))
            })
                               .FirstOrDefault(x => Directory.Exists(x));

            // Check for the EXE name they want
            var targetExe = new FileInfo(Path.Combine(latestAppDir, exeName.Replace("%20", " ")));

            this.Log().Info("Want to launch '{0}'", targetExe);

            // Check for path canonicalization attacks
            if (!targetExe.FullName.StartsWith(latestAppDir, StringComparison.Ordinal))
            {
                throw new ArgumentException();
            }

            if (!targetExe.Exists)
            {
                this.Log().Error("File {0} doesn't exist in current release", targetExe);
                throw new ArgumentException();
            }

            if (shouldWait)
            {
                waitForParentToExit();
            }

            try {
                this.Log().Info("About to launch: '{0}': {1}", targetExe.FullName, arguments ?? "");
                Process.Start(new ProcessStartInfo(targetExe.FullName, arguments ?? "")
                {
                    WorkingDirectory = Path.GetDirectoryName(targetExe.FullName)
                });
            } catch (Exception ex) {
                this.Log().ErrorException("Failed to start process", ex);
            }
        }
示例#11
0
        public static IEnumerable <ReleaseEntry> LoadLocalReleases(string localReleaseFile)
        {
            var file = File.OpenRead(localReleaseFile);

            // NB: sr disposes file
            using (var sr = new StreamReader(file, Encoding.UTF8))
            {
                return(ReleaseEntry.ParseReleaseFile(sr.ReadToEnd()));
            }
        }
示例#12
0
        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);
        }
示例#13
0
文件: UpdaterUI.cs 项目: HDRUK/RDMP
        private ReleaseEntry DownloadRelease(Asset releaseFile)
        {
            var content = new WebClient().DownloadString(releaseFile.browser_download_url);

            content = content.Replace(
                "ResearchDataManagementPlatform",
                releaseFile.browser_download_url.Replace("RELEASES", "") + "ResearchDataManagementPlatform");
            var result = ReleaseEntry.ParseReleaseFile(content).First();

            return(result);
        }
示例#14
0
        public IObservable <UpdateInfo> CheckForUpdate(bool ignoreDeltaUpdates = false)
        {
            IEnumerable <ReleaseEntry> localReleases = Enumerable.Empty <ReleaseEntry>();

            var noLock = checkForLock <UpdateInfo>();

            if (noLock != null)
            {
                return(noLock);
            }

            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.
                this.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
            if (isHttpUrl(updateUrlOrPath))
            {
                releaseFile = urlDownloader.DownloadUrl(String.Format("{0}/{1}", updateUrlOrPath, "RELEASES"));
            }
            else
            {
                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);
                }
            }

            var ret = releaseFile
                      .Select(ReleaseEntry.ParseReleaseFile)
                      .SelectMany(releases => determineUpdateInfo(localReleases, releases, ignoreDeltaUpdates))
                      .Multicast(new AsyncSubject <UpdateInfo>());

            ret.Connect();
            return(ret);
        }
示例#15
0
        public void ProcessStart(string exeName, string arguments, bool shouldWait)
        {
            if (String.IsNullOrWhiteSpace(exeName))
            {
                ShowHelp();
                return;
            }

            // Find the latest installed version's app dir
            var appDir   = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var releases = ReleaseEntry.ParseReleaseFile(
                File.ReadAllText(Utility.LocalReleaseFileForAppDir(appDir), Encoding.UTF8));

            var latestAppDir = releases
                               .OrderByDescending(x => x.Version)
                               .Select(x => Utility.AppDirForRelease(appDir, x))
                               .FirstOrDefault(x => Directory.Exists(x));

            // Check for the EXE name they want
            var targetExe = new FileInfo(Path.Combine(latestAppDir, exeName));

            this.Log().Info("Want to launch '{0}'", targetExe);

            // Check for path canonicalization attacks
            if (!targetExe.FullName.StartsWith(latestAppDir, StringComparison.Ordinal))
            {
                throw new ArgumentException();
            }

            if (!targetExe.Exists)
            {
                this.Log().Error("File {0} doesn't exist in current release", targetExe);
                throw new ArgumentException();
            }

            if (shouldWait)
            {
                waitForParentToExit();
            }

            try {
                this.Log().Info("About to launch: '{0}': {1}", targetExe.FullName, arguments ?? "");
                Process.Start(new ProcessStartInfo(targetExe.FullName, arguments ?? "")
                {
                    WorkingDirectory = Path.GetDirectoryName(targetExe.FullName)
                });
            } catch (Exception ex) {
                this.Log().ErrorException("Failed to start process", ex);
            }
        }
示例#16
0
        public async Task Install(bool silentInstall, ProgressSource progressSource, string sourceDirectory = null)
        {
            sourceDirectory = sourceDirectory ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var releasesPath = Path.Combine(sourceDirectory, "RELEASES");

            this.Log().Info("Starting install, writing to {0}", sourceDirectory);

            if (!File.Exists(releasesPath))
            {
                this.Log().Info("RELEASES doesn't exist, creating it at " + releasesPath);
                var nupkgs = (new DirectoryInfo(sourceDirectory)).GetFiles()
                             .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase))
                             .Select(x => ReleaseEntry.GenerateFromFile(x.FullName));

                ReleaseEntry.WriteReleaseFile(nupkgs, releasesPath);
            }

            var ourAppName = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesPath, Encoding.UTF8))
                             .First().PackageName;

            using (var mgr = new UpdateManager(sourceDirectory, ourAppName))
            {
                this.Log().Info("About to install to: " + mgr.RootAppDirectory);
                if (Directory.Exists(mgr.RootAppDirectory))
                {
                    this.Log().Warn("Install path {0} already exists, burning it to the ground", mgr.RootAppDirectory);

                    mgr.KillAllExecutablesBelongingToPackage();
                    await Task.Delay(500);

                    await this.ErrorIfThrows(() => Utility.DeleteDirectory(mgr.RootAppDirectory),
                                             "Failed to remove existing directory on full install, is the app still running???");

                    this.ErrorIfThrows(() => Utility.Retry(() => Directory.CreateDirectory(mgr.RootAppDirectory), 3),
                                       "Couldn't recreate app directory, perhaps Antivirus is blocking it");
                }

                Directory.CreateDirectory(mgr.RootAppDirectory);

                var updateTarget = Path.Combine(mgr.RootAppDirectory, "Update.exe");
                this.ErrorIfThrows(() => File.Copy(Assembly.GetExecutingAssembly().Location, updateTarget, true),
                                   "Failed to copy Update.exe to " + updateTarget);

                await mgr.FullInstall(silentInstall, progressSource.Raise);

                await this.ErrorIfThrows(() => mgr.CreateUninstallerRegistryEntry(),
                                         "Failed to create uninstaller registry entry");
            }
        }
示例#17
0
        public ReleaseEntry GetReleaseEntry(string sourceDirectory)
        {
            var releasesPath = Path.Combine(sourceDirectory, "RELEASES");

            if (!File.Exists(releasesPath))
            {
                this.Log().Info("RELEASES doesn't exist, creating it at " + releasesPath);
                var nupkgs = (new DirectoryInfo(sourceDirectory)).GetFiles()
                             .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase))
                             .Select(x => ReleaseEntry.GenerateFromFile(x.FullName));

                ReleaseEntry.WriteReleaseFile(nupkgs, releasesPath);
            }

            return(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesPath, Encoding.UTF8))
                   .First());
        }
示例#18
0
文件: Program.cs 项目: anthrax3/NSync
        static int Main(string[] args)
        {
            var optParams = parseOptions(args);

            if (optParams == null)
            {
                return(-1);
            }

            var targetDir  = optParams["target"];
            var package    = new ReleasePackage(optParams["input"]);
            var targetFile = Path.Combine(targetDir, package.SuggestedReleaseFileName);

            var fullRelease = package.CreateReleasePackage(targetFile,
                                                           optParams["pkgdir"] != "" ? optParams["pkgdir"] : null,
                                                           input => (new Markdown()).Transform(input));

            var releaseFile = Path.Combine(targetDir, "RELEASES");

            if (File.Exists(releaseFile))
            {
                var releaseEntries = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFile, Encoding.UTF8));

                var latestFullRelease = releaseEntries
                                        .Where(x => x.IsDelta == false)
                                        .MaxBy(x => x.Version)
                                        .Select(x => new ReleasePackage(Path.Combine(targetDir, x.Filename), true))
                                        .FirstOrDefault();

                var deltaFile = Path.Combine(targetDir, package.SuggestedReleaseFileName.Replace("full", "delta"));
                Console.WriteLine("{0} {1}", latestFullRelease.InputPackageFile, deltaFile);

                var deltaBuilder = new DeltaPackageBuilder();
                deltaBuilder.CreateDeltaPackage(package, latestFullRelease, deltaFile);
            }

            ReleaseEntry.BuildReleasesFile(targetDir);

            Console.WriteLine(fullRelease);
            return(0);
        }
示例#19
0
        public static async Task SyncRemoteReleases(Uri targetUri, DirectoryInfo releasesDir)
        {
            var releasesUri   = new Uri(targetUri + "/RELEASES");
            var releasesIndex = await retryAsync(3, () => downloadReleasesIndex(releasesUri));

            File.WriteAllText(Path.Combine(releasesDir.FullName, "RELEASES"), releasesIndex);

            var releasesToDownload = ReleaseEntry.ParseReleaseFile(releasesIndex)
                                     .Where(x => !x.IsDelta)
                                     .OrderByDescending(x => x.Version)
                                     .Take(5)
                                     .Select(x => new {
                LocalPath = Path.Combine(releasesDir.FullName, x.Filename),
                RemoteUrl = new Uri(targetUri + "/" + x.Filename)
            });

            foreach (var releaseToDownload in releasesToDownload)
            {
                await retryAsync(3, () => downloadRelease(releaseToDownload.LocalPath, releaseToDownload.RemoteUrl));
            }
        }
        ReleaseEntry readBundledReleasesFile()
        {
            var release = fileSystem.GetFileInfo(Path.Combine(currentAssemblyDir, "RELEASES"));

            if (!release.Exists)
            {
                UserError.Throw("This installer is incorrectly configured, please contact the author",
                                new FileNotFoundException(release.FullName));
                return(null);
            }

            ReleaseEntry ret;

            try {
                var fileText = fileSystem
                               .GetFile(release.FullName)
                               .ReadAllText(release.FullName, Encoding.UTF8);

                ret = ReleaseEntry
                      .ParseReleaseFile(fileText)
                      .Where(x => !x.IsDelta)
                      .OrderByDescending(x => x.Version)
                      .First();
            } catch (Exception ex) {
                this.Log().ErrorException("Couldn't read bundled RELEASES file", ex);
                UserError.Throw("This installer is incorrectly configured, please contact the author", ex);
                return(null);
            }

            // now set the logger to the found package name
            RxApp.LoggerFactory = _ => new FileLogger(ret.PackageName)
            {
                Level = ReactiveUIMicro.LogLevel.Info
            };
            ReactiveUIMicro.RxApp.ConfigureFileLogging(ret.PackageName); // HACK: we can do better than this later

            return(ret);
        }
示例#21
0
        ReleaseEntry readBundledReleasesFile()
        {
            var release = new FileInfo(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "RELEASES"));

            if (!release.Exists)
            {
                UserError.Throw("This installer is incorrectly configured, please contact the author",
                                new FileNotFoundException(release.FullName));
                return(null);
            }

            ReleaseEntry ret;

            try {
                ret = ReleaseEntry.ParseReleaseFile(File.ReadAllText(release.FullName, Encoding.UTF8)).Single();
            } catch (Exception ex) {
                this.Log().ErrorException("Couldn't read bundled RELEASES file", ex);
                UserError.Throw("This installer is incorrectly configured, please contact the author", ex);
                return(null);
            }

            return(ret);
        }
示例#22
0
            public async Task <RegistryKey> CreateUninstallerRegistryEntry(string uninstallCmd, string quietSwitch)
            {
                var releaseContent = File.ReadAllText(Path.Combine(rootAppDirectory, "packages", "RELEASES"), Encoding.UTF8);
                var releases       = ReleaseEntry.ParseReleaseFile(releaseContent);
                var latest         = releases.Where(x => !x.IsDelta).OrderByDescending(x => x.Version).First();

                // Download the icon and PNG => ICO it. If this doesn't work, who cares
                var pkgPath = Path.Combine(rootAppDirectory, "packages", latest.Filename);
                var zp      = new ZipPackage(pkgPath);

                var targetPng = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".png");
                var targetIco = Path.Combine(rootAppDirectory, "app.ico");

                // NB: Sometimes the Uninstall key doesn't exist
                using (var parentKey =
                           RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
                           .CreateSubKey("Uninstall", RegistryKeyPermissionCheck.ReadWriteSubTree))
                {
                    ;
                }

                var key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default)
                          .CreateSubKey(UninstallRegSubKey + "\\" + applicationName, RegistryKeyPermissionCheck.ReadWriteSubTree);

                if (zp.IconUrl != null && !File.Exists(targetIco))
                {
                    try
                    {
                        using (var wc = Utility.CreateWebClient())
                        {
                            await wc.DownloadFileTaskAsync(zp.IconUrl, targetPng);

                            using (var fs = new FileStream(targetIco, FileMode.Create))
                            {
                                if (zp.IconUrl.AbsolutePath.EndsWith("ico"))
                                {
                                    var bytes = File.ReadAllBytes(targetPng);
                                    fs.Write(bytes, 0, bytes.Length);
                                }
                                else
                                {
                                    using (var bmp = (Bitmap)Image.FromFile(targetPng))
                                        using (var ico = Icon.FromHandle(bmp.GetHicon()))
                                        {
                                            ico.Save(fs);
                                        }
                                }

                                key.SetValue("DisplayIcon", targetIco, RegistryValueKind.String);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.Info("Couldn't write uninstall icon, don't care", ex);
                    }
                    finally
                    {
                        File.Delete(targetPng);
                    }
                }

                var stringsToWrite = new[]
                {
                    new { Key = "DisplayName", Value = zp.Title ?? zp.Description ?? zp.Summary },
                    new { Key = "DisplayVersion", Value = zp.Version.ToString() },
                    new { Key = "InstallDate", Value = DateTime.Now.ToString("yyyyMMdd") },
                    new { Key = "InstallLocation", Value = rootAppDirectory },
                    new { Key = "Publisher", Value = string.Join(",", zp.Authors) },
                    new { Key = "QuietUninstallString", Value = $"{uninstallCmd} {quietSwitch}" },
                    new { Key = "UninstallString", Value = uninstallCmd },
                    new
                    {
                        Key = "URLUpdateInfo", Value = zp.ProjectUrl != null
                            ? zp.ProjectUrl.ToString()
                            : ""
                    }
                };

                var dwordsToWrite = new[]
                {
                    new { Key = "EstimatedSize", Value = (int)(new FileInfo(pkgPath).Length / 1024) },
                    new { Key = "NoModify", Value = 1 },
                    new { Key = "NoRepair", Value = 1 },
                    new { Key = "Language", Value = 0x0409 }
                };

                foreach (var kvp in stringsToWrite)
                {
                    key.SetValue(kvp.Key, kvp.Value, RegistryValueKind.String);
                }

                foreach (var kvp in dwordsToWrite)
                {
                    key.SetValue(kvp.Key, kvp.Value, RegistryValueKind.DWord);
                }

                return(key);
            }
示例#23
0
        public void Releasify(string package, string targetDir = null, string packagesDir = null, string bootstrapperExe = null, string backgroundGif = null, string signingOpts = null, string baseUrl = null, string setupIcon = null, bool generateMsi = true)
        {
            if (baseUrl != null)
            {
                if (!Utility.IsHttpUrl(baseUrl))
                {
                    throw new Exception(string.Format("Invalid --baseUrl '{0}'. A base URL must start with http or https and be a valid URI.", baseUrl));
                }

                if (!baseUrl.EndsWith("/"))
                {
                    baseUrl += "/";
                }
            }

            targetDir       = targetDir ?? Path.Combine(".", "Releases");
            packagesDir     = packagesDir ?? ".";
            bootstrapperExe = bootstrapperExe ?? Path.Combine(".", "Setup.exe");

            if (!Directory.Exists(targetDir))
            {
                Directory.CreateDirectory(targetDir);
            }

            if (!File.Exists(bootstrapperExe))
            {
                bootstrapperExe = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
                    "Setup.exe");
            }

            this.Log().Info("Bootstrapper EXE found at:" + bootstrapperExe);

            var di = new DirectoryInfo(targetDir);

            File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true);

            var allNuGetFiles = di.EnumerateFiles()
                                .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase));

            var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full"));
            var processed = new List <string>();

            var releaseFilePath  = Path.Combine(di.FullName, "RELEASES");
            var previousReleases = new List <ReleaseEntry>();

            if (File.Exists(releaseFilePath))
            {
                previousReleases.AddRange(ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8)));
            }

            foreach (var file in toProcess)
            {
                this.Log().Info("Creating release package: " + file.FullName);

                var rp = new ReleasePackage(file.FullName);
                rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), packagesDir, contentsPostProcessHook: pkgPath => {
                    new DirectoryInfo(pkgPath).GetAllFilesRecursively()
                    .Where(x => x.Name.ToLowerInvariant().EndsWith(".exe"))
                    .Where(x => !x.Name.ToLowerInvariant().Contains("squirrel.exe"))
                    .Where(x => Utility.ExecutableUsesWin32Subsystem(x.FullName))
                    .ForEachAsync(x => createExecutableStubForExe(x.FullName))
                    .Wait();

                    if (signingOpts == null)
                    {
                        return;
                    }

                    new DirectoryInfo(pkgPath).GetAllFilesRecursively()
                    .Where(x => Utility.FileIsLikelyPEImage(x.Name))
                    .ForEachAsync(async x => {
                        if (isPEFileSigned(x.FullName))
                        {
                            this.Log().Info("{0} is already signed, skipping", x.FullName);
                            return;
                        }

                        this.Log().Info("About to sign {0}", x.FullName);
                        await signPEFile(x.FullName, signingOpts);
                    })
                    .Wait();
                });

                processed.Add(rp.ReleasePackageFile);

                var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);
                if (prev != null)
                {
                    var deltaBuilder = new DeltaPackageBuilder(null);

                    var dp = deltaBuilder.CreateDeltaPackage(prev, rp,
                                                             Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta")));
                    processed.Insert(0, dp.InputPackageFile);
                }
            }

            foreach (var file in toProcess)
            {
                File.Delete(file.FullName);
            }

            var newReleaseEntries = processed
                                    .Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl))
                                    .ToList();
            var distinctPreviousReleases = previousReleases
                                           .Where(x => !newReleaseEntries.Select(e => e.Version).Contains(x.Version));
            var releaseEntries = distinctPreviousReleases.Concat(newReleaseEntries).ToList();

            ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);

            var targetSetupExe    = Path.Combine(di.FullName, "Setup.exe");
            var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First();

            File.Copy(bootstrapperExe, targetSetupExe, true);
            var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName, backgroundGif, signingOpts).Result;

            var writeZipToSetup = findExecutable("WriteZipToSetup.exe");

            try {
                var result = Utility.InvokeProcessAsync(writeZipToSetup, String.Format("\"{0}\" \"{1}\"", targetSetupExe, zipPath), CancellationToken.None).Result;
                if (result.Item1 != 0)
                {
                    throw new Exception("Failed to write Zip to Setup.exe!\n\n" + result.Item2);
                }
            } catch (Exception ex) {
                this.Log().ErrorException("Failed to update Setup.exe with new Zip file", ex);
            } finally {
                File.Delete(zipPath);
            }

            Utility.Retry(() =>
                          setPEVersionInfoAndIcon(targetSetupExe, new ZipPackage(package), setupIcon).Wait());

            if (signingOpts != null)
            {
                signPEFile(targetSetupExe, signingOpts).Wait();
            }

            if (generateMsi)
            {
                createMsiPackage(targetSetupExe, new ZipPackage(package)).Wait();

                if (signingOpts != null)
                {
                    signPEFile(targetSetupExe.Replace(".exe", ".msi"), signingOpts).Wait();
                }
            }
        }
            // NB: Once we uninstall the old version of the app, we try to schedule
            // it to be deleted at next reboot. Unfortunately, depending on whether
            // the user has admin permissions, this can fail. So as a failsafe,
            // before we try to apply any update, we assume previous versions in the
            // directory are "dead" (i.e. already uninstalled, but not deleted), and
            // we blow them away. This is to make sure that we don't attempt to run
            // an uninstaller on an already-uninstalled version.
            private async Task CleanDeadVersions(SemanticVersion originalVersion, SemanticVersion currentVersion, bool forceUninstall = false)
            {
                if (currentVersion == null)
                {
                    return;
                }

                var di = new DirectoryInfo(rootAppDirectory);

                if (!di.Exists)
                {
                    return;
                }

                Log.InfoFormat("cleanDeadVersions: for version {0}", currentVersion);

                string originalVersionFolder = null;

                if (originalVersion != null)
                {
                    originalVersionFolder = GetDirectoryForRelease(originalVersion).Name;
                    Log.InfoFormat("cleanDeadVersions: exclude folder {0}", originalVersionFolder);
                }

                string currentVersionFolder = null;

                if (currentVersion != null)
                {
                    currentVersionFolder = GetDirectoryForRelease(currentVersion).Name;
                    Log.InfoFormat("cleanDeadVersions: exclude folder {0}", currentVersionFolder);
                }

                // NB: If we try to access a directory that has already been
                // scheduled for deletion by MoveFileEx it throws what seems like
                // NT's only error code, ERROR_ACCESS_DENIED. Squelch errors that
                // come from here.
                var toCleanup = di.GetDirectories()
                                .Where(x => x.Name.ToLowerInvariant().Contains("app-"))
                                .Where(x => x.Name != currentVersionFolder && x.Name != originalVersionFolder)
                                .Where(x => !IsAppFolderDead(x.FullName));

                if (forceUninstall == false)
                {
                    await toCleanup.ForEachAsync(
                        async x =>
                    {
                        var squirrelApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(x.FullName);
                        var args         = $"--squirrel-obsolete {x.Name.Replace("app-", "")}";

                        if (squirrelApps.Count > 0)
                        {
                            // For each app, run the install command in-order and wait
                            await squirrelApps.ForEachAsync(
                                async exe =>
                            {
                                using (var cts = new CancellationTokenSource())
                                {
                                    cts.CancelAfter(10 * 1000);

                                    try
                                    {
                                        await Utility.InvokeProcessAsync(exe, args, cts.Token);
                                    }
                                    catch (Exception ex)
                                    {
                                        Log.Error("Coudln't run Squirrel hook, continuing: " + exe, ex);
                                    }
                                }
                            },
                                1 /* at a time */);
                        }
                    });
                }

                // Include dead folders in folders to :fire:
                toCleanup = di.GetDirectories()
                            .Where(x => x.Name.ToLowerInvariant().Contains("app-"))
                            .Where(x => x.Name != currentVersionFolder && x.Name != originalVersionFolder);

                // Get the current process list in an attempt to not burn
                // directories which have running processes
                var runningProcesses = UnsafeUtility.EnumerateProcesses();

                // Finally, clean up the app-X.Y.Z directories
                await toCleanup.ForEachAsync(
                    async x =>
                {
                    try
                    {
                        if (runningProcesses.All(p => p.Item1 == null || !p.Item1.StartsWith(x.FullName, StringComparison.OrdinalIgnoreCase)))
                        {
                            await Utility.DeleteDirectoryOrJustGiveUp(x.FullName);
                        }

                        if (Directory.Exists(x.FullName))
                        {
                            // NB: If we cannot clean up a directory, we need to make
                            // sure that anyone finding it later won't attempt to run
                            // Squirrel events on it. We'll mark it with a .dead file
                            MarkAppFolderAsDead(x.FullName);
                        }
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        Log.Warn("Couldn't delete directory: " + x.FullName, ex);

                        // NB: Same deal as above
                        MarkAppFolderAsDead(x.FullName);
                    }
                });

                // Clean up the packages directory too
                var releasesFile = Utility.LocalReleaseFileForAppDir(rootAppDirectory);
                var entries      = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesFile, Encoding.UTF8));
                var pkgDir       = Utility.PackageDirectoryForAppDir(rootAppDirectory);
                var releaseEntry = default(ReleaseEntry);

                foreach (var entry in entries)
                {
                    if (entry.Version == currentVersion)
                    {
                        releaseEntry = ReleaseEntry.GenerateFromFile(Path.Combine(pkgDir, entry.Filename));
                        continue;
                    }

                    File.Delete(Path.Combine(pkgDir, entry.Filename));
                }

                ReleaseEntry.WriteReleaseFile(new[] { releaseEntry }, releasesFile);
            }
示例#25
0
        public void Releasify(string package, string targetDir = null, string packagesDir = null, string bootstrapperExe = null, string backgroundGif = null, string signingOpts = null, string baseUrl = null, string setupIcon = null)
        {
            if (baseUrl != null)
            {
                if (!Utility.IsHttpUrl(baseUrl))
                {
                    throw new Exception(string.Format("Invalid --baseUrl '{0}'. A base URL must start with http or https and be a valid URI.", baseUrl));
                }

                if (!baseUrl.EndsWith("/"))
                {
                    baseUrl += "/";
                }
            }

            targetDir       = targetDir ?? ".\\Releases";
            packagesDir     = packagesDir ?? ".";
            bootstrapperExe = bootstrapperExe ?? ".\\Setup.exe";

            if (!Directory.Exists(targetDir))
            {
                Directory.CreateDirectory(targetDir);
            }

            if (!File.Exists(bootstrapperExe))
            {
                bootstrapperExe = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
                    "Setup.exe");
            }

            this.Log().Info("Bootstrapper EXE found at:" + bootstrapperExe);

            var di = new DirectoryInfo(targetDir);

            File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true);

            var allNuGetFiles = di.EnumerateFiles()
                                .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase));

            var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full"));
            var processed = new List <string>();

            var releaseFilePath  = Path.Combine(di.FullName, "RELEASES");
            var previousReleases = Enumerable.Empty <ReleaseEntry>();

            if (File.Exists(releaseFilePath))
            {
                previousReleases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8));
            }

            foreach (var file in toProcess)
            {
                this.Log().Info("Creating release package: " + file.FullName);

                var rp = new ReleasePackage(file.FullName);
                rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), packagesDir, contentsPostProcessHook: pkgPath => {
                    if (signingOpts == null)
                    {
                        return;
                    }

                    new DirectoryInfo(pkgPath).GetAllFilesRecursively()
                    .Where(x => x.Name.ToLowerInvariant().EndsWith(".exe"))
                    .ForEachAsync(x => signPEFile(x.FullName, signingOpts))
                    .Wait();
                });

                processed.Add(rp.ReleasePackageFile);

                var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);
                if (prev != null)
                {
                    var deltaBuilder = new DeltaPackageBuilder();

                    var dp = deltaBuilder.CreateDeltaPackage(prev, rp,
                                                             Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta")));
                    processed.Insert(0, dp.InputPackageFile);
                }
            }

            foreach (var file in toProcess)
            {
                File.Delete(file.FullName);
            }

            var releaseEntries = previousReleases.Concat(processed.Select(packageFilename => ReleaseEntry.GenerateFromFile(packageFilename, baseUrl)));

            ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);

            var targetSetupExe    = Path.Combine(di.FullName, "Setup.exe");
            var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First();

            File.Copy(bootstrapperExe, targetSetupExe, true);
            var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName, backgroundGif, signingOpts).Result;

            try {
                var zip = File.ReadAllBytes(zipPath);

                IntPtr handle = NativeMethods.BeginUpdateResource(targetSetupExe, false);
                if (handle == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }

                if (!NativeMethods.UpdateResource(handle, "DATA", new IntPtr(131), 0x0409, zip, zip.Length))
                {
                    throw new Win32Exception();
                }

                if (!NativeMethods.EndUpdateResource(handle, false))
                {
                    throw new Win32Exception();
                }
            } catch (Exception ex) {
                this.Log().ErrorException("Failed to update Setup.exe with new Zip file", ex);
            } finally {
                File.Delete(zipPath);
            }

            Utility.Retry(() =>
                          setPEVersionInfoAndIcon(targetSetupExe, new ZipPackage(package), setupIcon).Wait());

            if (signingOpts != null)
            {
                signPEFile(targetSetupExe, signingOpts).Wait();
            }
        }
示例#26
0
 public void ParseReleaseFileShouldReturnNothingForBlankFiles()
 {
     Assert.True(ReleaseEntry.ParseReleaseFile("").Count() == 0);
     Assert.True(ReleaseEntry.ParseReleaseFile(null).Count() == 0);
 }
示例#27
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);
        }
        public void Releasify(string package, string targetDir = null, string packagesDir = null, string bootstrapperExe = null)
        {
            targetDir       = targetDir ?? ".\\Releases";
            packagesDir     = packagesDir ?? ".";
            bootstrapperExe = bootstrapperExe ?? ".\\Setup.exe";

            if (!Directory.Exists(targetDir))
            {
                Directory.CreateDirectory(targetDir);
            }

            if (!File.Exists(bootstrapperExe))
            {
                bootstrapperExe = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
                    "Setup.exe");
            }

            this.Log().Info("Bootstrapper EXE found at:" + bootstrapperExe);

            var di = new DirectoryInfo(targetDir);

            File.Copy(package, Path.Combine(di.FullName, Path.GetFileName(package)), true);

            var allNuGetFiles = di.EnumerateFiles()
                                .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase));

            var toProcess = allNuGetFiles.Where(x => !x.Name.Contains("-delta") && !x.Name.Contains("-full"));

            var releaseFilePath  = Path.Combine(di.FullName, "RELEASES");
            var previousReleases = Enumerable.Empty <ReleaseEntry>();

            if (File.Exists(releaseFilePath))
            {
                previousReleases = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releaseFilePath, Encoding.UTF8));
            }

            foreach (var file in toProcess)
            {
                this.Log().Info("Creating release package: " + file.FullName);

                var rp = new ReleasePackage(file.FullName);
                rp.CreateReleasePackage(Path.Combine(di.FullName, rp.SuggestedReleaseFileName), packagesDir);

                var prev = ReleaseEntry.GetPreviousRelease(previousReleases, rp, targetDir);
                if (prev != null)
                {
                    var deltaBuilder = new DeltaPackageBuilder();

                    deltaBuilder.CreateDeltaPackage(prev, rp,
                                                    Path.Combine(di.FullName, rp.SuggestedReleaseFileName.Replace("full", "delta")));
                }
            }

            foreach (var file in toProcess)
            {
                File.Delete(file.FullName);
            }

            var releaseEntries = allNuGetFiles.Select(x => ReleaseEntry.GenerateFromFile(x.FullName));

            ReleaseEntry.WriteReleaseFile(releaseEntries, releaseFilePath);

            var targetSetupExe    = Path.Combine(di.FullName, "Setup.exe");
            var newestFullRelease = releaseEntries.MaxBy(x => x.Version).Where(x => !x.IsDelta).First();

            File.Copy(bootstrapperExe, targetSetupExe, true);
            var zipPath = createSetupEmbeddedZip(Path.Combine(di.FullName, newestFullRelease.Filename), di.FullName);

            try {
                var zip = File.ReadAllBytes(zipPath);

                IntPtr handle = NativeMethods.BeginUpdateResource(targetSetupExe, false);
                if (handle == IntPtr.Zero)
                {
                    throw new Win32Exception();
                }

                if (!NativeMethods.UpdateResource(handle, "DATA", new IntPtr(131), 0x0409, zip, zip.Length))
                {
                    throw new Win32Exception();
                }

                if (!NativeMethods.EndUpdateResource(handle, false))
                {
                    throw new Win32Exception();
                }
            } catch (Exception ex) {
                this.Log().ErrorException("Failed to update Setup.exe with new Zip file", ex);
            } finally {
                File.Delete(zipPath);
            }
        }
示例#29
0
        public async Task Install(bool silentInstall, ProgressSource progressSource, string sourceDirectory = null)
        {
            sourceDirectory = sourceDirectory ?? Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var releasesPath = Path.Combine(sourceDirectory, "RELEASES");

            this.Log().Info("Starting install, writing to {0}", sourceDirectory);

            if (!File.Exists(releasesPath))
            {
                this.Log().Info("RELEASES doesn't exist, creating it at " + releasesPath);
                var nupkgs = (new DirectoryInfo(sourceDirectory)).GetFiles()
                             .Where(x => x.Name.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase))
                             .Select(x => ReleaseEntry.GenerateFromFile(x.FullName));

                ReleaseEntry.WriteReleaseFile(nupkgs, releasesPath);
            }

            var ourAppName = ReleaseEntry.ParseReleaseFile(File.ReadAllText(releasesPath, Encoding.UTF8))
                             .First().PackageName;

            this.Log().Warn("Preparing to install");

            string tempSettingsFile = null;
            string destSettingsFile = null;

            using (var mgr = new UpdateManager(sourceDirectory, ourAppName)) {
                this.Log().Info("About to install to: " + mgr.RootAppDirectory);
                if (Directory.Exists(mgr.RootAppDirectory))
                {
                    this.Log().Warn("Install path {0} already exists, burning it to the ground", mgr.RootAppDirectory);

                    var settingsName = "UiPath.settings";
                    var settingsFile = Path.Combine(mgr.RootAppDirectory, settingsName);
                    tempSettingsFile = File.Exists(settingsFile) ? Path.GetTempPath() + Path.GetRandomFileName() : null;

                    if (tempSettingsFile != null)
                    {
                        this.Log().Warn("Backup uipath.settings");
                        destSettingsFile = settingsFile;
                        File.Copy(settingsFile, tempSettingsFile);
                    }

                    bool success    = false;
                    int  maxRetries = 3;
                    do
                    {
                        var killed = mgr.KillAllExecutablesBelongingToPackage();
                        await Task.Delay(500);

                        this.Log().Warn($"Deleted {killed} processes");

                        try
                        {
                            await this.ErrorIfThrows(() => Utility.DeleteDirectory(mgr.RootAppDirectory),
                                                     "Failed to remove existing directory on full install, is the app still running???");

                            success = true;
                        }
                        catch (Exception ex)
                        {
                            this.Log().Warn($"Failed to delete whole folder. Reason {ex.ToString()}");
                            this.Log().Warn($"Attempts left {maxRetries}");
                            if (maxRetries == 0)
                            {
                                throw;
                            }
                        }
                    }while (!success || maxRetries-- > 0);
                    this.ErrorIfThrows(() => Utility.Retry(() => Directory.CreateDirectory(mgr.RootAppDirectory), 3),
                                       "Couldn't recreate app directory, perhaps Antivirus is blocking it");
                }

                Directory.CreateDirectory(mgr.RootAppDirectory);

                var updateTarget = Path.Combine(mgr.RootAppDirectory, "Update.exe");
                this.ErrorIfThrows(() => File.Copy(Assembly.GetExecutingAssembly().Location, updateTarget, true),
                                   "Failed to copy Update.exe to " + updateTarget);

                await mgr.FullInstall(silentInstall, progressSource.Raise);

                if (destSettingsFile != null && tempSettingsFile != null)
                {
                    File.Copy(tempSettingsFile, destSettingsFile);
                }

                await this.ErrorIfThrows(() => mgr.CreateUninstallerRegistryEntry(),
                                         "Failed to create uninstaller registry entry");
            }
        }