Beispiel #1
0
        private static async Task VerifyPackageSignatureAsync(
            string source,
            Guid parentId,
            PackageIdentity package,
            PackageExtractionContext packageExtractionContext,
            ISignedPackageReader signedPackageReader,
            CancellationToken token)
        {
            if (packageExtractionContext.SignedPackageVerifier != null)
            {
                var repositorySignatureInfo = GetRepositorySignatureInfo(source);

                var verifierSettings = RepositorySignatureInfoUtility.GetSignedPackageVerifierSettings(
                    repositorySignatureInfo,
                    packageExtractionContext.SignedPackageVerifierSettings);

                var verifyResult = await packageExtractionContext.SignedPackageVerifier.VerifySignaturesAsync(
                    signedPackageReader,
                    verifierSettings,
                    token,
                    parentId);

                if (verifyResult.Signed)
                {
                    await LogPackageSignatureVerificationAsync(source, package, packageExtractionContext.Logger, verifyResult);

                    // Update errors and warnings with package id and source
                    verifyResult.Results
                    .SelectMany(r => r.Issues)
                    .ForEach(e => AddPackageIdentityToSignatureLog(source, package, e));

                    if (verifyResult.Valid)
                    {
                        // log any warnings
                        var warnings = verifyResult.Results.SelectMany(r => r.GetWarningIssues());

                        foreach (var warning in warnings)
                        {
                            await packageExtractionContext.Logger.LogAsync(warning);
                        }
                    }
                    else
                    {
                        throw new SignatureException(verifyResult.Results, package);
                    }
                }
            }
        }
        private static async Task <IEnumerable <string> > CopySatelliteFilesAsync(
            PackageReaderBase packageReader,
            PackagePathResolver packagePathResolver,
            PackageSaveMode packageSaveMode,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token)
        {
            if (packageReader == null)
            {
                throw new ArgumentNullException(nameof(packageReader));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            await VerifyPackageSignatureAsync(packageReader.GetIdentity(), packageExtractionContext, packageReader, token);

            var satelliteFilesCopied = Enumerable.Empty <string>();

            var result = await PackageHelper.GetSatelliteFilesAsync(packageReader, packagePathResolver, token);

            var runtimePackageDirectory = result.Item1;
            var satelliteFiles          = result.Item2
                                          .Where(file => PackageHelper.IsPackageFile(file, packageSaveMode))
                                          .ToList();

            if (satelliteFiles.Count > 0)
            {
                var packageFileExtractor = new PackageFileExtractor(satelliteFiles, packageExtractionContext.XmlDocFileSaveMode);

                // Now, add all the satellite files collected from the package to the runtime package folder(s)
                satelliteFilesCopied = await packageReader.CopyFilesAsync(
                    runtimePackageDirectory,
                    satelliteFiles,
                    packageFileExtractor.ExtractPackageFile,
                    packageExtractionContext.Logger,
                    token);
            }

            return(satelliteFilesCopied);
        }
Beispiel #3
0
        private static IEnumerable <string> CopySatelliteFiles(
            PackageReaderBase packageReader,
            PackagePathResolver packagePathResolver,
            PackageSaveMode packageSaveMode,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token)
        {
            if (packageReader == null)
            {
                throw new ArgumentNullException(nameof(packageReader));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var satelliteFilesCopied = Enumerable.Empty <string>();

            string runtimePackageDirectory;
            var    satelliteFiles = PackageHelper
                                    .GetSatelliteFiles(packageReader, packagePathResolver, out runtimePackageDirectory)
                                    .Where(file => PackageHelper.IsPackageFile(file, packageSaveMode))
                                    .ToList();

            if (satelliteFiles.Count > 0)
            {
                var packageFileExtractor = new PackageFileExtractor(satelliteFiles, packageExtractionContext.XmlDocFileSaveMode);

                // Now, add all the satellite files collected from the package to the runtime package folder(s)
                satelliteFilesCopied = packageReader.CopyFiles(
                    runtimePackageDirectory,
                    satelliteFiles,
                    packageFileExtractor.ExtractPackageFile,
                    packageExtractionContext.Logger,
                    token);
            }

            return(satelliteFilesCopied);
        }
        private static async Task VerifyPackageSignatureAsync(
            PackageIdentity package,
            PackageExtractionContext packageExtractionContext,
            ISignedPackageReader signedPackageReader,
            CancellationToken token)
        {
            if (packageExtractionContext.SignedPackageVerifier != null)
            {
                var verifyResult = await packageExtractionContext.SignedPackageVerifier.VerifySignaturesAsync(
                    signedPackageReader,
                    token);

                if (!verifyResult.Valid)
                {
                    throw new SignatureException(verifyResult.Results, package);
                }
            }
        }
        public static async Task <IEnumerable <string> > CopySatelliteFilesAsync(
            PackageIdentity packageIdentity,
            PackagePathResolver packagePathResolver,
            PackageSaveMode packageSaveMode,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token)
        {
            if (packageIdentity == null)
            {
                throw new ArgumentNullException(nameof(packageIdentity));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            var satelliteFilesCopied = Enumerable.Empty <string>();

            var nupkgFilePath = packagePathResolver.GetInstalledPackageFilePath(packageIdentity);

            if (File.Exists(nupkgFilePath))
            {
                using (var packageReader = new PackageArchiveReader(nupkgFilePath))
                {
                    return(await CopySatelliteFilesAsync(
                               packageReader,
                               packagePathResolver,
                               packageSaveMode,
                               packageExtractionContext,
                               token));
                }
            }

            return(satelliteFilesCopied);
        }
        /// <summary>
        /// Uses a copy function to install a package to a global packages directory.
        /// </summary>
        /// <param name="copyToAsync">
        /// A function which should copy the package to the provided destination stream.
        /// </param>
        /// <param name="packageExtractionContext">
        /// The version folder path context, which encapsulates all of the parameters to observe
        /// while installing the package.
        /// </param>
        /// <param name="token">The cancellation token.</param>
        /// <returns>
        /// True if the package was installed. False if the package already exists and therefore
        /// resulted in no copy operation.
        /// </returns>
        public static async Task <bool> InstallFromSourceAsync(
            string source,
            PackageIdentity packageIdentity,
            Func <Stream, Task> copyToAsync,
            VersionFolderPathResolver versionFolderPathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token,
            Guid parentId = default(Guid))
        {
            if (copyToAsync == null)
            {
                throw new ArgumentNullException(nameof(copyToAsync));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var logger       = packageExtractionContext.Logger;
            var extractionId = Guid.NewGuid();

            using (var telemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationId(parentId))
            {
                var targetPath   = versionFolderPathResolver.GetInstallPath(packageIdentity.Id, packageIdentity.Version);
                var targetNuspec = versionFolderPathResolver.GetManifestFilePath(packageIdentity.Id, packageIdentity.Version);
                var targetNupkg  = versionFolderPathResolver.GetPackageFilePath(packageIdentity.Id, packageIdentity.Version);
                var hashPath     = versionFolderPathResolver.GetHashPath(packageIdentity.Id, packageIdentity.Version);

                logger.LogVerbose(
                    $"Acquiring lock for the installation of {packageIdentity.Id} {packageIdentity.Version}");

                // Acquire the lock on a nukpg before we extract it to prevent the race condition when multiple
                // processes are extracting to the same destination simultaneously
                return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync(targetNupkg,
                                                                             action : async cancellationToken =>
                {
                    // If this is the first process trying to install the target nupkg, go ahead
                    // After this process successfully installs the package, all other processes
                    // waiting on this lock don't need to install it again.
                    if (!File.Exists(hashPath))
                    {
                        logger.LogVerbose(
                            $"Acquired lock for the installation of {packageIdentity.Id} {packageIdentity.Version}");

                        logger.LogMinimal(string.Format(
                                              CultureInfo.CurrentCulture,
                                              Strings.Log_InstallingPackage,
                                              packageIdentity.Id,
                                              packageIdentity.Version));

                        cancellationToken.ThrowIfCancellationRequested();

                        // We do not stop the package extraction after this point
                        // based on CancellationToken, but things can still be stopped if the process is killed.
                        if (Directory.Exists(targetPath))
                        {
                            // If we had a broken restore, clean out the files first
                            var info = new DirectoryInfo(targetPath);

                            foreach (var file in info.GetFiles())
                            {
                                file.Delete();
                            }

                            foreach (var dir in info.GetDirectories())
                            {
                                dir.Delete(true);
                            }
                        }
                        else
                        {
                            Directory.CreateDirectory(targetPath);
                        }

                        var targetTempNupkg = Path.Combine(targetPath, Path.GetRandomFileName());
                        var tempHashPath = Path.Combine(targetPath, Path.GetRandomFileName());
                        var packageSaveMode = packageExtractionContext.PackageSaveMode;

                        try
                        {
                            // Extract the nupkg
                            using (var nupkgStream = new FileStream(
                                       targetTempNupkg,
                                       FileMode.Create,
                                       FileAccess.ReadWrite,
                                       FileShare.ReadWrite | FileShare.Delete,
                                       bufferSize: 4096,
                                       useAsync: true))
                            {
                                await copyToAsync(nupkgStream);
                                nupkgStream.Seek(0, SeekOrigin.Begin);

                                using (var packageReader = new PackageArchiveReader(nupkgStream))
                                {
                                    if (packageSaveMode.HasFlag(PackageSaveMode.Nuspec) || packageSaveMode.HasFlag(PackageSaveMode.Files))
                                    {
                                        telemetry.StartIntervalMeasure();

                                        await VerifyPackageSignatureAsync(
                                            source,
                                            telemetry.OperationId,
                                            packageIdentity,
                                            packageExtractionContext,
                                            packageReader,
                                            token);

                                        telemetry.EndIntervalMeasure(PackagingConstants.PackageVerifyDurationName);
                                    }

                                    var nuspecFile = packageReader.GetNuspecFile();
                                    if ((packageSaveMode & PackageSaveMode.Nuspec) == PackageSaveMode.Nuspec)
                                    {
                                        packageReader.ExtractFile(nuspecFile, targetNuspec, logger);
                                    }

                                    if ((packageSaveMode & PackageSaveMode.Files) == PackageSaveMode.Files)
                                    {
                                        var nupkgFileName = Path.GetFileName(targetNupkg);
                                        var nuspecFileName = Path.GetFileName(targetNuspec);
                                        var hashFileName = Path.GetFileName(hashPath);
                                        var packageFiles = packageReader.GetFiles()
                                                           .Where(file => ShouldInclude(file, hashFileName));
                                        var packageFileExtractor = new PackageFileExtractor(
                                            packageFiles,
                                            packageExtractionContext.XmlDocFileSaveMode);
                                        packageReader.CopyFiles(
                                            targetPath,
                                            packageFiles,
                                            packageFileExtractor.ExtractPackageFile,
                                            logger,
                                            token);
                                    }

                                    string packageHash;
                                    nupkgStream.Position = 0;
                                    packageHash = Convert.ToBase64String(new CryptoHashProvider("SHA512").CalculateHash(nupkgStream));

                                    File.WriteAllText(tempHashPath, packageHash);
                                }
                            }
                        }
                        catch (SignatureException)
                        {
                            try
                            {
                                DeleteTargetAndTempPaths(targetPath, targetTempNupkg);
                            }
                            catch (IOException ex)
                            {
                                logger.LogWarning(string.Format(
                                                      CultureInfo.CurrentCulture,
                                                      Strings.ErrorUnableToDeleteFile,
                                                      targetTempNupkg,
                                                      ex.Message));
                            }

                            telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                                packageExtractionContext.PackageSaveMode,
                                NuGetOperationStatus.Failed,
                                ExtractionSource.DownloadResource,
                                packageIdentity);
                            throw;
                        }

                        // Now rename the tmp file
                        if ((packageExtractionContext.PackageSaveMode & PackageSaveMode.Nupkg) ==
                            PackageSaveMode.Nupkg)
                        {
                            File.Move(targetTempNupkg, targetNupkg);
                        }
                        else
                        {
                            try
                            {
                                File.Delete(targetTempNupkg);
                            }
                            catch (IOException ex)
                            {
                                logger.LogWarning(string.Format(
                                                      CultureInfo.CurrentCulture,
                                                      Strings.ErrorUnableToDeleteFile,
                                                      targetTempNupkg,
                                                      ex.Message));
                            }
                        }

                        // Note: PackageRepository relies on the hash file being written out as the
                        // final operation as part of a package install to assume a package was fully installed.
                        // Rename the tmp hash file
                        File.Move(tempHashPath, hashPath);

                        logger.LogVerbose($"Completed installation of {packageIdentity.Id} {packageIdentity.Version}");

                        telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                            packageExtractionContext.PackageSaveMode,
                            NuGetOperationStatus.Succeeded,
                            ExtractionSource.DownloadResource,
                            packageIdentity);
                        return true;
                    }
                    else
                    {
                        logger.LogVerbose("Lock not required - Package already installed "
                                          + $"{packageIdentity.Id} {packageIdentity.Version}");

                        telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                            packageExtractionContext.PackageSaveMode,
                            NuGetOperationStatus.NoOp,
                            ExtractionSource.DownloadResource,
                            packageIdentity);
                        return false;
                    }
                },
                                                                             token : token));
            }
        }
        public static async Task <IEnumerable <string> > ExtractPackageAsync(
            string source,
            PackageReaderBase packageReader,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token,
            Guid parentId = default(Guid))
        {
            if (packageReader == null)
            {
                throw new ArgumentNullException(nameof(packageReader));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            token.ThrowIfCancellationRequested();

            var packageSaveMode = packageExtractionContext.PackageSaveMode;
            var extractionId    = Guid.NewGuid();
            var filesAdded      = new List <string>();

            using (var telemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationId(parentId))
            {
                var packageIdentityFromNuspec = await packageReader.GetIdentityAsync(token);

                try
                {
                    telemetry.StartIntervalMeasure();

                    await VerifyPackageSignatureAsync(
                        source,
                        telemetry.OperationId,
                        packageIdentityFromNuspec,
                        packageExtractionContext,
                        packageReader,
                        token);

                    telemetry.EndIntervalMeasure(PackagingConstants.PackageVerifyDurationName);
                }
                catch (SignatureException)
                {
                    telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                        packageExtractionContext.PackageSaveMode,
                        NuGetOperationStatus.Failed,
                        ExtractionSource.NuGetFolderProject,
                        packageIdentityFromNuspec);
                    throw;
                }

                var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentityFromNuspec));
                var packageDirectory     = packageDirectoryInfo.FullName;

                var packageFiles = await packageReader.GetPackageFilesAsync(packageSaveMode, token);

                var packageFileExtractor = new PackageFileExtractor(packageFiles, packageExtractionContext.XmlDocFileSaveMode);

                filesAdded.AddRange(await packageReader.CopyFilesAsync(
                                        packageDirectory,
                                        packageFiles,
                                        packageFileExtractor.ExtractPackageFile,
                                        packageExtractionContext.Logger,
                                        token));

                if (packageSaveMode.HasFlag(PackageSaveMode.Nupkg))
                {
                    var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentityFromNuspec));
                    var filePath      = await packageReader.CopyNupkgAsync(nupkgFilePath, token);

                    if (!string.IsNullOrEmpty(filePath))
                    {
                        filesAdded.Add(filePath);
                    }
                }

                // Now, copy satellite files unless requested to not copy them
                if (packageExtractionContext.CopySatelliteFiles)
                {
                    filesAdded.AddRange(await CopySatelliteFilesAsync(
                                            packageReader,
                                            packagePathResolver,
                                            packageSaveMode,
                                            packageExtractionContext,
                                            token));
                }

                telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                    packageExtractionContext.PackageSaveMode,
                    NuGetOperationStatus.Succeeded,
                    ExtractionSource.NuGetFolderProject,
                    packageIdentityFromNuspec);
                return(filesAdded);
            }
        }
        public static async Task <IEnumerable <string> > ExtractPackageAsync(
            string source,
            Stream packageStream,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token,
            Guid parentId = default(Guid))
        {
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (!packageStream.CanSeek)
            {
                throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var packageSaveMode    = packageExtractionContext.PackageSaveMode;
            var filesAdded         = new List <string>();
            var nupkgStartPosition = packageStream.Position;

            using (var telemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationId(parentId))
            {
                using (var packageReader = new PackageArchiveReader(packageStream, leaveStreamOpen: true))
                {
                    var packageIdentityFromNuspec = await packageReader.GetIdentityAsync(CancellationToken.None);

                    var installPath          = packagePathResolver.GetInstallPath(packageIdentityFromNuspec);
                    var packageDirectoryInfo = Directory.CreateDirectory(installPath);
                    var packageDirectory     = packageDirectoryInfo.FullName;

                    try
                    {
                        telemetry.StartIntervalMeasure();

                        await VerifyPackageSignatureAsync(
                            source,
                            telemetry.OperationId,
                            packageIdentityFromNuspec,
                            packageExtractionContext,
                            packageReader,
                            token);

                        telemetry.EndIntervalMeasure(PackagingConstants.PackageVerifyDurationName);
                    }
                    catch (SignatureException)
                    {
                        telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                            packageExtractionContext.PackageSaveMode,
                            NuGetOperationStatus.Failed,
                            ExtractionSource.NuGetFolderProject,
                            packageIdentityFromNuspec);
                        throw;
                    }

                    var packageFiles = await packageReader.GetPackageFilesAsync(packageSaveMode, token);

                    if ((packageSaveMode & PackageSaveMode.Nuspec) == PackageSaveMode.Nuspec)
                    {
                        var sourceNuspecFile = packageFiles.Single(p => PackageHelper.IsManifest(p));

                        var targetNuspecPath = Path.Combine(
                            packageDirectory,
                            packagePathResolver.GetManifestFileName(packageIdentityFromNuspec));

                        // Extract the .nuspec file with a well known file name.
                        filesAdded.Add(packageReader.ExtractFile(
                                           sourceNuspecFile,
                                           targetNuspecPath,
                                           packageExtractionContext.Logger));

                        packageFiles = packageFiles.Except(new[] { sourceNuspecFile });
                    }

                    var packageFileExtractor = new PackageFileExtractor(packageFiles, packageExtractionContext.XmlDocFileSaveMode);

                    filesAdded.AddRange(await packageReader.CopyFilesAsync(
                                            packageDirectory,
                                            packageFiles,
                                            packageFileExtractor.ExtractPackageFile,
                                            packageExtractionContext.Logger,
                                            token));

                    if ((packageSaveMode & PackageSaveMode.Nupkg) == PackageSaveMode.Nupkg)
                    {
                        // During package extraction, nupkg is the last file to be created
                        // Since all the packages are already created, the package stream is likely positioned at its end
                        // Reset it to the nupkgStartPosition
                        packageStream.Seek(nupkgStartPosition, SeekOrigin.Begin);

                        var nupkgFilePath = Path.Combine(
                            packageDirectory,
                            packagePathResolver.GetPackageFileName(packageIdentityFromNuspec));

                        filesAdded.Add(packageStream.CopyToFile(nupkgFilePath));
                    }

                    // Now, copy satellite files unless requested to not copy them
                    if (packageExtractionContext.CopySatelliteFiles)
                    {
                        filesAdded.AddRange(await CopySatelliteFilesAsync(
                                                packageReader,
                                                packagePathResolver,
                                                packageSaveMode,
                                                packageExtractionContext,
                                                token));
                    }
                    telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                        packageExtractionContext.PackageSaveMode,
                        NuGetOperationStatus.Succeeded,
                        ExtractionSource.NuGetFolderProject,
                        packageIdentityFromNuspec);
                }

                return(filesAdded);
            }
        }
        public static async Task <IEnumerable <string> > ExtractPackageAsync(
            string source,
            PackageReaderBase packageReader,
            Stream packageStream,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token,
            Guid parentId = default(Guid))
        {
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var packageSaveMode    = packageExtractionContext.PackageSaveMode;
            var extractionId       = Guid.NewGuid();
            var nupkgStartPosition = packageStream.Position;
            var filesAdded         = new List <string>();


            using (var telemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationId(parentId))
            {
                var packageIdentityFromNuspec = await packageReader.GetIdentityAsync(token);

                try
                {
                    telemetry.StartIntervalMeasure();

                    await VerifyPackageSignatureAsync(
                        source,
                        telemetry.OperationId,
                        packageIdentityFromNuspec,
                        packageExtractionContext,
                        packageReader,
                        token);

                    telemetry.EndIntervalMeasure(PackagingConstants.PackageVerifyDurationName);
                }
                catch (SignatureException)
                {
                    telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                        packageExtractionContext.PackageSaveMode,
                        NuGetOperationStatus.Failed,
                        ExtractionSource.NuGetFolderProject,
                        packageIdentityFromNuspec);
                    throw;
                }

                var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentityFromNuspec));
                var packageDirectory     = packageDirectoryInfo.FullName;

                var packageFiles = await packageReader.GetPackageFilesAsync(packageSaveMode, token);

                var packageFileExtractor = new PackageFileExtractor(packageFiles, packageExtractionContext.XmlDocFileSaveMode);
                filesAdded.AddRange(await packageReader.CopyFilesAsync(
                                        packageDirectory,
                                        packageFiles,
                                        packageFileExtractor.ExtractPackageFile,
                                        packageExtractionContext.Logger,
                                        token));

                var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentityFromNuspec));
                if (packageSaveMode.HasFlag(PackageSaveMode.Nupkg))
                {
                    // During package extraction, nupkg is the last file to be created
                    // Since all the packages are already created, the package stream is likely positioned at its end
                    // Reset it to the nupkgStartPosition
                    if (packageStream.Position != 0)
                    {
                        if (!packageStream.CanSeek)
                        {
                            throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
                        }

                        packageStream.Position = 0;
                    }

                    filesAdded.Add(packageStream.CopyToFile(nupkgFilePath));
                }

                // Now, copy satellite files unless requested to not copy them
                if (packageExtractionContext.CopySatelliteFiles)
                {
                    filesAdded.AddRange(await CopySatelliteFilesAsync(
                                            packageReader,
                                            packagePathResolver,
                                            packageSaveMode,
                                            packageExtractionContext,
                                            token));
                }

                telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                    packageExtractionContext.PackageSaveMode,
                    NuGetOperationStatus.Succeeded,
                    ExtractionSource.NuGetFolderProject,
                    packageIdentityFromNuspec);

                return(filesAdded);
            }
        }
