p4_get #5

  • //
  • guest/
  • barrie_slaymaker/
  • safari/
  • src/
  • conf/
  • bin/
  • p4_get
  • View
  • Commits
  • Open Download .zip Download (5 KB)
#!/usr/bin/perl -w

#
# p4_get for Safari
# Copyright (c) 1999 by Barrie Slaymaker, [email protected]
#
# You may distribute under the terms of either the GNU General Public
# License or the Artistic License, as specified in the README file.
#
#
# Gets all files from a labelled version in to a subdirectory
#
# The subdirectory must be provided as the last argument, the
# list of files to get is read from stdin or from a file named in ARGV.
# The list of files should be the output of the 'p4 files' command.
#

use strict ;
use Getopt::Long ;
use File::Basename ;
use File::Path ;
use File::Copy ;

my @options = (
   'rev|r=s',
   'p4-file-list|l=s',
   'out-file|o=s',
) ;

my $options = {} ;

GetOptions( $options, @options ) ;

my $progname = basename( $0 ) ;

die "no targets specified"
   unless @ARGV ;

my $rev = $options->{'rev'} ;
$rev = '_head'
   unless defined( $rev ) && length( $rev ) ;
$rev = "_$rev"
   if $rev =~ /^(?:\d+|head)$/ ;
$rev =~ s/^#/_/;
 
my $out_file= $options->{'out-file'} ;
$out_file = ''
   unless defined( $out_file ) && length( $out_file ) ;

my $p4_file_list = $options->{'p4-file-list'} ;
$p4_file_list = ''
   unless defined( $p4_file_list ) && length( $p4_file_list ) ;

my $p4_files = get_p4_files() ;

# print( join( "\n", map { $_->[0] . '#' . $_->[1] } @$p4_files ) ) ;

#
# Scan arg list, then find matching files.  This makes the order
# of the resulting fetches more expected than the other way.
#
while ( @ARGV ) {
   my $target = pop @ARGV ;
   $target =~ s@/\.\.\.$@@ ;
   $target =~ s@^//?@@ ;

   my $target_name_length = length( $target ) ;

   for ( @$p4_files ) {
      my $p4_name = $_->[0] ;
      my $p4_rev  = $_->[1] ;
      die "undefined p4_name" unless defined $p4_name ;
      die "undefined file revision" unless defined $p4_rev ;
      my $file_rev = $p4_rev ;
      $file_rev =~ s/^#/_/ ;

      my $target_name = $p4_name ;
      $target_name =~ s@^//?@@ ;

      next unless substr( $target_name, 0, $target_name_length ) eq $target ;

      my $p4_rev_file_name = "$p4_name$p4_rev" ;
      my $rev_target_name  = "$file_rev/$target_name" ;
      my $out_file_name      = 
	 $out_file eq '' || $out_file eq '-' ?
	 "$rev/$target_name" :
	 $out_file ;
      get_file( $p4_rev_file_name, $rev_target_name ) ;

      if ( $rev_target_name ne $out_file_name ) {
         if ( -f $out_file_name ) {
            unlink $out_file_name or
               die "$: unlink $out_file_name" ;
         }
         else {
	    my ( undef, $dir ) = fileparse( $out_file_name ) ;
            mkpath( $dir, 0, 0775 ) ;
         }

	 link( $rev_target_name, $out_file_name ) or
	    die "$!: link( $rev_target_name, $out_file_name )" ;
#	 copy( $link, $out_file_name ) or
#	    die "$!: copy( $link, $out_file_name )" ;
#         my @chunks = split( '/', $dir ) ;
#	 my $updirs = '../' x @chunks ;
#         my $link = "$updirs$rev_target_name" ;
#	 if ( ! -l $out_file_name || $link ne readlink $out_file_name ) {
##	    print $link, '<=>', readlink $out_file_name, "\n" ;
#	    unlink( $out_file_name ) ;
#	    mkpath( $dir, 0, 0775 )
#	       unless -d $dir ;
#            print( "$prog_name: Linking $out_file_name -> $rev_target_name\n" ) ;
#	    symlink( $link, $out_file_name ) or
#	       die "$!: symlink( $link, $out_file_name )" ;
##	    print $link, '<=>', readlink $out_file_name, "\n" ;
#         }
      }
   }
}   

0 ;

##############################################################################


sub get_p4_files {
   my $file_list_name = $options->{'p4-file-list'} ;

   my ( undef, $file_dir ) = fileparse( $file_list_name ) ;
   mkpath( $file_dir, 0, 0775 )
      unless -d $file_dir ;

   my $p4 ;

   if ( defined $file_list_name && -f $file_list_name ) {
      $p4 = $file_list_name ;
      open( P4, "<$p4" ) or die "$!: $p4" ;
   }
   else {
      # Clean up the rev since "#" is passed in as an underscore
      my $p4_rev = $rev ;
      $p4_rev =~ s/^_/#/ ;

      $p4 = "p4 files //...$p4_rev" ;
      print( "Getting '$p4' list\n" ) ;

      open( P4, "$p4 |" ) or die "$!: p4 files command" ;
   }

   my $p4_files = [] ;

   my $none_such ;

   while ( <P4> ) {
      chomp ;
      my ( $name, $rev, $action, $desc ) = /^([^#]+)(#\d+)\s+-\s+(\w+)\s+(.*)/ ;
      next unless defined $desc && $action ne 'delete' ;
      push( @$p4_files, [ $name, $rev, $action, $desc ] ) ;
   }
   die "$!: $p4"
      unless close( P4 ) ;

   return $p4_files ;
}

################################

sub get_file {
   my ( $p4_name, $file_name ) = @_ ;

   if ( -f $file_name ) {
#      print( "$progname: $file_name exists\n" ) ;
      return
   }

   my ( undef, $dir ) = fileparse( $file_name ) ;
   mkpath( $dir, 0, 0775 ) 
      unless -d $dir ;

   open( OUTPUT, ">$file_name" ) or
      die "$! opening $file_name" ;

   my $p4 = "p4 print $p4_name |" ;
   print( "$progname: $file_name\n" ) ;
#      print( '.' ) ;
   open( P4, $p4 ) or
      die "$!: $p4" ;
   my $first_line = <P4> ;
#   print $first_line ;
   $\ = undef ;
   while (<P4>) {
      print OUTPUT $_ or
	 die "$!" ;
   }
   unless ( close( OUTPUT ) ) {
      my $msg = $! ;
      print "$progname: unlinking $file_name\n" ;
      unlink( $file_name ) or
         print STDERR "$progname: $! unlinking $file_name\n" ;
      die "$msg closing $file_name" ;
   }
   unless( close( P4 ) ) {
      my $code = $? ;
      print "$progname: unlinking $file_name\n" ;
      unlink( $file_name ) or
         print STDERR "$progname: $! unlinking $file_name\n" ;
      die "$p4 returned $code" ;
   }
}
# Change User Description Committed
#5 202 Barrie Slaymaker Converted to use hard links instead of symlinks or copies when
making @something/......  from _1/...... in the interests of
saving disk space and of allowing tar to archive something
other than a bunch of symlinks when taring up a directory.
#4 178 Barrie Slaymaker Modified cgimake to get the project name out of the target
       name if one isn't supplied. This makes it so that Apache's
       mod_rewrite is no longer needed to extract the project name
       from the URL and place it in the QUERY_STRING, and so that
       you can call cgimake from the command line and place the
       project name in the target path:

          cgimake /perl/_head/Default/depot/

       Modified cgimake to work easily from the command line

       Fixed some minor bugs in assembling paths that were causing
       // to appear in paths when no project is specified.

       Fixed minor bug that cause cgimake to try to read a
       bogus config file when there is no $project

       Tweaked p4_get to provide a more reasonable level of
       verbosity.

       Updated the apache doc to reflect the simpler,
       non-rewrite technique.

       Added targets to fetch a new _head revision if the
       head change number has changed.  Need to check in p4_update.
#3 168 Barrie Slaymaker Added YAPC paper, slides
#2 165 Barrie Slaymaker Applied Greg KH's license patch.
#1 162 Barrie Slaymaker First code & documentation checkin