#!perl -w
# -*- Perl -*-
# Copyright 1999 Greg Spencer (greg_spencer@acm.org)
package p4Util;
BEGIN {
# because not all machines do Y2K stuff right...
$YearFix = ((gmtime(946684800))[5] == 100) ? 100 : 0;
@epoch = localtime(0);
}
###############################################################
# Subroutines
###############################################################
# This takes a time integer and creates a simple timestamp from it.
# It returns a time string and a date string in a list (in that order).
# The date and time are in the local time zone.
# I *think* it's Y2K safe, but there is no warranty.
sub ShortTimestamp {
my $ltime = shift;
my $ampm = "am";
my @now = localtime($ltime);
if ($now[2]>12 && $now[2]!=24) {
$now[2] -= 12;
$ampm = "pm";
}
elsif ($now[2] == 12) {
# fix for "noon"
$ampm = "pm";
}
elsif ($now[2] == 24) {
# fix for "midnight"
$ampm = "am";
$now[2] = 12;
}
# do that Y2K stuff -- yucko.
# localtime should just return a four char year...
$year = $now[5];
$year += $YearFix if ($now[5] < $epoch[5]);
# just in case they do it "right" on some machines.
$year -= 1900 if $year > 1900;
$year += 1900;
return (sprintf ("%2d:%02d:%02d$ampm",$now[2],$now[1],$now[0]),
sprintf("%d/%d/%04d",$now[4]+1,$now[3],$year));
}
# This collects information about a list of files in the perforce
# database.
#
# It returns a hash of hashes with a number of pieces of information about
# the files.
#
# If the hash doesn't contain a file that was in the input, then that
# file could not be found, and the exists member will be undef.
# The hash is indexed by depot name (not local name).
#
# Stuff you can get:
# clientFile -- local path
# depotFile -- name in depot (same as hash key)
# headAction -- action at head rev, if in depot
# headChange -- head rev type, if in depot
# headRev -- head rev #, if in depot
# headType -- head rev type, if in depot
# headTime -- head rev mod time, if in depot
# haveRev -- rev had on client, if on client
# action -- open action, if opened
# change -- open changelist#, if opened
# unresolved -- unresolved integration records
# otherOpen -- set if someone else has it open
# otherLock -- set if someone else has it locked
# ourLock -- set if this user/client has it locked
# exists -- set if this file exists on the server
# error -- set if there was an error accessing the server
sub GetFileInfo {
my @input_files = @_;
my %filehash;
my $line;
my %info;
my @dircandidates;
# quote the filenames (in case there are spaces)
foreach (@input_files) {
chomp;
$_ = "\"$_\"";
}
# open the input pipe
if (!open(INPUT,"p4 fstat @input_files 2>&1 |")) {
return ();
}
foreach $line () {
chomp $line;
# These are extra args -- we convert them here to a list
# attached to the original entry. We're assuming that all the
# args have the form of otherOpen, which is that there is a
# field called "otherOpen" at the top level containing a count
# of other clients that have this file open, and additional
# args containing the names of the clients who have it open,
# with names like "otherOpen0" and "otherOpen1". We replace
# the top level value with a list where the top level value
# (the count, in this case) is the first entry in the list,
# and we append all other values to the list as we encounter
# them.
if ($line =~ m/^\.\.\. \.\.\.\s+(\w+)\s+(.*)/) {
my $parentarg = $1;
my $arg = $2;
$parentarg =~ s/\d+$//; # just strip the numbers to find the parent
# list is already there -- just append the arg
if ( ref($info{$parentarg}) ) {
push (@{$info{$parentarg}},$arg);
}
# create a new list with the parent value.
elsif ( $info{$parentarg} ) {
my $val = $info{$parentarg};
$info{$parentarg} = [];
push (@{$info{$parentarg}},$val);
push (@{$info{$parentarg}},$arg);
}
# hmm, args, but no parent arg yet?
# We'll just make a list, in case that makes sense.
else {
$info{$parentarg} = [];
push (@{$info{$parentarg}},$arg);
}
next; # we handled this already, so skip to the next line.
}
# We've reached a blank line, or an error, so add
# the collected data to the hash and clear out the
# locals. If there is no info, then skip it (to handle errors).
#
# This also sets $1 and $2 for the 'else' case.
#
# yes, this skips deleted files.
if ($line !~ m/^\.\.\.\s+(\w+)\s+(.*)/) {
if ($line =~ m/^(.*) - no such file/) {
$info{"depotFile"} = $1;
$info{"exists"} = 0;
$info{"isDir"} = 0;
$info{"error"} = "no such file";
# create an empty hash and copy the local one into it.
$filehash{$1}={};
%{$filehash{$1}}=%info;
push (@dircandidates,$1);
}
elsif ($info{"depotFile"} && $info{"headAction"} ne "delete") {
my $name = $info{"depotFile"};
my $shortname = $name;
$shortname =~ s|.*/||;
$info{"exists"} = 1;
$info{"isDir"} = 0;
$info{"error"} = 0;
$info{"shortname"} = $shortname;
# create an empty hash and copy the local one into it.
$filehash{$name}={};
%{$filehash{$name}}=%info;
}
%info = (); # clear out the local info;
next;
}
else {
$info{$1} = $2;
}
}
close INPUT;
# now, we go over the list of failed files, looking for ones that were
# directories.
if (@dircandidates) {
my $quoted = "";
foreach (@dircandidates) {
$quoted .= " \"$_\"";
}
if (!open(INPUT,"p4 dirs $quoted 2>&1 |")) {
return %filehash;
}
# if it's found, then it's a dir, and should
# exist, and be a directory
while () {
next if m/is not under client/;
if (!m/^(.*) - no such file\(s\)\.$/) {
$filehash{$1}{"isDir"} = 1;
$filehash{$1}{"exists"} = 1;
}
}
close INPUT;
}
return %filehash;
}
sub GetUserInfo {
my %retval = ();
if (!open(INPUT,"p4 users 2>&1 |")) {
return {};
}
while () {
chomp;
m/(.*) <(.*)> \((.*)\) accessed (.*)/;
$retval{$1} = [$2,$3,$4];
}
return %retval;
}
1;