#!/bin/sh

# rcstoperf - copy and convert an RCS or CVS tree into a PERFORCE tree
#
# $Id: //info.ravenbrook.com/project/mps/tool/rcs-import/rcstoperf.sh#2 $
#
# Adapted from
# ftp://ftp.perforce.com/pub/perforce/r99.1/tools/convert/rcs/rcstoperf.sh
# (NDL 2001-08-15)  
#
# Id: //depot/r99.1/p4-tools/convert/rcs/rcstoperf.sh#2  -- for 97.3 or later.
#
# Usage:
#
#	rcstoperf [ options ] OldRcsTree NewP4Root 
#
# Without options, it links the RCS tree over and loads all the metadata.
# If you're running this on Windows you will likely have to specify "-copy".
# The following options can override the default:
#
#       -copy           Copy the old RCS tree in under the new PERFORCE root
#	-clean		Delete all old depot metadata
#	-next change	Start with change # for incremental conversion
#
# You can also select which phases of the conversion are to take place:
#
#	-nocopy		Skip the copy/symlink phase
#	-extract	Extract the data from the RCS files
#	-changes	Cross reference extract data into changes
#	-meta		Build new PERFORCE metadata
#	-load		load metadata into PERFORCE files
#
# The RCS tree is linked in under _NewP4Root_/depot/IMPORT.  This tree
# is never updated (by PERFORCE): updates go into _NewP4Root_/depot/main.
# -symlink (the default) can only be used for a one-shot conversion
# (not for incremental conversions.)
#
# NOTE: You *must* leave the RCS files in the IMPORT directory,
# or symlinked via the IMPORT directory, since otherwise it is possible
# that Perforce will overwrite existing revisions!  In general, do
# not touch anything under the Perforce server root without contacting
# support@perforce.com first.

# Process options

mode="-symlink"
defphases="-extract -changes -meta -load"
usage="usage: rcstoperf [ $defphases ] OldRcsTree NewP4Root"
next=1

while :
do case $1 in

-copy | -symlink | -nocopy)
        mode=$1
        shift;;

-clean)
	clean=yes
	shift;;

-next)
	shift
	if [ $mode = '-symlink' ]          # NDL 2001-08-16 allow -nocopy
	then
	    echo "Use of -symlink incompatible with incremental conversion"
	    exit 1
	fi
	next=$1
	shift;;

# NDL 2001-08-14 - added -halt option, to allow me to run -copy and then quit.
-extract | -changes | -meta | -load | -halt)
	phases="$phases $1"
	shift;;

-*)	echo $usage; exit 1;;

*)	break;;

esac done

if [ $# != 2 ] 
then echo $usage; exit 1
fi

P4Root=$2

#
# Make sure the new p4 root is there.

[ -d "$P4Root" ] || mkdir "$P4Root" || exit 1
[ -d "$P4Root"/depot ] || mkdir "$P4Root"/depot || exit 1

# Make sure if incremental conversion, previous conversions did not symlink
if [ -r "$P4Root"/depot/.symlink -a  $next -gt 1 ] 
then
    echo "Incremental conversion incompatible with previous -symlink"
    exit 1
fi

#
# Temp files for conversion.  EXTRACT & META can get big.  
# Expect 15% - 30% of the RCS tree size.
#

CHANGES=$P4Root/tmp.changes
EXTRACT=$P4Root/tmp.extract
META=$P4Root/tmp.meta

# make sure Rcs tree is there
RcsTree=`cd "$1";pwd` || exit

#
# If they provide no options, we'll delete the temp files when
# done.
#

if [ -z "$phases" ]
then
    #trap 'rm -f "$META" "$CHANGES" "$EXTRACT"' 0
    phases=$defphases
fi

#
#  Process each option
#

for phase in $mode $phases
do case $phase in

-extract)

    #
    # Extract the data in the RCS files
    #

    echo "Building RCS metadata from $RcsTree..." 1>&2

    ( 
	    cd "$RcsTree"
	    # NDL 2001-08-14 added explicit -r argument to p4d - without it we get
	    #  "open for read: src/than.c,v: The system cannot find the path specified"
	    find * -name "*,v" -print | sed 's/\(.*\),v/"\1"/' | xargs p4d -r . -m 
    ) > "$EXTRACT"
    ;;

