Jelajahi Sumber

support/scripts/graph-depends allow for forward and reverse depends on same graph

The current implementation of buildroot depe dependency graphing
either does forward- or reverse-dependency traversal.

This patch enables buildroot to graph forward and reverse dependencies
on the graph for the same package: (Diagram Credit: Yann E. MORIN)

    $ make pkg-d-graph-both-depends

    pkg A -.            .-> pkg E
            \          /
    pkg B ----> pkg D ----> pkg F
            /          \
    pkg C -'            '-> pkg G

In the above example a single graph shows pkg {A,B,C} are needed
by pkg D, and pkg D is a dependency of pkg {E,F,G}.

Makefile help and manual are also updated.

Signed-off-by: Steve Hay <me@stevenhay.com>
[Arnout:
 - remove DEPTH and RDEPTH, their functionality is already covered by
   BR2_GRAPH_DEPS_OPTS;
 - remove --rdepth, it was felt to not add sufficient added value;
 - add the new target to the manual;
 - fix flake8 errors.
]
Signed-off-by: Arnout Vandecappelle <arnout@mind.be>
ʎɐH ǝʌǝʇS 2 tahun lalu
induk
melakukan
ca6c896bdd
4 mengubah file dengan 50 tambahan dan 27 penghapusan
  1. 3 0
      Makefile
  2. 4 0
      docs/manual/package-make-target.adoc
  3. 3 0
      package/pkg-generic.mk
  4. 40 27
      support/scripts/graph-depends

+ 3 - 0
Makefile

@@ -1171,6 +1171,9 @@ help:
 	@echo '                         - Recursively list packages which have <pkg> as a dependency'
 	@echo '  <pkg>-graph-depends    - Generate a graph of <pkg>'\''s dependencies'
 	@echo '  <pkg>-graph-rdepends   - Generate a graph of <pkg>'\''s reverse dependencies'
+	@echo '  <pkg>-graph-both-depends'
+	@echo '                         - Generate a graph of both <pkg>'\''s forward and'
+	@echo '                           reverse dependencies.
 	@echo '  <pkg>-dirclean         - Remove <pkg> build directory'
 	@echo '  <pkg>-reconfigure      - Restart the build from the configure step'
 	@echo '  <pkg>-rebuild          - Restart the build from the build step'

+ 4 - 0
docs/manual/package-make-target.adoc

@@ -81,6 +81,10 @@ graphs.
   dependencies (i.e the packages that depend on it, directly or
   indirectly)
 
+| +graph-both-depends+ | Generate a graph of this package in both
+  directions (i.e the packages that depend on it and on which it
+  depends, directly or indirectly)
+
 | +dirclean+        | Remove the whole package build directory
 
 | +reinstall+       | Re-run the install commands

+ 3 - 0
package/pkg-generic.mk

@@ -1042,6 +1042,9 @@ $(1)-graph-depends: graph-depends-requirements
 $(1)-graph-rdepends: graph-depends-requirements
 	$(call pkg-graph-depends,$(1),--reverse)
 
+$(1)-graph-both-depends: graph-depends-requirements
+	$(call pkg-graph-depends,$(1),--direct --reverse)
+
 $(1)-all-source:	$(1)-source
 $(1)-all-source:	$$(foreach p,$$($(2)_FINAL_ALL_DEPENDENCIES),$$(p)-all-source)
 

+ 40 - 27
support/scripts/graph-depends

@@ -159,11 +159,11 @@ def check_circular_deps(deps):
 
 # This functions trims down the dependency list of all packages.
 # It applies in sequence all the dependency-elimination methods.
-def remove_extra_deps(deps, rootpkg, transitive, arrow_dir):
+def remove_extra_deps(deps, rootpkg, transitive, direct):
     # For the direct dependencies, find and eliminate mandatory
     # deps, and add them to the root package. Don't do it for a
     # reverse graph, because mandatory deps are only direct deps.
-    if arrow_dir == "forward":
+    if direct:
         for pkg in list(deps.keys()):
             if not pkg == rootpkg:
                 for d in get_mandatory_deps(pkg, deps):
@@ -199,12 +199,13 @@ def print_attrs(outfile, pkg, pkg_type, pkg_version, depth, colors):
 
 # Print the dependency graph of a package
 def print_pkg_deps(outfile, dict_deps, dict_types, dict_versions, stop_list, exclude_list,
-                   arrow_dir, draw_graph, depth, max_depth, pkg, colors, done_deps=None):
+                   direct, draw_graph, depth, max_depth, pkg, colors, done_deps=None):
     if done_deps is None:
         done_deps = []
     if pkg in done_deps:
         return
     done_deps.append(pkg)
