#!/opt/bin/perl
my
$Opts
= {};
getopts(
'r:p:e:c:vudn'
,
$Opts
);
my
$Cwd
= cwd();
my
$Verbose
= 1;
my
$ExcludeRe
=
$Opts
->{e} ?
qr/$Opts->{e}/
i :
undef
;
my
$Debug
=
$Opts
->{v} || 0;
my
$RunDiff
=
$Opts
->{d} || 0;
my
$PkgDir
=
$Opts
->{p} || cwd();
my
$Repo
=
$Opts
->{r} or
die
"Need repository!\n"
. usage();
my
$Changes
=
$Opts
->{c} ||
'Changes ChangeLog'
;
my
$NoBranch
=
$Opts
->{n} || 0;
$Repo
=~ s|/$||;
my
$CPV
=
$Debug
?
'-v'
:
''
;
my
$TestBin
=
'ptardiff'
;
my
$PkgDirRe
=
quotemeta
(
$PkgDir
.
'/'
);
my
$BranchName
= basename(
$PkgDir
) .
'.'
. $$;
my
$OrigRepo
=
$Repo
;
if
(
$NoBranch
) {
my
$RepoCopy
=
"$Repo-$BranchName"
;
print
"Copying repository to $RepoCopy ..."
if
$Verbose
;
system
(
"cp -PpR -f $Repo $RepoCopy"
)
and
die
"Copying master repo to $RepoCopy failed: $?"
;
$Repo
=
$RepoCopy
;
print
"done\n"
if
$Verbose
;
}
else
{
print
"Setting up a branch from blead called '$BranchName'..."
if
$Verbose
;
chdir
$Repo
or
die
"Could not chdir to $Repo: $!"
;
unless
( -d
'.git'
) {
die
"\n$Repo is not a git repository\n"
;
}
my
$status
= `git status`;
unless
(
$status
=~ /nothing to commit/ims ) {
die
"\nWorking directory not clean. Stopping.\n"
;
}
system
(
"git checkout -b $BranchName blead"
)
and
die
"Could not create branch '$BranchName': $?"
;
print
"done\n"
if
$Verbose
;
}
chdir
$PkgDir
or
die
"Could not chdir to $PkgDir: $!"
;
my
@LibFiles
;
{
print
"Copying libdir..."
if
$Verbose
;
die
"Can't (yet) copy from a repository (found .git or .svn)"
if
-d
'.git'
|| -d
'.svn'
;
die
"No lib/ directory found\n"
unless
-d
'lib'
;
system
(
"cp -fR $CPV lib $Repo"
) and
die
"Copy of lib/ failed: $?"
;
@LibFiles
=
map
{
chomp
;
$_
}
grep
{
$ExcludeRe
&&
$_
=~
$ExcludeRe
?
do
{
warn
"Removing $Repo/$_\n"
;
system
(
"rm $Repo/$_"
) and
die
"rm '$Repo/$_' failed: $?"
;
undef
}
: 1
} `find lib -type f`
or
die
"Could not detect library files\n"
;
print
"done\n"
if
$Verbose
;
}
my
$RelTopDir
;
my
$TopDir
;
my
$ModName
;
my
@ModFiles
;
{
print
"Creating top level dir..."
if
$Verbose
;
@ModFiles
=
sort
{
length
(
$a
) <=>
length
(
$b
) }
map
{
chomp
;
$_
}
grep
{
$ExcludeRe
?
$_
!~
$ExcludeRe
: 1 }
grep
/\.p(?:m|od)$/,
`find
$PkgDir
/lib -type f`
or
die
"No TopDir detected\n"
;
$RelTopDir
=
$ModFiles
[0];
$RelTopDir
=~ s/^
$PkgDirRe
//;
$RelTopDir
=~ s/\.p(m|od)$//;
$TopDir
=
"$Repo/$RelTopDir"
;
unless
( -d
$TopDir
) {
system
(
"mkdir $TopDir"
) and
die
"Creating dir $TopDir failed: $?"
;
}
{
my
@list
= @{[
split
'/'
,
$RelTopDir
]};
$ModName
=
join
'::'
,
@list
[1 ..
$#list
];
}
@ModFiles
=
map
{ s|^
$PkgDirRe
||;
$_
}
@ModFiles
or
die
"Could not detect modfiles\n"
;
print
"done\n"
if
$Verbose
;
}
my
$TopDirRe
=
quotemeta
(
$TopDir
.
'/'
);
my
@TestFiles
;
{
print
"Copying t/* files to $TopDir..."
if
$Verbose
;
-d
't'
?
system
(
"cp -fR $CPV t $TopDir"
) &&
die
"Copy of t/ failed: $?"
:
warn
"No t/ directory found\n"
;
@TestFiles
=
map
{
chomp
; s|^
$TopDirRe
||; s|//|/|g;
$_
}
grep
{
$ExcludeRe
&&
$_
=~
$ExcludeRe
?
do
{
warn
"Removing $_\n"
;
system
(
"rm $TopDir/$_"
) and
die
"rm '$_' failed: $?"
;
undef
}
: 1
} `find t -type f`
or
die
"Could not detect testfiles\n"
;
print
"done\n"
if
$Verbose
;
}
my
$BinDir
;
my
@BinFiles
;
my
$TopBinDir
;
BIN: {
$BinDir
= -d
'bin'
?
'bin'
:
-d
'scripts'
?
'scripts'
:
undef
;
unless
(
$BinDir
) {
print
"No bin/ or scripts/ directory found\n"
if
$Verbose
;
last
BIN;
}
my
$TopBinDir
=
"$TopDir/$BinDir/"
;
print
"Copying $BinDir/* files to $TopBinDir..."
if
$Verbose
;
my
$CopyCmd
=
"cp -fR $CPV $BinDir $TopDir"
;
print
"Running '$CopyCmd'..."
if
$Verbose
;
system
(
$CopyCmd
) &&
die
"Copy of $BinDir failed: $?"
;
@BinFiles
=
map
{
chomp
; s|^
$TopDirRe
||; s|//|/|g;
$_
}
grep
{
$ExcludeRe
&&
$_
=~
$ExcludeRe
?
do
{
warn
"Removing $_\n"
;
system
(
"rm $TopDir/$_"
) and
die
"rm '$_' failed: $?"
;
undef
}
: 1
} `find
$BinDir
-type f`
or
die
"Could not detect binfiles\n"
;
print
"done\n"
if
$Verbose
;
}
my
@Changes
;
foreach
my
$cl
(
split
m/\s+/ =>
$Changes
) {
-f
$cl
or
next
;
push
@Changes
,
$cl
;
print
"Copying $cl files to $TopDir..."
if
$Verbose
;
system
(
"cp -f $CPV $cl $TopDir"
)
and
die
"Copy of $cl failed: $?"
;
}
my
@NewFiles
;
my
@ChangedFiles
;
{
for
my
$bin
(
map
{ basename(
$_
) }
@BinFiles
) {
print
"Registering $bin with system files...\n"
;
{
my
$file
=
'installperl'
;
unless
( `
grep
$TestBin
$Repo
/
$file
|
grep
$bin
` ) {
print
" Adding $bin to $file..."
if
$Verbose
;
system
(
"$^X -pi -e 's/($TestBin\\|)/$bin|\$1/' $Repo/$file"
)
and
die
"Could not add $bin to $file: $?"
;
print
"done\n"
if
$Verbose
;
push
@ChangedFiles
,
$file
;
}
else
{
print
" $bin already mentioned in $file\n"
if
$Verbose
;
}
}
{
my
$file
=
'utils.lst'
;
unless
( `
grep
$bin
$Repo
/
$file
` ) {
print
" Adding $bin to $file..."
if
$Verbose
;
system
(
"$^X -pi -e 's!($TestBin)!\$1\nutils/$bin!' $Repo/$file"
)
and
die
"Could not add $bin to $file: $?"
;
print
"done\n"
if
$Verbose
;
push
@ChangedFiles
,
$file
;
}
else
{
print
" $bin already mentioned in $file\n"
if
$Verbose
;
}
}
{
my
$src
=
"utils/${TestBin}.PL"
;
my
$file
=
"utils/${bin}.PL"
;
unless
( -e
"$Repo/$file"
) {
print
" Creating $file..."
if
$Verbose
;
system
(
"cp -f $Repo/$src $Repo/$file"
)
and
die
"Could not create $file from $src: $?"
;
my
$updir
=
join
' '
, (
split
(
'/'
,
$RelTopDir
),
$BinDir
);
system
(
"$^X -pi -e'"
.
's/^(.*?File::Spec->updir, qw\[).+?(\].*)$/'
.
"\$1 $updir \$2/' $Repo/$file"
) and
die
"Could not fix updir for $bin in $file: $?"
;
system
(
"$^X -pi -e's/$TestBin/$bin/' $Repo/$file"
)
and
die
"Could not update $file with '$bin' as name: $?"
;
print
"done\n"
if
$Verbose
;
}
else
{
print
" $file already exists\n"
if
$Verbose
;
}
push
@NewFiles
,
$file
;
}
{
my
$file
=
"utils/Makefile.PL"
;
unless
( `
grep
$bin
$Repo
/
$file
` ) {
print
" Adding $bin entries to $file..."
if
$Verbose
;
system
(
"$^X -pi -e'/^pl\\s+=/ && s/(${TestBin}.PL)/"
.
"\$1 ${bin}.PL/' $Repo/$file"
) and
die
"Could not add $bin to the pl = entry: $?"
;
system
(
"$^X -pi -e'/^plextract\\s+=/ "
.
"&& s/(${TestBin})/\$1 $bin/' $Repo/$file"
) and
die
"Could not add $bin to the plextract = entry: $?"
;
system
(
"$^X -pi -e'/^plextractexe\\s+=/ "
.
"&& s!(\./${TestBin})!\$1 ./$bin!' $Repo/$file"
) and
die
"Could not add $bin to the plextractexe = entry: $?"
;
system
(
"$^X -pi -e'/^(${TestBin}:.+)/; \$x=\$1 or next;"
.
"\$x =~ s/$TestBin/$bin/g;"
.
'$_.=$/.$x.$/;'
.
"' $Repo/$file"
) and
die
"Could not add $bin as a make directive: $?"
;
push
@ChangedFiles
,
$file
;
print
"done\n"
if
$Verbose
;
}
else
{
print
" $bin already added to $file\n"
if
$Verbose
;
}
}
for
my
$file
(
qw[win32/Makefile]
) {
unless
( `
grep
$bin
$Repo
/
$file
` ) {
print
" Adding $bin entries to $file..."
if
$Verbose
;
system
(
"$^X -pi -e'/^(.+?utils.${TestBin}.+)/;"
.
'$x=$1 or next;'
.
"\$x =~ s/$TestBin/$bin/g;"
.
'$_.=$x.$/;'
.
"' $Repo/$file"
) and
die
"Could not add $bin to UTILS section in $file: $?\n"
;
system
(
"$^X -pi -e's/( $TestBin)/\$1 $bin/' $Repo/$file"
)
and
die
"Could not add $bin to $file: $?\n"
;
push
@ChangedFiles
,
$file
;
print
"done\n"
if
$Verbose
;
}
else
{
print
" $bin already added to $file\n"
if
$Verbose
;
}
}
{
my
$file
=
'vms/descrip_mms.template'
;
unless
( `
grep
$bin
$Repo
/
$file
` ) {
print
$/.$/;
print
" WARNING! You should add entries like the following\n"
.
" to $file (Using $TestBin as an example)\n"
.
" Unfortunately I don't understand what these entries\n"
.
" do, so I won't change them automatically:\n\n"
;
print
`
grep
-nC1
$TestBin
$Repo
/
$file
`;
print
$/.$/;
}
else
{
print
" $bin already added to $file\n"
if
$Verbose
;
}
}
}
}
{
my
$file
=
$Repo
.
'/MANIFEST'
;
my
@manifest
;
{
open
my
$fh
,
'<'
,
$file
or
die
"Could not open $file: $!"
;
@manifest
= <
$fh
>;
close
$fh
;
}
my
%pkg_files
;
for
(
@ModFiles
) {
$pkg_files
{
$_
} =
"$_\t$ModName\n"
;
}
for
(
@TestFiles
) {
$pkg_files
{
"$RelTopDir/$_"
} =
"$RelTopDir/$_\t$ModName tests\n"
}
for
(
@BinFiles
) {
$pkg_files
{
"$RelTopDir/$_"
} =
"$RelTopDir/$_\tthe "
.
basename(
$_
) .
" utility\n"
;
}
for
(
@Changes
) {
$pkg_files
{
"$RelTopDir/$_"
} =
"$RelTopDir/$_\t$ModName change log\n"
;
}
for
(
@NewFiles
) {
$pkg_files
{
$_
} =
"$_\tthe "
.
do
{ m/(.+?)\.PL$/; basename($1) } .
" utility\n"
}
delete
$pkg_files
{ [
split
]->[0] }
for
@manifest
;
print
"Adding the following entries to the MANIFEST:\n"
if
$Verbose
;
print
"\t$_"
for
sort
values
%pkg_files
;
print
$/.$/;
push
@manifest
,
values
%pkg_files
;
{
chmod
0644,
$file
;
open
my
$fh
,
'>'
,
$file
or
die
"Could not open $file for writing: $!"
;
print
$fh
map
{
$_
->[0] }
sort
{
$a
->[1] cmp
$b
->[1] ||
$a
->[0] cmp
$b
->[0] }
map
{
my
$f
=
lc
$_
;
$f
=~ s/[^a-z0-9\s]//g; [
$_
,
$f
] }
@manifest
;
close
$fh
;
}
push
@ChangedFiles
,
'MANIFEST'
;
}
if
(
$RunDiff
) {
if
(
$NoBranch
) {
my
$diff
=
$Repo
;
$diff
=~ s/$$/patch/;
my
$master
= basename(
$OrigRepo
);
my
$repo
= basename(
$Repo
);
my
$chdir
= dirname(
$OrigRepo
);
my
$cmd
=
"cd $chdir; diff -ruN --exclude=.patch $master $repo > $diff"
;
print
"Running: '$cmd'\n"
;
print
"Generating diff..."
if
$Verbose
;
system
(
$cmd
);
die
"Could not write diff to '$diff'"
unless
-e
$diff
&& -s _;
print
"done\n"
if
$Verbose
;
print
"\nDiff can be applied with patch -p1 in $OrigRepo\n\n"
;
print
" Diff written to: $diff\n\n"
if
$Verbose
;
}
else
{
my
$diff
=
"$Repo/$BranchName"
;
$diff
=~ s/$$/patch/;
my
$cmd
=
"cd $Repo; git diff > $diff"
;
print
"Running: '$cmd'\n"
;
print
"Generating diff..."
if
$Verbose
;
system
(
$cmd
);
die
"Could not write diff to '$diff'"
unless
-e
$diff
&& -s _;
print
"done\n"
if
$Verbose
;
print
" Diff written to: $diff\n\n"
if
$Verbose
;
}
}
unless
(
$NoBranch
) {
chdir
$Repo
;
system
(
"git add $CPV $_"
)
for
(
@LibFiles
,
@NewFiles
,
@ChangedFiles
,
map
{
"$RelTopDir/$_"
}
@TestFiles
,
@BinFiles
,
@Changes
);
}
chdir
$Cwd
;
sub
usage {
my
$me
= basename($0);
return
qq[
Usage: $me -r PERL_REPO_DIR [-p PACKAGE_DIR]
[-v] [-d] [-e REGEX]
Options:
-r Path to perl-core git repository
-v Run verbosely
-c File containing changelog (
default
'Changes'
or
'ChangeLog'
)
-e Perl regex matching files that shouldn't be included
-d Create a diff as patch file
-p Path to the
package
to add. Defaults to cwd()
-n No branching; repository is not a git repo
\n];
}