Beispiel #1
0
        internal static INuGetPackageSources BuildNugetSources([NotNull] this SnapApp snapApp, [NotNull] string tempDirectory)
        {
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (tempDirectory == null)
            {
                throw new ArgumentNullException(nameof(tempDirectory));
            }
            var inMemorySettings = new NugetInMemorySettings(tempDirectory);

            var nugetFeeds = snapApp.Channels
                             .SelectMany(x => new List <SnapNugetFeed> {
                x.PushFeed, x.UpdateFeed as SnapNugetFeed
            })
                             .Where(x => x != null)
                             .DistinctBy(x => x.Name)
                             .Select(x => x.BuildPackageSource(inMemorySettings))
                             .ToList();

            return(new NuGetPackageSources(inMemorySettings, nugetFeeds));
        }
Beispiel #2
0
        public void TestBuildNugetFilename_SnapApp(bool isDelta)
        {
            var snapApp = new SnapApp
            {
                Id      = "demoapp",
                Version = new SemanticVersion(1, 0, 0, "preview-123"),
                IsFull  = !isDelta,
                Target  = new SnapTarget
                {
                    Os        = OSPlatform.Windows,
                    Framework = "netcoreapp2.1",
                    Rid       = "win7-x64"
                }
            };

            var fullOrDelta = snapApp.IsFull ? "full" : "delta";

            var expectedPackageId = $"{snapApp.Id}_{fullOrDelta}_{snapApp.Target.Rid}_snapx.{snapApp.Version.ToNormalizedString()}.nupkg".ToLowerInvariant();

            var actualPackageId = snapApp.BuildNugetFilename();

            Assert.Equal(expectedPackageId, actualPackageId);
        }
Beispiel #3
0
        internal static void GetCoreRunExecutableFullPath([NotNull] this SnapApp snapApp, [NotNull] ISnapFilesystem snapFilesystem, [NotNull] string baseDirectory, out string coreRunFullPath)
        {
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (snapFilesystem == null)
            {
                throw new ArgumentNullException(nameof(snapFilesystem));
            }
            if (baseDirectory == null)
            {
                throw new ArgumentNullException(nameof(baseDirectory));
            }

            var exeName = snapApp.Id;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                exeName += ".exe";
            }

            coreRunFullPath = snapFilesystem.PathCombine(baseDirectory, exeName);
        }
Beispiel #4
0
        static async Task PushPackagesAsync([NotNull] PackOptions packOptions, [NotNull] ILog logger, [NotNull] ISnapFilesystem filesystem,
                                            [NotNull] INugetService nugetService, [NotNull] ISnapPackageManager snapPackageManager, [NotNull] IDistributedMutex distributedMutex, [NotNull] SnapAppsReleases snapAppsReleases,
                                            [NotNull] SnapApp snapApp, [NotNull] SnapChannel snapChannel,
                                            [NotNull] List <string> packages, CancellationToken cancellationToken)
        {
            if (packOptions == null)
            {
                throw new ArgumentNullException(nameof(packOptions));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (distributedMutex == null)
            {
                throw new ArgumentNullException(nameof(distributedMutex));
            }
            if (snapAppsReleases == null)
            {
                throw new ArgumentNullException(nameof(snapAppsReleases));
            }
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (snapChannel == null)
            {
                throw new ArgumentNullException(nameof(snapChannel));
            }
            if (packages == null)
            {
                throw new ArgumentNullException(nameof(packages));
            }
            if (packages.Count == 0)
            {
                throw new ArgumentException("Value cannot be an empty collection.", nameof(packages));
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var pushDegreeOfParallelism = Math.Min(Environment.ProcessorCount, packages.Count);

            var nugetSources          = snapApp.BuildNugetSources(filesystem.PathGetTempPath());
            var pushFeedPackageSource = nugetSources.Items.Single(x => x.Name == snapChannel.PushFeed.Name);

            if (pushFeedPackageSource.IsLocalOrUncPath())
            {
                filesystem.DirectoryCreateIfNotExists(pushFeedPackageSource.SourceUri.AbsolutePath);
            }

            if (snapChannel.UpdateFeed.HasCredentials())
            {
                if (!logger.Prompt("y|yes", "Update feed contains credentials. Do you want to continue? [y|n]", infoOnly: packOptions.YesToAllPrompts))
                {
                    logger.Error("Publish aborted.");
                    return;
                }
            }

            logger.Info("Ready to publish application!");

            logger.Info($"Id: {snapApp.Id}");
            logger.Info($"Rid: {snapApp.Target.Rid}");
            logger.Info($"Channel: {snapChannel.Name}");
            logger.Info($"Version: {snapApp.Version}");
            logger.Info($"Feed name: {snapChannel.PushFeed.Name}");

            if (!logger.Prompt("y|yes", "Are you ready to push release upstream? [y|n]", infoOnly: packOptions.YesToAllPrompts))
            {
                logger.Error("Publish aborted.");
                return;
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            logger.Info($"Pushing packages to default channel: {snapChannel.Name}. Feed: {snapChannel.PushFeed.Name}.");

            await packages.ForEachAsync(async packageAbsolutePath =>
                                        await PushPackageAsync(nugetService, filesystem, distributedMutex,
                                                               nugetSources, pushFeedPackageSource, snapChannel, packageAbsolutePath, logger, cancellationToken), pushDegreeOfParallelism);

            logger.Info($"Successfully pushed {packages.Count} packages in {stopwatch.Elapsed.TotalSeconds:F1}s.");

            var skipInitialBlock = pushFeedPackageSource.IsLocalOrUncPath();

            await BlockUntilSnapUpdatedReleasesNupkgAsync(logger, snapPackageManager, snapAppsReleases,
                                                          snapApp, snapChannel, TimeSpan.FromSeconds(15), cancellationToken, skipInitialBlock, packOptions.SkipAwaitUpdate);
        }
Beispiel #5
0
        static async Task <int> CommandPackAsync([NotNull] PackOptions packOptions, [NotNull] ISnapFilesystem filesystem,
                                                 [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] INuGetPackageSources nuGetPackageSources,
                                                 [NotNull] ISnapPack snapPack, [NotNull] INugetService nugetService, [NotNull] ISnapOs snapOs,
                                                 [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ISnapExtractor snapExtractor,
                                                 [NotNull] ISnapPackageManager snapPackageManager, [NotNull] ICoreRunLib coreRunLib, [NotNull] ISnapNetworkTimeProvider snapNetworkTimeProvider,
                                                 [NotNull] ILog logger, [NotNull] IDistributedMutexClient distributedMutexClient, [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (packOptions == null)
            {
                throw new ArgumentNullException(nameof(packOptions));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (snapAppReader == null)
            {
                throw new ArgumentNullException(nameof(snapAppReader));
            }
            if (snapAppWriter == null)
            {
                throw new ArgumentNullException(nameof(snapAppWriter));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (snapPack == null)
            {
                throw new ArgumentNullException(nameof(snapPack));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (snapOs == null)
            {
                throw new ArgumentNullException(nameof(snapOs));
            }
            if (snapxEmbeddedResources == null)
            {
                throw new ArgumentNullException(nameof(snapxEmbeddedResources));
            }
            if (snapExtractor == null)
            {
                throw new ArgumentNullException(nameof(snapExtractor));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (coreRunLib == null)
            {
                throw new ArgumentNullException(nameof(coreRunLib));
            }
            if (snapNetworkTimeProvider == null)
            {
                throw new ArgumentNullException(nameof(snapNetworkTimeProvider));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (distributedMutexClient == null)
            {
                throw new ArgumentNullException(nameof(distributedMutexClient));
            }
            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            var(snapApps, snapApp, error, snapsManifestAbsoluteFilename) = BuildSnapAppFromDirectory(filesystem, snapAppReader,
                                                                                                     nuGetPackageSources, packOptions.Id, packOptions.Rid, workingDirectory);
            if (snapApp == null)
            {
                if (!error)
                {
                    logger.Error($"Snap with id {packOptions.Id} was not found in manifest: {snapsManifestAbsoluteFilename}");
                }

                return(1);
            }

            if (!SemanticVersion.TryParse(packOptions.Version, out var semanticVersion))
            {
                logger.Error($"Unable to parse semantic version (v2): {packOptions.Version}");
                return(1);
            }

            snapApp.Version = semanticVersion;

            if (packOptions.ReleasesNotes != null)
            {
                snapApp.ReleaseNotes = packOptions.ReleasesNotes;
            }

            var artifactsDirectory  = BuildArtifactsDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
            var installersDirectory = BuildInstallersDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
            var packagesDirectory   = BuildPackagesDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);

            filesystem.DirectoryCreateIfNotExists(installersDirectory);
            filesystem.DirectoryCreateIfNotExists(packagesDirectory);

            var snapAppChannel = snapApp.GetDefaultChannelOrThrow();

            MaybeOverrideLockToken(snapApps, logger, packOptions.Id, packOptions.LockToken);

            if (string.IsNullOrWhiteSpace(snapApps.Generic.Token))
            {
                logger.Error("Please specify a token in your snapx.yml file. A random UUID is sufficient.");
                return(1);
            }

            await using var distributedMutex = WithDistributedMutex(distributedMutexClient, logger, snapApps.BuildLockKey(snapApp), cancellationToken);

            logger.Info($"Schema version: {snapApps.Schema}");
            logger.Info($"Packages directory: {packagesDirectory}");
            logger.Info($"Artifacts directory: {artifactsDirectory}");
            logger.Info($"Installers directory: {installersDirectory}");
            logger.Info($"Pack strategy: {snapApps.Generic.PackStrategy}");
            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Id: {snapApp.Id}");
            logger.Info($"Version: {snapApp.Version}");
            logger.Info($"Channel: {snapAppChannel.Name}");
            logger.Info($"Rid: {snapApp.Target.Rid}");
            logger.Info($"OS: {snapApp.Target.Os.ToString().ToLowerInvariant()}");
            var installersStr = !snapApp.Target.Installers.Any() ? "None" : string.Join(", ", snapApp.Target.Installers);

            logger.Info($"Installers: {installersStr}");
            var shortcutsStr = !snapApp.Target.Shortcuts.Any() ? "None" : string.Join(", ", snapApp.Target.Shortcuts);

            logger.Info($"Shortcuts: {shortcutsStr}");

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var tryAcquireRetries = packOptions.LockRetries == -1 ? int.MaxValue : packOptions.LockRetries;

            if (!await distributedMutex.TryAquireAsync(TimeSpan.FromSeconds(15), tryAcquireRetries))
            {
                logger.Info('-'.Repeat(TerminalBufferWidth));
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var updateFeedPackageSource = await snapPackageManager.GetPackageSourceAsync(snapApp);

            logger.Info("Downloading releases nupkg.");

            var snapReleasesPackageDirectory = filesystem.DirectoryGetParent(packagesDirectory);

            filesystem.DirectoryCreateIfNotExists(snapReleasesPackageDirectory);

            var(snapAppsReleases, _, currentReleasesMemoryStream) = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken);

            if (currentReleasesMemoryStream != null)
            {
                await currentReleasesMemoryStream.DisposeAsync();
            }

            if (snapAppsReleases == null)
            {
                if (!logger.Prompt("y|yes", "Unable to find a previous release in any of your NuGet package sources. " +
                                   "Is this the first time you are publishing this application? " +
                                   "NB! The package may not yet be visible to due to upstream caching. [y/n]", infoOnly: packOptions.YesToAllPrompts)
                    )
                {
                    return(1);
                }

                snapAppsReleases = new SnapAppsReleases();
            }
            else
            {
                logger.Info($"Downloaded releases nupkg. Current version: {snapAppsReleases.Version}.");

                if (packOptions.Gc)
                {
                    var releasesRemoved = snapAppsReleases.Gc(snapApp);
                    logger.Info($"Garbage collected (removed) {releasesRemoved} releases.");
                }

                var snapAppChannelReleases = snapAppsReleases.GetReleases(snapApp, snapAppChannel);

                var restoreSummary = await snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases,
                                                                           updateFeedPackageSource, SnapPackageManagerRestoreType.Pack, logger : logger, cancellationToken : cancellationToken);

                if (!restoreSummary.Success)
                {
                    return(1);
                }

                if (snapAppChannelReleases.Any(x => x.Version >= snapApp.Version))
                {
                    logger.Error($"Version {snapApp.Version} is already published to feed: {updateFeedPackageSource.Name}.");
                    return(1);
                }
            }

            var snapPackageDetails = new SnapPackageDetails
            {
                SnapApp             = snapApp,
                NuspecBaseDirectory = artifactsDirectory,
                PackagesDirectory   = packagesDirectory,
                SnapAppsReleases    = snapAppsReleases
            };

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Building nupkg: {snapApp.Version}.");

            var pushPackages = new List <string>();

            var(fullNupkgMemoryStream, fullSnapApp, fullSnapRelease, deltaNupkgMemorystream, deltaSnapApp, deltaSnapRelease) =
                await snapPack.BuildPackageAsync(snapPackageDetails, coreRunLib, cancellationToken);

            var fullNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, fullSnapRelease.Filename);

            await using (fullNupkgMemoryStream)
                await using (deltaNupkgMemorystream)
                {
                    logger.Info($"Writing full nupkg to disk: {fullSnapRelease.Filename}. File size: {fullSnapRelease.FullFilesize.BytesAsHumanReadable()}");
                    await filesystem.FileWriteAsync(fullNupkgMemoryStream, fullNupkgAbsolutePath, default);

                    if (!fullSnapRelease.IsGenesis)
                    {
                        var deltaNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, deltaSnapRelease.Filename);
                        logger.Info(
                            $"Writing delta nupkg to disk: {deltaSnapRelease.Filename}. File size: {deltaSnapRelease.DeltaFilesize.BytesAsHumanReadable()}");
                        await filesystem.FileWriteAsync(deltaNupkgMemorystream, deltaNupkgAbsolutePath, default);
                    }
                }

            var fullOrDeltaSnapApp           = deltaSnapApp ?? fullSnapApp;
            var fullOrDeltaNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, fullOrDeltaSnapApp.BuildNugetFilename());

            pushPackages.Add(fullOrDeltaNupkgAbsolutePath);

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Retrieving network time from: {snapNetworkTimeProvider}.");

            var nowUtc = await SnapUtility.RetryAsync(async() => await snapNetworkTimeProvider.NowUtcAsync(), 3);

            if (!nowUtc.HasValue)
            {
                logger.Error($"Unknown error retrieving network time from: {snapNetworkTimeProvider}");
                return(1);
            }

            var localTimeStr = TimeZoneInfo
                               .ConvertTimeFromUtc(nowUtc.Value, TimeZoneInfo.Local)
                               .ToString("F", CultureInfo.CurrentCulture);

            logger.Info($"Successfully retrieved network time. Time is now: {localTimeStr}");
            logger.Info('-'.Repeat(TerminalBufferWidth));

            fullSnapRelease.CreatedDateUtc = nowUtc.Value;
            if (deltaSnapRelease != null)
            {
                deltaSnapRelease.CreatedDateUtc = nowUtc.Value;
            }
            snapAppsReleases.LastWriteAccessUtc = nowUtc.Value;

            int?forcedDbVersion = null;

            if (packOptions.DbVersion > 0)
            {
                if (packOptions.DbVersion <= snapAppsReleases.DbVersion)
                {
                    logger.Error($"Unable to force database version because version is less than or equal to current database version. \n" +
                                 $"Forced version: {packOptions.DbVersion}.\n" +
                                 $"Current database version: {snapAppsReleases.DbVersion}.");
                    return(1);
                }

                forcedDbVersion = packOptions.DbVersion;

                logger.Info($"Database version is forced because of '--db-version' option. Initial database version: {forcedDbVersion}.");
            }
            else if (fullOrDeltaSnapApp.IsGenesis &&
                     fullOrDeltaSnapApp.Version.Major > snapAppsReleases.Version.Major)
            {
                forcedDbVersion = fullOrDeltaSnapApp.Version.Major;
                logger.Info($"Database version is forced because genesis nupkg detected. Initial database version: {forcedDbVersion}");
            }

            logger.Info($"Building releases nupkg. Current database version: {snapAppsReleases.Version}.");

            var releasesMemoryStream      = snapPack.BuildReleasesPackage(fullOrDeltaSnapApp, snapAppsReleases, forcedDbVersion);
            var releasesNupkgAbsolutePath = snapOs.Filesystem.PathCombine(snapReleasesPackageDirectory, fullOrDeltaSnapApp.BuildNugetReleasesFilename());
            var releasesNupkgFilename     = filesystem.PathGetFileName(releasesNupkgAbsolutePath);
            await snapOs.Filesystem.FileWriteAsync(releasesMemoryStream, releasesNupkgAbsolutePath, cancellationToken);

            pushPackages.Add(releasesNupkgAbsolutePath);

            logger.Info("Finished building releases nupkg.\n" +
                        $"Filename: {releasesNupkgFilename}.\n" +
                        $"Size: {releasesMemoryStream.Length.BytesAsHumanReadable()}.\n" +
                        $"New database version: {snapAppsReleases.Version}.\n" +
                        $"Pack id: {snapAppsReleases.PackId:N}.");

            logger.Info('-'.Repeat(TerminalBufferWidth));

            await using (releasesMemoryStream)
            {
                if (!packOptions.SkipInstallers && fullOrDeltaSnapApp.Target.Installers.Any())
                {
                    var channels = fullOrDeltaSnapApp.IsGenesis ? fullOrDeltaSnapApp.Channels : new List <SnapChannel> {
                        snapAppChannel
                    };

                    foreach (var channel in channels)
                    {
                        var snapAppInstaller = new SnapApp(fullOrDeltaSnapApp);
                        snapAppInstaller.SetCurrentChannel(channel.Name);

                        if (fullOrDeltaSnapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Offline)))
                        {
                            logger.Info('-'.Repeat(TerminalBufferWidth));

                            var(installerOfflineSuccess, canContinueIfError, installerOfflineExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                                                                                                          installersDirectory, fullNupkgAbsolutePath, releasesNupkgAbsolutePath,
                                                                                                                                          true, cancellationToken);

                            if (!installerOfflineSuccess)
                            {
                                if (!canContinueIfError ||
                                    !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)",
                                                   infoOnly: packOptions.YesToAllPrompts))
                                {
                                    logger.Info('-'.Repeat(TerminalBufferWidth));
                                    logger.Error("Unknown error building offline installer.");
                                    return(1);
                                }
                            }
                            else
                            {
                                var installerOfflineExeStat = snapOs.Filesystem.FileStat(installerOfflineExeAbsolutePath);
                                logger.Info($"Successfully built offline installer. File size: {installerOfflineExeStat.Length.BytesAsHumanReadable()}.");
                            }
                        }

                        if (fullOrDeltaSnapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Web)))
                        {
                            logger.Info('-'.Repeat(TerminalBufferWidth));

                            var(installerWebSuccess, canContinueIfError, installerWebExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                                                                                                  installersDirectory, null, releasesNupkgAbsolutePath,
                                                                                                                                  false, cancellationToken);

                            if (!installerWebSuccess)
                            {
                                if (!canContinueIfError ||
                                    !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)",
                                                   infoOnly: packOptions.YesToAllPrompts))
                                {
                                    logger.Info('-'.Repeat(TerminalBufferWidth));
                                    logger.Error("Unknown error building offline installer.");
                                    return(1);
                                }
                            }
                            else
                            {
                                var installerWebExeStat = snapOs.Filesystem.FileStat(installerWebExeAbsolutePath);
                                logger.Info($"Successfully built web installer. File size: {installerWebExeStat.Length.BytesAsHumanReadable()}.");
                            }
                        }
                    }
                }
            }

            if (snapApps.Generic.PackStrategy == SnapAppsPackStrategy.push)
            {
                await PushPackagesAsync(packOptions, logger, filesystem, nugetService,
                                        snapPackageManager, distributedMutex, snapAppsReleases, fullOrDeltaSnapApp, snapAppChannel, pushPackages, cancellationToken);
            }

            logger.Info($"Fetching releases overview from feed {updateFeedPackageSource.Name}.");

            await CommandListAsync(new ListOptions { Id = fullOrDeltaSnapApp.Id }, filesystem, snapAppReader,
                                   nuGetPackageSources, nugetService, snapExtractor, snapPackageManager, logger, workingDirectory, cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Pack completed in {stopwatch.Elapsed.TotalSeconds:F1}s.");

            return(0);
        }
Beispiel #6
0
        public void TestBuildNugetSources_SnapApps()
        {
            var nugetOrgFeed = new SnapNugetFeed
            {
                Name   = "nuget.org",
                Source = new Uri(NuGetConstants.V3FeedUrl)
            };

            var nugetOrgMirrorFeed = new SnapNugetFeed
            {
                Name   = "nuget.org (mirror)",
                Source = new Uri(NuGetConstants.V3FeedUrl)
            };

            var snapApp = new SnapApp
            {
                Id       = "demoapp",
                Version  = new SemanticVersion(1, 0, 0),
                Channels = new List <SnapChannel>
                {
                    new SnapChannel {
                        UpdateFeed = nugetOrgFeed, PushFeed = nugetOrgFeed, Name = "test"
                    },
                    new SnapChannel {
                        UpdateFeed = nugetOrgFeed, PushFeed = nugetOrgFeed, Name = "staging"
                    },
                    new SnapChannel {
                        UpdateFeed = nugetOrgFeed, PushFeed = nugetOrgMirrorFeed, Name = "production"
                    }
                },
                Target = new SnapTarget
                {
                    Os        = OSPlatform.Windows,
                    Rid       = "win-x64",
                    Framework = "netcoreapp2.1"
                }
            };

            var snapApps = new SnapApps
            {
                Schema   = 1,
                Channels = snapApp.Channels.Select(x => new SnapsChannel(x)).ToList(),
                Apps     = new List <SnapsApp> {
                    new SnapsApp(snapApp)
                },
                Generic = new SnapAppsGeneric
                {
                    Packages = "./packages"
                }
            };

            var nugetPackageSources = snapApps.BuildNugetSources(new NuGetInMemoryPackageSources(_baseFixture.NugetTempDirectory, new List <PackageSource>
            {
                new PackageSource(nugetOrgFeed.Source.ToString(), nugetOrgFeed.Name),
                new PackageSource(nugetOrgMirrorFeed.Source.ToString(), nugetOrgMirrorFeed.Name)
            }));

            Assert.Equal(2, nugetPackageSources.Items.Count);

            var nugetOrgPackageSource = nugetPackageSources.Items.First();

            Assert.Equal(nugetOrgPackageSource.Name, nugetOrgFeed.Name);

            var nugetOrgMirrorPackageSource = nugetPackageSources.Items.Skip(1).First();

            Assert.Equal(nugetOrgMirrorPackageSource.Name, nugetOrgMirrorFeed.Name);
        }
