use
vars
qw( $VERSION $VERBOSE @EXPORT_OK)
;
$VERSION
=
'0.01'
;
$VERBOSE
= 0;
my
$vms_mode
;
my
$vms_lower_case
;
BEGIN {
$vms_mode
= 0;
$vms_lower_case
= 0;
if
( $^O eq
'VMS'
) {
VMS::Filespec->
import
;
$vms_mode
= 1;
$vms_lower_case
= 1;
my
$vms_efs_case
= 0;
my
$unix_rpt
= 0;
$unix_rpt
= VMS::Feature::current(
"filename_unix_report"
);
$vms_efs_case
= VMS::Feature::current(
"efs_case_preserve"
);
}
else
{
my
$env_unix_rpt
=
$ENV
{
'DECC$FILENAME_UNIX_REPORT'
} ||
''
;
$unix_rpt
=
$env_unix_rpt
=~ /^[ET1]/i;
my
$efs_case
=
$ENV
{
'DECC$EFS_CASE_PRESERVE'
} ||
''
;
$vms_efs_case
=
$efs_case
=~ /^[ET1]/i;
}
$vms_mode
= 0
if
$unix_rpt
;
$vms_lower_case
= 0
if
$vms_efs_case
;
}
}
BEGIN {
*{
import
} = \
&Exporter::import
;
@EXPORT_OK
=
qw(
undent
)
;
}
sub
undent {
my
(
$string
) =
@_
;
my
(
$space
) =
$string
=~ m/^(\s+)/;
$string
=~ s/^
$space
//gm;
return
(
$string
);
}
sub
chdir_all ($) {
chdir
(
'/'
)
if
$^O eq
'os2'
;
chdir
shift
;
}
END { chdir_all(MBTest->original_cwd); }
sub
new {
my
$self
=
bless
{},
shift
;
$self
->
reset
(
@_
);
}
sub
reset
{
my
$self
=
shift
;
my
%options
=
@_
;
$options
{name} ||=
'Simple'
;
$options
{version} ||=
q{'0.01'}
;
$options
{license} ||=
'perl'
;
$options
{dir} = File::Spec->rel2abs(
defined
$options
{dir} ?
$options
{dir} : MBTest->tmpdir
);
my
%data
= (
no_manifest
=> 0,
xs
=> 0,
inc
=> 0,
%options
,
);
%$self
=
%data
;
tie
%{
$self
->{filedata}},
'Tie::CPHash'
;
tie
%{
$self
->{pending}{change}},
'Tie::CPHash'
;
if
( -d
$self
->dirname ) {
warn
"Warning: Removing existing directory '@{[$self->dirname]}'\n"
;
File::Path::rmtree(
$self
->dirname );
}
File::Path::mkpath(
$self
->dirname );
$self
->_gen_default_filedata();
return
$self
;
}
sub
remove {
my
$self
=
shift
;
$self
->chdir_original
if
(
$self
->did_chdir);
File::Path::rmtree(
$self
->dirname );
return
$self
;
}
sub
revert {
my
(
$self
,
$file
) =
@_
;
if
(
defined
$file
) {
delete
$self
->{filedata}{
$file
};
delete
$self
->{pending}{
$_
}{
$file
}
for
qw/change remove/
;
}
else
{
delete
$self
->{filedata}{
$_
}
for
keys
%{
$self
->{filedata} };
for
my
$pend
(
qw/change remove/
) {
delete
$self
->{pending}{
$pend
}{
$_
}
for
keys
%{
$self
->{pending}{
$pend
} };
}
}
$self
->_gen_default_filedata;
}
sub
_gen_default_filedata {
my
$self
=
shift
;
my
$add_unless
=
sub
{
my
$self
=
shift
;
my
(
$member
,
$data
) =
@_
;
$self
->add_file(
$member
,
$data
)
unless
(
$self
->{filedata}{
$member
});
};
if
( !
$self
->{inc} ) {
$self
->
$add_unless
(
'Build.PL'
, undent(
<<" ---"));
use strict;
use Module::Build;
my \$builder = Module::Build->new(
module_name => '$self->{name}',
license => '$self->{license}',
);
\$builder->create_build_script();
---
}
else
{
$self
->
$add_unless
(
'Build.PL'
, undent(
<<" ---"));
use strict;
use inc::latest 'Module::Build';
my \$builder = Module::Build->new(
module_name => '$self->{name}',
license => '$self->{license}',
);
\$builder->create_build_script();
---
}
my
$module_filename
=
join
(
'/'
, (
'lib'
,
split
(/::/,
$self
->{name})) ) .
'.pm'
;
unless
(
$self
->{xs} ) {
$self
->
$add_unless
(
$module_filename
, undent(
<<" ---"));
package $self->{name};
use vars qw( \$VERSION );
\$VERSION = $self->{version};
use strict;
1;
__END__
=head1 NAME
$self->{name} - Perl extension for blah blah blah
=head1 DESCRIPTION
Stub documentation for $self->{name}.
=head1 AUTHOR
A. U. Thor, a.u.thor\@a.galaxy.far.far.away
=cut
---
$self
->
$add_unless
(
't/basic.t'
, undent(
<<" ---"));
use Test::More tests => 1;
use strict;
use $self->{name};
ok 1;
---
}
else
{
$self
->
$add_unless
(
$module_filename
, undent(
<<" ---"));
package $self->{name};
use strict;
use warnings;
our \$VERSION = $self->{version};
require Exporter;
require DynaLoader;
our \@ISA = qw(Exporter DynaLoader);
our \@EXPORT_OK = qw( okay );
bootstrap $self->{name} \$VERSION;
1;
__END__
=head1 NAME
$self->{name} - Perl extension for blah blah blah
=head1 DESCRIPTION
Stub documentation for $self->{name}.
=head1 AUTHOR
A. U. Thor, a.u.thor\@a.galaxy.far.far.away
=cut
---
my
$xs_filename
=
join
(
'/'
, (
'lib'
,
split
(/::/,
$self
->{name})) ) .
'.xs'
;
$self
->
$add_unless
(
$xs_filename
, undent(
<<" ---"));
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
MODULE = $self->{name} PACKAGE = $self->{name}
SV *
okay()
CODE:
RETVAL = newSVpv( "ok", 0 );
OUTPUT:
RETVAL
const char *
xs_version()
CODE:
RETVAL = XS_VERSION;
OUTPUT:
RETVAL
const char *
version()
CODE:
RETVAL = VERSION;
OUTPUT:
RETVAL
---
$self
->
$add_unless
(
'typemap'
, undent(
<<" ---"));
const char *\tT_PV
---
$self
->
$add_unless
(
't/basic.t'
, undent(
<<" ---"));
use Test::More tests => 2;
use strict;
use $self->{name};
ok 1;
ok( $self->{name}::okay() eq 'ok' );
---
}
}
sub
_gen_manifest {
my
$self
=
shift
;
my
$manifest
=
shift
;
open
(
my
$fh
,
'>'
,
$manifest
) or
do
{
die
"Can't write '$manifest'\n"
;
};
my
@files
= (
'MANIFEST'
,
keys
%{
$self
->{filedata}} );
my
$data
=
join
(
"\n"
,
sort
@files
) .
"\n"
;
print
$fh
$data
;
close
(
$fh
);
$self
->{filedata}{MANIFEST} =
$data
;
$self
->{pending}{change}{MANIFEST} = 1;
}
sub
name {
shift
()->{name} }
sub
dirname {
my
$self
=
shift
;
my
$dist
=
$self
->{distdir} ||
join
(
'-'
,
split
( /::/,
$self
->{name} ) );
return
File::Spec->catdir(
$self
->{dir},
$dist
);
}
sub
_real_filename {
my
$self
=
shift
;
my
$filename
=
shift
;
return
File::Spec->catfile(
split
( /\//,
$filename
) );
}
sub
regen {
my
$self
=
shift
;
my
%opts
=
@_
;
my
$dist_dirname
=
$self
->dirname;
if
(
$opts
{clean} ) {
$self
->clean()
if
-d
$dist_dirname
;
}
else
{
my
@files
=
keys
%{
$self
->{pending}{remove}};
foreach
my
$file
(
@files
) {
my
$real_filename
=
$self
->_real_filename(
$file
);
my
$fullname
= File::Spec->catfile(
$dist_dirname
,
$real_filename
);
if
( -e
$fullname
) {
1
while
unlink
(
$fullname
);
}
print
"Unlinking pending file '$file'\n"
if
$VERBOSE
;
delete
(
$self
->{pending}{remove}{
$file
} );
}
}
foreach
my
$file
(
keys
( %{
$self
->{filedata}} ) ) {
my
$real_filename
=
$self
->_real_filename(
$file
);
my
$fullname
= File::Spec->catfile(
$dist_dirname
,
$real_filename
);
if
( ! -e
$fullname
||
( -e
$fullname
&&
$self
->{pending}{change}{
$file
} ) ) {
print
"Changed file '$file'.\n"
if
$VERBOSE
;
my
$dirname
= File::Basename::dirname(
$fullname
);
unless
( -d
$dirname
) {
File::Path::mkpath(
$dirname
) or
do
{
die
"Can't create '$dirname'\n"
;
};
}
if
( -e
$fullname
) {
1
while
unlink
(
$fullname
);
}
open
(
my
$fh
,
'>'
,
$fullname
) or
do
{
die
"Can't write '$fullname'\n"
;
};
print
$fh
$self
->{filedata}{
$file
};
close
(
$fh
);
}
delete
(
$self
->{pending}{change}{
$file
} );
}
my
$manifest
= File::Spec->catfile(
$dist_dirname
,
'MANIFEST'
);
unless
(
$self
->{no_manifest} ) {
if
( -e
$manifest
) {
1
while
unlink
(
$manifest
);
}
$self
->_gen_manifest(
$manifest
);
}
return
$self
;
}
sub
clean {
my
$self
=
shift
;
my
$here
= Cwd::abs_path();
my
$there
= File::Spec->rel2abs(
$self
->dirname() );
if
( -d
$there
) {
chdir
(
$there
) or
die
"Can't change directory to '$there'\n"
;
}
else
{
die
"Distribution not found in '$there'\n"
;
}
my
%names
;
tie
%names
,
'Tie::CPHash'
;
foreach
my
$file
(
keys
%{
$self
->{filedata}} ) {
my
$filename
=
$self
->_real_filename(
$file
);
$filename
=
lc
(
$filename
)
if
$vms_lower_case
;
my
$dirname
= File::Basename::dirname(
$filename
);
$names
{
$filename
} = 0;
print
"Splitting '$dirname'\n"
if
$VERBOSE
;
my
@dirs
= File::Spec->splitdir(
$dirname
);
while
(
@dirs
) {
my
$dir
= (
scalar
(
@dirs
) == 1
?
$dirname
: File::Spec->catdir(
@dirs
) );
if
(
length
$dir
) {
print
"Setting directory name '$dir' in \%names\n"
if
$VERBOSE
;
$names
{
$dir
} = 0;
}
pop
(
@dirs
);
}
}
File::Find::finddepth(
sub
{
my
$name
= File::Spec->canonpath(
$File::Find::name
);
if
(
$vms_mode
) {
if
(
$name
ne
'.'
) {
$name
=~ s/\.\z//;
$name
= vmspath(
$name
)
if
-d
$name
;
}
}
if
($^O eq
'VMS'
) {
$name
= File::Spec->rel2abs(
$name
)
if
$name
eq File::Spec->curdir();
}
if
( not
exists
$names
{
$name
} ) {
print
"Removing '$name'\n"
if
$VERBOSE
;
File::Path::rmtree(
$_
);
}
}, ($^O eq
'VMS'
?
'./'
: File::Spec->curdir) );
chdir_all(
$here
);
return
$self
;
}
sub
add_file {
my
$self
=
shift
;
$self
->change_file(
@_
);
}
sub
remove_file {
my
$self
=
shift
;
my
$file
=
shift
;
unless
(
exists
$self
->{filedata}{
$file
} ) {
warn
"Can't remove '$file': It does not exist.\n"
if
$VERBOSE
;
}
delete
(
$self
->{filedata}{
$file
} );
$self
->{pending}{remove}{
$file
} = 1;
return
$self
;
}
sub
change_build_pl {
my
(
$self
,
@opts
) =
@_
;
my
$opts
=
ref
$opts
[0] eq
'HASH'
?
$opts
[0] : {
@opts
};
local
$Data::Dumper::Terse
= 1;
(
my
$args
= Dumper(
$opts
)) =~ s/^\s*\{|\}\s*$//g;
$self
->change_file(
'Build.PL'
, undent(
<<" ---") );
use strict;
use Module::Build;
my \$b = Module::Build->new(
# Some CPANPLUS::Dist::Build versions need to allow mismatches
# On logic: thanks to Module::Install, CPAN.pm must set both keys, but
# CPANPLUS sets only the one
allow_mb_mismatch => (
\$ENV{PERL5_CPANPLUS_IS_RUNNING} && ! \$ENV{PERL5_CPAN_IS_RUNNING} ? 1 : 0
),
$args
);
\$b->create_build_script();
---
return
$self
;
}
sub
change_file {
my
$self
=
shift
;
my
$file
=
shift
;
my
$data
=
shift
;
$self
->{filedata}{
$file
} =
$data
;
$self
->{pending}{change}{
$file
} = 1;
return
$self
;
}
sub
get_file {
my
$self
=
shift
;
my
$file
=
shift
;
exists
(
$self
->{filedata}{
$file
}) or croak(
"no such entry: '$file'"
);
return
$self
->{filedata}{
$file
};
}
sub
chdir_in {
my
$self
=
shift
;
$self
->{original_dir} ||= Cwd::cwd;
my
$dir
=
$self
->dirname;
chdir
(
$dir
) or
die
"Can't chdir to '$dir': $!"
;
return
$self
;
}
sub
did_chdir {
exists
shift
()->{original_dir} }
sub
chdir_original {
my
$self
=
shift
;
my
$dir
=
delete
$self
->{original_dir};
chdir_all(
$dir
) or
die
"Can't chdir to '$dir': $!"
;
return
$self
;
}
sub
new_from_context {
my
(
$self
,
@args
) =
@_
;
return
Module::Build->new_from_context(
quiet
=> 1,
@args
);
}
sub
run_build_pl {
my
(
$self
,
@args
) =
@_
;
return
Module::Build->run_perl_script(
'Build.PL'
, [], [
@args
])
}
sub
run_build {
my
(
$self
,
@args
) =
@_
;
my
$build_script
= $^O eq
'VMS'
?
'Build.com'
:
'Build'
;
return
Module::Build->run_perl_script(
$build_script
, [], [
@args
])
}
1;
__END__