Beispiel #10
0
        public static IEnumerable <string> ExtractPackage(
            Stream packageStream,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token)
        {
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (!packageStream.CanSeek)
            {
                throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var packageSaveMode = packageExtractionContext.PackageSaveMode;

            var filesAdded = new List <string>();

            var nupkgStartPosition = packageStream.Position;

            using (var packageReader = new PackageArchiveReader(packageStream, leaveStreamOpen: true))
            {
                var packageIdentityFromNuspec = packageReader.GetIdentity();

                var installPath          = packagePathResolver.GetInstallPath(packageIdentityFromNuspec);
                var packageDirectoryInfo = Directory.CreateDirectory(installPath);
                var packageDirectory     = packageDirectoryInfo.FullName;

                var packageFiles = packageReader.GetPackageFiles(packageSaveMode);

                if ((packageSaveMode & PackageSaveMode.Nuspec) == PackageSaveMode.Nuspec)
                {
                    var sourceNuspecFile = packageFiles.Single(p => PackageHelper.IsManifest(p));

                    var targetNuspecPath = Path.Combine(
                        packageDirectory,
                        packagePathResolver.GetManifestFileName(packageIdentityFromNuspec));

                    // Extract the .nuspec file with a well known file name.
                    filesAdded.Add(packageReader.ExtractFile(
                                       sourceNuspecFile,
                                       targetNuspecPath,
                                       packageExtractionContext.Logger));

                    packageFiles = packageFiles.Except(new[] { sourceNuspecFile });
                }

                var packageFileExtractor = new PackageFileExtractor(packageFiles, packageExtractionContext.XmlDocFileSaveMode);

                filesAdded.AddRange(packageReader.CopyFiles(
                                        packageDirectory,
                                        packageFiles,
                                        packageFileExtractor.ExtractPackageFile,
                                        packageExtractionContext.Logger,
                                        token));

                if ((packageSaveMode & PackageSaveMode.Nupkg) == PackageSaveMode.Nupkg)
                {
                    // During package extraction, nupkg is the last file to be created
                    // Since all the packages are already created, the package stream is likely positioned at its end
                    // Reset it to the nupkgStartPosition
                    packageStream.Seek(nupkgStartPosition, SeekOrigin.Begin);

                    var nupkgFilePath = Path.Combine(
                        packageDirectory,
                        packagePathResolver.GetPackageFileName(packageIdentityFromNuspec));

                    filesAdded.Add(packageStream.CopyToFile(nupkgFilePath));
                }

                // Now, copy satellite files unless requested to not copy them
                if (packageExtractionContext.CopySatelliteFiles)
                {
                    filesAdded.AddRange(CopySatelliteFiles(
                                            packageReader,
                                            packagePathResolver,
                                            packageSaveMode,
                                            packageExtractionContext,
                                            token));
                }
            }

            return(filesAdded);
        }
Beispiel #11
0
        public static async Task<IEnumerable<string>> ExtractPackageAsync(
            Stream packageStream,
            PackageIdentity packageIdentity,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            PackageSaveModes packageSaveMode,
            CancellationToken token)
        {
            var filesAdded = new List<string>();
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (!packageStream.CanSeek)
            {
                throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
            }

            if (packageIdentity == null)
            {
                throw new ArgumentNullException(nameof(packageIdentity));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            // TODO: Need to handle PackageSaveMode
            // TODO: Support overwriting files also?
            var zipArchive = new ZipArchive(packageStream);

            var packageReader = new PackageReader(zipArchive);
            var nuspecReader = new NuspecReader(packageReader.GetNuspec());
            packageIdentity = nuspecReader.GetIdentity();

            var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentity));
            var packageDirectory = packageDirectoryInfo.FullName;

            filesAdded.AddRange(await PackageHelper.CreatePackageFiles(zipArchive.Entries, packageDirectory, packageSaveMode, token));

            var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentity));
            if (packageSaveMode.HasFlag(PackageSaveModes.Nupkg))
            {
                // During package extraction, nupkg is the last file to be created
                // Since all the packages are already created, the package stream is likely positioned at its end
                // Reset it
                packageStream.Seek(0, SeekOrigin.Begin);
                filesAdded.Add(await PackageHelper.CreatePackageFile(nupkgFilePath, packageStream, token));
            }

            // Now, copy satellite files unless requested to not copy them
            if (packageExtractionContext == null
                || packageExtractionContext.CopySatelliteFiles)
            {
                filesAdded.AddRange(await CopySatelliteFilesAsync(packageIdentity, packagePathResolver, packageSaveMode, token));
            }

            return filesAdded;
        }
