Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DYN-6901 Pm - publish process improvements #15314

Merged
merged 11 commits into from
Jul 3, 2024
130 changes: 104 additions & 26 deletions src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Forms;
Expand Down Expand Up @@ -1052,7 +1051,12 @@ private bool IsDuplicateFile(PackageItemRootViewModel item1, PackageItemRootView
}
}

private List<PackageItemRootViewModel> BindParentToChild(Dictionary<string, PackageItemRootViewModel> items)
/// <summary>
/// Attempts to recreate the file/folder content structure
/// </summary>
/// <param name="items">A dictionary of the content items</param>
/// <returns></returns>
internal List<PackageItemRootViewModel> BindParentToChild(Dictionary<string, PackageItemRootViewModel> items)
{
foreach (var parent in items)
{
Expand Down Expand Up @@ -1082,25 +1086,61 @@ private List<PackageItemRootViewModel> GetRootItems(Dictionary<string, PackageIt
{
var rootItems = items.Values.Where(x => !x.isChild).ToList();
if (!rootItems.Any()) return rootItems;
var packageSourceDir = CurrentPackageDirectory ??= GetLongestCommonPrefix(items.Keys.ToArray());

var root = new PackageItemRootViewModel(packageSourceDir);
var updatedItems = new List<PackageItemRootViewModel>();
//check each root item and create any missing connections
var roots = new List<PackageItemRootViewModel>();

if (CurrentPackageDirectory != null)
{
roots.Add(new PackageItemRootViewModel(CurrentPackageDirectory));
}
else
{
var commonPaths = GetCommonPaths(items.Keys.ToArray());
if (commonPaths == null) return null;

// 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)
{
bool itemAssigned = false;
var itemDir = new DirectoryInfo(item.DirectoryName);
if (!itemDir.Parent.FullName.Equals(packageSourceDir))

foreach (var root in roots)
{
root.AddChildRecursively(item);
var rootDir = new DirectoryInfo(root.DirectoryName);

if (itemDir.FullName.StartsWith(rootDir.FullName, StringComparison.OrdinalIgnoreCase))
{
if (itemDir.Parent.FullName.Equals(rootDir.FullName))
{
root.ChildItems.Add(item);
}
else
{
root.AddChildRecursively(item);
}
itemAssigned = true;
break;
}
}
else

// If the item does not belong to any existing root, create a new root for it
if (!itemAssigned)
{
root.ChildItems.Add(item);
var newRoot = new PackageItemRootViewModel(item.DirectoryName);
newRoot.ChildItems.Add(item);
roots.Add(newRoot);
}
}
return root.ChildItems.ToList();
}

// Collect all child items from all roots
var allChildItems = roots.SelectMany(r => r.ChildItems).ToList();

return allChildItems;
}

/// <summary>
/// Test if path2 is subpath of path1
Expand Down Expand Up @@ -1132,22 +1172,56 @@ internal bool IsSubPathOfDeep(PackageItemRootViewModel path1, PackageItemRootVie
/// <summary>
/// Utility method to get the common file path, this may fail for files with the same partial name.
/// </summary>
/// <param name="s">A collection of filepaths</param>
/// <param name="paths">A collection of file paths</param>
/// <returns></returns>
internal string GetLongestCommonPrefix(string[] s)
internal List<string> GetCommonPaths(string[] paths)
{
int k = s[0].Length;
for (int i = 1; i < s.Length; i++)
if (paths == null || paths.Length == 0)
return new List<string>();

// Group paths by their root (drive letter)
var groupedPaths = paths.GroupBy(p => Path.GetPathRoot(p)).ToList();
List<string> commonPaths = new List<string>();

foreach (var group in groupedPaths)
{
k = Math.Min(k, s[i].Length);
for (int j = 0; j < k; j++)
if (s[i][j] != s[0][j])
var pathArray = group.ToArray();
if (pathArray.Length == 1)
{
commonPaths.Add(Path.GetDirectoryName(pathArray[0]));
continue;
}

var k = pathArray[0].Length;
for (var i = 1; i < pathArray.Length; i++)
{
k = Math.Min(k, pathArray[i].Length);
for (var j = 0; j < k; j++)
{
k = j;
break;
if (pathArray[i][j] != pathArray[0][j])
{
k = j;
break;
}
}
}

var commonPrefix = pathArray[0].Substring(0, k);
var commonDir = Path.GetDirectoryName(commonPrefix);

if (string.IsNullOrEmpty(commonDir))
{
// Special case for the root directory
commonDir = Path.GetPathRoot(commonPrefix);
}

if (!string.IsNullOrEmpty(commonDir))
{
commonPaths.Add(commonDir);
}
}
return Path.GetDirectoryName(s[0].Substring(0, k));

return commonPaths.Distinct().ToList();
}

/// <summary>
Expand Down Expand Up @@ -1897,7 +1971,7 @@ private void SelectDirectoryAndAddFilesRecursively()
}

/// <summary>
/// Combines adding files from single file prompt and files in folders propt
/// Combines adding files from single file prompt and files in folders prompt
/// </summary>
/// <param name="filePaths"></param>
internal void AddAllFilesAfterSelection(List<string> filePaths, string rootFolder = null)
Expand Down Expand Up @@ -2033,7 +2107,10 @@ private void RemoveSingleItem(PackageItemRootViewModel vm, DependencyType fileTy
CustomNodeDefinitions.Remove(CustomNodeDefinitions
.First(x => x.DisplayName == fileName));

CustomDyfFilepaths.Remove(fileName + ".dyf");
var keyToRemove = CustomDyfFilepaths.Keys
.FirstOrDefault(k => Path.GetFileNameWithoutExtension(k) == fileName);

if(keyToRemove != null) CustomDyfFilepaths.Remove(keyToRemove);
}
else
{
Expand Down Expand Up @@ -2665,6 +2742,7 @@ private void PreviewPackageBuild()
}
}

// Removes duplicate file names, retaining only the first encounter file path for each unique file name
files = files.GroupBy(file => Path.GetFileName(file), StringComparer.OrdinalIgnoreCase)
.Select(group => group.First())
.ToList();
Expand Down Expand Up @@ -2735,12 +2813,12 @@ internal PackageItemRootViewModel GetPreBuildRootItemViewModel(string publishPat
var doc = new PackageItemRootViewModel(new FileInfo(Path.Combine(docDir, fileName)));
docItemPreview.AddChildRecursively(doc);
}
else if (file.EndsWith(".dyf"))
else if (file.ToLower().EndsWith(".dyf"))
{
var dyfPreview = new PackageItemRootViewModel(fileName, Path.Combine(dyfDir, fileName));
dyfItemPreview.AddChildRecursively(dyfPreview);
}
else if (file.EndsWith(".dll") || PackageDirectoryBuilder.IsXmlDocFile(file, files) || PackageDirectoryBuilder.IsDynamoCustomizationFile(file, files))
else if (file.ToLower().EndsWith(".dll") || PackageDirectoryBuilder.IsXmlDocFile(file, files) || PackageDirectoryBuilder.IsDynamoCustomizationFile(file, files))
{
// Assemblies carry the information if they are NodeLibrary or not
if(Assemblies.Any(x => x.Name.Equals(Path.GetFileNameWithoutExtension(fileName))))
Expand Down
21 changes: 15 additions & 6 deletions src/DynamoPackages/PackageDirectoryBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ public IDirectoryInfo BuildDirectory(Package package, string packagesDirectory,
return rootDir;
}

/// <summary>
/// Attempts to recreate the file/folder structure from an existing data
/// </summary>
/// <param name="package">The package to be formed</param>
/// <param name="packagesDirectory">The parent directory (the published folder or the default packages directory)</param>
/// <param name="contentFiles">The collection of files to be moved</param>
/// <param name="markdownFiles">Separately provided markdown files</param>
/// <returns></returns>
public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirectory, IEnumerable<IEnumerable<string>> contentFiles, IEnumerable<string> markdownFiles)
{

Expand Down Expand Up @@ -127,7 +135,7 @@ private void RemapRetainCustomNodeFilePaths(IEnumerable<string> filePaths, List<
private void RemoveRetainDyfFiles(IEnumerable<string> filePaths, List<string> dyfFiles)
{
var dyfsToRemove = filePaths
.Where(x => x.EndsWith(".dyf") && fileSystem.FileExists(x) && Path.GetDirectoryName(x) != Path.GetDirectoryName(dyfFiles.First(f => Path.GetFileName(f).Equals(Path.GetFileName(x)))));
.Where(x => x.ToLower().EndsWith(".dyf") && fileSystem.FileExists(x) && Path.GetDirectoryName(x) != Path.GetDirectoryName(dyfFiles.First(f => Path.GetFileName(f).Equals(Path.GetFileName(x)))));

foreach (var dyf in dyfsToRemove)
{
Expand All @@ -138,7 +146,7 @@ private void RemoveRetainDyfFiles(IEnumerable<string> filePaths, List<string> dy
private void RemoveDyfFiles(IEnumerable<string> filePaths, IDirectoryInfo dyfDir)
{
var dyfsToRemove = filePaths
.Where(x => x.EndsWith(".dyf") && fileSystem.FileExists(x) && Path.GetDirectoryName(x) != dyfDir.FullName);
.Where(x => x.ToLower().EndsWith(".dyf") && fileSystem.FileExists(x) && Path.GetDirectoryName(x) != dyfDir.FullName);

foreach (var dyf in dyfsToRemove)
{
Expand Down Expand Up @@ -227,7 +235,8 @@ internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable<IEnumerable<stri
continue;
}

var relativePath = file.Substring(sourcePackageDir.Length);
// TODO: This will be properly fixed in the next PR
var relativePath = sourcePackageDir != null ? file.Substring(sourcePackageDir.Length) : Path.GetFileName(file);

// Ensure the relative path starts with a directory separator.
if (!string.IsNullOrEmpty(relativePath) && relativePath[0] != Path.DirectorySeparatorChar)
Expand Down Expand Up @@ -256,7 +265,7 @@ internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable<IEnumerable<stri

fileSystem.CopyFile(file, destPath);

if (file.EndsWith(".dyf"))
if (file.ToLower().EndsWith(".dyf"))
{
dyfFiles.Add(destPath);
}
Expand Down Expand Up @@ -304,11 +313,11 @@ internal void CopyFilesIntoPackageDirectory(IEnumerable<string> files, IEnumerab
{
targetFolder = docDirPath;
}
else if (file.EndsWith(".dyf"))
else if (file.ToLower().EndsWith(".dyf"))
{
targetFolder = dyfDirPath;
}
else if (file.EndsWith(".dll") || IsXmlDocFile(file, files) || IsDynamoCustomizationFile(file, files))
else if (file.ToLower().EndsWith(".dll") || IsXmlDocFile(file, files) || IsDynamoCustomizationFile(file, files))
{
targetFolder = binDirPath;
}
Expand Down
10 changes: 5 additions & 5 deletions test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,7 @@ public void CanRemoveAllDependencyTypes()
// This makes sense as we don't want to try to establish 'common parent' for folders that maybe too far apart in a tree structure
rootFolder = vm.PackageContents.Where(x => x.DependencyType.Equals(DependencyType.Folder));
Assert.AreEqual(1, rootFolder.Count());
Assert.AreEqual(4, PackageItemRootViewModel.GetFiles(rootFolder.First()).Count());
Assert.AreEqual(3, PackageItemRootViewModel.GetFiles(rootFolder.First()).Count()); // the 'doc' folder + the 2 files inside of it

Assert.DoesNotThrow(() => vm.RemoveItemCommand.Execute(rootFolder.First()));
Assert.IsFalse(vm.PackageContents.Any());
Expand Down Expand Up @@ -2321,8 +2321,8 @@ public void AssertPreviewPackageRetainFolderStructureEqualsPublishLocalPackageRe
var createdFolders = Directory.GetDirectories(publishPath, "*", SearchOption.AllDirectories).ToList();

// Assert
Assert.AreEqual(createdFiles.Count(), previewFiles.Count() + 1);
Assert.AreEqual(1, createdFolders.Count(), previewFolders.Count()); // One subfolder was created
Assert.AreEqual(createdFiles.Count(), previewFiles.Count());
Assert.AreEqual(0, createdFolders.Count()); // When single root, no nested folders should be created

// Clean up
Directory.Delete(publishPath, true);
Expand Down Expand Up @@ -2361,8 +2361,8 @@ public void AssertPreviewPackageRetainFolderStructureEqualsPublishLocalPackageRe
var createdFolders = Directory.GetDirectories(publishPath, "*", SearchOption.AllDirectories).ToList();

// Assert
Assert.AreEqual(createdFiles.Count(), previewFiles.Count() + 1);
Assert.AreEqual(1, createdFolders.Count(), previewFolders.Count()); // One subfolder was created
Assert.AreEqual(createdFiles.Count(), previewFiles.Count());
Assert.AreEqual(0, createdFolders.Count()); // When single root, no nested folders should be created

// Clean up
Directory.Delete(publishPath, true);
Expand Down
Loading
Loading