#!/usr/bin/perl -w -- -*-cperl-*- use strict; use warnings; use GraphViz; use File::Find; use Getopt::Long; use Pod::Usage; my %o; GetOptions(\%o, 'help|h|?!', 'man!', 'output|o:s', ) or pod2usage(-verbose => 1) && exit 1; $o{output} ||= "deps.ps"; pod2usage(-verbose => 1) && exit if $o{help}; pod2usage(-verbose => 2) && exit if $o{man}; my $ROOT = @ARGV ? $ARGV[0] : "/opt/rt3/var/mason_data/obj/standard"; if (!-r $ROOT) { pod2usage(-message => "\n$ROOT isn't a readable; this isn't uncommon,\n". "as the files are written by the web user.\n", -verbose => 1, ); exit; } elsif (!-d $ROOT) { pod2usage(-message => "\n$ROOT isn't a directory!\n", -verbose => 1, ); exit; } # Put together dependency list my %deps; find \&find_deps, $ROOT; # Assemble ane output .ps my $g = GraphViz->new(directed => 1, layout => 'neato', no_overlap => 1, epsilon => .5, width => 7.5, height => 10, pagewidth => 8.5, pageheight => 11, node => { shape => 'box', } ); $g->add_node($_) for keys %deps; for my $src (keys %deps) { for my $dst (keys %{$deps{$src}}) { $g->add_edge($src => $dst); } } $g->as_ps($o{output}); print "$o{output} written.\n"; sub find_deps { return unless -f; my $path = $File::Find::dir; $path =~ s/$ROOT//; my $file = "$path/$_"; $deps{$file} = {}; unless (open(FILE, $File::Find::name)) { warn "Can't open $File::Find::name: $!"; return; } while () { # This regex mostly works, but misses <&|path&>.. style calls. next unless /\$m->comp\(\s*(['"])([^'".][^'"]+)\1/; my $comp = $2; $comp = "$path/$comp" unless $comp =~ m|^/|; $deps{$file}{$comp}++; } close FILE; } __END__ =head1 NAME graph-mason-deps - create a graph of which mason components call each other =head1 SYNOPSIS graph-mason-deps # Reads /opt/rt3/var/mason_data/standard # Writes to deps.ps =head1 DESCRIPTION C is a script to produce a dependcy graph of Mason components using GraphViz. Though originally written for RT, it should work for any Mason system of components. It reads the cache files which are generated when Mason parses components; as such, it will only be able to see components that Mason has parsed already. As these Mason cache files are written by the web server, you may need elevated privileges in order to read them. =head1 OPTIONS =over =item S Specifies the path to the mason cache directory. Defaults to C Note that this directory, is usually written by C, C, or C, and thus you may need to be root to read it. =item --help, -h, or -? The help option lists a short page of sample usage instructions, along with descriptions of all of the available options. =item --man, or -S Lists the full man page for C, showing everything that --help does, along with general description, revision history, contact information, and so forth. This can be equally gotten by typing C =item --output S, or -o S Specifies the name of the postscript output file. By default, this is "deps.ps" =back =head1 AUTHOR =head2 Contact Info Alex Vandiver : alexmv@mit.edu =head2 Copyright Copyright (C) Alex Vandiver All rights reserved. This package is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut