#!/bin/bash
# ==========
# $File: //guest/adam_morriss/scripts/stream-hierarchy.sh $
# $Revision: #3 $
# $Change: 23302 $
#
# $Author: amo $
# $DateTimeTZ: 2017/11/30 09:40:44 -0800 PST $
# ==========
# PURPOSE
# Identify and extract a streams hierarchy from one server, and creating them on another.
# -----------
# 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 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
# messages
usage="Usage: $0 extract|insert streamDepotName"
param="Expecting two parameters, the task (extract or insert) and the streams depot name"
ntask="'$task' unknown - should be 'extract' or 'insert'"
nop4="'p4' client not found on this machine."
nodep="Unable to find stream depot '$strdepot'"
# parameter check - none
if [ "$#" -eq 0 ]; then
echo $usage
exit 0
fi
# parameter check - wrong number of parameters
if [ "$#" -ne 2 ]; then
echo $usage
echo $param
exit 1
fi
# does 'p4' exist?
p4cli=`which p4`
if [ -z "$p4cli" ]; then
echo $usage;
echo $nop4;
exit 3;
fi
# parameter check - can we find the stream depot specified?
streamdepot=`$p4cli -ztag -F %name% depots -t stream -e $strdepot`
if [ -z "$streamdepot" ]; then
echo $usage;
echo $nodep;
exit 4;
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
else # $task is neither 'extract' or 'insert' - end of implied parameter check
echo $usage
echo $ntask
exit 2
fi