Beispiel #12
0
        public static async Task <IEnumerable <string> > ExtractPackageAsync(
            PackageReaderBase packageReader,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token)
        {
            if (packageReader == null)
            {
                throw new ArgumentNullException(nameof(packageReader));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            token.ThrowIfCancellationRequested();

            var packageSaveMode = packageExtractionContext.PackageSaveMode;

            var filesAdded = new List <string>();

            var packageIdentityFromNuspec = await packageReader.GetIdentityAsync(token);

            var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentityFromNuspec));
            var packageDirectory     = packageDirectoryInfo.FullName;

            var packageFiles = await packageReader.GetPackageFilesAsync(packageSaveMode, token);

            var packageFileExtractor = new PackageFileExtractor(packageFiles, packageExtractionContext.XmlDocFileSaveMode);

            filesAdded.AddRange(await packageReader.CopyFilesAsync(
                                    packageDirectory,
                                    packageFiles,
                                    packageFileExtractor.ExtractPackageFile,
                                    packageExtractionContext.Logger,
                                    token));

            if (packageSaveMode.HasFlag(PackageSaveMode.Nupkg))
            {
                var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentityFromNuspec));
                var filePath      = await packageReader.CopyNupkgAsync(nupkgFilePath, token);

                if (!string.IsNullOrEmpty(filePath))
                {
                    filesAdded.Add(filePath);
                }
            }

            // Now, copy satellite files unless requested to not copy them
            if (packageExtractionContext.CopySatelliteFiles)
            {
                filesAdded.AddRange(await CopySatelliteFilesAsync(
                                        packageReader,
                                        packagePathResolver,
                                        packageSaveMode,
                                        packageExtractionContext,
                                        token));
            }

            return(filesAdded);
        }
Beispiel #13
0
        public static async Task <IEnumerable <string> > ExtractPackageAsync(Stream packageStream, PackageIdentity packageIdentity,
                                                                             PackagePathResolver packagePathResolver,
                                                                             PackageExtractionContext packageExtractionContext,
                                                                             PackageSaveModes packageSaveMode,
                                                                             CancellationToken token)
        {
            List <string> filesAdded = new List <string>();

            if (packageStream == null)
            {
                throw new ArgumentNullException("packageStream");
            }

            if (!packageStream.CanSeek)
            {
                throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
            }

            if (packageIdentity == null)
            {
                throw new ArgumentNullException("packageIdentity");
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException("packagePathResolver");
            }

            // TODO: Need to handle PackageSaveMode
            // TODO: Support overwriting files also?
            long nupkgStartPosition = packageStream.Position;
            var  zipArchive         = new ZipArchive(packageStream);

            // default to non-legacy paths
            bool useLegacyPaths = packageExtractionContext == null ? false : packageExtractionContext.UseLegacyPackageInstallPath;

            var          packageReader            = new PackageReader(zipArchive);
            var          nuspecReader             = new NuspecReader(packageReader.GetNuspec());
            NuGetVersion packageVersionFromNuspec = nuspecReader.GetVersion();

            var    packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(new PackageIdentity(packageIdentity.Id, packageVersionFromNuspec), useLegacyPaths));
            string packageDirectory     = packageDirectoryInfo.FullName;

            filesAdded.AddRange(await PackageHelper.CreatePackageFiles(zipArchive.Entries, packageDirectory, packageSaveMode, token));

            string nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentity));

            if (packageSaveMode.HasFlag(PackageSaveModes.Nupkg))
            {
                // During package extraction, nupkg is the last file to be created
                // Since all the packages are already created, the package stream is likely positioned at its end
                // Reset it to the nupkgStartPosition
                packageStream.Seek(nupkgStartPosition, SeekOrigin.Begin);
                filesAdded.Add(await PackageHelper.CreatePackageFile(nupkgFilePath, packageStream, token));
            }

            // Now, copy satellite files unless requested to not copy them
            if (packageExtractionContext == null || packageExtractionContext.CopySatelliteFiles)
            {
                filesAdded.AddRange(await CopySatelliteFilesAsync(packageIdentity, packagePathResolver, packageSaveMode, token));
            }

            return(filesAdded);
        }