Beispiel #7
0
        public SnapReleaseBuilder([NotNull] DisposableDirectory disposableDirectory, SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp, [NotNull] SnapReleaseBuilderContext builderContext)
        {
            if (builderContext == null)
            {
                throw new ArgumentNullException(nameof(builderContext));
            }

            _nuspec = new Dictionary <string, IDisposable>();

            SnapFilesystem        = builderContext.SnapFilesystem ?? throw new ArgumentNullException(nameof(builderContext.SnapFilesystem));
            SnapAppsReleases      = snapAppsReleases ?? throw new ArgumentNullException(nameof(snapAppsReleases));
            SnapApp               = snapApp ?? throw new ArgumentNullException(nameof(snapApp));
            CoreRunLib            = builderContext.CoreRunLib ?? throw new ArgumentNullException(nameof(builderContext.CoreRunLib));
            SnapCryptoProvider    = builderContext.SnapCryptoProvider ?? throw new ArgumentNullException(nameof(builderContext.SnapCryptoProvider));
            SnapEmbeddedResources = builderContext.SnapEmbeddedResources ?? throw new ArgumentNullException(nameof(builderContext.SnapEmbeddedResources));
            SnapPack              = builderContext.SnapPack ?? throw new ArgumentNullException(nameof(builderContext.SnapPack));

            BaseDirectory            = disposableDirectory ?? throw new ArgumentNullException(nameof(disposableDirectory));
            NugetPackagingDirectory  = SnapFilesystem.PathCombine(BaseDirectory.WorkingDirectory, "nuget", $"app-{snapApp.Version}");
            SnapAppBaseDirectory     = SnapFilesystem.PathCombine(BaseDirectory.WorkingDirectory, snapApp.Id);
            SnapAppInstallDirectory  = SnapFilesystem.PathCombine(SnapAppBaseDirectory, $"app-{snapApp.Version}");
            SnapAppPackagesDirectory = SnapFilesystem.PathCombine(SnapAppBaseDirectory, "packages");

            SnapFilesystem.DirectoryCreateIfNotExists(NugetPackagingDirectory);
            SnapFilesystem.DirectoryCreateIfNotExists(SnapAppPackagesDirectory);
            SnapFilesystem.DirectoryCreateIfNotExists(SnapAppInstallDirectory);
        }
Beispiel #8
0
        static async Task <int> CommandPromoteAsync([NotNull] PromoteOptions options, [NotNull] ISnapFilesystem filesystem,
                                                    [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] INuGetPackageSources nuGetPackageSources,
                                                    [NotNull] INugetService nugetService, [NotNull] IDistributedMutexClient distributedMutexClient,
                                                    [NotNull] ISnapPackageManager snapPackageManager, [NotNull] ISnapPack snapPack, [NotNull] ISnapOsSpecialFolders specialFolders,
                                                    [NotNull] ISnapNetworkTimeProvider snapNetworkTimeProvider, [NotNull] ISnapExtractor snapExtractor, [NotNull] ISnapOs snapOs,
                                                    [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ICoreRunLib coreRunLib,
                                                    [NotNull] ILog logger, [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (snapAppReader == null)
            {
                throw new ArgumentNullException(nameof(snapAppReader));
            }
            if (snapAppWriter == null)
            {
                throw new ArgumentNullException(nameof(snapAppWriter));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (distributedMutexClient == null)
            {
                throw new ArgumentNullException(nameof(distributedMutexClient));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (snapPack == null)
            {
                throw new ArgumentNullException(nameof(snapPack));
            }
            if (specialFolders == null)
            {
                throw new ArgumentNullException(nameof(specialFolders));
            }
            if (snapNetworkTimeProvider == null)
            {
                throw new ArgumentNullException(nameof(snapNetworkTimeProvider));
            }
            if (snapExtractor == null)
            {
                throw new ArgumentNullException(nameof(snapExtractor));
            }
            if (snapOs == null)
            {
                throw new ArgumentNullException(nameof(snapOs));
            }
            if (snapxEmbeddedResources == null)
            {
                throw new ArgumentNullException(nameof(snapxEmbeddedResources));
            }
            if (coreRunLib == null)
            {
                throw new ArgumentNullException(nameof(coreRunLib));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }

            var stopWatch = new Stopwatch();

            stopWatch.Restart();

            options.Channel = string.IsNullOrWhiteSpace(options.Channel) ? null : options.Channel;

            if (options.Channel != null && !options.Channel.IsValidChannelName())
            {
                logger.Error($"Invalid channel name: {options.Channel}");
                return(1);
            }

            var(snapApps, snapApp, error, _) = BuildSnapAppFromDirectory(filesystem, snapAppReader,
                                                                         nuGetPackageSources, options.Id, options.Rid, workingDirectory);
            if (snapApp == null)
            {
                if (!error)
                {
                    logger.Error($"Unable to find snap with id: {options.Id}. Rid: {options.Rid}.");
                }

                return(1);
            }

            var installersDirectory = BuildInstallersDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
            var packagesDirectory   = BuildPackagesDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);

            var promoteBaseChannel = snapApp.Channels.SingleOrDefault(x => string.Equals(x.Name, options.Channel, StringComparison.OrdinalIgnoreCase));

            if (promoteBaseChannel == null)
            {
                logger.Error($"Unable to find channel: {options.Channel}.");
                return(1);
            }

            MaybeOverrideLockToken(snapApps, logger, options.Id, options.LockToken);

            if (string.IsNullOrWhiteSpace(snapApps.Generic.Token))
            {
                logger.Error("Please specify a lock token in your snapx.yml file. It's sufficient to generate random UUID (Guid).");
                return(1);
            }

            await using var distributedMutex = WithDistributedMutex(distributedMutexClient, logger, snapApps.BuildLockKey(snapApp), cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var tryAcquireRetries = options.LockRetries == -1 ? int.MaxValue : options.LockRetries;

            if (!await distributedMutex.TryAquireAsync(TimeSpan.FromSeconds(15), tryAcquireRetries))
            {
                logger.Info('-'.Repeat(TerminalBufferWidth));
                return(1);
            }

            var channelsStr = string.Join(", ", snapApp.Channels.Select(x => x.Name));

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Snap id: {options.Id}");
            logger.Info($"Rid: {options.Rid}");
            logger.Info($"Source channel: {options.Channel}");
            logger.Info($"Channels: {channelsStr}");
            logger.Info('-'.Repeat(TerminalBufferWidth));

            logger.Info("Downloading releases nupkg.");
            var(snapAppsReleases, _, releasesMemoryStream) = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken);

            if (releasesMemoryStream != null)
            {
                await releasesMemoryStream.DisposeAsync();
            }
            if (snapAppsReleases == null)
            {
                logger.Error($"Unknown error downloading releases nupkg: {snapApp.BuildNugetReleasesFilename()}.");
                return(1);
            }

            var snapAppChannelReleases = snapAppsReleases.GetReleases(snapApp, promoteBaseChannel);

            var mostRecentRelease = snapAppChannelReleases.GetMostRecentRelease();

            if (mostRecentRelease == null)
            {
                logger.Error($"Unable to find any releases in channel: {promoteBaseChannel.Name}.");
                return(1);
            }

            snapApp.Version = mostRecentRelease.Version;

            var currentChannelIndex = mostRecentRelease.Channels.FindIndex(channelName => channelName == promoteBaseChannel.Name);
            var promotableChannels  = snapApp.Channels
                                      .Skip(currentChannelIndex + 1)
                                      .Select(channel =>
            {
                var releasesThisChannel = snapAppsReleases.GetReleases(snapApp, channel);
                if (releasesThisChannel.Any(x => mostRecentRelease.IsFull ? x.IsFull : x.IsDelta && x.Version == snapApp.Version))
                {
                    return(null);
                }

                return(channel);
            })
                                      .Where(x => x != null)
                                      .ToList();

            if (!promotableChannels.Any())
            {
                logger.Info($"Version {snapApp.Version} is already promoted to all channels.");
                return(0);
            }

            var promoteToChannels = new List <SnapChannel>();

            if (options.ToAllRemainingChannels)
            {
                promoteToChannels.AddRange(promotableChannels);
            }
            else
            {
                promoteToChannels.Add(promotableChannels.First());
            }

            var promoteToChannelsStr = string.Join(", ", promoteToChannels.Select(x => x.Name));

            if (!logger.Prompt("y|yes",
                               $"You are about to promote {snapApp.Id} ({snapApp.Version}) to the following " +
                               $"channel{(promoteToChannels.Count > 1 ? "s" : string.Empty)}: {promoteToChannelsStr}. " +
                               "Do you want to continue? [y|n]", infoOnly: options.YesToAllPrompts)
                )
            {
                return(1);
            }

            foreach (var snapRelease in snapAppChannelReleases.Where(x => x.Version <= mostRecentRelease.Version))
            {
                foreach (var promoteToChannel in promoteToChannels)
                {
                    if (!snapRelease.Channels.Contains(promoteToChannel.Name))
                    {
                        snapRelease.Channels.Add(promoteToChannel.Name);
                    }
                }
            }

            logger.Info("Building releases nupkg.");

            var nowUtc = await SnapUtility.RetryAsync(async() => await snapNetworkTimeProvider.NowUtcAsync(), 3, 1500);

            if (!nowUtc.HasValue)
            {
                logger.Error($"Unknown error while retrieving NTP timestamp from server: {snapNetworkTimeProvider}");
                return(1);
            }

            snapAppsReleases.LastWriteAccessUtc = nowUtc.Value;

            await using var releasesPackageMemoryStream = snapPack.BuildReleasesPackage(snapApp, snapAppsReleases);
            logger.Info("Finished building releases nupkg.");

            var restoreOptions = new RestoreOptions
            {
                Id                  = options.Id,
                Rid                 = options.Rid,
                BuildInstallers     = false,
                RestoreStrategyType = SnapPackageManagerRestoreType.Default
            };

            var restoreSuccess = 0 == await CommandRestoreAsync(
                restoreOptions, filesystem, snapAppReader, snapAppWriter, nuGetPackageSources,
                snapPackageManager, snapOs, snapxEmbeddedResources, coreRunLib, snapPack,
                logger, workingDirectory, cancellationToken
                );

            if (!restoreSuccess)
            {
                return(1);
            }

            await using var tmpDir = new DisposableDirectory(specialFolders.NugetCacheDirectory, filesystem);
            var releasesPackageFilename     = snapApp.BuildNugetReleasesFilename();
            var releasesPackageAbsolutePath = filesystem.PathCombine(tmpDir.WorkingDirectory, releasesPackageFilename);
            await filesystem.FileWriteAsync(releasesPackageMemoryStream, releasesPackageAbsolutePath, cancellationToken);

            if (!options.SkipInstallers && snapApp.Target.Installers.Any())
            {
                foreach (var channel in promoteToChannels)
                {
                    var snapAppInstaller = new SnapApp(snapApp);
                    snapAppInstaller.SetCurrentChannel(channel.Name);

                    var fullNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, snapApp.BuildNugetFullFilename());

                    if (snapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Offline)))
                    {
                        logger.Info('-'.Repeat(TerminalBufferWidth));

                        var(installerOfflineSuccess, canContinueIfError, installerOfflineExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs,
                                                                                                                                      snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                                                                                                      installersDirectory, fullNupkgAbsolutePath, releasesPackageAbsolutePath,
                                                                                                                                      true, cancellationToken);

                        if (!installerOfflineSuccess)
                        {
                            if (!canContinueIfError || !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)", infoOnly: options.YesToAllPrompts))
                            {
                                logger.Info('-'.Repeat(TerminalBufferWidth));
                                logger.Error("Unknown error building offline installer.");
                                return(1);
                            }
                        }
                        else
                        {
                            var installerOfflineExeStat = filesystem.FileStat(installerOfflineExeAbsolutePath);
                            logger.Info($"Successfully built offline installer. File size: {installerOfflineExeStat.Length.BytesAsHumanReadable()}.");
                        }
                    }

                    if (snapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Web)))
                    {
                        logger.Info('-'.Repeat(TerminalBufferWidth));

                        var(installerWebSuccess, canContinueIfError, installerWebExeAbsolutePath) = await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                                                                                              installersDirectory, null, releasesPackageAbsolutePath,
                                                                                                                              false, cancellationToken);

                        if (!installerWebSuccess)
                        {
                            if (!canContinueIfError ||
                                !logger.Prompt("y|yes", "Installer was not built. Do you still want to continue? (y|n)", infoOnly: options.YesToAllPrompts))
                            {
                                logger.Info('-'.Repeat(TerminalBufferWidth));
                                logger.Error("Unknown error building web installer.");
                                return(1);
                            }
                        }
                        else
                        {
                            var installerWebExeStat = filesystem.FileStat(installerWebExeAbsolutePath);
                            logger.Info($"Successfully built web installer. File size: {installerWebExeStat.Length.BytesAsHumanReadable()}.");
                        }
                    }
                }
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            foreach (var(channel, packageSource) in promoteToChannels.Select(snapChannel =>
            {
                var packageSource = nuGetPackageSources.Items.Single(x => x.Name == snapChannel.PushFeed.Name);
                return(snapChannel, packageSource);
            }).DistinctBy(x => x.packageSource.SourceUri))
            {
                logger.Info($"Uploading releases nupkg to feed: {packageSource.Name}.");

                await PushPackageAsync(nugetService, filesystem, distributedMutex, nuGetPackageSources, packageSource,
                                       channel, releasesPackageAbsolutePath, logger, cancellationToken);

                var skipInitialBlock = packageSource.IsLocalOrUncPath();

                await BlockUntilSnapUpdatedReleasesNupkgAsync(logger, snapPackageManager,
                                                              snapAppsReleases, snapApp, channel, TimeSpan.FromSeconds(15), cancellationToken, skipInitialBlock, options.SkipAwaitUpdate);

                logger.Info($"Successfully uploaded releases nupkg to channel: {channel.Name}.");
                logger.Info('-'.Repeat(TerminalBufferWidth));
            }

            logger.Info($"Promote completed in {stopWatch.Elapsed.TotalSeconds:0.0}s.");

            await CommandListAsync(new ListOptions { Id = snapApp.Id }, filesystem, snapAppReader,
                                   nuGetPackageSources, nugetService, snapExtractor, snapPackageManager, logger, workingDirectory, cancellationToken);

            return(0);
        }
