public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Steven Shi" <steven.shi@intel.com>
To: "Kinney, Michael D" <michael.d.kinney@intel.com>,
	"devel@edk2.groups.io" <devel@edk2.groups.io>,
	"Ni, Ray" <ray.ni@intel.com>
Cc: "Feng, Bob C" <bob.c.feng@intel.com>,
	"Gao, Liming" <liming.gao@intel.com>,
	Sean Brogan <sean.brogan@microsoft.com>,
	"Bret Barkelew" <Bret.Barkelew@microsoft.com>
Subject: Re: [edk2-devel] [Patch 1/1] BaseTools/Scripts: Add package dependency graphing tool
Date: Thu, 19 Dec 2019 01:11:15 +0000	[thread overview]
Message-ID: <06C8AB66E78EE34A949939824ABE2B3140269842@shsmsx102.ccr.corp.intel.com> (raw)
In-Reply-To: <E92EE9817A31E24EB0585FDF735412F5B9E4C890@ORSMSX113.amr.corp.intel.com>

[-- Attachment #1: Type: text/plain, Size: 28031 bytes --]

I reuse the BZ 2161 and add my requirement there as below.
https://bugzilla.tianocore.org/show_bug.cgi?id=2161

1. If without platform build log or DSC info, the tool only need to output module fanout build dependency info which includes what APIs (PPI/Protocol/Guid/PCD/Lib) a module depends on. No need to tell what these API's implementation instance are  (e.g. you don't know which library instance implement the library class/API without platform build info).
2. If with platform build log or DSC info, the tool need to output both module fanin and fanout info. And for the fanin and fanout info, the tool need output both APIs and their implementation instances paths (only need library instance module path and Static PCDs which impact a module build).
3. Please be aware the above dependency is only for the build dependency, not for the functionality dependency. Because the Uefi PPI/Protocol/Guid API's instances are always dynamic resolved/binding, and are not really needed in other module's static build, so only the PPI/Protocol/Guid API's definitions, not their instances, are the dependency of other module. But the library and static PCD are different, and their instances are necessary for other depending module pass build, so the library and static PCD instances are the dependency of other module.
4. Besides graph views, please combine and output all the dependency data as a single Json file, which will be easy for other metrics tool to consume.


Thanks

Steven Shi
Intel\SSG\SFE\FIE Firmware Infrastructure


From: Kinney, Michael D <michael.d.kinney@intel.com>
Sent: Tuesday, December 17, 2019 1:16 AM
To: Shi, Steven <steven.shi@intel.com>; devel@edk2.groups.io; Ni, Ray <ray.ni@intel.com>; Kinney, Michael D <michael.d.kinney@intel.com>
Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>; Sean Brogan <sean.brogan@microsoft.com>; Bret Barkelew <Bret.Barkelew@microsoft.com>
Subject: RE: [edk2-devel] [Patch 1/1] BaseTools/Scripts: Add package dependency graphing tool

Steve,

Yes.  I think a Module scoped view and a Platform scoped view would be good additions.

Can you please enter new BZ feature requests for these and add a summary of the features you would like to see in each?

Thanks,

Mike

From: Shi, Steven <steven.shi@intel.com<mailto:steven.shi@intel.com>>
Sent: Monday, December 16, 2019 12:48 AM
To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Ni, Ray <ray.ni@intel.com<mailto:ray.ni@intel.com>>; Kinney, Michael D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>
Cc: Feng, Bob C <bob.c.feng@intel.com<mailto:bob.c.feng@intel.com>>; Gao, Liming <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Sean Brogan <sean.brogan@microsoft.com<mailto:sean.brogan@microsoft.com>>; Bret Barkelew <Bret.Barkelew@microsoft.com<mailto:Bret.Barkelew@microsoft.com>>
Subject: RE: [edk2-devel] [Patch 1/1] BaseTools/Scripts: Add package dependency graphing tool


Ray,

I think you are asking for a module-level dependency tool. 😊



Mike,

This tool is cool. Besides the package level, do you think we can go further to figure out a module level dependency tool? With module level dependency info, we can define more interesting and comprehensive Modularity Metrics to measure the edk2 architecture quality (Architectural Technical Debt).







