internal static NuGetPackageSearchMedatadata BuildPackageSearchMetadata([NotNull] this SnapApp snapApp, [NotNull] INuGetPackageSources nugetSources) { if (snapApp == null) { throw new ArgumentNullException(nameof(snapApp)); } if (nugetSources == null) { throw new ArgumentNullException(nameof(nugetSources)); } var channel = snapApp.GetCurrentChannelOrThrow(); var updateFeed = (SnapNugetFeed)channel.UpdateFeed; var packageSource = nugetSources.Items.Single(x => x.Name == updateFeed.Name && x.SourceUri == updateFeed.Source); return(new NuGetPackageSearchMedatadata(snapApp.BuildPackageIdentity(), packageSource, DateTimeOffset.Now, new List <PackageDependency>())); }
internal static DownloadResourceResult BuildDownloadResourceResult([NotNull] this SnapApp snapApp, [NotNull] MemoryStream packageStream, [NotNull] INuGetPackageSources nugetSources) { if (snapApp == null) { throw new ArgumentNullException(nameof(snapApp)); } if (packageStream == null) { throw new ArgumentNullException(nameof(packageStream)); } if (nugetSources == null) { throw new ArgumentNullException(nameof(nugetSources)); } var channel = snapApp.GetCurrentChannelOrThrow(); var updateFeed = (SnapNugetFeed)channel.UpdateFeed; var packageSource = nugetSources.Items.Single(x => x.Name == updateFeed.Name && x.SourceUri == updateFeed.Source); return(new DownloadResourceResult(new MemoryStream(packageStream.ToArray()), new PackageArchiveReader(packageStream), packageSource.Name)); }
async Task InvokePostInstall(SnapApp snapApp, NuspecReader nuspecReader, string baseDirectory, string appDirectory, SemanticVersion currentVersion, bool isInitialInstall, ILog logger = null, CancellationToken cancellationToken = default) { var chmod = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows); var coreRunExeAbsolutePath = _snapOs.Filesystem .PathCombine(baseDirectory, _snapEmbeddedResources.GetCoreRunExeFilenameForSnapApp(snapApp)); var mainExeAbsolutePath = _snapOs.Filesystem .PathCombine(appDirectory, _snapEmbeddedResources.GetCoreRunExeFilenameForSnapApp(snapApp)); var iconAbsolutePath = !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && snapApp.Target.Icon != null? _snapOs.Filesystem.PathCombine(appDirectory, snapApp.Target.Icon) : null; var snapChannel = snapApp.GetCurrentChannelOrThrow(); logger?.Debug($"{nameof(coreRunExeAbsolutePath)}: {coreRunExeAbsolutePath}"); logger?.Debug($"{nameof(mainExeAbsolutePath)}: {mainExeAbsolutePath}"); logger?.Debug($"{nameof(iconAbsolutePath)}: {iconAbsolutePath}"); async Task ChmodAsync(string exePath) { if (exePath == null) { throw new ArgumentNullException(nameof(exePath)); } logger?.Info($"Attempting to change file permission for executable: {exePath}."); var chmodSuccess = await _snapOs.ProcessManager.ChmodExecuteAsync(exePath, cancellationToken); logger?.Info($"Permissions changed successfully: {(chmodSuccess ? "true" : "false")}."); } if (chmod) { await ChmodAsync(coreRunExeAbsolutePath); await ChmodAsync(mainExeAbsolutePath); } var coreRunExeFilename = _snapOs.Filesystem.PathGetFileName(coreRunExeAbsolutePath); if (!snapApp.Target.Shortcuts.Any()) { logger?.Warn("This application does not specify any shortcut locations."); } else { var shortcutLocations = snapApp.Target.Shortcuts.First(); snapApp.Target.Shortcuts.Skip(1).ForEach(x => shortcutLocations |= x); logger?.Info($"Shortcuts will be created in the following locations: {string.Join(", ", shortcutLocations)}"); try { var shortcutDescription = new SnapOsShortcutDescription { SnapApp = snapApp, UpdateOnly = isInitialInstall == false, NuspecReader = nuspecReader, ShortcutLocations = shortcutLocations, ExeAbsolutePath = coreRunExeAbsolutePath, IconAbsolutePath = iconAbsolutePath }; await _snapOs.CreateShortcutsForExecutableAsync(shortcutDescription, logger, cancellationToken); } catch (Exception e) { logger?.ErrorException($"Exception thrown while creating shortcut for exe: {coreRunExeFilename}", e); } } var snapAppDllAbsolutePath = _snapOs.Filesystem.PathCombine(appDirectory, SnapConstants.SnapAppDllFilename); try { logger?.Info($"Updating {snapAppDllAbsolutePath}. Current channel is: {snapChannel.Name}."); using var snapAppDllAssemblyDefinition = _snapAppWriter.BuildSnapAppAssembly(snapApp); using var snapAPpDllDestinationStream = _snapOs.Filesystem.FileWrite(snapAppDllAbsolutePath); snapAppDllAssemblyDefinition.Write(snapAPpDllDestinationStream); } catch (Exception e) { logger?.ErrorException($"Unknown error updating {snapAppDllAbsolutePath}", e); } var allSnapAwareApps = new List <string> { mainExeAbsolutePath }.Select(x => { var installOrUpdateTxt = isInitialInstall ? "--snapx-installed" : "--snapx-updated"; return(new ProcessStartInfoBuilder(x) .Add(installOrUpdateTxt) .Add(currentVersion.ToNormalizedString())); }) .ToList(); await InvokeSnapApps(allSnapAwareApps, TimeSpan.FromSeconds(15), isInitialInstall, currentVersion, logger, cancellationToken); }
static async Task <(bool success, bool canContinueIfError, string installerExeAbsolutePath)> BuildInstallerAsync([NotNull] ILog logger, [NotNull] ISnapOs snapOs, [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ISnapPack snapPack, [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] SnapApp snapApp, ICoreRunLib coreRunLib, [NotNull] string installersWorkingDirectory, string fullNupkgAbsolutePath, [NotNull] string releasesNupkgAbsolutePath, bool offline, CancellationToken cancellationToken) { if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (snapOs == null) { throw new ArgumentNullException(nameof(snapOs)); } if (snapxEmbeddedResources == null) { throw new ArgumentNullException(nameof(snapxEmbeddedResources)); } if (snapPack == null) { throw new ArgumentNullException(nameof(snapPack)); } if (snapAppReader == null) { throw new ArgumentNullException(nameof(snapAppReader)); } if (snapAppWriter == null) { throw new ArgumentNullException(nameof(snapAppWriter)); } if (snapApp == null) { throw new ArgumentNullException(nameof(snapApp)); } if (installersWorkingDirectory == null) { throw new ArgumentNullException(nameof(installersWorkingDirectory)); } if (releasesNupkgAbsolutePath == null) { throw new ArgumentNullException(nameof(releasesNupkgAbsolutePath)); } var installerPrefix = offline ? "offline" : "web"; var snapChannel = snapApp.GetCurrentChannelOrThrow(); logger.Info($"Preparing to build {installerPrefix} installer for channel: {snapChannel.Name}. Version: {snapApp.Version}."); var progressSource = new SnapProgressSource { Progress = percentage => { logger.Info($"Progress: {percentage}%."); } }; using var rootTempDir = snapOs.Filesystem.WithDisposableTempDirectory(installersWorkingDirectory); MemoryStream installerZipMemoryStream; MemoryStream warpPackerMemoryStream; string snapAppTargetRid; string warpPackerRid; string warpPackerArch; string installerFilename; string setupExtension; string setupIcon = null; var chmod = false; var changeSubSystemToWindowsGui = false; var installerIconSupported = false; if (snapOs.OsPlatform == OSPlatform.Windows) { warpPackerMemoryStream = snapxEmbeddedResources.WarpPackerWindows; warpPackerRid = "win-x64"; installerIconSupported = true; } else if (snapOs.OsPlatform == OSPlatform.Linux) { warpPackerMemoryStream = snapxEmbeddedResources.WarpPackerLinux; warpPackerRid = "linux-x64"; chmod = true; } else { throw new PlatformNotSupportedException(); } switch (snapApp.Target.Rid) { case "win-x64": installerZipMemoryStream = snapxEmbeddedResources.SetupWindows; warpPackerArch = "windows-x64"; snapAppTargetRid = "win-x64"; installerFilename = "Snap.Installer.exe"; changeSubSystemToWindowsGui = true; setupExtension = ".exe"; if (installerIconSupported && snapApp.Target.Icon != null) { setupIcon = snapApp.Target.Icon; } break; case "linux-x64": installerZipMemoryStream = snapxEmbeddedResources.SetupLinux; warpPackerArch = "linux-x64"; snapAppTargetRid = "linux-x64"; installerFilename = "Snap.Installer"; setupExtension = ".bin"; break; default: throw new PlatformNotSupportedException($"Unsupported rid: {snapApp.Target.Rid}"); } var repackageTempDir = snapOs.Filesystem.PathCombine(rootTempDir.WorkingDirectory, "repackage"); snapOs.Filesystem.DirectoryCreateIfNotExists(repackageTempDir); var rootTempDirWarpPackerAbsolutePath = snapOs.Filesystem.PathCombine(rootTempDir.WorkingDirectory, $"warp-packer-{warpPackerRid}.exe"); var installerRepackageAbsolutePath = snapOs.Filesystem.PathCombine(repackageTempDir, installerFilename); async Task BuildOfflineInstallerAsync() { if (fullNupkgAbsolutePath == null) { throw new ArgumentNullException(nameof(fullNupkgAbsolutePath)); } var repackageDirSnapAppDllAbsolutePath = snapOs.Filesystem.PathCombine(repackageTempDir, SnapConstants.SnapAppDllFilename); var repackageDirFullNupkgAbsolutePath = snapOs.Filesystem.PathCombine(repackageTempDir, "Setup.nupkg"); var repackageDirReleasesNupkgAbsolutePath = snapOs.Filesystem.PathCombine(repackageTempDir, snapOs.Filesystem.PathGetFileName(releasesNupkgAbsolutePath)); await using (installerZipMemoryStream) await using (warpPackerMemoryStream) { using var snapAppAssemblyDefinition = snapAppWriter.BuildSnapAppAssembly(snapApp); await using var snapAppDllDstMemoryStream = snapOs.Filesystem.FileWrite(repackageDirSnapAppDllAbsolutePath); await using var warpPackerDstStream = snapOs.Filesystem.FileWrite(rootTempDirWarpPackerAbsolutePath); using var zipArchive = new ZipArchive(installerZipMemoryStream, ZipArchiveMode.Read); snapAppAssemblyDefinition.Write(snapAppDllDstMemoryStream); progressSource.Raise(10); logger.Info("Extracting installer to temp directory."); zipArchive.ExtractToDirectory(repackageTempDir); progressSource.Raise(20); logger.Info("Copying assets to temp directory."); await Task.WhenAll( warpPackerMemoryStream.CopyToAsync(warpPackerDstStream, cancellationToken), snapOs.Filesystem.FileCopyAsync(fullNupkgAbsolutePath, repackageDirFullNupkgAbsolutePath, cancellationToken), snapOs.Filesystem.FileCopyAsync(releasesNupkgAbsolutePath, repackageDirReleasesNupkgAbsolutePath, cancellationToken)); if (installerIconSupported && setupIcon != null) { logger.Debug($"Writing installer icon: {setupIcon}."); var zipArchiveInstallerFilename = snapOs.Filesystem.PathCombine(repackageTempDir, installerFilename); var rcEditOptions = new RcEditOptions { Filename = zipArchiveInstallerFilename, IconFilename = setupIcon }; CommandRcEdit(rcEditOptions, coreRunLib, snapOs.Filesystem, logger); } } } async Task BuildWebInstallerAsync() { var repackageDirSnapAppDllAbsolutePath = snapOs.Filesystem.PathCombine(repackageTempDir, SnapConstants.SnapAppDllFilename); await using (installerZipMemoryStream) await using (warpPackerMemoryStream) { await using var warpPackerDstStream = snapOs.Filesystem.FileWrite(rootTempDirWarpPackerAbsolutePath); using var zipArchive = new ZipArchive(installerZipMemoryStream, ZipArchiveMode.Read); using var snapAppAssemblyDefinition = snapAppWriter.BuildSnapAppAssembly(snapApp); await using var snapAppDllDstMemoryStream = snapOs.Filesystem.FileWrite(repackageDirSnapAppDllAbsolutePath); snapAppAssemblyDefinition.Write(snapAppDllDstMemoryStream); progressSource.Raise(10); logger.Info("Extracting installer to temp directory."); zipArchive.ExtractToDirectory(repackageTempDir); progressSource.Raise(20); logger.Info("Copying assets to temp directory."); await Task.WhenAll( warpPackerMemoryStream.CopyToAsync(warpPackerDstStream, cancellationToken)); if (installerIconSupported && setupIcon != null) { logger.Debug($"Writing installer icon: {setupIcon}."); var zipArchiveInstallerFilename = snapOs.Filesystem.PathCombine(repackageTempDir, installerFilename); var rcEditOptions = new RcEditOptions { Filename = zipArchiveInstallerFilename, IconFilename = setupIcon }; CommandRcEdit(rcEditOptions, coreRunLib, snapOs.Filesystem, logger); } } } var installerFinalAbsolutePath = snapOs.Filesystem.PathCombine(installersWorkingDirectory, $"Setup-{snapAppTargetRid}-{snapApp.Id}-{snapChannel.Name}-{installerPrefix}{setupExtension}"); if (offline) { await BuildOfflineInstallerAsync(); } else { await BuildWebInstallerAsync(); } progressSource.Raise(50); var processStartInfoBuilder = new ProcessStartInfoBuilder(rootTempDirWarpPackerAbsolutePath) .Add($"--arch {warpPackerArch}") .Add($"--exec {installerFilename}") .Add($"--output {installerFinalAbsolutePath.ForwardSlashesSafe()}") .Add($"--input_dir {repackageTempDir.ForwardSlashesSafe()}"); if (chmod) { await snapOs.ProcessManager.ChmodExecuteAsync(rootTempDirWarpPackerAbsolutePath, cancellationToken); await snapOs.ProcessManager.ChmodExecuteAsync(installerRepackageAbsolutePath, cancellationToken); } logger.Info("Packaging installer."); var(exitCode, stdout) = await snapOs.ProcessManager.RunAsync(processStartInfoBuilder, cancellationToken); if (exitCode != 0) { logger.Error( $"Warp packer exited with error code: {exitCode}. Warp packer executable path: {rootTempDirWarpPackerAbsolutePath}. Stdout: {stdout}."); return(false, false, null); } progressSource.Raise(80); if (changeSubSystemToWindowsGui) { // NB! Unable to set icon on warped executable. Please refer to the following issue: // https://github.com/electron/rcedit/issues/70 var rcEditOptions = new RcEditOptions { ConvertSubSystemToWindowsGui = true, Filename = installerFinalAbsolutePath, //IconFilename = setupIcon }; CommandRcEdit(rcEditOptions, coreRunLib, snapOs.Filesystem, logger); } if (chmod) { await snapOs.ProcessManager.ChmodExecuteAsync(installerFinalAbsolutePath, cancellationToken); } progressSource.Raise(100); return(true, false, installerFinalAbsolutePath); }