Bug 1251100 - checksetup.pl no longer tells admins which modules are installed…

Bug 1251100 - checksetup.pl no longer tells admins which modules are installed and which version is installed
parent 516ac2ae
use 5.006;
use strict;
use warnings;
package CPAN::Meta::Feature;
our $VERSION = '2.150005';
use CPAN::Meta::Prereqs;
#pod =head1 DESCRIPTION
#pod
#pod A CPAN::Meta::Feature object describes an optional feature offered by a CPAN
#pod distribution and specified in the distribution's F<META.json> (or F<META.yml>)
#pod file.
#pod
#pod For the most part, this class will only be used when operating on the result of
#pod the C<feature> or C<features> methods on a L<CPAN::Meta> object.
#pod
#pod =method new
#pod
#pod my $feature = CPAN::Meta::Feature->new( $identifier => \%spec );
#pod
#pod This returns a new Feature object. The C<%spec> argument to the constructor
#pod should be the same as the value of the C<optional_feature> entry in the
#pod distmeta. It must contain entries for C<description> and C<prereqs>.
#pod
#pod =cut
sub new {
my ($class, $identifier, $spec) = @_;
my %guts = (
identifier => $identifier,
description => $spec->{description},
prereqs => CPAN::Meta::Prereqs->new($spec->{prereqs}),
);
bless \%guts => $class;
}
#pod =method identifier
#pod
#pod This method returns the feature's identifier.
#pod
#pod =cut
sub identifier { $_[0]{identifier} }
#pod =method description
#pod
#pod This method returns the feature's long description.
#pod
#pod =cut
sub description { $_[0]{description} }
#pod =method prereqs
#pod
#pod This method returns the feature's prerequisites as a L<CPAN::Meta::Prereqs>
#pod object.
#pod
#pod =cut
sub prereqs { $_[0]{prereqs} }
1;
# ABSTRACT: an optional feature provided by a CPAN distribution
=pod
=encoding UTF-8
=head1 NAME
CPAN::Meta::Feature - an optional feature provided by a CPAN distribution
=head1 VERSION
version 2.150005
=head1 DESCRIPTION
A CPAN::Meta::Feature object describes an optional feature offered by a CPAN
distribution and specified in the distribution's F<META.json> (or F<META.yml>)
file.
For the most part, this class will only be used when operating on the result of
the C<feature> or C<features> methods on a L<CPAN::Meta> object.
=head1 METHODS
=head2 new
my $feature = CPAN::Meta::Feature->new( $identifier => \%spec );
This returns a new Feature object. The C<%spec> argument to the constructor
should be the same as the value of the C<optional_feature> entry in the
distmeta. It must contain entries for C<description> and C<prereqs>.
=head2 identifier
This method returns the feature's identifier.
=head2 description
This method returns the feature's long description.
=head2 prereqs
This method returns the feature's prerequisites as a L<CPAN::Meta::Prereqs>
object.
=head1 BUGS
Please report any bugs or feature using the CPAN Request Tracker.
Bugs can be submitted through the web interface at
L<http://rt.cpan.org/Dist/Display.html?Queue=CPAN-Meta>
When submitting a bug or request, please include a test-file or a patch to an
existing test-file that illustrates the bug or desired feature.
=head1 AUTHORS
=over 4
=item *
David Golden <dagolden@cpan.org>
=item *
Ricardo Signes <rjbs@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by David Golden and Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
__END__
# vim: ts=2 sts=2 sw=2 et :
# vi:tw=72
use 5.006;
use strict;
use warnings;
package CPAN::Meta::History;
our $VERSION = '2.150005';
1;
# ABSTRACT: history of CPAN Meta Spec changes
__END__
=pod
=encoding UTF-8
=head1 NAME
CPAN::Meta::History - history of CPAN Meta Spec changes
=head1 VERSION
version 2.150005
=head1 DESCRIPTION
The CPAN Meta Spec has gone through several iterations. It was
originally written in HTML and later revised into POD (though published
in HTML generated from the POD). Fields were added, removed or changed,
sometimes by design and sometimes to reflect real-world usage after the
fact.
This document reconstructs the history of the CPAN Meta Spec based on
change logs, repository commit messages and the published HTML files.
In some cases, particularly prior to version 1.2, the exact version
when certain fields were introduced or changed is inconsistent between
sources. When in doubt, the published HTML files for versions 1.0 to
1.4 as they existed when version 2 was developed are used as the
definitive source.
Starting with version 2, the specification document is part of the
CPAN-Meta distribution and will be published on CPAN as
L<CPAN::Meta::Spec>.
Going forward, specification version numbers will be integers and
decimal portions will correspond to a release date for the CPAN::Meta
library.
=head1 HISTORY
=head2 Version 2
April 2010
=over
=item *
Revised spec examples as perl data structures rather than YAML
=item *
Switched to JSON serialization from YAML
=item *
Specified allowed version number formats
=item *
Replaced 'requires', 'build_requires', 'configure_requires',
'recommends' and 'conflicts' with new 'prereqs' data structure divided
by I<phase> (configure, build, test, runtime, etc.) and I<relationship>
(requires, recommends, suggests, conflicts)
=item *
Added support for 'develop' phase for requirements for maintaining
a list of authoring tools
=item *
Changed 'license' to a list and revised the set of valid licenses
=item *
Made 'dynamic_config' mandatory to reduce confusion
=item *
Changed 'resources' subkey 'repository' to a hash that clarifies
repository type, url for browsing and url for checkout
=item *
Changed 'resources' subkey 'bugtracker' to a hash for either web
or mailto resource
=item *
Changed specification of 'optional_features':
=over
=item *
Added formal specification and usage guide instead of just example
=item *
Changed to use new prereqs data structure instead of individual keys
=back
=item *
Clarified intended use of 'author' as generalized contact list
=item *
Added 'release_status' field to indicate stable, testing or unstable
status to provide hints to indexers
=item *
Added 'description' field for a longer description of the distribution
=item *
Formalized use of "x_" or "X_" for all custom keys not listed in the
official spec
=back
=head2 Version 1.4
June 2008
=over
=item *
Noted explicit support for 'perl' in prerequisites
=item *
Added 'configure_requires' prerequisite type
=item *
Changed 'optional_features'
=over
=item *
Example corrected to show map of maps instead of list of maps
(though descriptive text said 'map' even in v1.3)
=item *
Removed 'requires_packages', 'requires_os' and 'excluded_os'
as valid subkeys
=back
=back
=head2 Version 1.3
November 2006
=over
=item *
Added 'no_index' subkey 'directory' and removed 'dir' to match actual
usage in the wild
=item *
Added a 'repository' subkey to 'resources'
=back
=head2 Version 1.2
August 2005
=over
=item *
Re-wrote and restructured spec in POD syntax
=item *
Changed 'name' to be mandatory
=item *
Changed 'generated_by' to be mandatory
=item *
Changed 'license' to be mandatory
=item *
Added version range specifications for prerequisites
=item *
Added required 'abstract' field
=item *
Added required 'author' field
=item *
Added required 'meta-spec' field to define 'version' (and 'url') of the
CPAN Meta Spec used for metadata
=item *
Added 'provides' field
=item *
Added 'no_index' field and deprecated 'private' field. 'no_index'
subkeys include 'file', 'dir', 'package' and 'namespace'
=item *
Added 'keywords' field
=item *
Added 'resources' field with subkeys 'homepage', 'license', and
'bugtracker'
=item *
Added 'optional_features' field as an alternate under 'recommends'.
Includes 'description', 'requires', 'build_requires', 'conflicts',
'requires_packages', 'requires_os' and 'excluded_os' as valid subkeys
=item *
Removed 'license_uri' field
=back
=head2 Version 1.1
May 2003
=over
=item *
Changed 'version' to be mandatory
=item *
Added 'private' field
=item *
Added 'license_uri' field
=back
=head2 Version 1.0
March 2003
=over
=item *
Original release (in HTML format only)
=item *
Included 'name', 'version', 'license', 'distribution_type', 'requires',
'recommends', 'build_requires', 'conflicts', 'dynamic_config',
'generated_by'
=back
=head1 AUTHORS
=over 4
=item *
David Golden <dagolden@cpan.org>
=item *
Ricardo Signes <rjbs@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by David Golden and Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
use strict;
use warnings;
package CPAN::Meta::Merge;
our $VERSION = '2.150005';
use Carp qw/croak/;
use Scalar::Util qw/blessed/;
use CPAN::Meta::Converter 2.141170;
sub _is_identical {
my ($left, $right) = @_;
return
(not defined $left and not defined $right)
# if either of these are references, we compare the serialized value
|| (defined $left and defined $right and $left eq $right);
}
sub _identical {
my ($left, $right, $path) = @_;
croak sprintf "Can't merge attribute %s: '%s' does not equal '%s'", join('.', @{$path}), $left, $right
unless _is_identical($left, $right);
return $left;
}
sub _merge {
my ($current, $next, $mergers, $path) = @_;
for my $key (keys %{$next}) {
if (not exists $current->{$key}) {
$current->{$key} = $next->{$key};
}
elsif (my $merger = $mergers->{$key}) {
$current->{$key} = $merger->($current->{$key}, $next->{$key}, [ @{$path}, $key ]);
}
elsif ($merger = $mergers->{':default'}) {
$current->{$key} = $merger->($current->{$key}, $next->{$key}, [ @{$path}, $key ]);
}
else {
croak sprintf "Can't merge unknown attribute '%s'", join '.', @{$path}, $key;
}
}
return $current;
}
sub _uniq {
my %seen = ();
return grep { not $seen{$_}++ } @_;
}
sub _set_addition {
my ($left, $right) = @_;
return [ +_uniq(@{$left}, @{$right}) ];
}
sub _uniq_map {
my ($left, $right, $path) = @_;
for my $key (keys %{$right}) {
if (not exists $left->{$key}) {
$left->{$key} = $right->{$key};
}
# identical strings or references are merged identically
elsif (_is_identical($left->{$key}, $right->{$key})) {
1; # do nothing - keep left
}
elsif (ref $left->{$key} eq 'HASH' and ref $right->{$key} eq 'HASH') {
$left->{$key} = _uniq_map($left->{$key}, $right->{$key}, [ @{$path}, $key ]);
}
else {
croak 'Duplication of element ' . join '.', @{$path}, $key;
}
}
return $left;
}
sub _improvize {
my ($left, $right, $path) = @_;
my ($name) = reverse @{$path};
if ($name =~ /^x_/) {
if (ref($left) eq 'ARRAY') {
return _set_addition($left, $right, $path);
}
elsif (ref($left) eq 'HASH') {
return _uniq_map($left, $right, $path);
}
else {
return _identical($left, $right, $path);
}
}
croak sprintf "Can't merge '%s'", join '.', @{$path};
}
sub _optional_features {
my ($left, $right, $path) = @_;
for my $key (keys %{$right}) {
if (not exists $left->{$key}) {
$left->{$key} = $right->{$key};
}
else {
for my $subkey (keys %{ $right->{$key} }) {
next if $subkey eq 'prereqs';
if (not exists $left->{$key}{$subkey}) {
$left->{$key}{$subkey} = $right->{$key}{$subkey};
}
else {
Carp::croak "Cannot merge two optional_features named '$key' with different '$subkey' values"
if do { no warnings 'uninitialized'; $left->{$key}{$subkey} ne $right->{$key}{$subkey} };
}
}
require CPAN::Meta::Prereqs;
$left->{$key}{prereqs} =
CPAN::Meta::Prereqs->new($left->{$key}{prereqs})
->with_merged_prereqs(CPAN::Meta::Prereqs->new($right->{$key}{prereqs}))
->as_string_hash;
}
}
return $left;
}
my %default = (
abstract => \&_identical,
author => \&_set_addition,
dynamic_config => sub {
my ($left, $right) = @_;
return $left || $right;
},
generated_by => sub {
my ($left, $right) = @_;
return join ', ', _uniq(split(/, /, $left), split(/, /, $right));
},
license => \&_set_addition,
'meta-spec' => {
version => \&_identical,
url => \&_identical
},
name => \&_identical,
release_status => \&_identical,
version => \&_identical,
description => \&_identical,
keywords => \&_set_addition,
no_index => { map { ($_ => \&_set_addition) } qw/file directory package namespace/ },
optional_features => \&_optional_features,
prereqs => sub {
require CPAN::Meta::Prereqs;
my ($left, $right) = map { CPAN::Meta::Prereqs->new($_) } @_[0,1];
return $left->with_merged_prereqs($right)->as_string_hash;
},
provides => \&_uniq_map,
resources => {
license => \&_set_addition,
homepage => \&_identical,
bugtracker => \&_uniq_map,
repository => \&_uniq_map,
':default' => \&_improvize,
},
':default' => \&_improvize,
);
sub new {
my ($class, %arguments) = @_;
croak 'default version required' if not exists $arguments{default_version};
my %mapping = %default;
my %extra = %{ $arguments{extra_mappings} || {} };
for my $key (keys %extra) {
if (ref($mapping{$key}) eq 'HASH') {
$mapping{$key} = { %{ $mapping{$key} }, %{ $extra{$key} } };
}
else {
$mapping{$key} = $extra{$key};
}
}
return bless {
default_version => $arguments{default_version},
mapping => _coerce_mapping(\%mapping, []),
}, $class;
}
my %coderef_for = (
set_addition => \&_set_addition,
uniq_map => \&_uniq_map,
identical => \&_identical,
improvize => \&_improvize,
);
sub _coerce_mapping {
my ($orig, $map_path) = @_;
my %ret;
for my $key (keys %{$orig}) {
my $value = $orig->{$key};
if (ref($orig->{$key}) eq 'CODE') {
$ret{$key} = $value;
}
elsif (ref($value) eq 'HASH') {
my $mapping = _coerce_mapping($value, [ @{$map_path}, $key ]);
$ret{$key} = sub {
my ($left, $right, $path) = @_;
return _merge($left, $right, $mapping, [ @{$path} ]);
};
}
elsif ($coderef_for{$value}) {
$ret{$key} = $coderef_for{$value};
}
else {
croak "Don't know what to do with " . join '.', @{$map_path}, $key;
}
}
return \%ret;
}
sub merge {
my ($self, @items) = @_;
my $current = {};
for my $next (@items) {
if ( blessed($next) && $next->isa('CPAN::Meta') ) {
$next = $next->as_struct;
}
elsif ( ref($next) eq 'HASH' ) {
my $cmc = CPAN::Meta::Converter->new(
$next, default_version => $self->{default_version}
);
$next = $cmc->upgrade_fragment;
}
else {
croak "Don't know how to merge '$next'";
}
$current = _merge($current, $next, $self->{mapping}, []);
}
return $current;
}
1;
# ABSTRACT: Merging CPAN Meta fragments
# vim: ts=2 sts=2 sw=2 et :
__END__
=pod
=encoding UTF-8
=head1 NAME
CPAN::Meta::Merge - Merging CPAN Meta fragments
=head1 VERSION
version 2.150005
=head1 SYNOPSIS
my $merger = CPAN::Meta::Merge->new(default_version => "2");
my $meta = $merger->merge($base, @additional);
=head1 DESCRIPTION
=head1 METHODS
=head2 new
This creates a CPAN::Meta::Merge object. It takes one mandatory named
argument, C<version>, declaring the version of the meta-spec that must be
used for the merge. It can optionally take an C<extra_mappings> argument
that allows one to add additional merging functions for specific elements.
=head2 merge(@fragments)
Merge all C<@fragments> together. It will accept both CPAN::Meta objects and
(possibly incomplete) hashrefs of metadata.
=head1 AUTHORS
=over 4
=item *
David Golden <dagolden@cpan.org>
=item *
Ricardo Signes <rjbs@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2010 by David Golden and Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
use 5.008001;
use strict;
package Parse::CPAN::Meta;
# ABSTRACT: Parse META.yml and META.json CPAN metadata files
our $VERSION = '1.4417';
use Exporter;
use Carp 'croak';
our @ISA = qw/Exporter/;
our @EXPORT_OK = qw/Load LoadFile/;
sub load_file {
my ($class, $filename) = @_;
my $meta = _slurp($filename);
if ($filename =~ /\.ya?ml$/) {
return $class->load_yaml_string($meta);
}
elsif ($filename =~ /\.json$/) {
return $class->load_json_string($meta);
}
else {
$class->load_string($meta); # try to detect yaml/json
}
}
sub load_string {
my ($class, $string) = @_;
if ( $string =~ /^---/ ) { # looks like YAML
return $class->load_yaml_string($string);
}
elsif ( $string =~ /^\s*\{/ ) { # looks like JSON
return $class->load_json_string($string);
}
else { # maybe doc-marker-free YAML
return $class->load_yaml_string($string);
}
}
sub load_yaml_string {
my ($class, $string) = @_;
my $backend = $class->yaml_backend();
my $data = eval { no strict 'refs'; &{"$backend\::Load"}($string) };
croak $@ if $@;
return $data || {}; # in case document was valid but empty
}
sub load_json_string {
my ($class, $string) = @_;
my $data = eval { $class->json_backend()->new->decode($string) };
croak $@ if $@;
return $data || {};
}
sub yaml_backend {
if (! defined $ENV{PERL_YAML_BACKEND} ) {
_can_load( 'CPAN::Meta::YAML', 0.011 )
or croak "CPAN::Meta::YAML 0.011 is not available\n";
return "CPAN::Meta::YAML";
}
else {
my $backend = $ENV{PERL_YAML_BACKEND};
_can_load( $backend )
or croak "Could not load PERL_YAML_BACKEND '$backend'\n";
$backend->can("Load")
or croak "PERL_YAML_BACKEND '$backend' does not implement Load()\n";
return $backend;
}
}
sub json_backend {
if (! $ENV{PERL_JSON_BACKEND} or $ENV{PERL_JSON_BACKEND} eq 'JSON::PP') {
_can_load( 'JSON::PP' => 2.27103 )
or croak "JSON::PP 2.27103 is not available\n";
return 'JSON::PP';
}
else {
_can_load( 'JSON' => 2.5 )
or croak "JSON 2.5 is required for " .
"\$ENV{PERL_JSON_BACKEND} = '$ENV{PERL_JSON_BACKEND}'\n";
return "JSON";
}
}
sub _slurp {
require Encode;
open my $fh, "<:raw", "$_[0]" ## no critic
or die "can't open $_[0] for reading: $!";
my $content = do { local $/; <$fh> };
$content = Encode::decode('UTF-8', $content, Encode::PERLQQ());
return $content;
}
sub _can_load {
my ($module, $version) = @_;
(my $file = $module) =~ s{::}{/}g;
$file .= ".pm";
return 1 if $INC{$file};
return 0 if exists $INC{$file}; # prior load failed
eval { require $file; 1 }
or return 0;
if ( defined $version ) {
eval { $module->VERSION($version); 1 }
or return 0;
}
return 1;
}
# Kept for backwards compatibility only
# Create an object from a file
sub LoadFile ($) { ## no critic
return Load(_slurp(shift));
}
# Parse a document from a string.
sub Load ($) { ## no critic
require CPAN::Meta::YAML;
my $object = eval { CPAN::Meta::YAML::Load(shift) };
croak $@ if $@;
return $object;
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Parse::CPAN::Meta - Parse META.yml and META.json CPAN metadata files
=head1 VERSION
version 1.4417
=head1 SYNOPSIS
#############################################
# In your file
---
name: My-Distribution
version: 1.23
resources:
homepage: "http://example.com/dist/My-Distribution"
#############################################
# In your program
use Parse::CPAN::Meta;
my $distmeta = Parse::CPAN::Meta->load_file('META.yml');
# Reading properties
my $name = $distmeta->{name};
my $version = $distmeta->{version};
my $homepage = $distmeta->{resources}{homepage};
=head1 DESCRIPTION
B<Parse::CPAN::Meta> is a parser for F<META.json> and F<META.yml> files, using
L<JSON::PP> and/or L<CPAN::Meta::YAML>.
B<Parse::CPAN::Meta> provides three methods: C<load_file>, C<load_json_string>,
and C<load_yaml_string>. These will read and deserialize CPAN metafiles, and
are described below in detail.
B<Parse::CPAN::Meta> provides a legacy API of only two functions,
based on the YAML functions of the same name. Wherever possible,
identical calling semantics are used. These may only be used with YAML sources.
All error reporting is done with exceptions (die'ing).
Note that META files are expected to be in UTF-8 encoding, only. When
converted string data, it must first be decoded from UTF-8.
=begin Pod::Coverage
=end Pod::Coverage
=head1 METHODS
=head2 load_file
my $metadata_structure = Parse::CPAN::Meta->load_file('META.json');
my $metadata_structure = Parse::CPAN::Meta->load_file('META.yml');
This method will read the named file and deserialize it to a data structure,
determining whether it should be JSON or YAML based on the filename.
The file will be read using the ":utf8" IO layer.
=head2 load_yaml_string
my $metadata_structure = Parse::CPAN::Meta->load_yaml_string($yaml_string);
This method deserializes the given string of YAML and returns the first
document in it. (CPAN metadata files should always have only one document.)
If the source was UTF-8 encoded, the string must be decoded before calling
C<load_yaml_string>.
=head2 load_json_string
my $metadata_structure = Parse::CPAN::Meta->load_json_string($json_string);
This method deserializes the given string of JSON and the result.
If the source was UTF-8 encoded, the string must be decoded before calling
C<load_json_string>.
=head2 load_string
my $metadata_structure = Parse::CPAN::Meta->load_string($some_string);
If you don't know whether a string contains YAML or JSON data, this method
will use some heuristics and guess. If it can't tell, it assumes YAML.
=head2 yaml_backend
my $backend = Parse::CPAN::Meta->yaml_backend;
Returns the module name of the YAML serializer. See L</ENVIRONMENT>
for details.
=head2 json_backend
my $backend = Parse::CPAN::Meta->json_backend;
Returns the module name of the JSON serializer. This will either
be L<JSON::PP> or L<JSON>. Even if C<PERL_JSON_BACKEND> is set,
this will return L<JSON> as further delegation is handled by
the L<JSON> module. See L</ENVIRONMENT> for details.
=head1 FUNCTIONS
For maintenance clarity, no functions are exported by default. These functions
are available for backwards compatibility only and are best avoided in favor of
C<load_file>.
=head2 Load
my @yaml = Parse::CPAN::Meta::Load( $string );
Parses a string containing a valid YAML stream into a list of Perl data
structures.
=head2 LoadFile
my @yaml = Parse::CPAN::Meta::LoadFile( 'META.yml' );
Reads the YAML stream from a file instead of a string.
=head1 ENVIRONMENT
=head2 PERL_JSON_BACKEND
By default, L<JSON::PP> will be used for deserializing JSON data. If the
C<PERL_JSON_BACKEND> environment variable exists, is true and is not
"JSON::PP", then the L<JSON> module (version 2.5 or greater) will be loaded and
used to interpret C<PERL_JSON_BACKEND>. If L<JSON> is not installed or is too
old, an exception will be thrown.
=head2 PERL_YAML_BACKEND
By default, L<CPAN::Meta::YAML> will be used for deserializing YAML data. If
the C<PERL_YAML_BACKEND> environment variable is defined, then it is interpreted
as a module to use for deserialization. The given module must be installed,
must load correctly and must implement the C<Load()> function or an exception
will be thrown.
=for :stopwords cpan testmatrix url annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders metacpan
=head1 SUPPORT
=head2 Bugs / Feature Requests
Please report any bugs or feature requests through the issue tracker
at L<https://github.com/Perl-Toolchain-Gang/Parse-CPAN-Meta/issues>.
You will be notified automatically of any progress on your issue.
=head2 Source Code
This is open source software. The code repository is available for
public review and contribution under the terms of the license.
L<https://github.com/Perl-Toolchain-Gang/Parse-CPAN-Meta>
git clone https://github.com/Perl-Toolchain-Gang/Parse-CPAN-Meta.git
=head1 AUTHORS
=over 4
=item *
Adam Kennedy <adamk@cpan.org>
=item *
David Golden <dagolden@cpan.org>
=back
=head1 CONTRIBUTORS
=for stopwords Graham Knop Joshua ben Jore Karen Etheridge Neil Bowers Ricardo Signes Steffen Mueller
=over 4
=item *
Graham Knop <haarg@haarg.org>
=item *
Joshua ben Jore <jjore@cpan.org>
=item *
Karen Etheridge <ether@cpan.org>
=item *
Neil Bowers <neil@bowers.com>
=item *
Ricardo Signes <rjbs@cpan.org>
=item *
Steffen Mueller <smueller@cpan.org>
=back
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2015 by Adam Kennedy and Contributors.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
/MYMETA.* /MYMETA.*
/pm_to_blib /pm_to_blib
/blib /blib
/Bugzilla-*.*/
/skins/contrib/Dusk/admin.css /skins/contrib/Dusk/admin.css
/skins/contrib/Dusk/bug.css /skins/contrib/Dusk/bug.css
...@@ -35,6 +35,7 @@ use Bugzilla::Field; ...@@ -35,6 +35,7 @@ use Bugzilla::Field;
use Bugzilla::Flag; use Bugzilla::Flag;
use Bugzilla::Install::Localconfig qw(read_localconfig); use Bugzilla::Install::Localconfig qw(read_localconfig);
use Bugzilla::Install::Util qw(init_console include_languages i_am_persistent); use Bugzilla::Install::Util qw(init_console include_languages i_am_persistent);
use Bugzilla::Install::Requirements qw(load_cpan_meta check_cpan_feature);
use Bugzilla::Memcached; use Bugzilla::Memcached;
use Bugzilla::Template; use Bugzilla::Template;
use Bugzilla::Token; use Bugzilla::Token;
...@@ -243,28 +244,19 @@ sub api_server { ...@@ -243,28 +244,19 @@ sub api_server {
return $cache->{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 { sub feature {
my ($class, $feature_name) = @_; my ($class, $feature_name) = @_;
return 0 unless _CAN_HAS_FEATURE; return 0 unless CAN_HAS_FEATURE;
return unless $class->has_feature($feature_name); return 0 unless $class->has_feature($feature_name);
my $cache = $class->request_cache; my $cache = $class->process_cache;
my $feature = $cache->{feature_map}{$feature_name}; my $feature = $cache->{cpan_meta}->feature($feature_name);
# Bugzilla expects this will also load all the modules.. so we have to do that. # 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(). # Later we should put a deprecation warning here, and favor calling has_feature().
return 1 if $cache->{feature_loaded}{$feature_name}; return 1 if $cache->{feature_loaded}{$feature_name};
my @modules = $feature->requirements_for('runtime', 'requires')->required_modules; my @modules = $feature->prereqs->merged_requirements->required_modules;
require_module($_) foreach @modules; Module::Runtime::require_module($_) foreach @modules;
$cache->{feature_loaded}{$feature_name} = 1; $cache->{feature_loaded}{$feature_name} = 1;
return 1; return 1;
} }
...@@ -272,38 +264,17 @@ sub feature { ...@@ -272,38 +264,17 @@ sub feature {
sub has_feature { sub has_feature {
my ($class, $feature_name) = @_; my ($class, $feature_name) = @_;
return 0 unless _CAN_HAS_FEATURE; return 0 unless CAN_HAS_FEATURE;
my $cache = $class->request_cache; my $cache = $class->process_cache;
return $cache->{feature}->{$feature_name} return $cache->{feature}->{$feature_name}
if exists $cache->{feature}->{$feature_name}; if exists $cache->{feature}->{$feature_name};
my $dir = bz_locations()->{libpath}; my $meta = $cache->{cpan_meta} //= load_cpan_meta();
my $feature_map = $cache->{feature_map} //= do { my $feature = eval { $meta->feature($feature_name) }
my @meta_json = map { File::Spec->catfile($dir, $_) } qw( MYMETA.json META.json ); or ThrowCodeError('invalid_feature', { feature => $feature_name });
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;
}
}
\%map;
};
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 $cache->{feature}{$feature_name} = check_cpan_feature($feature)->{ok};
return $success;
} }
sub cgi { sub cgi {
......
...@@ -26,6 +26,8 @@ use Memoize; ...@@ -26,6 +26,8 @@ use Memoize;
bz_locations bz_locations
CAN_HAS_FEATURE
CONCATENATE_ASSETS CONCATENATE_ASSETS
IS_NULL IS_NULL
...@@ -218,6 +220,17 @@ use constant REST_DOC => 'https://bugzilla.readthedocs.org/en/latest/api/'; ...@@ -218,6 +220,17 @@ use constant REST_DOC => 'https://bugzilla.readthedocs.org/en/latest/api/';
use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml'; use constant REMOTE_FILE => 'http://updates.bugzilla.org/bugzilla-update.xml';
use constant LOCAL_FILE => 'bugzilla-update.xml'; # Relative to datadir. use constant LOCAL_FILE => 'bugzilla-update.xml'; # Relative to datadir.
use constant CAN_HAS_FEATURE => eval {
require CPAN::Meta::Prereqs;
require CPAN::Meta::Requirements;
require Module::Metadata;
require Module::Runtime;
CPAN::Meta::Prereqs->VERSION('2.132830');
CPAN::Meta::Requirements->VERSION('2.121');
Module::Metadata->VERSION('1.000019');
1;
};
# When true CSS and JavaScript assets will be concatanted and minified at # When true CSS and JavaScript assets will be concatanted and minified at
# run-time, to reduce the number of requests required to render a page. # run-time, to reduce the number of requests required to render a page.
# Setting this to a false value can help debugging. # Setting this to a false value can help debugging.
......
...@@ -22,6 +22,10 @@ use Bugzilla::Install::Util qw(install_string bin_loc success ...@@ -22,6 +22,10 @@ use Bugzilla::Install::Util qw(install_string bin_loc success
extension_requirement_packages); extension_requirement_packages);
use List::Util qw(max); use List::Util qw(max);
use Term::ANSIColor; use Term::ANSIColor;
use CPAN::Meta;
use CPAN::Meta::Prereqs;
use CPAN::Meta::Requirements;
use Module::Metadata;
use parent qw(Exporter); use parent qw(Exporter);
use autodie; use autodie;
...@@ -29,12 +33,17 @@ use autodie; ...@@ -29,12 +33,17 @@ use autodie;
our @EXPORT = qw( our @EXPORT = qw(
FEATURE_FILES FEATURE_FILES
check_requirements load_cpan_meta
check_cpan_requirements
check_cpan_feature
check_all_cpan_features
check_webdotbase check_webdotbase
check_font_file check_font_file
map_files_to_features map_files_to_features
); );
our $checking_for_indent = 0;
# This is how many *'s are in the top of each "box" message printed # This is how many *'s are in the top of each "box" message printed
# by checksetup.pl. # by checksetup.pl.
use constant TABLE_WIDTH => 71; use constant TABLE_WIDTH => 71;
...@@ -92,41 +101,110 @@ use constant FEATURE_FILES => ( ...@@ -92,41 +101,110 @@ use constant FEATURE_FILES => (
auth_delegation => ['auth.cgi'], auth_delegation => ['auth.cgi'],
); );
sub check_requirements { sub load_cpan_meta {
my ($output) = @_; my $dir = bz_locations()->{libpath};
my @meta_json = map { File::Spec->catfile($dir, $_) } qw( MYMETA.json META.json );
my $missing_apache = _missing_apache_modules(APACHE_MODULES, $output); my ($file) = grep { -f $_ } @meta_json;
# If we're running on Windows, reset the input line terminator so that if ($file) {
# console input works properly - loading CGI tends to mess it up open my $meta_fh, '<', $file or die "unable to open $file: $!";
$/ = "\015\012" if ON_WINDOWS; my $str = do { local $/ = undef; scalar <$meta_fh> };
# detaint
$str =~ /^(.+)$/s; $str = $1;
close $meta_fh;
return { apache => $missing_apache }; return CPAN::Meta->load_json_string($str);
}
else {
ThrowCodeError('cpan_meta_missing');
}
} }
sub _missing_apache_modules { sub check_all_cpan_features {
my ($modules, $output) = @_; my ($meta, $dirs, $output) = @_;
my $apachectl = _get_apachectl(); my %report;
return [] if !$apachectl;
my $command = "$apachectl -t -D DUMP_MODULES"; local $checking_for_indent = 2;
my $cmd_info = `$command 2>&1`;
# If apachectl returned a value greater than 0, then there was an print "\nOptional features:\n" if $output;
# error parsing Apache's configuration, and we can't check modules. my @features = sort { $a->identifier cmp $b->identifier } $meta->features;
my $retval = $?; foreach my $feature (@features) {
if ($retval > 0) { next if $feature->identifier eq 'features';
print STDERR install_string('apachectl_failed', printf "Feature '%s': %s\n", $feature->identifier, $feature->description if $output;
{ command => $command, root => ROOT_USER }), "\n"; my $result = check_cpan_feature($feature, $dirs, $output);
return []; print "\n" if $output;
$report{$feature->identifier} = {
description => $feature->description,
result => $result,
};
} }
print install_string('all_optional_features_require'), "\n" if $output;
my $features = check_cpan_feature($meta->feature('features'), $dirs, $output);
print "\n" if $output;
$report{features} = {
description => $meta->feature('features')->description,
result => $features,
};
return \%report;
}
sub check_cpan_feature {
my ($feature, $dirs, $output) = @_;
return _check_prereqs($feature->prereqs, $dirs, $output);
}
sub check_cpan_requirements {
my ($meta, $dirs, $output) = @_;
my $result = _check_prereqs($meta->effective_prereqs, $dirs, $output);
print colored(install_string('installation_failed'), COLOR_ERROR), "\n" if !$result->{ok} && $output;
return $result;
}
sub _check_prereqs {
my ($prereqs, $dirs, $output) = @_;
$dirs //= \@INC;
my $reqs = $prereqs->merged_requirements(['configure', 'runtime'], ['requires']);
my @found;
my @missing; my @missing;
foreach my $module (sort keys %$modules) {
my $ok = _check_apache_module($module, $modules->{$module}, foreach my $module (sort $reqs->required_modules) {
$cmd_info, $output); my $ok = _check_module($reqs, $module, $dirs, $output);
push(@missing, $module) if !$ok; if ($ok) {
push @found, $module;
}
else {
push @missing, $module;
}
} }
return \@missing;
return { ok => (@missing == 0), found => \@found, missing => \@missing };
} }
sub _check_module {
my ($reqs, $module, $dirs, $output) = @_;
my $required_version = $reqs->requirements_for_module($module);
if ($module eq 'perl') {
my $ok = $reqs->accepts_module($module, $]);
_checking_for({package => "perl", found => $], wanted => $required_version, ok => $ok}) if $output;
return $ok;
} else {
my $metadata = Module::Metadata->new_from_module($module, inc => $dirs);
my $version = eval { $metadata->version };
my $ok = $metadata && $version && $reqs->accepts_module($module, $version || 0);
_checking_for({package => $module, $version ? ( found => $version ) : (), wanted => $required_version, ok => $ok}) if $output;
return $ok;
}
}
sub _get_apachectl { sub _get_apachectl {
foreach my $bin_name (APACHE) { foreach my $bin_name (APACHE) {
my $bin = bin_loc($bin_name); my $bin = bin_loc($bin_name);
...@@ -140,18 +218,6 @@ sub _get_apachectl { ...@@ -140,18 +218,6 @@ sub _get_apachectl {
return undef; return undef;
} }
sub _check_apache_module {
my ($module, $config_name, $mod_info, $output) = @_;
my $ok;
if ($mod_info =~ /^\s+\Q$config_name\E\b/m) {
$ok = 1;
}
if ($output) {
_checking_for({ package => $module, ok => $ok });
}
return $ok;
}
sub check_webdotbase { sub check_webdotbase {
my ($output) = @_; my ($output) = @_;
...@@ -240,10 +306,11 @@ sub _checking_for { ...@@ -240,10 +306,11 @@ sub _checking_for {
} }
my $black_string = $blacklisted ? install_string('blacklisted') : ''; my $black_string = $blacklisted ? install_string('blacklisted') : '';
my $want_string = $wanted ? "v$wanted" : install_string('any'); my $want_string = $wanted ? "$wanted" : install_string('any');
my $str = sprintf "%s %20s %-11s $ok_string $black_string\n", my $str = sprintf "%s %20s %-11s $ok_string $black_string\n",
install_string('checking_for'), $package, "($want_string)"; ( ' ' x $checking_for_indent ) . install_string('checking_for'),
$package, "($want_string)";
print $ok ? $str : colored($str, COLOR_ERROR); print $ok ? $str : colored($str, COLOR_ERROR);
} }
...@@ -289,24 +356,27 @@ of file names (which are passed to C<glob>, so shell patterns work). ...@@ -289,24 +356,27 @@ of file names (which are passed to C<glob>, so shell patterns work).
=back =back
=head1 SUBROUTINES =head1 SUBROUTINES
=over 4 =over 4
=item C<check_requirements> =item C<check_cpan_requirements>
=over =over
=item B<Description> =item B<Description>
This checks what optional or required perl modules are installed, like This checks what required perl modules are installed, like
C<checksetup.pl> does. C<checksetup.pl> does.
=item B<Params> =item B<Params>
=over =over
=item C<$meta> - A C<CPAN::Meta> object.
=item C<$dirs> - the include dirs to search for modules, defaults to @INC.
=item C<$output> - C<true> if you want the function to print out information =item C<$output> - C<true> if you want the function to print out information
about what it's doing, and the versions of everything installed. about what it's doing, and the versions of everything installed.
...@@ -318,10 +388,81 @@ A hashref containing these values: ...@@ -318,10 +388,81 @@ A hashref containing these values:
=over =over
=item C<apache> - The name of each optional Apache module that is missing. =item C<ok> - if all the requirements are met, this is true.
=item C<found> - an arrayref of found modules
=item C<missing> - an arrayref of missing modules
=back
=back
=item C<check_cpan_feature>
=over
=item B<Description>
This checks that the optional Perl modules required for a feature are installed.
=item B<Params>
=over
=item C<$feature> - A C<CPAN::Meta::Feature> object.
=item C<$dirs> - the include dirs to search for modules, defaults to @INC.
=item C<$output> - C<true> if you want the function to print out information about what it's doing, and the versions of everything installed.
=back
=item B<Returns>
A hashref containing these values:
=over
=item C<ok> - if all the requirements are met, this is true.
=item C<found> - an arrayref of found modules
=item C<missing> - an arrayref of missing modules
=back =back
=item C<check_all_cpan_features>
=over
=item B<Description>
This checks which optional Perl modules are currently installed which can enable optional features.
=item B<Params>
=over
=item C<$meta> - A C<CPAN::Meta> object.
=item C<$dirs> - the include dirs to search for modules, defaults to @INC.
=item C<$output> - C<true> if you want the function to print out information
about what it's doing, and the versions of everything installed.
=back
=item B<Returns>
A hashref keyed on the feature name. The values
are hashrefs containing C<description> and C<result> keys.
C<description> is the English description of the feature.
C<result> is a hashref in the same format as the return value of C<check_cpan_requirements()>,
described previously.
=back =back
=item C<check_webdotbase($output)> =item C<check_webdotbase($output)>
...@@ -349,5 +490,11 @@ Returns: C<1> if the check was successful, C<0> otherwise. ...@@ -349,5 +490,11 @@ Returns: C<1> if the check was successful, C<0> otherwise.
Returns a hashref where file names are the keys and the value is the feature Returns a hashref where file names are the keys and the value is the feature
that must be enabled in order to compile that file. that must be enabled in order to compile that file.
=item C<load_cpan_meta>
Load MYMETA.json or META.json from the bugzilla directory, and a return a L<CPAN::Meta> object.
=back
=back =back
...@@ -269,6 +269,15 @@ sub indicate_progress { ...@@ -269,6 +269,15 @@ sub indicate_progress {
} }
} }
sub feature_description {
my ($feature_name) = @_;
eval {
my $meta = _cache()->{cpan_meta} //= Bugzilla::Install::Requirements::load_cpan_meta();
return $meta->feature($feature_name)->description
} or warn $@;
}
sub install_string { sub install_string {
my ($string_id, $vars) = @_; my ($string_id, $vars) = @_;
_cache()->{install_string_path} ||= template_include_path(); _cache()->{install_string_path} ||= template_include_path();
...@@ -854,6 +863,10 @@ Used by L<Bugzilla::Template> to determine the languages' list which ...@@ -854,6 +863,10 @@ Used by L<Bugzilla::Template> to determine the languages' list which
are compiled with the browser's I<Accept-Language> and the languages are compiled with the browser's I<Accept-Language> and the languages
of installed templates. of installed templates.
=item C<feature_description>
Return the English-language description of a feature from the (MY)META.json files.
=back =back
=head1 B<Methods in need of POD> =head1 B<Methods in need of POD>
......
...@@ -1146,6 +1146,8 @@ sub create { ...@@ -1146,6 +1146,8 @@ sub create {
'install_string' => \&Bugzilla::Install::Util::install_string, 'install_string' => \&Bugzilla::Install::Util::install_string,
'feature_description' => \&Bugzilla::Install::Util::feature_description,
'report_columns' => \&Bugzilla::Search::REPORT_COLUMNS, 'report_columns' => \&Bugzilla::Search::REPORT_COLUMNS,
# These don't work as normal constants. # These don't work as normal constants.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
"Bugzilla Developers <developers@bugzilla.org>" "Bugzilla Developers <developers@bugzilla.org>"
], ],
"dynamic_config" : 1, "dynamic_config" : 1,
"generated_by" : "ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150005", "generated_by" : "ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150001",
"license" : [ "license" : [
"unknown" "unknown"
], ],
...@@ -73,12 +73,13 @@ ...@@ -73,12 +73,13 @@
} }
}, },
"features" : { "features" : {
"description" : "Base support for Features", "description" : "Modules required to enable any feature",
"prereqs" : { "prereqs" : {
"runtime" : { "runtime" : {
"requires" : { "requires" : {
"CPAN::Meta" : "0", "CPAN::Meta::Prereqs" : "2.132830",
"CPAN::Meta::Check" : "0", "CPAN::Meta::Requirements" : "2.121",
"Module::Metadata" : "1.000019",
"Module::Runtime" : "0" "Module::Runtime" : "0"
} }
} }
...@@ -125,7 +126,7 @@ ...@@ -125,7 +126,7 @@
"runtime" : { "runtime" : {
"requires" : { "requires" : {
"Daemon::Generic" : "0", "Daemon::Generic" : "0",
"TheSchwartz" : "1.1" "TheSchwartz" : "1.10"
} }
} }
} }
...@@ -166,7 +167,8 @@ ...@@ -166,7 +167,8 @@
"prereqs" : { "prereqs" : {
"runtime" : { "runtime" : {
"requires" : { "requires" : {
"mod_perl2" : "0" "Apache::SizeLimit" : "0.96",
"mod_perl2" : "1.999022"
} }
} }
} }
...@@ -338,7 +340,7 @@ ...@@ -338,7 +340,7 @@
"prereqs" : { "prereqs" : {
"build" : { "build" : {
"requires" : { "requires" : {
"ExtUtils::MakeMaker" : "0" "ExtUtils::MakeMaker" : "6.55"
} }
}, },
"configure" : { "configure" : {
...@@ -347,6 +349,13 @@ ...@@ -347,6 +349,13 @@
} }
}, },
"runtime" : { "runtime" : {
"recommends" : {
"CPAN::Meta::Prereqs" : "2.132830",
"CPAN::Meta::Requirements" : "2.121",
"Module::Metadata" : "1.000019",
"Module::Runtime" : "0",
"Safe" : "2.30"
},
"requires" : { "requires" : {
"CGI" : "4.09", "CGI" : "4.09",
"DBI" : "1.614", "DBI" : "1.614",
...@@ -375,6 +384,5 @@ ...@@ -375,6 +384,5 @@
} }
}, },
"release_status" : "stable", "release_status" : "stable",
"version" : "5.1", "version" : "5.1"
"x_serialization_backend" : "JSON::PP version 2.27203"
} }
...@@ -3,7 +3,7 @@ abstract: 'Bugzilla Bug Tracking System' ...@@ -3,7 +3,7 @@ abstract: 'Bugzilla Bug Tracking System'
author: author:
- 'Bugzilla Developers <developers@bugzilla.org>' - 'Bugzilla Developers <developers@bugzilla.org>'
build_requires: build_requires:
ExtUtils::MakeMaker: '0' ExtUtils::MakeMaker: '6.55'
Pod::Checker: '0' Pod::Checker: '0'
Pod::Coverage: '0' Pod::Coverage: '0'
Test::More: '0' Test::More: '0'
...@@ -11,7 +11,7 @@ build_requires: ...@@ -11,7 +11,7 @@ build_requires:
configure_requires: configure_requires:
ExtUtils::MakeMaker: '6.55' ExtUtils::MakeMaker: '6.55'
dynamic_config: 1 dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150005' generated_by: 'ExtUtils::MakeMaker version 7.1, CPAN::Meta::Converter version 2.150001'
license: unknown license: unknown
meta-spec: meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html url: http://module-build.sourceforge.net/META-spec-v1.4.html
...@@ -45,10 +45,11 @@ optional_features: ...@@ -45,10 +45,11 @@ optional_features:
File::Copy::Recursive: '0' File::Copy::Recursive: '0'
File::Which: '0' File::Which: '0'
features: features:
description: 'Base support for Features' description: 'Modules required to enable any feature'
requires: requires:
CPAN::Meta: '0' CPAN::Meta::Prereqs: '2.132830'
CPAN::Meta::Check: '0' CPAN::Meta::Requirements: '2.121'
Module::Metadata: '1.000019'
Module::Runtime: '0' Module::Runtime: '0'
graphical_reports: graphical_reports:
description: 'Graphical Reports' description: 'Graphical Reports'
...@@ -71,7 +72,7 @@ optional_features: ...@@ -71,7 +72,7 @@ optional_features:
description: 'Mail Queueing' description: 'Mail Queueing'
requires: requires:
Daemon::Generic: '0' Daemon::Generic: '0'
TheSchwartz: '1.1' TheSchwartz: '1.10'
jsonrpc: jsonrpc:
description: 'JSON-RPC Interface' description: 'JSON-RPC Interface'
requires: requires:
...@@ -88,7 +89,8 @@ optional_features: ...@@ -88,7 +89,8 @@ optional_features:
mod_perl: mod_perl:
description: 'mod_perl support under Apache' description: 'mod_perl support under Apache'
requires: requires:
mod_perl2: '0' Apache::SizeLimit: '0.96'
mod_perl2: '1.999022'
moving: moving:
description: 'Move Bugs Between Installations' description: 'Move Bugs Between Installations'
requires: requires:
...@@ -162,6 +164,12 @@ optional_features: ...@@ -162,6 +164,12 @@ optional_features:
SOAP::Lite: '0.712' SOAP::Lite: '0.712'
Test::Taint: '1.06' Test::Taint: '1.06'
XMLRPC::Lite: '0.712' XMLRPC::Lite: '0.712'
recommends:
CPAN::Meta::Prereqs: '2.132830'
CPAN::Meta::Requirements: '2.121'
Module::Metadata: '1.000019'
Module::Runtime: '0'
Safe: '2.30'
requires: requires:
CGI: '4.09' CGI: '4.09'
DBI: '1.614' DBI: '1.614'
...@@ -179,4 +187,3 @@ requires: ...@@ -179,4 +187,3 @@ requires:
URI: '1.55' URI: '1.55'
perl: '5.014000' perl: '5.014000'
version: '5.1' version: '5.1'
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
...@@ -18,7 +18,10 @@ use warnings; ...@@ -18,7 +18,10 @@ use warnings;
use File::Basename; use File::Basename;
BEGIN { chdir dirname($0); } BEGIN { chdir dirname($0); }
use lib qw(. lib local/lib/perl5); use lib qw(. lib local/lib/perl5 .checksetup_lib/lib/perl5);
# the @INC which checksetup needs to operate against.
our @BUGZILLA_INC = grep { !/checksetup_lib/ } @INC;
use Getopt::Long qw(:config bundling); use Getopt::Long qw(:config bundling);
use Pod::Usage; use Pod::Usage;
...@@ -58,9 +61,13 @@ my $silent = $answers_file && !$switch{'verbose'}; ...@@ -58,9 +61,13 @@ my $silent = $answers_file && !$switch{'verbose'};
print(install_string('header', get_version_and_os()) . "\n") unless $silent; print(install_string('header', get_version_and_os()) . "\n") unless $silent;
exit 0 if $switch{'version'}; exit 0 if $switch{'version'};
# Check required --MODULES-- my $meta = load_cpan_meta();
my $module_results = check_requirements(!$silent); my $requirements = check_cpan_requirements($meta, \@BUGZILLA_INC, !$silent);
# Break out if checking the modules is all we have been asked to do.
exit 1 unless $requirements->{ok};
check_all_cpan_features($meta, \@BUGZILLA_INC, !$silent);
########################################################################### ###########################################################################
# Load Bugzilla Modules # Load Bugzilla Modules
......
...@@ -114,7 +114,8 @@ ...@@ -114,7 +114,8 @@
[% ELSIF error == "cookies_need_value" %] [% ELSIF error == "cookies_need_value" %]
Every cookie must have a value. Every cookie must have a value.
[% ELSIF error == "cpan_meta_missing" %]
META.json/MYMETA.json file is missing.
[% ELSIF error == "env_no_email" %] [% ELSIF error == "env_no_email" %]
Bugzilla did not receive an email address from the Bugzilla did not receive an email address from the
environment. environment.
......
...@@ -565,12 +565,10 @@ ...@@ -565,12 +565,10 @@
(You specified '[% name FILTER html %]'.) (You specified '[% name FILTER html %]'.)
[% ELSIF error == "feature_disabled" %] [% ELSIF error == "feature_disabled" %]
The [% install_string("feature_$feature") FILTER html %] feature is not The [% feature_description(feature) FILTER html %] feature is not available in this Bugzilla.
available in this Bugzilla.
[% IF user.in_group('admin') %] [% IF user.in_group('admin') %]
If you would like to enable this feature, please run If you would like to enable this feature, please run
<kbd>checksetup.pl</kbd> to see how to install the necessary <kbd>cpanm -l local --installdeps --with-feature [% feature FILTER html %] "."</kbd>
requirements for this feature.
[% END %] [% END %]
[% ELSIF error == "field_already_exists" %] [% ELSIF error == "field_already_exists" %]
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
# Please keep the strings in alphabetical order by their name. # Please keep the strings in alphabetical order by their name.
%strings = ( %strings = (
all_optional_features_require => 'All optional features above require the following modules to be found:',
any => 'any', any => 'any',
apachectl_failed => <<END, apachectl_failed => <<END,
WARNING: We could not check the configuration of Apache. This sometimes WARNING: We could not check the configuration of Apache. This sometimes
...@@ -44,9 +45,6 @@ can connect to your MySQL database and drop the bz_schema table, as a last ...@@ -44,9 +45,6 @@ can connect to your MySQL database and drop the bz_schema table, as a last
resort. resort.
END END
checking_for => 'Checking for', checking_for => 'Checking for',
checking_dbd => 'Checking available perl DBD modules...',
checking_optional => 'The following Perl modules are optional:',
checking_modules => 'Checking perl modules...',
chmod_failed => '##path##: Failed to change permissions: ##error##', chmod_failed => '##path##: Failed to change permissions: ##error##',
chown_failed => '##path##: Failed to change ownership: ##error##', chown_failed => '##path##: Failed to change ownership: ##error##',
commands_dbd => <<EOT, commands_dbd => <<EOT,
...@@ -93,6 +91,7 @@ END ...@@ -93,6 +91,7 @@ END
file_rename => 'Renaming ##from## to ##to##...', file_rename => 'Renaming ##from## to ##to##...',
header => "* This is Bugzilla ##bz_ver## on perl ##perl_ver##\n" header => "* This is Bugzilla ##bz_ver## on perl ##perl_ver##\n"
. "* Running on ##os_name## ##os_ver##", . "* Running on ##os_name## ##os_ver##",
installation_failed => '*** Installation aborted. Read the messages above. ***',
install_data_too_long => <<EOT, install_data_too_long => <<EOT,
WARNING: Some of the data in the ##table##.##column## column is longer than WARNING: Some of the data in the ##table##.##column## column is longer than
its new length limit of ##max_length## characters. The data that needs to be its new length limit of ##max_length## characters. The data that needs to be
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment