Skip to content

Instantly share code, notes, and snippets.

@jlawton
Created October 24, 2017 05:38
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jlawton/08901cf04556550299d807052cbbe658 to your computer and use it in GitHub Desktop.
Save jlawton/08901cf04556550299d807052cbbe658 to your computer and use it in GitHub Desktop.
Resolved Carthage dependency grapher
#!/usr/bin/env perl -w
use strict;
use Text::ParseWords qw(quotewords);
# Returns [DependencyName]
sub parseCartfile {
open(my $fh, '<', $_[0]) or die "Cannot open file $_[0]";
my @entries = ();
while (my $line = <$fh>) {
chomp $line;
if ($line !~ m/^(git|binary)/) {
next;
}
my @bits = quotewords('\s+', 0, $line);
if ($#bits >= 1) {
push( @entries, nameFromURL($bits[1]) );
}
}
close($fh);
return \@entries;
}
# Returns {DependencyName => Version}
sub parseCartfileResolved {
open(my $fh, '<', $_[0]) or die "Cannot open file $_[0]: $!";
my %entries = ();
while (my $line = <$fh>) {
chomp $line;
if ($line !~ m/^(git|binary)/) {
next;
}
my @bits = quotewords('\s+', 0, $line);
if ($#bits == 2) {
$entries{nameFromURL($bits[1])} = shortVersion($bits[2]);
}
}
close($fh);
return \%entries;
}
sub nameFromURL {
my $url = $_[0];
if ($url =~ m|^.*/([^/]+?)(\.git\|\.json)?$|) {
return $1;
}
die "Bad dependency: $url";
}
sub shortVersion {
my $version = $_[0];
if ($version =~ m/^[a-f0-9]{40}$/) {
return substr($version, 0, 6);
}
return $version;
}
sub graph {
my @edges = @{$_[0]};
my %versions = %{$_[1]};
my $graph = '';
$graph .= "digraph G {\n";
for my $edge (@edges) {
my @nodes = @{$edge};
$graph .= " \"$nodes[0]\" -> \"$nodes[1]\";\n";
}
$graph .= "\n";
for my $node (keys(%versions)) {
$graph .= " \"$node\" [label=\"$node\\n$versions{$node}\"];";
}
$graph .= "}\n";
return $graph;
}
sub pdfFromGraph {
my $graph = $_[0];
my $outputFile = $_[1];
# If this fails, we don't actually know, because it's run in a subshell. Ah well!
open(my $dot, '|-', "dot -Tpdf -o \"$outputFile\"") or die "Cannot run 'dot': $!";
print $dot $graph;
close($dot);
}
sub main {
my $root = ($#ARGV >= 0) ? $ARGV[0] : '.';
my $rootName = 'app';
my $resolvedFile = "$root/Cartfile.resolved";
my $checkouts = "$root/Carthage/Checkouts";
my @edges = ();
my %deps = %{parseCartfileResolved($resolvedFile)};
for my $dep (keys(%deps)) {
push( @edges, [ $rootName, $dep ] );
if (-f "$checkouts/$dep/Cartfile") {
my @subdeps = @{parseCartfile("$checkouts/$dep/Cartfile")};
for my $subdep (@subdeps) {
push( @edges, [ $dep, $subdep ] );
}
}
}
my $graph = graph(\@edges, \%deps);
my $outputFile = "/tmp/carthage-graph-$$.pdf";
pdfFromGraph($graph, $outputFile);
if (-f $outputFile) {
system('open', $outputFile);
sleep(1);
unlink($outputFile);
} else {
print "Failed to run 'dot'. Please install Graphviz. eg 'brew install graphviz'";
}
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment