public void RemoveShortcutsForExecutable(string exeName, ShortcutLocation locations) { var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory)); var thisRelease = Utility.FindCurrentVersion(releases); var zf = new ZipPackage(Path.Combine( Utility.PackageDirectoryForAppDir(rootAppDirectory), thisRelease.Filename)); var fileVerInfo = FileVersionInfo.GetVersionInfo( Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName)); foreach (var f in (ShortcutLocation[])Enum.GetValues(typeof(ShortcutLocation))) { if (!locations.HasFlag(f)) { continue; } var file = linkTargetForVersionInfo(f, zf, fileVerInfo); this.Log().Info("Removing shortcut for {0} => {1}", exeName, file); this.ErrorIfThrows(() => { if (File.Exists(file)) { File.Delete(file); } }, "Couldn't delete shortcut: " + file); } fixPinnedExecutables(zf.Version); }
public void CreateShortcutsForExecutable(string exeName, ShortcutLocation locations, bool updateOnly) { var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory)); var thisRelease = Utility.FindCurrentVersion(releases); var zf = new ZipPackage(Path.Combine( Utility.PackageDirectoryForAppDir(rootAppDirectory), thisRelease.Filename)); var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName); var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath); foreach (var f in (ShortcutLocation[])Enum.GetValues(typeof(ShortcutLocation))) { if (!locations.HasFlag(f)) { continue; } var file = linkTargetForVersionInfo(f, zf, fileVerInfo); var fileExists = File.Exists(file); // NB: If we've already installed the app, but the shortcut // is no longer there, we have to assume that the user didn't // want it there and explicitly deleted it, so we shouldn't // annoy them by recreating it. if (!fileExists && updateOnly) { this.Log().Warn("Wanted to update shortcut {0} but it appears user deleted it", file); continue; } this.Log().Info("Creating shortcut for {0} => {1}", exeName, file); this.ErrorIfThrows(() => { if (fileExists) { File.Delete(file); } var sl = new ShellLink { Target = exePath, IconPath = exePath, IconIndex = 0, WorkingDirectory = Path.GetDirectoryName(exePath), Description = zf.Description, }; this.Log().Info("About to save shortcut: {0}", file); if (ModeDetector.InUnitTestRunner() == false) { sl.Save(file); } }, "Can't write shortcut: " + file); } }
private static string GetExePath(string rootAppDirectory, string exeName, ReleaseEntry thisRelease) { var releaseDir = Utility.AppDirForRelease(rootAppDirectory, thisRelease); var exePath = Path.Combine(releaseDir, exeName); if (!File.Exists(exePath)) { var matches = Directory.GetFiles(releaseDir, exeName, SearchOption.AllDirectories); exePath = matches.FirstOrDefault() ?? exePath; } return(exePath); }
public Dictionary <ShortcutLocation, ShellLink> GetShortcutsForExecutable(string exeName, ShortcutLocation locations, string programArguments) { this.Log().Info("About to create shortcuts for {0}, rootAppDir {1}", exeName, rootAppDirectory); var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory)); var thisRelease = Utility.FindCurrentVersion(releases); var zf = new ZipPackage(Path.Combine( Utility.PackageDirectoryForAppDir(rootAppDirectory), thisRelease.Filename)); var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName); var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath); var ret = new Dictionary <ShortcutLocation, ShellLink>(); foreach (var f in (ShortcutLocation[])Enum.GetValues(typeof(ShortcutLocation))) { if (!locations.HasFlag(f)) { continue; } var file = linkTargetForVersionInfo(f, zf, fileVerInfo); var appUserModelId = String.Format("com.squirrel.{0}.{1}", zf.Id.Replace(" ", ""), exeName.Replace(".exe", "").Replace(" ", "")); var toastActivatorCLSDID = Utility.CreateGuidFromHash(appUserModelId).ToString(); this.Log().Info("Creating shortcut for {0} => {1}", exeName, file); this.Log().Info("appUserModelId: {0} | toastActivatorCLSID: {1}", appUserModelId, toastActivatorCLSDID); var target = Path.Combine(rootAppDirectory, exeName); var sl = new ShellLink { Target = target, IconPath = target, IconIndex = 0, WorkingDirectory = Path.GetDirectoryName(exePath), Description = zf.Description, }; if (!String.IsNullOrWhiteSpace(programArguments)) { sl.Arguments += String.Format(" -a \"{0}\"", programArguments); } sl.SetAppUserModelId(appUserModelId); sl.SetToastActivatorCLSID(toastActivatorCLSDID); ret.Add(f, sl); } return(ret); }
public Dictionary <ShortcutLocation, ShellLink> GetShortcutsForExecutable(string exeName, ShortcutLocation locations, string programArguments) { this.Log().Info("About to create shortcuts for {0}, rootAppDir {1}", exeName, rootAppDirectory); var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory)); var thisRelease = Utility.FindCurrentVersion(releases); var updateExe = Path.Combine(rootAppDirectory, "update.exe"); var zf = new ZipPackage(Path.Combine( Utility.PackageDirectoryForAppDir(rootAppDirectory), thisRelease.Filename)); var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName); var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath); var ret = new Dictionary <ShortcutLocation, ShellLink>(); foreach (var f in (ShortcutLocation[])Enum.GetValues(typeof(ShortcutLocation))) { if (!locations.HasFlag(f)) { continue; } var file = linkTargetForVersionInfo(f, zf, fileVerInfo); this.Log().Info("Creating shortcut for {0} => {1}", exeName, file); ShellLink sl; sl = new ShellLink { Target = updateExe, IconPath = exePath, IconIndex = 0, WorkingDirectory = Path.GetDirectoryName(exePath), Description = zf.Description, Arguments = "--processStart " + exeName, }; if (!String.IsNullOrWhiteSpace(programArguments)) { sl.Arguments += String.Format(" -a \"{0}\"", programArguments); } sl.SetAppUserModelId(String.Format("com.squirrel.{0}.{1}", zf.Id, exeName.Replace(".exe", ""))); sl.SetAppUserModelRelaunchCommand(String.Format("{0} {1}", sl.Target, sl.Arguments)); ret.Add(f, sl); } return(ret); }
public async Task <string> ApplyReleases(UpdateInfo updateInfo, bool silentInstall, bool attemptingFullInstall, Action <int> progress = null) { progress = progress ?? (_ => { }); progress(0); var release = await createFullPackagesFromDeltas(updateInfo.ReleasesToApply, updateInfo.CurrentlyInstalledVersion); progress(10); if (release == null) { if (attemptingFullInstall) { this.Log().Info("No release to install, running the app"); await invokePostInstall(updateInfo.CurrentlyInstalledVersion.Version, false, true, silentInstall); } progress(100); return(getDirectoryForRelease(updateInfo.CurrentlyInstalledVersion.Version).FullName); } var ret = await this.ErrorIfThrows(() => installPackageToAppDir(updateInfo, release), "Failed to install package to app dir"); progress(30); var currentReleases = await this.ErrorIfThrows(() => updateLocalReleasesFile(), "Failed to update local releases file"); progress(50); var newVersion = currentReleases.MaxBy(x => x.Version).First().Version; executeSelfUpdate(newVersion); await this.ErrorIfThrows(() => invokePostInstall(newVersion, attemptingFullInstall, false, silentInstall), "Failed to invoke post-install"); progress(75); this.Log().Info("Starting fixPinnedExecutables"); this.ErrorIfThrows(() => fixPinnedExecutables(updateInfo.FutureReleaseEntry.Version)); this.Log().Info("Fixing up tray icons"); var trayFixer = new TrayStateChanger(); var appDir = new DirectoryInfo(Utility.AppDirForRelease(rootAppDirectory, updateInfo.FutureReleaseEntry)); var allExes = appDir.GetFiles("*.exe").Select(x => x.Name).ToList(); this.ErrorIfThrows(() => trayFixer.RemoveDeadEntries(allExes, rootAppDirectory, updateInfo.FutureReleaseEntry.Version.ToString())); progress(80); unshimOurselves(); progress(85); try { var currentVersion = updateInfo.CurrentlyInstalledVersion != null ? updateInfo.CurrentlyInstalledVersion.Version : null; await cleanDeadVersions(currentVersion, newVersion); } catch (Exception ex) { this.Log().WarnException("Failed to clean dead versions, continuing anyways", ex); } progress(100); return(ret); }
public void CreateShortcutsForExecutable(string exeName, ShortcutLocation locations, bool updateOnly, string programArguments, string icon) { this.Log().Info("About to create shortcuts for {0}, rootAppDir {1}", exeName, rootAppDirectory); var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory)); var thisRelease = Utility.FindCurrentVersion(releases); var zf = new ZipPackage(Path.Combine( Utility.PackageDirectoryForAppDir(rootAppDirectory), thisRelease.Filename)); var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName); var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath); foreach (var f in (ShortcutLocation[])Enum.GetValues(typeof(ShortcutLocation))) { if (!locations.HasFlag(f)) { continue; } var file = linkTargetForVersionInfo(f, zf, fileVerInfo); var fileExists = File.Exists(file); // NB: If we've already installed the app, but the shortcut // is no longer there, we have to assume that the user didn't // want it there and explicitly deleted it, so we shouldn't // annoy them by recreating it. if (!fileExists && updateOnly) { this.Log().Warn("Wanted to update shortcut {0} but it appears user deleted it", file); continue; } this.Log().Info("Creating shortcut for {0} => {1}", exeName, file); ShellLink sl; this.ErrorIfThrows(() => Utility.Retry(() => { File.Delete(file); var target = Path.Combine(rootAppDirectory, exeName); sl = new ShellLink { Target = target, IconPath = icon ?? target, IconIndex = 0, WorkingDirectory = Path.GetDirectoryName(exePath), Description = zf.Description, }; if (!String.IsNullOrWhiteSpace(programArguments)) { sl.Arguments += String.Format(" -a \"{0}\"", programArguments); } var appUserModelId = String.Format("com.squirrel.{0}.{1}", zf.Id.Replace(" ", ""), exeName.Replace(".exe", "").Replace(" ", "")); var toastActivatorCLSID = Utility.CreateGuidFromHash(appUserModelId).ToString(); sl.SetAppUserModelId(appUserModelId); sl.SetToastActivatorCLSID(toastActivatorCLSID); this.Log().Info("About to save shortcut: {0} (target {1}, workingDir {2}, args {3}, toastActivatorCSLID {4})", file, sl.Target, sl.WorkingDirectory, sl.Arguments, toastActivatorCLSID); if (ModeDetector.InUnitTestRunner() == false) { sl.Save(file); } }, 4), "Can't write shortcut: " + file); } fixPinnedExecutables(zf.Version); }
public void CreateShortcutsForExecutable(string exeName, ShortcutLocation locations, bool updateOnly) { this.Log().Info("About to create shortcuts for {0}, rootAppDir {1}", exeName, rootAppDirectory); var releases = Utility.LoadLocalReleases(Utility.LocalReleaseFileForAppDir(rootAppDirectory)); var thisRelease = Utility.FindCurrentVersion(releases); var updateExe = Path.Combine(rootAppDirectory, "update.exe"); var zf = new ZipPackage(Path.Combine( Utility.PackageDirectoryForAppDir(rootAppDirectory), thisRelease.Filename)); var exePath = Path.Combine(Utility.AppDirForRelease(rootAppDirectory, thisRelease), exeName); var fileVerInfo = FileVersionInfo.GetVersionInfo(exePath); foreach (var f in (ShortcutLocation[])Enum.GetValues(typeof(ShortcutLocation))) { if (!locations.HasFlag(f)) { continue; } var file = linkTargetForVersionInfo(f, zf, fileVerInfo); var fileExists = File.Exists(file); // NB: If we've already installed the app, but the shortcut // is no longer there, we have to assume that the user didn't // want it there and explicitly deleted it, so we shouldn't // annoy them by recreating it. if (!fileExists && updateOnly) { this.Log().Warn("Wanted to update shortcut {0} but it appears user deleted it", file); continue; } this.Log().Info("Creating shortcut for {0} => {1}", exeName, file); ShellLink sl; this.ErrorIfThrows(() => { if (fileExists) { try { sl = new ShellLink(); sl.Open(file); if (sl.Target == updateExe && sl.Description == zf.Description && sl.IconPath == exePath) { return; } File.Delete(file); } catch (Exception ex) { this.Log().WarnException("Tried to compare shortcut and failed", ex); File.Delete(file); } } sl = new ShellLink { Target = updateExe, IconPath = exePath, IconIndex = 0, WorkingDirectory = Path.GetDirectoryName(exePath), Description = zf.Description, Arguments = "--processStart " + exeName, }; sl.SetAppUserModelId(String.Format("com.squirrel.{0}.{1}", zf.Id, exeName.Replace(".exe", ""))); this.Log().Info("About to save shortcut: {0} (target {1}, workingDir {2}, args {3})", file, sl.Target, sl.WorkingDirectory, sl.Arguments); if (ModeDetector.InUnitTestRunner() == false) { sl.Save(file); } }, "Can't write shortcut: " + file); } }
public async Task <string> ApplyReleases(UpdateInfo updateInfo, bool silentInstall, bool attemptingFullInstall, Action <int> progress = null) { progress = progress ?? (_ => { }); var release = await createFullPackagesFromDeltas(updateInfo.ReleasesToApply, updateInfo.CurrentlyInstalledVersion, x => progress(x * 4 / 5)); // The numbers in these progress reports are rather arbitrary. Experience indicates that applying the deltas takes most of the time. // Allocating 80% to that process is a crude approximation. The remaining identifiable steps are simply allocated equal time chunks // of 4% each. // These changes should probably not be pushed upstream without further enhancement. The time to apply deltas is probably dependent // on the size and complexity of the package being updated. progress(80); if (release == null) { if (attemptingFullInstall) { this.Log().Info("No release to install, running the app"); // JohnT: this doesn't work, because if the second argument ('isInitialInstall') is false, invokePostInstall does NOT // run the app. And we mustn't make it do so, or it will try to run the app after installing updates, // since passing attemptingFullInstall for this argument in the other call below is what prevents running // the app post-install when it is already running and updating itself. // We could pass true here for isInitialInstall, but then the app will be invoked as if for the first time, // but it clearly isn't the first time, because it was already installed. // For our fork, it doesn't currently matter, because if we ARE running the full installer and there is // nothing to do, we redo everything, which means that at this point in the code there IS something // to install, namely, the current full release. So I'm just not trying to fix it for now. // If we need to make this run the app we probably need distinct arguments for isInitialInstall and // attemptingFullInstall (or 'runFullApp' or similar). await invokePostInstall(updateInfo.CurrentlyInstalledVersion.Version, false, true, silentInstall); } progress(100); return(getDirectoryForRelease(updateInfo.CurrentlyInstalledVersion.Version).FullName); } var ret = await this.ErrorIfThrows(() => installPackageToAppDir(updateInfo, release), "Failed to install package to app dir"); progress(84); var currentReleases = await this.ErrorIfThrows(() => updateLocalReleasesFile(), "Failed to update local releases file"); progress(88); var newVersion = currentReleases.MaxBy(x => x.Version).First().Version; executeSelfUpdate(newVersion); await this.ErrorIfThrows(() => invokePostInstall(newVersion, attemptingFullInstall, false, silentInstall), "Failed to invoke post-install"); progress(92); this.Log().Info("Starting fixPinnedExecutables"); this.ErrorIfThrows(() => fixPinnedExecutables(updateInfo.FutureReleaseEntry.Version)); this.Log().Info("Fixing up tray icons"); var trayFixer = new TrayStateChanger(); var appDir = new DirectoryInfo(Utility.AppDirForRelease(rootAppDirectory, updateInfo.FutureReleaseEntry)); var allExes = appDir.GetFiles("*.exe").Select(x => x.Name).ToList(); this.ErrorIfThrows(() => trayFixer.RemoveDeadEntries(allExes, rootAppDirectory, updateInfo.FutureReleaseEntry.Version.ToString())); progress(96); unshimOurselves(); progress(98); try { var currentVersion = updateInfo.CurrentlyInstalledVersion != null ? updateInfo.CurrentlyInstalledVersion.Version : null; await cleanDeadVersions(currentVersion, newVersion); } catch (Exception ex) { this.Log().WarnException("Failed to clean dead versions, continuing anyways", ex); } progress(100); return(ret); }