Esempio n. 1
0
        public void SerializeThenDeserialize_WithValidArguments_RoundTrips(InstalledAndTransitivePackages expectedResult)
        {
            IInstalledAndTransitivePackages actualResult = SerializeThenDeserialize(IInstalledAndTransitivePackagesFormatter.Instance, expectedResult);

            Assert.Equal(actualResult.InstalledPackages.Count, expectedResult.InstalledPackages.Count);
            Assert.Equal(actualResult.TransitivePackages.Count, expectedResult.TransitivePackages.Count);

            foreach (IPackageReferenceContextInfo expectedPackage in expectedResult.InstalledPackages)
            {
                IPackageReferenceContextInfo actualPackage = actualResult.InstalledPackages.FirstOrDefault(p => p.Identity.Equals(expectedPackage.Identity));
                CheckPackageReferencesContextInfoAreEqual(actualPackage, expectedPackage);
            }

            foreach (IPackageReferenceContextInfo expectedPackage in expectedResult.TransitivePackages)
            {
                IPackageReferenceContextInfo actualPackage = actualResult.TransitivePackages.FirstOrDefault(p => p.Identity.Equals(expectedPackage.Identity));
                CheckPackageReferencesContextInfoAreEqual(actualPackage, expectedPackage);
            }
        }
        private async Task <(IPackageFeed?mainFeed, IPackageFeed?recommenderFeed)> CreatePackageFeedAsync(
            IReadOnlyCollection <IProjectContextInfo> projectContextInfos,
            IReadOnlyCollection <string> targetFrameworks,
            ItemFilter itemFilter,
            bool recommendPackages,
            IEnumerable <SourceRepository> sourceRepositories,
            CancellationToken cancellationToken)
        {
            var logger       = new VisualStudioActivityLogger();
            var uiLogger     = ServiceLocator.GetInstance <INuGetUILogger>();
            var packageFeeds = (mainFeed: (IPackageFeed?)null, recommenderFeed: (IPackageFeed?)null);

            if (itemFilter == ItemFilter.All && recommendPackages == false)
            {
                packageFeeds.mainFeed = new MultiSourcePackageFeed(sourceRepositories, uiLogger, TelemetryActivity.NuGetTelemetryService);
                return(packageFeeds);
            }

            IInstalledAndTransitivePackages installedAndTransitivePackages = await GetInstalledAndTransitivePackagesAsync(projectContextInfos, cancellationToken);

            PackageCollection installedPackageCollection  = PackageCollection.FromPackageReferences(installedAndTransitivePackages.InstalledPackages);
            PackageCollection transitivePackageCollection = PackageCollection.FromPackageReferences(installedAndTransitivePackages.TransitivePackages);

            SourceRepository packagesFolderSourceRepository = await _packagesFolderLocalRepositoryLazy.GetValueAsync(cancellationToken);

            IEnumerable <SourceRepository> globalPackageFolderRepositories = await _globalPackageFolderRepositoriesLazy.GetValueAsync(cancellationToken);

            var metadataProvider = new MultiSourcePackageMetadataProvider(
                sourceRepositories,
                packagesFolderSourceRepository,
                globalPackageFolderRepositories,
                logger);

            if (itemFilter == ItemFilter.All)
            {
                // if we get here, recommendPackages == true
                packageFeeds.mainFeed        = new MultiSourcePackageFeed(sourceRepositories, uiLogger, TelemetryActivity.NuGetTelemetryService);
                packageFeeds.recommenderFeed = new RecommenderPackageFeed(
                    sourceRepositories,
                    installedPackageCollection,
                    transitivePackageCollection,
                    targetFrameworks,
                    metadataProvider,
                    logger);
                return(packageFeeds);
            }

            if (itemFilter == ItemFilter.Installed)
            {
                packageFeeds.mainFeed = new InstalledPackageFeed(installedPackageCollection, metadataProvider, logger);
                return(packageFeeds);
            }

            if (itemFilter == ItemFilter.Consolidate)
            {
                packageFeeds.mainFeed = new ConsolidatePackageFeed(installedPackageCollection, metadataProvider, logger);
                return(packageFeeds);
            }

            // Search all / updates available cannot work without a source repo
            if (sourceRepositories == null)
            {
                return(packageFeeds);
            }

            if (itemFilter == ItemFilter.UpdatesAvailable)
            {
                packageFeeds.mainFeed = new UpdatePackageFeed(
                    _serviceBroker,
                    installedPackageCollection,
                    metadataProvider,
                    projectContextInfos.ToArray());

                return(packageFeeds);
            }

            throw new InvalidOperationException(
                      string.Format(CultureInfo.CurrentCulture, Strings.UnsupportedFeedType, itemFilter));
        }
