Example #1
0
        public async Task TestSha256_PackageArchiveReader_Central_Directory_Corrupt()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixture.BuildSnapApp();

            using var testDirectory             = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapOs.Filesystem);
            using var genesisSnapReleaseBuilder = _baseFixture
                                                  .WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext)
                                                  .AddNuspecItem(_baseFixture.BuildSnapExecutable(genesisSnapApp))
                                                  .AddSnapDll();
            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            Checksum(genesisPackageContext.FullPackageSnapRelease);
            Checksum(genesisPackageContext.FullPackageSnapRelease);

            void Checksum(SnapRelease snapRelease)
            {
                if (snapRelease == null)
                {
                    throw new ArgumentNullException(nameof(snapRelease));
                }
                using var asyncPackageCoreReader = new PackageArchiveReader(genesisPackageContext.FullPackageMemoryStream, true);
                var checksum1 = _snapCryptoProvider.Sha256(snapRelease, asyncPackageCoreReader, _snapPack);
                var checksum2 = _snapCryptoProvider.Sha256(snapRelease, asyncPackageCoreReader, _snapPack);

                Assert.NotNull(checksum1);
                Assert.True(checksum1.Length == 64);
                Assert.Equal(checksum1, checksum2);
            }
        }
Example #2
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);
        }
Example #3
0
 public byte[] ToSnapAppsReleases([NotNull] SnapAppsReleases snapAppsApps)
 {
     if (snapAppsApps == null)
     {
         throw new ArgumentNullException(nameof(snapAppsApps));
     }
     return(MessagePackSerializer.Serialize(snapAppsApps, MessagePackSerializerOptions.Standard.WithCompression(MessagePackCompression.Lz4BlockArray)));
 }
Example #4
0
        public async Task TestInstallAsync()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixture.BuildSnapApp();

            Assert.True(genesisSnapApp.Channels.Count >= 2);

            using var testDirectory             = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem);
            using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            var mainAssemblyDefinition = _baseFixture.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainAssemblyDefinition)
            .AddNuspecItem(mainAssemblyDefinition.BuildRuntimeConfigFilename(_snapFilesystem), mainAssemblyDefinition.BuildRuntimeConfig())
            .AddNuspecItem(_baseFixture.BuildLibrary("test1"))
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            var anyOs = SnapOs.AnyOs;

            Assert.NotNull(anyOs);

            var loggerMock = new Mock <ILog>();

            var progressSource = new Mock <ISnapProgressSource>();

            progressSource.
            Setup(x => x.Raise(It.IsAny <int>()));

            var failedRunAsyncReturnValues = new List <(int exitCode, string stdOut)>();

            var snapOsProcessManager = new Mock <ISnapOsProcessManager>();

            snapOsProcessManager
            .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) =>
            {
                var result = _snapOsProcessManager.RunAsync(builder, cancellationToken).GetAwaiter().GetResult();
                if (result.exitCode != 0)
                {
                    failedRunAsyncReturnValues.Add(result);
                }
                return(result);
            });
            snapOsProcessManager
            .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()))
            .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder));
            snapOsProcessManager
            .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken));
            _snapOsMock
            .Setup(x => x.Filesystem)
            .Returns(_snapFilesystem);
            _snapOsMock
            .Setup(x => x.ProcessManager)
            .Returns(snapOsProcessManager.Object);
            _snapOsMock
            .Setup(x => x.CreateShortcutsForExecutableAsync(
                       It.IsAny <SnapOsShortcutDescription>(),
                       It.IsAny <ILog>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask);

            using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem);
            using var installCts    = new CancellationTokenSource();
            var snapCurrentChannel = genesisPackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow();

            await _snapInstaller.InstallAsync(
                genesisPackageContext.FullPackageAbsolutePath,
                baseDirectory.WorkingDirectory,
                genesisPackageContext.FullPackageSnapRelease,
                snapCurrentChannel,
                progressSource.Object,
                loggerMock.Object,
                installCts.Token);

            var appDirectory          = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisPackageContext.FullPackageSnapApp.Version}");
            var snapAppUpdated        = appDirectory.GetSnapAppFromDirectory(_snapFilesystem, _snapAppReader);
            var snapAppUpdatedChannel = snapAppUpdated.GetCurrentChannelOrThrow();

            Assert.Equal(snapCurrentChannel.Name, snapAppUpdatedChannel.Name);

#if !PLATFORM_WINDOWS || NETFULLFRAMEWORK
            // TODO: ENABLE ME! Unable to run a dotnet 2.2 (shared) executable on Windows.
            Assert.Empty(failedRunAsyncReturnValues);
