use
vars
qw( $VERSION $VERBOSE @EXPORT_OK)
;
$VERSION
=
'0.01'
;
$VERBOSE
= 0;
BEGIN {
if
( $^O eq
'VMS'
) {
VMS::Filespec->
import
;
}
}
BEGIN {
*{
import
} = \
&Exporter::import
;
@EXPORT_OK
=
qw(
undent
)
;
}
sub
undent {
my
(
$string
) =
@_
;
my
(
$space
) =
$string
=~ m/^(\s+)/;
$string
=~ s/^
$space
//gm;
return
(
$string
);
}
sub
new {
my
$package
=
shift
;
my
%options
=
@_
;
$options
{name} ||=
'Simple'
;
$options
{dir} ||= Cwd::cwd();
my
%data
= (
skip_manifest
=> 0,
xs
=> 0,
%options
,
);
my
$self
=
bless
( \
%data
,
$package
);
$self
->{dir} = File::Spec->rel2abs(
$self
->{dir});
tie
%{
$self
->{filedata}},
'Tie::CPHash'
;
tie
%{
$self
->{pending}{change}},
'Tie::CPHash'
;
if
( -d
$self
->dirname ) {
warn
"Warning: Removing existing directory '@{[$self->dirname]}'\n"
;
$self
->remove;
}
$self
->_gen_default_filedata();
return
$self
;
}
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
});
};
$self
->
$add_unless
(
'Build.PL'
, undent(
<<" ---"));
use strict;
use Module::Build;
my \$builder = Module::Build->new(
module_name => '$self->{name}',
license => 'perl',
);
\$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 = '0.01';
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};
\$VERSION = '0.01';
require Exporter;
require DynaLoader;
\@ISA = qw(Exporter DynaLoader);
\@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
(
'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
;
my
$fh
= IO::File->new(
">$manifest"
) or
do
{
$self
->remove();
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
=
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
{
$self
->remove();
die
"Can't create '$dirname'\n"
;
};
}
if
( -e
$fullname
) {
1
while
unlink
(
$fullname
);
}
my
$fh
= IO::File->new(
">$fullname"
) or
do
{
$self
->remove();
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
->{skip_manifest} ) {
if
( -e
$manifest
) {
1
while
unlink
(
$manifest
);
}
$self
->_gen_manifest(
$manifest
);
}
}
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
);
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
($^O eq
'VMS'
) {
$name
=~ s/\.\z//;
$name
= vmspath(
$name
)
if
-d
$name
;
$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
(
$here
);
}
sub
remove {
my
$self
=
shift
;
croak(
"invalid usage -- remove()"
)
if
(
@_
);
$self
->chdir_original
if
(
$self
->did_chdir);
File::Path::rmtree(
$self
->dirname );
croak(
"\nthis test should have used chdir_in()"
)
unless
(Cwd::getcwd);
}
sub
revert {
my
$self
=
shift
;
die
"Unimplemented.\n"
;
}
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;
}
sub
change_build_pl {
my
(
$self
,
$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(
$args
);
\$b->create_build_script();
---
}
sub
change_file {
my
$self
=
shift
;
my
$file
=
shift
;
my
$data
=
shift
;
$self
->{filedata}{
$file
} =
$data
;
$self
->{pending}{change}{
$file
} = 1;
}
sub
chdir_in {
my
$self
=
shift
;
$self
->{original_dir} ||= Cwd::cwd;
my
$dir
=
$self
->dirname;
chdir
(
$dir
) or
die
"Can't chdir to '$dir': $!"
;
}
sub
did_chdir {
my
$self
=
shift
;
return
exists
(
$self
->{original_dir});
}
sub
chdir_original {
my
$self
=
shift
;
croak(
"never called chdir_in()"
)
unless
(
$self
->{original_dir});
my
$dir
=
$self
->{original_dir};
chdir
(
$dir
) or
die
"Can't chdir to '$dir': $!"
;
}
1;
__END__