diff --git a/fhem/FHEM/98_Installer.pm b/fhem/FHEM/98_Installer.pm
index c0db2c6d7..26b68fd2e 100644
--- a/fhem/FHEM/98_Installer.pm
+++ b/fhem/FHEM/98_Installer.pm
@@ -856,7 +856,10 @@ sub ExecuteFhemCommand($) {
$installer->{debug} = $cmd->{debug};
my $sudo = 'sudo -n ';
- $installer->{cpanversions} = 'echo n | ' . 'cpanm --version 2>&1';
+ $installer->{cpanversions} =
+'echo n | TEST=$(which cpanm) || echo "sh: command not found: cpanm"; which cpanm >/dev/null 2>&1 && sh -c "'
+ . $sudo
+ . '$(which cpanm) --version 2>&1" 2>&1';
$installer->{installperl} =
'echo n | sh -c "'
. $sudo
@@ -884,11 +887,9 @@ sub ExecuteFhemCommand($) {
{
if ( $1 =~ /App::cpanminus/i ) {
$installer->{installperl} =
- 'echo n | if [ -z "$(cpanm --version 2>/dev/null)" ]; then'
- . ' sh -c "curl -fsSL https://git.io/cpanm | '
+ 'sh -c "curl -fsSL https://git.io/cpanm | '
. $sudo
. '$(which perl) - App::cpanminus >/dev/null 2>&1" 2>&1; '
- . 'fi; '
. 'cpanm --version >/dev/null'
. ' && sh -c "'
. $sudo
@@ -1001,6 +1002,8 @@ sub GetCpanVersion($) {
if ( $line =~
m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?not.found$/i
or $line =~
+m/(?:(\w+?): )?(?:(\w+? \d+): )?\w+?: [^:]*?not.found: (\S+)$/i
+ or $line =~
m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i
)
{
@@ -1008,6 +1011,30 @@ m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i
$error->{summary} = "Not Found - $3 is not installed";
$error->{detail} = $line;
}
+ elsif ( $line =~ m/^sudo: /i ) {
+ my $error = {};
+ my $runningUser = getpwuid($<);
+ my $cpanmbin = `which cpanm`;
+ my $perlbin = `which perl`;
+ $cpanmbin =~ s/\n//g;
+ $perlbin =~ s/\n//g;
+ $error->{code} = "E403";
+ $error->{summary} =
+ "Forbidden - " . "passwordless sudo permissions required";
+ $error->{detail} =
+ $line
+ . "
"
+ . "You may add the following lines to /etc/sudoers.d/$runningUser:\n"
+ . "
" + . " $runningUser ALL=(ALL) NOPASSWD:SETENV: " + . $cpanmbin . " *" + . "\n $runningUser ALL=(ALL) NOPASSWD:SETENV: " + . $perlbin + . ' - App\:\:cpanminus' + . ""; + push @{ $h->{error} }, $error; + last; + } else { $error->{code} = "E501"; $error->{summary} = "Parsing error"; @@ -1088,6 +1115,8 @@ sub CpanInstall($) { elsif ( $line =~ m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?not.found$/i or $line =~ + m/(?:(\w+?): )?(?:(\w+? \d+): )?\w+?: [^:]*?not.found: (\S+)$/i + or $line =~ m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i ) { @@ -1103,7 +1132,9 @@ m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i my $error = {}; my $runningUser = getpwuid($<); my $cpanmbin = `which cpanm`; + my $perlbin = `which perl`; $cpanmbin =~ s/\n//g; + $perlbin =~ s/\n//g; $error->{code} = "E403"; $error->{summary} = "Forbidden - " . "passwordless sudo permissions required"; @@ -1113,7 +1144,7 @@ m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i . "You may add the following lines to /etc/sudoers.d/$runningUser:\n" . "
"
. " $runningUser ALL=(ALL) NOPASSWD:SETENV: "
- . $cpanmbin
+ . $perlbin
. ' - App\:\:cpanminus'
. "";
push @{ $h->{error} }, $error;
@@ -1194,6 +1225,8 @@ sub CpanUninstall($) {
elsif ( $line =~
m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?not.found$/i
or $line =~
+ m/(?:(\w+?): )?(?:(\w+? \d+): )?\w+?: [^:]*?not.found: (\S+)$/i
+ or $line =~
m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i
)
{
@@ -1329,6 +1362,8 @@ sub CpanOutdated($) {
if ( $line =~
m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?not.found$/i
or $line =~
+m/(?:(\w+?): )?(?:(\w+? \d+): )?\w+?: [^:]*?not.found: (\S+)$/i
+ or $line =~
m/(?:(\w+?): )?(?:(\w+? \d+): )?(\w+?): [^:]*?No.such.file.or.directory$/i
)
{
diff --git a/fhem/FHEM/Meta.pm b/fhem/FHEM/Meta.pm
index 80167c8ac..4173a2134 100644
--- a/fhem/FHEM/Meta.pm
+++ b/fhem/FHEM/Meta.pm
@@ -971,6 +971,8 @@ sub __PutMetadata {
return undef;
}
+my $scanner; # keep the scanner defined
+
# Extract metadata from FHEM module file
sub __GetMetadata {
return 0 unless ( __PACKAGE__ eq caller(0) );
@@ -1247,75 +1249,80 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
if ( keys %json > 0 ) {
- # try to use JSON::MaybeXS wrapper
- # for chance of better performance + open code
- # See: https://perlmaven.com/comparing-the-speed-of-json-decoders
- eval {
- require JSON::MaybeXS;
- import JSON::MaybeXS qw( decode_json );
- 1;
- };
- if ($@) {
- $@ = undef;
+ unless ( defined( &{'decode_json'} ) ) {
- # try to use JSON wrapper
- # for chance of better performance
+ # try to use JSON::MaybeXS wrapper
+ # for chance of better performance + open code
+ # See: https://perlmaven.com/comparing-the-speed-of-json-decoders
eval {
- require JSON;
- import JSON qw( decode_json );
+ require JSON::MaybeXS;
+ import JSON::MaybeXS qw( decode_json );
1;
};
-
if ($@) {
$@ = undef;
- # In rare cases, Cpanel::JSON::XS may
- # be installed but JSON|JSON::MaybeXS not ...
+ # try to use JSON wrapper
+ # for chance of better performance
eval {
- require Cpanel::JSON::XS;
- import Cpanel::JSON::XS qw(decode_json encode_json);
+ require JSON;
+ import JSON qw( decode_json );
1;
};
if ($@) {
$@ = undef;
- # In rare cases, JSON::XS may
- # be installed but JSON not ...
+ # In rare cases, Cpanel::JSON::XS may
+ # be installed but JSON|JSON::MaybeXS not ...
eval {
- require JSON::XS;
- import JSON::XS qw(decode_json encode_json);
+ require Cpanel::JSON::XS;
+ import Cpanel::JSON::XS qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
- # Fallback to built-in JSON which SHOULD
- # be available since 5.014 ...
+ # In rare cases, JSON::XS may
+ # be installed but JSON not ...
eval {
- require JSON::PP;
- import JSON::PP qw(decode_json encode_json);
+ require JSON::XS;
+ import JSON::XS qw(decode_json encode_json);
1;
};
if ($@) {
$@ = undef;
- # Fallback to JSON::backportPP in really rare cases
+ # Fallback to built-in JSON which SHOULD
+ # be available since 5.014 ...
eval {
- require JSON::backportPP;
- import JSON::backportPP
- qw(decode_json encode_json);
+ require JSON::PP;
+ import JSON::PP qw(decode_json encode_json);
1;
};
+
+ if ($@) {
+ $@ = undef;
+
+ # Fallback to JSON::backportPP
+ # in really rare cases
+ eval {
+ require JSON::backportPP;
+ import JSON::backportPP
+ qw(decode_json encode_json);
+ 1;
+ };
+ $@ = undef;
+ }
}
}
}
}
}
- if ( !$@ ) {
+ if ( defined( &{'decode_json'} ) ) {
foreach ( keys %json ) {
next
if (
@@ -1360,9 +1367,6 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
}
return undef if ($metaSection);
}
- else {
- $@ = undef;
- }
}
# special place for fhem.pl is this module file
@@ -1378,16 +1382,27 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
# Detect prereqs if not provided via META.json
if ( !defined( $modMeta->{prereqs} ) ) {
- eval {
- require Perl::PrereqScanner::NotQuiteLite;
- 1;
- };
- if ( !$@ ) {
- my $scanner = Perl::PrereqScanner::NotQuiteLite->new(
- parsers => [qw/:installed -UniversalVersion/],
- suggests => 1,
- );
+ # Initialize scanner first
+ unless ( defined($scanner) ) {
+ eval {
+ require Perl::PrereqScanner::NotQuiteLite;
+ 1;
+ };
+
+ if ($@) {
+ $@ = undef;
+ }
+ else {
+ $scanner = Perl::PrereqScanner::NotQuiteLite->new(
+ parsers => [qw/:installed -UniversalVersion/],
+ suggests => 1,
+ );
+ }
+ }
+
+ # Scan files
+ if ( defined($scanner) ) {
my $context = $scanner->scan_file($filePath);
my $requirements = $context->requires;
my $recommends = $context->recommends;
@@ -1446,9 +1461,6 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
}
}
}
- else {
- $@ = undef;
- }
}
else {
$modMeta->{x_prereqs_src} = 'META.json';