Skip to content

Commit

Permalink
[PTAL] [WIP] DYN-1662: As a dynamo dev, I want to serialize what pack…
Browse files Browse the repository at this point in the history
…ages are needed in a graph (#9723)

* Add Extensions block to json

* Serialize package manager data to new Extensions block

* Added IPackage interface

* Added IPackage interface

* Added PackageDependencies property to workspace model

* Added comments

* Unsubscribe from workspace on dispose

* Simplify CollectingAssembliesUsed

* assemblyPackageDict uses AssemblyName objects instead of strings. Rename CollectingPackageDependencies -> CollectingLocalPackages.

* NodeLibraries should be internal, not private

* assemblyPackageDict uses AssemblyName.FullName

* Use set for packageDependencies to avoid duplicates

* Add some comments to assembly collection

* AssemblyNames summary

* Adds PackageDependency serialization support for custom nodes from packages

* Rename GetCustomNodesPackagesFromGuids

* Rename GetCustomNodesPackagesFromGuids

* Add new PackageInfo class to replace IPackage for serialization

* Remove IPackage

* Move assembly name matching logic to PackageManager in order to remove AssemblyNames property from PackageInfo

* Remove unnecessary

* Fix AssemblyNames error

* Null check for PackageInfo converter

* Add obsolete attribute to events that should only be used by package manager

* Use InternalsVisibleTo to ensure only PM extension can subscribe to package dependency events

* Serialize IDs of nodes that are dependent on each package

* Update package manager dictionary logic for package load and remove events

* Fix Guid serialization

* Add comment to InternalsVisibleTo

* Name changes to make referencedAssembly use more clear

* Add comments to Assembly collection and make more efficient

* Comment added

* Remove unnecessary ref

* Removed Unecessary ref

* Comment fixes

* Rename PackageInfo -> PackageDependencyInfo

* Use Version type for PackageDependencyInfo Version property

* Rename Dependents -> Nodes

* Move GetAssembliesReferencedByNodes

* Added PackageDependency deserialization

* Simplify if statement

* Improve PackageDependencies update

* PackageDependency deserialization null check

* one line code improvements

* IsNodeLibrary check

* Remove unnecessary Any check

* Add unsuccessful PackageDependencyInfo serialization log

* Log message when node libraries or custom nodes are loaded by multiple packages

* Improved RemovedNodes handling

* Simplify descriptor lookup

* Update comments

* Store list of packages per assembly

* Store list of packages per custom node id

* Unsubscribe CurrentWorkspaceChanged

* lock packageDependencies

* Add NodePackageDictionary and CustomNodePackageDictionary null check

* Move assembly collection to WorkspaceModel because LibraryServices no longer required

* Remove white space

* Add "PackageDependencies" item to test .dyn

* Remove PackageDependencyInfo FullName property

* Throw exception for illegal subscribers to PackageDependency events
  • Loading branch information
scottmitchell authored Jun 3, 2019
1 parent b2e585a commit f6f43e2
Show file tree
Hide file tree
Showing 8 changed files with 544 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/DynamoCore/DynamoCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ limitations under the License.
<Compile Include="Engine\Profiling\ProfilingSession.cs" />
<Compile Include="Engine\ShortestQualifiedNameReplacer.cs" />
<Compile Include="Exceptions\LibraryLoadFailedException.cs" />
<Compile Include="Graph\Workspaces\PackageDependencyInfo.cs" />
<Compile Include="Graph\Nodes\NodeOutputData.cs" />
<Compile Include="Graph\Nodes\NodeInputData.cs" />
<Compile Include="Graph\Workspaces\LayoutExtensions.cs" />
Expand Down
102 changes: 102 additions & 0 deletions src/DynamoCore/Graph/Workspaces/PackageDependencyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Dynamo.Graph.Workspaces
{
/// <summary>
/// Class containing info about a Dynamo package.
/// Used for serialization.
/// </summary>
internal class PackageDependencyInfo
{
/// <summary>
/// Name of the package
/// </summary>
internal string Name { get; set; }

/// <summary>
/// Version of the package
/// </summary>
internal Version Version { get; set; }

/// <summary>
/// Guids of nodes in the workspace that are dependent on this package
/// </summary>
internal HashSet<Guid> Nodes
{
get { return nodes; }
}
private HashSet<Guid> nodes;

/// <summary>
/// Create a package info object from the package name and version
/// </summary>
/// <param name="name"></param>
/// <param name="version"></param>
internal PackageDependencyInfo(string name, Version version)
{
Name = name;
Version = version;
nodes = new HashSet<Guid>();
}

/// <summary>
/// Add the Guid of a dependent node
/// </summary>
/// <param name="guid"></param>
internal void AddDependent(Guid guid)
{
Nodes.Add(guid);
}

/// <summary>
/// Add the Guids of a dependent nodes
/// </summary>
/// <param name="guids"></param>
internal void AddDependents(IEnumerable<Guid> guids)
{
foreach(var guid in guids)
{
Nodes.Add(guid);
}
}

/// <summary>
/// Remove a dependent node
/// </summary>
/// <param name="guid"></param>
internal void RemoveDependent(Guid guid)
{
Nodes.Remove(guid);
}

/// <summary>
/// Checks whether two PackageDependencyInfos are equal
/// They are equal if their Name and Versions are equal
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (!(obj is PackageDependencyInfo))
{
return false;
}

var other = obj as PackageDependencyInfo;
if (other.Name == this.Name && other.Version == this.Version)
{
return true;
}
return false;
}
}
}
107 changes: 107 additions & 0 deletions src/DynamoCore/Graph/Workspaces/SerializationConverters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,16 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
// relevant ports.
var connectors = obj["Connectors"].ToObject<IEnumerable<ConnectorModel>>(serializer);