Beispiel #9
0
        static async Task <int> CommandRestoreAsync([NotNull] RestoreOptions restoreOptions,
                                                    [NotNull] ISnapFilesystem filesystem, [NotNull] ISnapAppReader snapAppReader, ISnapAppWriter snapAppWriter,
                                                    [NotNull] INuGetPackageSources nuGetPackageSources, [NotNull] ISnapPackageManager snapPackageManager,
                                                    [NotNull] ISnapOs snapOs, [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ICoreRunLib coreRunLib,
                                                    [NotNull] ISnapPack snapPack, [NotNull] ILog logger,
                                                    [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (restoreOptions == null)
            {
                throw new ArgumentNullException(nameof(restoreOptions));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (snapAppReader == null)
            {
                throw new ArgumentNullException(nameof(snapAppReader));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (snapOs == null)
            {
                throw new ArgumentNullException(nameof(snapOs));
            }
            if (snapxEmbeddedResources == null)
            {
                throw new ArgumentNullException(nameof(snapxEmbeddedResources));
            }
            if (coreRunLib == null)
            {
                throw new ArgumentNullException(nameof(coreRunLib));
            }
            if (snapPack == null)
            {
                throw new ArgumentNullException(nameof(snapPack));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }

            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }
            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            var(snapApps, snapAppTargets, errorBuildingSnapApps, _) = BuildSnapAppsesFromDirectory(filesystem, snapAppReader,
                                                                                                   nuGetPackageSources, workingDirectory, requirePushFeed: false);

            if (!snapApps.Apps.Any() || errorBuildingSnapApps)
            {
                return(1);
            }

            if (restoreOptions.Id != null)
            {
                snapAppTargets.RemoveAll(x =>
                                         !string.Equals(x.Id, restoreOptions.Id, StringComparison.OrdinalIgnoreCase));
            }

            if (restoreOptions.Rid != null)
            {
                snapAppTargets.RemoveAll(x =>
                                         !string.Equals(x.Target.Rid, restoreOptions.Rid, StringComparison.OrdinalIgnoreCase));
            }

            if (!snapAppTargets.Any())
            {
                logger.Error($"Unable to restore application {restoreOptions.Id} because it does not exist.");
                return(1);
            }

            if (restoreOptions.BuildInstallers)
            {
                restoreOptions.RestoreStrategyType = SnapPackageManagerRestoreType.Default;
            }

            var applicationNames = snapAppTargets.Select(x => x.Id).Distinct().ToList();
            var rids             = snapAppTargets.Select(x => x.Target.Rid).Distinct().ToList();

            logger.Info($"Applications that will be restored: {string.Join(", ", applicationNames)}. Runtime identifiers (RID): {string.Join(", ", rids)}.");

            var releasePackages = new Dictionary <string, (SnapAppsReleases snapReleases, PackageSource packageSource)>();

            foreach (var snapApp in snapAppTargets)
            {
                var packagesDirectory         = BuildPackagesDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
                var installersDirectory       = BuildInstallersDirectory(filesystem, workingDirectory, snapApps.Generic, snapApp);
                var releasesNupkgAbsolutePath = filesystem.PathCombine(filesystem.DirectoryGetParent(packagesDirectory), snapApp.BuildNugetReleasesFilename());

                filesystem.DirectoryCreateIfNotExists(packagesDirectory);
                filesystem.DirectoryCreateIfNotExists(installersDirectory);

                logger.Info('-'.Repeat(TerminalBufferWidth));
                logger.Info($"Id: {snapApp.Id}.");
                logger.Info($"Rid: {snapApp.Target.Rid}");
                logger.Info($"Packages directory: {packagesDirectory}");
                logger.Info($"Restore strategy: {restoreOptions.RestoreStrategyType}");
                logger.Info($"Restore installers: {(restoreOptions.BuildInstallers ? "yes" : "no")}");

                SnapAppsReleases snapAppsReleases;
                PackageSource    packageSource;
                if (releasePackages.TryGetValue(snapApp.Id, out var cached))
                {
                    snapAppsReleases = cached.snapReleases;
                    packageSource    = cached.packageSource;
                }
                else
                {
                    logger.Info($"Downloading releases nupkg for application {snapApp.Id}");

                    // ReSharper disable once UseDeconstruction
                    var uncached = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken);

                    if (uncached.snapAppsReleases == null)
                    {
                        logger.Error($"Failed to download releases nupkg for application {snapApp.Id}");
                        continue;
                    }

                    await using (uncached.releasesMemoryStream)
                    {
                        await filesystem.FileWriteAsync(uncached.releasesMemoryStream, releasesNupkgAbsolutePath, cancellationToken);
                    }

                    snapAppsReleases = uncached.snapAppsReleases;
                    packageSource    = uncached.packageSource;
                    releasePackages.Add(snapApp.Id, (uncached.snapAppsReleases, uncached.packageSource));

                    logger.Info($"Downloaded releases nupkg. Current version: {snapAppsReleases.Version}.");
                }

                foreach (var snapChannel in snapAppsReleases.GetChannels(snapApp))
                {
                    logger.Info('-'.Repeat(TerminalBufferWidth));
                    logger.Info($"Restoring channel {snapChannel.Name}.");

                    var snapAppReleases = snapAppsReleases.GetReleases(snapApp, snapChannel);
                    if (!snapAppReleases.Any())
                    {
                        logger.Info($"Skipping restore for channel {snapChannel.Name} because no releases was found.");
                        continue;
                    }

                    var restoreSummary = await snapPackageManager.RestoreAsync(packagesDirectory, snapAppReleases, packageSource,
                                                                               restoreOptions.RestoreStrategyType,
                                                                               logger : logger, cancellationToken : cancellationToken,
                                                                               checksumConcurrency : restoreOptions.RestoreConcurrency,
                                                                               downloadConcurrency : restoreOptions.DownloadConcurrency);

                    if (!restoreSummary.Success || !restoreOptions.BuildInstallers)
                    {
                        continue;
                    }

                    var mostRecentSnapRelease = snapAppReleases.GetMostRecentRelease();

                    var snapAppInstaller = new SnapApp(snapAppReleases.App)
                    {
                        Version = mostRecentSnapRelease.Version
                    };

                    snapAppInstaller.SetCurrentChannel(snapChannel.Name);

                    if (restoreOptions.BuildInstallers ||
                        snapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Web)))
                    {
                        logger.Info('-'.Repeat(TerminalBufferWidth));

                        await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                  installersDirectory, null, releasesNupkgAbsolutePath, false, cancellationToken);
                    }

                    if (restoreOptions.BuildInstallers ||
                        snapApp.Target.Installers.Any(x => x.HasFlag(SnapInstallerType.Offline)))
                    {
                        logger.Info('-'.Repeat(TerminalBufferWidth));

                        var fullNupkgAbsolutePath = filesystem.PathCombine(packagesDirectory, mostRecentSnapRelease.BuildNugetFullFilename());

                        await BuildInstallerAsync(logger, snapOs, snapxEmbeddedResources, snapAppWriter, snapAppInstaller, coreRunLib,
                                                  installersDirectory, fullNupkgAbsolutePath, releasesNupkgAbsolutePath, true, cancellationToken);
                    }

                    logger.Info($"Finished restoring channel {snapChannel.Name}.");
                    logger.Info('-'.Repeat(TerminalBufferWidth));
                }
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Restore completed in {stopwatch.Elapsed.TotalSeconds:0.0}s.");

            return(0);
        }
Beispiel #10
0
        internal void SetupDownloadAsyncWithProgressAsync([NotNull] Mock <INugetService> nugetServiceMock, [NotNull] SnapApp snapApp,
                                                          [NotNull] MemoryStream packageStream, [NotNull] INuGetPackageSources nuGetPackageSources)
        {
            if (nugetServiceMock == null)
            {
                throw new ArgumentNullException(nameof(nugetServiceMock));
            }
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }

            var packageIdentity        = snapApp.BuildPackageIdentity();
            var downloadResourceResult = snapApp.BuildDownloadResourceResult(packageStream, nuGetPackageSources);

            nugetServiceMock
            .Setup(x => x.DownloadAsyncWithProgressAsync(
                       It.IsAny <PackageSource>(),
                       It.Is <DownloadContext>(v => v.PackageIdentity.Equals(packageIdentity)),
                       It.IsAny <INugetServiceProgressSource>(),
                       It.IsAny <CancellationToken>()
                       ))
            .ReturnsAsync(() => downloadResourceResult);
        }
Beispiel #11
0
        static SnapApp BuildSnap()
        {
            var nugetOrgFeed = new SnapNugetFeed
            {
                Name            = "nuget.org",
                Source          = new Uri(NuGetConstants.V3FeedUrl),
                ProtocolVersion = NuGetProtocolVersion.V3,
                Username        = "******",
                Password        = "******",
                ApiKey          = "myapikey"
            };

            var updateFeedHttp = new SnapHttpFeed
            {
                Source = new Uri("https://mydynamicupdatefeed.com")
            };

            var testChannel = new SnapChannel
            {
                Name       = "test",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = nugetOrgFeed,
                Current    = true
            };

            var stagingChannel = new SnapChannel
            {
                Name       = "staging",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = updateFeedHttp
            };

            var productionChannel = new SnapChannel
            {
                Name       = "production",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = nugetOrgFeed
            };

            var snapApp = new SnapApp
            {
                Id       = "demoapp",
                Version  = new SemanticVersion(1, 0, 0),
                Channels = new List <SnapChannel>
                {
                    testChannel,
                    stagingChannel,
                    productionChannel
                },
                Target = new SnapTarget
                {
                    Os        = OSPlatform.Windows,
                    Framework = "netcoreapp2.1",
                    Rid       = "win7-x64",
                    Shortcuts = new List <SnapShortcutLocation>
                    {
                        SnapShortcutLocation.Desktop,
                        SnapShortcutLocation.Desktop,
                        SnapShortcutLocation.StartMenu
                    },
                    PersistentAssets = new List <string>
                    {
                        "application.json"
                    }
                }
            };

            return(snapApp);
        }
