You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
10724 lines
309 KiB
10724 lines
309 KiB
# _____________________________________________________________________________
|
|
#
|
|
# Purpose:
|
|
# PERL Module to handle common tasks for SDX
|
|
#
|
|
# Parameters:
|
|
# Specific to subroutine
|
|
#
|
|
# Output:
|
|
# Specific to subroutine
|
|
#
|
|
# _____________________________________________________________________________
|
|
|
|
#
|
|
# Some Global Definitions
|
|
#
|
|
$TRUE = 1;
|
|
$FALSE = 0;
|
|
$Callee = "";
|
|
|
|
package SDX;
|
|
|
|
require Win32::Mutex;
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Init
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Init
|
|
{
|
|
#
|
|
# Initialize globals
|
|
#
|
|
$main::Initializing = $main::TRUE;
|
|
$main::CreatingBranch= $main::FALSE;
|
|
$main::tmptmp = "$ENV{TMP}\\tmp";
|
|
$main::Platform = $ENV{PROCESSOR_ARCHITECTURE};
|
|
$main::StartPath = $ENV{STARTPATH};
|
|
$main::CodeBaseType = 0; # 1 == one project/depot, 2 == N projects/depot
|
|
$main::Null = "";
|
|
@main::ActiveDepots = ();
|
|
%main::DepotType = ();
|
|
@main::SDMapProjects = ();
|
|
@main::SDMapDepots = ();
|
|
@main::AllMappings = ();
|
|
@main::AllProjects = ();
|
|
@main::AllGroups = ();
|
|
@main::AllDepots = ();
|
|
@main::FileChunks = ();
|
|
$main::DepotFiles = 0;
|
|
$main::SDMapClient = "";
|
|
$main::SDMapBranch = "";
|
|
$main::SDMapCodeBase = "";
|
|
$main::SDMapCodeBaseType = "";
|
|
$main::Log = "";
|
|
$main::SDWeb = "http://sourcedepot";
|
|
$main::Files = 0;
|
|
$main::FilesResolved = 0;
|
|
$main::FilesUpdated = 0;
|
|
$main::FilesAdded = 0;
|
|
$main::FilesDeleted = 0;
|
|
$main::FilesToResolve = 0;
|
|
$main::FilesToMerge = 0;
|
|
$main::FilesNotClobbered = 0;
|
|
$main::FilesOpenAdd = 0;
|
|
$main::FilesOpenEdit = 0;
|
|
$main::FilesOpenDelete = 0;
|
|
$main::FilesReverted = 0;
|
|
$main::FilesNotConflicting = 0;
|
|
$main::FilesSkipped = 0;
|
|
$main::FilesConflicting = 0;
|
|
@main::ConflictingFiles = ();
|
|
$main::Changes = 0;
|
|
$main::IntegrationChanges = 0;
|
|
$main::LabelFilesAdded = 0;
|
|
$main::LabelFilesDeleted = 0;
|
|
$main::LabelFilesUpdated = 0;
|
|
$main::IntFilesAdded = 0;
|
|
$main::IntFilesDeleted = 0;
|
|
$main::IntFilesChanged = 0;
|
|
$main::DepotErrors = 0;
|
|
### $main::FailedSubmits = 0;
|
|
### $main::FilesLocked = 0;
|
|
|
|
$main::Mutex;
|
|
$main::HaveMutex = $main::FALSE;
|
|
|
|
%main::DepotsSeen = ();
|
|
|
|
#
|
|
# list of project names not to allow as aliases
|
|
#
|
|
%main::BadAliases =
|
|
(
|
|
alias => 1,
|
|
build => 1,
|
|
cat => 1,
|
|
cmd => 1,
|
|
cd => 1,
|
|
cp => 1,
|
|
dir => 1,
|
|
du => 1,
|
|
kill => 1,
|
|
list => 1,
|
|
ls => 1,
|
|
mv => 1,
|
|
net => 1,
|
|
rm => 1,
|
|
sd => 1,
|
|
sdx => 1,
|
|
setup => 1,
|
|
tc => 1,
|
|
vi => 1,
|
|
where => 1,
|
|
xcopy => 1
|
|
);
|
|
|
|
|
|
#
|
|
# hash of arrays of files to give the user
|
|
#
|
|
%main::SDXTools = (
|
|
toSDXRoot => [
|
|
"alias.sdx",
|
|
],
|
|
toSDTools => [
|
|
"sdx.cmd",
|
|
"sdx.pl",
|
|
"sdx.pm"
|
|
],
|
|
toSDToolsPA => [
|
|
"alias.exe",
|
|
"perl.exe",
|
|
"perlcore.dll",
|
|
"perlcrt.dll",
|
|
"sd.exe",
|
|
],
|
|
);
|
|
|
|
#
|
|
# hash of function pointers and default args
|
|
#
|
|
# command type 1 assumes the codebase type is 1 -- one project per depot
|
|
#
|
|
# if we find it's actually type 2 (N projects/depot), some of these will be
|
|
# modified later to change the scope of the command, since some commands
|
|
# (sd info, sd clients, sd branches) only make sense when reported per depot
|
|
# and are redundant when reported per project
|
|
#
|
|
# OtherOp() uses cmd type to determine whether to loop through projects and
|
|
# talk to depots by using SDPORT in SD.INI in each project root, or to
|
|
# loop through the list of enlisted depots from SD.MAP
|
|
#
|
|
%main::SDCmds =
|
|
( # scope scope
|
|
# # for type 1 for type 2
|
|
# those that help with SDX # (1:1) codebases (N:1) codebases
|
|
#
|
|
commands => {fn => \&OtherOp, defcmd => "", defarg => "", type => 1,}, # n/a n/a
|
|
usage => {fn => \&OtherOp, defcmd => "", defarg => "", type => 1,}, # n/a n/a
|
|
|
|
#
|
|
# those that change client or server state
|
|
#
|
|
client => {fn => \&OtherOp, defcmd => "client", defarg => "", type => 1,}, # project depot
|
|
defect => {fn => \&Defect, defcmd => "", defarg => "", type => 1,}, # project depot
|
|
deletefile => {fn => \&OtherOp, defcmd => "delete", defarg => "", type => 1,}, # project project
|
|
editfile => {fn => \&OtherOp, defcmd => "edit", defarg => "", type => 1,}, # project project
|
|
enlist => {fn => \&Enlist, defcmd => "", defarg => "", type => 1,}, # project depot
|
|
flush => {fn => \&OtherOp, defcmd => "flush", defarg => "", type => 1,}, # project project
|
|
integrate => {fn => \&OtherOp, defcmd => "integrate", defarg => "", type => 1,}, # project depot
|
|
labbranch => {fn => \&OtherOp, defcmd => "lbranch", defarg => "", type => 1,}, # project depot
|
|
label => {fn => \&OtherOp, defcmd => "label", defarg => "", type => 1,}, # project depot
|
|
labelsync => {fn => \&OtherOp, defcmd => "labelsync", defarg => "", type => 1,}, # project depot
|
|
protect => {fn => \&OtherOp, defcmd => "protect", defarg => "", type => 1,}, # project depot
|
|
repair => {fn => \&Repair, defcmd => "", defarg => "", type => 1,}, # project depot
|
|
resolve => {fn => \&OtherOp, defcmd => "resolve", defarg => "", type => 1,}, # project depot
|
|
revert => {fn => \&OtherOp, defcmd => "revert", defarg => "", type => 1,}, # project depot
|
|
submit => {fn => \&OtherOp, defcmd => "submit", defarg => "", type => 1,}, # project depot
|
|
sync => {fn => \&OtherOp, defcmd => "sync", defarg => "", type => 1,}, # project project
|
|
triggers => {fn => \&OtherOp, defcmd => "triggers", defarg => "", type => 1,}, # project depot
|
|
|
|
#
|
|
# those that report status
|
|
#
|
|
admin => {fn => \&OtherOp, defcmd => "admin", defarg => "", type => 1,}, # project depot
|
|
# branch => {fn => \&OtherOp, defcmd => "branch", defarg => "", type => 1,}, # project depot
|
|
branches => {fn => \&OtherOp, defcmd => "branches", defarg => "", type => 1,}, # project depot
|
|
clients => {fn => \&OtherOp, defcmd => "clients", defarg => "", type => 1,}, # project depot
|
|
# change => {fn => \&OtherOp, defcmd => "change", defarg => "", type => 1,}, # project project
|
|
changes => {fn => \&Changes, defcmd => "changes", defarg => "", type => 1,}, # project project
|
|
counters => {fn => \&OtherOp, defcmd => "counters", defarg => "", type => 1,}, # project depot
|
|
delta => {fn => \&Delta, defcmd => "", defarg => "", type => 1,},
|
|
diff2 => {fn => \&OtherOp, defcmd => "diff2", defarg => "", type => 1,},
|
|
dirs => {fn => \&OtherOp, defcmd => "dirs", defarg => "", type => 1,}, # project depot
|
|
files => {fn => \&OtherOp, defcmd => "files", defarg => "", type => 1,}, # project project
|
|
have => {fn => \&OtherOp, defcmd => "have", defarg => "", type => 1,}, # project project
|
|
info => {fn => \&OtherOp, defcmd => "info", defarg => "", type => 1,}, # project depot
|
|
integrated => {fn => \&OtherOp, defcmd => "integrated", defarg => "", type => 1,}, # project depot
|
|
labels => {fn => \&OtherOp, defcmd => "labels", defarg => "", type => 1,}, # project depot
|
|
opened => {fn => \&OtherOp, defcmd => "opened", defarg => "", type => 1,}, # project project
|
|
pending => {fn => \&OtherOp, defcmd => "changes", defarg => "-s pending", type => 1,}, # project depot
|
|
projects => {fn => \&OtherOp, defcmd => "projects", defarg => "", type => 1,}, # project project
|
|
resolved => {fn => \&OtherOp, defcmd => "resolved", defarg => "", type => 1,}, # project depot
|
|
status => {fn => \&OtherOp, defcmd => "status", defarg => "", type => 1,}, # project project
|
|
# user => {fn => \&OtherOp, defcmd => "user", defarg => "", type => 1,}, # project depot
|
|
users => {fn => \&OtherOp, defcmd => "users", defarg => "", type => 1,}, # project depot
|
|
where => {fn => \&OtherOp, defcmd => "where", defarg => "", type => 1,}, # project project
|
|
|
|
#
|
|
# internal
|
|
#
|
|
enumdepots => {fn => \&OtherOp, defcmd => "enumdepots", defarg => "", type => 1,}, # project project
|
|
);
|
|
|
|
#
|
|
# list of SD command/flag combinations not to allow
|
|
#
|
|
%main::BadCmds =
|
|
(
|
|
#
|
|
# -c makes no sense since change numbers aren't consistent across name space
|
|
#
|
|
-c => [
|
|
"integrate",
|
|
"revert",
|
|
"submit"
|
|
],
|
|
#
|
|
# don't want any switches to sdx branch/change/user except -o
|
|
#
|
|
-d => [
|
|
"branch",
|
|
"change",
|
|
"user"
|
|
],
|
|
-f => [
|
|
"branch",
|
|
"change",
|
|
"user"
|
|
],
|
|
#
|
|
# don't want to branch/client/changelist/label/user spec changing with -i
|
|
# sd(x) client is ok
|
|
#
|
|
-i => [
|
|
"branch",
|
|
"change",
|
|
"client",
|
|
"submit",
|
|
"user"
|
|
],
|
|
-t => [
|
|
"client",
|
|
"label"
|
|
],
|
|
);
|
|
|
|
#
|
|
# set the starting dir
|
|
#
|
|
open(CWD, 'cd 2>&1|');
|
|
$main::StartDir = <CWD>;
|
|
close(CWD);
|
|
chop $main::StartDir;
|
|
|
|
#
|
|
# figure out where we're running from
|
|
#
|
|
$main::InstallFrom = $ENV{STARTPATH};
|
|
|
|
#
|
|
# parse cmd line
|
|
#
|
|
SDX::ParseArgs(@_);
|
|
|
|
#
|
|
# return if we need usage already
|
|
#
|
|
$main::Usage and return;
|
|
|
|
#
|
|
# on new enlists in NT, don't let SDXROOT be > 8.3
|
|
#
|
|
# BUGBUG-1999/12/01-jeffmcd -- this should be an option in the codebase map -- SHORTROOT = 1
|
|
#
|
|
($main::NewEnlist and "\U$main::CodeBase" eq "NT") and do
|
|
{
|
|
my $root = (split(/\\/, $main::SDXRoot))[1];
|
|
(length((split/\./, $root)[0]) > 8 or length((split/\./, $root)[1]) > 3) and die("Please use an 8.3 name for \%SDXROOT\%.\n");
|
|
};
|
|
|
|
#
|
|
# does the SD client exist?
|
|
#
|
|
grep(/ recognized /, `sd.exe 2>&1`) and die("\nCan't find Source Depot client SD.EXE.\n");
|
|
|
|
#
|
|
# SD.MAP contains the relative paths to the roots of all projects the user
|
|
# is enlisted in, as created by SDX ENLIST, plus some keywords
|
|
#
|
|
# if we're doing anything other than enlisting or repairing, this must exist
|
|
#
|
|
$main::SDMap = "$main::SDXRoot\\sd.map";
|
|
|
|
#
|
|
# get attributes for this enlistment from SD.MAP
|
|
#
|
|
# fatal error if defecting, incrementally enlisting, or other op
|
|
# error text comes from ReadSDMap()
|
|
#
|
|
$main::Enlisting and $op = "enlist";
|
|
$main::Repairing and $op = "repair";
|
|
$main::Defecting and $op = "defect";
|
|
$main::OtherOp and $op = "otherop";
|
|
|
|
my $rc = SDX::ReadSDMap($op, "init");
|
|
!$rc and ($main::IncrEnlist or $main::Defecting or $main::OtherOp) and die("\n");
|
|
|
|
#
|
|
# if we have codebase and branch values from SD.MAP, use them
|
|
#
|
|
# handle some special cases
|
|
#
|
|
($main::SDMapCodeBase and $main::SDMapBranch and $main::SDMapCodeBaseType) and do
|
|
{
|
|
#
|
|
# on repair, warn the user we're changing these values
|
|
#
|
|
($main::Repairing and $main::CodeBase and $main::Branch) and do
|
|
{
|
|
print "\nUsing codebase and branch from $main::SDMap for repair. Ignoring ";
|
|
printf "%s.\n", $main::EnlistFromProfile ? "profile\n$main::Profile" : "'$main::CodeBase $main::Branch'\non command line";
|
|
};
|
|
|
|
#
|
|
# if the user is trying to enlist using a profile, they're already enlisted.
|
|
# the profile may have different codebase, branch or projects than what they
|
|
# already have, so error out
|
|
#
|
|
# $main::EnlistFromProfile can also be set during a repair
|
|
#
|
|
($main::EnlistFromProfile and !$main::Repairing) and do
|
|
{
|
|
print "\nEnlisting by profile is only supported for new enlistments.\n";
|
|
|
|
$main::CodeBase = "";
|
|
$main::Branch = "";
|
|
$main::Usage = $main::TRUE;
|
|
|
|
return;
|
|
};
|
|
|
|
#
|
|
# this may look like a new enlist but is actually incremental
|
|
#
|
|
# this prevents us from generating a unique client name later on,
|
|
# since the user is just adding another project to their enlistment
|
|
# and thought they needed to specify cb/br on the cmd line
|
|
#
|
|
# also prevents enlisting a different codebase or branch in
|
|
# this particular SDX Root
|
|
#
|
|
# repair-from-profile will also have $main::NewEnlist set
|
|
#
|
|
($main::NewEnlist and !$main::Repairing) and do
|
|
{
|
|
print "\nUsing codebase and branch from $main::SDMap. Ignoring '$main::CodeBase $main::Branch'\n";
|
|
print "on command line.\n";
|
|
|
|
$main::NewEnlist = $main::FALSE;
|
|
$main::IncrEnlist = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# finally, set primary codebase, type and branch
|
|
#
|
|
$main::CodeBase = $main::SDMapCodeBase;
|
|
$main::CodeBaseType = $main::SDMapCodeBaseType;
|
|
$main::Branch = $main::SDMapBranch;
|
|
};
|
|
|
|
#
|
|
# at this point we must have codebase, type and branch
|
|
#
|
|
(!$main::CodeBase or !$main::Branch) and do
|
|
{
|
|
print "\nMissing codebase and/or branch.\n";
|
|
$main::Usage = $main::TRUE;
|
|
return;
|
|
};
|
|
|
|
#
|
|
# be NT-centric for a minute and see if we know
|
|
# about a public change number
|
|
#
|
|
$main::PublicChangeNum = SDX::GetPublicChangeNum();
|
|
|
|
#
|
|
# if we're working in a type 2 (N projects per depot), modify some
|
|
# commands to work per-depot instead of per-project
|
|
#
|
|
# ie sdx submit on a type 1 should work per-project (which is actually a depot) and
|
|
# sdx submit on a type 2 should work per-depot (which encompasses several projects)
|
|
#
|
|
$main::CodeBaseType == 2 and do
|
|
{
|
|
$main::SDCmds{admin}{type} = 2;
|
|
# $main::SDCmds{branch}{type} = 2;
|
|
$main::SDCmds{branches}{type} = 2;
|
|
$main::SDCmds{client}{type} = 2;
|
|
$main::SDCmds{clients}{type} = 2;
|
|
$main::SDCmds{counters}{type} = 2;
|
|
$main::SDCmds{dirs}{type} = 2;
|
|
$main::SDCmds{info}{type} = 2;
|
|
$main::SDCmds{integrate}{type} = 2;
|
|
$main::SDCmds{labbranch}{type} = 2;
|
|
$main::SDCmds{label}{type} = 2;
|
|
$main::SDCmds{labels}{type} = 2;
|
|
$main::SDCmds{labelsync}{type} = 2;
|
|
$main::SDCmds{pending}{type} = 2;
|
|
$main::SDCmds{privatebranch}{type} = 2;
|
|
$main::SDCmds{protect}{type} = 2;
|
|
$main::SDCmds{submit}{type} = 2;
|
|
$main::SDCmds{triggers}{type} = 2;
|
|
$main::SDCmds{users}{type} = 2;
|
|
|
|
#
|
|
# these need to stay type 1 b/c they can take a filespec,
|
|
# which doesn't make sense when executing per-depot
|
|
# since we never leave %SDXROOT%
|
|
#
|
|
# $main::SDCmds{integrated}{type} = 2;
|
|
# $main::SDCmds{resolve}{type} = 2;
|
|
# $main::SDCmds{resolved}{type} = 2;
|
|
};
|
|
|
|
#
|
|
# fatal if no codebase type and not enlisting clean
|
|
#
|
|
# on a clean enlist we won't know the type until we have a chance to read $main::CodeBaseMap
|
|
#
|
|
(!$main::NewEnlist and !$main::Repairing and !$main::CodeBaseType) and die("\nCan't determine codebase type. Please contact the SDX alias.\n");
|
|
|
|
#
|
|
# set SDUSER and SDCLIENT
|
|
#
|
|
# if SDUSER is already defined in the environment
|
|
# assume it includes the domain name, and extract the user name
|
|
# otherwise use %USERNAME% and %USERDOMAIN%
|
|
#
|
|
# if SDCLIENT is already defined, use it, otherwise default to %COMPUTERNAME%.
|
|
#
|
|
# when defecting or repairing, if SDCLIENT is defined in the env, use it,
|
|
# otherwise use main::SDMapClient from SD.MAP. Ignore %COMPUTERNAME% unless we
|
|
# have no other choice
|
|
#
|
|
$main::SDUser = $ENV{SDUSER};
|
|
|
|
if ($main::SDUser)
|
|
{
|
|
$main::SDDomainUser = $main::SDUser;
|
|
$main::SDUser = (split(/\\/, $main::SDDomainUser))[1];
|
|
}
|
|
else
|
|
{
|
|
$main::SDUser = $ENV{USERNAME};
|
|
$main::SDDomainUser = "$ENV{USERDOMAIN}\\$main::SDUser";
|
|
}
|
|
|
|
#
|
|
# domain can't be computername, that is, user must be logged into the domain
|
|
#
|
|
("\U$ENV{USERDOMAIN}" eq "\U$ENV{COMPUTERNAME}") and die("\nTo enlist you must be logged into the domain and not your local machine.\n");
|
|
|
|
$main::SDClient = $ENV{SDCLIENT};
|
|
(!$main::SDClient) and do
|
|
{
|
|
$main::SDClient = ($main::Defecting or $main::Repairing or $main::IncrEnlist) ? $main::SDMapClient : $ENV{COMPUTERNAME};
|
|
|
|
#
|
|
# we may not be able to get the client name from SD.MAP so assume it's
|
|
# just the computer name, we'll catch it later if it isn't
|
|
#
|
|
$main::Repairing and !$main::SDClient and do
|
|
{
|
|
print "\nResorting to \%COMPUTERNAME\% for SD client name. Please verify below that\n";
|
|
print "this is the correct client for this enlistment before continuing. If not, set\n";
|
|
print "\%SDCLIENT\% correctly at the command line and rerun this command.\n";
|
|
$main::SDClient = $ENV{COMPUTERNAME};
|
|
};
|
|
};
|
|
|
|
!$main::SDUser and die("\nCan't determine SD user name. Verify that %USERNAME% is set in\nthe environment.\n");
|
|
!$main::SDClient and die("\nCan't determine SD client name. Verify that %COMPUTERNAME% is set\nin the environment.\n");
|
|
|
|
$main::V3 and do
|
|
{
|
|
printf "init: startdir=%s\n", $main::StartDir;
|
|
printf "init: startpath=%s\n", $main::StartPath;
|
|
printf "init: sdr = '%s'\n", $main::SDXRoot;
|
|
printf "init: sdm = '%s'\n", $main::SDMap;
|
|
printf "init: sdc = '%s'\n", $main::SDClient;
|
|
printf "init: sdu = '%s'\n", $main::SDUser;
|
|
printf "init: sddu = '%s'\n", $main::SDDomainUser;
|
|
printf "init: usage=%s\n", $main::Usage;
|
|
};
|
|
|
|
$main::Initializing = $main::FALSE;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Parses command line arguments to verify the right syntax is being used
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
# Errors if the wrong syntax is used otherwise sets the appropriate variables
|
|
# based on the command line arguments
|
|
# _____________________________________________________________________________
|
|
sub ParseArgs
|
|
{
|
|
#
|
|
# Initialize variables
|
|
#
|
|
$ArgCounter = 1; # start at one since 0th arg is redundant
|
|
$main::Usage = $main::FALSE;
|
|
$main::GetStarted = $main::TRUE;
|
|
$main::V1 = $main::FALSE;
|
|
$main::V2 = $main::FALSE;
|
|
$main::V3 = $main::FALSE;
|
|
$main::Enlisting = $main::FALSE;
|
|
$main::Defecting = $main::FALSE;
|
|
$main::Repairing = $main::FALSE;
|
|
$main::OtherOp = $main::TRUE;
|
|
$main::EnlistAll = $main::FALSE;
|
|
$main::EnlistClean = $main::FALSE;
|
|
$main::EnlistGroup = $main::FALSE;
|
|
$main::EnlistSome = $main::FALSE;
|
|
$main::EnlistFromProfile = $main::FALSE;
|
|
$main::NewEnlist = $main::FALSE;
|
|
$main::IncrEnlist = $main::FALSE;
|
|
$main::Exclusions = $main::TRUE;
|
|
$main::RestrictRoot = $main::FALSE;
|
|
$main::EnlistAsOther = $main::FALSE;
|
|
$main::Sync = $main::FALSE;
|
|
$main::DefectWithPrejudice = $main::FALSE;
|
|
$main::ToolsInRoot = $main::FALSE;
|
|
$main::Quiet = $main::FALSE;
|
|
$main::Logging = $main::FALSE;
|
|
$main::CBMProjectField = 0; # change these if you change
|
|
$main::CBMGroupField = 1; # the ordering of fields in
|
|
$main::CBMServerPortField = 2; # file PROJECTS.<CODEBASE>
|
|
$main::CBMDepotNameField = 3;
|
|
$main::CBMProjectRootField = 4;
|
|
$main::Profile = "";
|
|
$main::OtherClient = "";
|
|
$main::UserArgs = " ";
|
|
$main::Branch = "";
|
|
$main::SDXRoot = "";
|
|
$main::SDCmd = "";
|
|
$main::CodeBase = "";
|
|
$main::SubmitComment = "";
|
|
$main::ToolsProject = "";
|
|
$main::ToolsPath = "";
|
|
$main::ToolsProjectPath = "";
|
|
@main::OtherDirs = ();
|
|
@main::DefaultProjects = ();
|
|
@main::PlatformProjects = ();
|
|
@main::SomeProjects = ();
|
|
@main::ProfileProjects = ();
|
|
@main::InputForm = ();
|
|
$main::MinusB = $main::FALSE;
|
|
$main::MinusH = $main::FALSE;
|
|
$main::MinusI = $main::FALSE;
|
|
$main::MinusT = $main::FALSE;
|
|
$main::MinusO = $main::FALSE;
|
|
$main::MinusR = $main::FALSE;
|
|
$main::MinusV = $main::FALSE;
|
|
$main::MinusA = $main::FALSE;
|
|
my $MinusC = $main::FALSE;
|
|
my $MinusP = $main::FALSE;
|
|
my $MinusX = $main::FALSE;
|
|
|
|
#
|
|
# check SDXROOT for correctness
|
|
#
|
|
!exists($ENV{SDXROOT}) and do
|
|
{
|
|
print "\n%SDXROOT% is not set.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# don't allow illegal characters, or spaces at the beginning or end
|
|
#
|
|
# also don't allow '+' for now
|
|
#
|
|
my $root = $ENV{SDXROOT};
|
|
|
|
(!$main::Usage and ($root =~ /[\/*?"<>|+]/ or $root =~ /[\t\s]+$/ or $root =~ /^[\t\s]+/)) and do
|
|
{
|
|
print "\n\%SDXROOT% contains bad or undesirable characters: '$root'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
!$main::Usage and ((substr($root,0,1) !~ /[A-Za-z]/) or (substr($root,1,1) !~ /:/) or (substr($root,2,1) !~ /\\/)) and do
|
|
{
|
|
print "\n%SDXROOT% badly formed: '$root'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# may need to bail and show usage
|
|
#
|
|
$main::Usage and return;
|
|
|
|
#
|
|
# otherwise set the root
|
|
#
|
|
$main::SDXRoot = $root;
|
|
|
|
#
|
|
# first arg is always the operation we want to do
|
|
#
|
|
# make sure it's not a flag
|
|
# make sure it's a known cmd
|
|
#
|
|
if (($_[$ArgCounter] =~ /^-/) or ($_[$ArgCounter] =~ /^\//))
|
|
{
|
|
print "\nMissing command.\n";
|
|
$main::Usage = $main::TRUE;
|
|
return;
|
|
}
|
|
|
|
$main::SDCmd = $_[$ArgCounter];
|
|
$main::SDCmd =~ tr/A-Z/a-z/;
|
|
$ArgCounter++;
|
|
|
|
#
|
|
# return if no command or command not in list
|
|
#
|
|
if (!$main::SDCmd)
|
|
{
|
|
$main::Usage = $main::TRUE;
|
|
return;
|
|
}
|
|
|
|
(!exists($main::SDCmds{$main::SDCmd})) and die("\nUnknown command '$main::SDCmd'. Try sdx -? for info.\n");
|
|
|
|
#
|
|
# determine which SDX command this is
|
|
#
|
|
# an "other" operation is assumed by default
|
|
#
|
|
# maybe show command list or usage
|
|
#
|
|
# if enlist/defect/repair, set flags and satisfy required
|
|
# arguments later
|
|
#
|
|
($main::SDCmd =~ /usage/) and $main::Usage = $main::TRUE;
|
|
|
|
($main::SDCmd =~ /commands/) and do
|
|
{
|
|
$main::Usage = $main::TRUE;
|
|
$main::GetStarted = $main::FALSE;
|
|
};
|
|
|
|
$main::Usage and return;
|
|
|
|
#
|
|
# we have a valid command so any usage needed from this point
|
|
# will be specific to main::SDCmd
|
|
#
|
|
$main::GetStarted = $main::FALSE;
|
|
|
|
#
|
|
# set flags for enlist/defect/repair
|
|
#
|
|
$main::SDCmd =~ /enlist/ and do
|
|
{
|
|
$main::Enlisting = $main::TRUE;
|
|
$main::IncrEnlist = $main::TRUE;
|
|
$main::EnlistSome = $main::TRUE;
|
|
$main::OtherOp = $main::FALSE;
|
|
};
|
|
|
|
$main::SDCmd =~ /defect/ and do
|
|
{
|
|
$main::Defecting = $main::TRUE;
|
|
$main::DefectSome = $main::TRUE;
|
|
$main::OtherOp = $main::FALSE;
|
|
};
|
|
|
|
$main::SDCmd =~ /repair/ and do
|
|
{
|
|
$main::Repairing = $main::TRUE;
|
|
$main::OtherOp = $main::FALSE;
|
|
};
|
|
|
|
my $ignore = "";
|
|
|
|
#
|
|
# Cycle through parameters
|
|
#
|
|
my $arg = "";
|
|
my $subarg = "";
|
|
while ($_[$ArgCounter])
|
|
{
|
|
#
|
|
# if '-' or '/' is the first character in the arg then it's a flag
|
|
#
|
|
$arg = $_[$ArgCounter];
|
|
if (($arg =~ /^-/) or ($arg =~ /^\//))
|
|
{
|
|
$ArgPosition = 0;
|
|
|
|
CASE: while ($SubArg = substr $_[$ArgCounter], ++$ArgPosition)
|
|
{
|
|
$main::V2 and do
|
|
{
|
|
printf "subarg = '%s'\n", $SubArg;
|
|
};
|
|
|
|
#
|
|
# -# <string> equals $SubmitComment
|
|
#
|
|
if ($SubArg =~ /^\#/)
|
|
{
|
|
#
|
|
# the comment is from # to the end of the cmd string
|
|
#
|
|
if ($main::SDCmd eq "submit")
|
|
{
|
|
my $ac = $ArgCounter + 1;
|
|
while ($_[$ac])
|
|
{
|
|
$main::SubmitComment .= "$_[$ac] ";
|
|
$_[$ac] = "";
|
|
$ac++;
|
|
}
|
|
|
|
#
|
|
# set this for later
|
|
#
|
|
$main::MinusI = $main::TRUE;
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -1 is verbose debugging
|
|
#
|
|
if ($SubArg =~ /^1/)
|
|
{
|
|
$main::V1 = $main::TRUE;
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -2 is very verbose
|
|
#
|
|
if ($SubArg =~ /^2/)
|
|
{
|
|
$main::V2 = $main::TRUE;
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -3 you get the picture
|
|
#
|
|
if ($SubArg =~ /^3/)
|
|
{
|
|
$main::V3 = $main::TRUE;
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -a equals All
|
|
#
|
|
# if enlisting set a flag for later
|
|
# if defecting set defect flags
|
|
# else pass on to the SD command
|
|
#
|
|
if ($SubArg =~ /^a/i)
|
|
{
|
|
if ($main::Enlisting)
|
|
{
|
|
$MinusA = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
if ($main::Defecting)
|
|
{
|
|
$main::DefectAll = $main::TRUE;
|
|
$main::DefectGroup = $main::FALSE;
|
|
$main::DefectSome = $main::FALSE;
|
|
|
|
# null out list in case we collected some projects already
|
|
@main::SomeProjects = ();
|
|
}
|
|
else
|
|
{
|
|
if ($main::SDCmd eq "users" or $main::SDCmd eq "files" or $main::SDCmd eq "clients")
|
|
{
|
|
$main::MinusA = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
}
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -b is build number
|
|
#
|
|
if ($SubArg =~ /^b/i)
|
|
{
|
|
if ($main::SDCmd eq "changes")
|
|
{
|
|
$main::MinusB = $main::TRUE;
|
|
$ArgCounter++;
|
|
|
|
if (!($main::BuildNumber = $_[$ArgCounter]))
|
|
{
|
|
print "\nMissing build number.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
$_[$ArgCounter] = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -c is enlist clean
|
|
#
|
|
# if enlisting, set a flag for later
|
|
# else pass on to the SD command
|
|
#
|
|
if ($SubArg =~ /^c/i)
|
|
{
|
|
if ($main::Enlisting)
|
|
{
|
|
$MinusC = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# if defecting, -f equals DefectWithPrejudice
|
|
# else pass on to SD
|
|
#
|
|
if ($SubArg =~ /^f/i)
|
|
{
|
|
if ($main::Defecting)
|
|
{
|
|
$main::DefectWithPrejudice = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -g equals Logging
|
|
# the log file must be the next arg
|
|
#
|
|
if ($SubArg =~ /^g/i)
|
|
{
|
|
$ArgCounter++;
|
|
|
|
if (!($main::Log = $_[$ArgCounter]))
|
|
{
|
|
print "\nMissing log file.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
|
|
if (substr($main::Log,0,1) =~ /[\/-]/)
|
|
{
|
|
$main::Log !~ /\?/ and print "\nLog name '$main::Log' appears to be a command switch.\n";
|
|
$main::Log = "";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
|
|
#
|
|
# if we have a good log, set a flag and null out arg so it
|
|
# doesn't end up in user args
|
|
#
|
|
!$main::Usage and ($main::Logging = $main::TRUE and $_[$ArgCounter] = "");
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -h -- set flag for later, on sync/flush only
|
|
#
|
|
if ($SubArg =~ /^h/i)
|
|
{
|
|
($main::SDCmd =~ /sync|flush/) and $main::MinusH = $main::TRUE;
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -i -- read input form from cmd line, or
|
|
# show integration changes if cmd is sync or flush, or
|
|
# only rewrite SD.INIs if repairing
|
|
#
|
|
if ($SubArg =~ /^i/i)
|
|
{
|
|
$main::MinusI = $main::TRUE;
|
|
|
|
($main::SDCmd ne "sync" and $main::SDCmd ne "flush" and $main::SDCmd ne "repair" and $main::SDCmd ne "resolve") and @main::InputForm = <STDIN>;
|
|
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# when enlisting, -m equals $MinimalTools
|
|
#
|
|
if ($SubArg =~ /^m/i)
|
|
{
|
|
if ($main::Enlisting)
|
|
{
|
|
$main::MinimalTools = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -o -- set flag for later
|
|
#
|
|
if ($SubArg =~ /^o/i)
|
|
{
|
|
$main::MinusO = $main::TRUE;
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# when enlisting or repairing, -p means read from profile
|
|
# next arg must be path to the profile file
|
|
#
|
|
if ($SubArg =~ /^p/i)
|
|
{
|
|
if ($main::Enlisting or $main::Repairing)
|
|
{
|
|
$MinusP = $main::TRUE;
|
|
$ArgCounter++;
|
|
|
|
if (!($main::Profile = $_[$ArgCounter]))
|
|
{
|
|
print "\nMissing profile.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# if we have a good Profile, set flags and null out arg so it
|
|
# doesn't end up in user args
|
|
#
|
|
if (SDX::ReadProfile())
|
|
{
|
|
#
|
|
# set flag for enlist or repair
|
|
#
|
|
$main::EnlistFromProfile = $main::TRUE;
|
|
|
|
$main::Enlisting and do
|
|
{
|
|
$main::NewEnlist = $main::TRUE;
|
|
$main::IncrEnlist = $main::FALSE;
|
|
};
|
|
|
|
$_[$ArgCounter] = "";
|
|
}
|
|
else
|
|
{
|
|
die("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -q equals Quiet
|
|
#
|
|
if ($SubArg =~ /^q/i)
|
|
{
|
|
if ($main::SDCmd ne "diff2")
|
|
{
|
|
$main::Quiet = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -r equals RI when submitting
|
|
#
|
|
if ($SubArg =~ /^r/i)
|
|
{
|
|
if ($main::SDCmd eq "submit")
|
|
{
|
|
$main::MinusR = $main::TRUE;
|
|
$main::MinusT and do
|
|
{
|
|
printf "Already have -n, ignoring -%s.\n", $SubArg;
|
|
$main::MinusR = $main::FALSE;
|
|
};
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# when enlisting, defecting or repairing, -s equals $Sync
|
|
# else pass on
|
|
#
|
|
if ($SubArg =~ /^s/i)
|
|
{
|
|
if ($main::Enlisting || $main::Repairing || $main::Defecting)
|
|
{
|
|
$main::Sync = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -t equals Integration when submitting
|
|
#
|
|
if ($SubArg =~ /^t/i)
|
|
{
|
|
if ($main::SDCmd eq "submit")
|
|
{
|
|
$main::MinusT = $main::TRUE;
|
|
$main::MinusR and do
|
|
{
|
|
printf "Already have -r, ignoring -%s.\n", $SubArg;
|
|
$main::MinusT = $main::FALSE;
|
|
};
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -v equals Verbose
|
|
#
|
|
if ($SubArg =~ /^v/i)
|
|
{
|
|
$main::MinusV = $main::TRUE;
|
|
|
|
#
|
|
# maybe pass -v on to SD
|
|
#
|
|
($main::SDCmd eq "integrate" or $main::SDCmd eq "resolve") and do
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
};
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# when enlisting, -x turns off $Exclusions
|
|
# else pass on to SD
|
|
#
|
|
if ($SubArg =~ /^x/)
|
|
{
|
|
if ($main::Enlisting)
|
|
{
|
|
$MinusX = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
}
|
|
|
|
next CASE;
|
|
}
|
|
|
|
#
|
|
# -h or -? equals $Usage
|
|
#
|
|
if (($SubArg =~ /^h/i) or ($SubArg =~ /^\?/))
|
|
{
|
|
$main::Usage = $main::TRUE;
|
|
last CASE;
|
|
}
|
|
|
|
#
|
|
# add the switch to the user arg list
|
|
#
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
|
|
last CASE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# process non-switch args
|
|
#
|
|
|
|
#
|
|
# for general SD commands, add the arg to the user arg list
|
|
#
|
|
$main::OtherOp and do
|
|
{
|
|
SDX::AddUserArg($_[$ArgCounter]);
|
|
};
|
|
|
|
#
|
|
# if enlisting, arg is one of
|
|
# @client
|
|
# codebase and branch pair
|
|
# project name
|
|
#
|
|
$main::Enlisting and do
|
|
{
|
|
#
|
|
# first look for @<client>
|
|
#
|
|
if ((substr($_[$ArgCounter],0,1) =~ /@/) and !$main::EnlistAsOther)
|
|
{
|
|
$main::EnlistAsOther = $main::TRUE;
|
|
$main::NewEnlist = $main::TRUE;
|
|
$main::IncrEnlist = $main::FALSE;
|
|
$main::EnlistSome = $main::FALSE;
|
|
|
|
$main::OtherClient = substr($_[$ArgCounter],1,length($_[$ArgCounter]));
|
|
|
|
!$main::OtherClient and do
|
|
{
|
|
print "\nMissing client name after '\@'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\nenlist as other = $main::EnlistAsOther\n";
|
|
print "other = '$main::OtherClient'\n";
|
|
print "new enlist = $main::NewEnlist\n";
|
|
print "incr enlist = $main::IncrEnlist\n";
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# test for codebase if we don't have it already
|
|
#
|
|
# if arg is a codebase name (of the form PROJECTS.<codebase>) this is a new enlist
|
|
# assume the arg following is the branch name
|
|
#
|
|
if (!$main::CodeBase and SDX::VerifyCBMap($_[$ArgCounter]))
|
|
{
|
|
$main::NewEnlist = $main::TRUE;
|
|
$main::IncrEnlist = $main::FALSE;
|
|
|
|
$main::CodeBase = $_[$ArgCounter++];
|
|
$main::Branch = $_[$ArgCounter];
|
|
|
|
if ($main::Usage = SDX::VerifyCodeBaseAndBranch($main::CodeBase, $main::Branch))
|
|
{
|
|
$main::CodeBase = "";
|
|
$main::Branch = "";
|
|
}
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\nnew enlist = $main::NewEnlist\n";
|
|
print "incr enlist = $main::IncrEnlist\n";
|
|
print "codebase = '$main::CodeBase'\n";
|
|
print "branch = '$main::Branch'\n";
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# arg is a project name
|
|
#
|
|
# maybe add to list
|
|
#
|
|
if (!$main::EnlistAll and !$main::EnlistAsOther and !$main::EnlistFromProfile)
|
|
{
|
|
#
|
|
# BUGBUG-2000/01/26-jeffmcd -- finish
|
|
#
|
|
# if arg is of the form project\path\path\path, break it apart
|
|
# and associate the path with the project so we can write it in the view later
|
|
# else
|
|
# it's just a project name
|
|
#
|
|
# if ($_[$ArgCounter] =~ /.+\\.+/)
|
|
# {
|
|
# my @fields = split(/\\/,$_[$ArgCounter]);
|
|
# my $project = @fields[0];
|
|
# push @main::SomeProjects, $project;
|
|
#
|
|
# shift @fields;
|
|
# my $subpath = "";
|
|
# foreach (@fields) { $subpath .= "$_\\"; }
|
|
# chop $subpath;
|
|
# print "'$subpath'\n";
|
|
# # load the hash -- use project as key
|
|
# push @$main::ProjectSubPaths{$project}, $subpath;
|
|
# }
|
|
# else
|
|
# {
|
|
push @main::SomeProjects, lc $_[$ArgCounter];
|
|
# }
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
#
|
|
# if incrementally defecting, arg is project to defect from
|
|
#
|
|
($main::Defecting and !$main::DefectAll) and do
|
|
{
|
|
push @main::SomeProjects, lc $_[$ArgCounter];
|
|
};
|
|
|
|
#
|
|
# if repairing, current arg and the next are codebase and branch
|
|
#
|
|
$main::Repairing and do
|
|
{
|
|
#
|
|
# if codebase is null we need both values
|
|
# test the current arg to see if there's a codebase map for it, if so get the branch
|
|
#
|
|
!$main::CodeBase and do
|
|
{
|
|
SDX::VerifyCBMap($_[$ArgCounter]) and do
|
|
{
|
|
$main::CodeBase = $_[$ArgCounter++];
|
|
$main::Branch = $_[$ArgCounter];
|
|
|
|
if ($main::Usage = SDX::VerifyCodeBaseAndBranch($main::CodeBase, $main::Branch))
|
|
{
|
|
$main::CodeBase = "";
|
|
$main::Branch = "";
|
|
}
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\nrepairing, codebase = '$main::CodeBase'\n";
|
|
print "repairing, branch = '$main::Branch'\n";
|
|
};
|
|
};
|
|
};
|
|
|
|
#
|
|
# if we didn't use this arg as codebase, pass it on
|
|
#
|
|
(!$main::CodeBase) and SDX::AddUserArg($_[$ArgCounter]);
|
|
};
|
|
}
|
|
|
|
$ArgCounter++;
|
|
}
|
|
|
|
#
|
|
# maybe return for usage
|
|
#
|
|
$main::Usage and return;
|
|
|
|
#
|
|
# at this point all args have been accounted for
|
|
#
|
|
# figure out a couple things we couldn't earlier
|
|
#
|
|
|
|
#
|
|
# for a regular enlist-all, set some flags
|
|
#
|
|
($MinusA and $main::Enlisting) and do
|
|
{
|
|
if (!$main::EnlistAsOther and !$main::EnlistFromProfile)
|
|
{
|
|
$main::EnlistAll = $main::TRUE;
|
|
$main::EnlistGroup = $main::FALSE;
|
|
$main::EnlistSome = $main::FALSE;
|
|
|
|
# null out list in case we collected some projects already
|
|
@main::SomeProjects = ();
|
|
}
|
|
else
|
|
{
|
|
$ignore .= " -a";
|
|
}
|
|
};
|
|
|
|
#
|
|
# enlist clean if not enlisting as another client
|
|
#
|
|
$MinusC and do
|
|
{
|
|
if (!$main::EnlistAsOther)
|
|
{
|
|
$main::EnlistClean = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
$ignore .= " -c";
|
|
}
|
|
};
|
|
|
|
#
|
|
# enlisting as another client takes precedence over profiles
|
|
#
|
|
($MinusP) and do
|
|
{
|
|
if ($main::EnlistAsOther)
|
|
{
|
|
$ignore .= " -p $main::Profile";
|
|
|
|
$main::EnlistFromProfile = $main::FALSE;
|
|
$main::Profile = "";
|
|
@main::SomeProjects = ();
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# set flags
|
|
#
|
|
$main::NewEnlist = $main::TRUE;
|
|
$main::IncrEnlist = $main::FALSE;
|
|
|
|
$main::CodeBase = $main::ProfileCodeBase;
|
|
$main::Branch = $main::ProfileBranch;
|
|
push @main::SomeProjects, @main::ProfileProjects;
|
|
|
|
$main::V2 and do
|
|
{
|
|
$main::Repairing and print "\nrepairing from profile...\n";
|
|
print "\nnew enlist = $main::NewEnlist\n";
|
|
print "incr enlist = $main::IncrEnlist\n";
|
|
print "codebase = '$main::CodeBase'\n";
|
|
print "branch = '$main::Branch'\n";
|
|
print "some projects = '@main::SomeProjects'\n";
|
|
};
|
|
}
|
|
};
|
|
|
|
#
|
|
# ignore exclusions if not enlisting as another client
|
|
#
|
|
$MinusX and do
|
|
{
|
|
if (!$main::EnlistAsOther)
|
|
{
|
|
$main::Exclusions = $main::FALSE;
|
|
}
|
|
else
|
|
{
|
|
$ignore .= " -x";
|
|
}
|
|
};
|
|
|
|
#
|
|
# if we have args to ignore, say so
|
|
#
|
|
$main::EnlistAsOther and $ignore and printf "\nUsing client %s as a template, ignoring$ignore.\n", "\U$main::OtherClient";
|
|
$main::EnlistFromProfile and $ignore and print "\nUsing profile, ignoring$ignore and/or projects on command line.\n";
|
|
|
|
#
|
|
# do some early error checking so we can get usage if needed
|
|
#
|
|
$main::Enlisting and do
|
|
{
|
|
#
|
|
# make sure we're enlisting in either some or all projects
|
|
#
|
|
if (!$main::EnlistAsOther and !$main::EnlistSome and !$main::EnlistAll)
|
|
{
|
|
print "\nMissing projects to enlist, or -a.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
|
|
#
|
|
# if we're enlisting in only some projects and not as another client,
|
|
# the project list can't be empty
|
|
#
|
|
if ($main::EnlistSome and !$main::EnlistAsOther and ($#main::SomeProjects < 0))
|
|
{
|
|
print "\nMissing projects to enlist. Please specify projects or use -a for all.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
};
|
|
|
|
#
|
|
# same if defecting...
|
|
#
|
|
$main::Defecting and do
|
|
{
|
|
#
|
|
# make sure we're defecting in either some or all projects
|
|
#
|
|
if (!$main::DefectSome and !$main::DefectAll)
|
|
{
|
|
print "\nMissing projects to defect, or -a.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
|
|
#
|
|
# if we're defecting in only some projects, the project list
|
|
# can't be empty
|
|
#
|
|
if ($main::DefectSome and ($#main::SomeProjects < 0))
|
|
{
|
|
print "\nMissing projects to defect.\n";
|
|
$main::Usage = $main::TRUE;
|
|
}
|
|
};
|
|
|
|
#
|
|
# for now 'sdx branch' or 'sdx integrate' with no args is an error -- we don't want the UI popping up
|
|
# branch and integrate also requires args
|
|
#
|
|
(($main::SDCmd eq "branch" or $main::SDCmd eq "integrate") and $main::UserArgs =~ /^[\s]*$/) and do
|
|
{
|
|
print "\nMissing arguments to 'sdx $main::SDCmd'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# 'sdx opened -c' without 'default' is an error
|
|
#
|
|
(($main::SDCmd eq "opened") and ($main::UserArgs =~ /-c/ and $main::UserArgs !~ /-c default/)) and do
|
|
{
|
|
print "\n'sdx $main::SDCmd -c' requires 'default' as an argument.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
(($main::SDCmd eq "branch" or $main::SDCmd eq "change" or $main::SDCmd eq "user") and $main::UserArgs !~ /-o/) and do
|
|
{
|
|
print "\nOnly the -o switch is supported with 'sdx $main::SDCmd'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# don't allow "..." ".../*" ".../*.*" or their variations as arg to delete and edit
|
|
#
|
|
($main::SDCmd eq "deletefile" or $main::SDCmd eq "editfile") and do
|
|
{
|
|
($main::UserArgs =~ / \.\.\. |\.\.\.[\\\/]\*|\.\.\.[\\\/]+\*\.\* /) and do
|
|
{
|
|
my $ua = $main::UserArgs;
|
|
$ua =~ s/[\t\s]*//g;
|
|
print "\n'$ua' is not supported with 'sdx $main::SDCmd'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
};
|
|
|
|
#
|
|
# only allow 'status' arg to sd admin
|
|
#
|
|
($main::SDCmd eq "admin" and $main::UserArgs =~ / killthread | copyin | copyout | stop/) and do
|
|
{
|
|
print "\nOnly the 'status' command is supported with 'sdx admin'.\n";
|
|
$main::Usage = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# see if we need to check the format of (reverse) integration comments
|
|
#
|
|
# this helps sdx changes -b buildnum find I/RI events in the sd changes output
|
|
# and get build history
|
|
#
|
|
($main::SDCmd eq "submit" and $main::SubmitComment) and SDX::VerifySubmitComment();
|
|
|
|
$main::V4 and do
|
|
{
|
|
print "\nparseargs: cmd line = '@_'\n\n";
|
|
printf "parseargs: op = %s\n", $main::SDCmd;
|
|
printf "parseargs: userargs = '%s'\n", $main::UserArgs;
|
|
printf "parseargs: e = %s\n", $main::Enlisting;
|
|
printf "parseargs: r = %s\n", $main::Repairing;
|
|
printf "parseargs: d = %s\n", $main::Defecting;
|
|
printf "parseargs: o = %s\n", $main::OtherOp;
|
|
printf "parseargs: ea = %s\n", $main::EnlistAll;
|
|
printf "parseargs: es = %s\n", $main::EnlistSome;
|
|
printf "parseargs: da = %s\n", $main::DefectAll;
|
|
printf "parseargs: ds = %s\n", $main::DefectSome;
|
|
print "parseargs: submitcomment = '$main::SubmitComment'\n";
|
|
printf "parseargs: logging = %s\n", $main::Logging;
|
|
printf "parseargs: logfile = '%s'\n", $main::Log;
|
|
printf "parseargs: enlistfromprofile = %s\n", $main::EnlistFromProfile;
|
|
printf "parseargs: profile = '%s'\n", $main::Profile;
|
|
printf "parseargs: newenlist = %s\n", $main::NewEnlist;
|
|
printf "parseargs: increnlist = %s\n", $main::IncrEnlist;
|
|
printf "parseargs: enlistasother = %s\n", $main::EnlistAsOther;
|
|
printf "parseargs: otherclient = '%s'\n", $main::OtherClient;
|
|
printf "parseargs: u = %s\n", $main::Usage;
|
|
printf "parseargs: v1 = %s\n", $main::V1;
|
|
printf "parseargs: v2 = %s\n", $main::V2;
|
|
printf "parseargs: quiet = %s\n", $main::Quiet;
|
|
printf "parseargs: mintools = %s\n", $main::MinimalTools;
|
|
printf "parseargs: sync = %s\n", $main::Sync;
|
|
printf "parseargs: defectwithprejudice = %s\n", $main::DefectWithPrejudice;
|
|
|
|
printf "parseargs: sdxroot = %s\n", $main::SDXRoot;
|
|
printf "parseargs: cb = %s\n", $main::CodeBase;
|
|
printf "parseargs: br = %s\n", $main::Branch;
|
|
|
|
(($main::MinusI and !$main::Repairing) and !$main::MinusH) and do
|
|
{
|
|
print "parseargs: input form on STDIN:\n";
|
|
foreach (@main::InputForm) { print "'$_'\n"; }
|
|
};
|
|
|
|
if ($main::EnlistSome or $main::DefectSome)
|
|
{
|
|
print "\nSome projects on cmd line:\n\n";
|
|
foreach $project (@main::SomeProjects)
|
|
{
|
|
printf "\t%s\n", $project;
|
|
}
|
|
|
|
print "\n";
|
|
}
|
|
|
|
print "\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# AddUserArg
|
|
#
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub AddUserArg
|
|
{
|
|
my $arg = $_[0];
|
|
|
|
#
|
|
# if the arg is a switch associated with bad cmds
|
|
# see if our cmd is in the list
|
|
#
|
|
($arg =~ /^[-\/]/ and exists($main::BadCmds{$arg})) and do
|
|
{
|
|
foreach $cmd (@{$main::BadCmds{$arg}})
|
|
{
|
|
($cmd eq $main::SDCmd) and die("\nThe 'sdx $main::SDCmd $arg' command is not supported.\n");
|
|
}
|
|
};
|
|
|
|
$main::V4 and do
|
|
{
|
|
print "adding '$arg ' to '$main::UserArgs'\n";
|
|
};
|
|
|
|
$main::UserArgs .= $arg . " ";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ReadSDMap
|
|
#
|
|
# reads project name and project root (relative path from %SDXROOT%) from
|
|
# %SDXROOT%\sd.map into a list for use by Defect() and OtherOp()
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# populates $main::SDMapProjects list
|
|
# _____________________________________________________________________________
|
|
sub ReadSDMap
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
my $otherop = ($_[0] eq "otherop");
|
|
my $init = ($_[1] eq "init");
|
|
my $line;
|
|
my $repairmsg = $main::FALSE;
|
|
my $enlistmsg = $main::FALSE;
|
|
my $nomapmsg = $main::FALSE;
|
|
my $nokeysmsg = $main::FALSE;
|
|
my $noprojmsg = $main::FALSE;
|
|
|
|
#
|
|
# need to re-init this here each time
|
|
#
|
|
@main::SDMapProjects = ();
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "op = '$op'\n";
|
|
print "init = '$init'\n";
|
|
};
|
|
|
|
if (-e $main::SDMap)
|
|
{
|
|
open(SDMAP, "<$main::SDMap") or die("\nCan't open $main::SDMap for reading.\n");
|
|
|
|
while ($line = <SDMAP>)
|
|
{
|
|
#
|
|
# throw away comments, blank lines and certain non-project lines
|
|
#
|
|
$line =~ /^#|^[\t\s]*$/ and next;
|
|
|
|
#
|
|
# get the code base
|
|
#
|
|
if ($line =~ /^CODEBASE[\t\s]+/)
|
|
{
|
|
@fields = split(/[\t\s]*=[\t\s]*/, $line);
|
|
$main::SDMapCodeBase = "\U@fields[1]";
|
|
$main::SDMapCodeBase =~ s/[\t\s]*//g;
|
|
|
|
next;
|
|
}
|
|
|
|
#
|
|
# get the codebase type
|
|
#
|
|
if ($line =~ /^CODEBASETYPE/)
|
|
{
|
|
$main::SDMapCodeBaseType = (split(/[\t\s]*=[\t\s]*/, $line))[1];
|
|
chop $main::SDMapCodeBaseType;
|
|
next;
|
|
}
|
|
|
|
#
|
|
# get the branch
|
|
#
|
|
if ($line =~ /^BRANCH/)
|
|
{
|
|
$main::SDMapBranch = (split(/[\t\s]*=[\t\s]*/, $line))[1];
|
|
$main::SDMapBranch =~ s/[\t\s]*//g;
|
|
|
|
next;
|
|
}
|
|
|
|
#
|
|
# get the client
|
|
#
|
|
if ($line =~ /^CLIENT/)
|
|
{
|
|
$main::SDMapClient = (split(/[\t\s]*=[\t\s]*/, $line))[1];
|
|
$main::SDMapClient =~ s/[\t\s]*//g;
|
|
|
|
next;
|
|
}
|
|
|
|
#
|
|
# get the list of enlisted depots
|
|
#
|
|
if ($line =~ /^DEPOTS/)
|
|
{
|
|
my $fields = (split(/[\t\s]*=[\t\s]*/, $line))[1];
|
|
@main::SDMapDepots = split(/[\t\s]+/, $fields);
|
|
next;
|
|
}
|
|
|
|
#
|
|
# each line is of the form "project = projroot"
|
|
#
|
|
# throw away the '=' and push the project and root into the list
|
|
#
|
|
$line !~ /^(DEPOTS|CLIENT|BRANCH|CODEBASETYPE|CODEBASE)/ and do
|
|
{
|
|
chop $line;
|
|
$line =~ s/[\t\s]+//g;
|
|
@fields = split(/=/, $line);
|
|
push @main::SDMapProjects, [@fields];
|
|
};
|
|
}
|
|
|
|
close(SDMAP);
|
|
|
|
#
|
|
# if during init and no codebase type or depot list found,
|
|
# fix up the map quietly
|
|
#
|
|
($init) and do
|
|
{
|
|
(!$main::SDMapCodeBaseType or !@main::SDMapDepots) and do SDX::FixSDMap();
|
|
|
|
#
|
|
# track the actively used depots
|
|
#
|
|
# incremental enlist and defect may add/remove depots to/from this list
|
|
#
|
|
@main::ActiveDepots = @main::SDMapDepots;
|
|
};
|
|
|
|
$main::V4 and do
|
|
{
|
|
print "\n";
|
|
foreach $p (@main::SDMapProjects)
|
|
{
|
|
printf "readsdm: project, root = %s, %s\n", @$p[0], @$p[1];
|
|
}
|
|
|
|
print "\n";
|
|
foreach $p (@main::SDMapDepots)
|
|
{
|
|
printf "readsdm: depot = %s\n", $p;
|
|
}
|
|
|
|
print "\nreadsdm: main::SDMapCodeBase = '$main::SDMapCodeBase'\n";
|
|
print "readsdm: main::SDMapBranch = '$main::SDMapBranch'\n";
|
|
print "readsdm: main::SDMapClient = '$main::SDMapClient'\n";
|
|
print "readsdm: main::SDMapCodeBaseType = '$main::SDMapCodeBaseType'\n";
|
|
};
|
|
|
|
#
|
|
# return code depends on what we're doing and when
|
|
#
|
|
if ($init)
|
|
{
|
|
#
|
|
# return if we have the keywords else fail with msg
|
|
#
|
|
$enlisting and do
|
|
{
|
|
$main::V4 and print "\nduring init, sd.map exists, enlisting\n";
|
|
|
|
$main::SDMapCodeBase and $main::SDMapBranch and $main::SDMapClient and return 1;
|
|
|
|
$nokeysmsg = $main::TRUE;
|
|
$repairmsg = $main::TRUE;
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# all we care about in this case is the project list, b/c the map will
|
|
# be rewritten and any missing keywords restored
|
|
#
|
|
# fail silently if at all
|
|
#
|
|
$enlisting and do
|
|
{
|
|
$main::V4 and print "\nduring EDR, sd.map exists, enlisting\n";
|
|
|
|
@main::SDMapProjects and return 1;
|
|
};
|
|
}
|
|
|
|
#
|
|
# always return successfully when repairing, so we can continue and
|
|
# rewrite any missing lines from the map
|
|
#
|
|
$repairing and do
|
|
{
|
|
$main::V4 and print "\nduring EDR, sd.map exists, repairing\n";
|
|
|
|
return 1;
|
|
};
|
|
|
|
#
|
|
#
|
|
#
|
|
($defecting or $otherop) and do
|
|
{
|
|
$main::V4 and print "\nduring EDR, sd.map exists, defecting or otherop\n";
|
|
|
|
if ($main::SDMapCodeBase and $main::SDMapBranch and $main::SDMapClient)
|
|
{
|
|
@main::SDMapProjects and return 1;
|
|
|
|
$noprojmsg = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
$nokeysmsg = $main::TRUE;
|
|
}
|
|
|
|
$repairmsg = $main::TRUE;
|
|
};
|
|
|
|
#
|
|
# print error msgs
|
|
#
|
|
$nokeysmsg and do
|
|
{
|
|
printf "\n%s is missing one or more required keywords.\n", "\U$main::SDMap";
|
|
};
|
|
|
|
$noprojmsg and do
|
|
{
|
|
print "\nNo projects found in \U$main::SDMap.\n";
|
|
};
|
|
|
|
$repairmsg and do
|
|
{
|
|
printf "\nRun 'sdx repair %s %s' to update it, then rerun this command.\n", $main::SDMapCodeBase ? "\L$main::SDMapCodeBase" : "<codebase>", $main::SDMapBranch ? $main::SDMapBranch : "<branch>";
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# SD.MAP is missing
|
|
#
|
|
if ($init)
|
|
{
|
|
#
|
|
# assume this is an incremental enlist
|
|
#
|
|
($enlisting and !$main::NewEnlist) and do
|
|
{
|
|
$nomapmsg = $main::TRUE;
|
|
$enlistmsg = $main::TRUE;
|
|
};
|
|
|
|
($repairing or $defecting or $otherop) and do
|
|
{
|
|
$nomapmsg = $main::TRUE;
|
|
|
|
!$repairing and $repairmsg = $main::TRUE;
|
|
};
|
|
}
|
|
else
|
|
{
|
|
$enlisting and do
|
|
{
|
|
$main::V2 and print "\nduring EDR, no sd.map, enlisting\n";
|
|
};
|
|
|
|
$repairing and do
|
|
{
|
|
$main::V2 and print "\nduring EDR, no sd.map, repairing\n";
|
|
};
|
|
|
|
$defecting and do
|
|
{
|
|
$main::V2 and print "\nduring EDR, no sd.map, defecting\n";
|
|
};
|
|
|
|
$otherop and do
|
|
{
|
|
$main::V2 and print "\nduring EDR, no sd.map, otherop\n";
|
|
};
|
|
};
|
|
|
|
#
|
|
# print error msgs specific to missing SD.MAP cases
|
|
#
|
|
$nomapmsg and printf "\nCan't find %s to get enlistment information.\n", "\U$main::SDMap";
|
|
|
|
$enlistmsg and !$repairmsg and do
|
|
{
|
|
print "\nIf this is a new enlistment please run 'sdx enlist <codebase> <branch>' to\n";
|
|
print "specify the set of sources and the branch you want to enlist in.\n";
|
|
|
|
print "\nIf you are adding projects to an existing enlistment, the SD.MAP at\n";
|
|
printf "%s is missing. Run 'sdx repair <codebase> <branch>' to restore\n", "\U$main::SDXRoot";
|
|
print "it, then rerun this command.\n";
|
|
};
|
|
|
|
$repairmsg and !$enlistmsg and do
|
|
{
|
|
print "\nVerify that \%SDXROOT\% is set correctly, and that ";
|
|
printf "%s contains\n", "\U$main::SDXRoot";
|
|
printf "a valid enlistment. If it does, run 'sdx repair %s %s'\n", ($main::CodeBase ? $main::CodeBase : "<codebase>"), ($main::Branch ? $main::Branch : "<branch>");
|
|
print "to restore SD.MAP, then rerun this command.\n";
|
|
};
|
|
|
|
($repairmsg or $enlistmsg) and print "\nRun 'sdx repair -?' to see what repairing does to your enlistment.\n";
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# FixSDMap
|
|
#
|
|
# silently adds missing keywords to the user's SD.MAP
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub FixSDMap
|
|
{
|
|
#
|
|
# if no list of enlisted depots, figure it out and append it to the map
|
|
#
|
|
!@main::SDMapDepots and do
|
|
{
|
|
#
|
|
# figure out the list of active depots
|
|
#
|
|
SDX::OtherOp("enumdepots","");
|
|
|
|
#
|
|
# append
|
|
#
|
|
system "attrib -R -H -S $main::SDMap >nul 2>&1";
|
|
open(SDMAP, ">>$main::SDMap") or die("\nCan't append $main::SDMap.\n");
|
|
|
|
print SDMAP "\n";
|
|
SDX::WriteSDMapDepots(\@main::SDMapDepots, *SDMAP);
|
|
|
|
close SDMAP;
|
|
system "attrib +R +H +S $main::SDMap >nul 2>&1";
|
|
};
|
|
|
|
|
|
#
|
|
# same for the codebase type
|
|
#
|
|
!$main::SDMapCodeBaseType and do
|
|
{
|
|
#
|
|
# need to act as though we were enlisting to get enough information
|
|
# to determine the type
|
|
#
|
|
$main::CodeBase = $main::SDMapCodeBase;
|
|
|
|
if (SDX::VerifyCBMap($main::CodeBase))
|
|
{
|
|
SDX::ReadCodeBaseMap();
|
|
$main::SDMapCodeBaseType = $main::CodeBaseType;
|
|
|
|
#
|
|
# throw away results of the map read so we don't get duplicates
|
|
#
|
|
$main::ToolsProject = "";
|
|
$main::ToolsPath = "";
|
|
$main::ToolsProjectPath = "";
|
|
}
|
|
else
|
|
{
|
|
print "\n\nError fixing SD.MAP: can't find codebase map $main::CodeBaseMap.\n";
|
|
die("\nContact the SDX alias.\n");
|
|
}
|
|
|
|
#
|
|
# append
|
|
#
|
|
system "attrib -R -H -S $main::SDMap >nul 2>&1";
|
|
open(SDMAP, ">>$main::SDMap") or die("\nCan't append $main::SDMap.\n");
|
|
SDX::WriteSDMapCodeBaseType($main::SDMapCodeBaseType, *SDMAP);
|
|
close SDMAP;
|
|
system "attrib +R +H +S $main::SDMap >nul 2>&1";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# EnumDepots
|
|
#
|
|
# called by FixSDMap by OtherOp to walk the project roots and find SDPORT
|
|
# values
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# populates @main::SDMapDepots for writing to SD.MAP
|
|
# _____________________________________________________________________________
|
|
sub EnumDepots
|
|
{
|
|
my $userargs = $_[0];
|
|
my $project = $_[1];
|
|
my $sdini = $_[2];
|
|
my $sp;
|
|
|
|
$main::V4 and do
|
|
{
|
|
print "\n\n\nuserargs = '$userargs'\n";
|
|
print "project = '$project'\n";
|
|
};
|
|
|
|
#
|
|
# get server:port
|
|
#
|
|
open(INI, "< $sdini") or die("\nCan't read SD.INI.\n");
|
|
while (<INI>)
|
|
{
|
|
/^SDPORT/ and do
|
|
{
|
|
$sp = (split(/=/,$_))[1];
|
|
chop $sp;
|
|
};
|
|
}
|
|
close(INI);
|
|
|
|
#
|
|
# add to hash if unique
|
|
#
|
|
unless ($main::DepotsSeen{$sp})
|
|
{
|
|
$main::DepotsSeen{$sp} = 1;
|
|
push @main::SDMapDepots, $sp;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ListProjects
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub ListProjects
|
|
{
|
|
my $userargs = $_[0];
|
|
my $project = $_[1];
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\nuserargs = '$userargs'\n";
|
|
print "project = '$project'\n";
|
|
};
|
|
|
|
SDX::PrintCmd($header, 0);
|
|
|
|
for $p (@main::SDMapProjects)
|
|
{
|
|
(@$p[0] eq $project) and print "\n$main::SDXRoot\\@$p[1]\n";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Enlist
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Enlist
|
|
{
|
|
#
|
|
# munge the codebase map to create project, depot and group lists
|
|
# and figure out what the user wants to enlist in
|
|
#
|
|
if (SDX::InitForEnlist())
|
|
{
|
|
#
|
|
# for each depot we're enlisting in
|
|
# get the list of projects in this depot
|
|
# create/update the client view
|
|
# create/update the SD.MAP
|
|
# write the SD.INIs
|
|
#
|
|
foreach $depot (@main::EnlistDepots)
|
|
{
|
|
$serverport = @$depot[0];
|
|
$main::V3 and print "\n$serverport\n";
|
|
|
|
#
|
|
# from the list of all projects to enlist in, create a list of
|
|
# projects found in the current depot only
|
|
#
|
|
@main::ProjectsInThisDepot = ();
|
|
foreach $project (@main::EnlistProjects)
|
|
{
|
|
if ($serverport eq @$project[$main::CBMServerPortField])
|
|
{
|
|
push @main::ProjectsInThisDepot, [@{$project}];
|
|
|
|
$main::V3 and print "\t@$project\n";
|
|
}
|
|
}
|
|
|
|
print "\n";
|
|
|
|
#
|
|
# create or update the client view
|
|
#
|
|
SDX::EnlistProjects($depot, "enlist");
|
|
|
|
#
|
|
# upon registering the first client, release the mutex we
|
|
# took ownership of in MakeUniqueClient() so other enlists
|
|
# can continue
|
|
#
|
|
$main::HaveMutex and do
|
|
{
|
|
$main::HaveMutex = $main::FALSE;
|
|
$main::Mutex->release;
|
|
};
|
|
|
|
#
|
|
# create/update %SDXROOT%\SD.MAP
|
|
#
|
|
SDX::UpdateSDMap("enlist");
|
|
|
|
#
|
|
# create/update %SDXROOT%\SD.MAP
|
|
#
|
|
SDX::UpdateSDINIs("enlist");
|
|
}
|
|
|
|
#
|
|
# finish it off
|
|
#
|
|
SDX::FinishEnlist();
|
|
|
|
#
|
|
# success
|
|
#
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
printf "\nSDX had errors reading the file PROJECTS.%s or in constructing the list of\n", "\U$main::CodeBase";
|
|
print "projects and depots for enlisting.\n";
|
|
|
|
#
|
|
# failure
|
|
#
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# InitForEnlist
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
# returns 1 if successful, 0 otherwise
|
|
# _____________________________________________________________________________
|
|
sub InitForEnlist
|
|
{
|
|
#
|
|
# do the common init
|
|
#
|
|
SDX::InitForEDR("enlist");
|
|
|
|
#
|
|
# set the branch flag
|
|
#
|
|
# one of the following is true about $main::Branch
|
|
# - it matches $main::MasterBranch, in which case we're enlisting in the
|
|
# main sources for all projects for this code base
|
|
# - it matches one of the group build lab branch names, in which case we're
|
|
# enlisting in that lab's branched sources for all projects
|
|
# - it matches some other root-level branch defined by a developer or
|
|
# private lab
|
|
#
|
|
if ($main::Branch eq $main::MasterBranch)
|
|
{
|
|
$main::EnlistingMainBranch = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
foreach $br (@main::GroupBranches)
|
|
{
|
|
if ($main::Branch eq $br)
|
|
{
|
|
$main::EnlistingGroupBranch = $main::TRUE;
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$main::EnlistingMainBranch && !$main::EnlistingGroupBranch)
|
|
{
|
|
$main::EnlistingPrivateBranch = $main::TRUE;
|
|
}
|
|
|
|
# more error checking:
|
|
# - branch name can't be a project name
|
|
# - must be enlisting in all or some projects
|
|
# - if only some, project list can't be null
|
|
#
|
|
# verify that the branch the user gave us is not one of the projects
|
|
# in the codebase map. if so, they probably forgot to specify the
|
|
# branch name on the cmd line
|
|
#
|
|
foreach $project (@main::AllProjects)
|
|
{
|
|
($main::Branch eq @$project[$main::CBMProjectField]) and die("\nBranch name '$main::Branch' appears to be a project.\n");
|
|
}
|
|
|
|
#
|
|
# from the lists of all projects, groups and depots, create the lists
|
|
# of just those we'll enlist in
|
|
#
|
|
SDX::MakeTargetLists("enlist");
|
|
|
|
#
|
|
# see if we need to use a unique client name
|
|
#
|
|
if ($main::NewEnlist)
|
|
{
|
|
$main::SDClient = SDX::MakeUniqueClient();
|
|
}
|
|
else
|
|
{
|
|
SDX::VerifyAccess();
|
|
}
|
|
|
|
#
|
|
# if we have depots and projects to enlist in, continue
|
|
# else politely error-out
|
|
#
|
|
if (@main::EnlistDepots && @main::EnlistProjects)
|
|
{
|
|
if ($main::EnlistAsOther)
|
|
{
|
|
printf "\n\n\nThis script will enlist you in the %s sources using these settings:\n\n", "\U$main::CodeBase";
|
|
}
|
|
else
|
|
{
|
|
printf "\n\n\nThis script will %s in the %s sources", $main::NewEnlist ? "enlist you" : "add projects to your enlistment", "\U$main::CodeBase";
|
|
printf "%susing these settings:\n\n", $main::NewEnlist ? " " : "\n";
|
|
}
|
|
|
|
printf "\tRoot directory:\t\t%s\n", "\U$main::SDXRoot";
|
|
printf "\tBranch:\t\t\t%s\n", "\U$main::Branch";
|
|
printf "\tSD client name:\t\t%s\n", $main::SDClient;
|
|
printf "\tSD user name:\t\t%s\n", $main::SDDomainUser;
|
|
|
|
$main::EnlistAsOther and printf "\tClient template:\t%s\n", "\U$main::OtherClient";
|
|
|
|
#
|
|
# print the projects we're going to enlist in
|
|
#
|
|
$np = $#main::EnlistProjects+1;
|
|
printf "\n\tEnlisting in %s project%s...\n\n", $np, $np > 1 ? "s" : "";
|
|
foreach $project (@main::EnlistProjects)
|
|
{
|
|
printf "\t %s\n", @$project[$main::CBMProjectField];
|
|
}
|
|
|
|
#
|
|
# print the depots we're going to enlist in
|
|
#
|
|
$nd = $#main::EnlistDepots+1;
|
|
printf "\n\t...across %s depot%s:\n\n", $nd, $nd > 1 ? "s" : "";
|
|
foreach $depot (@main::EnlistDepots)
|
|
{
|
|
printf "\t %s\n", @$depot[0];
|
|
}
|
|
|
|
print "\n\nIF YOU ARE NOT READY TO ENLIST WITH THESE SETTINGS, HIT CTRL-BREAK NOW.\n";
|
|
print " ==================\n\n\n";
|
|
print "Otherwise,\n\n";
|
|
!$main::Quiet and system "pause";
|
|
|
|
print "\n\n";
|
|
|
|
#
|
|
# warn user if the branch they want doesn't exist
|
|
#
|
|
###
|
|
### SDX::VerifyBranch("enlist", $nd) and print "\nWarning: branch '$main::Branch' does not exist in one or more depots\n";
|
|
|
|
#
|
|
# if enlisting as another client, make sure the new client we want to create
|
|
# doesn't already exist
|
|
#
|
|
$main::EnlistAsOther and SDX::VerifyClient($nd);
|
|
|
|
#
|
|
# add some or all of the depots we're about to enlist in to
|
|
# the active list so they show up in SD.MAP later
|
|
#
|
|
SDX::UpdateActiveDepots("enlist", "");
|
|
|
|
$main::V4 and do
|
|
{
|
|
printf "\n";
|
|
printf "initforenlist: cb=%s\n", $main::CodeBase;
|
|
printf "initforenlist: cbm=%s\n", $main::CodeBaseMap;
|
|
printf "initforenlist: mb=%s\n", $main::MasterBranch;
|
|
printf "initforenlist: cv=%s\n", $main::ClientView;
|
|
printf "\n";
|
|
};
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
!@main::EnlistProjects and print "\nNo projects found. Unable to enlist.\n" and return 0;
|
|
!@main::EnlistDepots and print "\nNo depots found. Unable to enlist.\n" and return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# UpdateActiveDepots
|
|
#
|
|
# Add or remove server:port values to active depot list, depending on
|
|
# operation
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub UpdateActiveDepots
|
|
{
|
|
my $op = $_[0];
|
|
my $sp = $_[1];
|
|
|
|
my $enlisting = ($op eq "enlist");
|
|
my $defecting = ($op eq "defect");
|
|
|
|
($enlisting) and do
|
|
{
|
|
#
|
|
# on a clean enlist the list of active depots is
|
|
# those the user will enlist in
|
|
#
|
|
# active depot list is written to SD.MAP after enlisting
|
|
#
|
|
($main::NewEnlist) and do
|
|
{
|
|
my @unsorted = ();
|
|
for $depot (@main::EnlistDepots)
|
|
{
|
|
push @unsorted, @$depot[0];
|
|
}
|
|
|
|
#
|
|
# want this sorted
|
|
#
|
|
@main::ActiveDepots = SDX::SortDepots(\@unsorted);
|
|
};
|
|
|
|
#
|
|
# on an incremental enlist, add new depots only
|
|
#
|
|
($main::IncrEnlist) and do
|
|
{
|
|
my %hash = ();
|
|
|
|
for $depot (@main::ActiveDepots)
|
|
{
|
|
$hash{$depot} = 1;
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nhash:\n";
|
|
while (($k,$v) = each %hash)
|
|
{
|
|
printf " %-50s\t%s\n", $k, $v;
|
|
}
|
|
};
|
|
|
|
for $depot (@main::EnlistDepots)
|
|
{
|
|
my $sp = @$depot[0];
|
|
($hash{$sp} != 1) and do
|
|
{
|
|
push @main::ActiveDepots, $sp;
|
|
};
|
|
}
|
|
|
|
@main::ActiveDepots = SDX::SortDepots(\@main::ActiveDepots);
|
|
};
|
|
|
|
};
|
|
|
|
#
|
|
# null out dead server:port in active list
|
|
#
|
|
($defecting) and do
|
|
{
|
|
$main::V3 and do
|
|
{
|
|
print "\nbefore:\n";
|
|
for $d (@main::ActiveDepots)
|
|
{
|
|
print " '$d'\n";
|
|
}
|
|
};
|
|
|
|
grep {s/$sp//g} @main::ActiveDepots;
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nafter:\n";
|
|
for $d (@main::ActiveDepots)
|
|
{
|
|
print " '$d'\n";
|
|
}
|
|
};
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# EnlistProjects
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub EnlistProjects
|
|
{
|
|
$depot = $_[0];
|
|
$op = $_[1];
|
|
|
|
$serverport = @$depot[0];
|
|
|
|
if ($main::EnlistAsOther)
|
|
{
|
|
#
|
|
# register a new view using another client as a template
|
|
#
|
|
my $desc = 0;
|
|
my $pr = 0;
|
|
|
|
unlink $main::ClientView;
|
|
|
|
#
|
|
# Root: field for client view depends on depot type
|
|
#
|
|
# for type 1 (1 project/depot), root includes project name
|
|
# for type 2 (N projects/depot), root is just main::SDXRoot
|
|
#
|
|
# root is at least SDXRoot in either case
|
|
#
|
|
$root = $main::SDXRoot;
|
|
(@{$main::DepotType{$serverport}}[0] == 1) and $root = SDX::Type1Root($root);
|
|
|
|
#
|
|
# dump the other client into a list
|
|
#
|
|
@lines = `sd.exe -p $serverport client -o $main::OtherClient`;
|
|
|
|
$main::V3 and print "otherclient = '@lines'\n\n";
|
|
|
|
#
|
|
# munge the other's view to create a template
|
|
#
|
|
open(CLIENTVIEW, ">$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n");
|
|
|
|
#
|
|
# if OtherClient is a unique name, double up on the '\' so
|
|
# the s///gi works correctly
|
|
#
|
|
my $other = $main::OtherClient;
|
|
$other =~ s/\\/\\\\/g;
|
|
|
|
#
|
|
# transmogrify the client spec lines
|
|
#
|
|
foreach $line (@lines)
|
|
{
|
|
#
|
|
# if the most recent line was the description, the current line is its text
|
|
#
|
|
$desc and do
|
|
{
|
|
$line =~ s/^[\t\s]+.+/\tCreated by $main::SDDomainUser./g;
|
|
print CLIENTVIEW "$line";
|
|
|
|
$desc = 0;
|
|
next;
|
|
};
|
|
|
|
# throw away comments and certain other lines
|
|
$line =~ /(Update|Access):|^#/ and next;
|
|
|
|
# replace Client: with our client
|
|
$line =~ s/^Client:[\t\s]*.+/Client: $main::SDClient/g;
|
|
|
|
# replace owner name with our user name
|
|
$line =~ s/^Owner:[\t\s]*.+/Owner: $main::SDDomainUser/g;
|
|
|
|
# found the desc line, set a flag and replace it next time through
|
|
$line =~ /^Description:/ and $desc = 1;
|
|
|
|
# replace the old root with ours
|
|
$line =~ s/^Root:[\t\s]*.+/Root: $root/g;
|
|
|
|
# replace other client name in view lines with ours
|
|
$line =~ s/$other/$main::SDClient/gi;
|
|
|
|
print CLIENTVIEW "$line";
|
|
}
|
|
|
|
close(CLIENTVIEW);
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "==========\n";
|
|
system "type $main::ClientView";
|
|
print "==========\n";
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# create/update the view spec
|
|
#
|
|
SDX::CreateView($depot, $op);
|
|
}
|
|
|
|
#
|
|
# register the new/updated view
|
|
#
|
|
system "sd.exe -p $serverport client -i < $main::ClientView";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# FinishEnlist
|
|
#
|
|
# Finish up by:
|
|
# maybe syncing projects for the user
|
|
# generating SDINIT and alias files
|
|
# syncing the tools dir
|
|
# syncing any other dirs specified by the codebase map
|
|
# providing friendly verbage
|
|
#
|
|
# Parameters:
|
|
# none
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub FinishEnlist
|
|
{
|
|
#
|
|
# cleanup
|
|
#
|
|
unlink $main::ClientView;
|
|
|
|
#
|
|
# maybe unghost
|
|
#
|
|
$main::Sync and SDX::SyncFiles("enlist", $main::Null, $main::Null);
|
|
|
|
#
|
|
# give the user some direction on how to get started
|
|
#
|
|
# if the codebase map identified a tools dir, point them to that
|
|
# otherwise copy down the tools for them
|
|
#
|
|
|
|
#
|
|
# give the user the SD/SDX tools, batch files for aliases and SDX commands
|
|
#
|
|
SDX::ToolsEtc("enlist");
|
|
|
|
#
|
|
# also sync any OtherDirs at this time
|
|
#
|
|
@main::OtherDirs and SDX::SyncOtherDirs("enlist");
|
|
|
|
#
|
|
# if NT, addfile a default \developer\<username>\setenv.cmd
|
|
# not there yet
|
|
#
|
|
("\U$main::CodeBase" eq "NT") and SDX::WriteDefaultSetEnv();
|
|
|
|
#
|
|
# verbage for a succesful enlist
|
|
#
|
|
print "\nDone.\n";
|
|
|
|
$main::NewEnlist and do
|
|
{
|
|
$main::SDXRoot =~ tr/a-z/A-Z/;
|
|
$main::CodeBase =~ tr/a-z/A-Z/;
|
|
$sdtools = $main::SDXRoot . "\\sdtools";
|
|
|
|
print "\n\nThe directory $main::SDXRoot is now enlisted in the $main::CodeBase sources.\n";
|
|
|
|
print "\nThese SDX files were placed in your enlistment:\n";
|
|
|
|
if ($main::ToolsProject)
|
|
{
|
|
print "\n $main::SDXRoot\n";
|
|
printf "\t%-24smap to project roots and SD.INIs\n", "SD.MAP";
|
|
|
|
print "\n \U$main::ToolsProjectPath\n";
|
|
printf "\t%-24saliases for logging SDX output\n", "ALIAS.SDX";
|
|
printf "\t%-24saliases for navigating your enlistment\n", "ALIAS." . $main::CodeBase;
|
|
$main::CodeBaseMapFile =~ tr/a-z/A-Z/;
|
|
printf "\t%-24scodebase map for future enlist/defect/repair\n", $main::CodeBaseMapFile;
|
|
printf "\t%-24ssets default Source Depot vars and aliases\n", "SDINIT.CMD";
|
|
printf "\t%-24sscripts for cross-depot commands\n", "SDX.\*";
|
|
|
|
if (
|
|
"\U$main::CodeBase" eq "NT" or
|
|
"\U$main::CodeBase" eq "NTSDK" or
|
|
("\U$main::CodeBase" eq "NTTEST" and !$main::RestrictRoot) or
|
|
"\U$main::CodeBase" eq "NT.INTL" or
|
|
"\U$main::CodeBase" eq "MPC" or
|
|
"\U$main::CodeBase" eq "NGWS" or
|
|
"\U$main::CodeBase" eq "MGMT" or
|
|
"\U$main::CodeBase" eq "MOM" or
|
|
"\U$main::CodeBase" eq "PDDEPOT" or
|
|
"\U$main::CodeBase" eq "WINMEDIA" or
|
|
"\U$main::CodeBase" eq "WINSS"
|
|
)
|
|
{
|
|
printf "\n\nRun\n\n %s\\RAZZLE.CMD%s\n\nto start building.\n\n","\U$main::ToolsProjectPath", ($main::MinimalTools) ? " no_certcheck" : "";
|
|
}
|
|
else
|
|
{
|
|
print "\n\nTo use Source Depot, your build environment must:\n";
|
|
print "\n set SDXROOT=$main::SDXRoot\n";
|
|
printf " set PATH=\%SDXROOT\%\\%s;\%SDXROOT\%\\%s\\\%PROCESSOR_ARCHITECTURE\%;\%PATH\%\n", $main::ToolsPath ? "\U$main::ToolsPath" : "\U$main::ToolsProject", $main::ToolsPath ? "\U$main::ToolsPath" : "\U$main::ToolsProject";
|
|
printf " call %s\\SDINIT.CMD\n", "\U$main::ToolsProjectPath";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
print "\n $main::SDXRoot\n";
|
|
printf "\t%-24saliases for logging SDX output\n", "ALIAS.SDX";
|
|
printf "\t%-24saliases for navigating your enlistment\n", "ALIAS." . $main::CodeBase;
|
|
printf "\t%-24smap to project roots and SD.INIs\n", "SD.MAP";
|
|
printf "\t%-24ssets default Source Depot vars and aliases\n", "SDINIT.CMD";
|
|
|
|
print "\n $sdtools\n";
|
|
printf "\t%-24sPerl runtimes\n", "PERL\*";
|
|
$main::CodeBaseMapFile =~ tr/a-z/A-Z/;
|
|
printf "\t%-24scodebase map for future enlist/defect/repair\n", $main::CodeBaseMapFile;
|
|
printf "\t%-24sSource Depot client\n", "SD.EXE";
|
|
printf "\t%-24sscripts for cross-depot commands\n", "SDX.\*";
|
|
|
|
print "\n\nTO USE SDX/SD\n-------------\n";
|
|
print "Run $main::SDINIT. This will\n\n";
|
|
print " - set default Source Depot environment variables\n\n";
|
|
|
|
!$main::ToolsProject and print " - include $main::SDXRoot\\sdtools in your PATH\n\n";
|
|
|
|
print " - turn on aliases to log SDX output to $main::SDXRoot\\<command>.LOG\n";
|
|
print " and for changing between source projects\n\n";
|
|
print " - look for the file SDVARS.CMD and run it if found. This is\n";
|
|
print " useful for customizing Source Depot settings like SDEDITOR or\n";
|
|
print " SDPASSWD, adding other aliases, etc.\n";
|
|
|
|
print "\nYou can then run SDX or SD commands.\n";
|
|
|
|
!$main::Sync and do
|
|
{
|
|
print "\n\nYou may want to run 'sdx sync' to sync files in your enlistment.\n";
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Repair
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Repair
|
|
{
|
|
#
|
|
# munge the codebase map to create project, depot and group lists,
|
|
# then query the depots to figure out which depots and projects the
|
|
# user is already enlisted in
|
|
#
|
|
if (SDX::InitForRepair())
|
|
{
|
|
#
|
|
# if rewriting SD.INIs, SD.MAP must also be rewritten
|
|
# easiest to just initially remove it
|
|
#
|
|
($main::MinusI) and unlink $main::SDMap;
|
|
|
|
#
|
|
# for each depot we're repairing
|
|
# get the list of projects in this depot
|
|
# create/update the client view
|
|
# create/update the SD.MAP
|
|
# write the SD.INIs
|
|
#
|
|
foreach $depot (@main::RepairDepots)
|
|
{
|
|
$serverport = @$depot[0];
|
|
$main::V2 and print "\n$serverport\n";
|
|
|
|
#
|
|
# from the list of all projects to repair, create a list of
|
|
# projects found in the current depot only
|
|
#
|
|
@main::ProjectsInThisDepot = ();
|
|
foreach $project (@main::RepairProjects)
|
|
{
|
|
if ($serverport eq @$project[$main::CBMServerPortField])
|
|
{
|
|
push @main::ProjectsInThisDepot, [@{$project}];
|
|
|
|
$main::V2 and print "\t@$project\n";
|
|
}
|
|
}
|
|
|
|
print "\n";
|
|
|
|
#
|
|
# create or update the client view
|
|
# if not repairing only SD.INIs
|
|
#
|
|
if ($main::MinusI)
|
|
{
|
|
print "Repairing enlistment for depot $serverport.\n";
|
|
}
|
|
else
|
|
{
|
|
SDX::EnlistProjects($depot, "repair");
|
|
}
|
|
|
|
#
|
|
# create/update %SDXROOT%\SD.MAP
|
|
#
|
|
SDX::UpdateSDMap("repair");
|
|
|
|
#
|
|
# create/update <projroot>\SD.INI
|
|
#
|
|
SDX::UpdateSDINIs("repair");
|
|
}
|
|
|
|
#
|
|
# finish it off
|
|
#
|
|
SDX::FinishRepair();
|
|
|
|
#
|
|
# success
|
|
#
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
printf "\nThis client wasn't found in the depot(s) for the %s sources. Use 'sd -p\n", "\U$main::CodeBase";
|
|
print "<server:port> clients' to verify that $main::SDClient actually has an enlistment.\n\n";
|
|
|
|
#
|
|
# failure
|
|
#
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# InitForRepair
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub InitForRepair
|
|
{
|
|
#
|
|
# do the common init
|
|
#
|
|
SDX::InitForEDR("repair");
|
|
|
|
#
|
|
# query the depots and make the lists of depots and projects the user
|
|
# is enlisted in
|
|
#
|
|
if (SDX::GetProjectsToRepair())
|
|
{
|
|
SDX::VerifyAccess();
|
|
|
|
#
|
|
# starting verbage
|
|
#
|
|
printf "\n\n\nThis script will repair your enlistment in the %s sources using these\n", "\U$main::CodeBase";
|
|
printf "settings:\n\n";
|
|
printf "\tRoot directory:\t\t%s\n", "\U$main::SDXRoot";
|
|
printf "\tCode branch:\t\t%s\n", "\U$main::Branch";
|
|
printf "\tSD client name:\t\t%s\n", $main::SDClient;
|
|
printf "\tSD user name:\t\t%s\n", $main::SDDomainUser;
|
|
|
|
#
|
|
# print the projects to repair
|
|
#
|
|
$np = $#main::RepairProjects+1;
|
|
printf "\n\tRepairing %s%s project%s...\n\n", ($main::MinusI) ? "SD.INIs for " : "", $np, $np > 1 ? "s" : "";
|
|
foreach $project (@main::RepairProjects)
|
|
{
|
|
printf "\t %s\n", @$project[$main::CBMProjectField];
|
|
}
|
|
|
|
#
|
|
# print the depots to repair
|
|
#
|
|
$nd = $#main::RepairDepots+1;
|
|
printf "\n\t...across %s depot%s:\n\n", $nd, $nd > 1 ? "s" : "";
|
|
foreach $depot (@main::RepairDepots)
|
|
{
|
|
printf "\t %s\n", @$depot[0];
|
|
}
|
|
|
|
print "\n\nIF THESE SETTINGS ARE NOT CORRECT, HIT CTRL-BREAK NOW.\n";
|
|
print " ==================\n\n\n";
|
|
print "Otherwise,\n\n";
|
|
!$main::Quiet and system "pause";
|
|
|
|
print "\n\n";
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
printf "\nNo depots or projects found for client %s. Unable to repair.\n", "\U$main::SDClient";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# FinishRepair
|
|
#
|
|
# Finish up by:
|
|
# maybe syncing projects for the user
|
|
# generating SDINIT and alias files
|
|
# syncing the tools dir
|
|
# syncing any other dirs specified by the codebase map
|
|
# providing friendly verbage
|
|
#
|
|
# Parameters:
|
|
# none
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub FinishRepair
|
|
{
|
|
#
|
|
# cleanup
|
|
#
|
|
unlink $main::ClientView;
|
|
|
|
#
|
|
# sync files or tools if doing more than rewriting SD.INIs
|
|
#
|
|
!$main::MinusI and do
|
|
{
|
|
#
|
|
# maybe re-sync
|
|
#
|
|
$main::Sync and SDX::SyncFiles("repair", $main::Null, $main::Null);
|
|
|
|
#
|
|
# give the user the SD/SDX tools, batch files for aliases and SDX commands
|
|
#
|
|
SDX::ToolsEtc("repair");
|
|
|
|
#
|
|
# also sync any OtherDirs at this time
|
|
#
|
|
@main::OtherDirs and SDX::SyncOtherDirs("repair");
|
|
};
|
|
|
|
#
|
|
# verbage for a succesful repair
|
|
#
|
|
if ($main::MinusI)
|
|
{
|
|
printf "\n\nThe SD.INIs in your %s enlistment have been repaired.\n", "\U$main::CodeBase";
|
|
}
|
|
else
|
|
{
|
|
printf "\n\nYour %s enlistment has been repaired.\n", "\U$main::CodeBase";
|
|
}
|
|
|
|
(!$main::Sync and !$main::MinusI) and do
|
|
{
|
|
print "\nIf you are missing source files, run 'sd sync -f [filespec]' or 'sdx sync -f'\n";
|
|
print "to restore them.\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Defect
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# returns 0 if successful, 1 otherwise
|
|
# _____________________________________________________________________________
|
|
sub Defect
|
|
{
|
|
#
|
|
# munge the codebase map to create project, depot and group lists
|
|
# and figure out what the user wants to defect from
|
|
#
|
|
if (SDX::InitForDefect())
|
|
{
|
|
#
|
|
# for each depot we're defecting from
|
|
# get the list of projects in this depot
|
|
# create/update the client view
|
|
# create/update the SD.MAP
|
|
# write the SD.INIs
|
|
#
|
|
foreach $depot (@main::DefectDepots)
|
|
{
|
|
$serverport = @$depot[0];
|
|
$main::V2 and print "\n$serverport\n";
|
|
|
|
#
|
|
# from the list of all projects to defect from, create a list of
|
|
# projects found in the current depot only
|
|
#
|
|
@main::ProjectsInThisDepot = ();
|
|
foreach $project (@main::DefectProjects)
|
|
{
|
|
if ($serverport eq @$project[$main::CBMServerPortField])
|
|
{
|
|
push @main::ProjectsInThisDepot, [@{$project}];
|
|
$main::V2 and print "\t@$project\n";
|
|
}
|
|
}
|
|
|
|
print "\n";
|
|
|
|
#
|
|
# "update" the projects and INIs by removing them
|
|
#
|
|
SDX::UpdateSDINIs("defect");
|
|
|
|
#
|
|
# remove entries from SD.MAP or remove it entirely if defecting all
|
|
#
|
|
SDX::UpdateSDMap("defect");
|
|
|
|
#
|
|
# remove entries from client view, or delete client if
|
|
# entire view would be removed
|
|
#
|
|
SDX::DefectProjects($depot);
|
|
|
|
print "ok.\n";
|
|
}
|
|
|
|
#
|
|
# finish it off
|
|
#
|
|
SDX::FinishDefect();
|
|
|
|
#
|
|
# success
|
|
#
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
printf "\nSDX had errors reading the file PROJECTS.%s or constructing the list of\n", "\U$main::CodeBase";
|
|
print "projects and depots for defecting. Please contact the SDX alias.\n";
|
|
|
|
#
|
|
# failure
|
|
#
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# InitForDefect
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
# populates @main::DefectDepots and @main::DefectProjects
|
|
# returns 1 if successful or 0 if no projects left in list
|
|
# _____________________________________________________________________________
|
|
sub InitForDefect
|
|
{
|
|
#
|
|
# do the common init
|
|
#
|
|
SDX::InitForEDR("defect");
|
|
|
|
#
|
|
# verify that the branch the user gave us is not one of the
|
|
# projects in the codebase map. if so, they probably forgot to specify
|
|
# the branch name on the cmd line
|
|
#
|
|
foreach $project (@main::AllProjects)
|
|
{
|
|
($main::Branch eq @$project[$main::CBMProjectField]) and die("\nBranch name '$main::Branch' appears to be a project.\n");
|
|
}
|
|
|
|
#
|
|
# from the lists of all projects, groups and depots, create the lists
|
|
# of just those we'll defect from
|
|
#
|
|
SDX::MakeTargetLists("defect");
|
|
|
|
#
|
|
# verify access to the servers now that we have the list of depots made by MakeTargetLists
|
|
#
|
|
SDX::VerifyAccess();
|
|
|
|
#
|
|
# if we have depots and projects to defect from, continue
|
|
# else politely error-out
|
|
#
|
|
if (@main::DefectDepots && @main::DefectProjects)
|
|
{
|
|
#
|
|
# starting verbage
|
|
#
|
|
printf "\n\n\nThis script will defect you from projects in the %s sources using these\n", "\U$main::CodeBase";
|
|
printf "settings:\n\n";
|
|
printf "\tRoot directory:\t\t%s\n", "\U$main::SDXRoot";
|
|
printf "\tCode branch:\t\t%s\n", "\U$main::Branch";
|
|
printf "\tSD client name:\t\t%s\n", $main::SDClient;
|
|
printf "\tSD user name:\t\t%s\n", $main::SDDomainUser;
|
|
|
|
#
|
|
# print the projects to defect
|
|
#
|
|
$np = $#main::DefectProjects+1;
|
|
printf "\n\tDefecting from %s project%s...\n\n", $np, $np > 1 ? "s" : "";
|
|
foreach $project (@main::DefectProjects)
|
|
{
|
|
printf "\t %s\n", @$project[$main::CBMProjectField];
|
|
}
|
|
|
|
#
|
|
# print the depots to defect
|
|
#
|
|
$nd = $#main::DefectDepots+1;
|
|
printf "\n\t...across %s depot%s:\n\n", $nd, $nd > 1 ? "s" : "";
|
|
foreach $depot (@main::DefectDepots)
|
|
{
|
|
printf "\t %s\n", @$depot[0];
|
|
}
|
|
|
|
$main::DefectWithPrejudice and printf "\n\tALL FILES AND DIRECTORIES in %s will be deleted.\n", $np > 1 ? "these projects" : "this project";
|
|
|
|
print "\n\nIF THESE SETTINGS ARE NOT CORRECT, HIT CTRL-BREAK NOW.\n";
|
|
print " ==================\n\n\n";
|
|
print "Otherwise,\n\n";
|
|
!$main::Quiet and system "pause";
|
|
|
|
print "\n\n";
|
|
|
|
#
|
|
# verify that the branch the user wants exists in each depot
|
|
#
|
|
###
|
|
### SDX::VerifyBranch("defect", $nd);
|
|
|
|
#
|
|
# abort if the client still has files open
|
|
#
|
|
my @open = ();
|
|
if (@open = SDX::FilesOpen())
|
|
{
|
|
print "\n\nUnable to defect. Your client has these files open:\n\n";
|
|
print @open;
|
|
print "\nSubmit or revert the files, then rerun this command.\n";
|
|
die("\n");
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
print "\nNo depots or projects found. Unable to defect.\n";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# DefectProjects
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub DefectProjects
|
|
{
|
|
my $depot = $_[0];
|
|
my $serverport = @$depot[0];
|
|
|
|
if ($main::DefectAll)
|
|
{
|
|
#
|
|
# delete client completely
|
|
#
|
|
SDX::DeleteClient($serverport);
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# for this depot, remove some projects from the view
|
|
#
|
|
# if we have a reduced view to register, do it
|
|
# otherwise delete the client entirely from this depot
|
|
#
|
|
if (SDX::RemoveFromView($depot))
|
|
{
|
|
print "\n";
|
|
system "sd.exe -p $serverport client -i < $main::ClientView";
|
|
}
|
|
else
|
|
{
|
|
print "\n";
|
|
|
|
#
|
|
# delete client completely
|
|
#
|
|
SDX::DeleteClient($serverport);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# DeleteClient
|
|
#
|
|
# Delete $main::SDClient. Since clients are locked by default, non-
|
|
# superusers can't delete their client, even with -f, so unlock the client
|
|
# before deleting
|
|
#
|
|
# Parameters:
|
|
# none
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub DeleteClient
|
|
{
|
|
my $serverport = $_[0];
|
|
my @pending = ();
|
|
my @changenums = ();
|
|
|
|
#
|
|
# delete any pending changes owned by this client so we don't orphan them
|
|
#
|
|
@pending = grep(/$main::SDClient \*pending/, `sd.exe -p $serverport -c $main::SDClient changes -s pending`);
|
|
@pending and do
|
|
{
|
|
my $line;
|
|
|
|
$main::V2 and print "pending = '@pending'\n";
|
|
|
|
my @fields = ();
|
|
foreach $line (@pending)
|
|
{
|
|
@fields = split(/ /,$line);
|
|
push @changenums, $fields[1];
|
|
}
|
|
|
|
$main::V2 and print "changenums = '@changenums'\n";
|
|
foreach $line (@changenums)
|
|
{
|
|
`sd.exe -p $serverport change -f -d $line`;
|
|
}
|
|
};
|
|
|
|
#
|
|
# delete it
|
|
#
|
|
system "sd.exe -p $serverport client -d $main::SDClient";
|
|
|
|
#
|
|
# remove depot from the list of active depots
|
|
#
|
|
SDX::UpdateActiveDepots("defect", $serverport);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# FinishDefect
|
|
#
|
|
# Finish up by:
|
|
#
|
|
# Parameters:
|
|
# none
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub FinishDefect
|
|
{
|
|
#
|
|
# cleanup
|
|
#
|
|
unlink $main::ClientView;
|
|
|
|
#
|
|
# write SD.MAP one last time to update the depot list
|
|
#
|
|
if (SDX::GetMapProjects("defect"))
|
|
{
|
|
SDX::WriteSDMap(\@main::ExistingMap);
|
|
}
|
|
|
|
#
|
|
# remove root files only if defecting the world
|
|
#
|
|
$main::DefectAll and SDX::ToolsEtc("defect");
|
|
|
|
#
|
|
# verbage for a successful defect
|
|
#
|
|
print "\n\nOne or more projects were successfully defected.\n";
|
|
|
|
$main::DefectAll and do
|
|
{
|
|
my $path = $main::ToolsProject ? $main::ToolsProjectPath : ($main::SDXRoot . "\\sdtools");
|
|
printf "\nThe SD/SDX tools were in use. Please remove %s manually.\n", "\U$path";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# OtherOp
|
|
# called from sdx.pl to call an SD cmd
|
|
#
|
|
# Parameters:
|
|
# $sdcmd -- basic SD cmd as defined in %main::SDCmds
|
|
# $fulluserargs -- all args as passed in
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub OtherOp
|
|
{
|
|
my $sdcmd = $_[0];
|
|
my $fulluserargs = $_[1];
|
|
my $cmdtype = 0;
|
|
my $defcmd = "";
|
|
my $cmd = "";
|
|
my $fullcmd = "";
|
|
my $project = "";
|
|
my $userargs = "";
|
|
my $string = "";
|
|
|
|
!$sdcmd and die("\nMissing command to OtherOp().\n");;
|
|
|
|
#
|
|
# get the cmd string and default args, and maybe
|
|
# append user args
|
|
#
|
|
$defcmd = $main::SDCmds{$sdcmd}{defcmd};
|
|
$cmdtype = $main::SDCmds{$sdcmd}{type};
|
|
|
|
#
|
|
# strip the '~proj' args out of userargs so they don't pass to SD
|
|
#
|
|
$userargs = $fulluserargs;
|
|
$userargs =~ s/~\w+//g;
|
|
|
|
#
|
|
# see if we're creating a lab or private branch
|
|
#
|
|
# then map lbranch/pbranch to "branch" cmd so -o and -d will work
|
|
#
|
|
my $privatebranch = ($defcmd eq "pbranch" and $userargs !~ /-[do]+/);
|
|
my $labbranch = ($defcmd eq "lbranch" and $userargs !~ /-[do]+/);
|
|
|
|
($defcmd eq "pbranch" or $defcmd eq "lbranch") and $defcmd = "branch";
|
|
|
|
#
|
|
# get the complete command into one string
|
|
#
|
|
$cmd = $defcmd . " " . $main::SDCmds{$sdcmd}{defarg} . $userargs;
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "defcmd = '$defcmd'\n";
|
|
print "fulluserargs = '$fulluserargs'\n";
|
|
print "userargs = '$userargs'\n";
|
|
print "type = '$cmdtype'\n";
|
|
print "defargs = '$main::SDCmds{$sdcmd}{defarg}'\n";
|
|
print "cmd = '$cmd'\n";
|
|
};
|
|
|
|
print "\n";
|
|
|
|
#
|
|
# maybe delete previous log
|
|
#
|
|
$main::Logging and unlink $main::Log;
|
|
|
|
#
|
|
# if branching, give the user some instructions
|
|
#
|
|
$privatebranch and SDX::PrivateBranch($userargs, $main::Null, $main::Null, "start");
|
|
$labbranch and SDX::LabBranch($userargs, $main::Null, $main::Null, "start");
|
|
|
|
#
|
|
# for type 1 commands, where the scope as it appears to the user is per-
|
|
# project, loop through the project list and run $defcmd
|
|
#
|
|
# note that for type 1 codebases (with one project per depot), all commands
|
|
# are essentially type 1
|
|
#
|
|
$cmdtype == 1 and do
|
|
{
|
|
#
|
|
# for each project, change to it's root and run $defcmd
|
|
#
|
|
foreach $projectandroot (@main::SDMapProjects)
|
|
{
|
|
$project = @$projectandroot[0];
|
|
|
|
#
|
|
# common header
|
|
#
|
|
|
|
$header = "\n---------------- \U$project\n";
|
|
|
|
#
|
|
# skip this project if the user negated it on the cmd line with '~project'
|
|
#
|
|
$fulluserargs =~ /~$project / and next;
|
|
|
|
#
|
|
# get path to SD.INI, make sure we have it, and cd there
|
|
#
|
|
$fullprojectroot = $main::SDXRoot . "\\" . @$projectandroot[1];
|
|
$sdini = $fullprojectroot . "\\sd.ini";
|
|
|
|
(-e $sdini) or (print "$header\nCan't find $sdini.\n\nRun 'sdx repair $main::SDMapCodeBase $main::SDMapBranch' to restore it.\n" and next);
|
|
|
|
chdir $fullprojectroot or die("\nCan't cd to $fullprojectroot.\n");
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "project root = '$fullprojectroot'\n";
|
|
};
|
|
|
|
#
|
|
# enumdepots -- internal -- collects server:ports in use
|
|
#
|
|
$defcmd eq "enumdepots" and do
|
|
{
|
|
SDX::EnumDepots($userargs, $project, $sdini);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# files -- count depot files in chunks
|
|
#
|
|
$defcmd eq "files" and do
|
|
{
|
|
SDX::Files($userargs, $project, $header);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# projects -- list enlisted projects and their roots
|
|
#
|
|
$defcmd eq "projects" and do
|
|
{
|
|
SDX::ListProjects($userargs, $project, $header);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# status is a combination of opened and sync -n
|
|
#
|
|
$defcmd eq "status" and do
|
|
{
|
|
SDX::Status($userargs, $project, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# special-case lab branches only if creating one
|
|
#
|
|
$labbranch and do
|
|
{
|
|
SDX::LabBranch($userargs, $project, $header, "modify", $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# handle private branches
|
|
#
|
|
$privatebranch and do
|
|
{
|
|
SDX::PrivateBranch($userargs, $project, $header, "modify", $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# opened may need special handling
|
|
#
|
|
$defcmd eq "opened" and do
|
|
{
|
|
SDX::Opened($userargs, $project, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# resolve -am needs special handling
|
|
#
|
|
$defcmd eq "resolve" and do
|
|
{
|
|
SDX::Resolve($userargs, $project, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# submit may be using a comment from the cmd line
|
|
#
|
|
$defcmd eq "submit" and do
|
|
{
|
|
SDX::Submit($userargs, $project, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# sync/flush may need the -q(uiet) flag
|
|
#
|
|
($defcmd eq "sync" or $defcmd eq "flush") and do
|
|
{
|
|
SDX::SyncFlush($defcmd, $userargs, $project, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# it's none of the above, so print or run the final cmd string
|
|
#
|
|
$fullcmd = "sd.exe $cmd 2>&1";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
};
|
|
|
|
#
|
|
# for type 2 commands, where the cmd makes sense only at the depot level, loop
|
|
# through the depot list and run $defcmd
|
|
#
|
|
# type 2 commands only exist when the depot structure is type 2, where N projects
|
|
# exist per depot
|
|
#
|
|
$cmdtype == 2 and do
|
|
{
|
|
#
|
|
# for type 2 commands read the codebase map
|
|
# and figure out the depot type
|
|
#
|
|
SDX::GetDepotTypes();
|
|
|
|
#
|
|
# run the cmd on each depot
|
|
#
|
|
foreach $serverport (@main::SDMapDepots)
|
|
{
|
|
#
|
|
# for type 1 depots, get the project name
|
|
#
|
|
$project = (@{$main::DepotType{$serverport}}[0] == 1) ? "@{$main::DepotType{$serverport}}[1]\n" : "$serverport [MULTIPROJECT DEPOT]\n";
|
|
chop $project;
|
|
|
|
#
|
|
# header depends on depot type
|
|
#
|
|
# for type 1, show the project name
|
|
# for type 2, show the server:port
|
|
#
|
|
$header = "\n---------------- ";
|
|
$header .= "\U$project\n";
|
|
|
|
#
|
|
# skip this depot if it's type 1 and the user negated it on the cmd line with '~project'
|
|
#
|
|
$fulluserargs =~ /~$project / and next;
|
|
|
|
#
|
|
# special-case lab branches only if creating one
|
|
#
|
|
$labbranch and do
|
|
{
|
|
SDX::LabBranch($userargs, $serverport, $header, "modify", $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# handle private branches
|
|
#
|
|
$privatebranch and do
|
|
{
|
|
SDX::PrivateBranch($userargs, $serverport, $header, "modify", $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# opened may need special handling
|
|
#
|
|
$defcmd eq "opened" and do
|
|
{
|
|
SDX::Opened($userargs, $serverport, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# resolve -am needs special handling
|
|
#
|
|
$defcmd eq "resolve" and do
|
|
{
|
|
SDX::Resolve($userargs, $serverport, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# submit may be using a comment from the cmd line
|
|
#
|
|
$defcmd eq "submit" and do
|
|
{
|
|
SDX::Submit($userargs, $serverport, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# sync/flush may need the -q(uiet) flag
|
|
#
|
|
($defcmd eq "sync" or $defcmd eq "flush") and do
|
|
{
|
|
SDX::SyncFlush($defcmd, $userargs, $serverport, $header, $cmdtype);
|
|
next;
|
|
};
|
|
|
|
#
|
|
# it's none of the above, so print or run the final cmd string
|
|
#
|
|
$fullcmd = "sd.exe -p $serverport $cmd 2>&1";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
};
|
|
|
|
#
|
|
# if we just branched, give the user some instructions
|
|
#
|
|
$privatebranch and SDX::PrivateBranch($userargs, $main::Null, $main::Null, "end");
|
|
$labbranch and SDX::LabBranch($userargs, $main::Null, $main::Null, "end");
|
|
|
|
#
|
|
# print a file counter summary
|
|
#
|
|
SDX::PrintStats($defcmd, $userargs);
|
|
|
|
#
|
|
# success
|
|
#
|
|
return 0;
|
|
}
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Delta
|
|
# called from sdx.pl to calculate the changes in a given project
|
|
#
|
|
# Parameters:
|
|
# $fulluserargs -- all args as passed in
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Delta
|
|
{
|
|
local $base_change, $current_change;
|
|
local %baseline;
|
|
|
|
my $fulluserargs = $_[1];
|
|
my $cmd = "";
|
|
my $project = "";
|
|
my $string = "";
|
|
my $generate = 0;
|
|
|
|
if($fulluserargs) {
|
|
$fulluserargs =~ s/^\s+(.*)/$1/;
|
|
}
|
|
|
|
if($fulluserargs) {
|
|
@args = split /\s+/, $fulluserargs;
|
|
$generate = 0;
|
|
print "Checking for differences from baseline change number(s):\n";
|
|
} else {
|
|
$generate = 1;
|
|
}
|
|
|
|
#
|
|
# parse the arguments to get the base change number for each project.
|
|
#
|
|
|
|
foreach $entry (@args) {
|
|
($project, $change) = split /=/, $entry;
|
|
$baseline{$project} = $change;
|
|
}
|
|
|
|
#
|
|
# maybe delete previous log
|
|
#
|
|
$main::Logging and unlink $main::Log;
|
|
|
|
#
|
|
# for type 1 commands, where the scope as it appears to the user is per-
|
|
# project, loop through the project list and run $defcmd
|
|
#
|
|
# note that for type 1 codebases (with one project per depot), all commands
|
|
# are essentially type 1
|
|
#
|
|
|
|
#
|
|
# for each project, change to it's root and run $defcmd
|
|
#
|
|
|
|
foreach $projectandroot (@main::SDMapProjects)
|
|
{
|
|
$project = @$projectandroot[0];
|
|
|
|
#if(($generate == 0) && (!defined($baseline{$project}))) {
|
|
# print "no baseline for $project\n";
|
|
# next;
|
|
#}
|
|
|
|
#
|
|
# get path to SD.INI, make sure we have it, and cd there
|
|
#
|
|
$fullprojectroot = $main::SDXRoot . "\\" . @$projectandroot[1];
|
|
$sdini = $fullprojectroot . "\\sd.ini";
|
|
(-e $sdini) or (print "$header\nCan't find $sdini.\n\nRun 'sdx repair $main::SDMapCodeBase $main::SDMapBranch' to restore it.\n" and next);
|
|
chdir $fullprojectroot or die("\nCan't cd to $fullprojectroot.\n");
|
|
|
|
#
|
|
# Find out what the most recent change in this project is.
|
|
#
|
|
|
|
open FILE, "sd.exe changes -m 1 ...#have 2>&1|" or die("\nDelta: can't open pipe for $string\n");
|
|
my $line = <FILE>;
|
|
close FILE;
|
|
|
|
if($line =~ /Change ([0-9]+)/) {
|
|
$current_change = $1;
|
|
} else {
|
|
print "Error retrieving change: $line\n" if ($baseline);
|
|
next;
|
|
}
|
|
|
|
#
|
|
# if we have no baseline changes to compare against then just generate
|
|
# a command line which could be passed in later.
|
|
#
|
|
|
|
if($generate == 1) {
|
|
print "$project=$current_change ";
|
|
next;
|
|
}
|
|
|
|
print "$project: ";
|
|
|
|
#
|
|
# now check to see if we have an entry for this project in the
|
|
# baseline passed in.
|
|
#
|
|
|
|
$base_change = $baseline{$project};
|
|
#print "$baseline{$project} = $base_change\n";
|
|
|
|
if (!defined($base_change)) {
|
|
print "at change $current_change (no previous change # provided)\n";
|
|
next;
|
|
}
|
|
|
|
if ($base_change == $current_change) {
|
|
print "at original change $current_change\n";
|
|
next;
|
|
}
|
|
|
|
if ($base_change > $current_change) {
|
|
print "reverted from change $base_change to $current_change\n";
|
|
next;
|
|
}
|
|
|
|
#
|
|
# the current highest change number is > than the one in the baseline
|
|
# passed in. Try to determine which changes (if any) have been picked
|
|
# up.
|
|
#
|
|
|
|
#
|
|
# first check to see if we're just sunk to the new change number.
|
|
# do this by syncing to it again (-n). If no new files would be
|
|
# picked up then we're done.
|
|
#
|
|
|
|
$string = "sd.exe sync -n \@$current_change 2>&1|";
|
|
#print "$string\n";
|
|
open FILE, $string or die("\nCan't open pipe for $string\n");
|
|
$change_line = <FILE>;
|
|
close FILE;
|
|
|
|
#print "change_line = $change_line\n";
|
|
#print "substr = *", substr($change_line, 0, 1), "*\n";
|
|
if(substr($change_line, 0, 1) eq "@") {
|
|
print "updated from change $base_change to $current_change\n";
|
|
next;
|
|
}
|
|
|
|
#
|
|
# no such luck.
|
|
# get a list of all the files which are different (by syncing to the
|
|
# baseline change number) and print them out grouped by change number.
|
|
#
|
|
|
|
print "has files between change $base_change and $current_change (listing follows):\n";
|
|
|
|
$string = "sd.exe sync -n ...\@$base_change 2>&1|";
|
|
#print "$string\n";
|
|
|
|
open FILE, $string or die("\nDelta: can't open pipe for $string\n");
|
|
foreach $change_line (<FILE>) {
|
|
#print "raw: $change_line\n";
|
|
if(substr($change_line, 0, 2) != "//") {
|
|
print "error of some form\n";
|
|
last;
|
|
}
|
|
|
|
@t = split /\#/, $change_line;
|
|
#print "chopped: $t[0]\n";
|
|
|
|
$string = "sd.exe have $t[0] 2>&1|";
|
|
#print "$string\n";
|
|
open FILE2, $string or die("\nDelta: can't open pipe for $string\n");
|
|
$line = <FILE2>;
|
|
close FILE2;
|
|
|
|
@t = split / - /, $line;
|
|
|
|
print "\t$t[0]\n";
|
|
}
|
|
close FILE;
|
|
}
|
|
print "\n";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# RunSDCmd
|
|
#
|
|
# Print the header, then print or call the SD cmd
|
|
#
|
|
# Parameters:
|
|
# $string user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub RunSDCmd
|
|
{
|
|
my $header = $_[0];
|
|
my $fullcmd = $_[1];
|
|
|
|
#
|
|
# print the header
|
|
#
|
|
SDX::PrintCmd($header, 0);
|
|
|
|
#
|
|
# print or run the cmd
|
|
#
|
|
if ($main::V2)
|
|
{
|
|
SDX::PrintCmd($fullcmd, 1);
|
|
}
|
|
else
|
|
{
|
|
SDX::RunCmd($fullcmd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# PrintCmd
|
|
#
|
|
# Print cmd header or string
|
|
#
|
|
# Parameters:
|
|
# $string user output
|
|
# $op 0 - header, 1 - cmd
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub PrintCmd
|
|
{
|
|
my $string = $_[0];
|
|
my $op = $_[1];
|
|
|
|
$main::Logging and (open LOG, ">>$main::Log" or die("\nCan't append $main::Log.\n"));
|
|
|
|
$op == 0 and do
|
|
{
|
|
print "$string";
|
|
$main::Logging and print LOG "$string";
|
|
};
|
|
|
|
$op == 1 and do
|
|
{
|
|
print "`$string`\n";
|
|
$main::Logging and print LOG "`$string`\n";
|
|
};
|
|
|
|
$main::Logging and close LOG;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# RunCmd
|
|
#
|
|
# Run the given SD cmd, capturing the output, and maybe printing it to STDERR
|
|
#
|
|
# Parameters:
|
|
# $string user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub RunCmd
|
|
{
|
|
my $string = $_[0];
|
|
my $out = "";
|
|
my $resolved = ($string =~ / resolved /);
|
|
my $mergefile = "";
|
|
my @list = ();
|
|
|
|
!$string and die("\nNo command string in RunCmd.\n");
|
|
|
|
my $skippublic = 0;
|
|
|
|
#
|
|
# if NT, if not using -a, and if not verbose, filter out changes associated
|
|
# with the public change number
|
|
#
|
|
("\U$main::CodeBase" eq "NT" and ($main::UserArgs !~ /-a/) and ($main::PublicChangeNum and !$main::MinusV)) and do
|
|
{
|
|
$skippublic++;
|
|
};
|
|
|
|
#
|
|
# special-case sdx {clients|users} -t and -a
|
|
# set flags, maybe remove -t from cmd string
|
|
#
|
|
my $fa = ($string =~ / files / and $main::MinusA);
|
|
my $ca = ($string =~ / clients / and $main::MinusA);
|
|
my $ua = ($string =~ / users / and $main::MinusA);
|
|
my $ct = ($string =~ / clients / and $string =~ / -t /);
|
|
my $ut = ($string =~ / users / and $string =~ / -t /);
|
|
$ct and $string =~ s/-t//g;
|
|
$ut and $string =~ s/-t//g;
|
|
|
|
#
|
|
# run the cmd
|
|
#
|
|
# for commands like manual resolve that need user input, run them with the shell
|
|
#
|
|
if ($string =~ / resolve / and $string !~ /-a[tymf]*|-n/)
|
|
{
|
|
system "$string";
|
|
}
|
|
elsif ($main::MinusI and !$main::MinusH)
|
|
{
|
|
#
|
|
# write the input form to stdin
|
|
#
|
|
# no logging for now
|
|
#
|
|
open FILE, "| $string" or die("\nRunCMD: can't open pipe for $string.\n");
|
|
foreach (@main::InputForm) { print FILE "$_"; }
|
|
close FILE;
|
|
}
|
|
else
|
|
{
|
|
$main::Logging and (open LOG, ">>$main::Log" or die("\nCan't append $main::LOG\n"));
|
|
|
|
#
|
|
# run cmd unless sdx files -a
|
|
#
|
|
(!$fa) and do
|
|
{
|
|
open FILE, "$string |" or die("\nRunCMD: can't open pipe for $string\n");
|
|
};
|
|
|
|
my $quiet = $main::Quiet;
|
|
|
|
while (<FILE>)
|
|
{
|
|
#
|
|
# be noisy as soon as we see an SD error
|
|
#
|
|
/ error:/ and do
|
|
{
|
|
$main::Quiet = $main::FALSE;
|
|
$main::DepotErrors++;
|
|
};
|
|
|
|
#
|
|
# if skipping public changes, maybe skip this line
|
|
#
|
|
($skippublic and / change $main::PublicChangeNum/) and do
|
|
{
|
|
next;
|
|
};
|
|
|
|
#
|
|
# if sdx {clients|users} -a, save for later
|
|
#
|
|
($ca or $ua) and do
|
|
{
|
|
push @list, $_;
|
|
next;
|
|
};
|
|
|
|
#
|
|
# reformat for sdx {clients|users} -t and save for sorting later
|
|
#
|
|
($ct or $ut) and do
|
|
{
|
|
chop $_;
|
|
|
|
#
|
|
# remove friendly user name before splitting
|
|
#
|
|
$ut and $_ =~ s/\([_\. $A-Za-z0-9\\-]*\)//g;
|
|
|
|
@fields = split(/ /, $_);
|
|
|
|
$ct and do
|
|
{
|
|
my $u = @fields[$#fields-1];
|
|
$u =~ s/\.$//g;
|
|
push @list, sprintf("%s:%s %-20s %-20s %s\n", @fields[2], @fields[3], @fields[1], $u, @fields[5]);
|
|
};
|
|
|
|
$ut and push @list, sprintf("%s:%s %-20s\n", @fields[4], @fields[5], @fields[0]);
|
|
|
|
next;
|
|
};
|
|
|
|
#
|
|
# show results
|
|
#
|
|
# not logging, not quiet -- print to stdout
|
|
# not logging, quiet -- do not print to stdout
|
|
# logging, not quiet -- print to log
|
|
# logging, quiet -- print to log
|
|
#
|
|
|
|
#
|
|
# -q on sd <command> -o throws away only comment lines
|
|
#
|
|
($main::Quiet and $main::MinusO and /#/) and next;
|
|
|
|
#
|
|
# show progress on stdout if not quiet
|
|
# or show on stdout if quiet but sd cmd includes -o
|
|
#
|
|
(!$main::Quiet or ($main::Quiet and $main::MinusO)) and print;
|
|
|
|
#
|
|
# maybe log output
|
|
#
|
|
$main::Logging and print LOG;
|
|
|
|
#
|
|
# keep some stats
|
|
#
|
|
($resolved and / - /) and $main::FilesResolved++;
|
|
|
|
/ - branch\/sync from / and $main::IntFilesAdded++;
|
|
/ - branch from / and $main::IntFilesAdded++;
|
|
/ - delete from / and $main::IntFilesDeleted++;
|
|
/ - sync\/integrate from / and $main::IntFilesChanged++;
|
|
/ - integrate from / and $main::IntFilesChanged++;
|
|
/ - updating / and $main::FilesUpdated++;
|
|
/ - updated/ and $main::LabelFilesUpdated++;
|
|
/ - add / and $main::FilesOpenAdd++;
|
|
/ - delete / and $main::FilesOpenDelete++;
|
|
/ - edit / and $main::FilesOpenEdit++;
|
|
/ - added / and $main::FilesAdded++;
|
|
/ - added/ and $main::LabelFilesAdded++;
|
|
|
|
/ - deleted / and $main::FilesDeleted++;
|
|
/ - deleted/ and $main::LabelFilesDeleted++;
|
|
|
|
/ - merging | - vs / and do
|
|
{
|
|
$main::FilesToMerge++;
|
|
$mergefile = $_;
|
|
};
|
|
|
|
/ - must resolve / and $main::FilesToResolve++;
|
|
/ - resolve skipped/ and $main::FilesSkipped++;
|
|
|
|
/ [1-9][0-9]* conflicting/ and do
|
|
{
|
|
$main::FilesConflicting++;
|
|
push @main::ConflictingFiles, $mergefile;
|
|
$mergefile = "";
|
|
};
|
|
|
|
/ 0 conflicting| - copy from / and $main::FilesNotConflicting++;
|
|
/ clobber / and $main::FilesNotClobbered++;
|
|
/ reverted/ and $main::FilesReverted++;
|
|
|
|
### submits don't come through this block
|
|
### / - already locked / and $main::FilesLocked++;
|
|
### /Submit failed / and $main::FailedSubmits++;
|
|
}
|
|
|
|
#
|
|
# keep track of catastrophic sd.exe errors
|
|
#
|
|
close FILE or $main::DepotErrors++;
|
|
|
|
|
|
#
|
|
# sort and print
|
|
#
|
|
($ct or $ut) and do
|
|
{
|
|
@list = sort @list;
|
|
|
|
for (@list)
|
|
{
|
|
#
|
|
# show progress on stdout if not quiet
|
|
#
|
|
(!$main::Quiet) and print;
|
|
|
|
#
|
|
# maybe log output
|
|
#
|
|
$main::Logging and print LOG;
|
|
}
|
|
|
|
my $s = "\nTotal:\t$#list\n";
|
|
!$main::Quiet and print $s;
|
|
$main::Logging and print LOG $s;
|
|
};
|
|
|
|
#
|
|
# print totals for client/user counts
|
|
#
|
|
($ca or $ua) and do
|
|
{
|
|
!$main::Quiet and print "\nTotal:\t$#list\n";
|
|
$main::Logging and print LOG "\nTotal:\t$#list\n";
|
|
};
|
|
|
|
#
|
|
# print totals for file counts
|
|
#
|
|
($fa) and do
|
|
{
|
|
foreach (@main::FileChunks)
|
|
{
|
|
#
|
|
# show progress on stdout if not quiet
|
|
#
|
|
!$main::Quiet and print "$_\n";
|
|
|
|
#
|
|
# maybe log output
|
|
#
|
|
$main::Logging and print LOG "$_\n";
|
|
}
|
|
|
|
my $s = sprintf "%53s\nTotal:%47s\n", "=======", $main::DepotFiles;
|
|
!$main::Quiet and print $s;
|
|
$main::Logging and printf LOG $s;
|
|
};
|
|
|
|
$main::Logging and close LOG;
|
|
|
|
#
|
|
# maybe restore quiet mode for next SD call
|
|
#
|
|
$main::Quiet = $quiet;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# PrintStats
|
|
#
|
|
# Dump the file counters
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub PrintStats
|
|
{
|
|
my $defcmd = $_[0];
|
|
my $userargs = $_[1];
|
|
my $syncresolve = $main::FALSE;
|
|
my @counters = ("\n\n\n");
|
|
|
|
$userargs =~ /-a[fm]/ and $syncresolve = $main::TRUE;
|
|
|
|
$defcmd eq "integrate" and do
|
|
{
|
|
push @counters, sprintf "== Summary ==========\n";
|
|
push @counters, sprintf "\nAdded:%15s\n", $main::IntFilesAdded;
|
|
push @counters, sprintf "Deleted:%13s\n", $main::IntFilesDeleted;
|
|
push @counters, sprintf "Integrated:%10s\n", $main::IntFilesChanged;
|
|
push @counters, sprintf "\nTotal:%15s\n", $main::IntFilesAdded + $main::IntFilesDeleted + $main::IntFilesChanged;
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "$spacer%3s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "=====================\n";
|
|
};
|
|
|
|
($defcmd eq "sync" or $defcmd eq "flush") and do
|
|
{
|
|
my $header = "== Summary =========";
|
|
my $footer = "====================";
|
|
my $spacer = "";
|
|
|
|
$main::MinusH and do
|
|
{
|
|
$header .= "==============";
|
|
$spacer = " ";
|
|
};
|
|
|
|
#
|
|
# adjust update total
|
|
#
|
|
($main::FilesUpdated >= $main::FilesNotClobbered) and $main::FilesUpdated -= $main::FilesNotClobbered;
|
|
|
|
#
|
|
# print file stats
|
|
#
|
|
push @counters, sprintf "%s%s\n", $header, ($main::FilesSkipped or $main::FilesConflicting) ? "==========================================================" : "";
|
|
push @counters, sprintf "\nUpdated:%s%12s\n", $spacer, $main::FilesUpdated;
|
|
$main::FilesNotClobbered and push @counters, sprintf "Not Updated:%s%8s\n", $spacer, $main::FilesNotClobbered;
|
|
push @counters, sprintf "Added:%s%14s\n", $spacer, $main::FilesAdded;
|
|
push @counters, sprintf "Deleted:%s%12s\n", $spacer, $main::FilesDeleted;
|
|
|
|
#
|
|
# if no resolve use one resolve counter
|
|
#
|
|
(!$syncresolve and $main::FilesToResolve) and push @counters, sprintf "\nTo Resolve:%s%9s\n", $spacer, $main::FilesToResolve;
|
|
|
|
#
|
|
# else use others
|
|
#
|
|
$syncresolve and do
|
|
{
|
|
$main::FilesNotConflicting and push @counters, sprintf "Resolved:%s%11s\n", $spacer, $main::FilesNotConflicting;
|
|
$main::FilesSkipped and push @counters, sprintf "\nSkipped:%s%12s\n", $spacer, $main::FilesSkipped;
|
|
(!$main::FilesSkipped and $main::FilesConflicting) and push @counters, sprintf "\nConflicting:%s%8s\n", $spacer, $main::FilesConflicting;
|
|
};
|
|
|
|
#
|
|
# total count depends on whether we resolved
|
|
#
|
|
my $total = $main::FilesUpdated + $main::FilesNotClobbered + $main::FilesAdded + $main::FilesDeleted;
|
|
if ($syncresolve)
|
|
{
|
|
$total += $main::FilesNotConflicting;
|
|
|
|
$total += ($main::FileSkipped) ? $main::FilesSkipped : $main::FilesConflicting;
|
|
}
|
|
else
|
|
{
|
|
$total += $main::FilesToResolve;
|
|
}
|
|
|
|
push @counters, sprintf "\nTotal:%s%14s\n", $spacer, $total;
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "$spacer%2s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
#
|
|
# call out resolve problems
|
|
#
|
|
($main::FilesSkipped or $main::FilesConflicting) and do
|
|
{
|
|
if ($main::FilesSkipped)
|
|
{
|
|
push @counters, sprintf "\n\nSkipped Files [resolve manually]\n\n";
|
|
}
|
|
else
|
|
{
|
|
push @counters, sprintf "\n\nConflicting Files [edit and fix merge conflicts]\n\n";
|
|
}
|
|
|
|
foreach $file (@main::ConflictingFiles)
|
|
{
|
|
@fields = split(/ /,$file);
|
|
push @counters, sprintf "@fields[1]\n";
|
|
}
|
|
};
|
|
|
|
#
|
|
# if sync/flush is tracking changelists, print change stats
|
|
#
|
|
($main::MinusH) and do
|
|
{
|
|
my $total = $main::Changes;
|
|
|
|
push @counters, sprintf "\nChanges in this branch:%11s\n", $main::Changes;
|
|
|
|
$main::MinusI and do
|
|
{
|
|
push @counters, sprintf "Changes in other branches:%8s\n", $main::IntegrationChanges;
|
|
$total += $main::IntegrationChanges;
|
|
};
|
|
|
|
push @counters, sprintf "\nTotal:%28s\n", $total;
|
|
|
|
$footer .= "==============";
|
|
};
|
|
|
|
push @counters, sprintf "%s%s\n", $footer, ($main::FilesSkipped or $main::FilesConflicting) ? "==========================================================" : "";
|
|
};
|
|
|
|
$defcmd eq "opened" and do
|
|
{
|
|
push @counters, sprintf "== Summary =============\n";
|
|
push @counters, sprintf "\nOpen for Add:%11s\n", $main::FilesOpenAdd;
|
|
push @counters, sprintf "Open for Edit:%10s\n", $main::FilesOpenEdit;
|
|
push @counters, sprintf "Open for Delete:%8s\n", $main::FilesOpenDelete;
|
|
push @counters, sprintf "\nTotal:%18s\n", $main::FilesOpenAdd + $main::FilesOpenDelete + $main::FilesOpenEdit;
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "%6s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "========================\n";
|
|
};
|
|
|
|
$defcmd eq "labelsync" and do
|
|
{
|
|
push @counters, sprintf "== Summary =========\n";
|
|
push @counters, sprintf "\nAdded:%14s\n", $main::LabelFilesAdded;
|
|
push @counters, sprintf "Deleted:%12s\n", $main::LabelFilesDeleted;
|
|
push @counters, sprintf "Updated:%12s\n", $main::LabelFilesUpdated;
|
|
push @counters, sprintf "\nTotal:%14s\n", $main::LabelFilesAdded + $main::LabelFilesDeleted + $main::LabelFilesUpdated;
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "%2s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "====================\n";
|
|
};
|
|
|
|
$defcmd eq "resolve" and do
|
|
{
|
|
push @counters, sprintf "== Summary ===========\n";
|
|
|
|
if ($userargs =~ /-n/)
|
|
{
|
|
push @counters, sprintf "\nTo Resolve:%11s\n", $main::FilesToMerge;
|
|
}
|
|
else
|
|
{
|
|
push @counters, sprintf "\nResolved:%13s\n", $main::FilesNotConflicting;
|
|
|
|
$main::FilesSkipped and push @counters, sprintf "Skipped:%14s\n", $main::FilesSkipped;
|
|
(!$main::FilesSkipped and $main::FilesConflicting) and push @counters, sprintf "Conflicting:%10s\n", $main::FilesConflicting;
|
|
|
|
my $total = $main::FilesNotConflicting;
|
|
$total += ($main::FileSkipped) ? $main::FilesSkipped : $main::FilesConflicting;
|
|
push @counters, sprintf "\nTotal:%16s\n", $total;
|
|
}
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "%4s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "======================\n";
|
|
};
|
|
|
|
$defcmd eq "resolved" and do
|
|
{
|
|
push @counters, sprintf "== Summary ===========\n";
|
|
push @counters, sprintf "\nResolved:%13s\n", $main::FilesResolved;
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "%4s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "======================\n";
|
|
};
|
|
|
|
$defcmd eq "revert" and do
|
|
{
|
|
push @counters, sprintf "== Summary ===========\n";
|
|
push @counters, sprintf "\nReverted:%13s\n", $main::FilesReverted;
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "%4s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "======================\n";
|
|
};
|
|
|
|
=begin comment text
|
|
$defcmd eq "submit" and do
|
|
{
|
|
push @counters, sprintf "== Summary ===========\n";
|
|
$main::FailedSubmits and do
|
|
{
|
|
push @counters, sprintf "\nFailed Submits:%8s\n", $main::FailedSubmits;
|
|
push @counters, sprintf "\nFiles Locked by Others:%8s\n", $main::FilesLocked;
|
|
};
|
|
|
|
#
|
|
# call out fatal SD client errors
|
|
#
|
|
my $pad = sprintf "%4s", "";
|
|
$main::DepotErrors and SDX::DepotErrors(\@counters, $pad, $main::DepotErrors);
|
|
|
|
push @counters, sprintf "======================\n";
|
|
};
|
|
=end comment text
|
|
=cut
|
|
|
|
#
|
|
# print to stdout and maybe to the log file
|
|
# print the stats except in extra-quiet mode
|
|
#
|
|
foreach (@counters) { print; }
|
|
|
|
$main::Logging and do
|
|
{
|
|
open LOG, ">>$main::Log" or die("\nCan't append $main::LOG\n");
|
|
foreach (@counters) { print LOG; }
|
|
close LOG;
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# LabBranch
|
|
#
|
|
# called from OtherOp() to create a single high-level branch in the current
|
|
# project or depot
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if cmd type 2, project name if type 1
|
|
# $header user output
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub LabBranch
|
|
{
|
|
my $labbranch = "\L$_[0]";
|
|
my $spproject = $_[1];
|
|
my $header = $_[2];
|
|
my $op = $_[3];
|
|
my $cmdtype = $_[4];
|
|
my $branchview = "$ENV{TMP}\\branchview";
|
|
my $fullcmd = "";
|
|
|
|
#
|
|
# trim out ws
|
|
#
|
|
$labbranch =~ s/[\t\s]*//g;
|
|
|
|
!$labbranch and die("\nMissing branch name. Run 'sdx labbranch /?' for more information.\n");
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\nbranch = '$labbranch'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
#
|
|
# branch can't be Main
|
|
#
|
|
$labbranch eq "main" and die("\n'Main' is a reserved branch name.\n");
|
|
|
|
#
|
|
# print lab dev branch instructions
|
|
#
|
|
$op eq "start" and do
|
|
{
|
|
printf "\n\nThis script will create virtual lab branch %s.\n", "\U$labbranch";
|
|
|
|
if ($cmdtype == 1)
|
|
{
|
|
printf "\nIf %s is a new branch, for each project you are enlisted in, a branch\n", "\U$labbranch";
|
|
print "view of\n";
|
|
|
|
print "\n //depot/main/<project>/... //depot/$labbranch/<project>/...\n";
|
|
|
|
print "\nwill be used to map files into the branch.\n";
|
|
|
|
printf "\nIf %s exists, you can edit its view to add or remove directories and files.\n", "\U$labbranch";
|
|
|
|
print "\nYou can then integrate changes into the branch.\n";
|
|
}
|
|
else
|
|
{
|
|
print "\nLab branching is under construction for N:1 depots.\n";
|
|
}
|
|
|
|
print "\n\nIF YOU ARE NOT READY TO BRANCH, HIT CTRL-BREAK NOW.\n";
|
|
print " ==================\n\n\n";
|
|
print "Otherwise,\n\n";
|
|
system "pause";
|
|
|
|
print "\n\n";
|
|
};
|
|
|
|
#
|
|
# create branch in this project or depot
|
|
#
|
|
# called from loop in OtherOp
|
|
#
|
|
$op eq "modify" and do
|
|
{
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
|
|
#
|
|
# if the branch already exists, the user just wants to modify it, so
|
|
# give them the UI
|
|
# else
|
|
# create the default branch spec
|
|
#
|
|
if (SDX::BranchExists($labbranch, $sp, "", "by-name"))
|
|
{
|
|
my $fullcmd = "sd.exe $sp branch $labbranch";
|
|
$header .= "Updating branch $labbranch...\n";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
else
|
|
{
|
|
$main::CreatingBranch = $main::TRUE;
|
|
|
|
#
|
|
# create default spec
|
|
#
|
|
SDX::WriteDefaultBranch($spproject, $labbranch, $header, $sp, "lab");
|
|
}
|
|
};
|
|
|
|
#
|
|
# give the user instructions for adding the branch to their client view
|
|
#
|
|
$op eq "end" and do
|
|
{
|
|
print "\n\n\nDone.\n";
|
|
|
|
printf "\nTo use %s, you must:\n", "\U$labbranch";
|
|
|
|
print "\n 1. Populate the tools in the Root project\n";
|
|
|
|
print "\n 2. Enlist in the branch\n";
|
|
|
|
print "\n 3. Integrate changes to it and resolve merge conflicts\n";
|
|
|
|
print "\n 4. Submit your changes\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# PrivateBranch
|
|
#
|
|
# called from OtherOp() to create a private dev branch in each enlisted
|
|
# project/depot
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if cmd type 2, project name if type 1
|
|
# $header user output
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub PrivateBranch
|
|
{
|
|
my $pbranch = "\L$_[0]";
|
|
my $spproject = $_[1];
|
|
my $header = $_[2];
|
|
my $op = $_[3];
|
|
my $cmdtype = $_[4];
|
|
|
|
#
|
|
# trim out ws
|
|
#
|
|
$pbranch =~ s/[\t\s]*//g;
|
|
|
|
!$pbranch and die("\nMissing branch name. Run 'sdx privatebranch /?' for more information.\n");
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\nbranch = '$pbranch'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
#
|
|
# branch can't be Main
|
|
#
|
|
$pbranch eq "main" and die("\n'Main' is a reserved branch name.\n");
|
|
|
|
#
|
|
# print private dev branch instructions
|
|
#
|
|
$op eq "start" and do
|
|
{
|
|
printf "\n\nThis script will create or update private development branch %s.\n", "\U$pbranch";
|
|
|
|
printf "\nIf %s is a new branch, for each %s you are enlisted in this will:\n", "\U$pbranch", $cmdtype == 1 ? "project" : "depot";
|
|
|
|
print "\n 1. Create a default branch view, with placeholders representing\n";
|
|
printf " your project %s\n", $cmdtype == 1 ? "" : "and component";
|
|
|
|
print "\n 2. Ask you to edit the view to include only those directories and\n";
|
|
print " files you need in the branch\n";
|
|
|
|
printf "\nIf %s exists, you can edit its view to add or remove directories and files.\n", "\U$pbranch";
|
|
|
|
print "\nYou can then add the branched files to your client view and integrate\n";
|
|
print "changes into the branch.\n";
|
|
|
|
printf "\n\nIF YOU ARE NOT READY TO BRANCH, HIT CTRL-BREAK NOW.\n";
|
|
printf " ==================\n\n\n";
|
|
print "Otherwise,\n\n";
|
|
system "pause";
|
|
|
|
print "\n\n";
|
|
};
|
|
|
|
#
|
|
# create branch in this project or depot
|
|
#
|
|
# called from loop in OtherOp
|
|
#
|
|
$op eq "modify" and do
|
|
{
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
|
|
#
|
|
# if the branch already exists, the user just wants to modify it, so
|
|
# give them the UI
|
|
# else
|
|
# create and register the default branch spec, then call branch again
|
|
# and let the user edit out the placeholders
|
|
#
|
|
if (SDX::BranchExists($pbranch, $sp, "", "by-name"))
|
|
{
|
|
my $fullcmd = "sd.exe $sp branch $pbranch";
|
|
$header .= "Updating branch $pbranch...\n";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
else
|
|
{
|
|
$main::CreatingBranch = $main::TRUE;
|
|
|
|
#
|
|
# create default spec
|
|
#
|
|
SDX::WriteDefaultBranch($spproject, $pbranch, $header, $sp, "private");
|
|
|
|
#
|
|
# user must edit to remove the placeholders
|
|
#
|
|
SDX::EditBranch($sp, $pbranch);
|
|
}
|
|
};
|
|
|
|
#
|
|
# give the user instructions for adding the branch to their client view
|
|
#
|
|
$op eq "end" and do
|
|
{
|
|
print "\n\n\nDone.\n";
|
|
|
|
printf "\nTo use %s, you must:\n", "\U$pbranch";
|
|
|
|
print "\n 1. Modify your client view to include the branched files\n";
|
|
|
|
print "\n 2. Integrate changes to the branch and resolve merge conflicts\n";
|
|
|
|
print "\n 3. Submit your changes\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteDefaultBranch
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub WriteDefaultBranch()
|
|
{
|
|
my $spproject = $_[0];
|
|
my $branch = $_[1];
|
|
my $header = $_[2];
|
|
my $sp = $_[3];
|
|
my $type = $_[4];
|
|
my $branchview = "$ENV{TMP}\\branchview";
|
|
my $fullcmd = "";
|
|
|
|
$type eq "lab" and do
|
|
{
|
|
#
|
|
# create branch spec
|
|
#
|
|
open(BRANCHVIEW, ">$branchview") or die("\nCan't open $branchview for writing.\n");
|
|
print BRANCHVIEW "Branch:\t$branch\n";
|
|
print BRANCHVIEW "Owner:\t$main::SDDomainUser\n";
|
|
print BRANCHVIEW "Description:\n\tLab or milestone branch created by $main::SDDomainUser.\n";
|
|
print BRANCHVIEW "View:\n";
|
|
|
|
#
|
|
# for type 1 depots, include the project name
|
|
#
|
|
if ($main::CodeBaseType == 1)
|
|
{
|
|
print BRANCHVIEW "\t//depot/main/$spproject/... //depot/$branch/$spproject/...\n";
|
|
}
|
|
else
|
|
{
|
|
print BRANCHVIEW "\t//depot/main/... //depot/$branch/...\n";
|
|
}
|
|
|
|
close(BRANCHVIEW);
|
|
};
|
|
|
|
$type eq "private" and do
|
|
{
|
|
#
|
|
# for type 1 depots we know the project
|
|
#
|
|
my $proj = ($main::CodeBaseType == 1 ? $spproject : "<<Your-Project>>");
|
|
|
|
open(BRANCHVIEW, ">$branchview") or die("\nCan't open $branchview for writing.\n");
|
|
print BRANCHVIEW "Branch:\t$branch\n";
|
|
print BRANCHVIEW "Owner:\t$main::SDDomainUser\n";
|
|
print BRANCHVIEW "Description:\n\tPrivate branch created by $main::SDDomainUser.\n";
|
|
print BRANCHVIEW "View:\n";
|
|
print BRANCHVIEW "\t//depot/$main::SDMapBranch/$proj/<<PATH>>/<<FILE1>> //depot/private/$main::SDUser/$proj/<<PATH>>/<<FILE1>>\n";
|
|
print BRANCHVIEW "\t//depot/$main::SDMapBranch/$proj/<<PATH>>/<<FILE2>> //depot/private/$main::SDUser/$proj/<<PATH>>/<<FILE2>>\n";
|
|
print BRANCHVIEW "\t//depot/$main::SDMapBranch/$proj/<<PATH>>/<<FILE3>> //depot/private/$main::SDUser/$proj/<<PATH>>/<<FILE3>>\n";
|
|
close(BRANCHVIEW);
|
|
};
|
|
|
|
#
|
|
# register the branch
|
|
#
|
|
$fullcmd = "sd.exe $sp branch -i < $branchview 2>&1";
|
|
$header .= "Creating branch \U$branch...\n";
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# EditBranch
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub EditBranch()
|
|
{
|
|
my $sp = $_[0];
|
|
my $pbranch = $_[1];
|
|
my $found = $main::TRUE;
|
|
|
|
#
|
|
# let the user customize the spec
|
|
#
|
|
SDX::EditBranchSpec($sp, $pbranch);
|
|
|
|
#
|
|
# verify that the placeholders were removed
|
|
#
|
|
while ($found)
|
|
{
|
|
#
|
|
# dump the branch and look for telltale signs
|
|
#
|
|
### @lines = `sd.exe $sp branch -o $pbranch`;
|
|
|
|
my $found2 = $main::FALSE;
|
|
grep(/<<|>>/, `sd.exe $sp branch -o $pbranch`) and $found2 = $main::TRUE;
|
|
|
|
#
|
|
# maybe edit again
|
|
#
|
|
$found2 and SDX::EditBranchSpec($sp, $pbranch);
|
|
|
|
#
|
|
# else we're done
|
|
#
|
|
!$found2 and $found = $main::FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# EditBranchSpec
|
|
#
|
|
#
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub EditBranchSpec()
|
|
{
|
|
my $sp = $_[0];
|
|
my $pbranch = $_[1];
|
|
my $fullcmd = "";
|
|
|
|
$fullcmd = "sd.exe $sp branch $pbranch";
|
|
my $msg = "Edit the branch view to contain only the projects and files to branch.\n";
|
|
|
|
sleep(1);
|
|
|
|
SDX::RunSDCmd($msg, $fullcmd);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Resolve
|
|
#
|
|
# called from OtherOp() to resolve integrated files. uses sd -s to get
|
|
# verbose output so we can catch errors
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if codebase type 2, project name if type 1
|
|
# $header user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Resolve
|
|
{
|
|
my $userargs = $_[0];
|
|
my $spproject = $_[1];
|
|
my $header = $_[2];
|
|
my $cmdtype = $_[3];
|
|
my $fullcmd = "";
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\n\n\nuserargs = '$userargs'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
$fullcmd = "sd.exe $sp -s resolve $userargs 2>&1";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# SyncFlush
|
|
#
|
|
# called from OtherOp() to sync files or flush the sync state
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if codebase type 2, project name if type 1
|
|
# $header user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub SyncFlush
|
|
{
|
|
my $cmd = $_[0];
|
|
my $userargs = $_[1];
|
|
my $spproject = $_[2];
|
|
my $header = $_[3];
|
|
my $cmdtype = $_[4];
|
|
my $fullcmd = "";
|
|
my $nul = "";
|
|
my $userargs2 = "";
|
|
my $c1 = "";
|
|
my $c2 = "";
|
|
my $err = "Error getting changelists:";
|
|
my $minush = $main::MinusH;
|
|
|
|
$userargs2 = $userargs;
|
|
$userargs =~ s/ -(a[mf]|i) //g;
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\ncmd = '$cmd'\n";
|
|
print "userargs = '$userargs'\n";
|
|
print "userargs2 = '$userargs2'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
###$spproject ne "base" and return;
|
|
###print "\n\n\tBUGBUG comment this out:\n";
|
|
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
|
|
#
|
|
# if -h, user wants to see change lists go by, not files
|
|
# get the most recent change number they have
|
|
#
|
|
# look for depot errors
|
|
#
|
|
$main::MinusH and do
|
|
{
|
|
my @changes = `sd.exe $sp changes -m 1 ...#have 2>&1`;
|
|
grep(/error:/i, @changes) and $minush = SDX::SyncFlushErr($err,\@changes);
|
|
|
|
$main::MinusH and do
|
|
{
|
|
#
|
|
# changelist number must be all digits
|
|
# some SD auth errors aren't caught by the check above
|
|
#
|
|
$c1 = (split(/ /, @changes[0]))[1];
|
|
($c1 =~ /[\D]+/) and $minush = SDX::SyncFlushErr($err,\@changes);
|
|
};
|
|
};
|
|
|
|
#
|
|
# do the sync or flush
|
|
#
|
|
$fullcmd = "sd.exe $sp $cmd $userargs 2>&1";
|
|
$header .= "\u$cmd" . "ing...\n";
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
|
|
#
|
|
# get the most recent change number the user just picked up and
|
|
# get the list of changes between this and the previous one
|
|
# only get integration changes if MinusHI
|
|
#
|
|
$main::MinusH and do
|
|
{
|
|
my %changes = ();
|
|
my $revrange = "#have";
|
|
my $hdr = "";
|
|
|
|
#
|
|
# if -n we didn't actually sync or flush, so the 2nd change number
|
|
# must be what the user would pick up, not what they currently have
|
|
#
|
|
$userargs =~ / -n / and $revrange = "";
|
|
|
|
#
|
|
# get and verify change number
|
|
#
|
|
my @chgs = `sd.exe $sp changes -m 1 ...$revrange 2>&1`;
|
|
grep(/error:/i, @chgs) and $minush = SDX::SyncFlushErr($err,\@chgs);
|
|
|
|
#
|
|
# changelist number must be all digits
|
|
# some SD auth errors aren't caught by the check above
|
|
#
|
|
$c2 = (split(/ /, @chgs[0]))[1];
|
|
($c2 =~ /[\D]+/) and $minush = SDX::SyncFlushErr($err,\@chgs);
|
|
|
|
#
|
|
# only show changes if we would or did pick something up
|
|
#
|
|
($c1 != $c2) and do
|
|
{
|
|
$hdr = "\nListing changes...";
|
|
print "$hdr";
|
|
|
|
#
|
|
# use the next change number so we don't show changes we already have
|
|
#
|
|
$c1++;
|
|
|
|
#
|
|
# get the change list, first without, then with, integration changes
|
|
# mark previous changes in hash with 1
|
|
# if MinusI
|
|
# mark int changes (not already in hash) with 2
|
|
# sort
|
|
# print int changes tab-indented
|
|
#
|
|
my @changes = `sd.exe $sp changes ...\@$c1,\@$c2 2>&1`;
|
|
grep(/error:/i, @changes) and $minush = SDX::SyncFlushErr($err,\@changes);
|
|
|
|
@changes = grep {s/^Change //g} @changes;
|
|
|
|
foreach (@changes)
|
|
{
|
|
$changes{$_} = 1;
|
|
print ".";
|
|
}
|
|
|
|
$main::MinusI and do
|
|
{
|
|
my @changes = `sd.exe $sp changes -i ...\@$c1,\@$c2 2>&1`;
|
|
grep(/error:/i, @changes) and $minush = SDX::SyncFlushErr($err,\@changes);
|
|
|
|
@changes = grep {s/^Change //g} @changes;
|
|
|
|
foreach (@changes)
|
|
{
|
|
!$changes{$_} and $changes{$_} = 2;
|
|
}
|
|
|
|
print ".";
|
|
};
|
|
|
|
sub nn { $b <=> $a; }
|
|
@changes = sort nn keys %changes;
|
|
|
|
print ".";
|
|
|
|
#
|
|
# print the changes, with integration changes indented
|
|
#
|
|
# maybe log the output
|
|
#
|
|
print "\n";
|
|
|
|
$main::Logging and do
|
|
{
|
|
(open LOG, ">>$main::Log" or die("\nCan't append $main::LOG\n"));
|
|
print LOG "$hdr\n";
|
|
};
|
|
|
|
foreach $key (@changes)
|
|
{
|
|
my $ch = sprintf "%sChange $key", $changes{$key} == 2 ? " " : "";
|
|
|
|
print "$ch";
|
|
|
|
$main::Logging and print LOG "$ch";
|
|
|
|
#
|
|
# keep stats for OtherOp()
|
|
#
|
|
$ch =~ /^Change / and $main::Changes++;
|
|
$ch =~ / Change / and $main::IntegrationChanges++;
|
|
}
|
|
|
|
$main::Logging and close LOG;
|
|
};
|
|
|
|
$hdr = sprintf("Enlistment %s in sync through change number %s.\n", ($userargs2 =~ / -n / ? "would be" : "is"), $c2);
|
|
print "$hdr";
|
|
|
|
#
|
|
# print the changes, with integration changes indented
|
|
#
|
|
# maybe log the output
|
|
#
|
|
|
|
$main::Logging and do
|
|
{
|
|
(open LOG, ">>$main::Log" or die("\nCan't append $main::LOG\n"));
|
|
print LOG "$hdr\n";
|
|
close LOG;
|
|
};
|
|
};
|
|
|
|
#
|
|
# see if this is a sync with resolve
|
|
#
|
|
($cmd eq "sync") and do
|
|
{
|
|
$userargs2 =~ /-am/ and do
|
|
{
|
|
$fullcmd = "sd.exe $sp -s resolve $userargs2 2>&1";
|
|
$header = "\nResolving...\n";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
|
|
# remove -am for the next call
|
|
$userargs2 =~ s/-am//g;
|
|
|
|
$fullcmd = "sd.exe $sp -s resolve -n $userargs2 2>&1";
|
|
$header = "\nLooking for files needing manual resolution...\n";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
};
|
|
|
|
$userargs2 =~ /-af/ and do
|
|
{
|
|
$fullcmd = "sd.exe $sp -s resolve $userargs2 2>&1";
|
|
$header = "\nResolving...\n";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
};
|
|
};
|
|
|
|
#
|
|
# maybe restore
|
|
#
|
|
$main::MinusH = $minush;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# SyncFlushErr
|
|
#
|
|
# handle errors
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub SyncFlushErr
|
|
{
|
|
my $err = $_[0];
|
|
my ($list) = $_[1];
|
|
|
|
#
|
|
# temporarily disable -h
|
|
# print warning
|
|
#
|
|
$main::MinusH = $main::FALSE;
|
|
print "\n$err\n\n@$list\n";
|
|
|
|
#
|
|
# count for summary
|
|
#
|
|
$main::DepotErrors++;
|
|
|
|
return $main::TRUE;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Opened
|
|
#
|
|
# called from OtherOp() to get opened files
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if codebase type 2, project name if type 1
|
|
# $header user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Opened
|
|
{
|
|
my $userargs = $_[0];
|
|
my $spproject = $_[1];
|
|
my $header = $_[2];
|
|
my $cmdtype = $_[3];
|
|
my $fullcmd = "";
|
|
my $ch = "";
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\ncmd = '$cmd'\n";
|
|
print "userargs = '$userargs'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
|
|
#
|
|
# set the basic cmd
|
|
#
|
|
$fullcmd = "sd.exe $sp opened $userargs 2>&1";
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Files
|
|
#
|
|
# called from OtherOp() to list files
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if codebase type 2, project name if type 1
|
|
# $header user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Files
|
|
{
|
|
my $userargs = $_[0];
|
|
my $spproject = $_[1];
|
|
my $header = $_[2];
|
|
my $cmdtype = $_[3];
|
|
my $fullcmd = "";
|
|
my $ch = "";
|
|
|
|
@main::FileChunks = ();
|
|
$main::DepotFiles = 0;
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\ncmd = '$cmd'\n";
|
|
print "userargs = '$userargs'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
|
|
#
|
|
# set the basic cmd
|
|
#
|
|
$fullcmd = "sd.exe $sp files $userargs 2>&1";
|
|
|
|
#
|
|
# if the user wants a summary file count,
|
|
# chunk the depot into pieces that won't exceed MAXRESULTS
|
|
# save the results in a list
|
|
# use RunSDCmd to print total
|
|
#
|
|
if ($main::MinusA)
|
|
{
|
|
#
|
|
# print header
|
|
#
|
|
SDX::PrintCmd($header, 0);
|
|
|
|
(!$main::V2) and do
|
|
{
|
|
my @list = ();
|
|
my @dirs = `sd.exe $sp dirs //*/*/*`;
|
|
foreach (@dirs)
|
|
{
|
|
chop $_;
|
|
my @chunk = `sd.exe files $_/...`;
|
|
push @list, sprintf "%-45s %7s", $_, $#chunk + 1;
|
|
$main::DepotFiles += $#chunk + 1;
|
|
print ".";
|
|
}
|
|
|
|
push @main::FileChunks, @list;
|
|
|
|
print "\n";
|
|
|
|
#
|
|
# run it
|
|
#
|
|
SDX::RunCmd($fullcmd);
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
#run it
|
|
#
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Status
|
|
#
|
|
# called from OtherOp() to show opened/out of sync files
|
|
#
|
|
# Parameters:
|
|
# $labbranch branch name
|
|
# $spproject server:port if codebase type 2, project name if type 1
|
|
# $header user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Status
|
|
{
|
|
my $userargs = $_[0];
|
|
my $project = $_[1];
|
|
my $header = $_[2];
|
|
my $cmdtype = $_[3];
|
|
my $fullcmd1 = "";
|
|
my $fullcmd2 = "";
|
|
my $arg = "";
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\nuserargs = '$userargs'\n";
|
|
print "project = '$project'\n";
|
|
};
|
|
|
|
#
|
|
# for type 2 depots (N projects/depot) restrict scope to ...
|
|
#
|
|
# for the root project in a type 2 (other than NT), restrict scope to *
|
|
#
|
|
$main::CodeBaseType == 2 and do
|
|
{
|
|
$arg = ($project eq "root" and "\U$main::CodeBase" ne "NT") ? "*" : "...";
|
|
};
|
|
|
|
my $fullcmd1 = "sd.exe opened $arg 2>&1";
|
|
my $fullcmd2 = "sd.exe sync -n $arg 2>&1";
|
|
|
|
$header .= "Checking for open files...\n";
|
|
my $header2 = "\nChecking for files out of sync...\n";
|
|
|
|
if ($main::V2)
|
|
{
|
|
SDX::PrintCmd($header, 0);
|
|
SDX::PrintCmd($fullcmd1, 1);
|
|
|
|
SDX::PrintCmd($header2, 0);
|
|
SDX::PrintCmd($fullcmd2, 1);
|
|
}
|
|
else
|
|
{
|
|
SDX::PrintCmd($header, 0);
|
|
SDX::RunCmd($fullcmd1);
|
|
|
|
SDX::PrintCmd($header2, 0);
|
|
SDX::RunCmd($fullcmd2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Submit
|
|
#
|
|
# called from OtherOp() to handle submit
|
|
#
|
|
# Parameters:
|
|
# $userargs user args
|
|
# $project server:port if codebase type 2, project name if type 1
|
|
# $header user output
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Submit
|
|
{
|
|
my $userargs = $_[0];
|
|
my $spproject = $_[1];
|
|
my $header = $_[2];
|
|
my $cmdtype = $_[3];
|
|
my $fullcmd = "";
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\nuserargs = '$userargs'\n";
|
|
print "spproject = '$spproject'\n";
|
|
};
|
|
|
|
#
|
|
# maybe use server:port
|
|
#
|
|
my $sp = SDX::ServerPort($cmdtype, $spproject);
|
|
|
|
#
|
|
# assume a normal submit where the form gets brought up
|
|
#
|
|
$fullcmd = "sd.exe $sp submit $userargs 2>&1";
|
|
|
|
#
|
|
# special case if the user put the comment on the cmd line
|
|
#
|
|
($main::SubmitComment) and do
|
|
{
|
|
#
|
|
# dump the default changelist
|
|
#
|
|
@main::InputForm = `sd.exe $sp change -o 2>&1`;
|
|
|
|
#
|
|
# if it contains a file list, use it as the submit form,
|
|
# inserting the comment
|
|
#
|
|
# add -i to the sd cmd before passing it on
|
|
#
|
|
if (grep(/Files:$/, @main::InputForm))
|
|
{
|
|
foreach $_ (@main::InputForm) { $_ =~ s/<enter description here>/$main::SubmitComment/g; }
|
|
|
|
$main::V2 and print "submit form:\n\n'@main::InputForm'\n";
|
|
|
|
$fullcmd = "sd.exe $sp submit -i 2>&1";
|
|
}
|
|
};
|
|
|
|
SDX::RunSDCmd($header, $fullcmd);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# InitForEDR
|
|
#
|
|
# Do some common initialization for enlist, repair and defect
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub InitForEDR
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in InitForEDR().\n");
|
|
|
|
#
|
|
# init global vars and flags
|
|
#
|
|
$main::EnlistingMainBranch = $main::FALSE;
|
|
$main::EnlistingGroupBranch = $main::FALSE;
|
|
$main::EnlistingPrivateBranch = $main::FALSE;
|
|
$main::ClientView = "$main::SDXRoot\\clientview";
|
|
$main::CBMProjectField = 0; # change these if you change
|
|
$main::CBMGroupField = 1; # the ordering of fields in
|
|
$main::CBMServerPortField = 2; # file PROJECTS.<CODEBASE>
|
|
$main::CBMDepotNameField = 3;
|
|
$main::CBMProjectRootField = 4;
|
|
$main::MasterBranch = "";
|
|
@main::GroupBranches = ();
|
|
@main::EnlistProjects = ();
|
|
@main::EnlistGroups = ();
|
|
@main::EnlistDepots = ();
|
|
@main::DefectDepots = ();
|
|
@main::DefectProjects = ();
|
|
|
|
#
|
|
# if we're running from a razzle window, error out
|
|
#
|
|
$main::SDUser =~ /(x86|amd64|ia64)(fre|chk)/ and do
|
|
{
|
|
print "\nCan't run 'sdx enlist' from a build window -- can't use '$ENV{USERNAME}' as \%SDUSER\%.\n";
|
|
print "\nSet \%SDUSER\% to your login name or run 'sdx enlist' from a clean command\n";
|
|
print "window.\n";
|
|
die("\n");
|
|
};
|
|
|
|
#
|
|
# make sure we have PROJECTS.<codebase>
|
|
#
|
|
!SDX::VerifyCBMap($main::CodeBase) and do
|
|
{
|
|
print "\n\nCan't find codebase map $main::CodeBaseMap.\n";
|
|
|
|
print "\nRun 'sdx repair $main::CodeBase $main::Branch' from the SDX share from which you originally\n";
|
|
print "enlisted.\n";
|
|
|
|
die("\n");
|
|
};
|
|
|
|
#
|
|
# if not defecting, make the enlistment root
|
|
#
|
|
!$defecting and do
|
|
{
|
|
system "md $main::SDXRoot >nul 2>&1";
|
|
-e $main::SDXRoot or die("\nCan't create root dir $main::SDXRoot.\n");
|
|
};
|
|
|
|
#
|
|
# read the codebase map
|
|
# get MainBranch and GroupBranches list
|
|
# get master list of project.group.server:port.depot.projroot mappings
|
|
#
|
|
SDX::ReadCodeBaseMap();
|
|
|
|
#
|
|
# create the lists of all projects, groups and depots, removing any duplicates
|
|
#
|
|
SDX::MakePGDLists("");
|
|
|
|
#
|
|
# make sure we have a valid Tools project
|
|
#
|
|
$main::ToolsProject and do
|
|
{
|
|
my $found = $main::FALSE;
|
|
foreach $proj (@main::AllProjects)
|
|
{
|
|
(@$proj[0] eq $main::ToolsProject) and $found = $main::TRUE and last;
|
|
}
|
|
|
|
!$found and die("\nUnknown tools project \U'$main::ToolsProject'. C\Lheck the codebase map.\n");
|
|
};
|
|
}
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# VerifyAccess
|
|
#
|
|
# verify access to the relevant servers, dies if unable to access
|
|
#
|
|
# Parameters:
|
|
# none
|
|
#
|
|
# Output:
|
|
# prints status information to the screen while running and an error message
|
|
# for fatal errors
|
|
# _____________________________________________________________________________
|
|
sub VerifyAccess {
|
|
print "\nVerifying access to depots.";
|
|
|
|
for $depot (@main::VerifyDepots)
|
|
{
|
|
print ".";
|
|
|
|
my $serverport = @$depot[0];
|
|
|
|
my @err = `sd.exe -p $serverport client -o 2>&1`;
|
|
grep(/ failed/, @err) and die("\n\n@err\n");
|
|
|
|
SDX::AccessDenied(\@err, $serverport) and die("\n");
|
|
}
|
|
|
|
print "\nok\n";
|
|
}
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# RemoveFromView
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# returns 1 if a reduced client view exists, 0 if the view ends up empty or client
|
|
# doesn't exist in this depot
|
|
# _____________________________________________________________________________
|
|
sub RemoveFromView
|
|
{
|
|
my $depot = $_[0];
|
|
my $serverport = @$depot[0];
|
|
my $depotname = @$depot[1];
|
|
|
|
unlink $main::ClientView;
|
|
|
|
#
|
|
# write the default view lines for this depot and project(s)
|
|
#
|
|
SDX::WriteDefaultView($serverport, $depotname);
|
|
|
|
if (SDX::ClientExists($serverport, $main::SDClient))
|
|
{
|
|
print "Editing client view.";
|
|
|
|
#
|
|
# read the existing client view into @main::ExistingView
|
|
# and write the existing header to $main::ClientView
|
|
#
|
|
SDX::GetClientView("defect", $serverport, $main::SDClient);
|
|
|
|
#
|
|
# use the existing view lines as keys to a hash and
|
|
# mark each entry in ascending order
|
|
#
|
|
# using the default view lines as keys to the same
|
|
# hash, mark each entry found with 0 to indicate removed
|
|
#
|
|
# write the remaining hash lines back into the list
|
|
# and sort it back to its original order, which is how
|
|
# the user had it
|
|
#
|
|
my @tmpview = ();
|
|
my @tmpview2 = ();
|
|
my @finalview = ();
|
|
my @finalview2 = ();
|
|
my $linenum = 1;
|
|
|
|
# must be global for sort to work
|
|
%existingview = ();
|
|
%existingview2 = ();
|
|
|
|
#
|
|
# lowercase the line, so we don't keep
|
|
# duplicates that only differ by case
|
|
#
|
|
foreach $line (@main::ExistingView)
|
|
{
|
|
$existingview{"\L$line"} = $linenum++;
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nhash:\n";
|
|
while (($k,$v) = each %existingview)
|
|
{
|
|
printf "'%-50s'\t'%s'\n", $k, $v;
|
|
}
|
|
};
|
|
|
|
foreach $line (@main::DefaultView)
|
|
{
|
|
#
|
|
# extract the LHS of the default line as line2
|
|
# add '-' to find negation mappings
|
|
#
|
|
@fields = split(/\//,$line);
|
|
my $line2 = "";
|
|
for $x (0..4)
|
|
{
|
|
$line2 .= @fields[$x] . "/";
|
|
}
|
|
chop $line2;
|
|
|
|
my $line3 = $line2;
|
|
$line3 =~ s/\/\//-\/\//;
|
|
|
|
#
|
|
# mark any lines in the existing view that match
|
|
# the default line exactly
|
|
#
|
|
if ($existingview{"\L$line"})
|
|
{
|
|
$existingview{"\L$line"} = 0;
|
|
print ".";
|
|
}
|
|
|
|
#
|
|
# mark any lines which have the same LHS as the
|
|
# default line, including those that begin with '-'
|
|
#
|
|
while (($k,$v) = each %existingview)
|
|
{
|
|
if (($k =~ /^$line2/) || ($k =~ /^$line3/))
|
|
{
|
|
# print "\nmatch: '$k'\n";
|
|
$existingview{$k} = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
$main::V3 and print "\n\n\n\nhash, edited:\n";
|
|
|
|
while (($k,$v) = each %existingview)
|
|
{
|
|
$v and push @tmpview, $k;
|
|
$main::V3 and printf "'%-50s'\t'%s'\n", $k, $v;
|
|
}
|
|
|
|
#
|
|
# sort ascending on the numeric value of each key
|
|
#
|
|
sub ascending { my $rc = ($existingview{$a} <=> $existingview{$b}); }
|
|
@finalview = sort ascending @tmpview;
|
|
|
|
$main::V2 and print "\nfinal view:\n@finalview\n";
|
|
|
|
#
|
|
# if we still have a view and it still has valid project mappings,
|
|
# finish writing the client view by appending the newly reduced view spec
|
|
# else return
|
|
#
|
|
### if (@finalview && !SDX::PrivateView($depot, \@finalview))
|
|
if (@finalview)
|
|
{
|
|
open(CLIENTVIEW, ">>$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n");
|
|
|
|
for $viewline (@finalview)
|
|
{
|
|
printf CLIENTVIEW $viewline;
|
|
}
|
|
|
|
close(CLIENTVIEW);
|
|
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# PrivateView
|
|
#
|
|
# Determines if the list of view lines passed in contains any default project
|
|
# mappings. A view still containing such mappings means we have more than just
|
|
# the user's view customizations and can't throw the view away yet.
|
|
#
|
|
# Parameters:
|
|
# none
|
|
#
|
|
# Output:
|
|
# returns 1 if view has only private mappings and no default project lines in it
|
|
# 0 otherwise
|
|
# _____________________________________________________________________________
|
|
sub PrivateView
|
|
{
|
|
my $depot = $_[0];
|
|
my @view = $_[1];
|
|
|
|
my $serverport = @$depot[0];
|
|
|
|
#
|
|
# load the remaining view lines into a hash and mark each,
|
|
# ignoring lines beginning with '-'
|
|
#
|
|
|
|
#
|
|
# if hash is empty, return 1
|
|
#
|
|
|
|
#
|
|
# else get the full list of project view lines for all projects in this depot
|
|
#
|
|
|
|
#
|
|
# for each view line, return as soon as we get a hit
|
|
# if (hash{$viewline}) return 0
|
|
#
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ReadCodeBaseMap
|
|
#
|
|
# reads master branch, group branch list, and project.group.server:port.depot.projroot
|
|
# mappings into lists to manipulate later.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# sets $main::MasterBranch
|
|
# populates $main::GroupBranches list
|
|
# populates $main::AllMappings list
|
|
# _____________________________________________________________________________
|
|
sub ReadCodeBaseMap
|
|
{
|
|
open(CODEBASEMAP, $main::CodeBaseMap) or die("\nCan't open code base map $main::CodeBaseMap.\n");
|
|
|
|
while ($cbmline = <CODEBASEMAP>)
|
|
{
|
|
#
|
|
# throw away comments
|
|
#
|
|
$cbmline =~ /^#/ and next;
|
|
|
|
chop $cbmline;
|
|
|
|
#
|
|
# make sure the codebase we think we are matches SDX
|
|
#
|
|
if ($cbmline =~ /^CODEBASE[\t\s]*=/)
|
|
{
|
|
@fields = split(/[\t\s]*=[\t\s]*/, $cbmline);
|
|
$actualcb = @fields[1];
|
|
$actualcb =~ s/[\t\s]*//g;
|
|
|
|
$main::CodeBase =~ /$actualcb/i or die("\nError: Codebase name '$actualcb' in $main::CodeBaseMap doesn't match '$main::CodeBase'.\n");
|
|
}
|
|
|
|
#
|
|
# get the codebase type
|
|
#
|
|
if ($cbmline =~ /^CODEBASETYPE/)
|
|
{
|
|
$main::CodeBaseType = (split(/[\t\s]*=[\t\s]*/, $cbmline))[1];
|
|
next;
|
|
}
|
|
|
|
#
|
|
# get the master branch
|
|
#
|
|
if ($cbmline =~ /^MASTERBRANCH/)
|
|
{
|
|
@fields = split(/[\t\s]*=[\t\s]*/, $cbmline);
|
|
$main::MasterBranch = @fields[1];
|
|
$main::MasterBranch =~ s/[\t\s]*//g;
|
|
}
|
|
|
|
#
|
|
# get the group branches
|
|
#
|
|
if ($cbmline =~ /^GROUPBRANCHES/)
|
|
{
|
|
$cbmline =~ s/^GROUPBRANCHES[\t\s]*=[\t\s]*//g;
|
|
@main::GroupBranches = split(/[\t\s]+/, $cbmline);
|
|
}
|
|
|
|
#
|
|
# figure out whether we should give the user SD tools after
|
|
# enlisting or not
|
|
#
|
|
if ($cbmline =~ /^TOOLS/)
|
|
{
|
|
$cbmline =~ s/^TOOLS[\t\s]*=[\t\s]*//g;
|
|
@fields = split(/\\/, $cbmline);
|
|
|
|
# first token is always the project
|
|
$main::ToolsProject = "\L@fields[0]";
|
|
|
|
#
|
|
# if we have a project, get the relative and full paths to it
|
|
#
|
|
$main::ToolsProject and do
|
|
{
|
|
shift @fields;
|
|
foreach $p (@fields)
|
|
{
|
|
$main::ToolsPath .= "\L$p" . "\\";
|
|
}
|
|
|
|
$main::ToolsPath and chop $main::ToolsPath;
|
|
|
|
#
|
|
# if at the root, the full path doesn't include the project name
|
|
#
|
|
|
|
#
|
|
# only include a "\" below if SDXROOT doesn't end in one already
|
|
#
|
|
my $dblslash = ($main::SDXRoot =~ /\\$/ ? "" : "\\");
|
|
|
|
if ($main::ToolsProject eq "root")
|
|
{
|
|
#
|
|
# if the CBM lists "root" for the tools and we have no path, error out
|
|
#
|
|
!$main::ToolsPath and die("\nTools project is ROOT but no path was specified in \U$main::CodeBaseMap.\n");
|
|
|
|
$main::ToolsProjectPath = $main::SDXRoot . $dblslash . $main::ToolsPath;
|
|
$main::ToolsInRoot = $main::TRUE;
|
|
}
|
|
else
|
|
{
|
|
$main::ToolsProjectPath = $main::SDXRoot . $dblslash . $main::ToolsProject;
|
|
$main::ToolsPath and $main::ToolsProjectPath .= "\\" . $main::ToolsPath;
|
|
}
|
|
};
|
|
}
|
|
|
|
#
|
|
# get any other dirs to be sync'd on the user's behalf
|
|
#
|
|
if ($cbmline =~ /^OTHERDIRS/)
|
|
{
|
|
$cbmline =~ s/^OTHERDIRS[\t\s]*=[\t\s]*//g;
|
|
@main::OtherDirs = split(/[\t\s]+/,$cbmline);
|
|
}
|
|
|
|
#
|
|
# get any required projects
|
|
#
|
|
if ($cbmline =~ /^DEFAULTPROJECTS/)
|
|
{
|
|
$cbmline =~ s/^DEFAULTPROJECTS[\t\s]*=[\t\s]*//g;
|
|
@main::DefaultProjects = split(/[\t\s]+/,$cbmline);
|
|
}
|
|
|
|
#
|
|
# get any projects that need platform-specific subdirs trimmed
|
|
# in the view
|
|
#
|
|
if ($cbmline =~ /^PLATFORMPROJECTS/)
|
|
{
|
|
$cbmline =~ s/^PLATFORMPROJECTS[\t\s]*=[\t\s]*//g;
|
|
@main::PlatformProjects = split(/[\t\s]+/,$cbmline);
|
|
}
|
|
|
|
#
|
|
# see if we need to restrict the Root mapping
|
|
#
|
|
if ($cbmline =~ /^RESTRICTROOT/)
|
|
{
|
|
$cbmline =~ s/^RESTRICTROOT[\t\s]*=[\t\s]*//g;
|
|
$restrict = $cbmline;
|
|
$restrict =~ s/[\t\s]*//g;
|
|
|
|
if ($restrict eq "1" || "\U$restrict" eq "YES")
|
|
{
|
|
$main::RestrictRoot = $main::TRUE;
|
|
}
|
|
}
|
|
|
|
#
|
|
# if not one of the above, the line is a project-group-server:port-depot-projroot mapping
|
|
#
|
|
# lowercase the whole line, split it, then push it onto a list
|
|
#
|
|
if ($cbmline =~ /[a-zA-Z0-9]+:[0-9]+/)
|
|
{
|
|
$main::nMappings++;
|
|
@fields = split(/[\t\s]+/, "\L$cbmline");
|
|
push @main::AllMappings, [@fields];
|
|
}
|
|
}
|
|
|
|
close(CODEBASEMAP);
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\n";
|
|
printf "readcbm: \# mappings = %s\n", $main::nMappings;
|
|
printf "readcbm: codebase = '%s'\n", $main::CodeBase;
|
|
printf "readcbm: codebasetype = '%s'\n", $main::CodeBaseType;
|
|
printf "readcbm: masterbranch ='%s'\n", $main::MasterBranch;
|
|
|
|
if ($main::ToolsProject)
|
|
{
|
|
printf "readcbm: toolsproject='%s'\n", $main::ToolsProject;
|
|
printf "readcbm: toolspath='%s'\n", $main::ToolsPath;
|
|
printf "readcbm: toolsprojectpath='%s'\n", $main::ToolsProjectPath;
|
|
}
|
|
|
|
if (@main::OtherDirs)
|
|
{
|
|
foreach $d (@main::OtherDirs)
|
|
{
|
|
printf "readcbm: otherdir='%s'\n", $d;
|
|
}
|
|
}
|
|
|
|
if (@main::DefaultProjects)
|
|
{
|
|
foreach $d (@main::DefaultProjects)
|
|
{
|
|
printf "readcbm: defproj='%s'\n", $d;
|
|
}
|
|
}
|
|
|
|
if (@main::PlatformProjects)
|
|
{
|
|
foreach $d (@main::PlatformProjects)
|
|
{
|
|
printf "readcbm: platproj='%s'\n", $d;
|
|
}
|
|
}
|
|
|
|
foreach $b (@main::GroupBranches)
|
|
{
|
|
printf "readcbm: grbr='%s'\n", $b;
|
|
}
|
|
|
|
print "\n";
|
|
|
|
for $x (0..$main::nMappings-1)
|
|
{
|
|
for $y (0..4)
|
|
{
|
|
printf "readcbm: AllMappings[%s][%s] = %s\n", $x, $y, $main::AllMappings[$x][$y];
|
|
}
|
|
print "\n";
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# MakePGDLists
|
|
#
|
|
# Munges $main::AllMappings to create lists of projects, groups and servers.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# populates @main::AllProjects as 2D array with full mappings for all unique project names
|
|
# populates @main::AllGroups with list of all unique dev groups
|
|
# populates @main::AllDepots with list of all unique SD servers for this codebase
|
|
# _____________________________________________________________________________
|
|
sub MakePGDLists
|
|
{
|
|
#
|
|
# for each project, group, depot
|
|
# unless already seen, add to hash and push to corresponding array
|
|
#
|
|
$p = 0;
|
|
$g = 0;
|
|
$d = 0;
|
|
%seenproj = ();
|
|
%projhash = ();
|
|
%seengroup = ();
|
|
%seenserverport = ();
|
|
@fulldepotdesc = ();
|
|
|
|
for $x (0..$main::nMappings-1)
|
|
{
|
|
$proj = $main::AllMappings[$x][$main::CBMProjectField];
|
|
$group = $main::AllMappings[$x][$main::CBMGroupField];
|
|
$serverport = $main::AllMappings[$x][$main::CBMServerPortField];
|
|
$depotname = $main::AllMappings[$x][$main::CBMDepotNameField];
|
|
|
|
unless ($seenproj{$proj})
|
|
{
|
|
$p++;
|
|
$seenproj{$proj} = 1;
|
|
push @main::AllProjects, [@{$main::AllMappings[$x]}];
|
|
|
|
#
|
|
# place in hash -- use this later
|
|
#
|
|
$projhash{$proj} = [@{$main::AllMappings[$x]}];
|
|
}
|
|
|
|
unless ($seengroup{$group})
|
|
{
|
|
$g++;
|
|
$seengroup{$group} = 1;
|
|
push @main::AllGroups, $group;
|
|
}
|
|
|
|
unless ($seenserverport{$serverport})
|
|
{
|
|
$d++;
|
|
$seenserverport{$serverport} = 1;
|
|
@fulldepotdesc = ("$serverport","$depotname");
|
|
push @main::AllDepots, [@fulldepotdesc];
|
|
}
|
|
}
|
|
|
|
#
|
|
# set up a hash of project types
|
|
#
|
|
# project is type 1 (1 project per depot) if Group field
|
|
# in codebase map is "ntdev"
|
|
#
|
|
# project is type 2 (N projects per depot) otherwise
|
|
#
|
|
%main::ProjectType = ();
|
|
foreach $project (@main::AllProjects)
|
|
{
|
|
$main::ProjectType{@$project[$main::CBMProjectField]} = ("\L@$project[$main::CBMGroupField]" eq "ntdev") ? 1 : 2;
|
|
}
|
|
|
|
#
|
|
# figure out depot types
|
|
#
|
|
# a depot is type 1 if its server:port appears in the AllProjects list only once and
|
|
# its Group is "ntdev"
|
|
# else type 2
|
|
#
|
|
for $depot (@main::AllDepots)
|
|
{
|
|
$serverport = @$depot[0];
|
|
|
|
my $foundproj = "";
|
|
my $foundgroup = "";
|
|
my $count = 0;
|
|
foreach $project (@main::AllProjects)
|
|
{
|
|
$p = @$project[0];
|
|
$group = @$project[1];
|
|
$sp = @$project[2];
|
|
|
|
($serverport eq $sp) and do
|
|
{
|
|
$count++;
|
|
$foundproj = $p;
|
|
$foundgroup = $group;
|
|
|
|
$count > 1 and last;
|
|
}
|
|
}
|
|
|
|
if ($count == 1)
|
|
{
|
|
@{$main::DepotType{$serverport}}[0] = ($foundgroup eq "ntdev") ? 1 : 2;
|
|
@{$main::DepotType{$serverport}}[1] = ($foundgroup eq "ntdev") ? $foundproj : "";
|
|
}
|
|
|
|
if ($count > 1)
|
|
{
|
|
@{$main::DepotType{$serverport}}[0] = 2;
|
|
@{$main::DepotType{$serverport}}[1] = "";
|
|
}
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
# printf "\n\# of mappings = %s\n", $#main::AllMappings + 1;
|
|
# foreach $line (@main::AllMappings)
|
|
# {
|
|
# print "pgdlists: AllMappings[] = @$line\n";
|
|
# }
|
|
|
|
print "\n";
|
|
|
|
printf "\n\# of projects = %s\n", $#main::AllProjects + 1;
|
|
foreach $project (@main::AllProjects)
|
|
{
|
|
print "pgdlists: AllProjects[] = @$project\n";
|
|
}
|
|
|
|
print "\n";
|
|
|
|
# print "pgdlists: \%projhash:\n";
|
|
# while (($k,$v) = each %projhash)
|
|
# {
|
|
# printf "%20s\t", $k;
|
|
# print "@$v\n";
|
|
# }
|
|
|
|
print "pgdlists: \%ProjectType:\n";
|
|
while (($k,$v) = each %main::ProjectType)
|
|
{
|
|
printf "%20s\t", $k;
|
|
print "$v\n";
|
|
}
|
|
|
|
printf "\n\# of groups = %s\n", $#main::AllGroups + 1;
|
|
|
|
for $group (@main::AllGroups)
|
|
{
|
|
printf "pgdlists: AllGroups[] = $group\n";
|
|
}
|
|
|
|
printf "\n\# of depots = %s\n", $#main::AllDepots + 1;
|
|
|
|
for $depot (@main::AllDepots)
|
|
{
|
|
printf "pgdlists: AllDepots[] = @$depot\n";
|
|
}
|
|
|
|
print "\npgdlists: \%DepotType:\n";
|
|
while (($k,$v) = each %main::DepotType)
|
|
{
|
|
(@$v[0] == 1) and do
|
|
{
|
|
printf " %-50s\t", $k;
|
|
print "@$v[0], @$v[1]\n";
|
|
};
|
|
}
|
|
|
|
while (($k,$v) = each %main::DepotType)
|
|
{
|
|
(@$v[0] == 2) and do
|
|
{
|
|
printf " %-50s\t", $k;
|
|
print "@$v[0], @$v[1]\n";
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# MakeTargetLists
|
|
#
|
|
# Munges @main::AllProjects and @main::AllDepots to create @main::EnlistProjects and
|
|
# @main::EnlistDepots, the lists of just those projects and depots we'll actually
|
|
# enlist in.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# populates @main::EnlistProjects with projects to enlist
|
|
# populates @main::EnlistDepots with depots to enlist
|
|
# _____________________________________________________________________________
|
|
sub MakeTargetLists
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
my @depots = ();
|
|
my @projects = ();
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in MakeTargetLists().\n");
|
|
|
|
#
|
|
# if EnlistAll or DefectAll, the projects list depends on the codebase map or SD.MAP
|
|
# else the projects list consists of the rows for each in SomeProjects
|
|
#
|
|
if ($main::EnlistAll || $main::DefectAll)
|
|
{
|
|
#
|
|
# enlist in everything
|
|
#
|
|
$main::EnlistAll and @projects = @main::AllProjects;
|
|
|
|
#
|
|
# defect from everything in SD.MAP
|
|
#
|
|
$main::DefectAll and do
|
|
{
|
|
#
|
|
# for each project in @main::SDMapProjects, get the full
|
|
# project:group:depot:projroot mapping associated with it
|
|
# from the AllProjects list
|
|
#
|
|
foreach $project (@main::SDMapProjects)
|
|
{
|
|
my $found = $main::FALSE;
|
|
my $proj = @$project[0];
|
|
|
|
foreach $project2 (@main::AllProjects)
|
|
{
|
|
my $proj2 = @$project2[$main::CBMProjectField];
|
|
|
|
if ("\l$proj" eq "\l$proj2")
|
|
{
|
|
push @projects, [@{$project2}];
|
|
$found = $main::TRUE;
|
|
last;
|
|
}
|
|
}
|
|
|
|
!$found and print "Unknown project $proj in SD.MAP.\n";
|
|
}
|
|
};
|
|
}
|
|
else
|
|
{
|
|
print "\n";
|
|
|
|
#
|
|
# if enlisting
|
|
# if EnlistAsOther
|
|
# populate @main::SomeProjects with the list of projects
|
|
# the other client is enlisted in
|
|
#
|
|
if ($enlisting)
|
|
{
|
|
if ($main::EnlistAsOther)
|
|
{
|
|
my $found = $main::FALSE;
|
|
my %projects = ();
|
|
|
|
#
|
|
# be verbose if there are more than 3 depots to search
|
|
#
|
|
my $verbose = ($#main::AllDepots > 2);
|
|
$verbose and print "Getting client information for \U$main::OtherClient.";
|
|
|
|
#
|
|
# if OtherClient exists in each depot, get the view lines
|
|
# and extract the project names. put them in a hash for
|
|
# uniqueness
|
|
#
|
|
foreach $depot (@main::AllDepots)
|
|
{
|
|
$verbose and print ".";
|
|
|
|
my $serverport = @$depot[0];
|
|
|
|
if (SDX::ClientExists($serverport, $main::OtherClient))
|
|
{
|
|
$found = $main::TRUE;
|
|
|
|
SDX::GetClientView("repair", $serverport, $main::OtherClient);
|
|
|
|
# print "\n$main::OtherClient view in $serverport = \n'@main::ExistingView'\n";
|
|
|
|
my @fields = ();
|
|
foreach $line (@main::ExistingView)
|
|
{
|
|
#
|
|
# throw away " -//" negation lines
|
|
# and //depot/private lines
|
|
#
|
|
$line =~ /^[\t\s]+-/ and next;
|
|
$line =~ /^[\t\s]+\/\/depot\/private/ and next;
|
|
|
|
@fields = split(/\//,$line);
|
|
$projects{$fields[4]} = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (($k,$v) = each %projects)
|
|
{
|
|
push @main::SomeProjects, $k;
|
|
}
|
|
|
|
$main::V2 and print "\n\n$main::OtherClient projects = @main::SomeProjects\n";
|
|
|
|
print "\n";
|
|
|
|
!$found and do
|
|
{
|
|
printf "\nClient %s was not found in any of the %s depots. Please choose\n", "\U$main::OtherClient", "\U$main::CodeBase";
|
|
print "another client as a template.\n";
|
|
die("\n");
|
|
};
|
|
}
|
|
|
|
#
|
|
# for each proj in the DefaultProjects list, add it to
|
|
# the SomeProjects list if it doesn't already exist there
|
|
# and (for all but new enlistments) it's not already enlisted
|
|
#
|
|
# this should use a hash
|
|
#
|
|
foreach $defproj (@main::DefaultProjects)
|
|
{
|
|
$found = $main::FALSE;
|
|
# print "defproj = '\l$defproj'\n";
|
|
|
|
foreach $someproj (@main::SomeProjects)
|
|
{
|
|
# print "\tsomeproj = \l$someproj\n";
|
|
|
|
("\l$defproj" eq "\l$someproj") and do
|
|
{
|
|
$found = $main::TRUE;
|
|
last;
|
|
}
|
|
}
|
|
|
|
$main::IncrEnlist and do
|
|
{
|
|
foreach $p (@main::SDMapProjects)
|
|
{
|
|
# print "\t\tp = '\l@$p[0]'\n";
|
|
("\l$defproj" eq "\l@$p[0]") and do
|
|
{
|
|
$found = $main::TRUE;
|
|
last;
|
|
}
|
|
}
|
|
};
|
|
|
|
!$found and push @main::SomeProjects, $defproj;
|
|
}
|
|
}
|
|
|
|
#
|
|
# if defecting, don't let the user remove any Default Projects
|
|
#
|
|
if ($defecting)
|
|
{
|
|
#
|
|
# load SomeProjects into a hash
|
|
#
|
|
# for each default project, mark it as unwanted (0)
|
|
#
|
|
# write the wanted (1) hash entries back into a list
|
|
#
|
|
@tmpproj = ();
|
|
%someproj = ();
|
|
foreach $sp (@main::SomeProjects)
|
|
{
|
|
$someproj{$sp} = 1;
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
while (($k,$v) = each %someproj)
|
|
{
|
|
printf "%20s\t%s\n", $k, $v;
|
|
}
|
|
};
|
|
|
|
$found = $main::FALSE;
|
|
foreach $dp (@main::DefaultProjects)
|
|
{
|
|
if ($someproj{$dp} == 1)
|
|
{
|
|
$found = $main::TRUE;
|
|
$someproj{$dp} = 0;
|
|
printf "Ignoring default project %s.\n", "\U$dp";
|
|
}
|
|
}
|
|
|
|
$found and print "\nUse -a to defect from required projects.\n\n";
|
|
|
|
while (($k,$v) = each %someproj)
|
|
{
|
|
$v and push @tmpproj, $k;
|
|
$main::V3 and printf "%20s\t%s\n", $k, $v;
|
|
}
|
|
|
|
@main::SomeProjects = sort @tmpproj;
|
|
}
|
|
|
|
#
|
|
# at this point @main::SomeProjects has been populated
|
|
#
|
|
# for each proj named in @main::SomeProjects, get the full
|
|
# project:group:depot:projroot mapping associated with it
|
|
# from the AllProjects list
|
|
#
|
|
foreach $project (@main::SomeProjects)
|
|
{
|
|
$found = $main::FALSE;
|
|
|
|
foreach $project2 (@main::AllProjects)
|
|
{
|
|
$proj = @$project2[$main::CBMProjectField];
|
|
|
|
if ("\L$project" eq "\L$proj")
|
|
{
|
|
push @projects, [@{$project2}];
|
|
$found = $main::TRUE;
|
|
last;
|
|
}
|
|
}
|
|
|
|
!$found and print "Unknown project $project.\n";
|
|
}
|
|
}
|
|
|
|
#
|
|
# create a list of just those depots we will enlist in
|
|
#
|
|
# for each depot in the AllDepots list, if it exists in the
|
|
# EnlistProjects list, add it to the EnlistDepots list
|
|
#
|
|
foreach $depot (@main::AllDepots)
|
|
{
|
|
# printf "%s\n", @$depot[0];
|
|
foreach $project (@projects)
|
|
{
|
|
$serverport = @$project[$main::CBMServerPortField];
|
|
# printf "\t%s\n", $serverport;
|
|
|
|
if (@$depot[0] eq $serverport)
|
|
{
|
|
# printf "\t\t%s\n", $serverport;
|
|
push @depots, [@{$depot}];
|
|
last;
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# assign the depot/project lists accordingly
|
|
#
|
|
$enlisting and do
|
|
{
|
|
@main::EnlistDepots = @depots;
|
|
@main::EnlistProjects = @projects;
|
|
};
|
|
|
|
$defecting and do
|
|
{
|
|
@main::DefectDepots = @depots;
|
|
@main::DefectProjects = @projects;
|
|
};
|
|
|
|
#
|
|
# remember relevant depots to check for access
|
|
#
|
|
@main::VerifyDepots = @depots;
|
|
@main::VerifyProjects = @projects;
|
|
|
|
$main::V3 and do
|
|
{
|
|
if ($enlisting)
|
|
{
|
|
print "\n";
|
|
foreach $project (@main::EnlistProjects)
|
|
{
|
|
print "mtl: EnlistProjects[] = @$project\n";
|
|
}
|
|
|
|
print "\n";
|
|
foreach $depot (@main::EnlistDepots)
|
|
{
|
|
print "mtl: EnlistDepots = @$depot\n";
|
|
}
|
|
}
|
|
|
|
if ($defecting)
|
|
{
|
|
print "\n";
|
|
foreach $project (@main::DefectProjects)
|
|
{
|
|
print "mtl: DefectProjects[] = @$project\n";
|
|
}
|
|
|
|
print "\n";
|
|
foreach $depot (@main::DefectDepots)
|
|
{
|
|
print "mtl: DefectDepots = @$depot\n";
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# SortDepots
|
|
#
|
|
# Parameters:
|
|
# @unsorted -- simple array of depot server:ports
|
|
#
|
|
# Output:
|
|
# @sorted -- simple array, sorted first by type (1 or 2) then alpha for
|
|
# the type 1's
|
|
# _____________________________________________________________________________
|
|
sub SortDepots
|
|
{
|
|
my ($unsorted) = $_[0];
|
|
my @sorted = ();
|
|
my @list = ();
|
|
|
|
#
|
|
# for each type 1 depot, put its project name in a list
|
|
#
|
|
# sort the list
|
|
#
|
|
$main::V3 and print "\nunsorted depots:\n";
|
|
|
|
foreach $sp (@$unsorted)
|
|
{
|
|
(@{$main::DepotType{$sp}}[0] == 1) and push @list, @{$main::DepotType{$sp}}[1];
|
|
|
|
$main::V3 and printf " %20s %s\n", @{$main::DepotType{$sp}}[1], $sp;
|
|
}
|
|
|
|
@list = sort @list;
|
|
|
|
foreach $p (@list)
|
|
{
|
|
foreach $sp (@$unsorted)
|
|
{
|
|
|
|
(@{$main::DepotType{$sp}}[1] eq $p) and push @sorted, $sp;
|
|
}
|
|
}
|
|
|
|
#
|
|
# add the rest of the (type 2) depots to the list w/o sorting
|
|
#
|
|
foreach $sp (@$unsorted)
|
|
{
|
|
(@{$main::DepotType{$sp}}[0] == 2) and push @sorted, $sp;
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nsorted depots:\n";
|
|
foreach $sp (@sorted)
|
|
{
|
|
printf " %20s %s\n", @{$main::DepotType{$sp}}[1], $sp;
|
|
}
|
|
};
|
|
|
|
return @sorted;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# VerifyBranch
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub VerifyBranch
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
my $nd = $_[1];
|
|
my @depots = ();
|
|
|
|
printf "\nLooking for branch %s in the depot%s", "\U$main::Branch", $nd > 1 ? "s" : "";
|
|
|
|
$enlisting and @depots = @main::EnlistDepots;
|
|
$defecting and @depots = @main::DefectDepots;
|
|
|
|
my $warning = $main::FALSE;
|
|
foreach $depot (@depots)
|
|
{
|
|
print ".";
|
|
|
|
my $serverport = @$depot[0];
|
|
!grep(/Branch $main::Branch /, `sd.exe -p $serverport branches 2>&1`) and $warning = $main::TRUE;
|
|
}
|
|
|
|
!$warning and print "\nok.\n";
|
|
return $warning;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# VerifyClient
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub VerifyClient
|
|
{
|
|
my $client = "\U$main::SDClient";
|
|
print "\nChecking for client $client in the depots.";
|
|
|
|
foreach $depot (@main::AllDepots)
|
|
{
|
|
print ".";
|
|
|
|
my $serverport = @$depot[0];
|
|
|
|
if (SDX::ClientExists($serverport, $main::SDClient))
|
|
{
|
|
print "\n\n$client already exists. Enlisting with \@<client> is only supported for new\n";
|
|
print "enlistents. If you want to keep $client as your client name, run 'sdx defect\n";
|
|
print "$main::CodeBase $main::Branch -a -f' to defect, or set \%SDCLIENT\% to another\n";
|
|
print "name, then rerun this command.\n";
|
|
|
|
die("\n");
|
|
}
|
|
}
|
|
|
|
print "\nok.\n";
|
|
};
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetProjectsToRepair
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# populates @main::RepairDepots and @main::RepairProjects
|
|
# returns 1 if successful, 0 otherwise
|
|
# _____________________________________________________________________________
|
|
sub GetProjectsToRepair
|
|
{
|
|
@main::RepairDepots = ();
|
|
@main::RepairProjects = ();
|
|
%seen = ();
|
|
|
|
#
|
|
# if only rewriting SD.INIs, base the depot/project repair lists on
|
|
# whatever is in SD.MAP and the codebase map
|
|
#
|
|
if ($main::MinusI)
|
|
{
|
|
my %seen = ();
|
|
|
|
#
|
|
# build list of depots
|
|
#
|
|
for $proj (@main::SDMapProjects)
|
|
{
|
|
for $proj2 (@main::AllProjects)
|
|
{
|
|
(@$proj[$main::CBMProjectField] eq @$proj2[$main::CBMProjectField]) and do
|
|
{
|
|
push @main::RepairProjects, $proj2;
|
|
|
|
my $sp = @$proj2[$main::CBMServerPortField];
|
|
unless ($seen{$sp})
|
|
{
|
|
$seen{$sp} = 1;
|
|
push @main::RepairDepots, [("$sp", "@$proj2[$main::CBMDepotNameField]")];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# adjust the list of actively used depots to
|
|
# reflect what we got out of the codebase map
|
|
#
|
|
@main::ActiveDepots = ();
|
|
for $depot (@main::RepairDepots)
|
|
{
|
|
push @main::ActiveDepots, @$depot[0];
|
|
};
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# for each depot, see if the client exists
|
|
# if so, get its view and munge it to see which
|
|
# projects it includes
|
|
#
|
|
foreach $depot (@main::AllDepots)
|
|
{
|
|
$serverport = @$depot[0];
|
|
$main::V3 and print "\t$serverport\n";
|
|
|
|
if (SDX::ClientExists($serverport, $main::SDClient))
|
|
{
|
|
#
|
|
# add this depot to the list
|
|
#
|
|
push @main::RepairDepots, $depot;
|
|
|
|
#
|
|
# read the existing client view into @main::ExistingView
|
|
#
|
|
SDX::GetClientView("repair", $serverport, $main::SDClient);
|
|
|
|
foreach $line (@main::ExistingView)
|
|
{
|
|
#
|
|
# throw away negating view lines
|
|
#
|
|
$line =~ /^[\t\s]+-/ and next;
|
|
|
|
@fields = split(/\//, $line);
|
|
$branch = @fields[3];
|
|
$project = @fields[4];
|
|
|
|
$project and do
|
|
{
|
|
# print "b/p $branch $project\n";
|
|
for $projectline (@main::AllProjects)
|
|
{
|
|
if ("\U$project" eq "\U@$projectline[$main::CBMProjectField]")
|
|
{
|
|
unless ($seen{$project})
|
|
{
|
|
$seen{$project} = 1;
|
|
push @main::RepairProjects, $projectline;
|
|
}
|
|
|
|
last;
|
|
}
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
foreach $depot (@main::RepairDepots)
|
|
{
|
|
print "RepairDepots: @$depot\n";
|
|
}
|
|
|
|
print "\n";
|
|
|
|
foreach $project (@main::RepairProjects)
|
|
{
|
|
print "RepairProjects: @$project\n";
|
|
}
|
|
};
|
|
|
|
#
|
|
# verify access for all depots in the repair list
|
|
#
|
|
@main::VerifyDepots = @main::RepairDepots;
|
|
|
|
#
|
|
# return success as long as these two lists have values
|
|
#
|
|
(@main::RepairDepots && @main::RepairProjects) and return 1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# CreateView
|
|
#
|
|
# Parameters:
|
|
# Command Line Arguments
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub CreateView
|
|
{
|
|
$depot = $_[0];
|
|
my $enlisting = ($_[1] eq "enlist");
|
|
my $defecting = ($_[1] eq "defect");
|
|
my $repairing = ($_[1] eq "repair");
|
|
my $root = "";
|
|
my $clobber = $main::FALSE;
|
|
my $crlf = $main::FALSE;
|
|
$serverport = @$depot[0];
|
|
$depotname = @$depot[1];
|
|
@main::tmpView = ();
|
|
@main::FinalView = ();
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in CreateView().\n");
|
|
|
|
unlink $main::ClientView;
|
|
|
|
#
|
|
# write the default view lines for this depot and project(s)
|
|
#
|
|
SDX::WriteDefaultView($serverport, $depotname);
|
|
|
|
#
|
|
# if we're doing a clean enlist or the client doesn't already exist,
|
|
# use the default view
|
|
# else merge the default view with the existing view
|
|
#
|
|
if ($main::CleanEnlist or !SDX::ClientExists($serverport, $main::SDClient))
|
|
{
|
|
#
|
|
# Root: field for client view depends on depot type
|
|
#
|
|
# for type 1 (1 project/depot), root includes project name
|
|
# for type 2 (N projects/depot), root is just main::SDXRoot
|
|
#
|
|
# root is at least SDXRoot in either case
|
|
#
|
|
$root = $main::SDXRoot;
|
|
(@{$main::DepotType{$serverport}}[0] == 1) and $root = SDX::Type1Root($root);
|
|
|
|
#
|
|
# files in root project in NT are clobberable
|
|
#
|
|
# BUGBUG-2000/5/12-jeffmcd -- this should be an option in the codebase map -- ClobberRoot = 1 or 0
|
|
# 2002/9/5 -jeremyd -- the whole options line should be configurable and fall back to server defaults
|
|
#
|
|
if ("\U$main::CodeBase" eq "NT")
|
|
{
|
|
$project = @main::ProjectsInThisDepot[0];
|
|
$clobber = ("\L@$project[$main::CBMProjectField]" eq "root");
|
|
}
|
|
|
|
#
|
|
# SQL SD server is setup as crlf
|
|
#
|
|
if ("\l$serverport" eq "sqldepot.sys-ntgroup.ntdev.microsoft.com:1666")
|
|
{
|
|
$crlf = $main::TRUE;
|
|
}
|
|
|
|
#
|
|
# write default view header
|
|
#
|
|
open(CLIENTVIEW, ">$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n");
|
|
|
|
printf CLIENTVIEW "Client: %s\n\n", $main::SDClient;
|
|
printf CLIENTVIEW "Owner: %s\n\n", $main::SDDomainUser;
|
|
printf CLIENTVIEW "Description:\n Created by %s.\n\n", $main::SDDomainUser;
|
|
printf CLIENTVIEW "Root: %s\n\n", $root;
|
|
printf CLIENTVIEW "Options: noallwrite %sclobber nocompress %scrlf locked nomodtime\n\n", $clobber ? "" : "no", $crlf ? "" : "no";
|
|
printf CLIENTVIEW "View:\n";
|
|
|
|
#
|
|
# append the default view
|
|
#
|
|
for $line (@main::DefaultView)
|
|
{
|
|
printf CLIENTVIEW $line;
|
|
### push @clientview, $line;
|
|
}
|
|
|
|
close(CLIENTVIEW);
|
|
|
|
$verb = "Creating";
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# read the existing client view into @main::ExistingView
|
|
#
|
|
SDX:GetClientView("enlist", $serverport, $main::SDClient);
|
|
|
|
#
|
|
# concat the existing view and the default view
|
|
#
|
|
for $line (@main::ExistingView)
|
|
{
|
|
push @main::tmpView, $line;
|
|
}
|
|
|
|
for $line (@main::DefaultView)
|
|
{
|
|
push @main::tmpView, $line;
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nexisting + default:\n";
|
|
print @main::tmpView;
|
|
};
|
|
|
|
#
|
|
# sort the list for uniqueness, preserving order
|
|
#
|
|
%seen = ();
|
|
@uniq = ();
|
|
foreach $line (@main::tmpView)
|
|
{
|
|
#
|
|
# lowercase the line for the check, but push the
|
|
# unchanged version of line onto the list so
|
|
# we preserve the user's case
|
|
#
|
|
unless ($seen{"\L$line"})
|
|
{
|
|
$seen{"\L$line"} = 1;
|
|
push @uniq, $line;
|
|
}
|
|
}
|
|
|
|
@main::FinalView = @uniq;
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nfinal view:\n";
|
|
print @main::FinalView;
|
|
};
|
|
|
|
#
|
|
# now finish writing the client view by appending the
|
|
# final view spec
|
|
#
|
|
open(CLIENTVIEW, ">>$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n");
|
|
|
|
for $viewline (@main::FinalView)
|
|
{
|
|
printf CLIENTVIEW $viewline;
|
|
}
|
|
|
|
close(CLIENTVIEW);
|
|
|
|
$verb = "Updating existing";
|
|
$repairing and $verb = "Verifying";
|
|
}
|
|
|
|
printf "\n%s client %s in depot %s.\n", $verb, $main::SDClient, $serverport;
|
|
|
|
$main::V1 and do
|
|
{
|
|
$main::V2 and do
|
|
{
|
|
printf "\ndepot mapping for %s (//%s) consists of %s project(s):\n\n", $serverport, $depotname, $#main::ProjectsInThisDepot+1;
|
|
foreach $project (@main::ProjectsInThisDepot)
|
|
{
|
|
printf "\t%s\n", @$project[$main::CBMProjectField];
|
|
}
|
|
};
|
|
|
|
print "\n\n";
|
|
system "type $main::ClientView 2>&1";
|
|
print "\n--------------------------------------------------\n\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteDefaultView
|
|
#
|
|
# Create the default view lines for this depot/project and push them onto a list
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub WriteDefaultView()
|
|
{
|
|
$serverport = $_[0];
|
|
$depotname = $_[1];
|
|
|
|
$proj = "";
|
|
$group = "";
|
|
$projroot = "";
|
|
@main::DefaultView = ();
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "sp = '$serverport'\n";
|
|
print "depotname = '$depotname'\n";
|
|
};
|
|
|
|
#
|
|
# for each project in this depot, generate the depot mappings and push
|
|
# them onto a list
|
|
#
|
|
foreach $project (@main::ProjectsInThisDepot)
|
|
{
|
|
$usingroot = $main::FALSE;
|
|
$proj = @$project[$main::CBMProjectField];
|
|
$group = @$project[$main::CBMGroupField];
|
|
$projroot = @$project[$main::CBMProjectRootField];
|
|
|
|
#
|
|
# flip any '\' in the proj root path into '/' for SD
|
|
#
|
|
$projroot =~ s/\\/\//g;
|
|
|
|
#
|
|
# special case for enlisting a project directly in the root
|
|
#
|
|
if ($projroot eq "sdxroot")
|
|
{
|
|
$usingroot = $main::TRUE;
|
|
}
|
|
|
|
#
|
|
# if no project root was given in the codebase map,
|
|
# assume the root is same as the project name
|
|
#
|
|
if (!$projroot)
|
|
{
|
|
$projroot = $proj;
|
|
}
|
|
|
|
#
|
|
# create and save the view line for this project
|
|
#
|
|
# handle special case for SD sources
|
|
# handle special case for enlisting directly in %SDXROOT%
|
|
# otherwise handle normal case
|
|
#
|
|
|
|
#
|
|
# see if this project is one for which we should exclude
|
|
# some platform-specific dirs from its view
|
|
#
|
|
$found = $main::FALSE;
|
|
$Exclude = $main::FALSE;
|
|
foreach $someproj (@main::PlatformProjects)
|
|
{
|
|
if ("\U$proj" eq "\U$someproj")
|
|
{
|
|
$found = $main::TRUE;
|
|
}
|
|
}
|
|
|
|
if ($found && $main::Exclusions)
|
|
{
|
|
$Exclude = $main::TRUE;
|
|
|
|
if ("\U$main::Platform" eq "X86")
|
|
{
|
|
}
|
|
|
|
if ("\U$main::Platform" eq "AMD64")
|
|
{
|
|
@ExcludePlats = ("x86", "i386", "ia64");
|
|
}
|
|
|
|
if ("\U$main::Platform" eq "IA64")
|
|
{
|
|
@ExcludePlats = ("x86", "i386", "amd64");
|
|
}
|
|
}
|
|
|
|
#
|
|
# special case for handling the one project in the codebase map that can be enlisted directly
|
|
# in $main::SDXRoot
|
|
#
|
|
if ($usingroot)
|
|
{
|
|
$projroot = $proj;
|
|
|
|
#
|
|
# maybe restrict the scope of the root mapping
|
|
#
|
|
$rootspec = "...";
|
|
$main::RestrictRoot and do
|
|
{
|
|
$rootspec = "*";
|
|
};
|
|
|
|
#
|
|
# generate some shorthand for the depot-branch-project on LHS of the view
|
|
#
|
|
my $dbp = SDX::MakeDBP($serverport, $depotname, $group, $projroot);
|
|
|
|
#
|
|
# if this is the tools project and the user wants the minimal
|
|
# tool set, customize the view
|
|
#
|
|
# else generate the normal view line
|
|
#
|
|
my $mintools = ("\U$proj" eq "\U$main::ToolsProject" and $main::MinimalTools);
|
|
|
|
if ($mintools)
|
|
{
|
|
#
|
|
# add '/' if we have a tools path
|
|
#
|
|
my $tpath = ($main::ToolsPath ? "/$main::ToolsPath" : "");
|
|
|
|
#
|
|
# flip any '\' in the tools path into '/' for SD
|
|
#
|
|
$tpath =~ s/\\/\//g;
|
|
|
|
#
|
|
# -//depot/<branch>/<toolsproj>/... //<client>/...
|
|
#
|
|
$viewline = sprintf("\t-//%s/... //%s/...\n", $dbp, $main::SDClient);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# //depot/<branch>/<toolsproj>/* //<client>/*
|
|
#
|
|
$viewline = sprintf("\t//%s/* //%s/*\n", $dbp, $main::SDClient);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# //depot/<branch>/<toolsproj>[/<toolspath>/]* //<client>[/<toolspath>/]*
|
|
#
|
|
$viewline = sprintf("\t//%s%s/* //%s%s/*\n", $dbp, $tpath, $main::SDClient, $tpath);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# //depot/<branch>/<toolsproj>[/<toolspath>]/<PA>/*sd*exe //<client>[/<toolspath>]/<PA>/*sd*exe
|
|
#
|
|
$viewline = sprintf("\t//%s%s/%s/*sd*exe //%s%s/%s/*sd*exe\n", $dbp, $tpath, $main::Platform, $main::SDClient, $tpath, $main::Platform);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# //depot/<branch>/<toolsproj>[/<toolspath>]/<PA>/perl/... //<client>[/<toolspath>]/<PA>/perl/...
|
|
#
|
|
$viewline = sprintf("\t//%s%s/%s/perl/... //%s%s/%s/perl/...\n", $dbp, $tpath, $main::Platform, $main::SDClient, $tpath, $main::Platform);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
else
|
|
{
|
|
$viewline = sprintf("\t//%s/%s //%s/%s\n", $dbp, $rootspec, $main::SDClient, $rootspec);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
|
|
#
|
|
# if it's NT (or a codebase that uses NT's Root depot) and exclusionary mappings are allowed,
|
|
# restrict the user's view of \developer to just themselves
|
|
#
|
|
$main::Exclusions and do
|
|
{
|
|
### HACKHACK -- rm check on $main::RestrictRoot when old NTTEST CBM goes away
|
|
|
|
#
|
|
# BUGBUG-2000/01/18-jeffmcd -- add keyword USERSDIR=<some dir relative to root containing user-specific files>
|
|
#
|
|
(
|
|
"\U$main::CodeBase" eq "NT" or
|
|
("\U$main::CodeBase" eq "NTTEST" and !$main::RestrictRoot) or
|
|
"\U$main::CodeBase" eq "NTSDK" or
|
|
"\U$main::CodeBase" eq "NT.INTL" or
|
|
"\U$main::CodeBase" eq "MPC" or
|
|
"\U$main::CodeBase" eq "NGWS" or
|
|
"\U$main::CodeBase" eq "MGMT" or
|
|
"\U$main::CodeBase" eq "MOM" or
|
|
"\U$main::CodeBase" eq "PDDEPOT" or
|
|
"\U$main::CodeBase" eq "WINMEDIA" or
|
|
"\U$main::CodeBase" eq "WINSS"
|
|
) and do
|
|
{
|
|
#
|
|
# this negation line isn't necessary if we're doing minimal tools
|
|
#
|
|
!$mintools and do
|
|
{
|
|
$viewline = sprintf("\t-//%s/developer/... //%s/developer/...\n", $dbp, $main::SDClient);
|
|
push @main::DefaultView, $viewline;
|
|
};
|
|
|
|
$viewline = sprintf("\t//%s/developer/* //%s/developer/*\n", $dbp, $main::SDClient);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
$viewline = sprintf("\t//%s/developer/%s/... //%s/developer/%s/...\n", $dbp, $main::SDUser, $main::SDClient, $main::SDUser);
|
|
push @main::DefaultView, $viewline;
|
|
};
|
|
};
|
|
|
|
#
|
|
# only do the exclude lines if the root isn't already restricted
|
|
# and we're not doing minimal tools (since everything in Root will
|
|
# already be restricted except what the user needs)
|
|
#
|
|
if ($Exclude && !$main::RestrictRoot && !$main::MinimalTools)
|
|
{
|
|
for $e (@ExcludePlats)
|
|
{
|
|
#
|
|
# generate the view line and save it away
|
|
#
|
|
$viewline = sprintf("\t-//%s/.../%s/... //%s/.../%s/...\n", $dbp, $e, $main::SDClient, $e);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# generate the view line(s)
|
|
#
|
|
#
|
|
# for the USERS project in Scratch depots, only map in \users\<this user>
|
|
#
|
|
# BUGBUG-2000/01/10-jeffmcd -- remove this when enlisting with <project>\path\path\path is supported
|
|
#
|
|
if ("\U$main::CodeBase" eq "SCRATCH" and $projroot eq "users")
|
|
{
|
|
# shorthand
|
|
my $dbp = SDX::MakeDBP($serverport, $depotname, $group, $projroot);
|
|
|
|
# -//depot/<branch>/users/... //<client>/users/...
|
|
$viewline = sprintf("\t-//%s/... //%s/%s/...\n", $dbp, $main::SDClient, $projroot);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
# //depot/<branch>/users/<this user>/... //<client>/users/<this user>/...
|
|
$viewline = sprintf("\t//%s/%s/... //%s/%s/%s/...\n", $dbp, $main::SDUser, $main::SDClient, $projroot, $main::SDUser);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# the form of the project root depends on project type and codebase
|
|
#
|
|
my $proot = SDX::MakeProjectRoot($proj, $projroot);
|
|
|
|
#
|
|
# some shorthand
|
|
#
|
|
my $dbp = SDX::MakeDBP($serverport, $depotname, $group, $proj);
|
|
my $mintools = ("\U$main::ToolsProject" eq "\U$proj" and $main::MinimalTools);
|
|
|
|
#
|
|
# if $proj is the tools project and the user wants the minimal
|
|
# tool set, customize the view
|
|
#
|
|
# else generate the normal view line
|
|
#
|
|
if ($mintools)
|
|
{
|
|
#
|
|
# add '/' if we have a tools path
|
|
# add "/<project root>" if type 2 depot
|
|
#
|
|
my $tpath = ($main::ToolsPath ? "/$main::ToolsPath" : "");
|
|
|
|
#
|
|
# flip any '\' in the tools path into '/' for SD
|
|
#
|
|
$tpath =~ s/\\/\//g;
|
|
|
|
#
|
|
# 1: -//depot/<branch>/<proj>/... //<client>/...
|
|
# 2: -//depot/<branch>/<proj>/... //<client>/<project root>/...
|
|
#
|
|
$viewline = sprintf("\t-//%s/... //%s%s/...\n", $dbp, $main::SDClient, $proot);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# 1: //depot/<branch>/<proj>/<toolspath>/* //<client>/<toolspath>/*
|
|
# 2: //depot/<branch>/<proj>/<toolspath>/* //<client>/<project root>/<toolspath>/*
|
|
#
|
|
$viewline = sprintf("\t//%s%s/* //%s%s%s/*\n", $dbp, $tpath, $main::SDClient, $proot, $tpath);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# 1: //depot/<branch>/<proj>/<toolspath>/<PA>/*sd*exe //<client>/<toolspath>/<PA>/*sd*exe
|
|
# 2: //depot/<branch>/<proj>/<toolspath>/<PA>/*sd*exe //<client>/<project root>/<toolspath>/<PA>/*sd*exe
|
|
#
|
|
$viewline = sprintf("\t//%s%s/%s/*sd*exe //%s%s%s/%s/*sd*exe\n", $dbp, $tpath, $main::Platform, $main::SDClient, $proot, $tpath, $main::Platform);
|
|
push @main::DefaultView, $viewline;
|
|
|
|
#
|
|
# 1: //depot/<branch>/<proj>/<toolspath>/<PA>/perl/... //<client>/<toolspath>/<PA>/perl/...
|
|
# 2: //depot/<branch>/<proj>/<toolspath>/<PA>/perl/... //<client>/<project root>/<toolspath>/<PA>/perl/...
|
|
#
|
|
$viewline = sprintf("\t//%s%s/%s/perl/... //%s%s%s/%s/perl/...\n", $dbp, $tpath, $main::Platform, $main::SDClient, $proot, $tpath, $main::Platform);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# 1: //depot/<branch>/project/... //<client>/...
|
|
# 2: //depot/<branch>/<project>/... //<client>/<project root>/...
|
|
#
|
|
$viewline = sprintf("\t//%s/... //%s%s/...\n", $dbp, $main::SDClient, $proot);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
}
|
|
|
|
#
|
|
# add exclude lines to the view if this project is marked as
|
|
# having multiple platforms in the codebase map
|
|
#
|
|
if ($Exclude)
|
|
{
|
|
# shorthand
|
|
my $dbp = "$depotname/$main::Branch/$proj";
|
|
|
|
for $e (@ExcludePlats)
|
|
{
|
|
#
|
|
# generate the view line and save it away
|
|
#
|
|
# for type 1 projects (1 project/depot) project name can't be in RHS
|
|
#
|
|
# for type 2 projects (N projects/depot) project name must be in RHS
|
|
#
|
|
my $proot = SDX::MakeProjectRoot($proj, $projroot);
|
|
|
|
$viewline = sprintf("\t-//%s/.../%s/... //%s%s/.../%s/...\n", $dbp, $e, $main::SDClient, $proot, $e);
|
|
push @main::DefaultView, $viewline;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\ndefault view --------------------\n";
|
|
for $line (@main::DefaultView)
|
|
{
|
|
print "$line";
|
|
}
|
|
print "---------------------------------\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# MakeDBP
|
|
#
|
|
# builds depot-branch-project string depending on project's group
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# string
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub MakeDBP()
|
|
{
|
|
my $sp = $_[0];
|
|
my $depotname = $_[1];
|
|
my $group = $_[2];
|
|
my $projroot = $_[3];
|
|
my $path = "//$depotname/$main::Branch/$projroot";
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nmakedbp: sp = '$sp'\n";
|
|
print "makedbp: depotname = '$depotname'\n";
|
|
print "makedbp: group = '$group'\n";
|
|
print "makedbp: projroot = '$projroot'\n\n";
|
|
print "makedbp: path = '$path'\n\n";
|
|
};
|
|
|
|
#
|
|
# start with depot name
|
|
#
|
|
my $dbp = $depotname;
|
|
|
|
#
|
|
# determine branch
|
|
#
|
|
# NTDEV projects have lab branches, so we can use whichever one the user wants
|
|
#
|
|
# non-NTDEV projects (like Test, Spec, Intl projects) may or may not have the
|
|
# user's lab branch -- if it exists, use it, else default to the master branch
|
|
#
|
|
if (("\U$group" eq "NTDEV") or (SDX::BranchExists($main::Branch, $sp, $path, "by-path")))
|
|
{
|
|
$dbp .= "/$main::Branch/";
|
|
}
|
|
else
|
|
{
|
|
$dbp .= "/$main::MasterBranch/";
|
|
}
|
|
|
|
#
|
|
# add the project root
|
|
#
|
|
$dbp .= $projroot;
|
|
|
|
$main::V3 and print "makedbp: returning '$dbp'\n";
|
|
|
|
return $dbp;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ClientExists
|
|
#
|
|
# Determine if $main::SDClient exists in the given depot
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# TRUE if client found in depot, FALSE otherwise
|
|
# _____________________________________________________________________________
|
|
sub ClientExists()
|
|
{
|
|
my $serverport = $_[0];
|
|
my $client = $_[1];
|
|
my @out = ();
|
|
my $found = $main::FALSE;
|
|
|
|
#
|
|
# list clients and grep for client name
|
|
#
|
|
@out = `sd.exe -p $serverport clients 2>&1`;
|
|
(grep /Client $client /i, @out) and $found = $main::TRUE;
|
|
|
|
#
|
|
# die if we're ever denied access
|
|
#
|
|
SDX::AccessDenied(\@out, $serverport) and die("\n");
|
|
|
|
return $found;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# BranchExists
|
|
#
|
|
# Determine if a branch exists in the given depot
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# TRUE if found, FALSE otherwise
|
|
# _____________________________________________________________________________
|
|
sub BranchExists()
|
|
{
|
|
my $branch = $_[0];
|
|
my $sp = "-p $_[1]";
|
|
my $path = $_[2];
|
|
my $method = $_[3];
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\nbranchexists: branch = '$branch'\n";
|
|
print "branchexists: sp = '$sp'\n";
|
|
print "branchexists: path = '$path'\n";
|
|
print "branchexists: method = '$method'\n\n";
|
|
};
|
|
|
|
#
|
|
# list branches and look for branch name
|
|
#
|
|
($method eq "by-name") and do
|
|
{
|
|
grep(/Branch $branch/i, `sd.exe $sp branches 2>&1`) and return 1;
|
|
};
|
|
|
|
#
|
|
# see if //<depot>/<branch>/<project> is found
|
|
#
|
|
# sd dirs is unreliable, so look at the first line returned by sd files ...
|
|
#
|
|
($method eq "by-path") and do
|
|
{
|
|
my @out = ();
|
|
open FILE, "sd.exe $sp files $path/... 2>&1 |" or die("\nBranchExists: can't open pipe.\n");
|
|
while (<FILE>) { push @out, $_; last; }
|
|
close FILE;
|
|
|
|
grep(/ no such /, @out) and return 0;
|
|
return 1;
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetClientView
|
|
#
|
|
# Read the existing client view out of the depot for this client. Split it into
|
|
# header and view lines. If enlisting/defecting, write the header directly to the
|
|
# new client view file.
|
|
#
|
|
# Parameters:
|
|
# serverport depot server:port pair
|
|
# client SDClient name to look up
|
|
#
|
|
# Output:
|
|
# populates @main::ExistingView if repairing
|
|
# writes $main::ClientView if enlisting/defecting
|
|
# _____________________________________________________________________________
|
|
sub GetClientView()
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
my @view = ();
|
|
|
|
$serverport = $_[1];
|
|
$client = $_[2];
|
|
@main::ExistingView = ();
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in GetClientView().\n");
|
|
|
|
#
|
|
# dump the client view spec
|
|
#
|
|
@view = `sd.exe -p $serverport client -o $client 2>&1`;
|
|
|
|
#
|
|
# read the viewspec and maybe write the header for the new client view
|
|
#
|
|
($enlisting || $defecting) and (open(CLIENTVIEW, ">$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n"));
|
|
|
|
$header = $main::TRUE;
|
|
foreach $line (@view)
|
|
{
|
|
#
|
|
# throw away comments and blank lines
|
|
#
|
|
$line =~ /^#/ and next;
|
|
$line =~ /^[\t\s]*$/ and next;
|
|
|
|
#
|
|
# if we're still in the header, right the line directly
|
|
# to the new view
|
|
# otherwise push the view line into a list for later use
|
|
#
|
|
if ($header)
|
|
{
|
|
($enlisting || $defecting) and printf CLIENTVIEW $line;
|
|
}
|
|
else
|
|
{
|
|
push @main::ExistingView, $line;
|
|
}
|
|
|
|
@vline = split(/[\t\s]+/,$line);
|
|
if ("\U$vline[0]" eq "VIEW:")
|
|
{
|
|
$header = $main::FALSE;
|
|
}
|
|
}
|
|
|
|
($enlisting || $defecting) and close(CLIENTVIEW);
|
|
|
|
$main::V3 and do
|
|
{
|
|
# print "\nexisting view header:\n";
|
|
# system "type $main::ClientView";
|
|
|
|
print "\nexisting view -------------------\n";
|
|
print "'@main::ExistingView'\n";
|
|
print "---------------------------------\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# UpdateSDMap
|
|
#
|
|
# Creates or updates %SDXROOT%\SD.MAP, containing a list of projects and relative
|
|
# paths to their roots in the enlistment where the SD.INI can be found.
|
|
#
|
|
# Leaves these files read-only so they stay nailed down when we delete /S.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub UpdateSDMap
|
|
{
|
|
my $op = $_[0];
|
|
|
|
my $enlisting = ($op eq "enlist");
|
|
my $defecting = ($op eq "defect");
|
|
my $repairing = ($op eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in UpdateSDMap().\n");
|
|
|
|
@main::tmpMap = ();
|
|
|
|
#
|
|
# if we're doing a clean enlist (ie no SD.MAP exists), use the default map
|
|
# else merge the default map with the existing map
|
|
#
|
|
($enlisting || $repairing) and do
|
|
{
|
|
if (!(-e $main::SDMap))
|
|
{
|
|
printf "%s SD.MAP", $enlisting ? "Creating" : "Restoring";
|
|
|
|
@null = ();
|
|
SDX::WriteSDMap(\@null);
|
|
|
|
print "\n";
|
|
}
|
|
else
|
|
{
|
|
printf "%s SD.MAP", $enlisting ? "Updating" : "Repairing";
|
|
|
|
#
|
|
# load the default map into @main::DefaultMap
|
|
# and write the SD.INIs
|
|
#
|
|
SDX:WriteDefaultMap($main::Null, $main::Null);
|
|
|
|
#
|
|
# load the existing map into @main::ExistingMap
|
|
#
|
|
SDX::GetMapProjects($op);
|
|
|
|
#
|
|
# concat these two lists
|
|
#
|
|
for $line (@main::DefaultMap)
|
|
{
|
|
push @main::tmpMap, $line;
|
|
}
|
|
|
|
for $line (@main::ExistingMap)
|
|
{
|
|
push @main::tmpMap, $line;
|
|
}
|
|
|
|
$main::V1 and do
|
|
{
|
|
print "\ntmp map:\n\t";
|
|
print @main::tmpMap;
|
|
};
|
|
|
|
#
|
|
# unique-ify and sort them
|
|
#
|
|
%seen = ();
|
|
foreach $line (@main::tmpMap)
|
|
{
|
|
$seen{$line}++;
|
|
}
|
|
|
|
@uniq = keys %seen;
|
|
|
|
$main::V1 and do
|
|
{
|
|
print "\nuniq map:\n\t";
|
|
print @uniq;
|
|
};
|
|
|
|
@sorted = sort @uniq;
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nsorted:\n\t";
|
|
print @sorted;
|
|
};
|
|
|
|
#
|
|
# write it
|
|
#
|
|
SDX::WriteSDMap(\@sorted);
|
|
|
|
print "\n";
|
|
}
|
|
};
|
|
|
|
$defecting and do
|
|
{
|
|
if ($main::DefectAll)
|
|
{
|
|
SDX::KillSDMap();
|
|
}
|
|
else
|
|
{
|
|
print "Removing projects from SD.MAP";
|
|
|
|
#
|
|
# load the default map into @main::DefaultMap
|
|
#
|
|
SDX:WriteDefaultMap($main::Null,$main::Null);
|
|
|
|
#
|
|
# load the existing map into @main::ExistingMap
|
|
#
|
|
if (SDX::GetMapProjects($op))
|
|
{
|
|
#
|
|
# use the existing map lines as keys to a hash,
|
|
# lowercasing them to ignore upper/lowercase
|
|
# distinctions
|
|
#
|
|
# for each line in the default map, mark it as
|
|
# removed from the hash of existing lines
|
|
#
|
|
# write the unmarked hash lines back into the list
|
|
# and sort it
|
|
#
|
|
@tmpmap = ();
|
|
%existingmap = ();
|
|
foreach $em (@main::ExistingMap)
|
|
{
|
|
$existingmap{"\L$em"} = 1;
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\n\nexistingmap:\n";
|
|
while (($k,$v) = each %existingmap)
|
|
{
|
|
printf "%40s %s\n", $k, $v;
|
|
}
|
|
};
|
|
|
|
foreach $dm (@main::DefaultMap)
|
|
{
|
|
if ($existingmap{"\L$dm"} == 1)
|
|
{
|
|
$existingmap{"\L$dm"} = 0;
|
|
}
|
|
}
|
|
|
|
$main::V2 and print "\nexistingmap, edited:\n";
|
|
|
|
while (($k,$v) = each %existingmap)
|
|
{
|
|
$v and push @tmpmap, $k;
|
|
|
|
$main::V2 and do
|
|
{
|
|
my $vv = (!$v) ? " $v" : $v;
|
|
printf "%40s %s\n", $k, $vv;
|
|
}
|
|
}
|
|
|
|
@sorted = sort @tmpmap;
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nsorted:\n\t";
|
|
print @sorted;
|
|
};
|
|
|
|
#
|
|
# at this point, if we still have something to write in the map file,
|
|
# write it out
|
|
# else remove whatever's left of it
|
|
#
|
|
# this will happen in the case where there are no DefaultProjects in
|
|
# the codebase map and the user lists all known projects on the defect
|
|
# cmd line
|
|
#
|
|
($main::V3 and @sorted) and print "\n\t\@sorted not empty.\n";
|
|
($main::V3 and !@sorted) and print "\n\t\@sorted empty.\n";
|
|
|
|
if (@sorted)
|
|
{
|
|
SDX::WriteSDMap(\@sorted);
|
|
print "\n";
|
|
}
|
|
else
|
|
{
|
|
SDX::KillSDMap();
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
#
|
|
# if we still have a map file, make it RO, hidden
|
|
#
|
|
(-e $main::SDMap) and system "attrib +R +H $main::SDMap >nul 2>&1";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteSDMap
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteSDMap
|
|
{
|
|
my ($sorted) = $_;
|
|
|
|
$main::V3 and print "\n\nwritesdmap: sorted = @sorted\n";
|
|
|
|
system "attrib -R -H -S $main::SDMap >nul 2>&1";
|
|
open(SDMAP, ">$main::SDMap") or die("\nCan't open $main::SDMap for writing.\n");
|
|
|
|
print SDMAP "#\n# SD.MAP -- autogenerated by SDX -- do not edit\n#\n";
|
|
|
|
print SDMAP "\nCODEBASE = $main::CodeBase\n";
|
|
|
|
SDX::WriteSDMapCodeBaseType($main::CodeBaseType, *SDMAP);
|
|
|
|
print SDMAP "BRANCH = $main::Branch\n";
|
|
print SDMAP "CLIENT = $main::SDClient\n";
|
|
|
|
print SDMAP "\n#\n# project root\n# ------------------- -----------------------------------------------------\n";
|
|
|
|
#
|
|
# if we have a sorted list of projects, print them,
|
|
# else write the default list
|
|
#
|
|
if (@sorted)
|
|
{
|
|
foreach $line (@sorted)
|
|
{
|
|
@fields = split(/=/, $line);
|
|
printf SDMAP "%21s = %-52s\n", $fields[0], $fields[1];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# append the default map lines to SD.MAP
|
|
#
|
|
SDX::WriteDefaultMap("append",*SDMAP);
|
|
}
|
|
|
|
#
|
|
# print the list of enlisted depots
|
|
#
|
|
SDX::WriteSDMapDepots(\@main::ActiveDepots, *SDMAP);
|
|
|
|
close(SDMAP);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteSDMapDepots
|
|
#
|
|
# add list of enlisted depots to SD.MAP
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteSDMapDepots
|
|
{
|
|
my ($depots) = $_[0];
|
|
my $sdmap = $_[1];
|
|
|
|
my $list = "";
|
|
for $d (@$depots)
|
|
{
|
|
$d =~ /\:/ and do
|
|
{
|
|
$list .= "$d ";
|
|
};
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nabout to write depot list = '$list'\n";
|
|
};
|
|
|
|
print $sdmap "\n#\n# depots\n#\n";
|
|
print $sdmap "DEPOTS = $list\n\n";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteSDMapCodeBaseType
|
|
#
|
|
# add codebase type to SD.MAP
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteSDMapCodeBaseType
|
|
{
|
|
my $type = $_[0];
|
|
my $sdmap = $_[1];
|
|
|
|
print $sdmap "CODEBASETYPE = $type\n";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# KillSDMap
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub KillSDMap
|
|
{
|
|
-e $main::SDMap and do
|
|
{
|
|
print "Removing $main::SDMap\n";
|
|
|
|
system "attrib -R -H -S $main::SDMap >nul 2>&1";
|
|
unlink $main::SDMap;
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteDefaultMap
|
|
# writes the project-specific SD.MAP lines to the actual SD.MAP (if enlisting
|
|
# clean) or pushes them onto a list so we can sort them later.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteDefaultMap
|
|
{
|
|
my $appending = ($_[0] eq "append");
|
|
my $sdmap = $_[1];
|
|
|
|
@main::DefaultMap = ();
|
|
|
|
#
|
|
# maybe just append to the real SD.MAP, which at this point
|
|
# only contains the header
|
|
# otherwise write to a temp file
|
|
#
|
|
foreach $project (@main::ProjectsInThisDepot)
|
|
{
|
|
print ".";
|
|
|
|
$usingroot = $main::FALSE;
|
|
$proj = @$project[$main::CBMProjectField];
|
|
$serverport = @$project[$main::CBMServerPortField];
|
|
$projectroot = @$project[$main::CBMProjectRootField];
|
|
|
|
#
|
|
# if no project root was given in the codebase map,
|
|
# assume the root is same as the project name
|
|
#
|
|
if (!$projectroot)
|
|
{
|
|
$projectroot = $proj;
|
|
}
|
|
|
|
#
|
|
# special case for enlisting a project directly in the root
|
|
#
|
|
if ("\U$projectroot" eq "SDXROOT")
|
|
{
|
|
$usingroot = $main::TRUE;
|
|
$projectroot = ".";
|
|
}
|
|
|
|
#
|
|
# convert '/' to '\'
|
|
#
|
|
$projectroot =~ s/\//\\/g;
|
|
|
|
#
|
|
# push the map line onto the list so we can sort it
|
|
#
|
|
$mapline = sprintf("%s=%s", $proj, $projectroot);
|
|
push @main::DefaultMap, $mapline;
|
|
}
|
|
|
|
$appending and do
|
|
{
|
|
my @sorted = sort @main::DefaultMap;
|
|
for $line (@sorted)
|
|
{
|
|
@fields = split(/=/, $line);
|
|
printf $sdmap "%21s = %-52s\n", $fields[0], $fields[1];
|
|
}
|
|
};
|
|
|
|
$main::V1 and do
|
|
{
|
|
print "\n\ndefault map:\n\t";
|
|
for $line (@main::DefaultMap)
|
|
{
|
|
print "$line";
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetMapProjects
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# returns 1 if map found and list created, 0 otherwise
|
|
# _____________________________________________________________________________
|
|
sub GetMapProjects
|
|
{
|
|
my $op = $_[0];
|
|
my $line = "";
|
|
|
|
@main::ExistingMap = ();
|
|
|
|
#
|
|
# read the map again since it may be changing
|
|
#
|
|
if (SDX::ReadSDMap($op, $main::Null))
|
|
{
|
|
for $p (@main::SDMapProjects)
|
|
{
|
|
$line = @$p[0] . "=" . @$p[1];
|
|
push @main::ExistingMap, $line;
|
|
}
|
|
}
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nexisting map:\n\t";
|
|
for $line (@main::ExistingMap)
|
|
{
|
|
print "getmapproj: line = '$line'\n";
|
|
}
|
|
};
|
|
|
|
@main::ExistingMap and return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# UpdateSDINIs
|
|
#
|
|
# If enlisting or repairing, creates an SD.INI in the root of each project which
|
|
# points SDPORT to the server:port for that project and sets SDCLIENT.
|
|
#
|
|
# If defecting,
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub UpdateSDINIs
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in UpdateSDINIs().\n");
|
|
|
|
($enlisting || $repairing) and do
|
|
{
|
|
print "Writing SD.INIs in project roots";
|
|
|
|
foreach $project (@main::ProjectsInThisDepot)
|
|
{
|
|
print ".";
|
|
|
|
$usingroot = $main::FALSE;
|
|
$proj = @$project[$main::CBMProjectField];
|
|
$serverport = @$project[$main::CBMServerPortField];
|
|
$projectroot = @$project[$main::CBMProjectRootField];
|
|
|
|
#
|
|
# if no project root was given in the codebase map,
|
|
# assume the root is same as the project name
|
|
#
|
|
if (!$projectroot)
|
|
{
|
|
$projectroot = $proj;
|
|
}
|
|
|
|
#
|
|
# special case for enlisting a project directly in the root
|
|
#
|
|
if ("\U$projectroot" eq "SDXROOT")
|
|
{
|
|
$usingroot = $main::TRUE;
|
|
$projectroot = ".";
|
|
}
|
|
|
|
#
|
|
# convert '/' to '\'
|
|
#
|
|
$projectroot =~ s/\//\\/g;
|
|
|
|
#
|
|
# write the corresponding SD.INI
|
|
#
|
|
SDX::WriteSDINI($projectroot, $serverport);
|
|
}
|
|
};
|
|
|
|
$defecting and do
|
|
{
|
|
#
|
|
# sync #none the project and remove the whole thing
|
|
#
|
|
# can't just do sync #none across whole depot, since it would
|
|
# remove TOOLS dir and/or other default projects we want the user to keep
|
|
#
|
|
printf "\nDefecting client %s from projects in depot %s.\n", $main::SDClient, $serverport;
|
|
print "Please wait, syncing to remove files.";
|
|
|
|
foreach $project (@main::ProjectsInThisDepot)
|
|
{
|
|
$proj = @$project[$main::CBMProjectField];
|
|
$serverport = @$project[$main::CBMServerPortField];
|
|
$projectroot = @$project[$main::CBMProjectRootField];
|
|
|
|
#
|
|
# if no project root was given in the codebase map,
|
|
# assume the root is same as the project name
|
|
#
|
|
if (!$projectroot)
|
|
{
|
|
$projectroot = $proj;
|
|
}
|
|
|
|
#
|
|
# special case for enlisting a project directly in the root
|
|
#
|
|
if ("\U$projectroot" eq "SDXROOT")
|
|
{
|
|
$projectroot = ".";
|
|
}
|
|
|
|
#
|
|
# convert '/' to '\'
|
|
#
|
|
$projectroot =~ s/\//\\/g;
|
|
|
|
#
|
|
# maybe ghost files and remove the project
|
|
#
|
|
# specifically ignore the Tools project, it will be handled
|
|
# in FinishDefect()
|
|
#
|
|
$fullprojectroot = $main::SDXRoot . "\\" . $projectroot;
|
|
if (-e $fullprojectroot)
|
|
{
|
|
#
|
|
# sync #none to remove files
|
|
#
|
|
SDX::SyncFiles("defect", $fullprojectroot, $proj);
|
|
|
|
#
|
|
# nuke it all
|
|
#
|
|
SDX::RemoveProject($fullprojectroot, $serverport, $proj);
|
|
}
|
|
}
|
|
|
|
print "\n";
|
|
};
|
|
|
|
!$defecting and print "\nok.\n";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteSDINI
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteSDINI
|
|
{
|
|
$projectroot = $_[0];
|
|
$serverport = $_[1];
|
|
|
|
#
|
|
# write the corresponding SD.INI and make it RO, hidden
|
|
#
|
|
$fullprojectroot = $main::SDXRoot . "\\" . $projectroot;
|
|
$sdini = $fullprojectroot . "\\sd.ini";
|
|
|
|
system "mkdir $fullprojectroot >nul 2>&1";
|
|
-e $fullprojectroot or die "\nCan't create project root dir $fullprojectroot.\n";
|
|
|
|
#
|
|
# make it fully writable
|
|
#
|
|
system "attrib -R -H -S $sdini >nul 2>&1";
|
|
|
|
#
|
|
# write it
|
|
#
|
|
open(SDINI, ">$sdini") or die("\nCan't open $sdini for writing.\n");
|
|
printf SDINI "#\n# autogenerated by SDX - do not edit\n#\n";
|
|
printf SDINI "SDPORT=$serverport\n";
|
|
printf SDINI "SDCLIENT=$main::SDClient\n";
|
|
close(SDINI);
|
|
|
|
#
|
|
# make it read-only, hidden
|
|
#
|
|
system "attrib +R +H $sdini >nul 2>&1";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# SyncFiles
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub SyncFiles
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
my $fullprojectroot = $_[1];
|
|
my $proj = $_[2];
|
|
my $root = ($proj eq "root");
|
|
my $filespec;
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in SyncFiles().\n");
|
|
|
|
$defecting and do
|
|
{
|
|
chdir $fullprojectroot or die("\nCan't chdir to $fullprojectroot.\n");
|
|
print ".";
|
|
|
|
#
|
|
# handle the root carefully
|
|
#
|
|
if ($root)
|
|
{
|
|
#
|
|
# sync files directly in the root
|
|
#
|
|
$filespec = "*";
|
|
system "sd.exe sync $filespec#none >nul 2>&1";
|
|
|
|
#
|
|
# get the list of root subdirs
|
|
#
|
|
@main::RemovableRootDirs = SDX::GetImmediateSubDirs($proj);
|
|
|
|
#
|
|
# sync in the subdirs of the root individually, except
|
|
# for the tools dir
|
|
#
|
|
foreach $dir (@main::RemovableRootDirs)
|
|
{
|
|
$cmd = "sd.exe sync $dir\\...#none 2>&1";
|
|
SDX::ShowSyncProgress($cmd, 20);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# only sync if we're not in the tools project
|
|
#
|
|
if ($proj ne $main::ToolsProject)
|
|
{
|
|
$filespec = "...";
|
|
|
|
$cmd = "sd.exe sync $filespec#none 2>&1";
|
|
SDX::ShowSyncProgress($cmd, 20);
|
|
}
|
|
}
|
|
|
|
|
|
chdir $main::StartDir or die("\nCan't cd to start dir $main::StartDir.\n");
|
|
};
|
|
|
|
($enlisting || $repairing) and do
|
|
{
|
|
my @depotlist = ();
|
|
$enlisting and @depotlist = @main::EnlistDepots;
|
|
$defecting and @depotlist = @main::DefectDepots;
|
|
$repairing and @depotlist = @main::RepairDepots;
|
|
|
|
foreach $depot (@depotlist)
|
|
{
|
|
$serverport = @$depot[0];
|
|
|
|
printf "\n\nSyncing files in depot %s.", $serverport;
|
|
|
|
$cmd = "sd.exe -p $serverport -c $main::SDClient sync";
|
|
SDX::ShowSyncProgress($cmd, 20);
|
|
}
|
|
|
|
print "\n\n";
|
|
};
|
|
}
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# RemoveProject
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub RemoveProject
|
|
{
|
|
my $fullprojectroot = $_[0];
|
|
my $serverport = $_[1];
|
|
my $proj = $_[2];
|
|
my $root = ($proj eq "root");
|
|
|
|
my $sdini = $fullprojectroot . "\\sd.ini";
|
|
|
|
print ".";
|
|
|
|
chdir $fullprojectroot or die("\nCan't cd to $fullprojectroot.\n");
|
|
|
|
#
|
|
# maybe remove everything in the project
|
|
#
|
|
$main::DefectWithPrejudice and do
|
|
{
|
|
#
|
|
# if we're in the root project, don't just blindly delnode
|
|
# figure out which dirs exist under the root and delete each of these,
|
|
# excluding the Tools dir
|
|
#
|
|
if ($root)
|
|
{
|
|
#
|
|
# delete only the subdirs of the root project, except
|
|
# for the tools dir
|
|
#
|
|
foreach $dir (@main::RemovableRootDirs)
|
|
{
|
|
my $path = $main::SDXRoot . "\\" . $dir;
|
|
|
|
(-e $path) and do
|
|
{
|
|
chdir $path or die("\nCan't cd to root subdir $path.\n");
|
|
|
|
system "del /F /S /Q /A:RHS *.* >nul 2>&1";
|
|
|
|
chdir $main::StartDir or die("\nCan't cd to start dir $main::StartDir.\n");
|
|
print ".";
|
|
system "rd /S /Q $path >nul 2>&1";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# only remove the project if it isn't the tools
|
|
#
|
|
if ($proj ne $main::ToolsProject)
|
|
{
|
|
system "del /F /S /Q /A:RHS *.* >nul 2>&1";
|
|
|
|
chdir $main::StartDir or die("\nCan't cd to start dir $main::StartDir.\n");
|
|
print ".";
|
|
system "rd /S /Q $fullprojectroot >nul 2>&1";
|
|
}
|
|
}
|
|
};
|
|
|
|
#
|
|
# lastly, remove SD.INI
|
|
#
|
|
system "attrib -R -H -S $sdini >nul 2>&1";
|
|
unlink $sdini;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetImmediateSubDirs
|
|
#
|
|
# Ask SD for the list of dirs directly below $proj
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# returns a list of subdirs
|
|
# _____________________________________________________________________________
|
|
sub GetImmediateSubDirs
|
|
{
|
|
my $proj = $_[0];
|
|
my @list = ();
|
|
my @lines = ();
|
|
my $proj2 = "";
|
|
|
|
@lines = `sd.exe dirs //depot/$main::Branch/$proj/* 2>&1`;
|
|
foreach $line (@lines)
|
|
{
|
|
if ($line =~ /no such file/)
|
|
{
|
|
@list = ();
|
|
last;
|
|
}
|
|
|
|
@fields = split(/\//,$line);
|
|
$proj2 = "\L@fields[$#fields]";
|
|
chop $proj2;
|
|
|
|
if ($main::ToolsInRoot)
|
|
{
|
|
($proj2 ne $main::ToolsPath) and push @list, $proj2;
|
|
}
|
|
else
|
|
{
|
|
($proj2 ne $main::ToolsProject) and push @list, $proj2;
|
|
}
|
|
}
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n\n\ngetimmediatesubdirs: list = '@list'\n\n\n";
|
|
};
|
|
|
|
return @list;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ToolsEtc
|
|
#
|
|
# Puts the SD/SDX tools, batch files and aliases into the enlistment
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub ToolsEtc
|
|
{
|
|
my $op = $_[0];
|
|
|
|
my $enlisting = ($op eq "enlist");
|
|
my $defecting = ($op eq "defect");
|
|
my $repairing = ($op eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in ToolsEtc().\n");
|
|
|
|
#
|
|
# if the codebase map gave us a tools project, go there and sync for the
|
|
# user, otherwise handle the tools manually
|
|
#
|
|
if ($main::ToolsProject)
|
|
{
|
|
SDX::SyncTools($op);
|
|
}
|
|
else
|
|
{
|
|
SDX::CopyTools($op);
|
|
}
|
|
|
|
#
|
|
# write or remove the script to set the SD env vars
|
|
#
|
|
SDX::WriteSDINIT($op);
|
|
|
|
#
|
|
# write or remove project navigation aliases from $main::SDMap
|
|
#
|
|
SDX::WriteAliases($op);
|
|
|
|
#
|
|
# maybe clean up files in the root
|
|
#
|
|
$defecting and $main::DefectWithPrejudice and do
|
|
{
|
|
chdir $main::SDXRoot or die("\nCan't cd to $main::SDXRoot.\n");
|
|
system "del /Q /A:-R *.* >nul 2>&1";
|
|
chdir $main::StartDir or die("\nCan't cd to start dir $main::StartDir.\n");
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# SyncTools
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub SyncTools
|
|
{
|
|
my $op = $_[0];
|
|
|
|
my $enlisting = ($op eq "enlist");
|
|
my $defecting = ($op eq "defect");
|
|
my $repairing = ($op eq "repair");
|
|
|
|
my $n = 0;
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in SyncTools().\n");
|
|
|
|
(($enlisting and $main::NewEnlist) || ($repairing and $main::Sync)) and do
|
|
{
|
|
print "\n\nPlease wait, syncing tools $main::ToolsProjectPath.";
|
|
|
|
!(-e $main::ToolsProjectPath) and system "mkdir $main::ToolsProjectPath >nul 2>&1";
|
|
chdir $main::ToolsProjectPath;
|
|
|
|
$cmd = "sd.exe sync -f $main::ToolsProjectPath\\... 2>&1";
|
|
SDX::ShowSyncProgress($cmd, 10);
|
|
|
|
#
|
|
# make sure the SD client and PERL runtimes are read-only, since SD will leave them writable
|
|
# during the sync and susceptible to a clean build cleansing with del /s
|
|
#
|
|
system "attrib +R $main::ToolsProjectPath\\$main::Platform\\perl* >nul 2>&1";
|
|
system "attrib +R $main::ToolsProjectPath\\$main::Platform\\sd.exe >nul 2>&1";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# CopyTools
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub CopyTools
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
my $tools = "sdtools";
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in CopyTools().\n");
|
|
|
|
#
|
|
# when defecting, be selective about which files we remove since most are
|
|
# in use
|
|
#
|
|
($enlisting || $repairing) and do
|
|
{
|
|
#
|
|
# if we know the codebase map, add it to the list of things
|
|
# to copy to the tools dir
|
|
#
|
|
$main::CodeBaseMapFile and push @{$main::SDXTools{toSDTools}}, $main::CodeBaseMapFile;
|
|
|
|
#
|
|
# create the local tools dir
|
|
#
|
|
$destroot = "$main::SDXRoot\\$tools";
|
|
system "mkdir $destroot >nul 2>&1";
|
|
-e $destroot or die("\nCan't create tools dir $destroot.\n");
|
|
|
|
print "\n\nCopying Source Depot tools to $destroot";
|
|
};
|
|
|
|
foreach $file (@{$main::SDXTools{toSDXRoot}})
|
|
{
|
|
$src = "$main::StartPath\\$file";
|
|
$dest = "$main::SDXRoot\\$file";
|
|
|
|
($enlisting || $repairing) and print "." and SDX::CopyFile($src, $dest);
|
|
|
|
$defecting and unlink $dest;
|
|
}
|
|
|
|
($enlisting || $repairing) and do
|
|
{
|
|
foreach $file (@{$main::SDXTools{toSDTools}})
|
|
{
|
|
print ".";
|
|
|
|
$src = "$main::StartPath\\$file";
|
|
$dest = "$main::SDXRoot\\$tools\\$file";
|
|
|
|
SDX::CopyFile($src, $dest);
|
|
}
|
|
|
|
foreach $file (@{$main::SDXTools{toSDToolsPA}})
|
|
{
|
|
print ".";
|
|
|
|
$src = "$main::StartPath\\$main::Platform\\$file";
|
|
$dest = "$main::SDXRoot\\$tools\\$file";
|
|
|
|
SDX::CopyFile($src, $dest);
|
|
}
|
|
|
|
print "\nok.\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# CopyFile
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub CopyFile
|
|
{
|
|
$#_ == 1 or die("\nNot enough arguments to CopyFile().\n");
|
|
|
|
$src = $_[0];
|
|
$dest = $_[1];
|
|
|
|
$main::V2 and do
|
|
{
|
|
printf "\ncopy /Y /V $src $dest\n";
|
|
};
|
|
|
|
system "copy /Y /V $src $dest >nul 2>&1";
|
|
-e $dest or die("\nCan't copy $src to enlistment root $dest.\n");
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteSDINIT
|
|
#
|
|
# Write the SD environment variables to a batch file for the user to run later.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteSDINIT
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in WriteSDINIT().\n");
|
|
|
|
#
|
|
# SDINIT.CMD goes in the tools dir if we have one
|
|
# otherwise to SDXROOT
|
|
#
|
|
$file = "\\sdinit.cmd";
|
|
if ($main::ToolsProject)
|
|
{
|
|
$main::SDINIT = $main::ToolsProjectPath . $file;
|
|
}
|
|
else
|
|
{
|
|
$main::SDINIT = $main::SDXRoot . $file;
|
|
}
|
|
|
|
#
|
|
# make it writable
|
|
#
|
|
system "attrib -R -H -S $main::SDINIT >nul 2>&1";
|
|
|
|
#
|
|
# maybe (re)write
|
|
#
|
|
(($enlisting and !(-e $main::SDINIT)) or $repairing) and do
|
|
{
|
|
open(SDINIT, ">$main::SDINIT") or die("\nCan't open $main::SDINIT for writing.\n");
|
|
|
|
printf SDINIT "\@if \"%%_ECHO%%\" == \"\" \@echo off\n\n";
|
|
printf SDINIT "rem\nrem SDINIT.CMD -- autogenerated by SDX\nrem\n\n";
|
|
printf SDINIT "set SDXROOT=%s\n", $main::SDXRoot;
|
|
printf SDINIT "set SDCONFIG=sd.ini\n";
|
|
printf SDINIT "if \"%%SDEDITOR%%\" == \"\" set SDEDITOR=notepad.exe\n";
|
|
printf SDINIT "if \"%%SDDIFF%%\" == \"\" set SDDIFF=windiff.exe\n\n";
|
|
|
|
#
|
|
# only change the user's path if there's no tools dir
|
|
#
|
|
!$main::ToolsProject and printf SDINIT "set PATH=\%SDXROOT\%\\sdtools;\%PATH\%\n\n";
|
|
|
|
if ($main::ToolsProject)
|
|
{
|
|
my $tools;
|
|
$tools = $main::ToolsProject . "\\" . $main::ToolsPath;
|
|
$main::ToolsInRoot and $tools = $main::ToolsPath;
|
|
|
|
printf SDINIT "if exist \%SDXROOT\%\\$tools\\%PROCESSOR_ARCHITECTURE\%\\alias.exe \%SDXROOT\%\\$tools\\%PROCESSOR_ARCHITECTURE\%\\alias -f \%SDXROOT\%\\%s\\alias.sdx -f \%SDXROOT\%\\%s\\alias.%s\n\n", $tools, $tools, $main::CodeBase;
|
|
printf SDINIT "if exist \%SDXROOT\%\\%s\sdvars.cmd call \%SDXROOT\%\\%s\sdvars.cmd\n", $tools, $tools;
|
|
}
|
|
else
|
|
{
|
|
printf SDINIT "alias -f \%SDXROOT\%\\alias.sdx -f \%SDXROOT\%\\alias.%s\n\n", $main::CodeBase;
|
|
printf SDINIT "if exist \%SDXROOT\%\\sdvars.cmd call \%SDXROOT\%\\sdvars.cmd\n";
|
|
}
|
|
|
|
close(SDINIT);
|
|
|
|
#
|
|
# make it read-only
|
|
#
|
|
system "attrib +R $main::SDINIT >nul 2>&1";
|
|
};
|
|
|
|
#
|
|
# maybe delete it
|
|
#
|
|
$defecting and unlink $main::SDINIT;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteAliases
|
|
#
|
|
# Write ALIAS.<codebase> with project-specific aliases for CD'g around the tree
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteAliases
|
|
{
|
|
my $op = $_[0];
|
|
my $enlisting = ($op eq "enlist");
|
|
my $defecting = ($op eq "defect");
|
|
my $repairing = ($op eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in WriteAliases().\n");
|
|
|
|
#
|
|
# ALIAS.<codebase> goes in the tools dir if we have one
|
|
# otherwise to SDXROOT
|
|
#
|
|
$file = "\\alias.";
|
|
if ($main::ToolsProject)
|
|
{
|
|
$main::ALIASES = $main::ToolsProjectPath . $file . $main::CodeBase;
|
|
}
|
|
else
|
|
{
|
|
$main::ALIASES = $main::SDXRoot . $file . $main::CodeBase;
|
|
}
|
|
|
|
#
|
|
# make it writable
|
|
#
|
|
system "attrib -R -H -S $main::ALIASES >nul 2>&1";
|
|
|
|
#
|
|
# maybe (re)write it
|
|
#
|
|
($enlisting || $repairing) and do
|
|
{
|
|
#
|
|
# get the list of projects and roots
|
|
# need to reread the map since it may have changed
|
|
#
|
|
if (SDX::ReadSDMap($op, $main::Null))
|
|
{
|
|
open(ALIASES, ">$main::ALIASES") or die("\nCan't open $main::ALIASES for writing.\n");
|
|
|
|
print ALIASES "\n#\n# autogenerated by SDX -- do not edit\n";
|
|
print ALIASES "#\n";
|
|
|
|
#
|
|
# for each project and root, write an alias
|
|
#
|
|
foreach $projectandroot (@main::SDMapProjects)
|
|
{
|
|
$project = @$projectandroot[0];
|
|
$project =~ tr/A-Z/a-z/;
|
|
|
|
if (!exists($main::BadAliases{$project}))
|
|
{
|
|
printf ALIASES "%-24scd /d \%SDXROOT\%\\%s\\\$1\n", @$projectandroot[0], @$projectandroot[1];
|
|
}
|
|
}
|
|
|
|
close(ALIASES);
|
|
|
|
#
|
|
# make it read-only
|
|
#
|
|
system "attrib +R $main::ALIASES >nul 2>&1";
|
|
}
|
|
};
|
|
|
|
$defecting and do
|
|
{
|
|
unlink $main::ALIASES;
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# FilesOpen
|
|
#
|
|
# Parameters:
|
|
# $serverport
|
|
#
|
|
# Output:
|
|
# returns TRUE if the client has files opened in any of the depots, FALSE
|
|
# otherwise
|
|
# _____________________________________________________________________________
|
|
sub FilesOpen
|
|
{
|
|
my $depot;
|
|
my @open = ();
|
|
|
|
print "\nChecking for open files.";
|
|
|
|
#
|
|
# look for open files in each depot
|
|
#
|
|
foreach $depot (@main::DefectDepots)
|
|
{
|
|
print ".";
|
|
|
|
my $serverport = @$depot[0];
|
|
push @open, `sd.exe -p $serverport -c $main::SDClient opened 2>&1`;
|
|
}
|
|
|
|
my @err = ();
|
|
(@err = grep(/failed/, @open)) and do
|
|
{
|
|
print "\n\nOne or more depots are unavailable:\n\n@err\n";
|
|
die("\n");
|
|
};
|
|
|
|
$main::V3 and print "open = '@open'\n";
|
|
|
|
(@open = grep(/\/\//, @open)) and print "\nok.\n";
|
|
|
|
#
|
|
# if this list has anything in it, open files were found
|
|
#
|
|
@open;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetCodeBases
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub GetCodeBases
|
|
{
|
|
$rc = system "dir /B $main::StartPath\\projects.* > $main::tmptmp 2>nul";
|
|
|
|
if ($rc / 256)
|
|
{
|
|
print "\t\t(none)\n";
|
|
}
|
|
else
|
|
{
|
|
open(CBLIST, "<$main::tmptmp") or die("\nCan't open $main::tmptmp for reading.\n");
|
|
|
|
while ($line = <CBLIST>)
|
|
{
|
|
#
|
|
# trim out noise
|
|
#
|
|
chop $line;
|
|
$line =~ tr/a-z/A-Z/;
|
|
$line =~ s/PROJECTS|CMD|INC|BAT|//g;
|
|
$line =~ s/^\.//g;
|
|
|
|
if ($line)
|
|
{
|
|
printf "\t\t %s\n", $line;
|
|
}
|
|
}
|
|
|
|
close(CBLIST);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# VerifyCBMap
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub VerifyCBMap
|
|
{
|
|
my $codebase = $_[0];
|
|
my $rc;
|
|
|
|
#
|
|
# make sure we have the codebase map file
|
|
#
|
|
$main::CodeBaseMapFile = "projects." . $codebase;
|
|
$main::CodeBaseMap = $main::StartPath . "\\" . $main::CodeBaseMapFile;
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "\nverifycbmap: codebase = '$codebase'\n";
|
|
print "verifycbmap: codebasemapfile = '$main::CodeBaseMapFile'\n";
|
|
print "verifycbmap: codebasemap = '$main::CodeBaseMap'\n";
|
|
};
|
|
|
|
return -e $main::CodeBaseMap;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# SyncOtherDirs
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# _____________________________________________________________________________
|
|
sub SyncOtherDirs
|
|
{
|
|
my $enlisting = ($_[0] eq "enlist");
|
|
my $defecting = ($_[0] eq "defect");
|
|
my $repairing = ($_[0] eq "repair");
|
|
|
|
(!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in SyncOtherDirs().\n");
|
|
|
|
(($enlisting and $main::NewEnlist) || $repairing) and do
|
|
{
|
|
foreach $path (@main::OtherDirs)
|
|
{
|
|
if ($path eq ".")
|
|
{
|
|
my $fullpath = $main::SDXRoot;
|
|
my $filespec = ($fullpath =~ /\\$/ ? "" : "\\") . "*";
|
|
$fullpath .= $filespec;
|
|
|
|
print "\n\nPlease wait, syncing $fullpath.";
|
|
|
|
chdir $fullpath;
|
|
|
|
print ".";
|
|
system "sd.exe sync -f $fullpath >nul 2>&1";
|
|
print ".\n\n";
|
|
}
|
|
else
|
|
{
|
|
my $fullpath = $main::SDXRoot . "\\" . $path;
|
|
|
|
print "\n\nSyncing $fullpath.";
|
|
|
|
chdir $fullpath;
|
|
|
|
print ".";
|
|
system "sd.exe sync -f $fullpath\\... >nul 2>&1";
|
|
print ".\n\n";
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ReadProfile
|
|
#
|
|
# reads codebase, branch and list of projects from text file
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# sets $main::ProfileCodeBase
|
|
# sets $main::ProfileBranch
|
|
# populates $main::ProfileProjects
|
|
# _____________________________________________________________________________
|
|
sub ReadProfile
|
|
{
|
|
if (-e $main::Profile)
|
|
{
|
|
open(PROFILE, "<$main::Profile") or die("\nCan't open profile $main::Profile for reading.\n");
|
|
|
|
while ($line = <PROFILE>)
|
|
{
|
|
#
|
|
# throw away comments
|
|
#
|
|
$line =~ /^#/ and next;
|
|
|
|
chop $line;
|
|
|
|
#
|
|
# get codebase name
|
|
#
|
|
if ($line =~ /^CODEBASE/)
|
|
{
|
|
@fields = split(/[\t\s]*=[\t\s]*/, $line);
|
|
$main::ProfileCodeBase = @fields[1];
|
|
$main::ProfileCodeBase =~ s/[\t\s]*//g;
|
|
}
|
|
|
|
#
|
|
# get branch to enlist
|
|
#
|
|
if ($line =~ /^BRANCH/)
|
|
{
|
|
@fields = split(/[\t\s]*=[\t\s]*/, $line);
|
|
$main::ProfileBranch = @fields[1];
|
|
$main::ProfileBranch =~ s/[\t\s]*//g;
|
|
}
|
|
|
|
#
|
|
# get any projects
|
|
#
|
|
if ($line =~ /^PROJECTS/)
|
|
{
|
|
$line =~ s/^PROJECTS[\t\s]*=[\t\s]*//g;
|
|
@main::ProfileProjects = split(/[\t\s]+/,$line);
|
|
}
|
|
}
|
|
|
|
close(PROFILE);
|
|
|
|
$main::V2 and do
|
|
{
|
|
print "\n";
|
|
printf "readprofile: codebase = '%s'\n", $main::ProfileCodeBase;
|
|
printf "readprofile: branch = '%s'\n\n", $main::ProfileBranch;
|
|
|
|
foreach $p (@main::ProfileProjects)
|
|
{
|
|
printf "readprofile: profileprojects = '%s'\n", $p;
|
|
}
|
|
};
|
|
|
|
#
|
|
# make sure we have everything
|
|
#
|
|
$main::ProfileCodeBase and $main::ProfileBranch and @main::ProfileProjects and return 1;
|
|
|
|
print "The profile\n\n\t$main::Profile\n\nis missing the ";
|
|
|
|
!$main::ProfileCodeBase and print "codebase name.\n" and return 0;
|
|
!$main::ProfileBranch and print "branch name.\n" and return 0;
|
|
!@main::ProfileProjects and print "project list.\n";
|
|
}
|
|
else
|
|
{
|
|
print "\nCan't find profile $main::Profile.\n";
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# WriteDefaultSetEnv
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub WriteDefaultSetEnv
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Backup
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Backup
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Restore
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Restore
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Type1Root
|
|
#
|
|
# Root: field for client view depends on codebase type
|
|
#
|
|
# for type 1 (1 project/depot), root includes project name
|
|
# for type 2 (N projects/depot), root is just main::SDXRoot
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# $root
|
|
# _____________________________________________________________________________
|
|
sub Type1Root
|
|
{
|
|
my $root = $_[0];
|
|
my $project;
|
|
my $proj;
|
|
my $projroot;
|
|
|
|
#
|
|
# only one project per depot
|
|
#
|
|
$project = @main::ProjectsInThisDepot[0];
|
|
$proj = @$project[$main::CBMProjectField];
|
|
$projroot = @$project[$main::CBMProjectRootField];
|
|
|
|
#
|
|
# if no project root was given in the codebase map, assume
|
|
# the root is same as the project name
|
|
#
|
|
!$projroot and $projroot = $proj;
|
|
|
|
#
|
|
# if we're not the root project, append project name
|
|
#
|
|
!($projroot eq "sdxroot") and $root .= "\\$projroot";
|
|
|
|
return $root;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# MakeUniqueClient
|
|
#
|
|
# Returns a client name unique in the depots if $main::SDClient already
|
|
# exists. Waits on a global mutex to guarantee name is unique.
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# existing $main::SDClient if it's unique
|
|
# else a unique variation of $main::SDClient
|
|
# _____________________________________________________________________________
|
|
sub MakeUniqueClient
|
|
{
|
|
my $client = $main::SDClient;
|
|
my @list = ();
|
|
|
|
print "\nPlease wait, verifying client name $main::SDClient is available";
|
|
|
|
#
|
|
# we want to know we're the only enlist process trying to generate
|
|
# a unique client name
|
|
#
|
|
$main::V3 and print "\ncreating mutex\n";
|
|
$main::Mutex = Win32::Mutex->new($main::FALSE, "SDX_ENLIST");
|
|
|
|
#
|
|
# wait til we get it
|
|
#
|
|
$main::V3 and print "waiting on mutex\n";
|
|
$main::Mutex->wait(0x7fffffff);
|
|
|
|
$main::V3 and print "got it\n";
|
|
$main::HaveMutex = $main::TRUE;
|
|
|
|
#
|
|
# build a list of clients in each depot
|
|
#
|
|
# check for access denied as we go
|
|
#
|
|
foreach $depot (@main::VerifyDepots)
|
|
{
|
|
print ".";
|
|
$serverport = @$depot[0];
|
|
$main::V3 and print "$serverport\n";
|
|
|
|
push (@list, `sd.exe -p $serverport clients 2>&1`);
|
|
|
|
SDX::AccessDenied(\@list, $serverport) and die("\n");
|
|
}
|
|
|
|
$main::V4 and print "\n\nclient list = @list\n";
|
|
|
|
#
|
|
# loop til we have a unique name
|
|
#
|
|
$num = 1;
|
|
while (grep(/Client $client /i, @list))
|
|
{
|
|
print ".";
|
|
$client = "$main::SDClient-" . $num++;
|
|
}
|
|
|
|
#
|
|
# hang onto the mutex until we've registered the first client
|
|
# using the new name -- release it in Enlist()
|
|
#
|
|
$main::V3 and print "leaving MakeUniqueClient\n";
|
|
|
|
return $client;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# VerifyCodeBaseAndBranch
|
|
#
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# returns TRUE if error and usage needed, else FALSE
|
|
# _____________________________________________________________________________
|
|
sub VerifyCodeBaseAndBranch
|
|
{
|
|
my $codebase = $_[0];
|
|
my $branch = $_[1];
|
|
my $usage = $main::FALSE;
|
|
|
|
$main::V2 and print "codebase = '$codebase'\nbranch = '$branch'\n";
|
|
|
|
#
|
|
# verify
|
|
#
|
|
($codebase eq "") and print "\nMissing codebase.\n" and $usage = $main::TRUE;
|
|
|
|
(substr($codebase,0,1) =~ /[\/-]/) and do
|
|
{
|
|
$codebase !~ /\?/ and print "\nCodebase name '$codebase' appears to be a command switch.\n";
|
|
$usage = $main::TRUE;
|
|
};
|
|
|
|
substr($codebase,0,1) =~ /@/ and print "\nCodebase name '$codebase' appears to be a client name.\n" and $usage = $main::TRUE;
|
|
|
|
($branch eq "") and print "\nMissing branch.\n" and $usage = $main::TRUE;
|
|
|
|
(substr($branch,0,1) =~ /[\/-]/) and print "\nBranch name '$branch' appears to be a command switch.\n" and $usage = $main::TRUE;
|
|
|
|
return $usage;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# AccessDenied
|
|
#
|
|
# Parameters:
|
|
# $list -- to grep for access error
|
|
# $serverport -- depot where access failed
|
|
#
|
|
# Output:
|
|
# error msg and return 1 if denied, else 0
|
|
# _____________________________________________________________________________
|
|
sub AccessDenied
|
|
{
|
|
my ($list) = $_[0];
|
|
my $serverport = $_[1];
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "accessdenied: list = '@$list'\n";
|
|
print "accessdenied: serverport = '$serverport'\n";
|
|
};
|
|
|
|
grep(/ don't have permission /, @$list) and do
|
|
{
|
|
print "\n\n\nAccess denied to depot $serverport.\n";
|
|
|
|
print "\nYour domain user account must have permission to use this depot, or belong\n";
|
|
print "to a domain group that has access. Please email INFRA for assistance.\n";
|
|
|
|
return 1;
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ShowSyncProgress
|
|
#
|
|
# Parameters:
|
|
# $cmd -- sd sync cmd to run
|
|
#
|
|
# Output:
|
|
# ...
|
|
# _____________________________________________________________________________
|
|
sub ShowSyncProgress
|
|
{
|
|
my $cmd = $_[0];
|
|
my $mod = $_[1];
|
|
|
|
open FILE, "$cmd |" or die("\nShowSyncProgress: can't open pipe for $cmd.\n");
|
|
while (<FILE>) { !(++$n % $mod) and print "."; }
|
|
close FILE;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ShowSDProgress
|
|
#
|
|
# Parameters:
|
|
# $cmd -- sd cmd to run
|
|
#
|
|
# Output:
|
|
# ...
|
|
# _____________________________________________________________________________
|
|
sub ShowSDProgress
|
|
{
|
|
my $cmd = $_[0];
|
|
my $mod = $_[1];
|
|
|
|
open FILE, "$cmd |" or die("\nShowSDProgress: can't open pipe for $cmd.\n");
|
|
while (<FILE>) { !(++$n % $mod) and print "."; }
|
|
close FILE;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# ServerPort
|
|
#
|
|
# for type 1 depots we're in a project root and will have an SD.INI
|
|
# to tell us server:port
|
|
# for type 2 depots rely on passed in $sp
|
|
#
|
|
# Parameters:
|
|
#
|
|
# cmd or codebase type
|
|
#
|
|
# Output:
|
|
# ...
|
|
# _____________________________________________________________________________
|
|
sub ServerPort
|
|
{
|
|
my $type = $_[0];
|
|
my $sp = $_[1];
|
|
|
|
return ($type == 2 ? "-p $sp" : "");
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetPublicChangeNum
|
|
#
|
|
# get the public change number from $main::SDXROOT\public\public_changenum.sd
|
|
# if there is one
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# set $main::PublicChangeNum
|
|
# _____________________________________________________________________________
|
|
sub GetPublicChangeNum
|
|
{
|
|
("\U$main::CodeBase" eq "NT") and do
|
|
{
|
|
my $pcn = "$main::SDXRoot\\public\\public_changenum.sd";
|
|
my $line = "";
|
|
|
|
if (open(FILE, "<$pcn"))
|
|
{
|
|
$line = <FILE>;
|
|
close(FILE);
|
|
|
|
#
|
|
# $line is of the form "Change XXXX created."
|
|
#
|
|
return (split(/ /, $line))[1];
|
|
}
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetDepotTypes
|
|
#
|
|
# called by OtherOp only when executing type 2 commands
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# populate %main::DepotType
|
|
# _____________________________________________________________________________
|
|
sub GetDepotTypes
|
|
{
|
|
#
|
|
# for type 2 commands read the codebase map
|
|
# and figure out the depot type
|
|
#
|
|
if (SDX::VerifyCBMap($main::CodeBase))
|
|
{
|
|
SDX::ReadCodeBaseMap();
|
|
SDX::MakePGDLists();
|
|
}
|
|
else
|
|
{
|
|
print "\n\nError: Can't find codebase map $main::CodeBaseMap.\n";
|
|
die("\nContact the SDX alias.\n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# MakeProjectRoot
|
|
#
|
|
# for type 1 projects (1 project/depot), the project name is
|
|
# included in the Root: field of the client view and must not
|
|
# be used in the RHS of the view line
|
|
#
|
|
# for type 2 projects (N projects/depot) the project can't be part
|
|
# of the root and so must be included in the RHS
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# returns
|
|
# _____________________________________________________________________________
|
|
sub MakeProjectRoot
|
|
{
|
|
my $proj = $_[0];
|
|
my $projroot = $_[1];
|
|
|
|
$main::V3 and do
|
|
{
|
|
print "makeprojectroot: proj = '$proj'\n";
|
|
print "makeprojectroot: projroot = '$projroot'\n";
|
|
print "makeprojectroot: projtype{$proj} = $main::ProjectType{$proj}\n";
|
|
};
|
|
|
|
my $pr = ($main::ProjectType{$proj} == 2 ) ? "/$projroot" : "";
|
|
|
|
$main::V3 and print "makeprojectroot: returning '$pr'\n";
|
|
|
|
return $pr;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# DepotErrors
|
|
#
|
|
# format and print the number of errors we got trying to talk to depot
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub DepotErrors
|
|
{
|
|
my ($counters) = $_[0];
|
|
my $pad = $_[1];
|
|
my $errors = $_[2];
|
|
|
|
push @$counters, sprintf "\nSD CLIENT ERRORS:%s%s\n", $pad, $errors;
|
|
};
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# Changes
|
|
#
|
|
# generate build changelist summary for Main and lab branch(es)
|
|
# process all other sdx changes commands normally
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub Changes
|
|
{
|
|
$main::V3 and do
|
|
{
|
|
print "buildnum = $main::BuildNumber\n";
|
|
print "minusb = $main::MinusB\n";
|
|
print "sdcmd = $main::SDCmd\n";
|
|
print "userargs = $main::UserArgs\n";
|
|
};
|
|
|
|
#
|
|
# if not looking for build change summary, handle sdx changes command
|
|
# normally
|
|
#
|
|
if (!$main::MinusB)
|
|
{
|
|
SDX::OtherOp($main::SDCmd, $main::UserArgs);
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# return if not NT
|
|
#
|
|
($main::CodeBase ne "NT") and do
|
|
{
|
|
print "\nsdx changes -b only supported for NT codebase.\n";
|
|
return;
|
|
};
|
|
|
|
#
|
|
# create hash of history
|
|
#
|
|
(!SDX::GetBuildHistory($main::BuildNumber)) and return;
|
|
|
|
(!$main::BuildHistory{$main::BuildNumber}{buildtype}) and do
|
|
{
|
|
print "\nCould not determine $main::BuildNumber build type from RI/integration change comments.\n";
|
|
return;
|
|
};
|
|
|
|
#
|
|
# generate the lists of changes in this build
|
|
#
|
|
$type = $main::BuildHistory{$main::BuildNumber}{buildtype};
|
|
|
|
#
|
|
# Main
|
|
#
|
|
# consists of changes from lab branch(es) and Main
|
|
#
|
|
# sdx changes -b 2271 produces
|
|
# changes.2271.main.txt
|
|
# changes.2271.lab02_n.txt
|
|
# changes.2271.lab03_n.txt
|
|
# changes.2271.lab07_n.txt
|
|
#
|
|
($type eq "MAIN") and do
|
|
{
|
|
$main::V2 and do
|
|
{
|
|
print "\n$main::BuildNumber is an RI:\n";
|
|
SDX::PrintBH(\%main::BuildHistory, $main::BuildNumber);
|
|
};
|
|
|
|
SDX::GetMainChanges($main::BuildNumber, $type);
|
|
};
|
|
|
|
#
|
|
# BETA
|
|
#
|
|
# consists of changes from the beta branch
|
|
#
|
|
# sdx changes -b 2277 produces
|
|
# changes.2277.beta1.txt
|
|
#
|
|
($type eq "BETA") and do
|
|
{
|
|
$main::V2 and do
|
|
{
|
|
print "\n$main::BuildNumber is a BETA:\n";
|
|
SDX::PrintBH(\%main::BuildHistory, $main::BuildNumber);
|
|
};
|
|
|
|
#
|
|
# for beta builds there's only one contributing branch, betaX
|
|
# use the first one in the list
|
|
#
|
|
my $branch = @{$main::BuildHistory{$main::BuildNumber}{branches}}[0];
|
|
SDX::GetBranchChanges($main::BuildNumber, $branch, $type);
|
|
};
|
|
|
|
#
|
|
# IDX
|
|
#
|
|
# consists of changes from the original RI build and the IDX branch
|
|
#
|
|
# sdx changes -b 2267 produces
|
|
# changes.2267.main.txt
|
|
# changes.2267.lab02_n.txt
|
|
# changes.2267.idx01.txt
|
|
#
|
|
($type eq "IDX") and do
|
|
{
|
|
$main::V2 and do
|
|
{
|
|
print "\n$main::BuildNumber is an IDX:\n";
|
|
SDX::PrintBH(\%main::BuildHistory, $main::BuildNumber);
|
|
};
|
|
|
|
#
|
|
# get changes from the original RI build
|
|
#
|
|
SDX::GetMainChanges($main::BuildNumber, "MAIN");
|
|
|
|
#
|
|
# get changes from the IDX build
|
|
#
|
|
# for idx builds there's only one contributing branch, idx0N
|
|
# use the first one in the list
|
|
#
|
|
my $branch = (grep {/idx/} @{$main::BuildHistory{$main::BuildNumber}{branches}})[0];
|
|
SDX::GetBranchChanges($main::BuildNumber, $branch, $type);
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetMainChanges
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetMainChanges
|
|
{
|
|
my $buildnum = $_[0];
|
|
my $type = $_[1];
|
|
|
|
my $labbranch = "";
|
|
|
|
#
|
|
# get changes that went into //depot/main for this build
|
|
#
|
|
SDX::GetBranchChanges($buildnum, "main", $type);
|
|
|
|
#
|
|
# for each lab that RI'd, get changes that went into //depot/<lab>
|
|
#
|
|
my %seen = ();
|
|
my @labbranches = sort grep {/lab/} @{$main::BuildHistory{$buildnum}{branches}};
|
|
|
|
foreach $labbranch (@labbranches)
|
|
{
|
|
$seen{$labbranch} and next;
|
|
$seen{$labbranch} = 1;
|
|
|
|
SDX::GetBranchChanges($buildnum, $labbranch, $type);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetBranchChanges
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetBranchChanges
|
|
{
|
|
my $buildnum = $_[0];
|
|
my $branch = $_[1];
|
|
my $type = $_[2];
|
|
|
|
my $project = "";
|
|
|
|
$main::Logging = $main::TRUE;
|
|
$main::Log = "$main::SDXRoot\\changes.$buildnum.$branch.txt";
|
|
unlink $main::Log;
|
|
|
|
print "\n\n\nGetting changes for $buildnum $branch...\n";
|
|
|
|
#
|
|
# get changes that went into //depot/$branch for $buildnum
|
|
#
|
|
# for each project
|
|
# get ts1, ts2
|
|
# get change list
|
|
#
|
|
foreach $proj (@main::SDMapProjects)
|
|
{
|
|
my $ts1 = "";
|
|
my $ts2 = "";
|
|
|
|
$project = "\l@$proj[0]";
|
|
my $header = "\n---------------- \U$project\n";
|
|
|
|
#
|
|
# skip this project if the user negated it on the cmd line
|
|
#
|
|
$main::UserArgs =~ /~$project / and next;
|
|
|
|
#
|
|
# get path to SD.INI, make sure we have it, and cd there
|
|
#
|
|
$fpr = $main::SDXRoot . "\\" . @$proj[1];
|
|
$sdini = $fpr . "\\sd.ini";
|
|
(-e $sdini) or (print "$header\nCan't find $sdini.\n" and next);
|
|
chdir $fpr or die("\nCan't cd to $fpr.\n");
|
|
|
|
#
|
|
# ts1, ts2 depend on build type
|
|
#
|
|
($type eq "BETA") and ($ts1, $ts2, $header) = SDX::GetBetaTimestamps($buildnum, $branch, $project, $header);
|
|
($type eq "IDX") and ($ts1, $ts2, $header) = SDX::GetIDXTimestamps($buildnum, $branch, $project, $header);
|
|
($type eq "MAIN") and ($ts1, $ts2, $header) = SDX::GetMainTimestamps($buildnum, $branch, $project, $header);
|
|
|
|
$ts1 = "\@$ts1";
|
|
$ts2 = ($type eq "IDX" and $ts2 eq "CURRENT") ? "" : "\@$ts2";
|
|
|
|
#
|
|
# list changes
|
|
#
|
|
my $spec = "//depot/$branch/$project/...$ts1,$ts2";
|
|
my $cmd = "sd.exe changes $spec 2>&1";
|
|
$header .= "Getting changes for $spec\n\n";
|
|
SDX::RunSDCmd($header, $cmd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetMainTimestamps
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetMainTimestamps
|
|
{
|
|
my $buildnum = $_[0];
|
|
my $branch = $_[1];
|
|
my $project = $_[2];
|
|
my $header = $_[3];
|
|
|
|
my %bh = %main::BuildHistory;
|
|
my @ts = (); my $ts1 = ""; my $ts2 = ""; my $op = "";
|
|
|
|
=begin comment text
|
|
|
|
to trace integration records:
|
|
|
|
build contrib
|
|
build type op branch branch project change/timestamp
|
|
----- ---- --- ------ ------- ---------- -------------------------
|
|
2268 MAIN RI main lab07_n admin 15654 2000/09/08:17:00:04
|
|
2268 MAIN RI main lab07_n base 10928 2000/09/08:17:00:21
|
|
2268 MAIN RI main lab07_n com 1755 2000/09/08:17:00:29
|
|
2268 MAIN RI main lab07_n ds 4124 2000/09/08:17:00:54
|
|
2268 MAIN RI main lab07_n enduser 19639 2000/09/08:17:00:59
|
|
2268 MAIN RI main lab07_n inetsrv 1503 2000/09/08:17:01:23
|
|
2268 MAIN RI main lab07_n root 25483 2000/09/08:17:02:06
|
|
|
|
in Admin
|
|
sd describe -s 15654
|
|
for each file in the RI
|
|
sd changes //depot/lab07_n/admin/path/to/file.ext@ts1,@ts2
|
|
throw away data prior to ts1
|
|
push "change" lines ont list
|
|
sort, unique
|
|
print
|
|
|
|
[\\JEFFMCD5 E:\nt\admin] sd describe -s 15654 | qgrep -e integrate | awk "{print \"sd changes \"$2\"@2000/08/0
|
|
3:17:15:40,@2000/09/08:17:00:04\"}" | sed "s/#[0-9]+//g" | sed "s/\/main\//\/lab07_n\//g" | cmd.exe >>15654
|
|
|
|
[\\JEFFMCD5 E:\nt\admin] g Change 15654 | unique | sort /R
|
|
|
|
=end comment text
|
|
=cut
|
|
|
|
#
|
|
# main branch timestamps
|
|
#
|
|
($branch eq "main") and do
|
|
{
|
|
#
|
|
# ts1 =
|
|
#
|
|
# time of most recent event in Main (RI checkin, or integration to IDX/Beta branch)
|
|
# for the build prior to the build in question
|
|
# in //depot/main/$project
|
|
# for all branches that contributed
|
|
#
|
|
# if no data for $project, default to Root
|
|
#
|
|
my $build = $buildnum - 1;
|
|
my $p = $project;
|
|
|
|
($ts1, $op) = SDX::GetMainTS1($build, $p);
|
|
(!$ts1) and do
|
|
{
|
|
$p = "root";
|
|
($ts1, $op) = SDX::GetMainTS1($build, $p);
|
|
};
|
|
|
|
$main::V2 and $header .= "ts1 = $build $branch $p $op = $ts1\n";
|
|
|
|
#
|
|
# ts2 =
|
|
#
|
|
# time of event in Main (initial RI checkin if RI/IDX, or initial integration if BETA)
|
|
# for the build following the build in question
|
|
# in //depot/main/$project
|
|
# for all branches that contributed
|
|
# less five minutes
|
|
# OR
|
|
#
|
|
# time of final RI checkin
|
|
# for the build in question
|
|
# for all branches that contributed
|
|
#
|
|
# if no data for $project, default to Root
|
|
#
|
|
@ts = ();
|
|
$build = $buildnum + 1;
|
|
$p = $project;
|
|
|
|
($ts2, $op) = SDX::GetMainTS2($build, $p);
|
|
(!$ts2) and do
|
|
{
|
|
$p = "root";
|
|
($ts2, $op) = SDX::GetMainTS2($build, $p);
|
|
};
|
|
|
|
#
|
|
# subtract 5 minutes if not using current build
|
|
#
|
|
($build != $buildnum) and $ts2 = SDX::IncrDecrTS($ts2, 0, -5, 0);
|
|
|
|
$main::V2 and $header .= "ts2 = $build $branch $p $op = $ts2\n";
|
|
};
|
|
|
|
#
|
|
# lab branch timestamps
|
|
#
|
|
($branch =~ /lab/) and do
|
|
{
|
|
my @builds = sort keys %bh; my $first = @builds[0];
|
|
my $p = $project;
|
|
|
|
#
|
|
# ts1 = time of last RI checkin of this VBL into Main
|
|
#
|
|
# default to current build Root RI time, less 10 min, if no data
|
|
#
|
|
for ($prev = $buildnum - 1; $prev > $first; $prev--)
|
|
{
|
|
(exists($bh{$prev}{main}{$branch}{$p})) and do
|
|
{
|
|
push @ts, $bh{$prev}{main}{$branch}{$p}[1];
|
|
last;
|
|
};
|
|
}
|
|
|
|
@ts = reverse sort @ts;
|
|
@ts and $ts1 = @ts[0];
|
|
|
|
(!$ts1) and do
|
|
{
|
|
$p = "root"; $prev = $buildnum;
|
|
@ts = @{$bh{$buildnum}{main}{$branch}{$p}};
|
|
$ts1 = @ts[$#ts];
|
|
$ts1 = SDX::IncrDecrTS($ts1, 0, -10, 0);
|
|
};
|
|
|
|
$main::V2 and $header .= "ts1 = $prev $branch $p RI = $ts1\n";
|
|
|
|
#
|
|
# ts2 = time of final RI checkin for this VBL into Main
|
|
#
|
|
# default to Root if no data for this project
|
|
#
|
|
$p = $project;
|
|
@ts = @{$bh{$buildnum}{main}{$branch}{$p}};
|
|
$ts2 = @ts[$#ts];
|
|
|
|
(!$ts2) and do
|
|
{
|
|
$p = "root";
|
|
@ts = @{$bh{$buildnum}{main}{$branch}{$p}};
|
|
$ts2 = @ts[$#ts];
|
|
};
|
|
|
|
$main::V2 and $header .= "ts2 = $buildnum $branch $p RI = $ts2\n";
|
|
};
|
|
|
|
(!$main::V2 and !($ts1 and $ts2)) and do
|
|
{
|
|
my $ts = !$ts1 ? "ts1" : "ts2";
|
|
die("\n\nGetMainTimestamps: missing $ts for $buildnum $branch $project.\n");
|
|
};
|
|
|
|
return ($ts1, $ts2, $header);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetMainTS1
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetMainTS1
|
|
{
|
|
my $build = $_[0];
|
|
my $project = $_[1];
|
|
|
|
my %bh = %main::BuildHistory;
|
|
my $bt = ""; my $op = ""; my @ts = ();
|
|
|
|
#
|
|
# return if no data for this build
|
|
#
|
|
(!($bt = $bh{$build}{buildtype})) and return "";
|
|
|
|
($bt eq "MAIN") and do
|
|
{
|
|
my @labbranches = grep {/lab/} keys %main::AllBranches;
|
|
|
|
$op = "RI";
|
|
foreach (@labbranches) { (exists($bh{$build}{main}{$_}{$project})) and push @ts, $bh{$build}{main}{$_}{$project}[1]; }
|
|
};
|
|
|
|
($bt eq "BETA") and do
|
|
{
|
|
my @betabranches = grep {/beta/} keys %main::AllBranches;
|
|
|
|
$op = "INT";
|
|
foreach (@betabranches) { (exists($bh{$build}{$_}{$_}{$project})) and push @ts, $bh{$build}{$_}{$_}{$project}[1]; }
|
|
};
|
|
|
|
($bt eq "IDX") and do
|
|
{
|
|
my @idxbranches = grep {/idx/} keys %main::AllBranches;
|
|
|
|
$op = "INT";
|
|
foreach (@idxbranches) { (exists($bh{$build}{$_}{$_}{$project})) and push @ts, $bh{$build}{$_}{$_}{$project}[1]; }
|
|
};
|
|
|
|
#
|
|
# sort and reverse so final timestamp is first
|
|
#
|
|
@ts = reverse sort @ts;
|
|
|
|
return (@ts[0], $op);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetMainTS2
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetMainTS2
|
|
{
|
|
my $build = $_[0];
|
|
my $project = $_[1];
|
|
|
|
my %bh = %main::BuildHistory;
|
|
my $bt = ""; my $op = ""; my @ts = ();
|
|
|
|
#
|
|
# return if no data for this build
|
|
#
|
|
(!($bt = $bh{$build}{buildtype})) and return "";
|
|
|
|
#
|
|
# in the case of MAIN or IDX, we want the time of the blueline build
|
|
#
|
|
($bt eq "MAIN" or $bt eq "IDX") and do
|
|
{
|
|
my @labbranches = grep {/lab/} keys %main::AllBranches;
|
|
|
|
$op = "RI";
|
|
foreach (@labbranches) { (exists($bh{$build}{main}{$_}{$project})) and push @ts, $bh{$build}{main}{$_}{$project}[$#{$bh{$build}{main}{$_}{$project}}]; }
|
|
};
|
|
|
|
($bt eq "BETA") and do
|
|
{
|
|
my @betabranches = grep {/beta/} keys %main::AllBranches;
|
|
|
|
$op = "INT";
|
|
foreach (@betabranches) { (exists($bh{$build}{$_}{$_}{$project})) and push @ts, $bh{$build}{$_}{$_}{$project}[$#{$bh{$build}{$_}{$_}{$project}}]; }
|
|
};
|
|
|
|
#
|
|
# sort so the initial timestamp is first
|
|
# and return it
|
|
#
|
|
@ts = sort @ts;
|
|
|
|
return (@ts[0], $op);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetBetaTimestamps
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetBetaTimestamps
|
|
{
|
|
my $buildnum = $_[0];
|
|
my $branch = $_[1];
|
|
my $project = $_[2];
|
|
my $header = $_[3];
|
|
my %bh = %main::BuildHistory;
|
|
|
|
#
|
|
# ts1 = time of the most recent Beta build's RI to Main for this project
|
|
#
|
|
# OR
|
|
# earliest time of last full integration from Main to this branch for this project
|
|
#
|
|
my $ts1 = ""; my @ts = ();
|
|
my $prev = $buildnum - 1;
|
|
my @builds = sort keys %bh; my $first = @builds[0];
|
|
|
|
#
|
|
# look for the last build in which this project RI'd to Main
|
|
#
|
|
for ($prev = $buildnum - 1; $prev > $first; $prev--)
|
|
{
|
|
if (@ts = @{$bh{$prev}{main}{$branch}{$project}})
|
|
{
|
|
$ts1 = @ts[1];
|
|
$main::V2 and $header .= "ts1 = $prev $branch $project RI = $ts1\n";
|
|
last;
|
|
}
|
|
}
|
|
|
|
#
|
|
# otherwise find the last full integration from Main for this project
|
|
#
|
|
(!$ts1) and do
|
|
{
|
|
for ($prev = $buildnum; $prev > $first; $prev--)
|
|
{
|
|
if (@ts = @{$bh{$prev}{$branch}{$branch}{$project}})
|
|
{
|
|
$ts1 = @ts[$#ts];
|
|
$main::V2 and $header .= "ts1 = $prev $branch $project INT = $ts1\n";
|
|
last;
|
|
}
|
|
}
|
|
};
|
|
|
|
#
|
|
# ts2 = time of the final RI to Main of the build in question
|
|
#
|
|
# OR
|
|
# if no timestamp for this project, use Root's, it's close enough
|
|
#
|
|
my $p = $project;
|
|
@ts = @{$bh{$buildnum}{main}{$branch}{$project}};
|
|
my $ts2 = @ts[$#ts];
|
|
|
|
!$ts2 and do
|
|
{
|
|
$p = "root";
|
|
@ts = @{$bh{$buildnum}{main}{$branch}{$p}};
|
|
$ts2 = @ts[$#ts];
|
|
};
|
|
|
|
$main::V2 and $header .= "ts2 = $buildnum $branch $p RI = $ts2\n";
|
|
|
|
(!$main::V2 and !($ts1 and $ts2)) and do
|
|
{
|
|
my $ts = !$ts1 ? "ts1" : "ts2";
|
|
die("\n\nGetBetaTimestamps: missing $ts for $buildnum $branch $project.\n");
|
|
};
|
|
|
|
return ($ts1, $ts2, $header);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetIDXTimestamps
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetIDXTimestamps
|
|
{
|
|
my $buildnum = $_[0];
|
|
my $branch = $_[1];
|
|
my $project = $_[2];
|
|
my $header = $_[3];
|
|
|
|
my %bh = %main::BuildHistory;
|
|
my $prev; my $next;
|
|
my @ts = (); my $ts1 = ""; my $ts2 = "";
|
|
my @builds = sort keys %bh; my $first = @builds[0]; my $last = @builds[$#builds];
|
|
|
|
#
|
|
# ts1 = time of most recent INT from Main
|
|
# to this IDX branch
|
|
# for $project
|
|
# OR
|
|
# default to current build Root integration
|
|
#
|
|
my $p = $project;
|
|
for ($prev = $buildnum; $prev >= $first; $prev--)
|
|
{
|
|
if (@ts = @{$bh{$prev}{$branch}{$branch}{$p}})
|
|
{
|
|
$ts1 = @ts[1];
|
|
last;
|
|
}
|
|
}
|
|
|
|
(!$ts1) and do
|
|
{
|
|
$prev = $buildnum;
|
|
$p = "root";
|
|
$ts1 = @{$bh{$buildnum}{$branch}{$branch}{$p}}[1];
|
|
};
|
|
|
|
$main::V2 and $header .= "ts1 = $prev $branch $p INT = $ts1\n";
|
|
|
|
#
|
|
# ts2 = time of next full integration
|
|
# to this IDX branch
|
|
# for $project
|
|
# less 5 min,
|
|
# OR
|
|
# default to current state if no integration found
|
|
#
|
|
for ($next = $buildnum + 1; $next <= $last; $next++)
|
|
{
|
|
if (@ts = @{$bh{$next}{$branch}{$branch}{$project}})
|
|
{
|
|
$ts2 = @ts[1];
|
|
last;
|
|
}
|
|
}
|
|
|
|
if ($ts2)
|
|
{
|
|
$ts2 = SDX::IncrDecrTS($ts2, 0, -5, 0);
|
|
}
|
|
else
|
|
{
|
|
$next = $buildnum;
|
|
$ts2 = "CURRENT";
|
|
}
|
|
|
|
$main::V2 and $header .= "ts2 = $next $branch $project INT = $ts2\n";
|
|
|
|
#
|
|
# verify and return
|
|
#
|
|
(!$main::V2 and !($ts1 and $ts2)) and do
|
|
{
|
|
my $ts = !$ts1 ? "ts1" : "ts2";
|
|
die("\n\nGetIDXTimestamps: missing $ts for $buildnum $branch $project.\n");
|
|
};
|
|
|
|
return ($ts1, $ts2, $header);
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# IncrDecrTS
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub IncrDecrTS
|
|
{
|
|
use Time::Local;
|
|
|
|
my ($ts, $dhour, $dmin, $dsec) = (@_);
|
|
|
|
(!$ts) and die("\nIncrDecrTS: null timestamp. Probably missing some build history.\n");
|
|
|
|
#
|
|
# convert delta h/m/s to seconds
|
|
#
|
|
$dhour *= 3600;
|
|
$dmin *= 60;
|
|
|
|
#
|
|
# split $ts and convert to Epoch seconds
|
|
#
|
|
my ($year, $month, $day, $hour, $min, $sec) = split(/[:\/]/, $ts);;
|
|
$month--;
|
|
my $epoch = timelocal($sec, $min, $hour, $day, $month, $year);
|
|
|
|
#
|
|
# add/sub to Epoch seconds
|
|
#
|
|
$epoch += $dhour + $dmin + $dsec;
|
|
|
|
#
|
|
# convert Epoch seconds to y/m/d/h/m/s
|
|
#
|
|
($sec, $min, $hour, $day, $month, $year, $wday, $yday, $isdst) = localtime($epoch);
|
|
$year += 1900;
|
|
$month++;
|
|
# print "$year, $month, $day, $hour, $min, $sec [$wday, $yday, $isdst]\n";
|
|
|
|
#
|
|
# join into new $ts
|
|
#
|
|
$ts = "$year/$month/$day:$hour:$min:$sec";
|
|
|
|
return $ts;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetBuildHistory
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
#
|
|
# A hash table and indices. Here's the output for sdx changes -b 2271
|
|
# for Root:
|
|
#
|
|
# build contrib
|
|
# build type op branch branch project change/timestamp
|
|
# ----- ---- --- ------ ------- ---------- -------------------------
|
|
# 2255 MAIN RI main lab06_n root 21432 2000/07/31:16:26:53
|
|
# 2256 MAIN RI main lab07_n root 21857 2000/08/03:17:16:27
|
|
# 2257 MAIN RI main lab01_n root 22110 2000/08/07:19:35:50 22108 2000/08/07:19:24:09
|
|
# 2258 MAIN RI main lab02_n root 22392 2000/08/09:22:36:41
|
|
# 2259 MAIN RI main lab04_n root 22581 2000/08/11:14:05:28
|
|
# 2260 MAIN RI main lab06_n root 22889 2000/08/15:16:27:53
|
|
# 2261 MAIN RI main lab03_n root 23320 2000/08/18:15:01:08
|
|
# 2262 MAIN RI main lab02_n root 23634 2000/08/22:20:57:20
|
|
# 2263 MAIN RI main lab06_n root 23779 2000/08/23:20:47:21 23778 2000/08/23:20:23:14
|
|
# 2264 IDX INT idx02 idx02 root 24368 2000/08/29:12:14:53
|
|
# 2264 IDX RI main lab01_n root 24060 2000/08/25:21:32:19
|
|
# 2265 MAIN RI main lab04_n root 24730 2000/08/31:15:05:24
|
|
# 2266 MAIN RI main lab03_n root 24901 2000/09/01:17:02:46
|
|
# 2267 IDX INT idx01 idx01 root 25433 2000/09/08:12:22:27
|
|
# 2267 IDX RI main lab02_n root 25230 2000/09/06:21:36:33
|
|
# 2268 MAIN RI main lab07_n root 25483 2000/09/08:17:02:06
|
|
# 2269 MAIN RI main lab01_n root 25714 2000/09/11:21:05:15 25710 2000/09/11:20:31:44
|
|
# 2269 MAIN RI main lab04_n root 25714 2000/09/11:21:05:15 25710 2000/09/11:20:31:44
|
|
# 2270 MAIN RI main lab06_n root 26211 2000/09/16:13:43:41
|
|
# 2271 MAIN RI main lab02_n root 26594 2000/09/19:20:21:00
|
|
# 2271 MAIN RI main lab03_n root 26602 2000/09/19:20:54:23
|
|
# 2271 MAIN RI main lab07_n root 26585 2000/09/19:19:45:39 26583 2000/09/19:19:42:38
|
|
# 2272 MAIN RI main lab01_n root 26732 2000/09/20:19:19:54
|
|
# 2272 MAIN RI main lab04_n root 26739 2000/09/20:21:05:27
|
|
# 2273 BETA INT beta1 beta1 root 26744 2000/09/20:22:15:52 26744 2000/09/20:22:15:52 26717 2000/09/20:16:59:39
|
|
# 2273 BETA RI main beta1 root 27091 2000/09/23:18:32:20
|
|
# 2274 BETA RI main beta1 root 27255 2000/09/25:22:46:33
|
|
# 2275 BETA RI main beta1 root 27365 2000/09/26:18:03:00
|
|
# 2276 BETA RI main beta1 root 27524 2000/09/27:17:25:33
|
|
# 2277 BETA RI main beta1 root 27641 2000/09/28:16:54:01
|
|
# 2278 BETA RI main beta1 root 27784 2000/09/29:17:25:06
|
|
# 2280 BETA RI main beta1 root 28077 2000/10/03:16:18:28 28027 2000/10/03:12:02:17 27960 2000/10/02:21:24:52 27952 2000/10/02:19:35:15
|
|
# 2281 BETA RI main beta1 root 28112 2000/10/03:17:17:41 28109 2000/10/03:17:16:26 28107 2000/10/03:17:12:09
|
|
# _____________________________________________________________________________
|
|
sub GetBuildHistory
|
|
{
|
|
my $buildnum = $_[0];
|
|
my %bh = ();
|
|
my %br = ();
|
|
my $sdchanges = "sd.exe changes -m 500";
|
|
$main::BuildBranches = ();
|
|
$main::AllBranches = ();
|
|
|
|
#
|
|
# do a quick check in Main for RI/Int'n changes and bail
|
|
# if no data for this build
|
|
#
|
|
chdir $main::SDXRoot;
|
|
(!(grep {/ $main::BuildNumber /} grep {/'(RI|INT)[:]*/} `$sdchanges //depot/main/...`)) and do
|
|
{
|
|
print "\nNo build history for $main::BuildNumber found in RI/integration change comments.\n";
|
|
return 0;
|
|
};
|
|
|
|
print "\nGetting build history...";
|
|
foreach $proj (@main::SDMapProjects)
|
|
{
|
|
my $project = "\l@$proj[0]";
|
|
my $header = "\n---------------- \U$project\n";
|
|
|
|
#
|
|
# skip this project if the user negated it on the cmd line
|
|
#
|
|
$main::UserArgs =~ /~$project / and next;
|
|
|
|
#
|
|
# get path to SD.INI, make sure we have it, and cd there
|
|
#
|
|
$fpr = $main::SDXRoot . "\\" . @$proj[1];
|
|
$sdini = $fpr . "\\sd.ini";
|
|
(-e $sdini) or (print "$header\nCan't find $sdini.\n" and next);
|
|
chdir $fpr or die("\nCan't cd to $fpr.\n");
|
|
|
|
$main::V3 and print $header;
|
|
print "\n $project";
|
|
|
|
=begin comment text
|
|
|
|
# use this to fix change comments missing ri/i records:
|
|
|
|
my @main = grep {/$main::BuildNumber/i} `$sdchanges //depot/main/$project/...`;
|
|
foreach (@main)
|
|
{
|
|
$ch = (split(/ /, $_))[1];
|
|
print "\n$ch: $_";
|
|
system "sd.exe change -f $ch";
|
|
}
|
|
next;
|
|
|
|
=end comment text
|
|
=cut
|
|
|
|
#
|
|
# cast back in the major branches for integration/RI changes
|
|
#
|
|
# BUGBUG: change this to get last 500 ** from @1,@<timestamp of $main::BuildNumber> **
|
|
#
|
|
my @main = grep {/'RI[:]*/i} `$sdchanges //depot/main/$project/...`; print ".";
|
|
my @idx01 = grep {/'INT[:]*/i} `$sdchanges //depot/idx01/$project/...`; print ".";
|
|
my @idx02 = grep {/'INT[:]*/i} `$sdchanges //depot/idx02/$project/...`; print ".";
|
|
my @beta1 = grep {/'INT[:]*/i} `$sdchanges //depot/beta1/$project/...`; print ".";
|
|
|
|
#
|
|
# hash of pointers to changelist arrays
|
|
#
|
|
%main::BuildBranches = (main => \@main, idx01 => \@idx01, idx02 => \@idx02, beta1 => \@beta1, beta2 => \@beta2);
|
|
|
|
#
|
|
# populate the hash
|
|
#
|
|
# for each build branch
|
|
# for each change
|
|
# extract change number and timestamp
|
|
# extract build number
|
|
# extract branch(es)
|
|
# for each contributing lab branch
|
|
# store change number, timestamp
|
|
# also store branch names seen
|
|
# also keep track of branches affecting the build in question
|
|
#
|
|
while ($bb = each %main::BuildBranches)
|
|
{
|
|
# print ".";
|
|
|
|
foreach (@{$main::BuildBranches{$bb}})
|
|
{
|
|
$main::V3 and print "$_";
|
|
|
|
my @f = split(/ /,$_);
|
|
$change = @f[1];
|
|
$ts = "@f[3]:@f[4]";
|
|
|
|
#
|
|
# munge the comment field to get build # and branch(es) involved
|
|
#
|
|
@f = split(/'/,$_); @f = split(/ /, @f[1]);
|
|
my @bn = grep {/[0-9][0-9[0-9][0-9][,;:-]*$/} @f; $bn = @bn[0]; $bn =~ s/[,;:-]//g;
|
|
#
|
|
#$bn =~ /^(22[78][0-9]|2269)/ and next;
|
|
#print "bn = '$bn'\n";
|
|
#
|
|
# for each branch in the comment, save this changenum/ts
|
|
#
|
|
@branches = grep {/(lab|idx|beta)/i} @f;
|
|
foreach $br (@branches)
|
|
{
|
|
#
|
|
# always lowercase, and lab branches
|
|
# must end in _n
|
|
#
|
|
$br = "\l$br";
|
|
($br =~ /lab/) and do { $br =~ s/_n//g; $br .= "_n"; };
|
|
$main::V3 and print " $bn, $bb, $br, $project = ($change $ts)\n";
|
|
push @{$bh{$bn}{$bb}{$br}{$project}}, ($change,$ts);
|
|
|
|
# store branch name
|
|
$main::AllBranches{"\l$br"} = 1;
|
|
|
|
push @{$bh{$bn}{branches}}, $br;
|
|
}
|
|
}
|
|
|
|
$main::V3 and print "\n";
|
|
}
|
|
|
|
}
|
|
|
|
print "\n\n";
|
|
|
|
#
|
|
# figure out build types
|
|
#
|
|
foreach $bn (sort keys %bh)
|
|
{
|
|
my @btb = @{$bh{$bn}{branches}};
|
|
|
|
(grep {/lab/} @btb) and $bh{$bn}{buildtype} = "MAIN";
|
|
(grep {/beta/} @btb) and $bh{$bn}{buildtype} = "BETA";
|
|
(grep {/idx/} @btb) and $bh{$bn}{buildtype} = "IDX";
|
|
}
|
|
|
|
($main::V2) and do
|
|
{
|
|
SDX::PrintBH(\%bh, 0);
|
|
|
|
print "\n all build branches: "; foreach $br (sort keys %main::BuildBranches) { print "'$br' "; }
|
|
print "\n all lab branches: "; foreach $br (sort keys %main::AllBranches) { print "'$br' "; }
|
|
print "\n $buildnum type = '$bh{$buildnum}{buildtype}'\n";
|
|
};
|
|
|
|
%main::BuildHistory = %bh;
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# PrintBH
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub PrintBH
|
|
{
|
|
my ($bh, $buildnum) = @_;
|
|
|
|
print "\n";
|
|
|
|
#
|
|
# if we have a specific build number, print just its data
|
|
# else print the entire history
|
|
#
|
|
my $op = "";
|
|
my @bh2 = ();
|
|
my @builds = $buildnum ? ("$buildnum") : sort keys %$bh;
|
|
my @buildbranches = sort keys %main::BuildBranches;
|
|
my @allbranches = sort keys %main::AllBranches;
|
|
|
|
foreach $bn (@builds)
|
|
{
|
|
foreach $bb (@buildbranches)
|
|
{
|
|
foreach $br (@allbranches)
|
|
{
|
|
foreach (@main::SDMapProjects)
|
|
{
|
|
my $p = @$_[0];
|
|
|
|
$op = $bb eq "main" ? "RI" : "INT";
|
|
(exists($$bh{$bn}{$bb}{$br}{$p})) and push @bh2, sprintf " %-5s %-4s %-3s %-6s %-7s %-10s @{$$bh{$bn}{$bb}{$br}{$p}}\n", $bn, $$bh{$bn}{buildtype}, $op, $bb, $br, $p;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print " build contrib\n";
|
|
print " build type op branch branch project change/timestamp\n";
|
|
print " ----- ---- --- ------ ------- ---------- -------------------------\n";
|
|
|
|
@bh2 = sort @bh2;
|
|
foreach (@bh2) { print "$_"; }
|
|
|
|
print "\n\n";
|
|
}
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# GetActiveBranches
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub GetActiveBranches
|
|
{
|
|
=begin comment text
|
|
[\\JEFFMCD5 E:\nt] sd files //depot/*/root/* | qgrep -v -e delete -e /main | sed "s/\// /g" | awk "{print $2}"
|
|
| sort | unique
|
|
beta1
|
|
idx01
|
|
idx02
|
|
Lab01_N
|
|
lab01_n-vc
|
|
Lab01_N+1
|
|
Lab02_N
|
|
Lab02_N+1
|
|
Lab03_N
|
|
Lab03_N+1
|
|
Lab04_N
|
|
Lab04_N+1
|
|
Lab06_N
|
|
Lab06_N+1
|
|
Lab07_N
|
|
Lab07_N+1
|
|
Lab21_N
|
|
=end comment text
|
|
=cut
|
|
}
|
|
|
|
|
|
|
|
|
|
# _____________________________________________________________________________
|
|
#
|
|
# VerifySubmitComment
|
|
#
|
|
# Parameters:
|
|
#
|
|
# Output:
|
|
# _____________________________________________________________________________
|
|
sub VerifySubmitComment
|
|
{
|
|
#
|
|
# if user is RI'g or integrating, standardize comment
|
|
# RI: <lab(s)> <buildnum> <user-text>
|
|
# INT: <lab(s)> <buildnum> <user-text>
|
|
#
|
|
($main::MinusR or $main::MinusT) and do
|
|
{
|
|
my $sc = $main::SubmitComment; $sc =~ s/\+/PLUS/g;
|
|
my @f = split(/ /, $sc);
|
|
|
|
# RI:/INT:
|
|
my $op = $main::MinusR ? "RI:" : "INT:";
|
|
|
|
# branch(es)
|
|
my @branches = grep {/(lab|idx|beta)/i} @f;
|
|
if (!@branches)
|
|
{
|
|
print "\nMissing branch.\n";
|
|
print "\nSubmit comment must include the branch(es) being (reverse) integrated. Valid\n";
|
|
print "branch names are beta1, idx01, idx02, lab01_n, lab07_n+1, etc.\n";
|
|
die("\n");
|
|
}
|
|
else
|
|
{
|
|
#
|
|
# strip out redundant branch names
|
|
#
|
|
my %uniq = ();
|
|
foreach (@branches) { $uniq{$_} = 1; }
|
|
@branches = sort keys %uniq;
|
|
|
|
#
|
|
# strip name from original comment, avoid duplicates
|
|
#
|
|
foreach (@branches) { $sc =~ s/$_//g; }
|
|
|
|
#
|
|
# for bare lab branches, add _n
|
|
#
|
|
foreach (@branches) { ($_ =~ /lab[0-9][0-9]$/) and $_ .= "_n"; }
|
|
|
|
$branches = join ' ', @branches;
|
|
}
|
|
|
|
# build number
|
|
@bn = grep {/[0-9][0-9][0-9][0-9][,:;-]*/} @f; my $bn = @bn[0]; $bn =~ s/[,:;-]*//g;
|
|
if (!$bn)
|
|
{
|
|
print "\nMissing build number.\n";
|
|
print "\nSubmit comment must include the build number being (reverse) integrated.\n";
|
|
die("\n");
|
|
}
|
|
else
|
|
{
|
|
# strip buildnum from original comment
|
|
$sc =~ s/$bn//g;
|
|
}
|
|
|
|
$sc = "$op $branches $bn $sc";
|
|
$sc =~ s/PLUS/\+/g; $sc =~ s/[\t\s]+/ /g;
|
|
$main::SubmitComment = $sc;
|
|
|
|
$main::V2 and print "comment = '$main::SubmitComment'\n";
|
|
};
|
|
}
|
|
|
|
|
|
|
|
#
|
|
# if we get here, something's wrong
|
|
#
|
|
1;
|
|
|
|
|