Making a Dependency Graph with Custom Dependencies

Abstract: A sample python graph plugin to add custom dependencies to an architecture dependency graph.

Every so often, we get a request to allow users to add their own dependencies. The idea is the user knows things Understand can’t know, like run time dependencies, and it would be nice if those things could be included too. 

This request isn’t likely to be granted, at least not in terms of adding references and/or entities to the parse data. However, it is possible to have a custom graph plugin display additional dependencies. 

Python Code

Let’s start with a basic architecture graph plugin described in this article. The first change is to update the name function:

Update the name function

Next, instead of showing edges to each architecture child, we want to show an edge to each dependency. However, dependencies can by cyclical so we risk an infinite loop in python. To avoid this, we need to track the visited architectures. If you’re using a build before 1113, you may need to track the architecture’s long name in the visited set instead of using the architecture directly.

Add edges for dependencies instead of for children.

We now have a functional architecture dependency graph. But, we’d still like to add our oracular knowledge. Where does this oracular knowledge come from? For this script, I’ll assume that any additional dependencies are in a file called [dbname]_oracle.csv. That allows the script to be extended to multiple databases. The csv will have a source column and a destination column and no headers. So, for the call levels architecture for fastgrep created in this article, I’ll add these dependencies to fastgrep_oracle.csv.

calllevels/0,calllevels/6
calllevels/0,calllevels/4
calllevels/8,calllevels/4

Now I need to load the oracle file, if it exists, in my script. For the existence check, I’ll need to add an import:

Import needed to check file existence

Then, I can load the file near the top of my draw function. I’ll assume each entry is an architecture and use db.lookup_arch to convert it to an Understand.Arch object.

  # Load an oracle file
  oracle = dict()
  path = graph.db().name()[:-4] + "_oracle.csv"
  if os.path.exists(path):
    fin = open(path,'r')
    line = fin.readline()
    while line:
      parts = line.split(',')
      src = graph.db().lookup_arch(parts[0].strip())
      dest = graph.db().lookup_arch(parts[-1].strip())
      if src and dest:
        oracle.setdefault(src,[]).append(dest)
      line = fin.readline()
    fin.close()

Finally, I add my custom edges. I’ll make the edges blue so they’ll be more obvious.

Add the oracle edges

The final graph looks like this:

A dependency graph with custom edges added