Beispiel #12
0
        static void AssertSnapApp(SnapApp snapAppBefore, SnapApp snapAppAfter)
        {
            Assert.NotNull(snapAppBefore);
            Assert.NotNull(snapAppAfter);

            // Generic
            Assert.Equal(snapAppBefore.Id, snapAppAfter.Id);
            Assert.Equal(snapAppBefore.Version, snapAppAfter.Version);

            // Target
            Assert.NotNull(snapAppBefore.Target);
            Assert.NotNull(snapAppAfter.Target);
            Assert.Equal(snapAppBefore.Target.Os, snapAppAfter.Target.Os);
            Assert.NotNull(snapAppBefore.Target.Framework);
            Assert.NotNull(snapAppAfter.Target.Framework);
            Assert.Equal(snapAppBefore.Target.Framework, snapAppAfter.Target.Framework);
            Assert.Equal(snapAppBefore.Target.Rid, snapAppAfter.Target.Rid);
            Assert.Equal(snapAppBefore.Target.PersistentAssets, snapAppAfter.Target.PersistentAssets);

            // Channels
            Assert.Equal(snapAppBefore.Channels.Count, snapAppAfter.Channels.Count);
            for (var index = 0; index < snapAppAfter.Channels.Count; index++)
            {
                var lhsChannel = snapAppBefore.Channels[index];
                var rhsChannel = snapAppAfter.Channels[index];

                Assert.Equal(lhsChannel.Name, rhsChannel.Name);
                Assert.NotNull(lhsChannel.PushFeed);
                Assert.NotNull(rhsChannel.PushFeed);
                Assert.NotNull(lhsChannel.UpdateFeed);
                Assert.NotNull(rhsChannel.UpdateFeed);

                if (index == 0)
                {
                    Assert.True(lhsChannel.Current);
                    Assert.True(rhsChannel.Current);
                }
                else
                {
                    Assert.False(lhsChannel.Current);
                    Assert.False(rhsChannel.Current);
                }

                var lhsNugetPushFeed = lhsChannel.PushFeed;
                var rhsNugetPushFeed = rhsChannel.PushFeed;

                Assert.Equal(lhsNugetPushFeed.Name, rhsNugetPushFeed.Name);
                Assert.Equal(lhsNugetPushFeed.Source, rhsNugetPushFeed.Source);
                Assert.Equal(lhsNugetPushFeed.ProtocolVersion, rhsNugetPushFeed.ProtocolVersion);
                Assert.Equal(lhsNugetPushFeed.ApiKey, rhsNugetPushFeed.ApiKey);
                Assert.Equal(lhsNugetPushFeed.Username, rhsNugetPushFeed.Username);
                Assert.Equal(lhsNugetPushFeed.Password, rhsNugetPushFeed.Password);

                var lhsUpdateFeed = lhsChannel.UpdateFeed;
                var rhsUpdateFeed = rhsChannel.UpdateFeed;

                switch (rhsUpdateFeed)
                {
                case SnapNugetFeed rhsNugetUpdateFeed:
                    var lhsNugetUpdateFeed = (SnapNugetFeed)lhsUpdateFeed;
                    Assert.Equal(lhsNugetUpdateFeed.Name, rhsNugetUpdateFeed.Name);
                    Assert.Equal(lhsNugetUpdateFeed.Source, rhsNugetUpdateFeed.Source);
                    Assert.Equal(lhsNugetUpdateFeed.ProtocolVersion, rhsNugetUpdateFeed.ProtocolVersion);
                    Assert.Equal(lhsNugetUpdateFeed.ApiKey, rhsNugetUpdateFeed.ApiKey);
                    Assert.Equal(lhsNugetUpdateFeed.Username, rhsNugetUpdateFeed.Username);
                    Assert.Equal(lhsNugetUpdateFeed.Password, rhsNugetUpdateFeed.Password);
                    break;

                case SnapHttpFeed rhsHttpUpdateFeed:
                    var lhsHttpUpdateFeed = (SnapHttpFeed)lhsUpdateFeed;
                    Assert.NotNull(lhsHttpUpdateFeed.Source);
                    Assert.NotNull(rhsHttpUpdateFeed.Source);
                    Assert.Equal(lhsHttpUpdateFeed.Source, rhsHttpUpdateFeed.Source);
                    break;

                default:
                    throw new NotSupportedException(rhsUpdateFeed.GetType().ToString());
                }
            }
        }
Beispiel #13
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);
        }
Beispiel #14
0
        static async Task BlockUntilSnapUpdatedReleasesNupkgAsync([NotNull] ILog logger, [NotNull] ISnapPackageManager snapPackageManager,
                                                                  [NotNull] SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp,
                                                                  [NotNull] SnapChannel snapChannel, TimeSpan retryInterval, CancellationToken cancellationToken)
        {
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (snapAppsReleases == null)
            {
                throw new ArgumentNullException(nameof(snapAppsReleases));
            }
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (snapChannel == null)
            {
                throw new ArgumentNullException(nameof(snapChannel));
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            logger.Info('-'.Repeat(TerminalBufferWidth));

            logger.Info(
                $"Waiting until uploaded release nupkg is available in feed: {snapChannel.PushFeed.Name}. " +
                $"Retry every {retryInterval.TotalSeconds:0.0}s.");

            var logDashes = false;

            while (!cancellationToken.IsCancellationRequested)
            {
sleep:
                await Task.Delay(retryInterval, cancellationToken);

                if (logDashes)
                {
                    logger.Info('-'.Repeat(TerminalBufferWidth));
                }

                logDashes = true;

                var(upstreamSnapAppsReleases, _, releasesMemoryStream) = await snapPackageManager.GetSnapsReleasesAsync(snapApp, logger, cancellationToken);

                if (releasesMemoryStream != null)
                {
                    await releasesMemoryStream.DisposeAsync();
                }
                if (upstreamSnapAppsReleases == null)
                {
                    goto sleep;
                }

                if (upstreamSnapAppsReleases.PackId == snapAppsReleases.PackId)
                {
                    logger.Info($"{snapChannel.PushFeed.Name} releases nupkg has been successfully updated to version: {upstreamSnapAppsReleases.Version}.\n" +
                                $"Pack id: {upstreamSnapAppsReleases.PackId:N}. \n" +
                                $"Completed in {stopwatch.Elapsed.TotalSeconds:0.0}s. ");
                    break;
                }

                logger.Info(
                    $"Current {snapChannel.PushFeed.Name} version: {upstreamSnapAppsReleases.Version}.\n" +
                    $"Current pack id: {upstreamSnapAppsReleases.PackId:N}\n" +
                    $"Local version: {snapAppsReleases.Version}. \n" +
                    $"Local pack id: {snapAppsReleases.PackId:N} \n" +
                    $"Retry in {retryInterval.TotalSeconds:0.0}s.");
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));
        }
Beispiel #15
0
        internal void SetupDownloadLatestAsync([NotNull] Mock <INugetService> nugetServiceMock, [NotNull] SnapApp snapApp, string upstreamPackageId,
                                               [NotNull] MemoryStream packageStream, [NotNull] INuGetPackageSources nuGetPackageSources)
        {
            if (nugetServiceMock == null)
            {
                throw new ArgumentNullException(nameof(nugetServiceMock));
            }
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }

            var downloadResourceResult = snapApp.BuildDownloadResourceResult(packageStream, nuGetPackageSources);

            nugetServiceMock
            .Setup(x => x
                   .DownloadLatestAsync(
                       It.Is <string>(v => v.Equals(upstreamPackageId)),
                       It.IsAny <PackageSource>(),
                       It.IsAny <bool>(),
                       It.IsAny <bool>(),
                       It.IsAny <CancellationToken>())
                   )
            .ReturnsAsync(() => downloadResourceResult);
        }
Beispiel #16
0
        public async Task TestBuildSnapFeedsFromNugetPackageSources(NuGetProtocolVersion protocolVersion)
        {
            await using var nugetTempDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _fileSystem);

            var feedUrl = protocolVersion switch
            {
                NuGetProtocolVersion.V2 => NuGetConstants.V2FeedUrl,
                NuGetProtocolVersion.V3 => NuGetConstants.V3FeedUrl,
                _ => throw new NotSupportedException(protocolVersion.ToString())
            };

            var snapNugetFeed = new SnapNugetFeed
            {
                Name            = "nuget.org",
                ProtocolVersion = protocolVersion,
                Source          = new Uri(feedUrl),
                Username        = "******",
                Password        = "******",
                ApiKey          = "myapikey"
            };

            var snapChannel = new SnapChannel
            {
                Name       = "test",
                PushFeed   = snapNugetFeed,
                UpdateFeed = snapNugetFeed
            };

            var snapApp = new SnapApp
            {
                Channels = new List <SnapChannel> {
                    snapChannel
                }
            };

            var nugetPackageSources = snapApp.BuildNugetSources(nugetTempDirectory);

            Assert.NotNull(nugetPackageSources.Settings);
            Assert.Single(nugetPackageSources.Items);

            var snapFeeds = snapApp.BuildNugetSources(nugetTempDirectory);

            Assert.NotNull(snapFeeds.Settings);
            Assert.Single(snapFeeds.Items);

            var snapNugetFeedAfter = snapFeeds.Items.Single();

            Assert.Equal(snapNugetFeed.Name, snapNugetFeedAfter.Name);
            Assert.Equal((int)snapNugetFeed.ProtocolVersion, snapNugetFeedAfter.ProtocolVersion);
            Assert.Equal(snapNugetFeed.Source, snapNugetFeedAfter.SourceUri);
            Assert.Equal(snapNugetFeed.Username, snapNugetFeedAfter.Credentials.Username);
            var credential = snapNugetFeedAfter.Credentials;

            if (nugetPackageSources.IsPasswordEncryptionSupported())
            {
                Assert.False(credential.IsPasswordClearText);
                Assert.Equal(EncryptionUtility.DecryptString(snapNugetFeed.Password), credential.Password);
                Assert.Equal(snapNugetFeed.Password, credential.PasswordText);
            }
            else
            {
                Assert.True(credential.IsPasswordClearText);
                Assert.Equal(snapNugetFeed.Password, credential.Password);
            }
            Assert.Equal(snapNugetFeed.ApiKey, snapNugetFeedAfter.GetDecryptedValue(nugetPackageSources, ConfigurationConstants.ApiKeys));
        }
