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)); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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()); } } }
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); }
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)); }
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); }
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)); }
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)); }
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()); } } }
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}" }));
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); }
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); }
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); }
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); }
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); }
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)); }
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)); }