our
$AUTHORITY
=
'cpan:DDG'
;
$App::DuckPAN::Perl::VERSION
=
'1007'
;
no
warnings
'uninitialized'
;
sub
get_local_version {
my
(
$self
,
$module
) =
@_
;
my
$v
;
{
local
$@;
eval
{
my
$m
= Module::Data->new(
$module
);
$m
->
require
;
$v
=
$m
->version;
1;
} or
return
;
};
unless
(
defined
$v
) {
if
(
$module
eq
'App::DuckPAN'
||
$module
eq
'DDG'
){
return
$self
->app->dev_version;
}
return
;
}
return
version->parse(
$v
)
unless
ref
$v
;
return
$v
;
}
sub
cpanminus_install_error {
shift
->app->emit_and_exit(1,
"Failure on installation of modules!"
,
"There are several possible explanations and fixes for this error:"
,
"1. The download from CPAN was unsuccessful - Please restart this installer."
,
"2. Some other error occured - Please read the `build.log` mentioned in the errors and see if you can fix the problem yourself."
,
"If you are unable to solve the problem, please let us know by making a GitHub Issue in the DuckPAN Repo:"
,
"Make sure to attach the `build.log` file if it exists. Otherwise, copy/paste the output you see."
);
}
sub
duckpan_install {
my
(
$self
,
@modules
) =
@_
;
my
$mirror
=
$self
->app->duckpan;
my
(
$reinstall
,
$latest
);
my
$reinstall_latest
=
$modules
[0];
if
(
$reinstall_latest
eq
'reinstall'
) {
$reinstall
= 1;
shift
@modules
;
}
elsif
(
$reinstall_latest
eq
'latest'
) {
$latest
= 1;
shift
@modules
;
}
my
$packages
=
$self
->app->duckpan_packages;
my
@to_install
;
for
(
@modules
) {
my
$module
=
$packages
->
package
(
$_
);
$self
->app->emit_and_exit(1,
"Can't find package "
.
$_
.
" on "
.
$self
->app->duckpan)
unless
$module
;
my
$package
=
$module
->
package
;
my
$sp
=
$package
;
$sp
=~ s/\:\:/_/g;
my
$pinned_version
=
$ENV
{
$sp
};
my
$installed_version
=
$self
->get_local_version(
$package
);
my
$latest_version
= version->parse(
$module
->version);
my
$duckpan_module_url
=
$self
->app->duckpan .
'authors/id/'
.
$module
->distribution->pathname;
$self
->app->emit_info(
"$package: $installed_version installed, $pinned_version pinned, $latest_version latest"
)
if
$pinned_version
;
if
(
$installed_version
==
$self
->app->dev_version){
$self
->app->emit_notice(
"Skipping installation of $package. Development version detected!"
);
next
;
}
my
(
$install_it
,
$message
);
if
(
$reinstall
||
$latest
|| !
$installed_version
) {
my
$version
;
$version
=
$installed_version
unless
$latest
;
$version
||=
$pinned_version
||
$latest_version
;
if
(
$version
!=
$latest_version
){
unless
(
$duckpan_module_url
=
$self
->find_previous_url(
$module
,
$version
)){
$self
->app->emit_and_exit(1,
"Failed to find version $version of $package"
);
}
}
$message
=
$reinstall
?
"Reinstalling $package, version ($version)"
:
"You don't have $package installed. Installing version ($version)"
;
$install_it
= 1;
}
elsif
(
$pinned_version
) {
if
(
$pinned_version
!=
$installed_version
) {
if
(
$pinned_version
==
$latest_version
|| (
$duckpan_module_url
=
$self
->find_previous_url(
$module
,
$pinned_version
))) {
$install_it
= 1;
}
else
{
$message
=
"Could not locate version $pinned_version of '$package'"
;
$self
->app->emit_and_exit(1,
$message
);
}
}
else
{
$message
= (
$pinned_version
==
$latest_version
) ?
"You already have the latest version of '$package' installed!"
:
"A newer version of '$package' exists. Please update your version pin to match the newest version: $latest_version"
;
$install_it
= 0;
}
}
elsif
(
$installed_version
==
$latest_version
) {
$message
=
"You already have latest version ($installed_version) of $package"
;
}
elsif
(
$installed_version
>
$latest_version
) {
$message
=
"You have a newer version ($installed_version) of $package than duckpan.org ($latest_version)"
;
}
else
{
$message
=
"You have an older version ($installed_version) of $package than duckpan.org. Installing latest version ($latest_version)"
;
$install_it
= 1;
}
$self
->app->emit_notice(
$message
);
push
@to_install
,
$duckpan_module_url
if
(
$install_it
&& !(first {
$_
eq
$duckpan_module_url
}
@to_install
));
}
if
(
@to_install
){
unshift
@to_install
,
'--reinstall'
if
$reinstall
;
if
(
system
"cpanm @to_install"
){
my
$err
=
"cpanm failed (err $?) to (re)install the following modules:\n\n\t"
.
join
(
"\n\t"
,
@to_install
);
$self
->app->emit_and_exit(1,
$err
);
}
}
}
my
@POTENTIAL_AUTHORS
=
qw|
ALOHAAS
ANDREY_P
BRAD
BRIANS
CAINE
CRAZEDPSYC
DDGC
DYLANLL
GETTY
JAG
JBARRETT
JDORW
MGA
MOOLLAZA
RSSSSL
SDOUGBROWN
TOMMYTOMMYTOMMY
YEGG
ZT
|
;
sub
find_previous_url {
my
(
$self
,
$module
,
$desired_version
) =
@_
;
my
@cpanids
= uniq(
$self
->authors_of_latest_dists,
@POTENTIAL_AUTHORS
);
my
@cpan_dirs
=
map
{
join
(
'/'
,
substr
(
$_
, 0, 1),
substr
(
$_
, 0, 2),
$_
) }
@cpanids
;
my
$dist
=
$module
->distribution;
my
$filename
=
$dist
->filename;
$filename
=~ s|^[A-Z]/[A-Z]{2}/.*?/||;
my
$version
=
$dist
->version;
$filename
=~ s/
$version
/
$desired_version
/;
my
@urls
=
map
{
$self
->app->duckpan .
'authors/id/'
.
$_
.
'/'
.
$filename
}
@cpan_dirs
;
$self
->app->emit_debug(
"Checking up to "
.
scalar
@urls
.
" distributions for pinned version..."
);
my
$ua
= LWP::UserAgent->new(
agent
=>
'DPPF/0.001a'
,
requests_redirectable
=> []);
return
first {
$ua
->head(
$_
)->is_success }
@urls
;
}
sub
authors_of_latest_dists {
my
(
$self
) =
@_
;
my
@dists
=
$self
->app->duckpan_packages->distributions;
return
grep
{
defined
$_
}
map
{
$_
->cpanid }
@dists
;
}
1;