/// <summary>
        /// Determines if package needs to be reinstalled for the new target framework of the project
        /// </summary>
        /// <param name="newProjectFramework">current target framework of the project</param>
        /// <param name="oldProjectFramework">target framework of the project against which the package was installed</param>
        /// <param name="package">package for which reinstallation is being determined</param>
        /// <returns>whether the package identity needs to be reinstalled</returns>
        private static bool ShouldPackageBeReinstalled(NuGetFramework newProjectFramework, NuGetFramework oldProjectFramework, PackageIdentity package, NuGetPackageManager packageManager)
        {
            Debug.Assert(newProjectFramework != null);
            Debug.Assert(oldProjectFramework != null);
            Debug.Assert(package != null);

            // Default to true, i.e. package does not need to be reinstalled.
            bool isAllItemsCompatible = true;

            var packageFilePath = packageManager?.PackagesFolderNuGetProject?.GetInstalledPackageFilePath(package);

            if (string.IsNullOrEmpty(packageFilePath))
            {
                return(false);
            }

            try
            {
                using (var packageReader = new PackageArchiveReader(packageFilePath))
                {
                    var libItemGroups            = packageReader.GetLibItems();
                    var referenceItemGroups      = packageReader.GetReferenceItems();
                    var frameworkReferenceGroups = packageReader.GetFrameworkItems();
                    var contentFileGroups        = packageReader.GetContentItems();
                    var buildFileGroups          = packageReader.GetBuildItems();
                    var toolItemGroups           = packageReader.GetToolItems();

                    isAllItemsCompatible = IsNearestFrameworkSpecificGroupEqual(libItemGroups, newProjectFramework, oldProjectFramework) &&
                                           IsNearestFrameworkSpecificGroupEqual(referenceItemGroups, newProjectFramework, oldProjectFramework) &&
                                           IsNearestFrameworkSpecificGroupEqual(frameworkReferenceGroups, newProjectFramework, oldProjectFramework) &&
                                           IsNearestFrameworkSpecificGroupEqual(contentFileGroups, newProjectFramework, oldProjectFramework) &&
                                           IsNearestFrameworkSpecificGroupEqual(buildFileGroups, newProjectFramework, oldProjectFramework) &&
                                           IsNearestFrameworkSpecificGroupEqual(toolItemGroups, newProjectFramework, oldProjectFramework);
                }
            }
            catch (Exception ex)
            {
                ExceptionHelper.WriteErrorToActivityLog(ex);
            }

            // When all items are not compatible, the installed package should be retargeted.
            return(!isAllItemsCompatible);
        }