#endif

            var coreRunExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory,
                                                         _snapEmbeddedResources.GetCoreRunExeFilenameForSnapApp(genesisPackageContext.FullPackageSnapApp));
            var appExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory,
                                                     $"app-{genesisSnapReleaseBuilder.SnapApp.Version}", genesisSnapReleaseBuilder.CoreRunExe);
            var snapInstalledArguments = $"--snapx-installed {genesisPackageContext.FullPackageSnapApp.Version.ToNormalizedString()}";
            var snapFirstRunArguments  = $"--snapx-first-run {genesisPackageContext.FullPackageSnapApp.Version.ToNormalizedString()}";

            progressSource.Verify(x => x.Raise(It.Is <int>(v => v == 100)), Times.Once);

            if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
                snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                It.Is <string>(v => v == coreRunExe), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);
                snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                It.Is <string>(v => v == appExe), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);
            }

            _snapOsMock.Verify(x => x.KillAllProcessesInsideDirectory(
                                   It.Is <string>(v => v == baseDirectory.WorkingDirectory)), Times.Once);

            _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                   It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(),
                                   It.IsAny <CancellationToken>()), Times.Once);

            _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                   It.Is <SnapOsShortcutDescription>(v => v.ExeAbsolutePath == coreRunExe),
                                   It.Is <ILog>(v => v != null), It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);

            snapOsProcessManager.Verify(x => x.RunAsync(
                                            It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()), Times.Once);

            snapOsProcessManager.Verify(x => x.RunAsync(
                                            It.Is <ProcessStartInfoBuilder>(v => v.Filename == appExe &&
                                                                            v.Arguments == snapInstalledArguments),
                                            It.Is <CancellationToken>(v => v == installCts.Token)), Times.Once);

            snapOsProcessManager.Verify(x => x.StartNonBlocking(
                                            It.Is <ProcessStartInfoBuilder>(v => v.Filename == appExe
                                                                            & v.Arguments == snapFirstRunArguments)), Times.Once);
            snapOsProcessManager.Verify(x => x.StartNonBlocking(
                                            It.IsAny <ProcessStartInfoBuilder>()), Times.Once);
        }
