#!/bin/bash
# ==========
# $File: //guest/amo/scripts/stream-hierarchy.sh $
# $Revision: #1 $
# $Change: 24203 $
#
# $Author: amo $
# $DateTimeTZ: 2018/06/12 03:39:29 -0700 PDT $
# ==========
# PURPOSE
# Identify and extract a streams hierarchy from one server, and creating same on another server.
# -----------
# ASSUMPTIONS
# - the machine on which the extraction is carried out has access to the server from which the data is to be extracted
# - the machine on which the insertion is carried out has access to the server into which the data is to be inserted
# - a 2016.1 or later 'p4' client application is on this machine (the '-F' flag requires '16.1+)
# -----------
# The extraction process is as follows:
# - create a directory into which various files will be written;
# - extract the depot spec;
# - find all streams that match a given streams path, and write each spec to a separate file;
# - find all 'mainline' streams (or those without parent) and write each stream name to a file;
# - find all streams with a parent in the previously-created file, and write each stream name to another file - repeat;
# - halt once all the streams have been recorded (an empty file is the last created, for example);
# - package up the directory containing these lists of streams and the stream-spec files.
# -----------
# The insertion process is more or less the reverse of the above:
# - deliver the 'transfer' archive to a location where the data can be added to the target server;
# - unpack the archive;
# - create the depot spec from the file created;
# - iterate through the lists of streams, again in hierarchical order, starting with the lowest numbered list.
# -----------
# These two sequences complete the task as expected, although the process is not perfect.
# It is less of a 'script' and more of a sequence of commands.
# Things to add (some nice-to-have, some required):
# - error/exception handling;
# - improved method for looping through the various lists;
# - consider a rewrite using a different scripting language with better Perforce-ness: 'P4Python', for example?
#
# ==========
# Parameters
# task: either "extract" or "insert"
# strdepot: stream depot name
task=$1
strdepot=$2
function writeError() {
# messages
usage="USAGE: $0 extract|insert streamDepotName"
param="ERROR: Expecting two parameters, the task (extract or insert) and the streams depot name"
no_p4="ERROR: 'p4' client not found on this machine."
nodep="ERROR: Unable to find stream depot '$strdepot'"
ntask="ERROR: '$task' unknown - should be 'extract' or 'insert'"
unkno="ERROR: unknown event $1"
echo $usage
case $1 in
nameonly ) exit 0
;;
parameters ) echo $param; exit 1
;;
nop4client ) echo $nop4; exit 2
;;
nodepot ) echo $nodep; exit 3
;;
unknowntask ) echo $ntask; exit 4
;;
* ) echo $unkno; exit 99
;;
esac
}
# parameter check - none
if [ "$#" -eq 0 ]; then writeError nameonly; fi
# parameter check - wrong number of parameters
if [ "$#" -ne 2 ]; then writeError parameters; fi
# does 'p4' exist?
p4cli=`which p4`
if [ -z "$p4cli" ]; then writeError nop4client; fi
# parameter check - can we find the stream depot specified?
streamdepot=`$p4cli -ztag -F %name% depots -t stream -e $strdepot`
if [ -z "$streamdepot" ]; then writeError nodepot; fi
unset streamdepot
# If we've got this far without error, start the process - with an implied parameter check on 'task'
# DATA EXTRACTION
if [ "$task" -eq "extract" ]; then
exdepot="extract"
# create directory and switch into this location
mkdir -p $exdepot/$strdepot
cd $exdepot
# write depot spec to file
$p4cli depot -o $strdepot > $strdepot/$strdepot.depot.spec
# identify streams, write each to file.
# A stream called "//streamDepotName/myStream" would be written to "streamDepotName/myStream.spec"
for X in `$p4cli -ztag -F %Stream% streams //$strdepot/...`; do
$p4cli stream -o $X > `echo $X | sed -e 's/^\/\///g'`.spec;
done
# write a list of 'mainline' streams - those without parent stream
# Note: to include task streams with no parent, change "-F Type=mainline" for "-F Parent=none"
$p4cli -ztag -F %Stream% streams -F Type=mainline //$strdepot/... > streamspecs.0
# read the previous 'streamspecs' file, identifying all those with a parent in the aforementioned file
while read STREAM; do
$p4cli -ztag -F %Stream% streams -F Parent=$STREAM
done < streamspecs.0 > streamspecs.1
while read STREAM; do
$p4cli -ztag -F %Stream% streams -F Parent=$STREAM
done < streamspecs.1 > streamspecs.2
while read STREAM; do
$p4cli -ztag -F %Stream% streams -F Parent=$STREAM
done < streamspecs.2 > streamspecs.3
# repeat until the 'streamspecs' file being created is empty - no more streams with parent from prior list
# up one level, and package up the 'exdepot' folder
cd ..
tar -czvf $exdepot.tgz $exdepot
# DATA INSERTION
else if [ "$task" -eq "insert" ]; then
# unpack the files
tar -zxvf $exdepot.tgz
# change to the 'exdepot' directory created by the above command
cd $exdepot
# create the 'streamDepotName' depot from the depot spec saved
$p4cli depot -i < $strdepot/$strdepot.depot.spec
# starting with 'mainline' streams, create streams specs from the spec files
while read STREAM; do
SPEC=`echo $STREAM | sed -e 's/^\/\///g'`.spec
cat $SPEC | $p4cli stream -i
done < streamspecs.0
while read STREAM; do
SPEC=`echo $STREAM | sed -e 's/^\/\///g'`.spec
cat $SPEC | $p4cli stream -i
done < streamspecs.1
while read STREAM; do
SPEC=`echo $STREAM | sed -e 's/^\/\///g'`.spec
cat $SPEC | $p4cli stream -i
done < streamspecs.2
while read STREAM; do
SPEC=`echo $STREAM | sed -e 's/^\/\///g'`.spec
cat $SPEC | $p4cli stream -i
done < streamspecs.3
# repeat for all 'streamspecs' files provided
# $task is neither 'extract' or 'insert' - end of implied parameter check
else
writeError unknowntask
fi
echo END OF PROCESSING