Esempio n. 3
0
        private async Task PerformActionImplAsync(
            IServiceBroker serviceBroker,
            INuGetProjectManagerService projectManagerService,
            INuGetUI uiService,
            ResolveActionsAsync resolveActionsAsync,
            NuGetOperationType operationType,
            UserAction userAction,
            CancellationToken cancellationToken)
        {
            var status       = NuGetOperationStatus.Succeeded;
            var startTime    = DateTimeOffset.Now;
            var packageCount = 0;

            var continueAfterPreview = true;
            var acceptedLicense      = true;

            List <string> removedPackages  = null;
            var           existingPackages = new HashSet <Tuple <string, string> >();
            List <Tuple <string, string> > addedPackages      = null;
            List <Tuple <string, string> > updatedPackagesOld = null;
            List <Tuple <string, string> > updatedPackagesNew = null;
            bool?packageToInstallWasTransitive = null;

            // Enable granular level telemetry events for nuget ui operation
            uiService.ProjectContext.OperationId = Guid.NewGuid();

            Stopwatch packageEnumerationTime = new Stopwatch();

            packageEnumerationTime.Start();
            try
            {
                IServiceBroker sb            = uiService.UIContext.ServiceBroker;
                int            projectsCount = uiService.Projects.Count();
                IEnumerable <IPackageReferenceContextInfo> installedPackages = null;
                // collect the install state of the existing packages
                foreach (IProjectContextInfo project in uiService.Projects) // only one project when PM UI is in project mode
                {
                    if (projectsCount == 1 && !userAction.IsSolutionLevel && userAction.Action == NuGetProjectActionType.Install && project.ProjectStyle == ProjectModel.ProjectStyle.PackageReference && project.ProjectKind == NuGetProjectKind.PackageReference)
                    {
                        IInstalledAndTransitivePackages installedAndTransitives = await project.GetInstalledAndTransitivePackagesAsync(sb, cancellationToken);

                        installedPackages = installedAndTransitives.InstalledPackages;

                        packageToInstallWasTransitive = false;
                        string packageIdToInstall = VSTelemetryServiceUtility.NormalizePackageId(userAction.PackageId);
                        foreach (IPackageReferenceContextInfo transitivePackage in installedAndTransitives.TransitivePackages)
                        {
                            if (packageIdToInstall == VSTelemetryServiceUtility.NormalizePackageId(transitivePackage.Identity.Id))
                            {
                                packageToInstallWasTransitive = true;
                                break;
                            }
                        }
                    }
                    else
                    {
                        installedPackages = await project.GetInstalledPackagesAsync(sb, cancellationToken);
                    }

                    foreach (IPackageReferenceContextInfo package in installedPackages)
                    {
                        existingPackages.Add(CreatePackageTuple(package));
                    }
                }
            }
            catch (Exception)
            {
                // don't teardown the process if we have a telemetry failure
            }
            packageEnumerationTime.Stop();

            await _lockService.ExecuteNuGetOperationAsync(async() =>
            {
                try
                {
                    uiService.BeginOperation();

                    using (INuGetProjectUpgraderService projectUpgrader = await serviceBroker.GetProxyAsync <INuGetProjectUpgraderService>(
                               NuGetServices.ProjectUpgraderService,
                               cancellationToken))
                    {
                        bool isAcceptedFormat = await CheckPackageManagementFormatAsync(projectUpgrader, uiService, cancellationToken);
                        if (!isAcceptedFormat)
                        {
                            return;
                        }
                    }

                    TelemetryServiceUtility.StartOrResumeTimer();

                    IReadOnlyList <ProjectAction> actions = await resolveActionsAsync(projectManagerService);
                    IReadOnlyList <PreviewResult> results = await GetPreviewResultsAsync(projectManagerService, actions, cancellationToken);

                    if (operationType == NuGetOperationType.Uninstall)
                    {
                        // removed packages don't have version info
                        removedPackages = results.SelectMany(result => result.Deleted)
                                          .Select(package => package.Id)
                                          .Distinct()
                                          .ToList();
                        packageCount = removedPackages.Count;
                    }
                    else
                    {
                        // log rich info about added packages
                        addedPackages = results.SelectMany(result => result.Added)
                                        .Select(package => new Tuple <string, string>(package.Id, (package.Version == null ? "" : package.Version.ToNormalizedString())))
                                        .Distinct()
                                        .ToList();
                        var addCount = addedPackages.Count;

                        //updated packages can have an old and a new id.
                        updatedPackagesOld = results.SelectMany(result => result.Updated)
                                             .Select(package => new Tuple <string, string>(package.Old.Id, (package.Old.Version == null ? "" : package.Old.Version.ToNormalizedString())))
                                             .Distinct()
                                             .ToList();
                        updatedPackagesNew = results.SelectMany(result => result.Updated)
                                             .Select(package => new Tuple <string, string>(package.New.Id, (package.New.Version == null ? "" : package.New.Version.ToNormalizedString())))
                                             .Distinct()
                                             .ToList();
                        var updateCount = updatedPackagesNew.Count;

                        // update packages count
                        packageCount = addCount + updateCount;

                        if (updateCount > 0)
                        {
                            // set operation type to update when there are packages being updated
                            operationType = NuGetOperationType.Update;
                        }
                    }

                    TelemetryServiceUtility.StopTimer();

                    // Show the preview window.
                    if (uiService.DisplayPreviewWindow)
                    {
                        bool shouldContinue = uiService.PromptForPreviewAcceptance(results);
                        if (!shouldContinue)
                        {
                            continueAfterPreview = false;
                            return;
                        }
                    }

                    TelemetryServiceUtility.StartOrResumeTimer();

                    // Show the license acceptance window.
                    bool accepted = await CheckLicenseAcceptanceAsync(uiService, results, cancellationToken);

                    TelemetryServiceUtility.StartOrResumeTimer();

                    if (!accepted)
                    {
                        acceptedLicense = false;
                        return;
                    }

                    // Warn about the fact that the "dotnet" TFM is deprecated.
                    if (uiService.DisplayDeprecatedFrameworkWindow)
                    {
                        bool shouldContinue = await ShouldContinueDueToDotnetDeprecationAsync(projectManagerService, uiService, cancellationToken);

                        TelemetryServiceUtility.StartOrResumeTimer();

                        if (!shouldContinue)
                        {
                            return;
                        }
                    }

                    if (!cancellationToken.IsCancellationRequested)
                    {
                        await projectManagerService.ExecuteActionsAsync(
                            actions,
                            cancellationToken);

                        string[] projectIds = actions
                                              .Select(action => action.ProjectId)
                                              .Distinct()
                                              .ToArray();

                        uiService.UIContext.RaiseProjectActionsExecuted(projectIds);
                    }
                    else
                    {
                        status = NuGetOperationStatus.Cancelled;
                    }
                }
                catch (System.Net.Http.HttpRequestException ex)
                {
                    status = NuGetOperationStatus.Failed;
                    if (ex.InnerException != null)
                    {
                        uiService.ShowError(ex.InnerException);
                    }
                    else
                    {
                        uiService.ShowError(ex);
                    }
                }
                catch (Exception ex)
                {
                    status = NuGetOperationStatus.Failed;
                    uiService.ShowError(ex);
                }
                finally
                {
                    TelemetryServiceUtility.StopTimer();

                    var duration = TelemetryServiceUtility.GetTimerElapsedTime();

                    uiService.ProjectContext.Log(MessageLevel.Info,
                                                 string.Format(CultureInfo.CurrentCulture, Resources.Operation_TotalTime, duration));

                    uiService.EndOperation();

                    // don't show "Succeeded" if we actually cancelled...
                    if ((!continueAfterPreview) || (!acceptedLicense))
                    {
                        if (status == NuGetOperationStatus.Succeeded)
                        {
                            status = NuGetOperationStatus.Cancelled;
                        }
                    }

                    var plc = new PackageLoadContext(isSolution: false, uiService.UIContext);
                    IReadOnlyCollection <string> frameworks = await plc.GetSupportedFrameworksAsync();
                    string[] projectIds = (await ProjectUtility.GetSortedProjectIdsAsync(
                                               uiService.UIContext.ServiceBroker,
                                               uiService.Projects,
                                               cancellationToken)).ToArray();

                    var packageSourceMapping           = PackageSourceMapping.GetPackageSourceMapping(uiService.Settings);
                    bool isPackageSourceMappingEnabled = packageSourceMapping?.IsEnabled ?? false;
                    var actionTelemetryEvent           = new VSActionsTelemetryEvent(
                        uiService.ProjectContext.OperationId.ToString(),
                        projectIds,
                        operationType,
                        OperationSource.UI,
                        startTime,
                        status,
                        packageCount,
                        DateTimeOffset.Now,
                        duration.TotalSeconds,
                        isPackageSourceMappingEnabled: isPackageSourceMappingEnabled);

                    var nuGetUI = uiService as NuGetUI;
                    AddUiActionEngineTelemetryProperties(
                        actionTelemetryEvent,
                        continueAfterPreview,
                        acceptedLicense,
                        userAction,
                        nuGetUI?.SelectedIndex,
                        nuGetUI?.RecommendedCount,
                        nuGetUI?.RecommendPackages,
                        nuGetUI?.RecommenderVersion,
                        nuGetUI?.TopLevelVulnerablePackagesCount ?? 0,
                        nuGetUI?.TopLevelVulnerablePackagesMaxSeverities?.ToList() ?? new List <int>(),
                        existingPackages,
                        addedPackages,
                        removedPackages,
                        updatedPackagesOld,
                        updatedPackagesNew,
                        frameworks);

                    if (packageToInstallWasTransitive.HasValue)
                    {
                        actionTelemetryEvent.PackageToInstallWasTransitive = packageToInstallWasTransitive.Value;
                    }
                    actionTelemetryEvent["InstalledPackageEnumerationTimeInMilliseconds"] = packageEnumerationTime.ElapsedMilliseconds;

                    TelemetryActivity.EmitTelemetryEvent(actionTelemetryEvent);
                }
            }, cancellationToken);
        }