summaryrefslogtreecommitdiffstats
path: root/Bugzilla.pm
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla.pm')
-rw-r--r--Bugzilla.pm84
1 files changed, 61 insertions, 23 deletions
diff --git a/Bugzilla.pm b/Bugzilla.pm
index 221a64f76..2761c9fc7 100644
--- a/Bugzilla.pm
+++ b/Bugzilla.pm
@@ -34,7 +34,6 @@ use Bugzilla::Extension;
use Bugzilla::Field;
use Bugzilla::Flag;
use Bugzilla::Install::Localconfig qw(read_localconfig);
-use Bugzilla::Install::Requirements qw(OPTIONAL_MODULES have_vers);
use Bugzilla::Install::Util qw(init_console include_languages i_am_persistent);
use Bugzilla::Memcached;
use Bugzilla::Template;
@@ -47,6 +46,7 @@ use File::Spec::Functions;
use DateTime::TimeZone;
use Date::Parse;
use Safe;
+use List::Util qw(first);
#####################################################################
# Constants
@@ -245,32 +245,66 @@ sub api_server {
return $cache->{api_server};
}
+use constant _CAN_HAS_FEATURE => eval {
+ require CPAN::Meta;
+ require Module::Runtime;
+ require CPAN::Meta::Check;
+ Module::Runtime->import(qw(require_module));
+ CPAN::Meta::Check->import(qw(verify_dependencies));
+ 1;
+ };
+
sub feature {
- my ($class, $feature) = @_;
+ my ($class, $feature_name) = @_;
+ return 0 unless _CAN_HAS_FEATURE;
+ return unless $class->has_feature($feature_name);
+
+ my $cache = $class->request_cache;
+ my $feature = $cache->{feature_map}{$feature_name};
+ # Bugzilla expects this will also load all the modules.. so we have to do that.
+ # Later we should put a deprecation warning here, and favor calling has_feature().
+
+ return 1 if $cache->{feature_loaded}{$feature_name};
+ my @modules = $feature->requirements_for('runtime', 'requires')->required_modules;
+ require_module($_) foreach @modules;
+ $cache->{feature_loaded}{$feature_name} = 1;
+ return 1;
+}
+
+sub has_feature {
+ my ($class, $feature_name) = @_;
+
+ return 0 unless _CAN_HAS_FEATURE;
+
my $cache = $class->request_cache;
- return $cache->{feature}->{$feature}
- if exists $cache->{feature}->{$feature};
-
- my $feature_map = $cache->{feature_map};
- if (!$feature_map) {
- foreach my $package (@{ OPTIONAL_MODULES() }) {
- foreach my $f (@{ $package->{feature} }) {
- $feature_map->{$f} ||= [];
- push(@{ $feature_map->{$f} }, $package);
+ return $cache->{feature}->{$feature_name}
+ if exists $cache->{feature}->{$feature_name};
+
+ my $dir = bz_locations()->{libpath};
+ my $feature_map = $cache->{feature_map} //= do {
+ my @meta_json = map { File::Spec->catfile($dir, $_) } qw( MYMETA.json META.json );
+ my $file = first { -f $_ } @meta_json;
+ my %map;
+ if ($file) {
+ open my $meta_fh, '<', $file or die "unable to open $file: $!";
+ my $str = do { local $/ = undef; scalar <$meta_fh> };
+ trick_taint($str);
+ close $meta_fh;
+
+ my $meta = CPAN::Meta->load_json_string($str);
+
+ foreach my $feature ($meta->features) {
+ $map{$feature->identifier} = $feature->prereqs;
}
}
- $cache->{feature_map} = $feature_map;
- }
- if (!$feature_map->{$feature}) {
- ThrowCodeError('invalid_feature', { feature => $feature });
- }
+ \%map;
+ };
- my $success = 1;
- foreach my $package (@{ $feature_map->{$feature} }) {
- have_vers($package) or $success = 0;
- }
- $cache->{feature}->{$feature} = $success;
+ ThrowCodeError('invalid_feature', { feature => $feature_name }) if !$feature_map->{$feature_name};
+ my $success = !verify_dependencies($feature_map->{$feature_name}, 'runtime', 'requires');
+
+ $cache->{feature}{$feature_name} = $success;
return $success;
}
@@ -1015,8 +1049,12 @@ this Bugzilla installation.
=item C<feature>
-Tells you whether or not a specific feature is enabled. For names
-of features, see C<OPTIONAL_MODULES> in C<Bugzilla::Install::Requirements>.
+Wrapper around C<has_feature()> that also loads all of required modules into the runtime.
+
+=item C<has_feature>
+
+Consults F<MYMETA.yml> for optional Bugzilla features and returns true if all the requirements
+are installed.
=item C<api_server>