Beispiel #1
0
        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>()));
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }