Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Produce a DGML graph from the ApiPort data #695

Merged
merged 7 commits into from
Sep 25, 2018

Conversation

AlexGhiondea
Copy link
Contributor

Create a mechanism to create a DGLM graph from the ApiPort data that will show the dependencies of the input assemblies.

This is how the DGML document looks like. Each node has 2 indexes (one for itself in isolation and one that describes the portability of the references).

image

/cc @twsouthwick @conniey

@AlexGhiondea
Copy link
Contributor Author

Ping?

@conniey conniey changed the base branch from master to dev September 8, 2018 20:33
@@ -38,6 +40,61 @@ public DependencyFinderEngineHelper(IDependencyFilter assemblyFilter, MetadataRe
_currentAssemblyName = _reader.GetString(assemblyDefinition.Name);
}

private IList<AssemblyReferenceInformation> ComputeAssemblyReferences(MetadataReader metadataReader)
{
List<AssemblyReferenceInformation> refs = new List<AssemblyReferenceInformation>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it's a VS code fix, but we usually use var when the types are obvious.
Same for the other variables below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a fan of style, but I will change to match the project style!

return refs;
}

private static string FormatPublicKeyToken(MetadataReader metadataReader, BlobHandle handle)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have extension methods that provide this: MetadataReaderExtensions.FormatAssemblyInfo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove this?


namespace Microsoft.Fx.Portability.Reports.DGML
{
class ReferenceGraph
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@twsouthwick I thought we had stylecop analysers that forced us to specify the access modifier as public, internal, etc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go and modify the ruleset. :)

FileExtension = ".dgml"
};

private DGMLManager dgml = new DGMLManager();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: private readonly

{
private readonly Dictionary<string, Guid> _nodesDictionary = new Dictionary<string, Guid>();

private XElement nodes;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: private readonly

var refNode = rg.GetOrAddNodeForAssembly(new ReferenceNode(reference.ToString()));

// if the reference is missing, flag it as such.
if (unresolvedAssemblies.Contains(reference.ToString()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refNode.IsMissing = unresolvedAssemblies.Contains(reference.ToString());

{
class ReferenceGraph
{
public Dictionary<ReferenceNode, ReferenceNode> Nodes { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this Nodes member set else where? If not, we can make this:
public Dictionary<ReferenceNode, ReferenceNode> Nodes { get; }


public List<TargetUsageInfo> UsageData { get; set; }

public string Assembly { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public string Assembly { get; }
and same with any other members below that are only set in the constructor

public ReferenceNode(string AssemblyName, bool unresolved = false)
{
Assembly = AssemblyName;
this.Unresolved = unresolved;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary this. and naming of AssemblyName to assemblyName

{
Assembly = AssemblyName;
this.Unresolved = unresolved;
Nodes = new HashSet<ReferenceNode>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also need to pass in your ReferenceNodeComparer for the HashSet? Might be better to have a ReferenceNodeComparer.Instance so we don't have to create multiple instances of this comparer.

@conniey
Copy link
Member

conniey commented Sep 8, 2018

I apologise for the delayed response. I don't get emails from github for some reason. Thanks for this! Excited to have another ReportFormatter

@AlexGhiondea
Copy link
Contributor Author

Thanks for the review @conniey! I will try and address the comments this week!

Copy link
Member

@twsouthwick twsouthwick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple comments, but I need to understand why the breaking change on the IReportWriter. This will cause the change to have some ripple effects on the service

return refs;
}

private static string FormatPublicKeyToken(MetadataReader metadataReader, BlobHandle handle)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you remove this?

@@ -0,0 +1,131 @@
// Copyright (c) Microsoft. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be easier with the public class below. Construct a request and a response and check if outputs the expectedc structure. Usually easiest to create a simple project, run the tool, and dump those values

@@ -26,7 +26,7 @@ public ExcelReportWriter(ITargetMapper targetMapper)

public ResultFormatInformation Format { get { return _formatInformation; } }

public void WriteStream(Stream stream, AnalyzeResponse response)
public void WriteStream(Stream stream, AnalyzeResponse response, AnalyzeRequest request)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What information do you need from the AnalyzeRequest? This may make it difficult to incorporate into the service

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use that information to create the assembly reference graph. When we first analyze the assemblies (before we send them back) we capture enough information about their dependencies to allow us to generate the DGML graph.

That information can be computed before we send the request as well -- and we can probably stash it somewhere in order for the information to survive the round-trip.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep in mind that the writers are inserted as output formatters in the MVC pipeline, so it just gets the output. If you can find a way to have it go through the AnalyzeResponse, that would be ideal, as I'm not sure how we could easily get the request without some jumping through hoops (maybe accessing the HttpContext or something, but I'm not as familiar with ASP.NET as ASP.NET Core). You can annotate it with [JsonIgnore] so it won't be serialized down if application/json is requested

AlexGhiondea and others added 5 commits September 20, 2018 11:16
In order to pass the required information to the report generator we are going
to pass the AnalyzeRequest to the report generator.
This is used to display the data as-is.
…ed (available and not)

This is the information required to add information about the references into the data.
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Security.Cryptography;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you still need this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will double check and fix this and the other comment from Connie! Thanks a lot!!!


public ReferenceGraph()
{
Nodes = new Dictionary<ReferenceNode, ReferenceNode>(new ReferenceNodeComparer());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReferenceNodeComparer.Instance

@AlexGhiondea
Copy link
Contributor Author

I have resolved the last issues you mentioned. Thanks for the review!

I have rebased some of the changes away to keep the history in a better spot (ie. remove all the 'address feedback' commits).

@twsouthwick twsouthwick merged commit a90b32b into microsoft:dev Sep 25, 2018
@twsouthwick
Copy link
Member

Thanks @AlexGhiondea!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants