diff --git a/FHEM/98_Installer.pm b/FHEM/98_Installer.pm index c0db2c6d7..26b68fd2e 100644 --- a/FHEM/98_Installer.pm +++ b/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/Meta.pm b/FHEM/Meta.pm index 80167c8ac..4173a2134 100644 --- a/FHEM/Meta.pm +++ b/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';