my
$Id
=
q$Id: APC2SVN.pm 220 2006-10-22 10:51:44Z k $
;
our
$VERSION
=
sprintf
"%.3f"
, 1 +
substr
(
q$Rev: 220 $
,4)/1000;
our
@ISA
=
qw(Exporter)
;
our
@EXPORT_OK
=
qw(latest_change url_latest_change get_dirs_to_add
get_dirs_to_delete delete_empty_dirs)
;
our
$DEBUG
= 0;
sub
latest_change ();
sub
url_latest_change ($);
sub
get_dirs_to_add (@);
sub
get_dirs_to_delete (@);
sub
dir_will_be_empty ($);
sub
delete_empty_dirs (@);
sub
latest_change () {
my
$lastpatch
= 0;
my
(
$rev
);
warn
"DEBUG: Running svn info -R"
if
$DEBUG
;
open
my
$svninfo
,
"svn info -R |"
or
die
"Can't fork 'svn info': $!\n"
;
local
$/;
local
$_
= <
$svninfo
>;
close
$svninfo
;
$rev
= max(/^Last Changed Rev: (\d+)/gm);
$/ =
"\n"
;
my
$triesleft
= 4;
until
(
$lastpatch
) {
last
unless
$rev
;
warn
"DEBUG: Running svn log -r $rev"
if
$DEBUG
;
open
my
$svnlog
,
"svn log -r $rev |"
or
die
"Can't fork 'svn log': $!\n"
;
while
(<
$svnlog
>) {
chomp
;
if
($. == 2) {
if
(/^rev (\d+):/) {
$rev
= $1;
}
else
{
die
"Unexpected log-status-line: '$_'"
;
}
}
elsif
(/^Change (\d+) by /) {
$lastpatch
= $1;
last
;
}
}
1
while
<
$svnlog
>;
unless
(
close
$svnlog
) {
warn
"Warning (probably harmless): Can't close 'svn log -r $rev': $!"
;
}
$rev
--
unless
$lastpatch
;
last
unless
$rev
;
last
unless
--
$triesleft
> 0;
}
return
$lastpatch
if
$lastpatch
;
warn
"DEBUG: Running svn log"
if
$DEBUG
;
open
my
$svnlog
,
'svn log |'
or
die
"Can't fork 'svn log': $!\n"
;
while
(<
$svnlog
>) {
if
(/^Change (\d+) by /) {
$lastpatch
= $1;
last
;
}
}
close
$svnlog
;
$lastpatch
;
}
sub
url_latest_change ($) {
my
$url
=
shift
;
my
$lastpatch
= 0;
warn
"DEBUG: Running svn log $url"
if
$DEBUG
;
open
my
$svnlog
,
"svn log $url |"
or
die
"Can't fork 'svn log $url': $!\n"
;
local
($/) =
"\n"
;
while
(<
$svnlog
>) {
if
(/^Change (\d+) by /) {
$lastpatch
= $1;
last
;
}
}
close
$svnlog
;
$lastpatch
;
}
sub
get_dirs_to_add (@) {
return
()
if
@_
== 0;
my
%dirs
= ();
for
my
$file
(
@_
) {
my
$dir
=
$file
;
while
((
$dir
= dirname
$dir
) ne
"."
) {
$dirs
{
$dir
} = 1
unless
$dirs
{
$dir
} or -d
$dir
;
}
}
return
sort
{
length
$a
<=>
length
$b
}
keys
%dirs
;
}
sub
get_dirs_to_delete (@) {
return
()
if
@_
== 0;
my
%dirs
= ();
for
my
$file
(
@_
) {
my
$dir
= dirname
$file
;
$dirs
{
$dir
} = 1
if
!
$dirs
{
$dir
} and dir_will_be_empty(
$dir
);
}
return
sort
{
length
$b
<=>
length
$a
}
keys
%dirs
;
}
sub
dir_will_be_empty ($) {
my
$dir
=
shift
;
my
$ret
= 1;
my
$count
= 0;
my
@glob
=
grep
!/\/\.svn$/,
glob
"$dir/*"
;
return
1
unless
@glob
;
my
$glob
=
join
" "
,
map
{
"'$_'"
}
@glob
;
warn
"DEBUG: Running svn info $glob"
if
$DEBUG
;
open
my
$svninfo
,
"svn info $glob |"
or
die
"Can't fork 'svn info': $!\n"
;
while
(<
$svninfo
>) {
next
if
!/^Schedule: (\w+)/;
++
$count
;
$ret
= 0
if
$1 ne
'delete'
;
}
close
$svninfo
;
return
$count
?
$ret
: 0;
}
sub
delete_empty_dirs (@) {
my
@files
=
@_
;
my
@to_delete_recursively
=
my
@to_delete
= get_dirs_to_delete(
@files
);
if
(
@to_delete
) {
warn
"DEBUG: Running svn rm on to_delete[@to_delete]"
if
$DEBUG
;
system
(
svn
=>
'rm'
,
@to_delete
)
and
die
"Error executing svn rm : $!,$?\n"
;
push
@to_delete_recursively
, delete_empty_dirs(
@to_delete
);
}
@to_delete_recursively
;
}
1;