Пример #2
0
        public override async Task <bool> UninstallPackageAsync(PackageIdentity packageIdentity, INuGetProjectContext nuGetProjectContext, CancellationToken token)
        {
            if (packageIdentity == null)
            {
                throw new ArgumentNullException(nameof(packageIdentity));
            }

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

            // Step-1: Check if the package already exists after setting the nuGetProjectContext
            ProjectSystem.NuGetProjectContext = nuGetProjectContext;

            var packageReference = (await GetInstalledPackagesAsync(token))
                                   .FirstOrDefault(p => p.PackageIdentity.Equals(packageIdentity));

            if (packageReference == null)
            {
                nuGetProjectContext.Log(MessageLevel.Warning, Strings.PackageDoesNotExistInProject,
                                        packageIdentity, ProjectSystem.ProjectName);
                return(false);
            }

            var packageTargetFramework = packageReference.TargetFramework ?? ProjectSystem.TargetFramework;
            var packageEventArgs       = new PackageEventArgs(FolderNuGetProject,
                                                              packageIdentity,
                                                              FolderNuGetProject.GetInstalledPath(packageIdentity));

            if (PackageUninstalling != null)
            {
                PackageUninstalling(this, packageEventArgs);
            }

            PackageEventsProvider.Instance.NotifyUninstalling(packageEventArgs);

            using (var packageStream = File.OpenRead(FolderNuGetProject.GetInstalledPackageFilePath(packageIdentity)))
            {
                var zipArchive    = new ZipArchive(packageStream);
                var packageReader = new PackageArchiveReader(zipArchive);

                // Step-2: Execute powershell script - uninstall.ps1
                var toolItemGroups           = packageReader.GetToolItems();
                var compatibleToolItemsGroup = MSBuildNuGetProjectSystemUtility
                                               .GetMostCompatibleGroup(packageTargetFramework, toolItemGroups);
                compatibleToolItemsGroup = MSBuildNuGetProjectSystemUtility.Normalize(compatibleToolItemsGroup);

                if (MSBuildNuGetProjectSystemUtility.IsValid(compatibleToolItemsGroup))
                {
                    var uninstallPS1RelativePath = compatibleToolItemsGroup.Items.FirstOrDefault(
                        p => p.EndsWith(Path.DirectorySeparatorChar + PowerShellScripts.Uninstall,
                                        StringComparison.OrdinalIgnoreCase));

                    if (!string.IsNullOrEmpty(uninstallPS1RelativePath))
                    {
                        var packageInstallPath = FolderNuGetProject.GetInstalledPath(
                            packageIdentity);
                        await ProjectServices.ScriptService.ExecutePackageScriptAsync(
                            packageIdentity,
                            packageInstallPath,
                            uninstallPS1RelativePath,
                            nuGetProjectContext,
                            throwOnFailure : false,
                            token : token);
                    }
                }

                // Step-3: Obtain the various item groups
                // Get the package target framework instead of using project targetframework
                var referenceItemGroups = packageReader.GetReferenceItems();
                var contentFileGroups   = packageReader.GetContentItems();
                var buildFileGroups     = packageReader.GetBuildItems();

                // Step-4: Get the most compatible items groups for all items groups
                var compatibleReferenceItemsGroup =
                    MSBuildNuGetProjectSystemUtility.GetMostCompatibleGroup(packageTargetFramework, referenceItemGroups);

                var compatibleContentFilesGroup =
                    MSBuildNuGetProjectSystemUtility.GetMostCompatibleGroup(packageTargetFramework, contentFileGroups);

                var compatibleBuildFilesGroup =
                    MSBuildNuGetProjectSystemUtility.GetMostCompatibleGroup(packageTargetFramework, buildFileGroups);

                compatibleReferenceItemsGroup
                    = MSBuildNuGetProjectSystemUtility.Normalize(compatibleReferenceItemsGroup);
                compatibleContentFilesGroup
                    = MSBuildNuGetProjectSystemUtility.Normalize(compatibleContentFilesGroup);
                compatibleBuildFilesGroup
                    = MSBuildNuGetProjectSystemUtility.Normalize(compatibleBuildFilesGroup);

                // Step-5: Remove package reference from packages.config
                await PackagesConfigNuGetProject.UninstallPackageAsync(packageIdentity, nuGetProjectContext, token);

                // Step-6: Remove packages.config from MSBuildNuGetProject if there are no packages
                //         OR Add it again (to ensure that Source Control works), when there are some packages
                if (!(await PackagesConfigNuGetProject.GetInstalledPackagesAsync(token)).Any())
                {
                    ProjectSystem.RemoveFile(Path.GetFileName(PackagesConfigNuGetProject.FullPath));
                }
                else
                {
                    ProjectSystem.AddExistingFile(Path.GetFileName(PackagesConfigNuGetProject.FullPath));
                }

                // Step-7: Uninstall package from the msbuild project
                // Step-7.1: Remove references
                if (MSBuildNuGetProjectSystemUtility.IsValid(compatibleReferenceItemsGroup))
                {
                    foreach (var item in compatibleReferenceItemsGroup.Items)
                    {
                        if (IsAssemblyReference(item))
                        {
                            await ProjectSystem.RemoveReferenceAsync(Path.GetFileName(item));
                        }
                    }
                }

                // Step-7.2: Framework references are never removed. This is a no-op

                // Step-7.3: Remove content files
                if (MSBuildNuGetProjectSystemUtility.IsValid(compatibleContentFilesGroup))
                {
                    var packagesPaths = (await GetInstalledPackagesAsync(token))
                                        .Select(pr => FolderNuGetProject.GetInstalledPackageFilePath(pr.PackageIdentity));

                    await MSBuildNuGetProjectSystemUtility.DeleteFilesAsync(
                        ProjectSystem,
                        zipArchive,
                        packagesPaths,
                        compatibleContentFilesGroup,
                        FileTransformers,
                        token);
                }

                // Step-7.4: Remove build imports
                if (MSBuildNuGetProjectSystemUtility.IsValid(compatibleBuildFilesGroup))
                {
                    foreach (var buildImportFile in compatibleBuildFilesGroup.Items)
                    {
                        var fullImportFilePath = Path.Combine(FolderNuGetProject.GetInstalledPath(packageIdentity), buildImportFile);
                        ProjectSystem.RemoveImport(fullImportFilePath);
                    }
                }

                // Step-7.5: Remove binding redirects. This is a no-op
                // Binding redirects will be removed when all packages have finished
                // uninstalling for performance reasons

                // Step-8: Raise PackageReferenceRemoved event
                if (PackageReferenceRemoved != null)
                {
                    PackageReferenceRemoved(this, packageEventArgs);
                }

                PackageEventsProvider.Instance.NotifyReferenceRemoved(packageEventArgs);
            }

            // Step-9: Uninstall package from the folderNuGetProject
            await FolderNuGetProject.UninstallPackageAsync(packageIdentity, nuGetProjectContext, token);

            // Step-10: Raise PackageUninstalled event
            if (PackageUninstalled != null)
            {
                PackageUninstalled(this, packageEventArgs);
            }

            PackageEventsProvider.Instance.NotifyUninstalled(packageEventArgs);

            return(true);
        }
Пример #3
0
 public IEnumerable <FrameworkSpecificGroup> GetBuildItems()
 {
     return(packageArchiveReader.GetBuildItems());
 }