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); } }
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); }
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"); } }
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()); } }
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); }
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); } }
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())); } }
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); }
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); }
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); }
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); } }
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"); } }
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()); }
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); }
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); }
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); }
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); }
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); }
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(); } }
public void ParseReleaseFileShouldReturnNothingForBlankFiles() { Assert.True(ReleaseEntry.ParseReleaseFile("").Count() == 0); Assert.True(ReleaseEntry.ParseReleaseFile(null).Count() == 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); } }
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"); } }