-changes)

    #
    # Now pass through the file again and generate the checkpoint file
    # Build change numbers according to uniq description/user during a
    # date period.  Limit the time gap for a single change to be 1
    # minute.
    #

    echo 'cross referencing changes into atomic actions...' 1>&2

    awk '$1 == "@change@" { print $2, $3, $4 }' "$EXTRACT" | sort -n | 
    awk "
	BEGIN { c = $next - 1 }
	\$1 > d + 60 || \$2\$3 != old { ++c; old=\$2\$3 } 
	{ print c, \$1,\$2,\$3; d = \$1; }
    " > "$CHANGES"
    ;;

-meta)

    #
    # Now pass through the file again and generate the checkpoint file
    #

    echo 'building p4 metadata checkpoint file...' 1>&2

    ( cat "$CHANGES"; echo "@---@"; sed 's:\(@//[^ @]*\) :\1!!!:g' "$EXTRACT" ) | 
    awk '

	    $0 == "@---@" { 
		print "@put@ @db.counters@ @change@", lastChange
		++state
		next 
	    }

	    state == 0 { 

		seenChange[$1] = 0;
		lastChange = $1;
		changeTable[ $2$3$4 ] = $1;
		next
	    }

	    state == 1 && $1 == "@rev@" {

		change = changeTable[ $6$9$10 ];

		print "@put@ @db.rev@", $2, $3, 0, $4, $5, change, $6, $7, $8, 0
		print "@put@ @db.revcx@", change, $2, $3, $5

		next;
	    }

	    state == 1 && $1 == "@integ@" {

		print "@put@ @db.integ@", $2, $3, $4, $5, $6,$7, $8, $9,$10
		next;
	    }

	    state == 1 && $1 == "@label@" {

		if( $6 > labelDate[ $2 ] )
		    labelDate[ $2 ] = $6;

		print "@put@", "@db.have@", $3, $4, $5

		next
	    }

	    state == 1 && $1 == "@change@" {

		change = changeTable[ $2$3$4 ]

		if( seenChange[ change ] )
		{
		    if( $5 == "@" && NF == 5 || $NF !~ /@[[:space:]]*$/ )
			skipping = 1;

		    next;
		}

		seenChange[ change ] = 1;

		d = ""; for( i = 5; $i != ""; i++ ) d = d $i " ";
		subd = substr( d, 1, 31 );
		gsub( /@/, "", subd );
		subd = "@"subd"@"

		print "@put@ @db.change@", change, change, \
			"@cvs@", $4, $2, 1, subd
		print "@put@ @db.desc@", change, d

		# Turn on printing if this change description spans
		# more than one line.

		if( $5 == "@" && NF == 5 || $NF !~ /@[[:space:]]*$/ )
		    printing = 1;

		next;
	    }

	    state == 1 && skipping == 1 {
		if( $NF ~ /@[[:space:]]*$/ )
		    skipping = 0;

		next;
	    }

	    state == 1 && printing == 1 {
		print

		if( $NF ~ /@[[:space:]]*$/ )
		    printing = 0;

		next;
	    }

	    END {
		for( l in labelDate )
		    print "@put@ @db.domain@", l, 108, "@@ @@ @cvs@", \
			    labelDate[ l ], 0, "@Imported from CVS.@"
	    }
    ' | sed 's/!!!/ /g' > "$META"
    ;;

-load)

    #
    # Now load the metadata into the p4 files.
    # We do this twice, more or less to sort it.  The db files are
    # alot smaller with sorted data.
    #

    echo 'Load p4 metadata checkpoint file...' 1>&2

    [ $clean ] && rm -f "$P4Root"/db.* "$P4ROOT"/checkpoint.*
    rm -f "$P4Root"/tmp.checkpt
    p4d -r "$P4Root" -jr tmp.meta
    p4d -r "$P4Root" -jd tmp.checkpt
    rm -f "$P4Root"/db.*
    p4d -r "$P4Root" -jr tmp.checkpt
    ;;

-copy)
    #
    # Copy the RCS source tree to the depot.
    #

    echo 'Copying RCS files...' 1>&2

    [ -d "$P4Root"/depot/IMPORT ] || mkdir "$P4Root"/depot/IMPORT || exit 1
    cp -r "$RcsTree"/* "$P4Root"/depot/IMPORT

    rm -f "$P4Root"/depot/.symlink

    ;;

-symlink)
    #
    # Link the RCS tree into the depot
    #

    echo 'Linking RCS tree...' 1>&2

    ln -s "$RcsTree" "$P4Root"/depot/IMPORT
    touch "$P4Root"/depot/.symlink
    ;;

esac done
