use
POSIX
':sys_wait_h'
;
sub
repo_client {
my
$self
=
shift
;
$self
->{P4_REPO_CLIENT} =
shift
if
@_
;
return
$self
->{P4_REPO_CLIENT} ;
}
sub
p4 {
my
$self
=
shift
;
local
$ENV
{P4PASSWD} =
$self
->repo_password
if
defined
$self
->repo_password ;
unshift
@{
$_
[0]},
'-p'
,
$self
->repo_server
if
defined
$self
->repo_server ;
unshift
@{
$_
[0]},
'-c'
,
$self
->repo_client
if
defined
$self
->repo_client ;
unshift
@{
$_
[0]},
'-u'
,
$self
->repo_user
if
defined
$self
->repo_user ;
my
$tmp
=
$ENV
{PWD} ;
delete
$ENV
{PWD} ;
my
$args
=
shift
;
$self
->run_safely( [
"p4"
,
@$args
],
@_
) ;
$ENV
{PWD} =
$tmp
if
defined
$tmp
;
}
sub
parse_p4_repo_spec {
my
$self
=
shift
;
my
(
$spec
) =
@_
;
my
$parsed_spec
=
$self
->parse_repo_spec(
$spec
) ;
my
(
$user
,
$client
) ;
(
$user
,
$client
) =
$self
->repo_user =~ m/([^()]*)(?:\((.*)\))?/
if
defined
$self
->repo_user ;
$client
=
"vcp_tmp_$$"
unless
defined
$client
&&
length
$client
;
$self
->repo_user(
$user
) ;
$self
->repo_client(
$client
) ;
if
(
$self
->can(
"min"
) ) {
my
$filespec
=
$self
->repo_filespec ;
my
(
$name
,
$min
,
$comma
,
$max
) ;
(
$name
,
$min
,
$comma
,
$max
) =
$filespec
=~ m/^([^@]*)(?:@(-?\d+)(?:(\D|\.\.)((?:\d+|
or
die
"Unable to parse p4 filespec '$filespec'\n"
;
die
"'$comma' should be ',' in revision range in '$filespec'\n"
if
defined
$comma
&&
$comma
ne
','
;
if
( !
defined
$min
) {
$min
= 1 ;
$max
=
'#head'
;
}
if
( !
defined
$max
) {
$max
=
$min
;
}
elsif
(
lc
(
$max
) eq
'#head'
) {
$self
->p4( [
qw( counter change )
], \
$max
) ;
chomp
$max
;
}
if
(
$max
== 0 ) {
die
"Current change number is 0, no work to do\n"
;
}
if
(
$min
< 0 ) {
$min
=
$max
+
$min
;
}
$self
->repo_filespec(
$name
) ;
$self
->min(
$min
) ;
$self
->max(
$max
) ;
}
return
$parsed_spec
;
}
sub
init_p4_view {
my
$self
=
shift
;
my
$client
=
$self
->repo_client ;
$self
->repo_client(
undef
) ;
my
$client_exists
=
grep
$_
eq
$client
,
$self
->p4_clients ;
debug
"p4: client '$client' exists"
if
$client_exists
&& debugging
$self
;
$self
->repo_client(
$client
) ;
my
$client_spec
=
$self
->p4_get_client_spec ;
$client_spec
=
$self
->p4_get_client_spec
if
$^O =~ /Win32/ &&
$client_spec
=~ /[\x80-\xFF]/;
$self
->queue_p4_restore_client_spec(
$client_exists
?
$client_spec
:
undef
);
my
$p4_spec
=
$self
->repo_filespec ;
$p4_spec
=~ s{(/(\.\.\.)?)?$}{/...} ;
my
$work_dir
=
$self
->work_root ;
$client_spec
=~ s{^Root.*}{Root:\t
$work_dir
}m ;
$client_spec
=~ s{^View.*}{View:\n\t
$p4_spec
\t//
$client
/...\n}ms ;
debug
"p4: using client spec"
,
$client_spec
if
debugging
$self
;
$client_spec
=~ s{^(Options:.*)}{$1 nocrlf}m
if
$^O =~ /Win32/ ;
$client_spec
=~ s{^LineEnd.*}{LineEnd:\tunix}mi ;
debug
"p4: using client spec"
,
$client_spec
if
debugging
$self
;
$self
->p4_set_client_spec(
$client_spec
) ;
}
sub
p4_clients {
my
$self
=
shift
;
my
$clients
;
$self
->p4( [
"clients"
, ],
">"
, \
$clients
) ;
return
map
{ /^Client (\S*)/ ; $1 }
split
/\n/m,
$clients
;
}
sub
p4_get_client_spec {
my
$self
=
shift
;
my
$client_spec
;
$self
->p4( [
"client"
,
"-o"
],
">"
, \
$client_spec
) ;
return
$client_spec
;
}
my
@client_backups
;
END {
my
$child_exit
;
{
local
$?;
for
(
@client_backups
) {
my
(
$object
,
$name
,
$spec
) =
@$_
;
my
$tmp_name
=
$object
->repo_client ;
$object
->repo_client(
$name
) ;
if
(
defined
$spec
) {
$object
->p4_set_client_spec(
$spec
) ;
}
else
{
my
$out
;
$object
->p4( [
"client"
,
"-df"
,
$object
->repo_client ],
">"
, \
$out
);
warn
"vcp: unexpected stdout from p4:\np4: "
,
$out
unless
$out
=~ /^Client\s.*\sdeleted./ ;
$child_exit
= $?;
}
$object
->repo_client(
$tmp_name
) ;
$_
=
undef
;
}
@client_backups
= () ;
}
$? =
$child_exit
if
$child_exit
&& ! $?;
}
sub
queue_p4_restore_client_spec {
my
$self
=
shift
;
my
(
$client_spec
) =
@_
;
push
@client_backups
, [
$self
,
$self
->repo_client,
$client_spec
] ;
}
sub
p4_set_client_spec {
my
$self
=
shift
;
my
(
$client_spec
) =
@_
;
my
$out
;
$self
->p4( [
"client"
,
"-i"
],
"<"
, \
$client_spec
,
">"
, \
$out
) ;
die
"vcp: unexpected stdout from p4:\np4: "
,
$out
unless
$out
=~ /^Client\s.*\ssaved.$/ ;
}
1 ;