# _____________________________________________________________________________ # # Purpose: # PERL Module to handle common tasks for SDX # # Parameters: # Specific to subroutine # # Output: # Specific to subroutine # # _____________________________________________________________________________ # # Some Global Definitions # $TRUE = 1; $FALSE = 0; $Callee = ""; package SDX; require Win32::Mutex; # _____________________________________________________________________________ # # Init # # Parameters: # Command Line Arguments # # Output: # _____________________________________________________________________________ sub Init { # # Initialize globals # $main::Initializing = $main::TRUE; $main::CreatingBranch= $main::FALSE; $main::tmptmp = "$ENV{TMP}\\tmp"; $main::Platform = $ENV{PROCESSOR_ARCHITECTURE}; $main::StartPath = $ENV{STARTPATH}; $main::CodeBaseType = 0; # 1 == one project/depot, 2 == N projects/depot $main::Null = ""; @main::ActiveDepots = (); %main::DepotType = (); @main::SDMapProjects = (); @main::SDMapDepots = (); @main::AllMappings = (); @main::AllProjects = (); @main::AllGroups = (); @main::AllDepots = (); @main::FileChunks = (); $main::DepotFiles = 0; $main::SDMapClient = ""; $main::SDMapBranch = ""; $main::SDMapCodeBase = ""; $main::SDMapCodeBaseType = ""; $main::Log = ""; $main::SDWeb = "http://sourcedepot"; $main::Files = 0; $main::FilesResolved = 0; $main::FilesUpdated = 0; $main::FilesAdded = 0; $main::FilesDeleted = 0; $main::FilesToResolve = 0; $main::FilesToMerge = 0; $main::FilesNotClobbered = 0; $main::FilesOpenAdd = 0; $main::FilesOpenEdit = 0; $main::FilesOpenDelete = 0; $main::FilesReverted = 0; $main::FilesNotConflicting = 0; $main::FilesSkipped = 0; $main::FilesConflicting = 0; @main::ConflictingFiles = (); $main::Changes = 0; $main::IntegrationChanges = 0; $main::LabelFilesAdded = 0; $main::LabelFilesDeleted = 0; $main::LabelFilesUpdated = 0; $main::IntFilesAdded = 0; $main::IntFilesDeleted = 0; $main::IntFilesChanged = 0; $main::DepotErrors = 0; ### $main::FailedSubmits = 0; ### $main::FilesLocked = 0; $main::Mutex; $main::HaveMutex = $main::FALSE; %main::DepotsSeen = (); # # list of project names not to allow as aliases # %main::BadAliases = ( alias => 1, build => 1, cat => 1, cmd => 1, cd => 1, cp => 1, dir => 1, du => 1, kill => 1, list => 1, ls => 1, mv => 1, net => 1, rm => 1, sd => 1, sdx => 1, setup => 1, tc => 1, vi => 1, where => 1, xcopy => 1 ); # # hash of arrays of files to give the user # %main::SDXTools = ( toSDXRoot => [ "alias.sdx", ], toSDTools => [ "sdx.cmd", "sdx.pl", "sdx.pm" ], toSDToolsPA => [ "alias.exe", "perl.exe", "perlcore.dll", "perlcrt.dll", "sd.exe", ], ); # # hash of function pointers and default args # # command type 1 assumes the codebase type is 1 -- one project per depot # # if we find it's actually type 2 (N projects/depot), some of these will be # modified later to change the scope of the command, since some commands # (sd info, sd clients, sd branches) only make sense when reported per depot # and are redundant when reported per project # # OtherOp() uses cmd type to determine whether to loop through projects and # talk to depots by using SDPORT in SD.INI in each project root, or to # loop through the list of enlisted depots from SD.MAP # %main::SDCmds = ( # scope scope # # for type 1 for type 2 # those that help with SDX # (1:1) codebases (N:1) codebases # commands => {fn => \&OtherOp, defcmd => "", defarg => "", type => 1,}, # n/a n/a usage => {fn => \&OtherOp, defcmd => "", defarg => "", type => 1,}, # n/a n/a # # those that change client or server state # client => {fn => \&OtherOp, defcmd => "client", defarg => "", type => 1,}, # project depot defect => {fn => \&Defect, defcmd => "", defarg => "", type => 1,}, # project depot deletefile => {fn => \&OtherOp, defcmd => "delete", defarg => "", type => 1,}, # project project editfile => {fn => \&OtherOp, defcmd => "edit", defarg => "", type => 1,}, # project project enlist => {fn => \&Enlist, defcmd => "", defarg => "", type => 1,}, # project depot flush => {fn => \&OtherOp, defcmd => "flush", defarg => "", type => 1,}, # project project integrate => {fn => \&OtherOp, defcmd => "integrate", defarg => "", type => 1,}, # project depot labbranch => {fn => \&OtherOp, defcmd => "lbranch", defarg => "", type => 1,}, # project depot label => {fn => \&OtherOp, defcmd => "label", defarg => "", type => 1,}, # project depot labelsync => {fn => \&OtherOp, defcmd => "labelsync", defarg => "", type => 1,}, # project depot protect => {fn => \&OtherOp, defcmd => "protect", defarg => "", type => 1,}, # project depot repair => {fn => \&Repair, defcmd => "", defarg => "", type => 1,}, # project depot resolve => {fn => \&OtherOp, defcmd => "resolve", defarg => "", type => 1,}, # project depot revert => {fn => \&OtherOp, defcmd => "revert", defarg => "", type => 1,}, # project depot submit => {fn => \&OtherOp, defcmd => "submit", defarg => "", type => 1,}, # project depot sync => {fn => \&OtherOp, defcmd => "sync", defarg => "", type => 1,}, # project project triggers => {fn => \&OtherOp, defcmd => "triggers", defarg => "", type => 1,}, # project depot # # those that report status # admin => {fn => \&OtherOp, defcmd => "admin", defarg => "", type => 1,}, # project depot # branch => {fn => \&OtherOp, defcmd => "branch", defarg => "", type => 1,}, # project depot branches => {fn => \&OtherOp, defcmd => "branches", defarg => "", type => 1,}, # project depot clients => {fn => \&OtherOp, defcmd => "clients", defarg => "", type => 1,}, # project depot # change => {fn => \&OtherOp, defcmd => "change", defarg => "", type => 1,}, # project project changes => {fn => \&Changes, defcmd => "changes", defarg => "", type => 1,}, # project project counters => {fn => \&OtherOp, defcmd => "counters", defarg => "", type => 1,}, # project depot delta => {fn => \&Delta, defcmd => "", defarg => "", type => 1,}, diff2 => {fn => \&OtherOp, defcmd => "diff2", defarg => "", type => 1,}, dirs => {fn => \&OtherOp, defcmd => "dirs", defarg => "", type => 1,}, # project depot files => {fn => \&OtherOp, defcmd => "files", defarg => "", type => 1,}, # project project have => {fn => \&OtherOp, defcmd => "have", defarg => "", type => 1,}, # project project info => {fn => \&OtherOp, defcmd => "info", defarg => "", type => 1,}, # project depot integrated => {fn => \&OtherOp, defcmd => "integrated", defarg => "", type => 1,}, # project depot labels => {fn => \&OtherOp, defcmd => "labels", defarg => "", type => 1,}, # project depot opened => {fn => \&OtherOp, defcmd => "opened", defarg => "", type => 1,}, # project project pending => {fn => \&OtherOp, defcmd => "changes", defarg => "-s pending", type => 1,}, # project depot projects => {fn => \&OtherOp, defcmd => "projects", defarg => "", type => 1,}, # project project resolved => {fn => \&OtherOp, defcmd => "resolved", defarg => "", type => 1,}, # project depot status => {fn => \&OtherOp, defcmd => "status", defarg => "", type => 1,}, # project project # user => {fn => \&OtherOp, defcmd => "user", defarg => "", type => 1,}, # project depot users => {fn => \&OtherOp, defcmd => "users", defarg => "", type => 1,}, # project depot where => {fn => \&OtherOp, defcmd => "where", defarg => "", type => 1,}, # project project # # internal # enumdepots => {fn => \&OtherOp, defcmd => "enumdepots", defarg => "", type => 1,}, # project project ); # # list of SD command/flag combinations not to allow # %main::BadCmds = ( # # -c makes no sense since change numbers aren't consistent across name space # -c => [ "integrate", "revert", "submit" ], # # don't want any switches to sdx branch/change/user except -o # -d => [ "branch", "change", "user" ], -f => [ "branch", "change", "user" ], # # don't want to branch/client/changelist/label/user spec changing with -i # sd(x) client is ok # -i => [ "branch", "change", "client", "submit", "user" ], -t => [ "client", "label" ], ); # # set the starting dir # open(CWD, 'cd 2>&1|'); $main::StartDir = ; 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. $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; }; # # -# 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 = ; 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 @ # 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.) this is a new enlist # assume the arg following is the branch name # if (!$main::CodeBase and SDX::VerifyCBMap($_[$ArgCounter])) { $main::NewEnlist = $main::TRUE; $main::IncrEnlist = $main::FALSE; $main::CodeBase = $_[$ArgCounter++]; $main::Branch = $_[$ArgCounter]; if ($main::Usage = SDX::VerifyCodeBaseAndBranch($main::CodeBase, $main::Branch)) { $main::CodeBase = ""; $main::Branch = ""; } $main::V2 and do { print "\nnew enlist = $main::NewEnlist\n"; print "incr enlist = $main::IncrEnlist\n"; print "codebase = '$main::CodeBase'\n"; print "branch = '$main::Branch'\n"; }; } else { # # arg is a project name # # maybe add to list # if (!$main::EnlistAll and !$main::EnlistAsOther and !$main::EnlistFromProfile) { # # BUGBUG-2000/01/26-jeffmcd -- finish # # if arg is of the form project\path\path\path, break it apart # and associate the path with the project so we can write it in the view later # else # it's just a project name # # if ($_[$ArgCounter] =~ /.+\\.+/) # { # my @fields = split(/\\/,$_[$ArgCounter]); # my $project = @fields[0]; # push @main::SomeProjects, $project; # # shift @fields; # my $subpath = ""; # foreach (@fields) { $subpath .= "$_\\"; } # chop $subpath; # print "'$subpath'\n"; # # load the hash -- use project as key # push @$main::ProjectSubPaths{$project}, $subpath; # } # else # { push @main::SomeProjects, lc $_[$ArgCounter]; # } } } } }; # # if incrementally defecting, arg is project to defect from # ($main::Defecting and !$main::DefectAll) and do { push @main::SomeProjects, lc $_[$ArgCounter]; }; # # if repairing, current arg and the next are codebase and branch # $main::Repairing and do { # # if codebase is null we need both values # test the current arg to see if there's a codebase map for it, if so get the branch # !$main::CodeBase and do { SDX::VerifyCBMap($_[$ArgCounter]) and do { $main::CodeBase = $_[$ArgCounter++]; $main::Branch = $_[$ArgCounter]; if ($main::Usage = SDX::VerifyCodeBaseAndBranch($main::CodeBase, $main::Branch)) { $main::CodeBase = ""; $main::Branch = ""; } $main::V2 and do { print "\nrepairing, codebase = '$main::CodeBase'\n"; print "repairing, branch = '$main::Branch'\n"; }; }; }; # # if we didn't use this arg as codebase, pass it on # (!$main::CodeBase) and SDX::AddUserArg($_[$ArgCounter]); }; } $ArgCounter++; } # # maybe return for usage # $main::Usage and return; # # at this point all args have been accounted for # # figure out a couple things we couldn't earlier # # # for a regular enlist-all, set some flags # ($MinusA and $main::Enlisting) and do { if (!$main::EnlistAsOther and !$main::EnlistFromProfile) { $main::EnlistAll = $main::TRUE; $main::EnlistGroup = $main::FALSE; $main::EnlistSome = $main::FALSE; # null out list in case we collected some projects already @main::SomeProjects = (); } else { $ignore .= " -a"; } }; # # enlist clean if not enlisting as another client # $MinusC and do { if (!$main::EnlistAsOther) { $main::EnlistClean = $main::TRUE; } else { $ignore .= " -c"; } }; # # enlisting as another client takes precedence over profiles # ($MinusP) and do { if ($main::EnlistAsOther) { $ignore .= " -p $main::Profile"; $main::EnlistFromProfile = $main::FALSE; $main::Profile = ""; @main::SomeProjects = (); } else { # # set flags # $main::NewEnlist = $main::TRUE; $main::IncrEnlist = $main::FALSE; $main::CodeBase = $main::ProfileCodeBase; $main::Branch = $main::ProfileBranch; push @main::SomeProjects, @main::ProfileProjects; $main::V2 and do { $main::Repairing and print "\nrepairing from profile...\n"; print "\nnew enlist = $main::NewEnlist\n"; print "incr enlist = $main::IncrEnlist\n"; print "codebase = '$main::CodeBase'\n"; print "branch = '$main::Branch'\n"; print "some projects = '@main::SomeProjects'\n"; }; } }; # # ignore exclusions if not enlisting as another client # $MinusX and do { if (!$main::EnlistAsOther) { $main::Exclusions = $main::FALSE; } else { $ignore .= " -x"; } }; # # if we have args to ignore, say so # $main::EnlistAsOther and $ignore and printf "\nUsing client %s as a template, ignoring$ignore.\n", "\U$main::OtherClient"; $main::EnlistFromProfile and $ignore and print "\nUsing profile, ignoring$ignore and/or projects on command line.\n"; # # do some early error checking so we can get usage if needed # $main::Enlisting and do { # # make sure we're enlisting in either some or all projects # if (!$main::EnlistAsOther and !$main::EnlistSome and !$main::EnlistAll) { print "\nMissing projects to enlist, or -a.\n"; $main::Usage = $main::TRUE; } # # if we're enlisting in only some projects and not as another client, # the project list can't be empty # if ($main::EnlistSome and !$main::EnlistAsOther and ($#main::SomeProjects < 0)) { print "\nMissing projects to enlist. Please specify projects or use -a for all.\n"; $main::Usage = $main::TRUE; } }; # # same if defecting... # $main::Defecting and do { # # make sure we're defecting in either some or all projects # if (!$main::DefectSome and !$main::DefectAll) { print "\nMissing projects to defect, or -a.\n"; $main::Usage = $main::TRUE; } # # if we're defecting in only some projects, the project list # can't be empty # if ($main::DefectSome and ($#main::SomeProjects < 0)) { print "\nMissing projects to defect.\n"; $main::Usage = $main::TRUE; } }; # # for now 'sdx branch' or 'sdx integrate' with no args is an error -- we don't want the UI popping up # branch and integrate also requires args # (($main::SDCmd eq "branch" or $main::SDCmd eq "integrate") and $main::UserArgs =~ /^[\s]*$/) and do { print "\nMissing arguments to 'sdx $main::SDCmd'.\n"; $main::Usage = $main::TRUE; }; # # 'sdx opened -c' without 'default' is an error # (($main::SDCmd eq "opened") and ($main::UserArgs =~ /-c/ and $main::UserArgs !~ /-c default/)) and do { print "\n'sdx $main::SDCmd -c' requires 'default' as an argument.\n"; $main::Usage = $main::TRUE; }; (($main::SDCmd eq "branch" or $main::SDCmd eq "change" or $main::SDCmd eq "user") and $main::UserArgs !~ /-o/) and do { print "\nOnly the -o switch is supported with 'sdx $main::SDCmd'.\n"; $main::Usage = $main::TRUE; }; # # don't allow "..." ".../*" ".../*.*" or their variations as arg to delete and edit # ($main::SDCmd eq "deletefile" or $main::SDCmd eq "editfile") and do { ($main::UserArgs =~ / \.\.\. |\.\.\.[\\\/]\*|\.\.\.[\\\/]+\*\.\* /) and do { my $ua = $main::UserArgs; $ua =~ s/[\t\s]*//g; print "\n'$ua' is not supported with 'sdx $main::SDCmd'.\n"; $main::Usage = $main::TRUE; }; }; # # only allow 'status' arg to sd admin # ($main::SDCmd eq "admin" and $main::UserArgs =~ / killthread | copyin | copyout | stop/) and do { print "\nOnly the 'status' command is supported with 'sdx admin'.\n"; $main::Usage = $main::TRUE; }; # # see if we need to check the format of (reverse) integration comments # # this helps sdx changes -b buildnum find I/RI events in the sd changes output # and get build history # ($main::SDCmd eq "submit" and $main::SubmitComment) and SDX::VerifySubmitComment(); $main::V4 and do { print "\nparseargs: cmd line = '@_'\n\n"; printf "parseargs: op = %s\n", $main::SDCmd; printf "parseargs: userargs = '%s'\n", $main::UserArgs; printf "parseargs: e = %s\n", $main::Enlisting; printf "parseargs: r = %s\n", $main::Repairing; printf "parseargs: d = %s\n", $main::Defecting; printf "parseargs: o = %s\n", $main::OtherOp; printf "parseargs: ea = %s\n", $main::EnlistAll; printf "parseargs: es = %s\n", $main::EnlistSome; printf "parseargs: da = %s\n", $main::DefectAll; printf "parseargs: ds = %s\n", $main::DefectSome; print "parseargs: submitcomment = '$main::SubmitComment'\n"; printf "parseargs: logging = %s\n", $main::Logging; printf "parseargs: logfile = '%s'\n", $main::Log; printf "parseargs: enlistfromprofile = %s\n", $main::EnlistFromProfile; printf "parseargs: profile = '%s'\n", $main::Profile; printf "parseargs: newenlist = %s\n", $main::NewEnlist; printf "parseargs: increnlist = %s\n", $main::IncrEnlist; printf "parseargs: enlistasother = %s\n", $main::EnlistAsOther; printf "parseargs: otherclient = '%s'\n", $main::OtherClient; printf "parseargs: u = %s\n", $main::Usage; printf "parseargs: v1 = %s\n", $main::V1; printf "parseargs: v2 = %s\n", $main::V2; printf "parseargs: quiet = %s\n", $main::Quiet; printf "parseargs: mintools = %s\n", $main::MinimalTools; printf "parseargs: sync = %s\n", $main::Sync; printf "parseargs: defectwithprejudice = %s\n", $main::DefectWithPrejudice; printf "parseargs: sdxroot = %s\n", $main::SDXRoot; printf "parseargs: cb = %s\n", $main::CodeBase; printf "parseargs: br = %s\n", $main::Branch; (($main::MinusI and !$main::Repairing) and !$main::MinusH) and do { print "parseargs: input form on STDIN:\n"; foreach (@main::InputForm) { print "'$_'\n"; } }; if ($main::EnlistSome or $main::DefectSome) { print "\nSome projects on cmd line:\n\n"; foreach $project (@main::SomeProjects) { printf "\t%s\n", $project; } print "\n"; } print "\n"; }; } # _____________________________________________________________________________ # # AddUserArg # # # Parameters: # # Output: # _____________________________________________________________________________ sub AddUserArg { my $arg = $_[0]; # # if the arg is a switch associated with bad cmds # see if our cmd is in the list # ($arg =~ /^[-\/]/ and exists($main::BadCmds{$arg})) and do { foreach $cmd (@{$main::BadCmds{$arg}}) { ($cmd eq $main::SDCmd) and die("\nThe 'sdx $main::SDCmd $arg' command is not supported.\n"); } }; $main::V4 and do { print "adding '$arg ' to '$main::UserArgs'\n"; }; $main::UserArgs .= $arg . " "; } # _____________________________________________________________________________ # # ReadSDMap # # reads project name and project root (relative path from %SDXROOT%) from # %SDXROOT%\sd.map into a list for use by Defect() and OtherOp() # # Parameters: # # Output: # populates $main::SDMapProjects list # _____________________________________________________________________________ sub ReadSDMap { my $enlisting = ($_[0] eq "enlist"); my $defecting = ($_[0] eq "defect"); my $repairing = ($_[0] eq "repair"); my $otherop = ($_[0] eq "otherop"); my $init = ($_[1] eq "init"); my $line; my $repairmsg = $main::FALSE; my $enlistmsg = $main::FALSE; my $nomapmsg = $main::FALSE; my $nokeysmsg = $main::FALSE; my $noprojmsg = $main::FALSE; # # need to re-init this here each time # @main::SDMapProjects = (); $main::V3 and do { print "op = '$op'\n"; print "init = '$init'\n"; }; if (-e $main::SDMap) { open(SDMAP, "<$main::SDMap") or die("\nCan't open $main::SDMap for reading.\n"); while ($line = ) { # # 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" : "", $main::SDMapBranch ? $main::SDMapBranch : ""; }; } 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 ' 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 ' 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 : ""), ($main::Branch ? $main::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 () { /^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\\setenv.cmd # not there yet # ("\U$main::CodeBase" eq "NT") and SDX::WriteDefaultSetEnv(); # # verbage for a succesful enlist # print "\nDone.\n"; $main::NewEnlist and do { $main::SDXRoot =~ tr/a-z/A-Z/; $main::CodeBase =~ tr/a-z/A-Z/; $sdtools = $main::SDXRoot . "\\sdtools"; print "\n\nThe directory $main::SDXRoot is now enlisted in the $main::CodeBase sources.\n"; print "\nThese SDX files were placed in your enlistment:\n"; if ($main::ToolsProject) { print "\n $main::SDXRoot\n"; printf "\t%-24smap to project roots and SD.INIs\n", "SD.MAP"; print "\n \U$main::ToolsProjectPath\n"; printf "\t%-24saliases for logging SDX output\n", "ALIAS.SDX"; printf "\t%-24saliases for navigating your enlistment\n", "ALIAS." . $main::CodeBase; $main::CodeBaseMapFile =~ tr/a-z/A-Z/; printf "\t%-24scodebase map for future enlist/defect/repair\n", $main::CodeBaseMapFile; printf "\t%-24ssets default Source Depot vars and aliases\n", "SDINIT.CMD"; printf "\t%-24sscripts for cross-depot commands\n", "SDX.\*"; if ( "\U$main::CodeBase" eq "NT" or "\U$main::CodeBase" eq "NTSDK" or ("\U$main::CodeBase" eq "NTTEST" and !$main::RestrictRoot) or "\U$main::CodeBase" eq "NT.INTL" or "\U$main::CodeBase" eq "MPC" or "\U$main::CodeBase" eq "NGWS" or "\U$main::CodeBase" eq "MGMT" or "\U$main::CodeBase" eq "MOM" or "\U$main::CodeBase" eq "PDDEPOT" or "\U$main::CodeBase" eq "WINMEDIA" or "\U$main::CodeBase" eq "WINSS" ) { printf "\n\nRun\n\n %s\\RAZZLE.CMD%s\n\nto start building.\n\n","\U$main::ToolsProjectPath", ($main::MinimalTools) ? " no_certcheck" : ""; } else { print "\n\nTo use Source Depot, your build environment must:\n"; print "\n set SDXROOT=$main::SDXRoot\n"; printf " set PATH=\%SDXROOT\%\\%s;\%SDXROOT\%\\%s\\\%PROCESSOR_ARCHITECTURE\%;\%PATH\%\n", $main::ToolsPath ? "\U$main::ToolsPath" : "\U$main::ToolsProject", $main::ToolsPath ? "\U$main::ToolsPath" : "\U$main::ToolsProject"; printf " call %s\\SDINIT.CMD\n", "\U$main::ToolsProjectPath"; } } else { print "\n $main::SDXRoot\n"; printf "\t%-24saliases for logging SDX output\n", "ALIAS.SDX"; printf "\t%-24saliases for navigating your enlistment\n", "ALIAS." . $main::CodeBase; printf "\t%-24smap to project roots and SD.INIs\n", "SD.MAP"; printf "\t%-24ssets default Source Depot vars and aliases\n", "SDINIT.CMD"; print "\n $sdtools\n"; printf "\t%-24sPerl runtimes\n", "PERL\*"; $main::CodeBaseMapFile =~ tr/a-z/A-Z/; printf "\t%-24scodebase map for future enlist/defect/repair\n", $main::CodeBaseMapFile; printf "\t%-24sSource Depot client\n", "SD.EXE"; printf "\t%-24sscripts for cross-depot commands\n", "SDX.\*"; print "\n\nTO USE SDX/SD\n-------------\n"; print "Run $main::SDINIT. This will\n\n"; print " - set default Source Depot environment variables\n\n"; !$main::ToolsProject and print " - include $main::SDXRoot\\sdtools in your PATH\n\n"; print " - turn on aliases to log SDX output to $main::SDXRoot\\.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 \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 " 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 = ; 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 = ; 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 () { #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 = ; 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 () { # # 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 -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//... //depot/$labbranch//...\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 : "<>"); 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/<>/<> //depot/private/$main::SDUser/$proj/<>/<>\n"; print BRANCHVIEW "\t//depot/$main::SDMapBranch/$proj/<>/<> //depot/private/$main::SDUser/$proj/<>/<>\n"; print BRANCHVIEW "\t//depot/$main::SDMapBranch/$proj/<>/<> //depot/private/$main::SDUser/$proj/<>/<>\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//$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. $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. # !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 = ) { # # 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 \@ is only supported for new\n"; print "enlistents. If you want to keep $client as your client name, run 'sdx defect\n"; print "$main::CodeBase $main::Branch -a -f' to defect, or set \%SDCLIENT\% to another\n"; print "name, then rerun this command.\n"; die("\n"); } } print "\nok.\n"; }; # _____________________________________________________________________________ # # GetProjectsToRepair # # Parameters: # # Output: # populates @main::RepairDepots and @main::RepairProjects # returns 1 if successful, 0 otherwise # _____________________________________________________________________________ sub GetProjectsToRepair { @main::RepairDepots = (); @main::RepairProjects = (); %seen = (); # # if only rewriting SD.INIs, base the depot/project repair lists on # whatever is in SD.MAP and the codebase map # if ($main::MinusI) { my %seen = (); # # build list of depots # for $proj (@main::SDMapProjects) { for $proj2 (@main::AllProjects) { (@$proj[$main::CBMProjectField] eq @$proj2[$main::CBMProjectField]) and do { push @main::RepairProjects, $proj2; my $sp = @$proj2[$main::CBMServerPortField]; unless ($seen{$sp}) { $seen{$sp} = 1; push @main::RepairDepots, [("$sp", "@$proj2[$main::CBMDepotNameField]")]; } } } } # # adjust the list of actively used depots to # reflect what we got out of the codebase map # @main::ActiveDepots = (); for $depot (@main::RepairDepots) { push @main::ActiveDepots, @$depot[0]; }; } else { # # for each depot, see if the client exists # if so, get its view and munge it to see which # projects it includes # foreach $depot (@main::AllDepots) { $serverport = @$depot[0]; $main::V3 and print "\t$serverport\n"; if (SDX::ClientExists($serverport, $main::SDClient)) { # # add this depot to the list # push @main::RepairDepots, $depot; # # read the existing client view into @main::ExistingView # SDX::GetClientView("repair", $serverport, $main::SDClient); foreach $line (@main::ExistingView) { # # throw away negating view lines # $line =~ /^[\t\s]+-/ and next; @fields = split(/\//, $line); $branch = @fields[3]; $project = @fields[4]; $project and do { # print "b/p $branch $project\n"; for $projectline (@main::AllProjects) { if ("\U$project" eq "\U@$projectline[$main::CBMProjectField]") { unless ($seen{$project}) { $seen{$project} = 1; push @main::RepairProjects, $projectline; } last; } } }; } } } } $main::V3 and do { foreach $depot (@main::RepairDepots) { print "RepairDepots: @$depot\n"; } print "\n"; foreach $project (@main::RepairProjects) { print "RepairProjects: @$project\n"; } }; # # verify access for all depots in the repair list # @main::VerifyDepots = @main::RepairDepots; # # return success as long as these two lists have values # (@main::RepairDepots && @main::RepairProjects) and return 1; return 0; } # _____________________________________________________________________________ # # CreateView # # Parameters: # Command Line Arguments # # Output: # # _____________________________________________________________________________ sub CreateView { $depot = $_[0]; my $enlisting = ($_[1] eq "enlist"); my $defecting = ($_[1] eq "defect"); my $repairing = ($_[1] eq "repair"); my $root = ""; my $clobber = $main::FALSE; my $crlf = $main::FALSE; $serverport = @$depot[0]; $depotname = @$depot[1]; @main::tmpView = (); @main::FinalView = (); (!$enlisting && !$defecting && !$repairing) and die("\nUnknown operation in CreateView().\n"); unlink $main::ClientView; # # write the default view lines for this depot and project(s) # SDX::WriteDefaultView($serverport, $depotname); # # if we're doing a clean enlist or the client doesn't already exist, # use the default view # else merge the default view with the existing view # if ($main::CleanEnlist or !SDX::ClientExists($serverport, $main::SDClient)) { # # Root: field for client view depends on depot type # # for type 1 (1 project/depot), root includes project name # for type 2 (N projects/depot), root is just main::SDXRoot # # root is at least SDXRoot in either case # $root = $main::SDXRoot; (@{$main::DepotType{$serverport}}[0] == 1) and $root = SDX::Type1Root($root); # # files in root project in NT are clobberable # # BUGBUG-2000/5/12-jeffmcd -- this should be an option in the codebase map -- ClobberRoot = 1 or 0 # 2002/9/5 -jeremyd -- the whole options line should be configurable and fall back to server defaults # if ("\U$main::CodeBase" eq "NT") { $project = @main::ProjectsInThisDepot[0]; $clobber = ("\L@$project[$main::CBMProjectField]" eq "root"); } # # SQL SD server is setup as crlf # if ("\l$serverport" eq "sqldepot.sys-ntgroup.ntdev.microsoft.com:1666") { $crlf = $main::TRUE; } # # write default view header # open(CLIENTVIEW, ">$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n"); printf CLIENTVIEW "Client: %s\n\n", $main::SDClient; printf CLIENTVIEW "Owner: %s\n\n", $main::SDDomainUser; printf CLIENTVIEW "Description:\n Created by %s.\n\n", $main::SDDomainUser; printf CLIENTVIEW "Root: %s\n\n", $root; printf CLIENTVIEW "Options: noallwrite %sclobber nocompress %scrlf locked nomodtime\n\n", $clobber ? "" : "no", $crlf ? "" : "no"; printf CLIENTVIEW "View:\n"; # # append the default view # for $line (@main::DefaultView) { printf CLIENTVIEW $line; ### push @clientview, $line; } close(CLIENTVIEW); $verb = "Creating"; } else { # # read the existing client view into @main::ExistingView # SDX:GetClientView("enlist", $serverport, $main::SDClient); # # concat the existing view and the default view # for $line (@main::ExistingView) { push @main::tmpView, $line; } for $line (@main::DefaultView) { push @main::tmpView, $line; } $main::V3 and do { print "\nexisting + default:\n"; print @main::tmpView; }; # # sort the list for uniqueness, preserving order # %seen = (); @uniq = (); foreach $line (@main::tmpView) { # # lowercase the line for the check, but push the # unchanged version of line onto the list so # we preserve the user's case # unless ($seen{"\L$line"}) { $seen{"\L$line"} = 1; push @uniq, $line; } } @main::FinalView = @uniq; $main::V3 and do { print "\nfinal view:\n"; print @main::FinalView; }; # # now finish writing the client view by appending the # final view spec # open(CLIENTVIEW, ">>$main::ClientView") or die("\nCan't open $main::ClientView for writing.\n"); for $viewline (@main::FinalView) { printf CLIENTVIEW $viewline; } close(CLIENTVIEW); $verb = "Updating existing"; $repairing and $verb = "Verifying"; } printf "\n%s client %s in depot %s.\n", $verb, $main::SDClient, $serverport; $main::V1 and do { $main::V2 and do { printf "\ndepot mapping for %s (//%s) consists of %s project(s):\n\n", $serverport, $depotname, $#main::ProjectsInThisDepot+1; foreach $project (@main::ProjectsInThisDepot) { printf "\t%s\n", @$project[$main::CBMProjectField]; } }; print "\n\n"; system "type $main::ClientView 2>&1"; print "\n--------------------------------------------------\n\n"; }; } # _____________________________________________________________________________ # # WriteDefaultView # # Create the default view lines for this depot/project and push them onto a list # # Parameters: # # Output: # # _____________________________________________________________________________ sub WriteDefaultView() { $serverport = $_[0]; $depotname = $_[1]; $proj = ""; $group = ""; $projroot = ""; @main::DefaultView = (); $main::V3 and do { print "sp = '$serverport'\n"; print "depotname = '$depotname'\n"; }; # # for each project in this depot, generate the depot mappings and push # them onto a list # foreach $project (@main::ProjectsInThisDepot) { $usingroot = $main::FALSE; $proj = @$project[$main::CBMProjectField]; $group = @$project[$main::CBMGroupField]; $projroot = @$project[$main::CBMProjectRootField]; # # flip any '\' in the proj root path into '/' for SD # $projroot =~ s/\\/\//g; # # special case for enlisting a project directly in the root # if ($projroot eq "sdxroot") { $usingroot = $main::TRUE; } # # if no project root was given in the codebase map, # assume the root is same as the project name # if (!$projroot) { $projroot = $proj; } # # create and save the view line for this project # # handle special case for SD sources # handle special case for enlisting directly in %SDXROOT% # otherwise handle normal case # # # see if this project is one for which we should exclude # some platform-specific dirs from its view # $found = $main::FALSE; $Exclude = $main::FALSE; foreach $someproj (@main::PlatformProjects) { if ("\U$proj" eq "\U$someproj") { $found = $main::TRUE; } } if ($found && $main::Exclusions) { $Exclude = $main::TRUE; if ("\U$main::Platform" eq "X86") { } if ("\U$main::Platform" eq "AMD64") { @ExcludePlats = ("x86", "i386", "ia64"); } if ("\U$main::Platform" eq "IA64") { @ExcludePlats = ("x86", "i386", "amd64"); } } # # special case for handling the one project in the codebase map that can be enlisted directly # in $main::SDXRoot # if ($usingroot) { $projroot = $proj; # # maybe restrict the scope of the root mapping # $rootspec = "..."; $main::RestrictRoot and do { $rootspec = "*"; }; # # generate some shorthand for the depot-branch-project on LHS of the view # my $dbp = SDX::MakeDBP($serverport, $depotname, $group, $projroot); # # if this is the tools project and the user wants the minimal # tool set, customize the view # # else generate the normal view line # my $mintools = ("\U$proj" eq "\U$main::ToolsProject" and $main::MinimalTools); if ($mintools) { # # add '/' if we have a tools path # my $tpath = ($main::ToolsPath ? "/$main::ToolsPath" : ""); # # flip any '\' in the tools path into '/' for SD # $tpath =~ s/\\/\//g; # # -//depot///... ///... # $viewline = sprintf("\t-//%s/... //%s/...\n", $dbp, $main::SDClient); push @main::DefaultView, $viewline; # # //depot///* ///* # $viewline = sprintf("\t//%s/* //%s/*\n", $dbp, $main::SDClient); push @main::DefaultView, $viewline; # # //depot//[//]* //[//]* # $viewline = sprintf("\t//%s%s/* //%s%s/*\n", $dbp, $tpath, $main::SDClient, $tpath); push @main::DefaultView, $viewline; # # //depot//[/]//*sd*exe //[/]//*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//[/]//perl/... //[/]//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= # ( "\U$main::CodeBase" eq "NT" or ("\U$main::CodeBase" eq "NTTEST" and !$main::RestrictRoot) or "\U$main::CodeBase" eq "NTSDK" or "\U$main::CodeBase" eq "NT.INTL" or "\U$main::CodeBase" eq "MPC" or "\U$main::CodeBase" eq "NGWS" or "\U$main::CodeBase" eq "MGMT" or "\U$main::CodeBase" eq "MOM" or "\U$main::CodeBase" eq "PDDEPOT" or "\U$main::CodeBase" eq "WINMEDIA" or "\U$main::CodeBase" eq "WINSS" ) and do { # # this negation line isn't necessary if we're doing minimal tools # !$mintools and do { $viewline = sprintf("\t-//%s/developer/... //%s/developer/...\n", $dbp, $main::SDClient); push @main::DefaultView, $viewline; }; $viewline = sprintf("\t//%s/developer/* //%s/developer/*\n", $dbp, $main::SDClient); push @main::DefaultView, $viewline; $viewline = sprintf("\t//%s/developer/%s/... //%s/developer/%s/...\n", $dbp, $main::SDUser, $main::SDClient, $main::SDUser); push @main::DefaultView, $viewline; }; }; # # only do the exclude lines if the root isn't already restricted # and we're not doing minimal tools (since everything in Root will # already be restricted except what the user needs) # if ($Exclude && !$main::RestrictRoot && !$main::MinimalTools) { for $e (@ExcludePlats) { # # generate the view line and save it away # $viewline = sprintf("\t-//%s/.../%s/... //%s/.../%s/...\n", $dbp, $e, $main::SDClient, $e); push @main::DefaultView, $viewline; } } } else { # # generate the view line(s) # # # for the USERS project in Scratch depots, only map in \users\ # # BUGBUG-2000/01/10-jeffmcd -- remove this when enlisting with \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//users/... ///users/... $viewline = sprintf("\t-//%s/... //%s/%s/...\n", $dbp, $main::SDClient, $projroot); push @main::DefaultView, $viewline; # //depot//users//... ///users//... $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 "/" if type 2 depot # my $tpath = ($main::ToolsPath ? "/$main::ToolsPath" : ""); # # flip any '\' in the tools path into '/' for SD # $tpath =~ s/\\/\//g; # # 1: -//depot///... ///... # 2: -//depot///... ////... # $viewline = sprintf("\t-//%s/... //%s%s/...\n", $dbp, $main::SDClient, $proot); push @main::DefaultView, $viewline; # # 1: //depot////* ////* # 2: //depot////* /////* # $viewline = sprintf("\t//%s%s/* //%s%s%s/*\n", $dbp, $tpath, $main::SDClient, $proot, $tpath); push @main::DefaultView, $viewline; # # 1: //depot/////*sd*exe /////*sd*exe # 2: //depot/////*sd*exe //////*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/////perl/... /////perl/... # 2: //depot/////perl/... //////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//project/... ///... # 2: //depot///... ////... # $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 //// 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 () { 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. 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. 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 = ) { # # 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 = ) { # # 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 () { !(++$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 () { !(++$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 = ; 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/ # 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,@ ** # 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: # INT: # ($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;