Skip to content

Commit

Permalink
DYN-6901 Pm - publish process improvements (#15314)
Browse files Browse the repository at this point in the history
  • Loading branch information
dnenov committed Jul 3, 2024
1 parent 53ec381 commit 851839e
Show file tree
Hide file tree
Showing 7 changed files with 354 additions and 52 deletions.
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 CopyFilesIntoRetainedPackageDirectory(IEnumerable<IEnumerable<stri
{
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

0 comments on commit 851839e

Please sign in to comment.