IEnumerable<PackageDependencyInfo> packageDependencies;
if (obj["PackageDependencies"] != null)
{
packageDependencies = obj["PackageDependencies"].ToObject<IEnumerable<PackageDependencyInfo>>(serializer);
}
else
{
packageDependencies = new List<PackageDependencyInfo>();
}

var info = new WorkspaceInfo(guid.ToString(), name, description, Dynamo.Models.RunType.Automatic);

// IsVisibleInDynamoLibrary and Category should be set explicitly for custom node workspace
Expand Down Expand Up @@ -587,6 +597,8 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
info, verboseLogging, isTestMode);
}

ws.PackageDependencies = packageDependencies.ToList();

return ws;
}

Expand Down Expand Up @@ -689,6 +701,10 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
}
writer.WriteEndArray();

// PackageDependencies
writer.WritePropertyName("PackageDependencies");
serializer.Serialize(writer, ws.PackageDependencies);

if (engine != null)
{
// Bindings
Expand Down Expand Up @@ -739,6 +755,97 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
}
}

/// <summary>
/// PackageDependencyInfoConverter is used to serialize and deserialize graph package dependencies
/// </summary>
public class PackageDependencyInfoConverter : JsonConverter
{
private Logging.ILogger logger;

/// <summary>
/// Constructs a PackageDependencyInfoConverter.
/// </summary>
/// <param name="logger"></param>
public PackageDependencyInfoConverter(Logging.ILogger logger)
{
this.logger = logger;
}

public override bool CanConvert(Type objectType)
{
return typeof(PackageDependencyInfo).IsAssignableFrom(objectType);
}

public override bool CanRead
{
get { return true; }
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
PackageDependencyInfo p = value as PackageDependencyInfo;
if (p != null)
{
writer.WriteStartObject();
writer.WritePropertyName("Name");
writer.WriteValue(p.Name);
writer.WritePropertyName("Version");
writer.WriteValue(p.Version.ToString());
writer.WritePropertyName("Nodes");
writer.WriteStartArray();
foreach(var node in p.Nodes)
{
writer.WriteValue(node.ToString("N"));
}
writer.WriteEndArray();
writer.WriteEndObject();
}
else
{
logger.LogWarning("Unnsuccessful attempt to serialize a PackageDependencyInfo object.", Logging.WarningLevel.Moderate);
}
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var obj = JObject.Load(reader);

// Get package name
var name = obj["Name"].Value<string>();

// Try get package version
var versionString = obj["Version"].Value<string>();
Version version;
if (!Version.TryParse(versionString, out version))
{
logger.LogWarning(
string.Format("The version of Package Dependency {0} could not be deserialized.", name),
Logging.WarningLevel.Moderate);
}

// Create new PackageDependencyInfo
var packageInfo = new PackageDependencyInfo(name, version);

// Try get dependent node IDs
var nodes = obj["Nodes"].Values<string>();
foreach(var nodeID in nodes)
{
Guid guid;
if (!Guid.TryParse(nodeID, out guid))
{
logger.LogWarning(
string.Format("The id ({0}) of a node dependent on {1} could not be parsed as a GUID.", nodeID, name),
Logging.WarningLevel.Moderate);
}
else
{
packageInfo.AddDependent(guid);
}
}
return packageInfo;
}
}

/// <summary>
/// DummyNodeWriteConverter is used for serializing DummyNodes to JSON.
/// Note that the DummyNode objects serialize as their original content and not as a DummyNode.
Expand Down
3 changes: 2 additions & 1 deletion src/DynamoCore/Graph/Workspaces/SerializationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ internal static string ToJson(this WorkspaceModel workspace, EngineController en
new ConnectorConverter(logger),
new WorkspaceWriteConverter(engine),
new DummyNodeWriteConverter(),
new TypedParameterConverter()
new TypedParameterConverter(),
new PackageDependencyInfoConverter(logger),
},
ReferenceResolverProvider = () => { return new IdReferenceResolver(); }
};
Expand Down
Loading

0 comments on commit f6f43e2

Please sign in to comment.