sub
new {
my
(
$class
,
$main
,
$opts
) =
@_
;
confess(
'No main entry point defined'
)
unless
$main
;
confess(
'No output file specified'
)
unless
$opts
->{
'output'
};
return
bless
{
'main'
=>
$main
,
'output'
=>
$opts
->{
'output'
},
'header'
=>
$opts
->{
'header'
},
'desc'
=>
$opts
->{
'desc'
},
'modules'
=> {},
'libdirs'
=> {}
},
$class
;
}
sub
_module_path {
my
(
$module
) =
@_
;
my
$pat
=
qr/[a-z0-9_]*/
i;
confess(
'Invalid module name'
)
unless
$module
=~ /^
$pat
(::
$pat
)*$/i;
my
@path_components
=
split
/::/,
$module
;
$path_components
[-1] .=
'.pm'
;
return
Filesys::POSIX::Path->full(
join
(
'/'
,
@path_components
) );
}
sub
add_module {
my
(
$self
,
$file
,
$name
) =
@_
;
my
$short_module_path
= _module_path(
$name
);
my
$bundle_module_path
=
"lib/$short_module_path"
;
my
$libdir
= Filesys::POSIX::Path->full(
$file
);
$libdir
=~ s/\/
$short_module_path
$//;
$self
->{
'libdirs'
}->{
$libdir
} = 1;
$self
->{
'modules'
}->{
$bundle_module_path
} =
$file
;
}
sub
add_dist {
my
(
$self
,
$dist
) =
@_
;
confess(
"Cannot add unprepared dist $dist->{'path'} to bundle"
)
unless
$dist
->prepared;
foreach
my
$path
( @{
$dist
->modules } ) {
my
$file
=
"$dist->{'basedir'}/$path"
;
$self
->{
'modules'
}->{
$path
} =
$file
;
}
$self
->{
'libdirs'
}->{
$dist
->libdir } = 1;
}
sub
libdirs {
my
(
$self
) =
@_
;
return
sort
keys
%{
$self
->{
'libdirs'
} };
}
sub
check {
my
(
$self
) =
@_
;
my
@dirs
=
@INC
;
push
@dirs
,
$self
->libdirs;
local
$ENV
{
'PERL5LIB'
} =
join
(
':'
,
@dirs
);
confess(
"Main entry point $self->{'main'} not found"
)
unless
-f
$self
->{
'main'
};
unless
( Build::PPK::Exec->silent( $^X,
'-c'
,
$self
->{
'main'
} ) == 0 ) {
confess(
"Errors while checking $self->{'main'}: $@"
);
}
}
sub
prepare {
my
(
$self
) =
@_
;
my
$fs
= Filesys::POSIX->new(
Filesys::POSIX::Mem->new,
'noatime'
=> 1
);
foreach
my
$dir
(
qw(lib scripts)
) {
$fs
->
mkdir
(
$dir
);
}
$fs
->
map
(
$self
->{
'main'
},
'scripts/main.pl'
);
foreach
my
$bundle_module_path
(
keys
%{
$self
->{
'modules'
} } ) {
my
$file
=
$self
->{
'modules'
}->{
$bundle_module_path
};
my
$path
= Filesys::POSIX::Path->new(
$bundle_module_path
);
$fs
->mkpath(
$path
->dirname );
$fs
->
map
(
$file
,
$path
->full );
}
return
$fs
;
}
sub
assemble {
my
(
$self
,
$fs
) =
@_
;
my
$stub
= File::ShareDir::dist_file(
'Build-PPK'
,
'stub.pl'
);
my
$output_fh
;
unless
(
sysopen
(
$output_fh
,
$self
->{
'output'
},
&Fcntl::O_CREAT
|
&Fcntl::O_TRUNC
|
&Fcntl::O_WRONLY
, 0755 ) ) {
confess(
"Unable to open $self->{'output'} for writing: $!"
);
}
print
{
$output_fh
}
"#! /usr/bin/perl\n"
;
if
(
$self
->{
'header'
} ) {
open
(
my
$header_fh
,
'<'
,
$self
->{
'header'
} ) or confess(
"Unable to open $self->{'header'} for reading: $!"
);
while
(
my
$line
=
readline
(
$header_fh
) ) {
chomp
$line
;
$line
=~ s/\
$Desc
\$/\
$Desc
:
$self
->{
'desc'
}\$/g
if
$self
->{
'desc'
};
print
{
$output_fh
}
"$line\n"
;
}
close
$header_fh
;
}
print
{
$output_fh
}
"\n"
;
open
(
my
$stub_fh
,
'<'
,
$stub
) or confess(
"Unable to open stub $stub for reading: $!"
);
while
(
my
$len
=
read
(
$stub_fh
,
my
$buf
, 4096 ) ) {
print
{
$output_fh
}
$buf
;
}
close
$stub_fh
;
my
$pipeline
= Build::PPK::Pipeline->
open
(
sub
{
$fs
->tar( Filesys::POSIX::IO::Handle->new( \
*STDOUT
),
'.'
);
},
sub
{
exec
'gzip'
or confess(
"Unable to exec() gzip: $!"
);
},
sub
{
while
(
my
$len
=
read
( STDIN,
my
$buf
, 4047 ) ) {
print
{
$output_fh
} MIME::Base64::encode_base64(
$buf
);
}
}
);
$pipeline
->
close
;
close
$output_fh
;
}
1;