You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@subversion.apache.org by Karl Fogel <kf...@newton.ch.collab.net> on 2002/12/12 17:47:54 UTC

Re: [PATCH] New file proposed (name change!) tools/contrib/svn_filesystem_doctor

Scott Harrison <sh...@users.sourceforge.net> writes:
> New file.
>        svn_filesystem_doctor - analyze and manipulate svn reposi-
>        tories on a filesystem

Scott, I was about to add this tool, but then I realized it might be
out of date w.r.t. recent changes to svnadmin usage.  Do you know?

By the way, maybe 'svn_repos_doctor' would be more intuitive?

-Karl

> #!/usr/bin/perl
> 
> =head1 NAME
> 
> svn_filesystem_doctor - analyze and manipulate svn repositories on a filesystem
> 
> =head1 SYNOPSIS
> 
> svn_filesystem_doctor S<[ B<--printf>="I<string>" ]>
>                 S<[ B<--oldsvnadminpath>="I<command_path>" ]>
>                 S<[ B<--svnadminpath>="I<command_path>" ]>
> 		S<[ B<--autochange> ]> S<[ B<--backup> ]>
> 	        S<[ B<--stdin> ]> S<[ B<--findall>="I<starting_path>" ]>
>                 S<[ B<--apacheconf> ]>
> 
> At minimum, either B<stdin> or the B<findall> flag must be specified in order
> to launch B<svn_filesystem_doctor>.
> 
> The B<printf> I<string> can consist of the following escaped characters:
> 
> =over 4
> 
> =item %d
> 
> Directory path to a subversion repository.
> 
> =item %s
> 
> The format schema of the subversion repository.  A value of "0N" means
> that the format schema equals version 0 that it does not work with the current
> B<svnadmin> command.  A value of "0Y" means version 0, and that it does work
> with the current B<svnadmin> command.  A value of "13Y" means version 13
> and that it does work with the current B<svnadmin> command.  And so on.
> 
> =back
> 
> =head1 DESCRIPTION
> 
> Looks at an existing filesystem and diagnoses the locations and states
> of various subversion repositories (and this means "repositories", not
> working copies).  This program also facilitates the generation
> of plain-text backups as well as upgrading the format db schema
> based on new releases of subversion.
> 
> =head2 Getting the subversion repositories
> 
> The B<findall> and B<stdin> flags control the repositories that this
> script works with.  The B<findall> flag will probe the entire filesystem
> and look for likely locations of subversion repositories (using heuristics
> related to directory structure).  The B<stdin> flag will alternatively
> accept a list of subversion directory filesystem paths (for which to apply
> the B<--printf>, B<--autochange>, or other functionalities).
> 
> =head2 Locating the svnadmin executable
> 
> The B<svnadminpath> and B<oldsvnadminpath> flags specify the location
> of the B<svnadmin> executables necessary to implement various
> svn_filesystem_doctor functionalities.  Ordinarily, just the B<svnadminpath>
> variable would need to be specified (if it is not specified, the regular shell
> command path is used).  The B<oldsvnadminpath> variable is specified for
> situations where the older version of B<svnadmin> is needed to perform db
> format schema upgrades (C<oldsvnadmin dump> followed by a C<currentsvnadmin
> load>)....
> 
> =head2 Functionalities of svn_filesystem_doctor
> 
> =over 4
> 
> =item * Generate an apache configuration file
> 
> >From the determined list of subversion repositories, an apache configuration
> text string is generated.  This functionality is invoked by the B<apacheconf>
> flag.  The configuration text is passed to standard output.
> 
> =item * Autochange: update db format schemas used by subversion repositories
> 
> Subversion repositories are updated from an older database format to a
> newer database format.  This functionality is invoked by the B<autochange>
> flag.  The manual procedure for this is:
> 
> =over 4
> 
> C<svnadmin1 dump reposname E<gt> reposname.dump>
> 
> C<svnadmin2 load reposname E<lt> reposname.dump>
> 
> =back
> 
> where C<svnadmin1> and C<svnadmin2> are the old and new binary B<svnadmin>
> executables respectively.  C<svnadmin1> is specified by the
> B<oldsvnadminpath> variable.  C<svnadmin2> is specified by the
> B<svnadminpath> variable (or, if not specified, by the default location
> in the shell command path).
> 
> =item * Backup by generating plain-text files for each subversion repository
> 
> This dumps (creates) plain-text repository backup files for every specified
> subversion repository.  This functionality is invoked by the B<backup> flag.
> The list of generated backup files is sent to standard output.
> 
> =item * Print out repository information (printf)
> 
> This functionality is invoked by the B<printf> command line argument
> (and this is also the default functionality if no functionality is
> specified).  The repository locations (and potentially other information)
> is output to standard output.
> 
> =back
> 
> =cut
> 
> use Getopt::Long; # Get specified options from the command line.
> 
> # ============================= Process command-line arguments and error-check.
> my $usage=(<<END);
> Usage of svn_filesystem_doctor.
> 
> SYNOPSIS
>     svn_filesystem_doctor [ --printf="*string*" ]
>     [ --oldsvnadminpath="*command_path*" ]
>     [ --svnadminpath="*command_path*" ] [ --autochange ] [ --backup ]
>     [ --stdin ] [ --findall="*starting_path*" ] [ --apacheconf ]
> 
>     At minimum, either stdin or the findall flag must be specified in order
>     to launch svn_filesystem_doctor.
> 
>     The printf *string* can consist of the following escaped characters:
> 
>     %d  Directory path to a subversion repository.
> 
>     %s  The format schema of the subversion repository. A value of "0N"
>         means that the format schema equals version 0 that it does not work
>         with the current svnadmin command. A value of "0Y" means version 0,
>         and that it does work with the current svnadmin command. A value of
>         "13Y" means version 13 and that it does work with the current
>         svnadmin command. And so on.
> 
> DESCRIPTION
>     Looks at an existing filesystem and diagnoses the locations and states
>     of various subversion repositories (and this means "repositories", not
>     working copies). This program also facilitates the generation of
>     plain-text backups as well as upgrading the format db schema based on
>     new releases of subversion.
> 
>   Getting the subversion repositories
> 
>     The findall and stdin flags control the repositories that this script
>     works with. The findall flag will probe the entire filesystem and look
>     for likely locations of subversion repositories (using heuristics
>     related to directory structure and also applying the "svnadmin youngest"
>     command. The stdin flag will alternatively accept a list of subversion
>     directory filesystem paths (for which to apply the --printf,
>     --autochange, or other functionalities).
> 
>   Locating the svnadmin executable
> 
>     The svnadminpath and oldsvnadminpath flags specify the location of the
>     svnadmin executables necessary to implement various svn_filesystem_doctor
>     functionalities. Ordinarily, just the svnadminpath variable would need
>     to be specified (if it is not specified, the regular shell command path
>     is used). The oldsvnadminpath variable is specified for situations where
>     the older version of svnadmin is needed to perform db format schema
>     upgrades ("oldsvnadmin dump" followed by a "currentsvnadmin load")....
> 
>   Functionalities of svn_filesystem_doctor
> 
>     * Generate an apache configuration file
>         From the determined list of subversion repositories, an apache
>         configuration text string is generated. This functionality is
>         invoked by the apacheconf flag. The configuration text is passed to
>         standard output.
> 
>     * Autochange: update db format schemas used by subversion repositories
>         Subversion repositories are updated from an older database format to
>         a newer database format. This functionality is invoked by the
>         autochange flag. The manual procedure for this is:
> 
>             "svnadmin1 dump reposname > reposname.dump"
> 
>             "svnadmin2 load reposname < reposname.dump"
> 
>         where "svnadmin1" and "svnadmin2" are the old and new binary
>         svnadmin executables respectively. "svnadmin1" is specified by the
>         oldsvnadminpath variable. "svnadmin2" is specified by the
>         svnadminpath variable (or, if not specified, by the default location
>         in the shell command path).
> 
>     * Backup by generating plain-text files for each subversion repository
>         This dumps (creates) plain-text repository backup files for every
>         specified subversion repository. This functionality is invoked by
>         the backup flag. The list of generated backup files is sent to
>         standard output.
> 
>     * Print out repository information (printf)
>         This functionality is invoked by the printf command line argument (and
> 	this is also the default functionality if no functionality is
>         specified).  The repository locations (and potentially other
>         information) is output to standard output.
> 
> END
> my %h; # This has will store the command line options values.
> my $retval = &GetOptions(\%h,
> 			 "printf=s","oldsvnadminpath=s","svnadminpath=s",
> 			 "autochange","backup","findall=s","stdin",
> 			 "apacheconf");
> 
> # Command option syntax must be correct.
> unless ($retval)
>   {
>     print($usage);
>     exit(1);
>   }
> 
> # At minimum, either the findall or the stdin flag needs to be specified
> # (so that a list of repositories can be obtained to work on).
> unless ($h{'findall'} or $h{'stdin'})
>   {
>     print($usage);
>     exit(1);
>   }
> 
> # Both findall and stdin flags cannot be specified together.
> if ($h{'findall'} and $h{'stdin'})
>   {
>     print('findall and stdin cannot both be specified'."\n");
>     print($usage);
>     exit(1);
>   }
> 
> # If specified, the findall path should exist on the filesystem.
> if (defined($h{'findall'}))
>   {
>     unless (-e $h{'findall'})
>       {
> 	print('The findall variable does not exist on the'.
> 	      ' filesystem'."\n");
> 	print($usage);
> 	exit(1);
>       }
>   }
> 
> # If specified, the oldsvnadminpath should exist on the filesystem.
> if (defined($h{'oldsvnadminpath'}))
>   {
>     unless (-x $h{'oldsvnadminpath'})
>       {
> 	print('The oldsvnadminpath variable does not exist as an executable '.
> 	      'on the filesystem'."\n");
> 	print($usage);
> 	exit(1);
>       }
>   }
> 
> # If specified, the findall path should exist on the filesystem.
> if (defined($h{'svnadminpath'}))
>   {
>     unless (-x $h{'svnadminpath'})
>       {
> 	print('The svnadminpath variable does not exist as an executable on '.
> 	      ' the filesystem'."\n");
> 	print($usage);
> 	exit(1);
>       }
>   }
> 
> # If autochange is specified, then oldsvnadminpath should be specified.
> if ($h{'autochange'})
>   {
>     unless ($h{'oldsvnadminpath'})
>       {
> 	print('For autochange, the oldsvnadminpath value must be specified.'.
> 	      "\n");
> 	print($usage);
> 	exit(1);
>       }
>   }
> 
> # ==================== Gather the list of subversion repositories to work with.
> my @subversion_repository_list;
> if ($h{'stdin'}) # Subversion repository directory list coming through stdin?
>   {
>     my @a = <>;
>     @subversion_repository_list = map {chomp; $_} @a;
>   }
> elsif ($h{'findall'}) # Scan, starting from specified location in filesystem.
>   {
>  my @a = `find $h{'findall'} -maxdepth 1000 -type d -name "hooks" 2>/dev/null`;
>     foreach my $possible (@a)
>       {
> 	chomp($possible);
> 	$possible =~ s/\/[^\/]*$//;
> 	opendir(SDIR,$possible);
> 	my @otherdirs = grep {!/^\.\.?$/} readdir(SDIR);
> 	closedir(SDIR);
> 	my $score = 0; # The "heuristical measure" as to whether = svn repos. 
> 	foreach my $odir (@otherdirs)
> 	  {
> 	    if ($odir eq 'locks')
> 	      {
> 		$score++;
> 	      }
> 	    if ($odir eq 'db')
> 	      {
> 		$score++;
> 	      }
> 	  }
> 	if ($score > 1) # Score is good?
> 	  {
> 	    push(@subversion_repository_list,$possible); # Add to list.
> 	  }
>       }
>   }
> 
> # ============================================ Locate the svnadmin executables.
> my $oldsvnadmin; # Set to the svnadmin command (of old database format schema).
> my $currentsvnadmin;# Set to the svnadmin command (of desired format schema).
> 
> # Set the variables.
> if ($h{'oldsvnadminpath'})
>   {
>     $oldsvnadmin = $h{'oldsvnadminpath'};
>   }
> if ($h{'svnadminpath'})
>   {
>     $currentsvnadmin = $h{'svnadminpath'};
>   }
> else
>   {
>     $currentsvnadmin = 'svnadmin';
>     system("$currentsvnadmin --version 2>/dev/null");
>     if ($? == 127)
>       {
> 	print('Cannot find the current svnadmin command.'."\n");
> 	exit(1);
>       }
>   }
> 
> # ================================== Determine the function(s) to be performed.
> my @functions; # List of functions to perform on the repository list.
> if ($h{'printf'})
>   {
>     push(@functions,'printf');
>   }
> if ($h{'autochange'})
>   {
>     push(@functions,'autochange');
>   }
> if ($h{'backup'})
>   {
>     push(@functions,'backup');
>   }
> if ($h{'apacheconf'})
>   {
>     push(@functions,'apacheconf');
>   }
> 
> if (!@functions) # printf is the default
>   {
>     push(@functions,'printf');
>   }
> 
> # ========================================================= Carry out the task.
> foreach my $function (@functions)
>   {
>     if ($function eq 'printf') # Output information.
>       {
> 	foreach my $repos (@subversion_repository_list)
> 	  {
> 	    my $p = $h{'printf'};
> 	    unless ($p)
> 	      {
> 		$p = $repos."\n";
> 	      }
> 	    else
> 	      {
> 		$p =~ s/^\"//;
> 		$p =~ s/\"$//;
> 		$p =~ s/\\t/\t/g;
> 		$p =~ s/\\n/\n/g;
> 		$p =~ s/\%d/$repos/g;
> 	      }
> 	    if ($p =~ /\%s/)
> 	      {
> 		my $format;
> 		if (-e "$repos/format")
> 		  {
> 		    $format = `cat $repos/format`;
> 		    chomp($format);
> 		  }
> 		else
> 		  {
> 		    $format = 0;
> 		  }
> 		$p =~ s/\%s/$format/g;
> 	      }
> 	    print($p);
> 	  }
>       }
>     if ($function eq 'backup') # Create plaintext backups (svnadmin dump).
>       {
> 	my $timestamp = `date +"%Y%m%d%H%M%S"`;
> 	chomp($timestamp);
> 	foreach my $repos (@subversion_repository_list)
> 	  {
> 	    system("$currentsvnadmin dump $repos > $repos.$timestamp.dump");
> 	    if ($?)
> 	      {
> 		print('FAILURE:'.$repos."\n");
> 	      }
> 	    else
> 	      {
> 		print('SUCCESS:'.$repos."\n");
> 		print('(RESTORE):'.
> 		      "mv $repos $repos.old; $currentsvnadmin create $repos; ".
> 		      "$currentsvnadmin load $repos < $repos.$timestamp.dump".
> 		      "\n");
> 	      }
> 	  }
>       }
>     if ($function eq 'autochange') # Try to convert database format schemas.
>       {
> 	my $timestamp = `date +"%Y%m%d%H%M%S"`;
> 	chomp($timestamp);
> 	foreach my $repos (@subversion_repository_list)
> 	  {
> 	    system("$oldsvnadmin dump $repos > $repos.$timestamp.dump");
> 	    system("mv $repos > $repos.$timestamp.old") unless $?;
> 	    system("$currentsvnadmin create $repos") unless $?;
> 	    system("$currentsvnadmin load $repos < $repos.$timestamp.dump")
> 		unless $?;
> 	    system("rm -f $repos.$timestamp.old") unless $?;
> 	    if ($?)
> 	      {
> 		print('FAILURE:'.$repos."\n");
> 	      }
> 	    else
> 	      {
> 		print('SUCCESS:'.$repos."\n");
> 	      }
> 	  }
>       }
>     if ($function eq 'apacheconf') # Generate an apache configuration.
>       {
> 	my $timestamp = `date +"%Y%m%d%H%M%S"`;
> 	foreach my $repos (@subversion_repository_list)
> 	  {
> 	    my $reposdir = $repos;
> 	    $reposdir =~ s/^.*\/([^\/]*)$/$1/;
> 	    print(<<END);
> <Directory $repos>
>     Options FollowSymLinks Indexes
>     AllowOverride All
> </Directory>
> <Location /svn/$reposdir>
>    DAV svn
>    SVNPath $repos
> 
>    # Limit write permission to list of valid users.
>    <LimitExcept GET PROPFIND OPTIONS REPORT>
>       # Require SSL connection for password protection.
>       # SSLRequireSSL
> 
>       AuthType Basic
>       AuthName "Authorization Realm"
>       AuthUserFile /subversion_users/passwdfile
>       Require valid-user
>    </LimitExcept>
> </Location>
> END
>           }
>       }
>   }
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
> For additional commands, e-mail: dev-help@subversion.tigris.org

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org