Beispiel #14
0
        public static async Task<IEnumerable<string>> ExtractPackageAsync(
            PackageReaderBase packageReader,
            Stream packageStream,
            PackageIdentity packageIdentity,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            PackageSaveModes packageSaveMode,
            CancellationToken token)
        {
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (packageIdentity == null)
            {
                throw new ArgumentNullException(nameof(packageIdentity));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            // TODO: Need to handle PackageSaveMode
            // TODO: Support overwriting files also?
            var filesAdded = new List<string>();

            var nuspecReader = new NuspecReader(packageReader.GetNuspec());
            packageIdentity = nuspecReader.GetIdentity();

            var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentity));
            var packageDirectory = packageDirectoryInfo.FullName;

            foreach (var file in packageReader.GetFiles().Where(file => PackageHelper.IsPackageFile(file, packageSaveMode)))
            {
                token.ThrowIfCancellationRequested();

                var targetPath = Path.Combine(packageDirectory, file);
                Directory.CreateDirectory(Path.GetDirectoryName(targetPath));

                using (var sourceStream = packageReader.GetStream(file))
                {
                    using (var targetStream = new FileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 1024, useAsync: true))
                    {
                        await sourceStream.CopyToAsync(targetStream);
                    }
                }

                filesAdded.Add(file);
            }

            var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentity));
            if (packageSaveMode.HasFlag(PackageSaveModes.Nupkg))
            {
                // During package extraction, nupkg is the last file to be created
                // Since all the packages are already created, the package stream is likely positioned at its end
                // Reset it
                if (packageStream.Position != 0)
                {
                    if (!packageStream.CanSeek)
                    {
                        throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
                    }

                    packageStream.Position = 0;

                }

                filesAdded.Add(await PackageHelper.CreatePackageFile(nupkgFilePath, packageStream, token));
            }

            // Now, copy satellite files unless requested to not copy them
            if (packageExtractionContext == null || packageExtractionContext.CopySatelliteFiles)
            {
                PackageIdentity runtimeIdentity;
                string packageLanguage;
                var isSatellitePackage = PackageHelper.IsSatellitePackage(nuspecReader, out runtimeIdentity, out packageLanguage);

                // Short-circuit this if the package is not a satellite package.
                if (isSatellitePackage)
                {
                    filesAdded.AddRange(await CopySatelliteFilesAsync(packageIdentity, packagePathResolver, packageSaveMode, token));
                }
            }

            return filesAdded;
        }
        public static async Task <bool> InstallFromSourceAsync(
            PackageIdentity packageIdentity,
            IPackageDownloader packageDownloader,
            VersionFolderPathResolver versionFolderPathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token,
            Guid parentId = default(Guid))
        {
            if (packageDownloader == null)
            {
                throw new ArgumentNullException(nameof(packageDownloader));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var logger = packageExtractionContext.Logger;

            using (var telemetry = TelemetryActivity.CreateTelemetryActivityWithNewOperationId(parentId))
            {
                var targetPath   = versionFolderPathResolver.GetInstallPath(packageIdentity.Id, packageIdentity.Version);
                var targetNuspec = versionFolderPathResolver.GetManifestFilePath(packageIdentity.Id, packageIdentity.Version);
                var targetNupkg  = versionFolderPathResolver.GetPackageFilePath(packageIdentity.Id, packageIdentity.Version);
                var hashPath     = versionFolderPathResolver.GetHashPath(packageIdentity.Id, packageIdentity.Version);

                logger.LogVerbose(
                    $"Acquiring lock for the installation of {packageIdentity.Id} {packageIdentity.Version}");

                // Acquire the lock on a nukpg before we extract it to prevent the race condition when multiple
                // processes are extracting to the same destination simultaneously
                return(await ConcurrencyUtilities.ExecuteWithFileLockedAsync(targetNupkg,
                                                                             action : async cancellationToken =>
                {
                    // If this is the first process trying to install the target nupkg, go ahead
                    // After this process successfully installs the package, all other processes
                    // waiting on this lock don't need to install it again.
                    if (!File.Exists(hashPath))
                    {
                        logger.LogVerbose(
                            $"Acquired lock for the installation of {packageIdentity.Id} {packageIdentity.Version}");

                        logger.LogMinimal(string.Format(
                                              CultureInfo.CurrentCulture,
                                              Strings.Log_InstallingPackage,
                                              packageIdentity.Id,
                                              packageIdentity.Version));

                        cancellationToken.ThrowIfCancellationRequested();

                        // We do not stop the package extraction after this point
                        // based on CancellationToken, but things can still be stopped if the process is killed.
                        if (Directory.Exists(targetPath))
                        {
                            // If we had a broken restore, clean out the files first
                            var info = new DirectoryInfo(targetPath);

                            foreach (var file in info.GetFiles())
                            {
                                file.Delete();
                            }

                            foreach (var dir in info.GetDirectories())
                            {
                                dir.Delete(true);
                            }
                        }
                        else
                        {
                            Directory.CreateDirectory(targetPath);
                        }

                        var targetTempNupkg = Path.Combine(targetPath, Path.GetRandomFileName());
                        var tempHashPath = Path.Combine(targetPath, Path.GetRandomFileName());
                        var packageSaveMode = packageExtractionContext.PackageSaveMode;

                        // Extract the nupkg
                        var copiedNupkg = await packageDownloader.CopyNupkgFileToAsync(targetTempNupkg, cancellationToken);

                        if (packageSaveMode.HasFlag(PackageSaveMode.Nuspec) || packageSaveMode.HasFlag(PackageSaveMode.Files))
                        {
                            try
                            {
                                telemetry.StartIntervalMeasure();

                                await VerifyPackageSignatureAsync(
                                    packageDownloader.Source,
                                    telemetry.OperationId,
                                    packageIdentity,
                                    packageExtractionContext,
                                    packageDownloader.SignedPackageReader,
                                    token);

                                telemetry.EndIntervalMeasure(PackagingConstants.PackageVerifyDurationName);
                            }
                            catch (SignatureException)
                            {
                                try
                                {
                                    // Dispose of it now because it is holding a lock on the temporary .nupkg file.
                                    packageDownloader.Dispose();

                                    DeleteTargetAndTempPaths(targetPath, targetTempNupkg);
                                }
                                catch (IOException ex)
                                {
                                    logger.LogWarning(string.Format(
                                                          CultureInfo.CurrentCulture,
                                                          Strings.ErrorUnableToDeleteFile,
                                                          targetTempNupkg,
                                                          ex.Message));
                                }

                                telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                                    packageExtractionContext.PackageSaveMode,
                                    NuGetOperationStatus.Failed,
                                    ExtractionSource.RestoreCommand,
                                    packageIdentity);
                                throw;
                            }
                        }

                        if (packageSaveMode.HasFlag(PackageSaveMode.Nuspec))
                        {
                            var nuspecFileNameFromReader = await packageDownloader.CoreReader.GetNuspecFileAsync(cancellationToken);
                            var packageFiles = new[] { nuspecFileNameFromReader };
                            var packageFileExtractor = new PackageFileExtractor(
                                packageFiles,
                                XmlDocFileSaveMode.None);
                            var packageDirectoryPath = Path.GetDirectoryName(targetNuspec);

                            var extractedNuspecFilePath = (await packageDownloader.CoreReader.CopyFilesAsync(
                                                               packageDirectoryPath,
                                                               packageFiles,
                                                               packageFileExtractor.ExtractPackageFile,
                                                               logger,
                                                               cancellationToken))
                                                          .SingleOrDefault();

                            // CopyFilesAsync(...) just extracts files to a directory.
                            // We may have to fix up the casing of the .nuspec file name.
                            if (!string.IsNullOrEmpty(extractedNuspecFilePath))
                            {
                                if (PathUtility.IsFileSystemCaseInsensitive)
                                {
                                    var nuspecFileName = Path.GetFileName(targetNuspec);
                                    var actualNuspecFileName = Path.GetFileName(extractedNuspecFilePath);

                                    if (!string.Equals(nuspecFileName, actualNuspecFileName, StringComparison.Ordinal))
                                    {
                                        var tempNuspecFilePath = Path.Combine(packageDirectoryPath, Path.GetRandomFileName());

                                        File.Move(extractedNuspecFilePath, tempNuspecFilePath);
                                        File.Move(tempNuspecFilePath, targetNuspec);
                                    }
                                }
                                else if (!File.Exists(targetNuspec))
                                {
                                    File.Move(extractedNuspecFilePath, targetNuspec);
                                }
                            }
                        }

                        if (packageSaveMode.HasFlag(PackageSaveMode.Files))
                        {
                            var hashFileName = Path.GetFileName(hashPath);
                            var packageFiles = (await packageDownloader.CoreReader.GetFilesAsync(cancellationToken))
                                               .Where(file => ShouldInclude(file, hashFileName));
                            var packageFileExtractor = new PackageFileExtractor(
                                packageFiles,
                                packageExtractionContext.XmlDocFileSaveMode);
                            await packageDownloader.CoreReader.CopyFilesAsync(
                                targetPath,
                                packageFiles,
                                packageFileExtractor.ExtractPackageFile,
                                logger,
                                token);
                        }

                        var packageHash = await packageDownloader.GetPackageHashAsync("SHA512", cancellationToken);

                        File.WriteAllText(tempHashPath, packageHash);

                        // Now rename the tmp file
                        if (packageExtractionContext.PackageSaveMode.HasFlag(PackageSaveMode.Nupkg))
                        {
                            if (copiedNupkg)
                            {
                                // Dispose of it now because it is holding a lock on the temporary .nupkg file.
                                packageDownloader.Dispose();

                                File.Move(targetTempNupkg, targetNupkg);
                            }
                        }
                        else
                        {
                            try
                            {
                                File.Delete(targetTempNupkg);
                            }
                            catch (IOException ex)
                            {
                                logger.LogWarning(string.Format(
                                                      CultureInfo.CurrentCulture,
                                                      Strings.ErrorUnableToDeleteFile,
                                                      targetTempNupkg,
                                                      ex.Message));
                            }
                        }

                        // Note: PackageRepository relies on the hash file being written out as the
                        // final operation as part of a package install to assume a package was fully installed.
                        // Rename the tmp hash file
                        File.Move(tempHashPath, hashPath);

                        logger.LogVerbose($"Completed installation of {packageIdentity.Id} {packageIdentity.Version}");

                        telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                            packageExtractionContext.PackageSaveMode,
                            NuGetOperationStatus.Succeeded,
                            ExtractionSource.RestoreCommand,
                            packageIdentity);
                        return true;
                    }
                    else
                    {
                        logger.LogVerbose("Lock not required - Package already installed "
                                          + $"{packageIdentity.Id} {packageIdentity.Version}");

                        telemetry.TelemetryEvent = new PackageExtractionTelemetryEvent(
                            packageExtractionContext.PackageSaveMode,
                            NuGetOperationStatus.NoOp,
                            ExtractionSource.RestoreCommand,
                            packageIdentity);
                        return false;
                    }
                },
                                                                             token : token));
            }
        }
