// Deletes an empty folder from disk and the project private static void DeleteDirectory(IMSBuildProjectSystem projectSystem, string path) { var fullPath = Path.Combine(projectSystem.ProjectFullPath, path); if (!Directory.Exists(fullPath)) { return; } // Only delete this folder if it is empty and we didn't specify that we want to recurse if (GetFiles(projectSystem, path, "*.*", recursive: false).Any() || GetDirectories(projectSystem, path).Any()) { projectSystem.NuGetProjectContext.Log(MessageLevel.Warning, Strings.Warning_DirectoryNotEmpty, path); return; } projectSystem.RegisterProcessedFiles(new[] { path }); projectSystem.DeleteDirectory(path, recursive: false); // Workaround for update-package TFS issue. If we're bound to TFS, do not try and delete directories. var sourceControlManager = SourceControlUtility.GetSourceControlManager(projectSystem.NuGetProjectContext); if (sourceControlManager != null) { // Source control bound, do not delete return; } // 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: false); // The directory is not guaranteed to be gone since there could be // other open handles. Wait, up to half a second, until the directory is gone. for (var i = 0; Directory.Exists(fullPath) && i < 5; ++i) { Thread.Sleep(100); } projectSystem.RegisterProcessedFiles(new[] { path }); projectSystem.NuGetProjectContext.Log(MessageLevel.Debug, Strings.Debug_RemovedFolder, fullPath); } }
internal static async Task DeleteFilesAsync( IMSBuildProjectSystem projectSystem, ZipArchive zipArchive, IEnumerable <string> otherPackagesPath, FrameworkSpecificGroup frameworkSpecificGroup, IDictionary <FileTransformExtensions, IPackageFileTransformer> fileTransformers, CancellationToken cancellationToken) { var packageTargetFramework = frameworkSpecificGroup.TargetFramework; IPackageFileTransformer transformer; var directoryLookup = frameworkSpecificGroup.Items.ToLookup( p => Path.GetDirectoryName(ResolveTargetPath(projectSystem, fileTransformers, fte => fte.UninstallExtension, GetEffectivePathForContentFile(packageTargetFramework, p), out transformer))); // 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; var projectFullPath = projectSystem.ProjectFullPath; // Remove files from every directory foreach (var directory in directories) { var directoryFiles = directoryLookup.Contains(directory) ? directoryLookup[directory] : Enumerable.Empty <string>(); if (!Directory.Exists(Path.Combine(projectFullPath, directory))) { continue; } foreach (var file in directoryFiles) { if (IsEmptyFolder(file)) { continue; } // Resolve the path var path = ResolveTargetPath(projectSystem, fileTransformers, fte => fte.UninstallExtension, GetEffectivePathForContentFile(packageTargetFramework, file), out transformer); if (projectSystem.IsSupportedFile(path)) { // Register the file being uninstalled (used by web site project system). projectSystem.RegisterProcessedFiles(new[] { path }); if (transformer != null) { // TODO: use the framework from packages.config instead of the current framework // which may have changed during re-targeting var projectFramework = projectSystem.TargetFramework; var matchingFiles = new List <InternalZipFileInfo>(); foreach (var otherPackagePath in otherPackagesPath) { using (var otherPackageZipReader = new PackageArchiveReader(otherPackagePath)) { // use the project framework to find the group that would have been installed var mostCompatibleContentFilesGroup = GetMostCompatibleGroup( projectFramework, otherPackageZipReader.GetContentItems()); if (IsValid(mostCompatibleContentFilesGroup)) { // Should not normalize content files group. // It should be like a ZipFileEntry with a forward slash. foreach (var otherPackageItem in mostCompatibleContentFilesGroup.Items) { if (GetEffectivePathForContentFile(packageTargetFramework, otherPackageItem) .Equals( GetEffectivePathForContentFile(packageTargetFramework, file), StringComparison.OrdinalIgnoreCase)) { matchingFiles.Add(new InternalZipFileInfo(otherPackagePath, otherPackageItem)); } } } } } try { var zipArchiveFileEntry = PathUtility.GetEntry(zipArchive, file); if (zipArchiveFileEntry != null) { await transformer.RevertFileAsync( () => Task.FromResult(zipArchiveFileEntry.Open()), path, matchingFiles, projectSystem, cancellationToken); } } catch (Exception e) { projectSystem.NuGetProjectContext.Log(MessageLevel.Warning, e.Message); } } else { try { var zipArchiveFileEntry = PathUtility.GetEntry(zipArchive, file); if (zipArchiveFileEntry != null) { await DeleteFileSafeAsync( path, () => Task.FromResult(zipArchiveFileEntry.Open()), projectSystem, cancellationToken); } } catch (Exception e) { projectSystem.NuGetProjectContext.Log(MessageLevel.Warning, e.Message); } } } } // If the directory is empty then delete it if (!GetFilesSafe(projectSystem, directory).Any() && !GetDirectoriesSafe(projectSystem, directory).Any()) { DeleteDirectorySafe(projectSystem, directory); } } }
internal static async Task AddFilesAsync( IMSBuildProjectSystem projectSystem, IAsyncPackageCoreReader packageReader, FrameworkSpecificGroup frameworkSpecificGroup, IDictionary <FileTransformExtensions, IPackageFileTransformer> fileTransformers, CancellationToken cancellationToken) { var packageTargetFramework = frameworkSpecificGroup.TargetFramework; var packageItemListAsArchiveEntryNames = frameworkSpecificGroup.Items.ToList(); packageItemListAsArchiveEntryNames.Sort(new PackageItemComparer()); try { var paths = packageItemListAsArchiveEntryNames.Select( file => ResolvePath(fileTransformers, fte => fte.InstallExtension, GetEffectivePathForContentFile(packageTargetFramework, file))); paths = paths.Where(p => !string.IsNullOrEmpty(p)); projectSystem.RegisterProcessedFiles(paths); } catch (Exception) { // Ignore all exceptions for now } foreach (var file in packageItemListAsArchiveEntryNames) { if (IsEmptyFolder(file)) { continue; } var effectivePathForContentFile = GetEffectivePathForContentFile(packageTargetFramework, file); // Resolve the target path IPackageFileTransformer installTransformer; var path = ResolveTargetPath(projectSystem, fileTransformers, fte => fte.InstallExtension, effectivePathForContentFile, out installTransformer); if (projectSystem.IsSupportedFile(path)) { if (installTransformer != null) { await installTransformer.TransformFileAsync( () => packageReader.GetStreamAsync(file, cancellationToken), path, projectSystem, cancellationToken); } else { // Ignore uninstall transform file during installation string truncatedPath; var uninstallTransformer = FindFileTransformer(fileTransformers, fte => fte.UninstallExtension, effectivePathForContentFile, out truncatedPath); if (uninstallTransformer != null) { continue; } await TryAddFileAsync( projectSystem, path, () => packageReader.GetStreamAsync(file, cancellationToken), cancellationToken); } } } }