Thanks



Steven Shi

Intel\SSG\SFE\FIE Firmware Infrastructure





> -----Original Message-----

> From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> <devel@edk2.groups.io<mailto:devel@edk2.groups.io>> On Behalf Of Ni, Ray

> Sent: Monday, December 16, 2019 4:41 PM

> To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>; Ni, Ray <ray.ni@intel.com<mailto:ray.ni@intel.com>>; Kinney, Michael D

> <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>

> Cc: Feng, Bob C <bob.c.feng@intel.com<mailto:bob.c.feng@intel.com>>; Gao, Liming

> <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Sean Brogan <sean.brogan@microsoft.com<mailto:sean.brogan@microsoft.com>>; Bret

> Barkelew <Bret.Barkelew@microsoft.com<mailto:Bret.Barkelew@microsoft.com>>

> Subject: Re: [edk2-devel] [Patch 1/1] BaseTools/Scripts: Add package

> dependency graphing tool

>

> Mike,

> This pkg dep tool can tell through weight when a module depends on a new

> pkg.

> But it cannot tell when a module depends on another

> PCD/Protocol/Guid/Ppi/Library which belongs to an already-depended pkg.

>

> Failure to tell such information may make a bad module (that violates the

> dependency rules) worse (wrongly depend on more interfaces).

>

> Do you think that the tool can be enhanced in future to detect the case?

>

> Thanks,

> Ray

>

> > -----Original Message-----

> > From: devel@edk2.groups.io<mailto:devel@edk2.groups.io> <devel@edk2.groups.io<mailto:devel@edk2.groups.io>> On Behalf Of Ni,

> Ray

> > Sent: Monday, December 16, 2019 1:57 PM

> > To: Kinney, Michael D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>;

> devel@edk2.groups.io<mailto:devel@edk2.groups.io>

> > Cc: Feng, Bob C <bob.c.feng@intel.com<mailto:bob.c.feng@intel.com>>; Gao, Liming

> > <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Sean Brogan <sean.brogan@microsoft.com<mailto:sean.brogan@microsoft.com>>;

> Bret

> > Barkelew <Bret.Barkelew@microsoft.com<mailto:Bret.Barkelew@microsoft.com>>

> > Subject: Re: [edk2-devel] [Patch 1/1] BaseTools/Scripts: Add package

> > dependency graphing tool

> >

> > Mike,

> > 2 minor comments regarding the help string in below.

> >

> > > -----Original Message-----

> > > From: Kinney, Michael D <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>

> > > Sent: Saturday, December 14, 2019 3:45 AM

> > > To: devel@edk2.groups.io<mailto:devel@edk2.groups.io>

> > > Cc: Ni, Ray <ray.ni@intel.com<mailto:ray.ni@intel.com>>; Feng, Bob C <bob.c.feng@intel.com<mailto:bob.c.feng@intel.com>>;

> Gao,

> > > Liming <liming.gao@intel.com<mailto:liming.gao@intel.com>>; Sean Brogan

> > <sean.brogan@microsoft.com<mailto:sean.brogan@microsoft.com>>;

> > > Bret Barkelew <Bret.Barkelew@microsoft.com<mailto:Bret.Barkelew@microsoft.com>>

> > > Subject: [Patch 1/1] BaseTools/Scripts: Add package dependency

> graphing

> > > tool

> > >

> > > https://bugzilla.tianocore.org/show_bug.cgi?id=2161

> > >

> > > Add python script that recursively scans a directory for EDK II

> > > packages and generates GraphViz dot input that is used to render

> > > a graph of package dependencies in SVG format.

> > >

> > > Detects following error/warning conditions:

> > > * Ambiguous dependencies (multiple matches)

> > > * Unresolved dependencies

> > > * Circular dependencies

> > > * Nested packages

> > >

> > > usage: PackageDependencyGraph [-h] [-w WORKSPACE] [-p

> > PACKAGESPATH]

> > >                               [-d DOTOUTPUTFILE] [-o SVGOUTPUTFILE]

> > >                               [-g IGNOREDIRECTORY] [-k SKIPPACKAGE]

> > >                               [-s] [-u] [-l] [-f] [-b] [-v] [-q]