Beispiel #16
0
        public static IEnumerable <string> ExtractPackage(
            PackageReaderBase packageReader,
            Stream packageStream,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            CancellationToken token)
        {
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            if (packageExtractionContext == null)
            {
                throw new ArgumentNullException(nameof(packageExtractionContext));
            }

            var packageSaveMode = packageExtractionContext.PackageSaveMode;

            var nupkgStartPosition = packageStream.Position;
            var filesAdded         = new List <string>();

            var packageIdentityFromNuspec = packageReader.GetIdentity();

            var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentityFromNuspec));
            var packageDirectory     = packageDirectoryInfo.FullName;

            var packageFiles         = packageReader.GetPackageFiles(packageSaveMode);
            var packageFileExtractor = new PackageFileExtractor(packageFiles, packageExtractionContext.XmlDocFileSaveMode);

            filesAdded.AddRange(packageReader.CopyFiles(
                                    packageDirectory,
                                    packageFiles,
                                    packageFileExtractor.ExtractPackageFile,
                                    packageExtractionContext.Logger,
                                    token));

            var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentityFromNuspec));

            if (packageSaveMode.HasFlag(PackageSaveMode.Nupkg))
            {
                // During package extraction, nupkg is the last file to be created
                // Since all the packages are already created, the package stream is likely positioned at its end
                // Reset it to the nupkgStartPosition
                if (packageStream.Position != 0)
                {
                    if (!packageStream.CanSeek)
                    {
                        throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
                    }

                    packageStream.Position = 0;
                }

                filesAdded.Add(packageStream.CopyToFile(nupkgFilePath));
            }

            // Now, copy satellite files unless requested to not copy them
            if (packageExtractionContext.CopySatelliteFiles)
            {
                filesAdded.AddRange(CopySatelliteFiles(
                                        packageReader,
                                        packagePathResolver,
                                        packageSaveMode,
                                        packageExtractionContext,
                                        token));
            }

            return(filesAdded);
        }
