From 067d6c5ea60a2a6376d201d12720beb0b9c21ba0 Mon Sep 17 00:00:00 2001 From: Yishai Galatzer Date: Mon, 12 Oct 2015 16:16:12 -0700 Subject: [PATCH] Fix https://github.com/NuGet/Home/issues/225 Fix https://github.com/NuGet/Home/issues/1547 1. Change the order of uninstall to run the uninstall.ps1 script first (to match NuGet 2) 2. Check that the folder exists before trying to delete it 3. Remove duplicate call to Remove file from the project --- .../Projects/IMSBuildNuGetProjectSystem.cs | 1 - .../Projects/MSBuildNuGetProject.cs | 103 ++++++++---------- .../MSBuildNuGetProjectSystemUtility.cs | 47 ++++++-- 3 files changed, 82 insertions(+), 69 deletions(-) diff --git a/src/NuGet.Core/NuGet.ProjectManagement/Projects/IMSBuildNuGetProjectSystem.cs b/src/NuGet.Core/NuGet.ProjectManagement/Projects/IMSBuildNuGetProjectSystem.cs index a211a9a9da1..da82aca2a32 100644 --- a/src/NuGet.Core/NuGet.ProjectManagement/Projects/IMSBuildNuGetProjectSystem.cs +++ b/src/NuGet.Core/NuGet.ProjectManagement/Projects/IMSBuildNuGetProjectSystem.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.IO; -using System.IO.Compression; using System.Threading.Tasks; using NuGet.Frameworks; using NuGet.Packaging.Core; diff --git a/src/NuGet.Core/NuGet.ProjectManagement/Projects/MSBuildNuGetProject.cs b/src/NuGet.Core/NuGet.ProjectManagement/Projects/MSBuildNuGetProject.cs index 2355810841f..a16e4f4fc62 100644 --- a/src/NuGet.Core/NuGet.ProjectManagement/Projects/MSBuildNuGetProject.cs +++ b/src/NuGet.Core/NuGet.ProjectManagement/Projects/MSBuildNuGetProject.cs @@ -17,33 +17,6 @@ namespace NuGet.ProjectManagement { - internal class PackageItemComparer : IComparer - { - public int Compare(string x, string y) - { - // BUG 636: We sort files so that they are added in the correct order - // e.g aspx before aspx.cs - - if (x.Equals(y, StringComparison.OrdinalIgnoreCase)) - { - return 0; - } - - // Add files that are prefixes of other files first - if (x.StartsWith(y, StringComparison.OrdinalIgnoreCase)) - { - return -1; - } - - if (y.StartsWith(x, StringComparison.OrdinalIgnoreCase)) - { - return 1; - } - - return string.Compare(y, x, StringComparison.OrdinalIgnoreCase); - } - } - /// /// This class represents a NuGetProject based on a .NET project. This also contains an instance of a /// FolderNuGetProject @@ -92,7 +65,9 @@ public class MSBuildNuGetProject : NuGetProject { new FileTransformExtensions(".install.xdt", ".uninstall.xdt"), new XdtTransformer() } }; - public MSBuildNuGetProject(IMSBuildNuGetProjectSystem msbuildNuGetProjectSystem, string folderNuGetProjectPath, string packagesConfigFolderPath) + public MSBuildNuGetProject(IMSBuildNuGetProjectSystem msbuildNuGetProjectSystem, + string folderNuGetProjectPath, + string packagesConfigFolderPath) { if (msbuildNuGetProjectSystem == null) { @@ -178,7 +153,7 @@ public override async Task InstallPackageAsync( return false; } - // Step-2: Create PackageReader using the PackageStream and obtain the various item groups + // Step-2: Create PackageReader using the PackageStream and obtain the various item groups downloadResourceResult.PackageStream.Seek(0, SeekOrigin.Begin); var packageReader = downloadResourceResult.PackageReader; if (packageReader == null) @@ -279,7 +254,7 @@ public override async Task InstallPackageAsync( } PackageEventsProvider.Instance.NotifyInstalling(packageEventArgs); - // Step-6: Install package to FolderNuGetProject + // Step-6: Install package to FolderNuGetProject await FolderNuGetProject.InstallPackageAsync(packageIdentity, downloadResourceResult, nuGetProjectContext, token); // Step-7: Raise PackageInstalled event @@ -303,10 +278,12 @@ public override async Task InstallPackageAsync( { var referenceItemFullPath = Path.Combine(packageInstallPath, referenceItem); var referenceName = Path.GetFileName(referenceItem); + if (MSBuildNuGetProjectSystem.ReferenceExists(referenceName)) { MSBuildNuGetProjectSystem.RemoveReference(referenceName); } + MSBuildNuGetProjectSystem.AddReference(referenceItemFullPath); } } @@ -403,36 +380,57 @@ public override async Task UninstallPackageAsync(PackageIdentity packageId } var packageTargetFramework = packageReference.TargetFramework ?? MSBuildNuGetProjectSystem.TargetFramework; - var packageEventArgs = new PackageEventArgs(FolderNuGetProject, packageIdentity, FolderNuGetProject.GetInstalledPath(packageIdentity)); + var packageEventArgs = new PackageEventArgs(FolderNuGetProject, + packageIdentity, + FolderNuGetProject.GetInstalledPath(packageIdentity)); + + if (PackageUninstalling != null) + { + PackageUninstalling(this, packageEventArgs); + } + using (var packageStream = File.OpenRead(FolderNuGetProject.GetInstalledPackageFilePath(packageIdentity))) { - // Step-2: Create PackageReader using the PackageStream and obtain the various item groups - // Get the package target framework instead of using project targetframework var zipArchive = new ZipArchive(packageStream); var packageReader = new PackageReader(zipArchive); + // Step-2: Execute powershell script - uninstall.ps1 + var toolItemGroups = packageReader.GetToolItems(); + var compatibleToolItemsGroup = MSBuildNuGetProjectSystemUtility + .GetMostCompatibleGroup(packageTargetFramework, toolItemGroups); + + 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 MSBuildNuGetProjectSystem.ExecuteScriptAsync(packageIdentity, packageInstallPath, uninstallPS1RelativePath, this, throwOnFailure: false); + } + } + + // 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-3: Get the most compatible items groups for all items groups + // 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); - // TODO: Need to handle References element?? - // Step-4: Raise PackageUninstalling event - if (PackageUninstalling != null) - { - PackageUninstalling(this, packageEventArgs); - } PackageEventsProvider.Instance.NotifyUninstalling(packageEventArgs); - // Step-5: Uninstall package from packages.config + // 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 @@ -484,38 +482,27 @@ public override async Task UninstallPackageAsync(PackageIdentity packageId } // 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: Execute powershell script - uninstall.ps1 - var toolItemGroups = packageReader.GetToolItems(); - var compatibleToolItemsGroup = MSBuildNuGetProjectSystemUtility.GetMostCompatibleGroup(packageTargetFramework, - toolItemGroups); - 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 MSBuildNuGetProjectSystem.ExecuteScriptAsync(packageIdentity, packageInstallPath, uninstallPS1RelativePath, this, throwOnFailure: false); - } - } + PackageEventsProvider.Instance.NotifyReferenceRemoved(packageEventArgs); } - // Step-10: Uninstall package from the folderNuGetProject + // Step-9: Uninstall package from the folderNuGetProject await FolderNuGetProject.UninstallPackageAsync(packageIdentity, nuGetProjectContext, token); - // Step-11: Raise PackageUninstalled event + // Step-10: Raise PackageUninstalled event if (PackageUninstalled != null) { PackageUninstalled(this, packageEventArgs); } + PackageEventsProvider.Instance.NotifyUninstalled(packageEventArgs); return true; diff --git a/src/NuGet.Core/NuGet.ProjectManagement/Utility/MSBuildNuGetProjectSystemUtility.cs b/src/NuGet.Core/NuGet.ProjectManagement/Utility/MSBuildNuGetProjectSystemUtility.cs index a00fd90db80..bd6fd17597e 100644 --- a/src/NuGet.Core/NuGet.ProjectManagement/Utility/MSBuildNuGetProjectSystemUtility.cs +++ b/src/NuGet.Core/NuGet.ProjectManagement/Utility/MSBuildNuGetProjectSystemUtility.cs @@ -77,7 +77,7 @@ internal static void AddFiles(IMSBuildNuGetProjectSystem msBuildNuGetProjectSyst IDictionary fileTransformers) { var packageTargetFramework = frameworkSpecificGroup.TargetFramework; - + var packageItemListAsArchiveEntryNames = frameworkSpecificGroup.Items.ToList(); packageItemListAsArchiveEntryNames.Sort(new PackageItemComparer()); try @@ -154,9 +154,9 @@ internal static void DeleteFiles(IMSBuildNuGetProjectSystem msBuildNuGetProjectS // Get all directories that this package may have added var directories = from grouping in directoryLookup - from directory in FileSystemUtility.GetDirectories(grouping.Key, altDirectorySeparator: false) - orderby directory.Length descending - select directory; + from directory in FileSystemUtility.GetDirectories(grouping.Key, altDirectorySeparator: false) + orderby directory.Length descending + select directory; // Remove files from every directory foreach (var directory in directories) @@ -329,6 +329,7 @@ internal static void DeleteDirectory(IMSBuildNuGetProjectSystem msBuildNuGetProj msBuildNuGetProjectSystem.NuGetProjectContext.Log(MessageLevel.Warning, Strings.Warning_DirectoryNotEmpty, path); return; } + msBuildNuGetProjectSystem.DeleteDirectory(path, recursive); // Workaround for update-package TFS issue. If we're bound to TFS, do not try and delete directories. @@ -339,7 +340,10 @@ internal static void DeleteDirectory(IMSBuildNuGetProjectSystem msBuildNuGetProj return; } - try + // For potential project systems that do not remove items from disk, we delete the folder directly + // There is no actual scenario where we know this is broken without the code below, but since the + // code was always there, we are leaving it behind for now. + if (!Directory.Exists(fullPath)) { Directory.Delete(fullPath, recursive); @@ -349,13 +353,9 @@ internal static void DeleteDirectory(IMSBuildNuGetProjectSystem msBuildNuGetProj { Thread.Sleep(100); } - msBuildNuGetProjectSystem.RemoveFile(path); msBuildNuGetProjectSystem.NuGetProjectContext.Log(MessageLevel.Debug, Strings.Debug_RemovedFolder, fullPath); } - catch (DirectoryNotFoundException) - { - } } private static void PerformSafeAction(Action action, INuGetProjectContext nuGetProjectContext) @@ -510,5 +510,32 @@ internal static void AddFile(IMSBuildNuGetProjectSystem msBuildNuGetProjectSyste msBuildNuGetProjectSystem.AddFile(path, memoryStream); } } + + private class PackageItemComparer : IComparer + { + public int Compare(string x, string y) + { + // BUG 636: We sort files so that they are added in the correct order + // e.g aspx before aspx.cs + + if (x.Equals(y, StringComparison.OrdinalIgnoreCase)) + { + return 0; + } + + // Add files that are prefixes of other files first + if (x.StartsWith(y, StringComparison.OrdinalIgnoreCase)) + { + return -1; + } + + if (y.StartsWith(x, StringComparison.OrdinalIgnoreCase)) + { + return 1; + } + + return string.Compare(y, x, StringComparison.OrdinalIgnoreCase); + } + } } -} +} \ No newline at end of file