> > >                               [--debug [0-9]]

> > >

> > > Recursively scan a directory for EDK II packages and generate GraphViz

> dot

> > > input that is used to render a graph of package dependencies in SVG

> > format.

> > > Copyright (c) 2019, Intel Corporation. All rights reserved.

> > >

> > > optional arguments:

> > >   -h, --help            show this help message and exit

> > >   -w WORKSPACE, --workspace WORKSPACE

> > >                         Directory to recursively scan for EDK II packages.

> > >                         Default is current directory.

> > >   -p PACKAGESPATH, --packages-path PACKAGESPATH

> > >                         List of directories to recursively scan for EDK II

> > >                         packages.

> > >   -d DOTOUTPUTFILE, --dot-output DOTOUTPUTFILE

> > >                         DOT output filename.

> > >   -o OUTPUTFILE, --output OUTPUTFILE

> > >                         SVG output filename.

> > >   -g IGNOREDIRECTORY, --ignore-directory IGNOREDIRECTORY

> > >                         Name of directory to ignore. Option can be repeated

> > >                         to ignore multiple directories.

> >

> > 1. Name of directory to ignore when scanning for EDKII Module INFs.

> >

> > >   -k SKIPPACKAGE, --skip-package SKIPPACKAGE

> > >                         Name of EDK II Package DEC file to skip. Option can

> > >                         be repeated to skip multiple EDK II packages.

> >

> > 2. Name of EDK II Package DEC file (including .DEC suffix) to skip. Option

> can

> > Be repeated to skip multiple EDK II packages.

> >

> > >   -s, --self-dependency

> > >                         Include self links in dependency graph. Default is

> > >                         disabled.

> > >   -u, --unresolved      Include unresolved EDK II packages in dependency

> > >                         graph. Default is disabled.

> > >   -l, --label           Label links with the number of EDK II package

> > >                         dependencies. Default is disabled.

> > >   -f, --full-paths      Label package nodes with full path to EDK II

> > >                         package.  Default is disabled.

> > >   -b, --web-browser     Display SVG output file in default web browser.

> > >                         Default is disabled.

> > >   -v, --verbose         Increase output messages

> > >   -q, --quiet           Reduce output messages

> > >   --debug [0-9]         Set debug level

> > >

> > > Cc: Ray Ni <ray.ni@intel.com<mailto:ray.ni@intel.com>>

> > > Cc: Bob Feng <bob.c.feng@intel.com<mailto:bob.c.feng@intel.com>>

> > > Cc: Liming Gao <liming.gao@intel.com<mailto:liming.gao@intel.com>>

> > > Cc: Sean Brogan <sean.brogan@microsoft.com<mailto:sean.brogan@microsoft.com>>

> > > Cc: Bret Barkelew <Bret.Barkelew@microsoft.com<mailto:Bret.Barkelew@microsoft.com>>

> > > Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com<mailto:michael.d.kinney@intel.com>>

> > > ---

> > >  BaseTools/Scripts/PackageDependencyGraph.py | 296

> > > ++++++++++++++++++++

> > >  1 file changed, 296 insertions(+)

> > >  create mode 100644 BaseTools/Scripts/PackageDependencyGraph.py

> > >

> > > diff --git a/BaseTools/Scripts/PackageDependencyGraph.py

> > > b/BaseTools/Scripts/PackageDependencyGraph.py

> > > new file mode 100644

> > > index 0000000000..b3c8e41774

> > > --- /dev/null

> > > +++ b/BaseTools/Scripts/PackageDependencyGraph.py

> > > @@ -0,0 +1,296 @@

> > > +# @file

> > > +# Recursively scan a directory for EDK II packages and generate

> GraphViz

> > > dot

> > > +# input that is used to render a graph of package dependencies in SVG

> > > format.

> > > +#

> > > +# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>

> > > +# SPDX-License-Identifier: BSD-2-Clause-Patent

> > > +#

> > > +##

> > > +

> > > +import os

> > > +import sys

> > > +import argparse

> > > +import subprocess

> > > +import webbrowser

> > > +import networkx as nx

> > > +from edk2toollib.uefi.edk2.parsers.inf_parser import InfParser