Beispiel #17
0
        public static async Task <IEnumerable <string> > ExtractPackageAsync(
            PackageReaderBase packageReader,
            Stream packageStream,
            PackageIdentity packageIdentity,
            PackagePathResolver packagePathResolver,
            PackageExtractionContext packageExtractionContext,
            PackageSaveModes packageSaveMode,
            CancellationToken token)
        {
            if (packageStream == null)
            {
                throw new ArgumentNullException(nameof(packageStream));
            }

            if (packageIdentity == null)
            {
                throw new ArgumentNullException(nameof(packageIdentity));
            }

            if (packagePathResolver == null)
            {
                throw new ArgumentNullException(nameof(packagePathResolver));
            }

            // TODO: Need to handle PackageSaveMode
            // TODO: Support overwriting files also?
            var filesAdded = new List <string>();

            var nuspecReader = new NuspecReader(packageReader.GetNuspec());

            packageIdentity = nuspecReader.GetIdentity();

            var packageDirectoryInfo = Directory.CreateDirectory(packagePathResolver.GetInstallPath(packageIdentity));
            var packageDirectory     = packageDirectoryInfo.FullName;

            foreach (var file in packageReader.GetFiles().Where(file => PackageHelper.IsPackageFile(file, packageSaveMode)))
            {
                token.ThrowIfCancellationRequested();

                var targetPath = Path.Combine(packageDirectory, file);
                Directory.CreateDirectory(Path.GetDirectoryName(targetPath));

                using (var sourceStream = packageReader.GetStream(file))
                {
                    using (var targetStream = new FileStream(targetPath, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 1024, useAsync: true))
                    {
                        await sourceStream.CopyToAsync(targetStream);
                    }
                }

                filesAdded.Add(file);
            }

            var nupkgFilePath = Path.Combine(packageDirectory, packagePathResolver.GetPackageFileName(packageIdentity));

            if (packageSaveMode.HasFlag(PackageSaveModes.Nupkg))
            {
                // During package extraction, nupkg is the last file to be created
                // Since all the packages are already created, the package stream is likely positioned at its end
                // Reset it
                if (packageStream.Position != 0)
                {
                    if (!packageStream.CanSeek)
                    {
                        throw new ArgumentException(Strings.PackageStreamShouldBeSeekable);
                    }

                    packageStream.Position = 0;
                }

                filesAdded.Add(await PackageHelper.CreatePackageFile(nupkgFilePath, packageStream, token));
            }

            // Now, copy satellite files unless requested to not copy them
            if (packageExtractionContext == null || packageExtractionContext.CopySatelliteFiles)
            {
                PackageIdentity runtimeIdentity;
                string          packageLanguage;
                var             isSatellitePackage = PackageHelper.IsSatellitePackage(nuspecReader, out runtimeIdentity, out packageLanguage);

                // Short-circuit this if the package is not a satellite package.
                if (isSatellitePackage)
                {
                    filesAdded.AddRange(await CopySatelliteFilesAsync(packageIdentity, packagePathResolver, packageSaveMode, token));
                }
            }

            return(filesAdded);
        }