Beispiel #17
0
        internal void SetupGetMetadatasAsync([NotNull] Mock <INugetService> nugetServiceMock, [NotNull] INuGetPackageSources nuGetPackageSources, [NotNull] SnapApp snapApp)
        {
            if (nugetServiceMock == null)
            {
                throw new ArgumentNullException(nameof(nugetServiceMock));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }

            var upstreamPackageId = snapApp.BuildNugetUpstreamId();

            nugetServiceMock.Setup(x =>
                                   x.GetMetadatasAsync(
                                       It.Is <string>(v => string.Equals(v, upstreamPackageId)),
                                       It.IsAny <NuGetPackageSources>(),
                                       It.IsAny <bool>(),
                                       It.IsAny <bool>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(() =>
            {
                var packageSearchMedatadata = snapApp.BuildPackageSearchMetadata(nuGetPackageSources);
                return(new List <NuGetPackageSearchMedatadata> {
                    packageSearchMedatadata
                });
            });

            nugetServiceMock.Setup(x =>
                                   x.GetLatestMetadataAsync(
                                       It.Is <string>(v => string.Equals(v, upstreamPackageId)),
                                       It.IsAny <PackageSource>(),
                                       It.IsAny <bool>(),
                                       It.IsAny <bool>(),
                                       It.IsAny <CancellationToken>()))
            .ReturnsAsync(() => snapApp.BuildPackageSearchMetadata(nuGetPackageSources));
        }
Beispiel #18
0
        public async Task TestBuildSnapApp()
        {
            await using var nugetTempDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _fileSystem);

            var nugetOrgFeed = new SnapNugetFeed
            {
                Name            = "nuget.org",
                Source          = new Uri(NuGetConstants.V3FeedUrl),
                ProtocolVersion = NuGetProtocolVersion.V3,
                Username        = "******",
                Password        = "******",
                ApiKey          = "myapikey"
            };

            var updateFeedHttp = new SnapHttpFeed
            {
                Source = new Uri("https://mydynamicupdatefeed.com")
            };

            var testChannel = new SnapChannel
            {
                Name       = "test",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = nugetOrgFeed,
                Current    = true
            };

            var stagingChannel = new SnapChannel
            {
                Name       = "staging",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = updateFeedHttp
            };

            var productionChannel = new SnapChannel
            {
                Name       = "production",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = nugetOrgFeed
            };

            var snapAppBefore = new SnapApp
            {
                Id      = "demoapp",
                MainExe = "demoapp",
                InstallDirectoryName = "demoapp",
                SuperVisorId         = Guid.NewGuid().ToString(),
                Version  = new SemanticVersion(1, 0, 0),
                Channels = new List <SnapChannel>
                {
                    testChannel,
                    stagingChannel,
                    productionChannel
                },
                Target = new SnapTarget
                {
                    Os        = OSPlatform.Windows,
                    Framework = "netcoreapp2.1",
                    Rid       = "win-x64",
                    Shortcuts = new List <SnapShortcutLocation>
                    {
                        SnapShortcutLocation.Desktop,
                        SnapShortcutLocation.Startup
                    },
                    PersistentAssets = new List <string>
                    {
                        "subdirectory",
                        "myjsonfile.json"
                    }
                }
            };

            var snapApps = new SnapApps(snapAppBefore);

            var snapAppAfter = snapApps.BuildSnapApp(snapAppBefore.Id, snapAppBefore.Target.Rid,
                                                     snapAppBefore.BuildNugetSources(nugetTempDirectory), _fileSystem);

            snapAppAfter.Version = snapAppBefore.Version.BumpMajor();

            // Generic
            Assert.Equal(snapAppBefore.Id, snapAppAfter.Id);
            Assert.Equal(snapAppBefore.InstallDirectoryName, snapAppAfter.InstallDirectoryName);
            Assert.Equal(snapAppBefore.MainExe, snapAppAfter.MainExe);
            Assert.NotNull(snapAppAfter.MainExe);
            Assert.Equal(snapAppBefore.SuperVisorId, snapAppAfter.SuperVisorId);
            Assert.True(snapAppBefore.Version < snapAppAfter.Version);

            // Target
            Assert.NotNull(snapAppBefore.Target);
            Assert.NotNull(snapAppAfter.Target);
            Assert.Equal(snapAppBefore.Target.Os, snapAppAfter.Target.Os);
            Assert.Equal(snapAppBefore.Target.Rid, snapAppAfter.Target.Rid);
            Assert.NotNull(snapAppBefore.Target.Framework);
            Assert.NotNull(snapAppAfter.Target.Framework);
            Assert.Equal(snapAppBefore.Target.Framework, snapAppAfter.Target.Framework);
            Assert.Equal(snapAppBefore.Target.Rid, snapAppAfter.Target.Rid);
            Assert.Equal(snapAppBefore.Target.Shortcuts, snapAppAfter.Target.Shortcuts);
            Assert.Equal(snapAppBefore.Target.PersistentAssets, snapAppAfter.Target.PersistentAssets);

            // Channels
            Assert.Equal(snapAppBefore.Channels.Count, snapAppAfter.Channels.Count);
            for (var index = 0; index < snapAppAfter.Channels.Count; index++)
            {
                var lhsChannel = snapAppBefore.Channels[index];
                var rhsChannel = snapAppAfter.Channels[index];

                Assert.Equal(lhsChannel.Name, rhsChannel.Name);
                Assert.NotNull(lhsChannel.PushFeed);
                Assert.NotNull(rhsChannel.PushFeed);
                Assert.NotNull(lhsChannel.UpdateFeed);
                Assert.NotNull(rhsChannel.UpdateFeed);

                if (index == 0)
                {
                    Assert.True(lhsChannel.Current);
                    Assert.True(rhsChannel.Current);
                }
                else
                {
                    Assert.False(lhsChannel.Current);
                    Assert.False(rhsChannel.Current);
                }

                var lhsNugetPushFeed = lhsChannel.PushFeed;
                var rhsNugetPushFeed = rhsChannel.PushFeed;

                Assert.Equal(lhsNugetPushFeed.Name, rhsNugetPushFeed.Name);
                Assert.Equal(lhsNugetPushFeed.Source, rhsNugetPushFeed.Source);
                Assert.Equal(lhsNugetPushFeed.ProtocolVersion, rhsNugetPushFeed.ProtocolVersion);
                Assert.Equal(lhsNugetPushFeed.ApiKey, rhsNugetPushFeed.ApiKey);
                Assert.Equal(lhsNugetPushFeed.Username, rhsNugetPushFeed.Username);

                // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                if (lhsNugetPushFeed.IsPasswordEncryptionSupported())
                {
                    Assert.Equal(EncryptionUtility.DecryptString(lhsNugetPushFeed.Password), rhsNugetPushFeed.Password);
                }
                else
                {
                    Assert.Equal(lhsNugetPushFeed.Password, rhsNugetPushFeed.Password);
                }

                var lhsUpdateFeed = lhsChannel.UpdateFeed;
                var rhsUpdateFeed = rhsChannel.UpdateFeed;

                switch (rhsUpdateFeed)
                {
                case SnapNugetFeed rhsNugetUpdateFeed:
                    var lhsNugetUpdateFeed = (SnapNugetFeed)lhsUpdateFeed;
                    Assert.Equal(lhsNugetUpdateFeed.Name, rhsNugetUpdateFeed.Name);
                    Assert.Equal(lhsNugetUpdateFeed.Source, rhsNugetUpdateFeed.Source);
                    Assert.Equal(lhsNugetUpdateFeed.ProtocolVersion, rhsNugetUpdateFeed.ProtocolVersion);
                    Assert.Equal(lhsNugetUpdateFeed.ApiKey, rhsNugetUpdateFeed.ApiKey);
                    Assert.Equal(lhsNugetUpdateFeed.Username, rhsNugetUpdateFeed.Username);
                    Assert.Equal(
                        lhsNugetUpdateFeed.IsPasswordEncryptionSupported()
                                ? EncryptionUtility.DecryptString(lhsNugetUpdateFeed.Password)
                                : lhsNugetUpdateFeed.Password, rhsNugetUpdateFeed.Password);
                    break;

                case SnapHttpFeed rhsHttpUpdateFeed:
                    var lhsHttpUpdateFeed = (SnapHttpFeed)lhsUpdateFeed;
                    Assert.NotNull(lhsHttpUpdateFeed.Source);
                    Assert.NotNull(rhsHttpUpdateFeed.Source);
                    Assert.Equal(lhsHttpUpdateFeed.Source, rhsHttpUpdateFeed.Source);
                    break;

                default:
                    throw new NotSupportedException(rhsUpdateFeed.GetType().ToString());
                }
            }
        }
Beispiel #19
0
        static async Task <int> CommandListAsync([NotNull] ListOptions options, [NotNull] ISnapFilesystem filesystem,
                                                 [NotNull] ISnapAppReader appReader, [NotNull] INuGetPackageSources nuGetPackageSources, [NotNull] INugetService nugetService,
                                                 [NotNull] ISnapExtractor snapExtractor, [NotNull] ILog logger,
                                                 [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (appReader == null)
            {
                throw new ArgumentNullException(nameof(appReader));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (snapExtractor == null)
            {
                throw new ArgumentNullException(nameof(snapExtractor));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }

            var(snapApps, snapAppses, errorBuildingSnapApps, _) = BuildSnapAppsesFromDirectory(filesystem, appReader, nuGetPackageSources, workingDirectory);

            if (!snapApps.Apps.Any() || errorBuildingSnapApps)
            {
                return(1);
            }

            if (options.Id != null)
            {
                if (!snapApps.Apps.Any(x => string.Equals(x.Id, options.Id, StringComparison.OrdinalIgnoreCase)))
                {
                    logger.Error($"Unable to find application with id: {options.Id}");
                    return(1);
                }
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            var snapAppses1DGraph = new List <(SnapApp snapApp,
                                               string channelName, string fullOrDeltaPackageId, PackageSource packageSource)>();

            var tables = new List <(SnapApp snapApp, ConsoleTable table)>();

            foreach (var snapApp in snapAppses)
            {
                if (options.Id != null &&
                    !string.Equals(snapApp.Id, options.Id, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                foreach (var channel in snapApp.Channels)
                {
                    var snapAppTmp = new SnapApp(snapApp);
                    snapAppTmp.SetCurrentChannel(channel.Name);

                    var packageSource = nuGetPackageSources.Items.Single(x => x.Name == channel.PushFeed.Name &&
                                                                         x.SourceUri == channel.PushFeed.Source);

                    snapAppses1DGraph.Add((snapApp, channel.Name, snapAppTmp.BuildNugetUpstreamId(), packageSource));
                    snapAppses1DGraph.Add((snapApp, channel.Name, snapAppTmp.BuildNugetUpstreamId(), packageSource));
                }

                var table = tables.SingleOrDefault(x => x.snapApp.Id == snapApp.Id);
                if (table != default)
                {
                    continue;
                }

                var tableColumns = new List <string>();
                tableColumns.Add("Rid");
                tableColumns.AddRange(snapApp.Channels.Select(x => $"Channel: {x.Name}"));
                tableColumns.Add("Summary");

                tables.Add((snapApp, new ConsoleTable(tableColumns)
                {
                    Header = $"Id: {snapApp.Id}"
                }));
Beispiel #20
0
        public async Task TestBuildSnapApp_Throws_If_Multiple_Nuget_Push_Feed_Names()
        {
            await using var nugetTempDirectory = new DisposableDirectory(_baseFixture.WorkingDirectory, _fileSystem);

            var nugetOrgFeed = new SnapNugetFeed
            {
                Name            = "nuget.org",
                Source          = new Uri(NuGetConstants.V3FeedUrl),
                ProtocolVersion = NuGetProtocolVersion.V3,
                Username        = "******",
                Password        = "******",
                ApiKey          = "myapikey"
            };

            var nugetOrgFeed2 = new SnapNugetFeed
            {
                Name            = "nuget2.org",
                Source          = new Uri(NuGetConstants.V3FeedUrl),
                ProtocolVersion = NuGetProtocolVersion.V3,
                Username        = "******",
                Password        = "******",
                ApiKey          = "myapikey"
            };

            var testChannel = new SnapChannel
            {
                Name       = "test",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = nugetOrgFeed,
                Current    = true
            };

            var stagingChannel = new SnapChannel
            {
                Name       = "staging",
                PushFeed   = nugetOrgFeed2,
                UpdateFeed = nugetOrgFeed2
            };

            var productionChannel = new SnapChannel
            {
                Name       = "production",
                PushFeed   = nugetOrgFeed,
                UpdateFeed = nugetOrgFeed
            };

            var snapAppBefore = new SnapApp
            {
                Id           = "demoapp",
                SuperVisorId = Guid.NewGuid().ToString(),
                Version      = new SemanticVersion(1, 0, 0),
                Channels     = new List <SnapChannel>
                {
                    testChannel,
                    stagingChannel,
                    productionChannel
                },
                Target = new SnapTarget
                {
                    Os        = OSPlatform.Windows,
                    Framework = "netcoreapp2.1",
                    Rid       = "win-x64",
                    Shortcuts = new List <SnapShortcutLocation>
                    {
                        SnapShortcutLocation.Desktop,
                        SnapShortcutLocation.Startup
                    },
                    PersistentAssets = new List <string>
                    {
                        "subdirectory",
                        "myjsonfile.json"
                    }
                }
            };

            var snapApps = new SnapApps(snapAppBefore);

            var ex = Assert.Throws <Exception>(() => snapApps.BuildSnapApp(snapAppBefore.Id, snapAppBefore.Target.Rid,
                                                                           snapAppBefore.BuildNugetSources(nugetTempDirectory), _fileSystem));

            Assert.Equal($"Multiple nuget push feeds is not supported: nuget.org,nuget2.org. Application id: {snapAppBefore.Id}", ex.Message);
        }
Beispiel #21
0
        public SnapApp BuildSnapApp(string id = "demoapp", bool isGenesis = false, string rid = null, OSPlatform osPlatform = default)
        {
            var pushFeed = new SnapNugetFeed
            {
                Name            = "nuget.org",
                Source          = new Uri(NuGetConstants.V3FeedUrl),
                ProtocolVersion = NuGetProtocolVersion.V3,
                ApiKey          = "myapikey"
            };

            var updateFeedNuget = new SnapNugetFeed
            {
                Name            = "nuget.org",
                Source          = new Uri(NuGetConstants.V3FeedUrl),
                ProtocolVersion = NuGetProtocolVersion.V3,
                Username        = "******",
                Password        = "******"
            };

            var updateFeedHttp = new SnapHttpFeed
            {
                Source = new Uri("https://mydynamicupdatefeed.com")
            };

            var testChannel = new SnapChannel
            {
                Name       = "test",
                PushFeed   = pushFeed,
                UpdateFeed = updateFeedNuget,
                Current    = true
            };

            var stagingChannel = new SnapChannel
            {
                Name       = "staging",
                PushFeed   = pushFeed,
                UpdateFeed = updateFeedHttp
            };

            var productionChannel = new SnapChannel
            {
                Name       = "production",
                PushFeed   = pushFeed,
                UpdateFeed = updateFeedNuget
            };

            if (osPlatform == default)
            {
                if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    osPlatform = OSPlatform.Windows;
                }
                else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
                {
                    osPlatform = OSPlatform.Linux;
                }
            }

            if (osPlatform != OSPlatform.Windows && osPlatform != OSPlatform.Linux)
            {
                throw new NotSupportedException($"Unsupported OS platform: {osPlatform}");
            }

            var snapApp = new SnapApp
            {
                Id           = id,
                SuperVisorId = Guid.NewGuid().ToString(),
                Version      = new SemanticVersion(1, 0, 0),
                IsGenesis    = isGenesis,
                IsFull       = isGenesis,
                Channels     = new List <SnapChannel>
                {
                    testChannel,
                    stagingChannel,
                    productionChannel
                },
                Target = new SnapTarget
                {
                    Os        = osPlatform,
                    Framework = "netcoreapp2.1",
                    Rid       = rid ?? "win-x64",
                    Shortcuts = new List <SnapShortcutLocation>
                    {
                        SnapShortcutLocation.Desktop,
                        SnapShortcutLocation.Startup,
                        SnapShortcutLocation.StartMenu
                    },
                    PersistentAssets = new List <string>
                    {
                        "application.json"
                    }
                }
            };

            return(snapApp);
        }
Beispiel #22
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 #23
0
        internal void AssertChecksums([NotNull] SnapApp snapApp, [NotNull] SnapRelease snapRelease, [NotNull] List <string> extractedFiles)
        {
            if (snapApp == null)
            {
                throw new ArgumentNullException(nameof(snapApp));
            }
            if (snapRelease == null)
            {
                throw new ArgumentNullException(nameof(snapRelease));
            }
            if (extractedFiles == null)
            {
                throw new ArgumentNullException(nameof(extractedFiles));
            }

            var nupkgAbsoluteFilename = SnapFilesystem.PathCombine(SnapAppPackagesDirectory, snapRelease.Filename);

            Assert.True(SnapFilesystem.FileExists(nupkgAbsoluteFilename));

            using var packageArchiveReader = new PackageArchiveReader(nupkgAbsoluteFilename);
            Assert.Equal(snapApp.ReleaseNotes, snapRelease.ReleaseNotes);

            foreach (var releaseChecksum in snapRelease.Files)
            {
                var(_, _, checksumFileAbsolutePath) = NormalizePath(snapRelease, releaseChecksum.NuspecTargetPath);
                Assert.NotNull(checksumFileAbsolutePath);

                if (snapRelease.IsDelta)
                {
                    var deletedChecksum = snapRelease.Deleted.SingleOrDefault(x => x == releaseChecksum.NuspecTargetPath);
                    if (deletedChecksum != null)
                    {
                        Assert.False(SnapFilesystem.FileExists(checksumFileAbsolutePath));
                        continue;
                    }

                    var unmodifiedChecksum = snapRelease.Unmodified.SingleOrDefault(x => x == releaseChecksum.NuspecTargetPath);
                    if (unmodifiedChecksum != null)
                    {
                        Assert.False(SnapFilesystem.FileExists(checksumFileAbsolutePath));
                        continue;
                    }
                }

                Assert.True(SnapFilesystem.FileExists(checksumFileAbsolutePath));

                using var fileStream = SnapFilesystem.FileRead(checksumFileAbsolutePath);
                var diskSha256Checksum = SnapCryptoProvider.Sha256(fileStream);
                var diskFilesize       = SnapFilesystem.FileStat(checksumFileAbsolutePath).Length;

                SnapReleaseChecksum targetChecksum;
                bool useFullChecksum;
                if (snapRelease.IsFull)
                {
                    targetChecksum  = releaseChecksum;
                    useFullChecksum = true;
                    goto checksum;
                }

                if (SnapPack.NeverGenerateBsDiffsTheseAssemblies.Any(x => x == releaseChecksum.NuspecTargetPath))
                {
                    targetChecksum  = releaseChecksum;
                    useFullChecksum = true;
                    goto checksum;
                }

                targetChecksum = snapRelease.New.SingleOrDefault(x => x.NuspecTargetPath == releaseChecksum.NuspecTargetPath);
                if (targetChecksum != null)
                {
                    useFullChecksum = true;
                }
                else
                {
                    targetChecksum  = snapRelease.Modified.SingleOrDefault(x => x.NuspecTargetPath == releaseChecksum.NuspecTargetPath);
                    useFullChecksum = false;
                }

checksum:
                Assert.NotNull(targetChecksum);

                var expectedChecksum = useFullChecksum ? targetChecksum.FullSha256Checksum : targetChecksum.DeltaSha256Checksum;
                var expectedFilesize = useFullChecksum ? targetChecksum.FullFilesize : targetChecksum.DeltaFilesize;

                Assert.NotNull(expectedChecksum);
                if (expectedChecksum == SnapConstants.Sha256EmptyFileChecksum)
                {
                    Assert.Equal(0, expectedFilesize);
                }
                else
                {
                    Assert.True(expectedFilesize > 0);
                }

                Assert.Equal(expectedChecksum, diskSha256Checksum);
                Assert.Equal(expectedFilesize, diskFilesize);
            }

            var snapReleaseChecksum = SnapCryptoProvider.Sha256(snapRelease, packageArchiveReader, SnapPack);
            var snapReleaseFilesize = SnapFilesystem.FileStat(nupkgAbsoluteFilename)?.Length;

            var expectedReleaseChecksum = snapRelease.IsFull ? snapRelease.FullSha256Checksum : snapRelease.DeltaSha256Checksum;
            var expectedReleaseFilesize = snapRelease.IsFull ? snapRelease.FullFilesize : snapRelease.DeltaFilesize;

            Assert.Equal(expectedReleaseChecksum, snapReleaseChecksum);
            Assert.Equal(expectedReleaseFilesize, snapReleaseFilesize);
        }
Beispiel #24
0
        static async Task <int> CommandDemoteAsync([NotNull] DemoteOptions options, [NotNull] ISnapFilesystem filesystem,
                                                   [NotNull] ISnapAppReader snapAppReader, [NotNull] ISnapAppWriter snapAppWriter, [NotNull] INuGetPackageSources nuGetPackageSources,
                                                   [NotNull] INugetService nugetService, [NotNull] IDistributedMutexClient distributedMutexClient,
                                                   [NotNull] ISnapPackageManager snapPackageManager, [NotNull] ISnapPack snapPack,
                                                   [NotNull] ISnapNetworkTimeProvider snapNetworkTimeProvider, [NotNull] ISnapExtractor snapExtractor, [NotNull] ISnapOs snapOs,
                                                   [NotNull] ISnapxEmbeddedResources snapxEmbeddedResources, [NotNull] ICoreRunLib coreRunLib,
                                                   [NotNull] ILog logger, [NotNull] string workingDirectory, CancellationToken cancellationToken)
        {
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (filesystem == null)
            {
                throw new ArgumentNullException(nameof(filesystem));
            }
            if (snapAppReader == null)
            {
                throw new ArgumentNullException(nameof(snapAppReader));
            }
            if (snapAppWriter == null)
            {
                throw new ArgumentNullException(nameof(snapAppWriter));
            }
            if (nuGetPackageSources == null)
            {
                throw new ArgumentNullException(nameof(nuGetPackageSources));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }
            if (distributedMutexClient == null)
            {
                throw new ArgumentNullException(nameof(distributedMutexClient));
            }
            if (snapPackageManager == null)
            {
                throw new ArgumentNullException(nameof(snapPackageManager));
            }
            if (snapPack == null)
            {
                throw new ArgumentNullException(nameof(snapPack));
            }
            if (snapNetworkTimeProvider == null)
            {
                throw new ArgumentNullException(nameof(snapNetworkTimeProvider));
            }
            if (snapExtractor == null)
            {
                throw new ArgumentNullException(nameof(snapExtractor));
            }
            if (snapOs == null)
            {
                throw new ArgumentNullException(nameof(snapOs));
            }
            if (snapxEmbeddedResources == null)
            {
                throw new ArgumentNullException(nameof(snapxEmbeddedResources));
            }
            if (coreRunLib == null)
            {
                throw new ArgumentNullException(nameof(coreRunLib));
            }
            if (logger == null)
            {
                throw new ArgumentNullException(nameof(logger));
            }
            if (workingDirectory == null)
            {
                throw new ArgumentNullException(nameof(workingDirectory));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (nugetService == null)
            {
                throw new ArgumentNullException(nameof(nugetService));
            }

            var stopwatch = new Stopwatch();

            stopwatch.Restart();

            var             anyRid             = options.Rid == null;
            var             anyVersion         = options.FromVersion == null;
            SnapApp         anyRidSnapApp      = null;
            SemanticVersion fromVersion        = null;
            var             runtimeIdentifiers = new List <string>();

            if (!anyVersion)
            {
                if (!SemanticVersion.TryParse(options.FromVersion, out fromVersion))
                {
                    Console.WriteLine($"Unable to parse from version: {options.FromVersion}");
                    return(1);
                }

                if (!options.RemoveAll)
                {
                    Console.WriteLine("You must specify --remove-all if you want to demote releases newer than --from-version.");
                    return(1);
                }
            }

            var snapApps = BuildSnapAppsFromDirectory(filesystem, snapAppReader, workingDirectory);

            if (!snapApps.Apps.Any())
            {
                return(1);
            }

            foreach (var snapsApp in snapApps.Apps)
            {
                foreach (var target in snapsApp.Targets.Where(target =>
                                                              anyRid || string.Equals(options.Rid, target.Rid, StringComparison.OrdinalIgnoreCase)))
                {
                    anyRidSnapApp = snapApps.BuildSnapApp(snapsApp.Id, target.Rid, nuGetPackageSources, filesystem);
                    runtimeIdentifiers.AddRange(snapApps.GetRids(anyRidSnapApp));
                    break;
                }
            }

            if (anyRidSnapApp == null)
            {
                if (anyRid)
                {
                    logger.Error($"Unable to find application with id: {options.Id}.");
                    return(1);
                }

                logger.Error($"Unable to find application with id: {options.Id}. Rid: {options.Rid}");
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            Console.WriteLine($"Demoting application with id: {anyRidSnapApp.Id}.");
            Console.WriteLine($"Runtime identifiers (RID): {string.Join(", ", runtimeIdentifiers)}");

            if (anyRid)
            {
                if (!logger.Prompt("y|yes", "You have not specified a rid, all releases in listed runtime identifiers will be removed. " +
                                   "Do you want to continue? [y|n]")
                    )
                {
                    return(1);
                }
            }

            MaybeOverrideLockToken(snapApps, logger, options.Id, options.LockToken);

            if (string.IsNullOrWhiteSpace(snapApps.Generic.Token))
            {
                logger.Error("Please specify a token in your snapx.yml file. A random UUID is sufficient.");
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var packagesDirectory = BuildPackagesDirectory(filesystem, workingDirectory);

            filesystem.DirectoryCreateIfNotExists(packagesDirectory);

            await using var distributedMutex = WithDistributedMutex(distributedMutexClient, logger,
                                                                    snapApps.BuildLockKey(anyRidSnapApp), cancellationToken);

            var tryAcquireRetries = options.LockRetries == -1 ? int.MaxValue : options.LockRetries;

            if (!await distributedMutex.TryAquireAsync(TimeSpan.FromSeconds(15), tryAcquireRetries))
            {
                logger.Info('-'.Repeat(TerminalBufferWidth));
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            logger.Info("Downloading releases nupkg.");

            var(snapAppsReleases, _, currentReleasesMemoryStream) = await snapPackageManager
                                                                    .GetSnapsReleasesAsync(anyRidSnapApp, logger, cancellationToken);

            if (currentReleasesMemoryStream != null)
            {
                await currentReleasesMemoryStream.DisposeAsync();
            }

            if (snapAppsReleases == null)
            {
                return(1);
            }

            if (!snapAppsReleases.Any())
            {
                logger.Error($"Releases nupkg does not contain application id: {anyRidSnapApp.Id}");
                return(1);
            }


            logger.Info($"Downloaded releases nupkg. Current version: {snapAppsReleases.Version}.");

            var snapAppReleases = options.RemoveAll ?
                                  snapAppsReleases.GetReleases(anyRidSnapApp, x =>
            {
                bool VersionFilter()
                {
                    return(anyVersion || x.Version > fromVersion);
                }

                bool RidFilter()
                {
                    return(anyRid || x.Target.Rid == anyRidSnapApp.Target.Rid);
                }

                return(RidFilter() && VersionFilter());
            }) :
                                  snapAppsReleases.GetMostRecentReleases(anyRidSnapApp, x => anyRid || x.Target.Rid == anyRidSnapApp.Target.Rid);

            if (!snapAppReleases.Any())
            {
                logger.Error("Unable to find any releases that matches demotion criterias.");
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var consoleTable = new ConsoleTable("Rid", "Channels", "Version", "Count")
            {
                Header = $"Demote summary overview. Total releases: {snapAppReleases.Count()}."
            };

            foreach (var(rid, releases) in snapAppReleases.ToDictionaryByKey(x => x.Target.Rid))
            {
                var channels       = releases.SelectMany(x => x.Channels).Distinct().ToList();
                var releaseVersion = options.RemoveAll ? "All versions" : releases.First().Version.ToString();
                consoleTable.AddRow(new object[]
                {
                    rid,
                    string.Join(", ", channels),
                    releaseVersion,
                    releases.Count.ToString()
                });
            }

            consoleTable.Write(logger);

            if (!logger.Prompt("y|yes", "Ready to demote releases. Do you want to continue? [y|n]"))
            {
                return(1);
            }

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Retrieving network time from: {snapNetworkTimeProvider}.");

            var nowUtc = await SnapUtility.RetryAsync(async() => await snapNetworkTimeProvider.NowUtcAsync(), 3);

            if (!nowUtc.HasValue)
            {
                logger.Error($"Unknown error retrieving network time from: {snapNetworkTimeProvider}");
                return(1);
            }

            var localTimeStr = TimeZoneInfo
                               .ConvertTimeFromUtc(nowUtc.Value, TimeZoneInfo.Local)
                               .ToString("F", CultureInfo.CurrentCulture);

            logger.Info($"Successfully retrieved network time. Time is now: {localTimeStr}");
            logger.Info('-'.Repeat(TerminalBufferWidth));

            var snapAppsReleasesDemotedCount = snapAppsReleases.Demote(snapAppReleases);

            if (snapAppsReleasesDemotedCount != snapAppReleases.Count())
            {
                logger.Error("Unknown error when removing demoted releases. " +
                             $"Expected to remove {snapAppReleases.Count()} but only {snapAppsReleasesDemotedCount} was removed.");
                return(1);
            }

            logger.Info("Building releases nupkg. " +
                        $"Current database version: {snapAppsReleases.Version}. " +
                        $"Releases count: {snapAppsReleases.Count()}.");

            var releasesMemoryStream = !snapAppsReleases.Any() ?
                                       snapPack.BuildEmptyReleasesPackage(anyRidSnapApp, snapAppsReleases) :
                                       snapPack.BuildReleasesPackage(anyRidSnapApp, snapAppsReleases);

            var releasesNupkgAbsolutePath = snapOs.Filesystem.PathCombine(packagesDirectory, anyRidSnapApp.BuildNugetReleasesFilename());
            var releasesNupkgFilename     = filesystem.PathGetFileName(releasesNupkgAbsolutePath);
            await snapOs.Filesystem.FileWriteAsync(releasesMemoryStream, releasesNupkgAbsolutePath, cancellationToken);

            logger.Info("Finished building releases nupkg.\n" +
                        $"Filename: {releasesNupkgFilename}.\n" +
                        $"Size: {releasesMemoryStream.Length.BytesAsHumanReadable()}.\n" +
                        $"New database version: {snapAppsReleases.Version}.\n" +
                        $"Pack id: {snapAppsReleases.PackId:N}.");

            logger.Info('-'.Repeat(TerminalBufferWidth));

            var anySnapTargetDefaultChannel = anyRidSnapApp.Channels.First();
            var nugetSources  = anyRidSnapApp.BuildNugetSources(filesystem.PathGetTempPath());
            var packageSource = nugetSources.Items.Single(x => x.Name == anySnapTargetDefaultChannel.PushFeed.Name);

            await PushPackageAsync(nugetService, filesystem, distributedMutex, nuGetPackageSources, packageSource,
                                   anySnapTargetDefaultChannel, releasesNupkgAbsolutePath, cancellationToken, logger);

            await BlockUntilSnapUpdatedReleasesNupkgAsync(logger, snapPackageManager, snapAppsReleases, anyRidSnapApp,
                                                          anySnapTargetDefaultChannel, TimeSpan.FromSeconds(15), cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));

            await CommandRestoreAsync(new RestoreOptions
            {
                Id              = anyRidSnapApp.Id,
                Rid             = anyRid ? null : anyRidSnapApp.Target.Rid,
                BuildInstallers = true
            }, filesystem, snapAppReader, snapAppWriter,
                                      nuGetPackageSources, snapPackageManager, snapOs, snapxEmbeddedResources,
                                      coreRunLib, snapPack, logger, workingDirectory, cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));

            logger.Info($"Fetching releases overview from feed: {anySnapTargetDefaultChannel.PushFeed.Name}");

            await CommandListAsync(new ListOptions { Id = anyRidSnapApp.Id }, filesystem, snapAppReader,
                                   nuGetPackageSources, nugetService, snapExtractor, logger, workingDirectory, cancellationToken);

            logger.Info('-'.Repeat(TerminalBufferWidth));
            logger.Info($"Demote completed in {stopwatch.Elapsed.TotalSeconds:F1}s.");

            return(0);
        }
Beispiel #25
0
 internal SnapReleaseBuilder WithSnapReleaseBuilder(DisposableDirectory disposableDirectory, [NotNull] SnapAppsReleases snapAppsReleases, [NotNull] SnapApp snapApp, [NotNull] SnapReleaseBuilderContext builderContext)
 {
     if (snapAppsReleases == null)
     {
         throw new ArgumentNullException(nameof(snapAppsReleases));
     }
     if (snapApp == null)
     {
         throw new ArgumentNullException(nameof(snapApp));
     }
     if (builderContext == null)
     {
         throw new ArgumentNullException(nameof(builderContext));
     }
     return(new SnapReleaseBuilder(disposableDirectory, snapAppsReleases, snapApp, builderContext));
 }
Beispiel #26
0
        public void TestBuildNugetSourcesFromSnapApp(NuGetProtocolVersion protocolVersion)
        {
            string feedUrl;

            switch (protocolVersion)
            {
            case NuGetProtocolVersion.V2:
                feedUrl = NuGetConstants.V2FeedUrl;
                break;

            case NuGetProtocolVersion.V3:
                feedUrl = NuGetConstants.V3FeedUrl;
                break;

            default:
                throw new NotSupportedException(protocolVersion.ToString());
            }

            var snapNugetFeed = new SnapNugetFeed
            {
                Name            = "nuget.org",
                ProtocolVersion = protocolVersion,
                Source          = new Uri(feedUrl),
                Username        = "******",
                Password        = "******",
                ApiKey          = "myapikey"
            };

            var snapChannel = new SnapChannel
            {
                Name       = "test",
                PushFeed   = snapNugetFeed,
                UpdateFeed = snapNugetFeed
            };

            var snapApp = new SnapApp
            {
                Channels = new List <SnapChannel> {
                    snapChannel
                }
            };

            var nuGetPackageSources = snapApp.BuildNugetSources(_baseFixture.NugetTempDirectory);

            Assert.Single(nuGetPackageSources.Items);

            var packageSource = nuGetPackageSources.Items.Single();

            Assert.True(packageSource.IsEnabled);
            Assert.True(packageSource.IsOfficial);
            Assert.False(packageSource.IsPersistable);
            Assert.False(packageSource.IsMachineWide);

            Assert.Equal(snapNugetFeed.Name, packageSource.Name);
            Assert.Equal(snapNugetFeed.Source.ToString(), packageSource.TrySourceAsUri.ToString());
            Assert.Equal((int)snapNugetFeed.ProtocolVersion, packageSource.ProtocolVersion);
            Assert.NotNull(packageSource.Credentials);

            var credential = packageSource.Credentials;

            Assert.Equal(snapNugetFeed.Username, credential.Username);
            if (nuGetPackageSources.IsPasswordEncryptionSupported())
            {
                Assert.False(credential.IsPasswordClearText);
                Assert.Equal(EncryptionUtility.DecryptString(snapNugetFeed.Password), credential.Password);
                Assert.Equal(snapNugetFeed.Password, credential.PasswordText);
            }
            else
            {
                Assert.True(credential.IsPasswordClearText);
                Assert.Equal(snapNugetFeed.Password, credential.Password);
            }
            Assert.Equal(snapNugetFeed.Name, credential.Source);

            Assert.Equal(snapNugetFeed.ApiKey, packageSource.GetDecryptedValue(nuGetPackageSources, ConfigurationConstants.ApiKeys));
        }