> > > +

> > > +#

> > > +# Globals for help information

> > > +#

> > > +__prog__        = 'PackageDependencyGraph'

> > > +__copyright__   = 'Copyright (c) 2019, Intel Corporation. All rights

> > reserved.'

> > > +__description__ = '''Recursively scan a directory for EDK II packages and

> > > +generate GraphViz dot input that is used to render a graph of package

> > > +dependencies in SVG format.'''

> > > +

> > > +if __name__ == '__main__':

> > > +

> > > +    #

> > > +    # Create command line argument parser object

> > > +    #

> > > +    parser = argparse.ArgumentParser (prog = __prog__,

> > > +                                      description = __description__ + '\n' +

> __copyright__,

> > > +                                      conflict_handler = 'resolve')

> > > +    parser.add_argument ("-w", "--workspace", dest = 'Workspace',

> default

> > =

> > > os.curdir,

> > > +                         help = "Directory to recursively scan for EDK II packages.

> > > Default is current directory.")

> > > +    parser.add_argument ("-p", "--packages-path", dest = 'PackagesPath',

> > > default = None,

> > > +                         help = "List of directories to recursively scan for EDK II

> > > packages.")

> > > +    parser.add_argument ("-d", "--dot-output", dest = 'DotOutputFile',

> > > +                         help = "DOT output filename.")

> > > +    parser.add_argument ("-o", "--output", dest = 'SvgOutputFile',

> > > +                         help = "SVG output filename.")

> > > +    parser.add_argument ("-g", "--ignore-directory", dest =

> > 'IgnoreDirectory',

> > > action='append', default=[],

> > > +                         help = "Name of directory to ignore.  Option can be

> repeated

> > to

> > > ignore multiple directories.")

> > > +    parser.add_argument ("-k", "--skip-package", dest = 'SkipPackage',

> > > action='append', default=[],

> > > +                         help = "Name of EDK II Package DEC file to skip.  Option

> can

> > be

> > > repeated to skip multiple EDK II packages.")

> > > +    parser.add_argument ("-s", "--self-dependency", dest =

> > > 'SelfDependency', action = "store_true", default = False,

> > > +                         help = "Include self links in dependency graph.  Default is

> > > disabled.")

> > > +    parser.add_argument ("-u", "--unresolved", dest = 'Unresolved',

> action

> > =

> > > "store_true", default=False,

> > > +                         help = "Include unresolved EDK II packages in dependency

> > > graph.  Default is disabled.")

> > > +    parser.add_argument ("-l", "--label", dest = 'Label', action =

> > "store_true",

> > > default=False,

> > > +                         help = "Label links with the number of EDK II package

> > > dependencies.  Default is disabled.")

> > > +    parser.add_argument ("-f", "--full-paths", dest = 'FullPaths', action =

> > > "store_true", default=False,

> > > +                         help = "Label package nodes with full path to EDK II

> package.

> > > Default is disabled.")

> > > +    parser.add_argument ("-b", "--web-browser", dest = 'WebBrowser',

> > > action = "store_true", default=False,

> > > +                         help = "Display SVG output file in default web browser.

> > Default

> > > is disabled.")

> > > +    parser.add_argument ("-v", "--verbose", dest = 'Verbose', action =

> > > "store_true",

> > > +                         help = "Increase output messages")

> > > +    parser.add_argument ("-q", "--quiet", dest = 'Quiet', action =

> > > "store_true",

> > > +                         help = "Reduce output messages")

> > > +    parser.add_argument ("--debug", dest = 'Debug', type = int, metavar =

> > > '[0-9]', choices = range (0, 10), default = 0,

> > > +                         help = "Set debug level")

> > > +

> > > +    #

> > > +    # Parse command line arguments

> > > +    #

> > > +    args = parser.parse_args ()

> > > +

> > > +    #

> > > +    # Find all EDK II package DEC files

> > > +    #

> > > +    Components = {}

> > > +    SearchPaths = [args.Workspace]

> > > +    if args.PackagesPath:

> > > +        SearchPaths += args.PackagesPath.split(os.pathsep)

> > > +    SearchPaths = [os.path.realpath(x) for x in SearchPaths]

> > > +    for SearchPath in SearchPaths:

> > > +        for root, dirs, files in os.walk (SearchPath):

> > > +            for name in files:

> > > +                FilePath = os.path.join (root, name)

> > > +                if

> > > set(FilePath.split(os.sep)).intersection(set(args.IgnoreDirectory)) != set():

> > > +                    if args.Verbose:

> > > +                        print ('IGNORE:' + FilePath)

> > > +                    continue

> > > +                if os.path.splitext(FilePath)[1].lower() in ['.dec']:

> > > +                    DecFile = os.path.realpath (FilePath)

> > > +                    if os.path.split(DecFile)[1] in args.SkipPackage:

> > > +                        if args.Verbose:

> > > +                            print ('SKIP:' + DecFile)

> > > +                        continue

> > > +                    if DecFile not in Components:

> > > +                        if args.Verbose:

> > > +                            print ('PACKAGE:' + DecFile)

> > > +                        Components[DecFile] = {}

> > > +

> > > +    #

> > > +    # Find EDK II component INF files in each EDK II package

> > > +    #

> > > +    PackageLabels = {}

> > > +    UnresolvedPackages = []

> > > +    AmbiguousDependencies = []

> > > +    for DecFile in Components:

> > > +        DecPath = os.path.split (DecFile)[0]

> > > +        if DecFile not in PackageLabels:

> > > +            PackageLabels[DecFile] = (DecFile.replace(os.path.sep,'\\n'),

> 'white')

> > > +            if not args.FullPaths:

> > > +                PackagePath = os.path.relpath(DecFile,

> os.path.split(DecPath)[0])

> > > +                PackageLabels[DecFile] =

> (PackagePath.replace(os.path.sep,'\\n'),

> > > 'white')

> > > +        for root, dirs, files in os.walk (DecPath):

> > > +            for name in files:

> > > +                FilePath = os.path.join(root, name)

> > > +                if

> > > set(FilePath.split(os.sep)).intersection(set(args.IgnoreDirectory)) != set():

> > > +                    if args.Verbose:

> > > +                        print ('IGNORE:' + FilePath)

> > > +                    continue

> > > +                if os.path.splitext(FilePath)[1].lower() in ['.inf']:

> > > +                    InfFile = os.path.realpath (FilePath)

> > > +                    Inf = InfParser ()

> > > +                    Inf.ParseFile (InfFile)

> > > +                    DependentPackages = []

> > > +                    for Dependency in Inf.PackagesUsed:

> > > +                        Dependency = os.path.normpath(Dependency)

> > > +                        if os.path.split(Dependency)[1] in args.SkipPackage:

> > > +                            if args.Verbose:

> > > +                                print ('SKIP:' + Dependency)

> > > +                            continue

> > > +                        Found = False

> > > +                        for SearchPath in SearchPaths:

> > > +                            PackagePath = os.path.realpath(os.path.join(SearchPath,

> > > Dependency))

> > > +                            if os.path.exists(PackagePath):

> > > +                                DependentPackages.append(PackagePath)

> > > +                                if not args.FullPaths:

> > > +                                    PackageLabels[PackagePath] =

> > > (Dependency.replace(os.path.sep,'\\n'), 'white')

> > > +                                Found = True

> > > +                                break

> > > +                        if not Found:

> > > +                            Count = 0

> > > +                            Match = ''

> > > +                            for DecFile2 in Components:

> > > +                                if DecFile2.endswith(Dependency):

> > > +                                    if Count == 0:

> > > +                                        Match = DecFile2

> > > +                                    Count = Count + 1

> > > +                            if Count > 1:

> > > +                                AmbiguousDependencies.append (Dependency)

> > > +                            if Count == 1:

> > > +                                DependentPackages.append(Match)

> > > +                                if not args.FullPaths:

> > > +                                    PackageLabels[Match] =

> > > (Dependency.replace(os.path.sep,'\\n'), 'white')

> > > +                                Found = True

> > > +                        if not Found and args.Unresolved:

> > > +                            if args.Verbose:

> > > +                                print ('WARNING: Dependent package not found ' +

> > > Dependency)

> > > +                            DependentPackages.append(Dependency)

> > > +                            UnresolvedPackages.append(Dependency)

> > > +                            PackageLabels[Dependency] =

> > > (Dependency.replace(os.path.sep,'\\n'), 'white')

> > > +                    Components[DecFile][InfFile] = DependentPackages

> > > +    if AmbiguousDependencies:

> > > +        for Dependency in set(AmbiguousDependencies):

> > > +            print ('ERROR: MULTIPLE:   ' + Dependency)

> > > +        print ('Use --packages-path to provide search priority.')

> > > +        sys.exit(1)

> > > +

> > > +    #

> > > +    # Generate GraphViz dot input file contents.

> > > +    # Use networkx to detect circular dependencies.

> > > +    #

> > > +    MaxWeight = 0

> > > +    MaxWeightDecFile = list(Components.keys())[0]

> > > +    Graph = nx.DiGraph()

> > > +    Edges = []

> > > +    for DecFile in Components:

> > > +        if args.Verbose:

> > > +            print ('PACKAGE DEPENDENCIES:' + DecFile)

> > > +        AllDependencies = []

> > > +        Dependencies = set()

> > > +        for InfFile in Components[DecFile]:

> > > +            AllDependencies += Components[DecFile][InfFile]

> > > +            Dependencies =

> Dependencies.union(Components[DecFile][InfFile])

> > > +        if not args.SelfDependency:

> > > +            Dependencies = Dependencies.difference(set([DecFile]))

> > > +        for Dependency in Dependencies:

> > > +            Weight = AllDependencies.count(Dependency)

> > > +            if Weight > MaxWeight:

> > > +                MaxWeight = Weight

> > > +                MaxWeightDecFile = DecFile

> > > +            if args.Verbose:

> > > +                print ('  DEPENDENCY: Weight(' + str(Weight) + ') ' +

> Dependency)

> > > +            Edges.append('  "{Package}" -> "{Dependency}" [label =

> > > "{Weight}"];'.format(

> > > +                Package    = DecFile,

> > > +                Dependency = Dependency,

> > > +                Weight     = str(Weight) if args.Label else ''

> > > +                ))

> > > +            Graph.add_edge(DecFile, Dependency)

> > > +    Edges.sort()

> > > +

> > > +    #

> > > +    # Set fill color to yellow if a packages is part of a circular dependency

> > > +    #

> > > +    for Node in set([x for y in list(nx.simple_cycles(Graph)) for x in y]):

> > > +        PackageLabels[Node] = (PackageLabels[Node][0], 'yellow')

> > > +        print ('ERROR: CIRCULAR:   ' + Node)

> > > +

> > > +    #

> > > +    # Set fill color to pink if a package that is nested inside another

> package.

> > > +    # Set fill color to orange if a package is nested inside another package

> > and

> > > +    # is part of a circular dependency.

> > > +    #

> > > +    for DecFile in Components:

> > > +        DecPath = os.path.split (DecFile)[0]

> > > +        for DecFile2 in Components:

> > > +            if DecFile2 == DecFile:

> > > +                continue

> > > +            if os.path.commonpath ([DecPath, DecFile2]) != DecPath:

> > > +                continue

> > > +            if len(DecFile2) < len(DecPath):

> > > +                DecFile2 = DecFile

> > > +            print ('ERROR: NESTED:     ' + DecFile2)

> > > +            if PackageLabels[DecFile2][1] == 'yellow':

> > > +                PackageLabels[DecFile2] = (PackageLabels[DecFile2][0],

> 'orange')

> > > +            else:

> > > +                PackageLabels[DecFile2] = (PackageLabels[DecFile2][0], 'pink')

> > > +

> > > +    #

> > > +    # Set fill color to red for nodes that are unresolved

> > > +    #

> > > +    for Node in set(UnresolvedPackages):

> > > +        PackageLabels[Node] = (PackageLabels[Node][0], 'red')

> > > +        print ('ERROR: UNRESOLVED: ' + Node)

> > > +

> > > +    #

> > > +    # Add node statements to set node label and fill color

> > > +    #

> > > +    Nodes = []

> > > +    for Package in PackageLabels:

> > > +        Nodes.append('  "{Package}"

> > [label="{Label}",fillcolor={Color}];'.format(

> > > +            Package = Package,

> > > +            Label = PackageLabels[Package][0],

> > > +            Color = PackageLabels[Package][1]

> > > +            ))

> > > +    Nodes.sort()

> > > +

> > > +    #

> > > +    # Generate dot file from Nodes and Edges and add a Legend at top of

> > > graph

> > > +    #

> > > +    Dot = []

> > > +    Dot.append('digraph {')

> > > +    Dot.append('  rankdir=BT;')

> > > +    Dot.append('  node [shape=Mrecord,style=filled];')

> > > +    Dot.append('')

> > > +    Dot = Dot + Nodes

> > > +    Dot.append('')

> > > +    Dot = Dot + Edges

> > > +    Dot.append('')

> > > +    Dot.append('  subgraph legend {')

> > > +    Dot.append('    rank=sink;')

> > > +    Dot.append('    Unresolved     [label="Unresolved Dependency",

> > > fillcolor=red];')

> > > +    Dot.append('    Circular       [label="Circular Dependency",

> > > fillcolor=yellow];')

> > > +    Dot.append('    Nested         [label="Nested Package",

> > > fillcolor=pink];')

> > > +    Dot.append('    NestedCircular [label="Nested Package with Circular

> > > Dependency",fillcolor=orange];')

> > > +    Dot.append('  }')

> > > +    if MaxWeightDecFile:

> > > +        Dot.append('  Unresolved->"' + MaxWeightDecFile + '" [style=invis];')

> > > +    Dot.append('}')

> > > +

> > > +    if args.DotOutputFile:

> > > +        #

> > > +        # Write GraphViz dot file contents to DotOutputFile

> > > +        #

> > > +        with open(os.path.realpath(args.DotOutputFile), 'w') as File:

> > > +            File.write('\n'.join(Dot))

> > > +    if args.SvgOutputFile:

> > > +        #

> > > +        # Use GraphViz 'dot' command to generate SVG output file

> > > +        #

> > > +        args.SvgOutputFile = os.path.realpath(args.SvgOutputFile)

> > > +        try:

> > > +            Process = subprocess.Popen('dot -Tsvg',

> > > +              stdin=subprocess.PIPE,

> > > +              stdout=open(args.SvgOutputFile, 'w'),

> > > +              stderr=subprocess.PIPE,

> > > +              shell=True

> > > +              )

> > > +            Process.stdin.write ('\n'.join(Dot).encode())

> > > +            Process.communicate()

> > > +            if Process.returncode != 0:

> > > +                print ("ERROR: Can not run GraphViz 'dot' command.  Check

> install

> > > and path.")

> > > +                sys.exit(Process.returncode)

> > > +        except:

> > > +            print ("ERROR: Can not run GraphViz 'dot' command.  Check

> install

> > and

> > > path.")

> > > +            sys.exit(1)

> > > +        #

> > > +        # Display SVG file in default web browser

> > > +        #

> > > +        if args.WebBrowser:

> > > +            webbrowser.open(args.SvgOutputFile)

> > > --

> > > 2.21.0.windows.1

> >

> >

> >

>

>

> 



[-- Attachment #2: Type: text/html, Size: 80142 bytes --]

  parent reply	other threads:[~2019-12-19  1:11 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-12-13 19:44 [Patch 0/1] BaseTools/Scripts: Add package dependency graphing tool Michael D Kinney
2019-12-13 19:44 ` [Patch 1/1] " Michael D Kinney
2019-12-16  5:56   ` Ni, Ray
     [not found]   ` <15E0C4623803B81C.31060@groups.io>
2019-12-16  8:40     ` [edk2-devel] " Ni, Ray
2019-12-16  8:48       ` Steven Shi
2019-12-16 17:16         ` Michael D Kinney
2019-12-16 19:45           ` Sean
2019-12-17  2:48             ` Ni, Ray
2019-12-17 16:10               ` Steven Shi
2019-12-19  1:11           ` Steven Shi [this message]
2019-12-16 17:14       ` Michael D Kinney
2019-12-17  2:53         ` Ni, Ray

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=06C8AB66E78EE34A949939824ABE2B3140269842@shsmsx102.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox