⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 svn-graph.pl

📁 subversion-1.4.5.tar.gz 配置svn的源码
💻 PL
字号:
#!/usr/bin/perl -w# vim:ts=2:sw=2:expandtab## svn-graph.pl - produce a GraphViz .dot graph for the branch history#                of a node## ====================================================================# Copyright (c) 2000-2006 CollabNet.  All rights reserved.## This software is licensed as described in the file COPYING, which# you should have received as part of this distribution.  The terms# are also available at http://subversion.tigris.org/license-1.html.# If newer versions of this license are posted there, you may use a# newer version instead, at your option.## This software consists of voluntary contributions made by many# individuals.  For exact contribution history, see the revision# history and logs, available at http://subversion.tigris.org/.# ====================================================================## View graphs using a command like:##   svn-graph.pl file:///tmp/repos | dotty -## TODO:#  - Calculate the repository root at runtime so the user can pass#    the node of interest as a single URL.#  - (Also?) produce the graphical output ourselves (SVG?) instead#    of writing a GraphViz ".dot" data file.  This can be done with#    GraphViz using 'dot'.#  - Display svnmerge.py/Subversion merge history.#use strict;use Getopt::Std;# Turn off output buffering$|=1;require SVN::Core;require SVN::Ra;# The URL of the Subversion repository we wish to graph# (e.g. "http://svn.collab.net/repos/svn").my $repos_url;# The revision range we operate on, from $startrev -> $youngest.my $youngest;my $startrev;# This is the node we're interested inmy $startpath;# Set the variables declared above.parse_commandline();# Point at the root of a repository so we get can look at# every revision.my $ra = SVN::Ra->new($repos_url);# Handle identifier for the aboslutely youngest revision.if ($youngest eq 'HEAD'){  $youngest = $ra->get_latest_revnum();}# The "interesting" nodes are potential sources for copies.  This list#   grows as we move through time.# The "tracking" nodes are the most recent revisions of paths we're#   following as we move through time.  If we hit a delete of a path#   we remove it from the tracking array (i.e. we're no longer interested#   in it).my %interesting = ("$startpath:$startrev", 1);my %tracking = ("$startpath", $startrev);my %codeline_changes_forward = ();my %codeline_changes_back = ();my %copysource = ();my %copydest = ();write_graph_descriptor();#print STDERR "\n";# Validate the command-line arguments, and set the global variables# $repos_url, $youngest, $startrev, and $startpath.sub parse_commandline{  my %cmd_opts;  my $usage = "usage: svn-graph.pl [-r START_REV:END_REV] [-p PATH] REPOS_URL  -r the revision range (defaults to 0 through HEAD)  -p the repository-relative path (defaults to /trunk)  -h show this help information (other options will be ignored)";  # Defaults.  $cmd_opts{'r'} = '1:HEAD';  $cmd_opts{'p'} = '/trunk';  getopts('r:p:h', \%cmd_opts) or die $usage;  die $usage if scalar(@ARGV) < 1;  $repos_url = $ARGV[0];  $cmd_opts{'r'} =~ m/(\d+)(:(.+))?/;  if ($3)  {    $youngest = ($3 eq 'HEAD' ? $3 : int($3));    $startrev = int($1);  }  else  {    $youngest = ($3 eq 'HEAD' ? $1 : int($1));    $startrev = 1;  }  $startpath = $cmd_opts{'p'};  # Print help info (and exit nicely) if requested.  if ($cmd_opts{'h'})  {    print($usage);    exit 0;  }}# This function is a callback which is invoked for every revision as# we traverse change log messages.sub process_revision{  my $changed_paths = shift;  my $revision = shift || '';  my $author = shift || '';  my $date = shift || '';  my $message = shift || '';  my $pool = shift;  #print STDERR "$revision\r";  foreach my $path (keys %$changed_paths)  {    my $copyfrom_path = $$changed_paths{$path}->copyfrom_path;    my $copyfrom_rev = undef;    my $action = $$changed_paths{$path}->action;    # See if we're deleting one of our tracking nodes    if ($action eq 'D' and exists($tracking{$path}))    {      print "\t\"$path:$tracking{$path}\" ";      print "[label=\"$path:$tracking{$path}\\nDeleted in r$revision\",color=red];\n";      delete($tracking{$path});      next;    }    ### TODO: Display a commit which was the result of a merge    ### operation with [sytle=dashed,color=blue]    # If this is a copy, work out if it was from somewhere interesting    if (defined($copyfrom_path))    {      $copyfrom_rev = $tracking{$copyfrom_path};    }    if (defined($copyfrom_rev) &&        exists($interesting{$copyfrom_path . ':' . $copyfrom_rev}))    {      $interesting{$path . ':' . $revision} = 1;      $tracking{$path} = $revision;      print "\t\"$copyfrom_path:$copyfrom_rev\" -> ";      print " \"$path:$revision\"";      print " [label=\"copy at r$revision\",color=green];\n";      $copysource{"$copyfrom_path:$copyfrom_rev"} = 1;      $copydest{"$path:$revision"} = 1;    }    # For each change, we'll walk up the path one component at a time,    # updating any parents that we're tracking (i.e. a change to    # /trunk/asdf/foo updates /trunk).  We mark that parent as    # interesting (a potential source for copies), draw a link, and    # update its tracking revision.    do    {      if (exists($tracking{$path}) && $tracking{$path} != $revision)      {        $codeline_changes_forward{"$path:$tracking{$path}"} =          "$path:$revision";        $codeline_changes_back{"$path:$revision"} =          "$path:$tracking{$path}";        $interesting{$path . ':' . $revision} = 1;        $tracking{$path} = $revision;      }      $path =~ s:/[^/]*$::;    } until ($path eq '');  }}# Write a descriptor for the graph in GraphViz .dot format to stdout.sub write_graph_descriptor{  # Begin writing the graph descriptor.  print "digraph tree {\n";  print "\tgraph [bgcolor=white];\n";  print "\tnode [color=lightblue2, style=filled];\n";  print "\tedge [color=black, labeljust=r];\n";  print "\n";  # Retrieve the requested history.  $ra->get_log(['/'], $startrev, $youngest, 0, 1, 0, \&process_revision);  # Now ensure that everything is linked.  foreach my $codeline_change (keys %codeline_changes_forward)  {    # If this node is not the first in its codeline chain, and it isn't    # the source of a copy, it won't be the source of an edge    if (exists($codeline_changes_back{$codeline_change}) &&        !exists($copysource{$codeline_change}))    {      next;    }    # If this node is the first in it's chain, or the source of    # a copy, then we'll print it, and then find the next in    # the chain that needs to be printed too    if (!exists($codeline_changes_back{$codeline_change}) or         exists($copysource{$codeline_change}) )    {      print "\t\"$codeline_change\" -> ";      my $nextchange = $codeline_changes_forward{$codeline_change};      my $changecount = 1;      while (defined($nextchange))      {        if (exists($copysource{$nextchange}) or            !exists($codeline_changes_forward{$nextchange}) )        {          print "\"$nextchange\" [label=\"$changecount change";          if ($changecount > 1)          {            print 's';          }          print '"];';          last;        }        $changecount++;        $nextchange = $codeline_changes_forward{$nextchange};      }      print "\n";    }  }  # Complete the descriptor (delaying write of font size to avoid  # inheritance by any subgraphs).  #my $title = "Family Tree\n$startpath, $startrev through $youngest";  #print "\tgraph [label=\"$title\", fontsize=18];\n";  print "}\n";}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -