Skip to content

Commit

Permalink
perl: generalize the Git::LoadCPAN facility
Browse files Browse the repository at this point in the history
Change the two wrappers that load from CPAN (local OS) or our own copy
to do so via the same codepath.

I added the Error.pm wrapper in 20d2a30 ("Makefile: replace
perl/Makefile.PL with simple make rules", 2017-12-10), and shortly
afterwards Matthieu Moy added a wrapper for Mail::Address in
bd869f6 ("send-email: add and use a local copy of Mail::Address",
2018-01-05).

His loader was simpler since Mail::Address doesn't have an "import"
method, but didn't do the same sanity checking; For example, a missing
FromCPAN directory (which OS packages are likely not to have) wouldn't
be explicitly warned about as a "BUG: ...".

Update both to use a common implementation based on the previous
Error.pm loader. Which has been amended to take the module to load as
parameter, as well as whether or not that module has an import
method.

This loader should be generic enough to handle almost all CPAN modules
out there, some use some crazy loading magic and wouldn't like being
wrapped like this, but that would be immediately obvious, and we'd
find out right away since the module wouldn't work at all.

Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
avar authored and gitster committed Mar 5, 2018
1 parent 2865467 commit edfb7b9
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 58 deletions.
74 changes: 74 additions & 0 deletions perl/Git/LoadCPAN.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package Git::LoadCPAN;
use 5.008;
use strict;
use warnings;

=head1 NAME
Git::LoadCPAN - Wrapper for loading modules from the CPAN (OS) or Git's own copy
=head1 DESCRIPTION
The Perl code in Git depends on some modules from the CPAN, but we
don't want to make those a hard requirement for anyone building from
source.
Therefore the L<Git::LoadCPAN> namespace shipped with Git contains
wrapper modules like C<Git::LoadCPAN::Module::Name> that will first
attempt to load C<Module::Name> from the OS, and if that doesn't work
will fall back on C<Git::FromCPAN::Module::Name> shipped with Git
itself.
Usually distributors will not ship with Git's Git::FromCPAN tree at
all, preferring to use their own packaging of CPAN modules instead.
This module is only intended to be used for code shipping in the
C<git.git> repository. Use it for anything else at your peril!
=cut

sub import {
shift;
my $caller = caller;
my %args = @_;
my $module = exists $args{module} ? delete $args{module} : die "BUG: Expected 'module' parameter!";
my $import = exists $args{import} ? delete $args{import} : die "BUG: Expected 'import' parameter!";
die "BUG: Too many arguments!" if keys %args;

# Foo::Bar to Foo/Bar.pm
my $package_pm = $module;
$package_pm =~ s[::][/]g;
$package_pm .= '.pm';

eval {
require $package_pm;
1;
} or do {
my $error = $@ || "Zombie Error";

my $Git_LoadCPAN_pm_path = $INC{"Git/LoadCPAN.pm"} || die "BUG: Should have our own path from %INC!";

require File::Basename;
my $Git_LoadCPAN_pm_root = File::Basename::dirname($Git_LoadCPAN_pm_path) || die "BUG: Can't figure out lib/Git dirname from '$Git_LoadCPAN_pm_path'!";

require File::Spec;
my $Git_pm_FromCPAN_root = File::Spec->catdir($Git_LoadCPAN_pm_root, 'FromCPAN');
die "BUG: '$Git_pm_FromCPAN_root' should be a directory!" unless -d $Git_pm_FromCPAN_root;

local @INC = ($Git_pm_FromCPAN_root, @INC);
require $package_pm;
};

if ($import) {
no strict 'refs';
*{"${caller}::import"} = sub {
shift;
use strict 'refs';
unshift @_, $module;
goto &{"${module}::import"};
};
use strict 'refs';
}
}

1;
44 changes: 4 additions & 40 deletions perl/Git/LoadCPAN/Error.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,9 @@ package Git::LoadCPAN::Error;
use 5.008;
use strict;
use warnings;

=head1 NAME
Git::LoadCPAN::Error - Wrapper for the L<Error> module, in case it's not installed
=head1 DESCRIPTION
Wraps the import function for the L<Error> module.
This module is only intended to be used for code shipping in the
C<git.git> repository. Use it for anything else at your peril!
=cut

sub import {
shift;
my $caller = caller;

eval {
require Error;
1;
} or do {
my $error = $@ || "Zombie Error";

my $Git_Error_pm_path = $INC{"Git/LoadCPAN/Error.pm"} || die "BUG: Should have our own path from %INC!";

require File::Basename;
my $Git_Error_pm_root = File::Basename::dirname($Git_Error_pm_path) || die "BUG: Can't figure out lib/Git dirname from '$Git_Error_pm_path'!";

require File::Spec;
my $Git_pm_FromCPAN_root = File::Spec->catdir($Git_Error_pm_root, '..', 'FromCPAN');
die "BUG: '$Git_pm_FromCPAN_root' should be a directory!" unless -d $Git_pm_FromCPAN_root;

local @INC = ($Git_pm_FromCPAN_root, @INC);
require Error;
};

unshift @_, $caller;
goto &Error::import;
}
use Git::LoadCPAN (
module => 'Error',
import => 1,
);

1;
22 changes: 4 additions & 18 deletions perl/Git/LoadCPAN/Mail/Address.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,9 @@ package Git::LoadCPAN::Mail::Address;
use 5.008;
use strict;
use warnings;

=head1 NAME
Git::LoadCPAN::Mail::Address - Wrapper for the L<Mail::Address> module, in case it's not installed
=head1 DESCRIPTION
This module is only intended to be used for code shipping in the
C<git.git> repository. Use it for anything else at your peril!
=cut

eval {
require Mail::Address;
1;
} or do {
require Git::FromCPAN::Mail::Address;
};
use Git::LoadCPAN (
module => 'Mail::Address',
import => 0,
);

1;

0 comments on commit edfb7b9

Please sign in to comment.