async Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release) { var pkg = new ZipPackage(Path.Combine(updateInfo.PackageDirectory, release.Filename)); var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); // Copy all of the files out of the lib/ dirs in the NuGet package // into our target App directory. // // NB: We sort this list in order to guarantee that if a Net20 // and a Net40 version of a DLL get shipped, we always end up // with the 4.0 version. this.Log().Info("Writing files to app directory: {0}", target.FullName); var toWrite = pkg.GetLibFiles().Where(x => pathIsInFrameworkProfile(x, appFrameworkVersion)) .OrderBy(x => x.Path) .ToList(); // NB: Because of the above NB, we cannot use ForEachAsync here, we // have to copy these files in-order. Once we fix assembly resolution, // we can kill both of these NBs. await Task.Run(() => toWrite.ForEach(x => copyFileToLocation(target, x))); await pkg.GetContentFiles().ForEachAsync(x => copyFileToLocation(target, x)); return(target.FullName); }
public static async Task DeleteDirectoryOrJustGiveUp(string dir) { try { await Utility.DeleteDirectory(dir); } catch { var message = String.Format("Uninstall failed to delete dir '{0}'", dir); } }
public static async Task DeleteDirectoryWithFallbackToNextReboot(string dir) { try { await Utility.DeleteDirectory(dir); } catch (Exception ex) { var message = String.Format("Uninstall failed to delete dir '{0}', punting to next reboot", dir); LogHost.Default.WarnException(message, ex); Utility.DeleteDirectoryAtNextReboot(dir); } }
async Task initializeClientAppDirectory() { // On bootstrap, we won't have any of our directories, create them var pkgDir = Path.Combine(rootAppDirectory, "packages"); if (Directory.Exists(pkgDir)) { await Utility.DeleteDirectory(pkgDir); } Directory.CreateDirectory(pkgDir); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release) { return(Task.Run(async() => { var zipper = new FastZip(); var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); this.Log().Info("Writing files to app directory: {0}", target.FullName); zipper.ExtractZip( Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName, FastZip.Overwrite.Always, (o) => true, null, @"lib", true); // Move all of the files out of the lib/ dirs in the NuGet package // into our target App directory. // // NB: We sort this list in order to guarantee that if a Net20 // and a Net40 version of a DLL get shipped, we always end up // with the 4.0 version. var libDir = target.GetDirectories().First(x => x.Name.Equals("lib", StringComparison.OrdinalIgnoreCase)); var toMove = libDir.GetDirectories().OrderBy(x => x.Name); toMove.ForEach(ld => { ld.GetDirectories() .ForEachAsync(subdir => subdir.MoveTo(subdir.FullName.Replace(ld.FullName, target.FullName))) .Wait(); ld.GetFiles() .ForEachAsync(file => { var tgt = Path.Combine(target.FullName, file.Name); this.Log().Info("Moving file {0} to {1}", file.FullName, tgt); if (File.Exists(tgt)) { Utility.DeleteFileHarder(tgt, true); } file.MoveTo(tgt); }) .Wait(); }); await Utility.DeleteDirectory(libDir.FullName); return target.FullName; })); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release, Action <int> progressCallback) { return(Task.Run(async() => { var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); try { this.Log().Info("Writing files to app directory: {0}", target.FullName); await ReleasePackage.ExtractZipForInstall( Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName, rootAppDirectory, progressCallback); } catch (Exception ex) { try { //Don't leave that empty directory there: its existence will prevent the user from even using the previous version. await Utility.DeleteDirectory(target.FullName); } catch (Exception error) { //This is going to be one very stuck user... this.Log().ErrorException("Failed to cleanup new directory after failed install: " + target.FullName, error); } throw ex; } return target.FullName; })); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release) { return(Task.Run(async() => { var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); this.Log().Info("Writing files to app directory: {0}", target.FullName); await ReleasePackage.ExtractZipForInstall( Path.Combine(updateInfo.PackageDirectory, release.Filename), target.FullName); return target.FullName; })); }
public async Task FullUninstall() { var currentRelease = getReleases().MaxBy(x => x.Name.ToSemanticVersion()).FirstOrDefault(); this.Log().Info("Starting full uninstall"); if (currentRelease.Exists) { var version = currentRelease.Name.ToSemanticVersion(); try { var squirrelAwareApps = SquirrelAwareExecutableDetector.GetAllSquirrelAwareApps(currentRelease.FullName); if (isAppFolderDead(currentRelease.FullName)) { throw new Exception("App folder is dead, but we're trying to uninstall it?"); } var allApps = currentRelease.EnumerateFiles() .Where(x => x.Name.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) .Where(x => !x.Name.StartsWith("squirrel.", StringComparison.OrdinalIgnoreCase) && !x.Name.StartsWith("update.", StringComparison.OrdinalIgnoreCase)) .ToList(); if (squirrelAwareApps.Count > 0) { await squirrelAwareApps.ForEachAsync(async exe => { using (var cts = new CancellationTokenSource()) { cts.CancelAfter(10 * 1000); try { await Utility.InvokeProcessAsync(exe, String.Format("--squirrel-uninstall {0}", version), cts.Token); } catch (Exception ex) { this.Log().ErrorException("Failed to run cleanup hook, continuing: " + exe, ex); } } }, 1 /*at a time*/); } else { allApps.ForEach(x => RemoveShortcutsForExecutable(x.Name, ShortcutLocations.Defaults)); } // NB: Some people attempt to uninstall apps while // they're still running. I cannot even. var toKill = allApps .SelectMany(x => Process.GetProcessesByName(x.Name.Replace(".exe", ""))) .ToList(); if (toKill.Count > 0) { toKill.ForEach(x => x.Kill()); Thread.Sleep(750); } } catch (Exception ex) { this.Log().WarnException("Failed to run pre-uninstall hooks, uninstalling anyways", ex); } } fixPinnedExecutables(new SemanticVersion(255, 255, 255, 255)); bool didSucceedDeleting = false; const int retryAttempts = 10; for (int i = 0; i < retryAttempts; ++i) { try { await Utility.DeleteDirectory(rootAppDirectory); didSucceedDeleting = true; } catch (Exception) { Thread.Sleep(1000); // Give the OS a second to release handles and we'll try again } } if (!didSucceedDeleting) { await this.ErrorIfThrows(() => Utility.DeleteDirectoryOrJustGiveUp(rootAppDirectory), "Failed to delete app directory: " + rootAppDirectory); } // NB: We drop this file here so that --checkInstall will ignore // this folder - if we don't do this, users who "accidentally" run as // administrator will find the app reinstalling itself on every // reboot File.WriteAllText(Path.Combine(rootAppDirectory, ".dead"), " "); }
Task <string> installPackageToAppDir(UpdateInfo updateInfo, ReleaseEntry release, Action <int> progress) { return(Task.Run(async() => { var target = getDirectoryForRelease(release.Version); // NB: This might happen if we got killed partially through applying the release if (target.Exists) { this.Log().Warn("Found partially applied release folder, killing it: " + target.FullName); await Utility.DeleteDirectory(target.FullName); } target.Create(); var totalSize = GetTotalUncompressedSize(updateInfo, release); var currentExtractedSize = 0L; using (var stream = File.OpenRead(Path.Combine(updateInfo.PackageDirectory, release.Filename))) { // progress.Report(new InstallerStep("Extracting")); var zipIn = new ZipInputStream(stream); var zipEntry = zipIn.GetNextEntry(); while (zipEntry != null) { var entryName = zipEntry.Name; var pathParts = entryName.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var foundLib = false; foreach (var part in pathParts) { if (part.Equals("lib", StringComparison.InvariantCulture)) { foundLib = true; } } if (!foundLib) { zipEntry = zipIn.GetNextEntry(); continue; } var buffer = new byte[4096]; var fullZipToPath = Path.Combine(target.FullName, entryName.Replace('/', Path.DirectorySeparatorChar)); var directoryName = zipEntry.IsFile ? Path.GetDirectoryName(fullZipToPath) : fullZipToPath; if (!string.IsNullOrEmpty(directoryName)) { Directory.CreateDirectory(directoryName); } using (var streamWriter = File.Create(fullZipToPath)) { currentExtractedSize += zipEntry.Size; StreamUtils.Copy(zipIn, streamWriter, buffer); progress((int)((double)currentExtractedSize * 100.0 / (double)totalSize)); } zipEntry = zipIn.GetNextEntry(); } } this.Log().Info("Writing files to app directory: {0}", target.FullName); // Move all of the files out of the lib/ dirs in the NuGet package // into our target App directory. // // NB: We sort this list in order to guarantee that if a Net20 // and a Net40 version of a DLL get shipped, we always end up // with the 4.0 version. var libDir = target.GetDirectories().First(x => x.Name.Equals("lib", StringComparison.OrdinalIgnoreCase)); var toMove = libDir.GetDirectories().OrderBy(x => x.Name); toMove.ForEach(ld => { ld.GetDirectories() .ForEachAsync(subdir => subdir.MoveTo(subdir.FullName.Replace(ld.FullName, target.FullName))) .Wait(); ld.GetFiles() .ForEachAsync(file => { var tgt = Path.Combine(target.FullName, file.Name); this.Log().Info("Moving file {0} to {1}", file.FullName, tgt); if (File.Exists(tgt)) { Utility.DeleteFileHarder(tgt, true); } file.MoveTo(tgt); }) .Wait(); }); await Utility.DeleteDirectory(libDir.FullName); return target.FullName; })); }