diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs index d82f87e742e..890989f359c 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs @@ -895,8 +895,9 @@ public bool RetainFolderStructureOverride /// /// The root directory of the package /// - private string CurrentPackageDirectory { get; set; } + private IEnumerable CurrentPackageRootDirectories { get; set; } private static MetadataLoadContext sharedMetaDataLoadContext = null; + /// /// A shared MetaDataLoadContext that is used for assembly inspection during package publishing. /// This member is shared so the behavior is similar to the ReflectionOnlyLoadContext this is replacing. @@ -1073,34 +1074,30 @@ internal List BindParentToChild(Dictionary - /// Gets the list PackageItemRootViewModel items which will be at the root directory of the package with all the child items. + /// Organizes package items into root items based on common paths and hierarchical structure. + /// This includes determining root items, establishing parent-child relationships, and collecting all child items. /// - /// - /// - private List GetRootItems(Dictionary items) + /// A dictionary of package item keys and their corresponding PackageItemRootViewModel objects. + /// A list of PackageItemRootViewModel items representing the organized root items and their child items. + private List OrganizePackageRootItems(Dictionary items) { var rootItems = items.Values.Where(x => !x.isChild).ToList(); if (!rootItems.Any()) return rootItems; var roots = new List(); + + var commonPaths = GetCommonPaths(items.Keys.ToArray()); + if (commonPaths == null) return null; - if (CurrentPackageDirectory != null) - { - roots.Add(new PackageItemRootViewModel(CurrentPackageDirectory)); - } - else - { - var commonPaths = GetCommonPaths(items.Keys.ToArray()); - if (commonPaths == null) return null; + CurrentPackageRootDirectories = commonPaths; - // Add a new root item for each common path found - commonPaths.ForEach(p => roots.Add(new PackageItemRootViewModel(p))); - } + // Add a new root item for each common path found + commonPaths.ForEach(p => roots.Add(new PackageItemRootViewModel(p))); // Check each root item and create any missing connections foreach (var item in rootItems) @@ -1532,7 +1529,7 @@ internal static PublishPackageViewModel FromLocalPackage(DynamoViewModel dynamoV CopyrightHolder = pkg.CopyrightHolder, CopyrightYear = pkg.CopyrightYear, IsPublishFromLocalPackage = true, - CurrentPackageDirectory = pkg.RootDirectory, + CurrentPackageRootDirectories = new List { pkg.RootDirectory }, //default retain folder structure to true when publishing a new version from local. RetainFolderStructureOverride = retainFolderStructure }; @@ -2270,7 +2267,7 @@ private void Submit() { // begin submission var pmExtension = dynamoViewModel.Model.GetPackageManagerExtension(); - var handle = pmExtension.PackageManagerClient.PublishAsync(Package, RetainFolderStructureOverride ? updatedFiles : contentFiles, MarkdownFiles, IsNewVersion, RetainFolderStructureOverride); + var handle = pmExtension.PackageManagerClient.PublishAsync(Package, RetainFolderStructureOverride ? updatedFiles : contentFiles, MarkdownFiles, IsNewVersion, CurrentPackageRootDirectories, RetainFolderStructureOverride); // start upload Uploading = true; @@ -2365,11 +2362,7 @@ private void PublishLocally() var remapper = new CustomNodePathRemapper(DynamoViewModel.Model.CustomNodeManager, DynamoModel.IsTestMode); var builder = new PackageDirectoryBuilder(new MutatingFileSystem(), remapper); - if (string.IsNullOrEmpty(Package.RootDirectory)) - { - Package.RootDirectory = CurrentPackageDirectory; - } - builder.BuildRetainDirectory(Package, publishPath, updatedFiles, MarkdownFiles); + builder.BuildRetainDirectory(Package, publishPath, CurrentPackageRootDirectories, updatedFiles, MarkdownFiles); UploadState = PackageUploadHandle.State.Uploaded; } else @@ -2770,11 +2763,11 @@ internal PackageItemRootViewModel GetExistingRootItemViewModel(string publishPat { if (!PackageContents.Any()) return null; if (PackageContents.Count(x => x.DependencyType.Equals(DependencyType.Folder)) == 1) { - // If there is only one root item, nest it under the new root package folder + // If there is only one root item, this root item becomes the new folder var item = PackageContents.First(x => x.DependencyType.Equals(DependencyType.Folder)); item = new PackageItemRootViewModel(Path.Combine(publishPath, packageName)); - item.AddChildren(new List { PackageContents.First() } ); + item.AddChildren( PackageContents.First().ChildItems.ToList() ); return item; } @@ -2783,6 +2776,9 @@ internal PackageItemRootViewModel GetExistingRootItemViewModel(string publishPat var rootItem = new PackageItemRootViewModel(Path.Combine(publishPath, packageName)); foreach(var item in PackageContents) { + // Skip 'bare' custom nodes, they will be represented by their CustomNodePreview counterparts + if(item.DependencyType.Equals(DependencyType.CustomNode)) { continue; } + item.isChild = true; rootItem.AddChildren(item); } diff --git a/src/DynamoPackages/PackageDirectoryBuilder.cs b/src/DynamoPackages/PackageDirectoryBuilder.cs index 2b5873d7d31..5e1a69ec73e 100644 --- a/src/DynamoPackages/PackageDirectoryBuilder.cs +++ b/src/DynamoPackages/PackageDirectoryBuilder.cs @@ -11,7 +11,11 @@ namespace Dynamo.PackageManager public interface IPackageDirectoryBuilder { IDirectoryInfo BuildDirectory(Package packages, string packagesDirectory, IEnumerable files, IEnumerable markdownfiles); + IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> contentFiles, IEnumerable markdownFiles); + + [Obsolete] IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable> contentFiles, IEnumerable markdownFiles); + } /// @@ -69,12 +73,41 @@ public IDirectoryInfo BuildDirectory(Package package, string packagesDirectory, /// /// The package to be formed /// The parent directory (the published folder or the default packages directory) + /// All possible root folders for this collection of contentFiles /// The collection of files to be moved /// Separately provided markdown files /// - public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable> contentFiles, IEnumerable markdownFiles) + public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> contentFiles, IEnumerable markdownFiles) { + var rootPath = Path.Combine(packagesDirectory, package.Name); + var rootDir = fileSystem.TryCreateDirectory(rootPath); + package.RootDirectory = rootDir.FullName; + + var dyfFiles = new List(); + + RemoveUnselectedFiles(contentFiles.SelectMany(files => files).ToList(), rootDir); + CopyFilesIntoRetainedPackageDirectory(contentFiles, markdownFiles, roots, rootDir, out dyfFiles); + RemoveRetainDyfFiles(contentFiles.SelectMany(files => files).ToList(), dyfFiles); + RemapRetainCustomNodeFilePaths(contentFiles.SelectMany(files => files).ToList(), dyfFiles); + + WritePackageHeader(package, rootDir); + + return rootDir; + } + + /// + /// [Obsolete] Attempts to recreate the file/folder structure from an existing data + /// + /// The package to be formed + /// The parent directory (the published folder or the default packages directory) + /// The collection of files to be moved + /// Separately provided markdown files + /// + [Obsolete] + public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable> contentFiles, IEnumerable markdownFiles) + { + var rootPath = Path.Combine(packagesDirectory, package.Name); var rootDir = fileSystem.TryCreateDirectory(rootPath); var sourcePackageDir = package.RootDirectory; @@ -84,9 +117,9 @@ public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirec RemoveUnselectedFiles(contentFiles.SelectMany(files => files).ToList(), rootDir); CopyFilesIntoRetainedPackageDirectory(contentFiles, markdownFiles, sourcePackageDir, rootDir, out dyfFiles); - RemoveRetainDyfFiles(contentFiles.SelectMany(files => files).ToList(), dyfFiles); - + RemoveRetainDyfFiles(contentFiles.SelectMany(files => files).ToList(), dyfFiles); RemapRetainCustomNodeFilePaths(contentFiles.SelectMany(files => files).ToList(), dyfFiles); + WritePackageHeader(package, rootDir); return rootDir; @@ -114,8 +147,7 @@ private void RemapRetainCustomNodeFilePaths(IEnumerable filePaths, List< { foreach (var func in filePaths.Where(x => x.EndsWith(".dyf"))) { - //var remapLocation = dyfFiles.First(x => Path.GetDirectoryName(x).Equals(Path.GetDirectoryName(func))); - var remapLocation = dyfFiles.First(x => + var remapLocation = dyfFiles.FirstOrDefault(x => { var p1 = Path.GetFileName(Path.GetDirectoryName(x)); var f1 = Path.GetFileName(x); @@ -127,7 +159,15 @@ private void RemapRetainCustomNodeFilePaths(IEnumerable filePaths, List< return r1.Equals(r2); }); - pathRemapper.SetPath(func, remapLocation); + + // If no full path match is found, try to match based on filename only + if (remapLocation == null) + { + remapLocation = dyfFiles.FirstOrDefault(x => + Path.GetFileName(x).Equals(Path.GetFileName(func), StringComparison.OrdinalIgnoreCase)); + } + + pathRemapper.SetPath(func, remapLocation); } } @@ -221,6 +261,130 @@ private void WritePackageHeader(Package package, IDirectoryInfo rootDir) fileSystem.WriteAllText(headerPath, pkgHeaderStr); } + /// + /// Copies content and markdown files into a retained package directory, normalizing paths and maintaining directory structure. + /// We use the 'roots' collection as a guide to the folders we expect to find in the root directory of the package. + /// Based on that, we either want to nest inside a new package folder (if more than 2 root folders are found) + /// or if just 1 root folder is found, then use that as the new package folder + /// + /// A collection of collections of content file paths to be copied. + /// A collection of markdown file paths to be copied. + /// A collection of root directories to normalize file paths against. + /// The root directory into which the files will be copied. + /// An output list of paths to .dyf files that were copied. + internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable> contentFiles, + IEnumerable markdownFiles, + IEnumerable roots, + IDirectoryInfo rootDir, + out List dyfFiles) + { + dyfFiles = new List(); + + // Normalize roots to ensure consistent comparison + var normalizedRoots = roots.Select(r => Path.GetFullPath(r)).ToList(); + + // Determine if all files are under a single folder + var distinctFolders = contentFiles.SelectMany(f => f) + .Where(f => f != null) + .Select(f => f.Substring(normalizedRoots.First().Length).TrimStart(new char[] { '/', '\\' })) + .Select(rp => rp.Split(new char[] { '/', '\\' })[0]) + .Distinct() + .Count(); + + foreach (var files in contentFiles) + { + foreach (var file in files.Where(x => x != null)) + { + // If the file doesn't actually exist, don't copy it + if (!fileSystem.FileExists(file)) + { + continue; + } + + string relativePath = ""; + + foreach (var root in normalizedRoots) + { + var normalizedFile = Path.GetFullPath(file); + if (normalizedFile.StartsWith(root, StringComparison.OrdinalIgnoreCase)) + { + relativePath = normalizedFile.Substring(root.Length); + // Trim leading directory separators + relativePath = relativePath.TrimStart(new char[] { '/', '\\' }); + } + } + + // If we have more than 1 root, then we need to nest into a new root folder + // If we don't, and in order to preserve 1-to-1 folder structure, we remove the original root and replace with the package name + if (normalizedRoots.Count() == 1 && distinctFolders == 1) + { + relativePath = RemoveFirstFolder(relativePath); + } + + // Ensure the relative path starts with a directory separator. + if (!string.IsNullOrEmpty(relativePath) && relativePath[0] != Path.DirectorySeparatorChar) + { + relativePath = Path.DirectorySeparatorChar + relativePath; + } + + var destPath = Path.Combine(rootDir.FullName, relativePath.TrimStart('\\')); + + if (fileSystem.FileExists(destPath)) + { + fileSystem.DeleteFile(destPath); + } + + if (!Directory.Exists(Path.GetDirectoryName(destPath))) + { + Directory.CreateDirectory(Path.GetDirectoryName(destPath)); + } + + fileSystem.CopyFile(file, destPath); + + if (file.ToLower().EndsWith(".dyf")) + { + dyfFiles.Add(destPath); + } + } + } + + + // All files under Markdown directory do not apply to the rule above, + // because they may fall into extra folder instead of docs folder, + // currently there is on obvious way to filter them properly only based on path string. + var docDirPath = Path.Combine(rootDir.FullName, DocumentationDirectoryName); + foreach (var file in markdownFiles.Where(x => x != null)) + { + var destPath = Path.Combine(docDirPath, Path.GetFileName(file)); + + if (fileSystem.FileExists(destPath)) + { + fileSystem.DeleteFile(destPath); + } + + fileSystem.CopyFile(file, destPath); + } + } + + private static string RemoveFirstFolder(string path) + { + var parts = path.Split(new string[] { "\\" }, StringSplitOptions.RemoveEmptyEntries); + + if (parts.Length > 1) return "\\" + String.Join("\\", parts, 1, parts.Length - 1); + + return "\\" + parts[0]; + } + + /// + /// [Obsolete] Copies content and markdown files into a retained package directory, + /// maintaining directory structure and handling specific cases like .dyf files and markdown files. + /// + /// A collection of collections of content file paths to be copied. + /// A collection of markdown file paths to be copied. + /// The source directory of the package files. + /// The root directory into which the files will be copied. + /// An output list of paths to .dyf files that were copied. + [Obsolete] internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable> contentFiles, IEnumerable markdownFiles, string sourcePackageDir, IDirectoryInfo rootDir, out List dyfFiles) { dyfFiles = new List(); @@ -260,7 +424,7 @@ internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable + /// Copies files into appropriate directories within a package, determining the target directory based on file type and path. + /// + /// A collection of file paths to be copied. + /// A collection of markdown file paths to be copied. + /// The directory for .dyf files. + /// The directory for binary files (.dll and related). + /// The directory for extra files that do not fit other categories. + /// The directory for documentation files. internal void CopyFilesIntoPackageDirectory(IEnumerable files, IEnumerable markdownFiles, IDirectoryInfo dyfDir, IDirectoryInfo binDir, IDirectoryInfo extraDir, IDirectoryInfo docDir) diff --git a/src/DynamoPackages/PackageManagerClient.cs b/src/DynamoPackages/PackageManagerClient.cs index 1afe669ecd0..943c96ea155 100644 --- a/src/DynamoPackages/PackageManagerClient.cs +++ b/src/DynamoPackages/PackageManagerClient.cs @@ -226,19 +226,32 @@ private bool ExecuteTermsOfUseCall(bool queryAcceptanceStatus) }, false); } - internal PackageUploadHandle PublishAsync(Package package, object files, IEnumerable markdownFiles, bool isNewVersion, bool retainFolderStructure) + /// + /// Asynchronously publishes a package along with associated files and markdown files. + /// We use the 'roots' collection as a guide to the folders we expect to find in the root directory of the package. + /// Based on that, we either want to nest inside a new package folder (if more than 2 root folders are found) + /// or if just 1 root folder is found, then use that as the new package folder + /// + /// The package to be published. + /// The files to be included in the package. + /// The markdown files to be included in the package. + /// Indicates if this is a new version of an existing package. + /// A collection of root directories to normalize file paths against. + /// Indicates whether to retain the original folder structure. + /// A Used to track the upload status. + internal PackageUploadHandle PublishAsync(Package package, object files, IEnumerable markdownFiles, bool isNewVersion, IEnumerable roots, bool retainFolderStructure) { var packageUploadHandle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(package)); Task.Factory.StartNew(() => { - Publish(package, files, markdownFiles, isNewVersion, packageUploadHandle, retainFolderStructure); + Publish(package, files, markdownFiles, isNewVersion, packageUploadHandle, roots, retainFolderStructure); }); return packageUploadHandle; } - internal void Publish(Package package, object files, IEnumerable markdownFiles, bool isNewVersion, PackageUploadHandle packageUploadHandle, bool retainFolderStructure = false) + internal void Publish(Package package, object files, IEnumerable markdownFiles, bool isNewVersion, PackageUploadHandle packageUploadHandle, IEnumerable roots, bool retainFolderStructure = false) { try { @@ -246,7 +259,7 @@ internal void Publish(Package package, object files, IEnumerable markdow if (isNewVersion) { var pkg = retainFolderStructure ? - uploadBuilder.NewPackageVersionRetainUpload(package, packageUploadDirectory, (IEnumerable>)files, markdownFiles, + uploadBuilder.NewPackageVersionRetainUpload(package, packageUploadDirectory, roots, (IEnumerable>)files, markdownFiles, packageUploadHandle) : uploadBuilder.NewPackageVersionUpload(package, packageUploadDirectory, (IEnumerable)files, markdownFiles, packageUploadHandle); @@ -256,7 +269,7 @@ internal void Publish(Package package, object files, IEnumerable markdow else { var pkg = retainFolderStructure ? - uploadBuilder.NewPackageRetainUpload(package, packageUploadDirectory, (IEnumerable>)files, markdownFiles, + uploadBuilder.NewPackageRetainUpload(package, packageUploadDirectory, roots, (IEnumerable>)files, markdownFiles, packageUploadHandle) : uploadBuilder.NewPackageUpload(package, packageUploadDirectory, (IEnumerable)files, markdownFiles, packageUploadHandle); diff --git a/src/DynamoPackages/PackageUploadBuilder.cs b/src/DynamoPackages/PackageUploadBuilder.cs index 390f1a9ae75..ac3cd37158b 100644 --- a/src/DynamoPackages/PackageUploadBuilder.cs +++ b/src/DynamoPackages/PackageUploadBuilder.cs @@ -12,13 +12,13 @@ public interface IPackageUploadBuilder PackageUpload NewPackageUpload(Package package, string packagesDirectory, IEnumerable files, IEnumerable markdownFiles, PackageUploadHandle handle); - PackageUpload NewPackageRetainUpload(Package package, string packagesDirectory, IEnumerable> files, IEnumerable markdownFiles, + PackageUpload NewPackageRetainUpload(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle); PackageVersionUpload NewPackageVersionUpload(Package package, string packagesDirectory, IEnumerable files, IEnumerable markdownFiles, PackageUploadHandle handle); - PackageVersionUpload NewPackageVersionRetainUpload(Package package, string packagesDirectory, + PackageVersionUpload NewPackageVersionRetainUpload(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle); } @@ -85,7 +85,6 @@ public PackageUpload NewPackageUpload(Package package, string packagesDirectory, /// /// Build a new package and upload retaining folder structure - /// TODO: Should that be a separate method or an override? Break API ok? /// /// /// @@ -94,6 +93,27 @@ public PackageUpload NewPackageUpload(Package package, string packagesDirectory, /// /// /// + public PackageUpload NewPackageRetainUpload(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle) + { + if (package == null) throw new ArgumentNullException("package"); + if (packagesDirectory == null) throw new ArgumentNullException("packagesDirectory"); + if (files == null) throw new ArgumentNullException("files"); + if (handle == null) throw new ArgumentNullException("handle"); + + return new PackageUpload(NewRequestBody(package), + BuildAndZip(package, packagesDirectory, roots, files, markdownFiles, handle).Name); + } + + /// + /// [Obsolete] Build a new package and upload retaining folder structure + /// + /// + /// + /// + /// + /// + /// + [Obsolete] public PackageUpload NewPackageRetainUpload(Package package, string packagesDirectory, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle) { if (package == null) throw new ArgumentNullException("package"); @@ -130,11 +150,34 @@ public PackageVersionUpload NewPackageVersionUpload(Package package, string pack /// /// /// + /// + /// + /// + /// + /// + /// + public PackageVersionUpload NewPackageVersionRetainUpload(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle) + { + if (package == null) throw new ArgumentNullException("package"); + if (packagesDirectory == null) throw new ArgumentNullException("packagesDirectory"); + if (files == null) throw new ArgumentNullException("files"); + if (handle == null) throw new ArgumentNullException("handle"); + if (roots == null) throw new ArgumentNullException("roots"); + + return new PackageVersionUpload(NewRequestBody(package), BuildAndZip(package, packagesDirectory, roots, files, markdownFiles, handle).Name); + } + + /// + /// [Obsolete] Build a new version of the package and upload retaining folder structure + /// + /// + /// /// /// /// /// /// + [Obsolete] public PackageVersionUpload NewPackageVersionRetainUpload(Package package, string packagesDirectory, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle) { if (package == null) throw new ArgumentNullException("package"); @@ -160,6 +203,18 @@ private IFileInfo BuildAndZip(Package package, string packagesDirectory, IEnumer return Zip(dir); } + private IFileInfo BuildAndZip(Package package, string packagesDirectory, IEnumerable roots, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle) + { + handle.UploadState = PackageUploadHandle.State.Copying; + + var dir = builder.BuildRetainDirectory(package, packagesDirectory, roots, files, markdownFiles); + + handle.UploadState = PackageUploadHandle.State.Compressing; + + return Zip(dir); + } + + [Obsolete] private IFileInfo BuildAndZip(Package package, string packagesDirectory, IEnumerable> files, IEnumerable markdownFiles, PackageUploadHandle handle) { handle.UploadState = PackageUploadHandle.State.Copying; @@ -171,6 +226,7 @@ private IFileInfo BuildAndZip(Package package, string packagesDirectory, IEnumer return Zip(dir); } + private IFileInfo Zip(IDirectoryInfo directory) { IFileInfo info; diff --git a/test/DynamoCoreWpfTests/CrashReportingTests.cs b/test/DynamoCoreWpfTests/CrashReportingTests.cs index 44578c0296e..16204a69b99 100644 --- a/test/DynamoCoreWpfTests/CrashReportingTests.cs +++ b/test/DynamoCoreWpfTests/CrashReportingTests.cs @@ -1,12 +1,11 @@ using System; using System.IO; -using System.Windows.Threading; +using System.Linq; using Dynamo.Models; using Dynamo.PackageManager; using Dynamo.Utilities; using Dynamo.ViewModels; using Dynamo.Wpf.Utilities; -using DynamoCoreWpfTests; using NUnit.Framework; namespace Dynamo.Tests @@ -152,7 +151,7 @@ public void NoLoadedPackages() //Gets package loader var packageLoader = CurrentDynamoModel.GetPackageManagerExtension()?.PackageLoader; Assert.IsNotNull(packageLoader); - Assert.IsEmpty(packageLoader.LocalPackages); + Assert.IsEmpty(packageLoader.LocalPackages, string.Join(", ", packageLoader.LocalPackages.Select(x => x.Name))); //Get packages data from null package loader var packagesData = Wpf.Utilities.CrashUtilities.PackagesToMakrdown(packageLoader); diff --git a/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs b/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs index 7e0a40446fe..1411f13ed6b 100644 --- a/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs +++ b/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs @@ -2074,7 +2074,7 @@ public void AssertGetExistingRootItemViewModelReturnsCorrectItem() var testFoldersCount = testRootItems.Count(x => x.DependencyType.Equals(DependencyType.Folder)); var testFilesCount = testRootItems.Count(x => !x.DependencyType.Equals(DependencyType.Folder)); - Assert.AreEqual(foldersCount, testFoldersCount - 1); + Assert.AreEqual(foldersCount, testFoldersCount); Assert.AreEqual(filesCount, testFilesCount); } @@ -2362,7 +2362,7 @@ public void AssertPreviewPackageRetainFolderStructureEqualsPublishLocalPackageRe // Assert Assert.AreEqual(createdFiles.Count(), previewFiles.Count()); - Assert.AreEqual(0, createdFolders.Count()); // When single root, no nested folders should be created + Assert.AreEqual(3, createdFolders.Count()); // Clean up Directory.Delete(publishPath, true); @@ -2427,9 +2427,14 @@ public void AssertPublishNewPackageVersion_SuccessfulForLoadedPackages() var allFiles = vm.BuildPackage(); Assert.IsNotNull(allFiles); + var updatedFiles = vm.UpdateFilesForRetainFolderStructure(allFiles); Assert.IsNotNull(updatedFiles); + var roots = vm.GetCommonPaths(allFiles.ToArray()); + Assert.IsNotNull(roots); + + var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(package)); var fs = new RecordedFileSystem((fn) => updatedFiles.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); @@ -2441,7 +2446,7 @@ public void AssertPublishNewPackageVersion_SuccessfulForLoadedPackages() // Assert Assert.DoesNotThrow(() => { - m.NewPackageVersionRetainUpload(package, publishPath, updatedFiles, Enumerable.Empty(), handle); + m.NewPackageVersionRetainUpload(package, publishPath, roots, updatedFiles, Enumerable.Empty(), handle); }); Assert.AreNotEqual(PackageUploadHandle.State.Error, handle.UploadState); diff --git a/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs b/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs index 15c71389dce..edc9dea6185 100644 --- a/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs +++ b/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs @@ -471,6 +471,24 @@ public void FindCommonPaths_MultipleRoots() } + [Test] + public void FindCommonPaths_MultipleRootsSingleCommonPath() + { + var vm = new PublishPackageViewModel(ViewModel); + var paths = new string[] + { + "C:\\Packages\\PackageTest\\Loc1\\Sub11\\test.docx", + "C:\\Packages\\PackageTest\\Loc2\\Sub21\\test2.docx", + "C:\\Packages\\PackageTest2\\Loc1\\test.dyn", + }; + + var commonPaths = vm.GetCommonPaths(paths); + + Assert.AreEqual(1, commonPaths.Count); + Assert.AreEqual("C:\\Packages", commonPaths[0]); + } + + [Test] public void FindCommonPaths_BaseRoot() { @@ -487,7 +505,6 @@ public void FindCommonPaths_BaseRoot() Assert.AreEqual("C:\\", commonPaths[0]); } - #endregion } diff --git a/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs b/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs index b5830036267..8e4aff826a3 100644 --- a/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs +++ b/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs @@ -47,8 +47,9 @@ public void BuildRetainPackageDirectory_DoesExpectedNumberOfOperations() var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); Assert.AreEqual(1, fs.DirectoriesCreated.Count()); Assert.AreEqual(2, fs.CopiedFiles.Count()); @@ -92,8 +93,9 @@ public void BuildRetainPackageDirectory_BuildsExpectedDirectories() var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); var rootDir = Path.Combine(pkgsDir, pkg.Name); @@ -133,9 +135,10 @@ public void BuildRetainPackageDirectory_FormsPackageHeader() var db = new PackageDirectoryBuilder(fs, pr.Object); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; // where the magic happens... - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); var rootDir = Path.Combine(pkgsDir, pkg.Name); @@ -192,8 +195,10 @@ public void BuildRetainPackageDirectory_RemapsCustomNodePaths() var db = new PackageDirectoryBuilder(fs, pr.Object); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + // where the magic happens... + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); var dyfDir1 = Path.Combine(pkgsDir, pkg.Name, Path.GetFileName(Path.GetDirectoryName(files[0].First())), Path.GetFileName(files[0].First())); var dyfDir2 = Path.Combine(pkgsDir, pkg.Name, Path.GetFileName(Path.GetDirectoryName(files[1].First())), Path.GetFileName(files[1].First())); @@ -244,8 +249,9 @@ public void BuildRetainPackageDirectory_UpdatesTheArgumentPackageWithNewDirector var db = new PackageDirectoryBuilder(fs, pr.Object); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); var rootDir = Path.Combine(pkgsDir, pkg.Name); @@ -290,8 +296,9 @@ public void BuildPackageRetainDirectory_CopiesTheOriginalFiles() var db = new PackageDirectoryBuilder(fs, pr.Object); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); var dyfDir1 = Path.Combine(pkgsDir, pkg.Name, Path.GetFileName(Path.GetDirectoryName(files[0].First()))); var dyfDir2 = Path.Combine(pkgsDir, pkg.Name, Path.GetFileName(Path.GetDirectoryName(files[1].First()))); @@ -343,8 +350,9 @@ public void BuildRetainPackageDirectory_CopiesMarkDownFiles() var db = new PackageDirectoryBuilder(fs, pr.Object); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, markdownFiles); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, markdownFiles); var mdDir = Path.Combine(pkgsDir, pkg.Name, PackageDirectoryBuilder.DocumentationDirectoryName); @@ -394,8 +402,9 @@ public void BuildRetainPackageDirectory_DeletesTheOriginalFiles() var db = new PackageDirectoryBuilder(fs, pr.Object); var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); // The original files are moved @@ -455,7 +464,9 @@ public void BuildRetainPackageDirectory_DoesNotIncludeUnselectedFiles() var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); var pkgsDir = @"C:\dynamopackages"; - db.BuildRetainDirectory(pkg, pkgsDir, files, Enumerable.Empty()); + var roots = new List { @"C:\pkg\" }; + + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); Assert.AreEqual(1, fs.DirectoriesCreated.Count()); @@ -465,6 +476,48 @@ public void BuildRetainPackageDirectory_DoesNotIncludeUnselectedFiles() Assert.AreEqual(1, fs.NewFilesWritten.Count()); } + + [Test] + public void BuildRetainPackageDirectory_CreatesCorrectSingleFolderStructure() + { + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder1\subfolder1\file2.dyf" } }; + var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); + var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); + var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); + + var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; + + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); + + var rootDir = Path.Combine(pkgsDir, pkg.Name); + + Assert.IsTrue(fs.CopiedFiles.Any(x => x.Item2.Equals(@"C:\dynamopackages\Foo\file1.dyf"))); + Assert.IsTrue(fs.CopiedFiles.Any(x => x.Item2.Equals(@"C:\dynamopackages\Foo\subfolder1\file2.dyf"))); + } + + + + [Test] + public void BuildRetainPackageDirectory_CreatesCorrectMultipleFolderStructure() + { + var files = new List>() { new[] { @"C:\pkg\PackageTest\loc1\sub1\file1.dyf" }, new[] { @"C:\pkg\PackageTest2\loc1\file2.dyf" } }; + var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); + var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); + var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); + + var pkgsDir = @"C:\dynamopackages"; + var roots = new List { @"C:\pkg\" }; + + db.BuildRetainDirectory(pkg, pkgsDir, roots, files, Enumerable.Empty()); + + var rootDir = Path.Combine(pkgsDir, pkg.Name); + + Assert.IsTrue(fs.CopiedFiles.Any(x => x.Item2.Equals(@"C:\dynamopackages\Foo\PackageTest\loc1\sub1\file1.dyf"))); + Assert.IsTrue(fs.CopiedFiles.Any(x => x.Item2.Equals(@"C:\dynamopackages\Foo\PackageTest2\loc1\file2.dyf"))); + } + + #endregion #region CopyFilesIntoPackageDirectory diff --git a/test/Libraries/PackageManagerTests/PackageManagerClientTests.cs b/test/Libraries/PackageManagerTests/PackageManagerClientTests.cs index 9667158d975..0e4b77706c9 100644 --- a/test/Libraries/PackageManagerTests/PackageManagerClientTests.cs +++ b/test/Libraries/PackageManagerTests/PackageManagerClientTests.cs @@ -327,7 +327,7 @@ public void Publish_SetsHandleToDoneWhenNewPackagePublishSucceeds() var pkg = new Package("", "Package", "0.1.0", "MIT"); var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); - pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), false, handle); + pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), false, handle, Enumerable.Empty()); Assert.AreEqual(PackageUploadHandle.State.Uploaded, handle.UploadState); } @@ -347,7 +347,7 @@ public void Publish_SetsHandleToDoneWhenNewPackageVersionPublishSucceeds() var pkg = new Package("", "Package", "0.1.0", "MIT"); var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); - pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), false, handle); + pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), false, handle, Enumerable.Empty()); Assert.AreEqual(PackageUploadHandle.State.Uploaded, handle.UploadState); } @@ -363,7 +363,7 @@ public void Publish_SetsErrorStatusWhenRequestThrowsAnException() var pkg = new Package("", "Package", "0.1.0", "MIT"); var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); - pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), false, handle); + pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), false, handle, Enumerable.Empty()); Assert.AreEqual(PackageUploadHandle.State.Error, handle.UploadState); } @@ -382,7 +382,7 @@ public void Publish_SetsErrorStatusWhenResponseIsNull() var pkg = new Package("", "Package", "0.1.0", "MIT"); var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); - pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), true, handle); + pc.Publish(pkg, Enumerable.Empty(), Enumerable.Empty(), true, handle, Enumerable.Empty()); Assert.AreEqual(PackageUploadHandle.State.Error, handle.UploadState); } @@ -409,7 +409,7 @@ public void PublishRetain_SetsHandleToDoneWhenNewPackagePublishSucceeds() var listOfEmptyEnumerables = Enumerable.Range(1, 5) .Select(_ => Enumerable.Empty()); - pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), false, handle, true); + pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), false, handle, Enumerable.Empty(), true); Assert.AreEqual(PackageUploadHandle.State.Uploaded, handle.UploadState); } @@ -431,7 +431,7 @@ public void PublishRetain_SetsHandleToDoneWhenNewPackageVersionPublishSucceeds() var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); var listOfEmptyEnumerables = Enumerable.Range(1, 5) .Select(_ => Enumerable.Empty()); - pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), false, handle, true); + pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), false, handle, Enumerable.Empty(), true); Assert.AreEqual(PackageUploadHandle.State.Uploaded, handle.UploadState); } @@ -449,7 +449,7 @@ public void PublishRetain_SetsErrorStatusWhenRequestThrowsAnException() var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); var listOfEmptyEnumerables = Enumerable.Range(1, 5) .Select(_ => Enumerable.Empty()); - pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), false, handle, true); + pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), false, handle, Enumerable.Empty(), true); Assert.AreEqual(PackageUploadHandle.State.Error, handle.UploadState); } @@ -470,7 +470,7 @@ public void PublishRetain_SetsErrorStatusWhenResponseIsNull() var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); var listOfEmptyEnumerables = Enumerable.Range(1, 5) .Select(_ => Enumerable.Empty()); - pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), true, handle, true); + pc.Publish(pkg, listOfEmptyEnumerables, Enumerable.Empty(), true, handle, Enumerable.Empty(), true); Assert.AreEqual(PackageUploadHandle.State.Error, handle.UploadState); } diff --git a/test/Libraries/PackageManagerTests/PackageUploadBuilderTests.cs b/test/Libraries/PackageManagerTests/PackageUploadBuilderTests.cs index fdc538869f3..9b6fcc00fc2 100644 --- a/test/Libraries/PackageManagerTests/PackageUploadBuilderTests.cs +++ b/test/Libraries/PackageManagerTests/PackageUploadBuilderTests.cs @@ -44,7 +44,7 @@ private IPackageUploadBuilder BigPackageUploadRetainBuilderMock() zipper.Setup((x) => x.Zip(It.IsAny())).Returns(bigzip.Object); var pdb = new Mock(); - pdb.Setup(x => x.BuildRetainDirectory(It.IsAny(), It.IsAny(), It.IsAny>>(), It.IsAny>())) + pdb.Setup(x => x.BuildRetainDirectory(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>>(), It.IsAny>())) .Returns((new Mock()).Object); // this package upload builder will try to return a zip that is too big @@ -191,7 +191,7 @@ public void NewPackageUploadRetain_ThrowsExceptionWhenPackageIsTooBig() var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); - Assert.Throws(() => pub.NewPackageRetainUpload(pkg, pkgsDir, files, Enumerable.Empty(), handle)); + Assert.Throws(() => pub.NewPackageRetainUpload(pkg, pkgsDir, Enumerable.Empty(), files, Enumerable.Empty(), handle)); } [Test] @@ -204,10 +204,10 @@ public void NewPackageVersionUploadRetain_ThrowsForNullArguments() var m = new PackageUploadBuilder(MockMaker.Empty(), MockMaker.Empty()); - Assert.Throws(() => m.NewPackageRetainUpload(null, pkgsDir, files, Enumerable.Empty(), handle)); - Assert.Throws(() => m.NewPackageRetainUpload(pkg, null, files, Enumerable.Empty(), handle)); - Assert.Throws(() => m.NewPackageRetainUpload(pkg, pkgsDir, null, Enumerable.Empty(), handle)); - Assert.Throws(() => m.NewPackageRetainUpload(pkg, pkgsDir, files, Enumerable.Empty(), null)); + Assert.Throws(() => m.NewPackageRetainUpload(null, pkgsDir, Enumerable.Empty(), files, Enumerable.Empty(), handle)); + Assert.Throws(() => m.NewPackageRetainUpload(pkg, null, Enumerable.Empty(), files, Enumerable.Empty(), handle)); + Assert.Throws(() => m.NewPackageRetainUpload(pkg, pkgsDir, Enumerable.Empty(), null, Enumerable.Empty(), handle)); + Assert.Throws(() => m.NewPackageRetainUpload(pkg, pkgsDir, Enumerable.Empty(), files, Enumerable.Empty(), null)); } #endregion @@ -259,7 +259,7 @@ public void NewPackageVersionUploadRetain_ThrowsExceptionWhenPackageIsTooBig() var handle = new PackageUploadHandle(PackageUploadBuilder.NewRequestBody(pkg)); - Assert.Throws(() => pub.NewPackageVersionRetainUpload(pkg, pkgsDir, files, Enumerable.Empty(), handle)); + Assert.Throws(() => pub.NewPackageVersionRetainUpload(pkg, pkgsDir, Enumerable.Empty(), files, Enumerable.Empty(), handle)); } [Test] @@ -272,10 +272,10 @@ public void NewPackageUploadRetain_ThrowsForNullArguments() var m = new PackageUploadBuilder(MockMaker.Empty(), MockMaker.Empty()); - Assert.Throws(() => m.NewPackageVersionRetainUpload(null, pkgsDir, files, Enumerable.Empty(), handle)); - Assert.Throws(() => m.NewPackageVersionRetainUpload(pkg, null, files, Enumerable.Empty(), handle)); - Assert.Throws(() => m.NewPackageVersionRetainUpload(pkg, pkgsDir, null, Enumerable.Empty(), handle)); - Assert.Throws(() => m.NewPackageVersionRetainUpload(pkg, pkgsDir, files, Enumerable.Empty(), null)); + Assert.Throws(() => m.NewPackageVersionRetainUpload(null, pkgsDir, Enumerable.Empty(), files, Enumerable.Empty(), handle)); + Assert.Throws(() => m.NewPackageVersionRetainUpload(pkg, null, Enumerable.Empty(), files, Enumerable.Empty(), handle)); + Assert.Throws(() => m.NewPackageVersionRetainUpload(pkg, pkgsDir, Enumerable.Empty(), null, Enumerable.Empty(), handle)); + Assert.Throws(() => m.NewPackageVersionRetainUpload(pkg, pkgsDir, Enumerable.Empty(), files, Enumerable.Empty(), null)); } #endregion