Alien-Build
view release on metacpan or search on metacpan
lib/Alien/Build.pm view on Meta::CPAN
);
};
$error = $@;
$type = 'share' unless defined $type;
}
if($error)
{
if($env eq 'system')
{
die $error;
}
$self->log("error in probe (will do a share install): $@");
$self->log("Don't panic, we will attempt a share build from source if possible.");
$self->log("Do not file a bug unless you expected a system install to succeed.");
$type = 'share';
}
if($env && $env ne $type)
{
die "requested $env install not available";
}
if($type !~ /^(system|share)$/)
{
Carp::croak "probe hook returned something other than system or share: $type";
}
if($type eq 'share' && (!$self->meta_prop->{network}) && (!$self->meta_prop->{local_source}))
{
$self->log("install type share requested or detected, but network fetch is turned off");
$self->log("see https://metacpan.org/pod/Alien::Build::Manual::FAQ#Network-fetch-is-turned-off");
Carp::croak "network fetch is turned off";
}
$self->runtime_prop->{install_type} = $type;
$type;
}
sub download
{
my($self) = @_;
return $self unless $self->install_type eq 'share';
return $self if $self->install_prop->{complete}->{download};
if($self->meta->has_hook('download'))
{
my $tmp;
local $CWD;
my $valid = 0;
$self->_call_hook(
{
before => sub {
$tmp = Alien::Build::TempDir->new($self, "download");
$CWD = "$tmp";
},
verify => sub {
my @list = grep { $_->basename !~ /^\./, } _path('.')->children;
my $count = scalar @list;
if($count == 0)
{
die "no files downloaded";
}
elsif($count == 1)
{
my($archive) = $list[0];
if(-d $archive)
{
# TODO: this is probably a bug that we don't set
# download or compelte properties?
$self->log("single dir, assuming directory");
}
else
{
$self->log("single file, assuming archive");
}
$self->install_prop->{download} = $archive->absolute->stringify;
$self->install_prop->{complete}->{download} = 1;
$valid = 1;
}
else
{
$self->log("multiple files, assuming directory");
$self->install_prop->{complete}->{download} = 1;
$self->install_prop->{download} = _path('.')->absolute->stringify;
$valid = 1;
}
},
after => sub {
$CWD = $self->root;
},
},
'download',
);
# experimental and undocumented for now
if($self->meta->has_hook('check_download'))
{
$self->meta->call_hook(check_download => $self);
}
return $self if $valid;
}
else
{
# This will call the default download hook
# defined in Core::Download since the recipe
# does not provide a download hook
my $ret = $self->_call_hook('download');
# experimental and undocumented for now
if($self->meta->has_hook('check_download'))
{
$self->meta->call_hook(check_download => $self);
}
lib/Alien/Build.pm view on Meta::CPAN
{
$self->log("warning: extract received no download details for $archive");
}
if($self->download_rule eq 'digest')
{
die "required digest missing for $archive" unless $checked_digest;
}
elsif($self->download_rule eq 'encrypt')
{
die "file was fetched insecurely for $archive" unless $encrypted_fetch;
}
elsif($self->download_rule eq 'digest_or_encrypt')
{
die "file was fetched insecurely and required digest missing for $archive" unless $checked_digest || $encrypted_fetch;
}
elsif($self->download_rule eq 'digest_and_encrypt')
{
die "file was fetched insecurely and required digest missing for $archive" unless $checked_digest || $encrypted_fetch;
die "required digest missing for $archive" unless $checked_digest;
die "file was fetched insecurely for $archive" unless $encrypted_fetch;
}
elsif($self->download_rule eq 'warn')
{
unless($checked_digest || $encrypted_fetch)
{
$self->log("!!! NOTICE OF FUTURE CHANGE IN BEHAVIOR !!!");
$self->log("a future version of Alien::Build will die here by default with this exception: file was fetched insecurely and required digest missing for $archive");
$self->log("!!! NOTICE OF FUTURE CHANGE IN BEHAVIOR !!!");
}
}
else
{
die "internal error, unknown download rule: @{[ $self->download_rule ]}";
}
}
my $nick_name = 'build';
if($self->meta_prop->{out_of_source})
{
$nick_name = 'extract';
my $extract = $self->install_prop->{extract};
return $extract if defined $extract && -d $extract;
}
my $tmp;
local $CWD;
my $ret;
$self->_call_hook({
before => sub {
# called build instead of extract, because this
# will be used for the build step, and technically
# extract is a substage of build anyway.
$tmp = Alien::Build::TempDir->new($self, $nick_name);
$CWD = "$tmp";
},
verify => sub {
my $path = '.';
if($self->meta_prop->{out_of_source} && $self->install_prop->{extract})
{
$path = $self->install_prop->{extract};
}
my @list = grep { $_->basename !~ /^\./ && $_->basename ne 'pax_global_header' } _path($path)->children;
my $count = scalar @list;
if($count == 0)
{
die "no files extracted";
}
elsif($count == 1 && -d $list[0])
{
$ret = $list[0]->absolute->stringify;
}
else
{
$ret = "$tmp";
}
},
after => sub {
$CWD = $self->root;
},
}, 'extract', $archive);
$self->install_prop->{extract} ||= $ret;
$ret ? $ret : ();
}
sub build
{
my($self) = @_;
# save the evironment, in case some plugins decide
# to alter it. Or us! See just a few lines below.
local %ENV = %ENV;
my $stage = _path($self->install_prop->{stage});
$stage->mkpath;
my $tmp;
if($self->install_type eq 'share')
{
foreach my $suffix ('', '_ffi')
{
local $CWD;
delete $ENV{DESTDIR} unless $self->meta_prop->{destdir};
my %env_meta = %{ $self->meta_prop ->{env} || {} };
my %env_inst = %{ $self->install_prop->{env} || {} };
if($self->meta_prop->{env_interpolate})
lib/Alien/Build.pm view on Meta::CPAN
$code->(@_);
$ret;
}
);
}
sub before_hook
{
my($self, $name, $code) = @_;
$self->around_hook(
$name => sub {
my $orig = shift;
$code->(@_);
my $ret = $orig->(@_);
$ret;
}
);
}
sub call_hook
{
my $self = shift;
my %args = ref $_[0] ? %{ shift() } : ();
my($name, @args) = @_;
my $error;
my @hooks = @{ $self->{hook}->{$name} || []};
if(@hooks == 0)
{
if(defined $self->{default_hook}->{$name})
{
@hooks = ($self->{default_hook}->{$name})
}
elsif(!$args{all})
{
Carp::croak "No hooks registered for $name";
}
}
my $value;
foreach my $hook (@hooks)
{
if(eval { $args[0]->isa('Alien::Build') })
{
%{ $args[0]->{hook_prop} } = (
name => $name,
);
}
my $wrapper = $self->{around}->{$name} || sub { my $code = shift; $code->(@_) };
my $value;
$args{before}->() if $args{before};
if(ref($hook) eq 'CODE')
{
$value = eval {
my $value = $wrapper->(sub { $hook->(@_) }, @args);
$args{verify}->('code') if $args{verify};
$value;
};
}
else
{
$value = $wrapper->(sub {
eval {
$hook->execute(@_);
$args{verify}->('command') if $args{verify};
};
defined $args{ok} ? $args{ok} : 1;
}, @args);
}
$error = $@;
$args{after}->() if $args{after};
if($args{all})
{
die if $error;
}
else
{
next if $error;
next if $args{continue} && $args{continue}->($value);
return $value;
}
}
die $error if $error && ! $args{all};
$value;
}
sub apply_plugin
{
my($self, $name, @args) = @_;
my $class;
my $pm;
my $found;
if($name =~ /^=(.*)$/)
{
$class = $1;
$pm = "$class.pm";
$pm =~ s!::!/!g;
$found = 1;
}
if($name !~ /::/ && !$found)
{
foreach my $inc (@INC)
{
# TODO: allow negotiators to work with @INC hooks
next if ref $inc;
my $file = Path::Tiny->new("$inc/Alien/Build/Plugin/$name/Negotiate.pm");
if(-r $file)
{
$class = "Alien::Build::Plugin::${name}::Negotiate";
$pm = "Alien/Build/Plugin/$name/Negotiate.pm";
$found = 1;
last;
}
}
}
unless($found)
{
$class = "Alien::Build::Plugin::$name";
lib/Alien/Build.pm view on Meta::CPAN
Any property may be used from a command:
probe [ 'some command %{.meta.plugin_fetch_newprotocol_foo}' ];
probe [ 'some command %{.install.plugin_fetch_newprotocol_bar}' ];
probe [ 'some command %{.runtime.plugin_fetch_newprotocol_baz}' ];
probe [ 'some command %{.meta.my_foo}' ];
probe [ 'some command %{.install.my_bar}' ];
probe [ 'some command %{.runtime.my_baz}' ];
=head2 meta_prop
my $href = $build->meta_prop;
my $href = Alien::Build->meta_prop;
Meta properties have to do with the recipe itself, and not any particular
instance that probes or builds that recipe. Meta properties can be changed
from within an L<alienfile> using the C<meta_prop> directive, or from
a plugin from its C<init> method (though should NOT be modified from any
hooks registered within that C<init> method). This is not strictly enforced,
but if you do not follow this rule your recipe will likely be broken.
=over
=item arch
This is a hint to an installer like L<Alien::Build::MM> or L<Alien::Build::MB>,
that the library or tool contains architecture dependent files and so should
be stored in an architecture dependent location. If not specified by your
L<alienfile> then it will be set to true.
=item check_digest
True if cryptographic digest should be checked when files are fetched
or downloaded. This is set by
L<Digest negotiator plugin|Alien::Build::Plugin::Digest::Negotiate>.
=item destdir
Some plugins (L<Alien::Build::Plugin::Build::Autoconf> for example) support
installing via C<DESTDIR>. They will set this property to true if they
plan on doing such an install. This helps L<Alien::Build> find the staged
install files and how to locate them.
If available, C<DESTDIR> is used to stage install files in a sub directory before
copying the files into C<blib>. This is generally preferred method
if available.
=item destdir_filter
Regular expression for the files that should be copied from the C<DESTDIR>
into the stage directory. If not defined, then all files will be copied.
=item destdir_ffi_filter
Same as C<destdir_filter> except applies to C<build_ffi> instead of C<build>.
=item digest
This properties contains the cryptographic digests (if any) that should
be used when verifying any fetched and downloaded files. It is a hash
reference where the key is the filename and the value is an array
reference containing a pair of values, the first being the algorithm
('SHA256' is recommended) and the second is the actual digest. The
special filename C<*> may be specified to indicate that any downloaded
file should match that digest. If there are both real filenames and
the C<*> placeholder, the real filenames will be used for filenames
that match and any other files will use the placeholder. Example:
$build->meta_prop->{digest} = {
'foo-1.00.tar.gz' => [ SHA256 => '9feac593aa49a44eb837de52513a57736457f1ea70078346c60f0bfc5f24f2c1' ],
'foo-1.01.tar.gz' => [ SHA256 => '6bbde6a7f10ae5924cf74afc26ff5b7bc4b4f9dfd85c6b534c51bd254697b9e7' ],
'*' => [ SHA256 => '33a20aae3df6ecfbe812b48082926d55391be4a57d858d35753ab1334b9fddb3' ],
};
Cryptographic signatures will only be checked
if the L<check_digest meta property|/check_digest> is set and if the
L<Digest negotiator plugin|Alien::Build::Plugin::Digest::Negotiate> is loaded.
(The Digest negotiator can be used directly, but is also loaded automatically
if you use the L<digest directive|alienfile/digest> is used by the L<alienfile>).
=item env
Environment variables to override during the build stage.
=item env_interpolate
Environment variable values will be interpolated with helpers. Example:
meta->prop->{env_interpolate} = 1;
meta->prop->{env}->{PERL} = '%{perl}';
=item local_source
Set to true if source code package is available locally. (that is not fetched
over the internet). This is computed by default based on the C<start_url>
property. Can be set by an L<alienfile> or plugin.
=item platform
Hash reference. Contains information about the platform beyond just C<$^O>.
=over 4
=item platform.compiler_type
Refers to the type of flags that the compiler accepts. May be expanded in the
future, but for now, will be one of:
=over 4
=item microsoft
On Windows when using Microsoft Visual C++
=item unix
Virtually everything else, including gcc on windows.
=back
( run in 1.105 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )