Branching Wrapper

Branch Both the Underlying DM and PI

Branching in Perforce IPLM is agnostic to branching the underlying DM system. This requires customers to write their own DM branching routine (P4 'integrate'/'populate', svn 'copy' for example). This script can be used as a highly functional starting point to help with this. The script below is self contained and works out of the box, but it can be modified to suit your needs.

This script performs the following steps:

  • Create a workspace with the source IP on the release specified (LATEST release if not specified)
  • Update the source client to include the branch location
  • Create a P4 label (svn tag) of the files in the workspace
  • Integrate the label from source to branch location
  • Run the 'pi ip copy' command to create the same branch in PI
  • Clean up the workspace, label etc.

Although the script below is designed to work with P4 as DM backend, the same procedure will also work for other DM systems (e.g. SVN).

Branching script
#!/usr/bin/perl 
# -*- coding: utf-8 -*-
################################################################################
# Copyright (c) 2010-2016 Perforce, Inc.
# All Rights Reserved.
#
# This source file is confidential and the proprietary information of
# Perforce, Inc. and its receipt or possession does not convey any rights to
# reproduce or disclose its contents, or to manufacture, use or sell anything
# it may describe. Reproduction, disclosure or use without Perforce, Inc.
# specific written authorization is strictly forbidden.
###############################################################################

use strict;
use warnings;

sub print_help {
    print "This script creates a workspace with the specified IPV\n";
    print "and then creates a new line of the IP by first copying\n";
    print "P4 files over to that location and then branching PI\n";
    print "    Usage: $0 LIB.IP[\@VER.LINE] BRANCH_NAME P4_TARGET_PATH SCRATCH_WS_PATH [-n]\n";
    print "    Specifying '-n' at the end will show a dry-run of all the commands this script will run\n";
}

sub get_client_details {
    my $spec = shift;
    my $name = $1 if ($spec =~ /^Client:\s+(.*)$/m);
    my $src_path = $1 if($spec =~ /\s+(\/\/\S+)\s/);
    return $name, $src_path;
}

sub run_cmd {
    my $cmd = shift;
    print $cmd."\n";
    if (not $main::dry_run) {
        my $res = `$cmd 2>&1`;
        if ($?) {
            print $res;
            exit 1;
        }
        print $res if ($main::debug);
        return $res;
    }
}

if ((@ARGV != 4) && (@ARGV != 5)) { print_help(); exit 1; }

our $debug = 0;
our $dry_run = 0;
my $libip;

#########
### Basic ARG Parse
my $ip_name = $ARGV[0];
if ($ip_name =~ /\@/) {
    $libip = $`;
} else {
    $libip = $ip_name;
    $ip_name .= "\@LATEST.TRUNK";
}

my $branch_name = $ARGV[1];

my $target_base;
my $target_path = $ARGV[2];
if ($target_path =~ /\/\.\.\.$/) {
    $target_base = $`;
} else {
    $target_base = $target_path;
    $target_path .= "/...";
}

my $scratch_dir = $ARGV[3];
if (@ARGV == 5) { $dry_run = 1;}

my $cmd;
my $res;
######### 
## Create a workspace with IP in local mode

if (!-e $scratch_dir) {
    $cmd = "mkdir -p $scratch_dir";
    run_cmd($cmd);
    die ("Could not create scratch_dir $scratch_dir") if (!-e $scratch_dir);
}
chdir($scratch_dir);
$cmd = "pi ip load $ip_name --local $libip";
run_cmd($cmd);

chdir($libip);
my $pwd = `pwd`;
chomp $pwd;
my $p4 = "p4 -d $pwd ";

#########
### Get the current $p4 client spec
my $client_name = "TBD";
my $src_path = "...";

$cmd = "$p4 client -o";
my $p4_client_spec = run_cmd($cmd);
($client_name, $src_path) = get_client_details($p4_client_spec);

#########
## Update the existing client with a new line to the destination
## of the copy
my $new_view_line = "\t$target_path //$client_name/".$libip.".".$branch_name."/...\n";
my $new_client_spec = $p4_client_spec;
$new_client_spec .= $new_view_line;

my $rnd = int(rand(10000));
my $file = "/tmp/pi_p4_copy_$rnd";

open(FH, ">", $file) || die ("Could not open file $file");
print FH $new_client_spec;
close FH;

$cmd = "$p4 client -i < $file";
run_cmd($cmd);


#########
## Create a label to reflect the current state of the WS
open(FH, ">", $file) || die ("Could not open file $file");
my $label_spec = "pi_${libip}_${branch_name}";
print FH "Label:\t$label_spec\nView:\n\t$src_path\n";
close FH;

$cmd = "$p4 label -i < $file";
run_cmd($cmd);

$cmd = "$p4 labelsync -l $label_spec";
run_cmd($cmd);

#########
## Integrate across the branch using the label just created
## Submit the changes
$cmd = "$p4 integrate $src_path\@$label_spec $target_path";
run_cmd($cmd);

$cmd = "$p4 submit -d 'Integrating Branch $label_spec'";
run_cmd($cmd);

#########
## Make a branch in PI with the target
my $description = "'creating new line $libip\@.$branch_name'";
$cmd = "pi ip cp $ip_name $libip\@.$branch_name --repo-path=$target_base -d $description";
run_cmd($cmd);

$cmd = "pi ip list $libip\@.$branch_name";
my $ls = run_cmd($cmd);
print $ls;

##########################
## Cleanup
## Update the client spec back to where it was, sync the workspace etc.
open(FH, ">", $file) || die ("Could not open file $file");
print FH $p4_client_spec;
close FH;

$cmd = "$p4 client -i < $file";
run_cmd($cmd);

$cmd = "$p4 sync ...";
run_cmd($cmd);

$cmd = "$p4 label -d $label_spec";
run_cmd($cmd);

$cmd = "rm $file";
run_cmd($cmd);