windows-nt/Source/XPSP1/NT/tools/sdx.pm
2020-09-26 16:20:57 +08:00

10714 lines
298 KiB
Perl

# _____________________________________________________________________________
#
# 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,},
diff => {fn => \&OtherOp, defcmd => "diff", 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, $_[$ArgCounter];
# }
}
}
}
};
#
# if incrementally defecting, arg is project to defect from
#
($main::Defecting and !$main::DefectAll) and do
{
push @main::SomeProjects, $_[$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"
)
{
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;
$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
#
if ("\U$main::CodeBase" eq "NT")
{
$project = @main::ProjectsInThisDepot[0];
$clobber = ("\L@$project[$main::CBMProjectField]" eq "root");
}
#
# 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 nocrlf locked nomodtime\n\n", $clobber ? "" : "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"
) 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;