public static async Task InstallFromSourceAsync()

in src/NuGet.Core/NuGet.Packaging/PackageExtractor.cs [379:591]


        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 packageExtractionTelemetryEvent = new PackageExtractionTelemetryEvent(packageExtractionContext.PackageSaveMode, NuGetOperationStatus.Failed, ExtractionSource.DownloadResource, packageIdentity);
            using (var telemetry = TelemetryActivity.Create(parentId, packageExtractionTelemetryEvent))
            {

                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);
                var nupkgMetadataFilePath = versionFolderPathResolver.GetNupkgMetadataPath(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(nupkgMetadataFilePath))
                        {
                            logger.LogVerbose(
                                $"Acquired lock for the installation of {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 tempNupkgMetadataPath = Path.Combine(targetPath, Path.GetRandomFileName());
                            var packageSaveMode = packageExtractionContext.PackageSaveMode;
                            string contentHash;

                            try
                            {
                                // Extract the nupkg
                                using (var nupkgStream = new FileStream(
                                    targetTempNupkg,
                                    FileMode.Create,
                                    FileAccess.ReadWrite,
                                    FileShare.ReadWrite | FileShare.Delete,
                                    bufferSize: 4096))
                                {
                                    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 hashFileName = Path.GetFileName(hashPath);
                                            var nupkgMetadataFileName = Path.GetFileName(nupkgMetadataFilePath);
                                            var packageFiles = packageReader.GetFiles()
                                                .Where(file => ShouldInclude(file, hashFileName, nupkgMetadataFileName));
                                            var packageFileExtractor = new PackageFileExtractor(
                                                packageFiles,
                                                packageExtractionContext.XmlDocFileSaveMode);
                                            packageReader.CopyFiles(
                                                targetPath,
                                                packageFiles,
                                                packageFileExtractor.ExtractPackageFile,
                                                logger,
                                                token);
                                        }

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

                                        File.WriteAllText(tempHashPath, packageHash);

                                        // get hash for the unsigned content of package
                                        contentHash = packageReader.GetContentHash(cancellationToken, GetUnsignedPackageHash: () => packageHash);

                                        // write the new hash file
                                        var hashFile = new NupkgMetadataFile()
                                        {
                                            ContentHash = contentHash,
                                            Source = source
                                        };

                                        NupkgMetadataFileFormat.Write(tempNupkgMetadataPath, hashFile);
                                    }
                                }
                            }
                            catch (SignatureException)
                            {
                                try
                                {
                                    DeleteTargetAndTempPaths(targetPath, targetTempNupkg);
                                }
                                catch (IOException ex)
                                {
                                    logger.LogWarning(string.Format(
                                        CultureInfo.CurrentCulture,
                                        Strings.ErrorUnableToDeleteFile,
                                        targetTempNupkg,
                                        ex.Message));
                                }

                                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);

                            File.Move(tempNupkgMetadataPath, nupkgMetadataFilePath);

                            logger.LogInformation(StringFormatter.Log_InstalledPackage(packageIdentity.Id, packageIdentity.Version.OriginalVersion, source, contentHash, targetPath));

                            packageExtractionTelemetryEvent.SetResult(NuGetOperationStatus.Succeeded);
                            return true;
                        }
                        else
                        {
                            logger.LogVerbose("Lock not required - Package already installed "
                                                + $"{packageIdentity.Id} {packageIdentity.Version}");

                            packageExtractionTelemetryEvent.SetResult(NuGetOperationStatus.NoOp);
                            return false;
                        }
                    },
                    token: token);
            }
        }