Example #5
0
        public async Task TestInstallAsync_Different_Channel()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixture.BuildSnapApp();

            Assert.True(genesisSnapApp.Channels.Count >= 2);

            using var testDirectory             = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem);
            using var genesisSnapReleaseBuilder = _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            var mainAssemblyDefinition = _baseFixture.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainAssemblyDefinition)
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            var loggerMock = new Mock <ILog>();

            var snapOsProcessManager = new Mock <ISnapOsProcessManager>();

            snapOsProcessManager
            .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) =>
            {
                var result = _snapOsProcessManager.RunAsync(builder, cancellationToken).GetAwaiter().GetResult();
                return(result);
            });
            snapOsProcessManager
            .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()))
            .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder));
            snapOsProcessManager
            .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
            .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken));
            _snapOsMock
            .Setup(x => x.Filesystem)
            .Returns(_snapFilesystem);
            _snapOsMock
            .Setup(x => x.ProcessManager)
            .Returns(snapOsProcessManager.Object);
            _snapOsMock
            .Setup(x => x.CreateShortcutsForExecutableAsync(
                       It.IsAny <SnapOsShortcutDescription>(),
                       It.IsAny <ILog>(),
                       It.IsAny <CancellationToken>()))
            .Returns(Task.CompletedTask);

            using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem);
            using var installCts    = new CancellationTokenSource();
            var nextSnapChannel = genesisSnapApp.GetNextChannel();

            await _snapInstaller.InstallAsync(
                genesisPackageContext.FullPackageAbsolutePath,
                baseDirectory.WorkingDirectory,
                genesisPackageContext.FullPackageSnapRelease,
                nextSnapChannel,
                null,
                loggerMock.Object,
                installCts.Token);

            var appDirectory          = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, $"app-{genesisPackageContext.FullPackageSnapApp.Version}");
            var snapAppUpdated        = appDirectory.GetSnapAppFromDirectory(_snapFilesystem, _snapAppReader);
            var snapAppUpdatedChannel = snapAppUpdated.GetCurrentChannelOrThrow();

            Assert.Equal(nextSnapChannel.Name, snapAppUpdatedChannel.Name);
        }
        public async Task TestRestoreAsync_Checksums_Genesis()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixturePackaging.BuildSnapApp();
            var snapAppChannel   = genesisSnapApp.GetDefaultChannelOrThrow();

            using var rootDirectory                = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem);
            using var restoreDirectory             = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem);
            using var nugetPackageSourcesDirectory = _snapFilesystem.WithDisposableTempDirectory(_baseFixturePackaging.WorkingDirectory);
            using var genesisReleaseBuilder        =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, genesisSnapApp, _releaseBuilderContext);
            var packagesDirectory = _snapFilesystem.PathCombine(restoreDirectory.WorkingDirectory, "packages");

            _snapFilesystem.DirectoryCreate(packagesDirectory);

            var nugetPackageSources = genesisSnapApp.BuildNugetSources(nugetPackageSourcesDirectory.WorkingDirectory);
            var packageSource       = nugetPackageSources.Items.Single();

            genesisReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(genesisSnapApp))
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixturePackaging.BuildPackageAsync(genesisReleaseBuilder);

            var snapAppChannelReleases = snapAppsReleases.GetReleases(genesisSnapApp, snapAppChannel);
            var progressSourceMock     = new Mock <ISnapPackageManagerProgressSource>();

            progressSourceMock.Setup(x => x.RaiseChecksumProgress(
                                         It.IsAny <int>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>()));

            var genesisPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, genesisPackageContext.FullPackageSnapRelease.Filename);

            await _snapFilesystem.FileCopyAsync(genesisPackageContext.FullPackageAbsolutePath, genesisPackageAbsolutePath, default);

            var restoreSummary = await _snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases,
                                                                        packageSource, SnapPackageManagerRestoreType.Default, progressSourceMock.Object);

            progressSourceMock.Verify(x => x.RaiseChecksumProgress(
                                          It.Is <int>(v => v == 0),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 1)), Times.Once);

            progressSourceMock.Verify(x => x.RaiseChecksumProgress(
                                          It.Is <int>(v => v == 100),
                                          It.Is <long>(v => v == 1),
                                          It.Is <long>(v => v == 1),
                                          It.Is <long>(v => v == 1)), Times.Once);

            Assert.Equal(SnapPackageManagerRestoreType.Default, restoreSummary.RestoreType);

            Assert.Single(restoreSummary.ChecksumSummary);
            Assert.True(restoreSummary.ChecksumSummary[0].Ok);
            Assert.Equal(genesisPackageContext.FullPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[0].SnapRelease.Filename);

            Assert.Empty(restoreSummary.DownloadSummary);
            Assert.Empty(restoreSummary.ReassembleSummary);
            Assert.True(restoreSummary.Success);

            using var packageArchiveReader = new PackageArchiveReader(genesisPackageAbsolutePath);
            Assert.Equal(genesisPackageContext.FullPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity());
            Assert.Equal(genesisPackageContext.FullPackageSnapRelease.FullSha256Checksum,
                         _snapCryptoProvider.Sha256(genesisPackageContext.FullPackageSnapRelease, packageArchiveReader, _snapPack));
        }
        public async Task TestRestoreAsync_Downloads_Genesis_Delta_Consecutive_And_Reassembles_Full_From_Newest_Delta_Only()
        {
            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixturePackaging.BuildSnapApp();
            var update1SnapApp   = _baseFixturePackaging.Bump(genesisSnapApp);
            var update2SnapApp   = _baseFixturePackaging.Bump(update1SnapApp);
            var snapAppChannel   = genesisSnapApp.GetDefaultChannelOrThrow();

            using var rootDirectory                = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem);
            using var restoreDirectory             = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem);
            using var nugetPackageSourcesDirectory = _snapFilesystem.WithDisposableTempDirectory(_baseFixturePackaging.WorkingDirectory);
            using var genesisReleaseBuilder        =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, genesisSnapApp, _releaseBuilderContext);
            using var update1ReleaseBuilder =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update1SnapApp, _releaseBuilderContext);
            using var update2ReleaseBuilder =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update2SnapApp, _releaseBuilderContext);
            var packagesDirectory   = _snapFilesystem.PathCombine(restoreDirectory.WorkingDirectory, "packages");
            var nugetPackageSources = genesisSnapApp.BuildNugetSources(nugetPackageSourcesDirectory.WorkingDirectory);
            var packageSource       = nugetPackageSources.Items.Single();

            genesisReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(genesisSnapApp))
            .AddSnapDll();

            update1ReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update1SnapApp))
            .AddSnapDll();

            update2ReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update2SnapApp))
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixturePackaging.BuildPackageAsync(genesisReleaseBuilder);

            using var update1PackageContext = await _baseFixturePackaging.BuildPackageAsync(update1ReleaseBuilder);

            using var update2PackageContext = await _baseFixturePackaging.BuildPackageAsync(update2ReleaseBuilder);

            _baseFixtureNuget.SetupDownloadAsyncWithProgressAsync(_nugetServiceMock,
                                                                  genesisPackageContext.FullPackageSnapApp,
                                                                  genesisPackageContext.FullPackageMemoryStream,
                                                                  nugetPackageSources
                                                                  );

            _baseFixtureNuget.SetupDownloadAsyncWithProgressAsync(_nugetServiceMock,
                                                                  update1PackageContext.DeltaPackageSnapApp,
                                                                  update1PackageContext.DeltaPackageMemoryStream,
                                                                  nugetPackageSources
                                                                  );

            _baseFixtureNuget.SetupDownloadAsyncWithProgressAsync(_nugetServiceMock,
                                                                  update2PackageContext.DeltaPackageSnapApp,
                                                                  update2PackageContext.DeltaPackageMemoryStream,
                                                                  nugetPackageSources
                                                                  );

            var snapAppChannelReleases = snapAppsReleases.GetReleases(genesisSnapApp, snapAppChannel);
            var progressSourceMock     = new Mock <ISnapPackageManagerProgressSource>();

            progressSourceMock.Setup(x => x.RaiseChecksumProgress(
                                         It.IsAny <int>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>()));
            progressSourceMock.Setup(x =>
                                     x.RaiseDownloadProgress(
                                         It.IsAny <int>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>()));
            progressSourceMock.Setup(x => x.RaiseRestoreProgress(
                                         It.IsAny <int>(),
                                         It.IsAny <long>(),
                                         It.IsAny <long>()));

            var restoreSummary = await _snapPackageManager.RestoreAsync(packagesDirectory, snapAppChannelReleases,
                                                                        packageSource, SnapPackageManagerRestoreType.Default, progressSourceMock.Object);

            progressSourceMock.Verify(x => x.RaiseChecksumProgress(
                                          It.Is <int>(v => v == 0),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 4)), Times.Once);

            progressSourceMock.Verify(x => x.RaiseChecksumProgress(
                                          It.Is <int>(v => v == 100),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 4),
                                          It.Is <long>(v => v == 4)), Times.Once);

            var totalBytesToDownload = genesisPackageContext.FullPackageSnapRelease.FullFilesize +
                                       update1PackageContext.DeltaPackageSnapRelease.DeltaFilesize +
                                       update2PackageContext.DeltaPackageSnapRelease.DeltaFilesize;

            progressSourceMock.Verify(x => x.RaiseDownloadProgress(
                                          It.Is <int>(v => v == 0),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 3),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == totalBytesToDownload)));

            progressSourceMock.Verify(x => x.RaiseRestoreProgress(
                                          It.Is <int>(v => v == 0),
                                          It.Is <long>(v => v == 0),
                                          It.Is <long>(v => v == 8)), Times.Once);

            progressSourceMock.Verify(x => x.RaiseRestoreProgress(
                                          It.Is <int>(v => v == 100),
                                          It.Is <long>(v => v == 8),
                                          It.Is <long>(v => v == 8)), Times.Once);

            Assert.Equal(SnapPackageManagerRestoreType.Default, restoreSummary.RestoreType);

            Assert.Equal(4, restoreSummary.ChecksumSummary.Count);
            Assert.False(restoreSummary.ChecksumSummary[0].Ok);
            Assert.Equal(genesisPackageContext.FullPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[0].SnapRelease.Filename);
            Assert.False(restoreSummary.ChecksumSummary[1].Ok);
            Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[1].SnapRelease.Filename);
            Assert.False(restoreSummary.ChecksumSummary[2].Ok);
            Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[2].SnapRelease.Filename);
            Assert.False(restoreSummary.ChecksumSummary[3].Ok);
            Assert.Equal(update2PackageContext.FullPackageSnapRelease.Filename, restoreSummary.ChecksumSummary[3].SnapRelease.Filename);

            Assert.Equal(3, restoreSummary.DownloadSummary.Count);
            Assert.True(restoreSummary.DownloadSummary[0].Ok);
            Assert.Equal(genesisPackageContext.FullPackageSnapRelease.Filename, restoreSummary.DownloadSummary[0].SnapRelease.Filename);
            Assert.True(restoreSummary.DownloadSummary[1].Ok);
            Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.DownloadSummary[1].SnapRelease.Filename);
            Assert.True(restoreSummary.DownloadSummary[2].Ok);
            Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.Filename, restoreSummary.DownloadSummary[2].SnapRelease.Filename);

            _nugetServiceMock.Verify(x => x.DownloadAsyncWithProgressAsync(
                                         It.IsAny <PackageSource>(),
                                         It.Is <DownloadContext>(v => v.PackageIdentity.Equals(genesisPackageContext.FullPackageSnapRelease.BuildPackageIdentity())),
                                         It.IsAny <INugetServiceProgressSource>(),
                                         It.IsAny <CancellationToken>()), Times.Once);

            _nugetServiceMock.Verify(x => x.DownloadAsyncWithProgressAsync(
                                         It.IsAny <PackageSource>(),
                                         It.Is <DownloadContext>(v => v.PackageIdentity.Equals(update1PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity())),
                                         It.IsAny <INugetServiceProgressSource>(),
                                         It.IsAny <CancellationToken>()), Times.Once);

            _nugetServiceMock.Verify(x => x.DownloadAsyncWithProgressAsync(
                                         It.IsAny <PackageSource>(),
                                         It.Is <DownloadContext>(v => v.PackageIdentity.Equals(update2PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity())),
                                         It.IsAny <INugetServiceProgressSource>(),
                                         It.IsAny <CancellationToken>()), Times.Once);

            Assert.Single(restoreSummary.ReassembleSummary);
            Assert.True(restoreSummary.ReassembleSummary[0].Ok);
            Assert.Equal(update2PackageContext.FullPackageSnapRelease.Filename, restoreSummary.ReassembleSummary[0].SnapRelease.Filename);

            Assert.True(restoreSummary.Success);

            var genesisPackageAbsolutePath = _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.DownloadSummary[0].SnapRelease.Filename);

            var update1FullPackageAbsolutePath =
                _snapFilesystem.PathCombine(packagesDirectory, update1PackageContext.FullPackageSnapRelease.Filename);
            var update1DeltaPackageAbsolutePath =
                _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.DownloadSummary[1].SnapRelease.Filename);

            var update2FullPackageAbsolutePath =
                _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.ReassembleSummary[0].SnapRelease.Filename);
            var update2DeltaPackageAbsolutePath =
                _snapFilesystem.PathCombine(packagesDirectory, restoreSummary.DownloadSummary[2].SnapRelease.Filename);

            using (var packageArchiveReader = new PackageArchiveReader(genesisPackageAbsolutePath))
            {
                Assert.Equal(genesisPackageContext.FullPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity());
                Assert.Equal(genesisPackageContext.FullPackageSnapRelease.FullSha256Checksum,
                             _snapCryptoProvider.Sha256(genesisPackageContext.FullPackageSnapRelease, packageArchiveReader, _snapPack));
            }

            Assert.False(_snapFilesystem.FileExists(update1FullPackageAbsolutePath));

            using (var packageArchiveReader = new PackageArchiveReader(update1DeltaPackageAbsolutePath))
            {
                Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity());
                Assert.Equal(update1PackageContext.DeltaPackageSnapRelease.DeltaSha256Checksum,
                             _snapCryptoProvider.Sha256(update1PackageContext.DeltaPackageSnapRelease, packageArchiveReader, _snapPack));
            }

            using (var packageArchiveReader = new PackageArchiveReader(update2FullPackageAbsolutePath))
            {
                Assert.Equal(update2PackageContext.FullPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity());
                Assert.Equal(update2PackageContext.FullPackageSnapRelease.FullSha256Checksum,
                             _snapCryptoProvider.Sha256(update2PackageContext.FullPackageSnapRelease, packageArchiveReader, _snapPack));
            }

            using (var packageArchiveReader = new PackageArchiveReader(update2DeltaPackageAbsolutePath))
            {
                Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.BuildPackageIdentity(), packageArchiveReader.GetIdentity());
                Assert.Equal(update2PackageContext.DeltaPackageSnapRelease.DeltaSha256Checksum,
                             _snapCryptoProvider.Sha256(update2PackageContext.DeltaPackageSnapRelease, packageArchiveReader, _snapPack));
            }
        }