+
     if draw_graph:
         print_attrs(outfile, pkg, dict_types[pkg], dict_versions[pkg], depth, colors)
     elif depth != 0:
@@ -231,9 +232,12 @@ def print_pkg_deps(outfile, dict_deps, dict_types, dict_versions, stop_list, exc
                     break
             if add:
                 if draw_graph:
-                    outfile.write("%s -> %s [dir=%s]\n" % (pkg_node_name(pkg), pkg_node_name(d), arrow_dir))
+                    if direct:
+                        outfile.write("%s -> %s [dir=%s]\n" % (pkg_node_name(pkg), pkg_node_name(d), "forward"))
+                    else:
+                        outfile.write("%s -> %s [dir=%s]\n" % (pkg_node_name(d), pkg_node_name(pkg), "forward"))
                 print_pkg_deps(outfile, dict_deps, dict_types, dict_versions, stop_list, exclude_list,
-                               arrow_dir, draw_graph, depth + 1, max_depth, d, colors, done_deps)
+                               direct, draw_graph, depth + 1, max_depth, d, colors, done_deps)
 
 
 def parse_args():
@@ -265,9 +269,9 @@ def parse_args():
                         default=False)
     parser.add_argument("--no-transitive", dest="transitive", action='store_false',
                         help="Draw (do not draw) transitive dependencies")
-    parser.add_argument("--direct", dest="direct", action='store_true', default=True,
+    parser.add_argument("--direct", dest="direct", action='store_true', default=False,
                         help="Draw direct dependencies (the default)")
-    parser.add_argument("--reverse", dest="direct", action='store_false',
+    parser.add_argument("--reverse", dest="reverse", action='store_true', default=False,
                         help="Draw reverse dependencies")
     parser.add_argument("--quiet", '-q', dest="quiet", action='store_true',
                         help="Quiet")
@@ -292,6 +296,9 @@ def main():
             sys.exit(1)
         outfile = open(args.outfile, "w")
 
+    if not args.direct and not args.reverse:
+        args.direct = True
+
     if args.package is None:
         mode = MODE_FULL
         rootpkg = 'all'
@@ -312,13 +319,9 @@ def main():
     if args.exclude_mandatory:
         exclude_list += MANDATORY_DEPS
 
-    if args.direct:
-        arrow_dir = "forward"
-    else:
-        if mode == MODE_FULL:
-            logging.error("--reverse needs a package")
-            sys.exit(1)
-        arrow_dir = "back"
+    if args.reverse and mode == MODE_FULL:
+        logging.error("--reverse needs a package")
+        sys.exit(1)
 
     draw_graph = not args.flat_list
 
@@ -330,23 +333,33 @@ def main():
         logging.error("Error: incorrect color list '%s'" % args.colors)
         sys.exit(1)
 
-    deps, rdeps, dict_types, dict_versions = brpkgutil.get_dependency_tree()
-    dict_deps = deps if args.direct else rdeps
-
-    check_circular_deps(dict_deps)
-    if check_only:
-        sys.exit(0)
-
-    dict_deps = remove_extra_deps(dict_deps, rootpkg, args.transitive, arrow_dir)
-
     # Start printing the graph data
-    if draw_graph:
+    if not check_only and draw_graph:
         outfile.write("digraph G {\n")
 
-    print_pkg_deps(outfile, dict_deps, dict_types, dict_versions, stop_list, exclude_list,
-                   arrow_dir, draw_graph, 0, args.depth, rootpkg, colors)
+    deps, rdeps, dict_types, dict_versions = brpkgutil.get_dependency_tree()
 
-    if draw_graph:
+    # forward
+    if args.direct:
+        dict_deps = deps
+        direct = True
+        check_circular_deps(dict_deps)
+        if not check_only:
+            dict_deps = remove_extra_deps(dict_deps, rootpkg, args.transitive, direct)
+            print_pkg_deps(outfile, dict_deps, dict_types, dict_versions, stop_list, exclude_list,
+                           direct, draw_graph, 0, args.depth, rootpkg, colors)
+
+    # reverse
+    if args.reverse:
+        dict_deps = rdeps
+        direct = False
+        check_circular_deps(dict_deps)
+        if not check_only:
+            dict_deps = remove_extra_deps(dict_deps, rootpkg, args.transitive, direct)
+            print_pkg_deps(outfile, dict_deps, dict_types, dict_versions, stop_list, exclude_list,
+                           direct, draw_graph, 0, args.depth, rootpkg, colors)
+
+    if not check_only and draw_graph:
         outfile.write("}\n")
     else:
         outfile.write("\n")