Example #8
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));
 }
Example #9
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);
        }
Example #10
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);
        }
Example #11
0
        public async Task TestUpdateAsync()
        {
            var snapAppsReleases = new SnapAppsReleases();

            var genesisSnapApp = _baseFixture.BuildSnapApp();
            var update1SnapApp = _baseFixture.Bump(genesisSnapApp);
            var update2SnapApp = _baseFixture.Bump(update1SnapApp);

            await using var testDirectory       = new DisposableDirectory(_baseFixture.WorkingDirectory, _snapFilesystem);
            using var genesisSnapReleaseBuilder =
                      _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            using var update1SnapReleaseBuilder =
                      _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, update1SnapApp, _snapReleaseBuilderContext);
            using var update2SnapReleaseBuilder =
                      _baseFixture.WithSnapReleaseBuilder(testDirectory, snapAppsReleases, update2SnapApp, _snapReleaseBuilderContext);
            var mainExecutable = _baseFixture.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainExecutable)
            .AddNuspecItem(mainExecutable.BuildRuntimeConfigFilename(_snapFilesystem), mainExecutable.BuildRuntimeConfig())
            .AddNuspecItem(_baseFixture.BuildLibrary("test1"))
            .AddSnapDll();

            update1SnapReleaseBuilder
            .AddNuspecItem(genesisSnapReleaseBuilder, 0)
            .AddNuspecItem(genesisSnapReleaseBuilder, 1)
            .AddNuspecItem(genesisSnapReleaseBuilder, 2)
            .AddNuspecItem(_baseFixture.BuildLibrary("test2"))
            .AddSnapDll();

            update2SnapReleaseBuilder
            .AddNuspecItem(update1SnapReleaseBuilder, 0)
            .AddNuspecItem(update1SnapReleaseBuilder, 1)
            .AddNuspecItem(update1SnapReleaseBuilder, 2)
            .AddNuspecItem(update1SnapReleaseBuilder, 3)
            .AddNuspecItem(_baseFixture.BuildLibrary("test3"))
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixture.BuildPackageAsync(genesisSnapReleaseBuilder);

            using (await _baseFixture.BuildPackageAsync(update1SnapReleaseBuilder))
            {
                using var update2PackageContext = await _baseFixture.BuildPackageAsync(update2SnapReleaseBuilder);

                var loggerMock = new Mock <ILog>();

                var progressSource = new Mock <ISnapProgressSource>();
                progressSource.
                Setup(x => x.Raise(It.IsAny <int>()));

                var snapOsProcessManager = new Mock <ISnapOsProcessManager>();
                snapOsProcessManager
                .Setup(x => x.RunAsync(It.IsAny <ProcessStartInfoBuilder>(), It.IsAny <CancellationToken>()))
                .ReturnsAsync((ProcessStartInfoBuilder builder, CancellationToken cancellationToken) =>
                {
                    var result = TplHelper.RunSync(() => _snapOsProcessManager.RunAsync(builder, cancellationToken));
                    return(result);
                });
                snapOsProcessManager
                .Setup(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()))
                .Returns((ProcessStartInfoBuilder builder) => _snapOsProcessManager.StartNonBlocking(builder));
                snapOsProcessManager
                .Setup(x => x.ChmodExecuteAsync(It.IsAny <string>(), It.IsAny <CancellationToken>()))
                .Returns((string filename, CancellationToken cancellationToken) => _snapOsProcessManager.ChmodExecuteAsync(filename, cancellationToken));
                _snapOsMock
                .Setup(x => x.Filesystem)
                .Returns(_snapFilesystem);
                _snapOsMock
                .Setup(x => x.ProcessManager)
                .Returns(snapOsProcessManager.Object);
                _snapOsMock
                .Setup(x => x.CreateShortcutsForExecutableAsync(
                           It.IsAny <SnapOsShortcutDescription>(),
                           It.IsAny <ILog>(),
                           It.IsAny <CancellationToken>()))
                .Returns(Task.CompletedTask);

                await using var baseDirectory = _baseFixture.WithDisposableTempDirectory(_snapFilesystem);
                using var updateCts           = new CancellationTokenSource();
                await _snapInstaller.InstallAsync(
                    genesisPackageContext.FullPackageAbsolutePath,
                    baseDirectory.WorkingDirectory,
                    genesisPackageContext.FullPackageSnapRelease,
                    genesisPackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(),
                    cancellationToken : updateCts.Token);

                _snapOsMock.Invocations.Clear();
                snapOsProcessManager.Invocations.Clear();

                var update2FullNupkgAbsolutePath = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, "packages",
                                                                               update2PackageContext.FullPackageSnapRelease.BuildNugetFilename());

                await _snapFilesystem.FileCopyAsync(update2PackageContext.FullPackageAbsolutePath,
                                                    update2FullNupkgAbsolutePath, default);

                await _snapInstaller.UpdateAsync(
                    baseDirectory.WorkingDirectory,
                    update2PackageContext.FullPackageSnapRelease,
                    update2PackageContext.FullPackageSnapApp.GetCurrentChannelOrThrow(),
                    progressSource.Object,
                    loggerMock.Object,
                    updateCts.Token);

                var coreRunExe = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory, update2SnapReleaseBuilder.CoreRunExe);
                var appExe     = _snapFilesystem.PathCombine(baseDirectory.WorkingDirectory,
                                                             $"app-{update2SnapReleaseBuilder.SnapApp.Version}", update2SnapReleaseBuilder.CoreRunExe);
                var snapUpdatedArguments = $"--snapx-updated {update2SnapReleaseBuilder.SnapApp.Version.ToNormalizedString()}";

                progressSource.Verify(x => x.Raise(It.Is <int>(v => v == 100)), Times.Once);

                if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
                {
                    snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                    It.IsAny <string>(), It.IsAny <CancellationToken>()), Times.Exactly(2));
                    snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                    It.Is <string>(v => v == coreRunExe), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);
                    snapOsProcessManager.Verify(x => x.ChmodExecuteAsync(
                                                    It.Is <string>(v => v == appExe), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);
                }

                _snapOsMock.Verify(x => x.KillAllProcessesInsideDirectory(
                                       It.IsAny <string>()), Times.Never);

                _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                       It.IsAny <SnapOsShortcutDescription>(), It.IsAny <ILog>(),
                                       It.IsAny <CancellationToken>()), Times.Once);

                _snapOsMock.Verify(x => x.CreateShortcutsForExecutableAsync(
                                       It.Is <SnapOsShortcutDescription>(v => v.ExeAbsolutePath == coreRunExe),
                                       It.Is <ILog>(v => v != null), It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);

                snapOsProcessManager.Verify(x => x.RunAsync(It.Is <ProcessStartInfoBuilder>(
                                                                v => v.Filename == appExe && v.Arguments == snapUpdatedArguments),
                                                            It.Is <CancellationToken>(v => v == updateCts.Token)), Times.Once);

                snapOsProcessManager.Verify(x => x.StartNonBlocking(It.IsAny <ProcessStartInfoBuilder>()), Times.Never);
            }
        }
Example #12
0
        public async Task TestGetSnapsReleasesAsync()
        {
            using var _ = LogHelper.Capture(_testOutputHelper, LogProvider.SetCurrentLogProvider);

            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixturePackaging.BuildSnapApp();
            var update1SnapApp   = _baseFixturePackaging.Bump(genesisSnapApp);
            var update2SnapApp   = _baseFixturePackaging.Bump(update1SnapApp);

            await using var rootDirectory = new DisposableDirectory(_baseFixturePackaging.WorkingDirectory, _snapFilesystem);
            await using var nugetPackageSourcesDirectory = _snapFilesystem.WithDisposableTempDirectory(_baseFixturePackaging.WorkingDirectory);
            using var genesisReleaseBuilder =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, genesisSnapApp, _releaseBuilderContext);
            using var update1ReleaseBuilder =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update1SnapApp, _releaseBuilderContext);
            using var update2ReleaseBuilder =
                      _baseFixturePackaging.WithSnapReleaseBuilder(rootDirectory, snapAppsReleases, update2SnapApp, _releaseBuilderContext);
            var nugetPackageSources = genesisSnapApp.BuildNugetSources(nugetPackageSourcesDirectory.WorkingDirectory);

            genesisReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(genesisSnapApp))
            .AddSnapDll();

            update1ReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update1SnapApp))
            .AddSnapDll();

            update2ReleaseBuilder
            .AddNuspecItem(_baseFixturePackaging.BuildSnapExecutable(update2SnapApp))
            .AddSnapDll();

            using (await _baseFixturePackaging.BuildPackageAsync(genesisReleaseBuilder))
                using (await _baseFixturePackaging.BuildPackageAsync(update1ReleaseBuilder))
                {
                    using var update2PackageContext = await _baseFixturePackaging.BuildPackageAsync(update2ReleaseBuilder);

                    await using var releasesNupkgMemoryStream = _snapPack.BuildReleasesPackage(genesisSnapApp, snapAppsReleases);
                    var expectedVersion = SemanticVersion.Parse("1.0.0");

                    var expectedPackageIdentity = new PackageIdentity(
                        update2PackageContext.FullPackageSnapRelease.BuildNugetReleasesUpstreamId(),
                        expectedVersion.ToNuGetVersion());

                    using (var releasesPackageArchiveReader = new PackageArchiveReader(releasesNupkgMemoryStream, true))
                    {
                        Assert.Equal(expectedPackageIdentity, releasesPackageArchiveReader.GetIdentity());
                    }

                    releasesNupkgMemoryStream.Seek(0, SeekOrigin.Begin);

                    _baseFixtureNuget.SetupReleases(_nugetServiceMock, releasesNupkgMemoryStream, nugetPackageSources, genesisSnapApp);

                    var(snapAppsReleasesAfter, packageSourceAfter, releasesMemoryStream) = await _snapPackageManager.GetSnapsReleasesAsync(genesisSnapApp);

                    await using (releasesMemoryStream)
                    {
                        Assert.NotNull(releasesMemoryStream);
                        Assert.Equal(0, releasesMemoryStream.Position);
                        Assert.True(releasesMemoryStream.Length > 0);

                        Assert.NotNull(snapAppsReleasesAfter);
                        Assert.NotNull(packageSourceAfter);
                        Assert.Equal(expectedVersion, snapAppsReleases.Version);
                        Assert.Equal(expectedVersion, snapAppsReleasesAfter.Version);

                        var snapAppReleases = snapAppsReleasesAfter.GetReleases(genesisSnapApp);
                        Assert.Equal(3, snapAppReleases.Count());
                    }
                }
        }
Example #13
0
        public async Task TestInstall_Offline_Using_Local_PackageSource()
        {
            await using var specialFoldersAnyOs = new SnapOsSpecialFoldersUnitTest(_snapFilesystem, _baseFixturePackaging.WorkingDirectory);
            await using var packagesDirectory   = new DisposableDirectory(specialFoldersAnyOs.WorkingDirectory, _snapFilesystem);
            using var cts = new CancellationTokenSource();

            SetupSnapOsMock(specialFoldersAnyOs);

            var snapInstallerIoEnvironment = new SnapInstallerIoEnvironment
            {
                WorkingDirectory        = specialFoldersAnyOs.WorkingDirectory,
                ThisExeWorkingDirectory = specialFoldersAnyOs.WorkingDirectory,
                SpecialFolders          = specialFoldersAnyOs,
            };

            var snapAppsReleases = new SnapAppsReleases();
            var genesisSnapApp   = _baseFixturePackaging.BuildSnapApp(localPackageSourceDirectory: packagesDirectory);

            Assert.True(genesisSnapApp.Channels.Count >= 2);

            using var genesisSnapReleaseBuilder = _baseFixturePackaging.WithSnapReleaseBuilder(packagesDirectory, snapAppsReleases, genesisSnapApp, _snapReleaseBuilderContext);
            var mainAssemblyDefinition = _baseFixturePackaging.BuildSnapExecutable(genesisSnapApp);

            genesisSnapReleaseBuilder
            .AddNuspecItem(mainAssemblyDefinition)
            .AddSnapDll();

            using var genesisPackageContext = await _baseFixturePackaging.BuildPackageAsync(genesisSnapReleaseBuilder, cts.Token);

            var releasesFilename   = _snapFilesystem.PathCombine(snapInstallerIoEnvironment.ThisExeWorkingDirectory, genesisPackageContext.FullPackageSnapApp.BuildNugetReleasesFilename());
            var snapAppDllFilename = _snapFilesystem.PathCombine(snapInstallerIoEnvironment.ThisExeWorkingDirectory, SnapConstants.SnapAppDllFilename);
            var setupNupkgFilename = _snapFilesystem.PathCombine(snapInstallerIoEnvironment.ThisExeWorkingDirectory, SnapConstants.SetupNupkgFilename);

            await using var releasePackageMemoryStream = _snapPack.BuildReleasesPackage(genesisSnapApp, snapAppsReleases);

            await _snapFilesystem.FileWriteAsync(genesisPackageContext.FullPackageMemoryStream, setupNupkgFilename, cts.Token);

            await _snapFilesystem.FileWriteAsync(releasePackageMemoryStream, releasesFilename, cts.Token);

            using var snapAppDllAssemblyDefinition = _snapAppWriter.BuildSnapAppAssembly(genesisSnapApp);
            snapAppDllAssemblyDefinition.Write(snapAppDllFilename);

            var(exitCode, installerType) = await Program.MainImplAsync(new[] { "--headless" }, LogLevel.Info, cts, _snapOsMock.Object, x =>
            {
                x.Register <ISnapInstallerIoEnvironment>(_ => snapInstallerIoEnvironment);
                return((ISnapInstallerEnvironment)x.GetInstance(typeof(ISnapInstallerEnvironment)));
            });

            Assert.Equal(0, exitCode);
            Assert.Equal(SnapInstallerType.Offline, installerType);

            var appInstallDirectory = _snapInstaller.GetApplicationDirectory(
                _snapFilesystem.PathCombine(specialFoldersAnyOs.LocalApplicationData, genesisSnapApp.Id), genesisSnapApp.Version);

            var files = _snapFilesystem.DirectoryGetAllFiles(appInstallDirectory).OrderBy(x => x, new OrdinalIgnoreCaseComparer()).ToList();

            Assert.Equal(3, files.Count);
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                Assert.EndsWith($"{genesisSnapApp.Id}.exe", files[0]);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                Assert.EndsWith(genesisSnapApp.Id, files[0]);
            }
            else
            {
                throw new PlatformNotSupportedException();
            }
            Assert.EndsWith(SnapConstants.SnapAppDllFilename, files[1]);
            Assert.EndsWith(SnapConstants.SnapDllFilename, files[2]);
        }
Example #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));
        }