mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-07 23:09:26 +00:00
98_Installer: introduce full system prereq analysis by using getter checkPrereq
git-svn-id: https://svn.fhem.de/fhem/trunk@19031 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
28119fcb3b
commit
da94cb3fd7
@ -17,8 +17,8 @@ sub Installer_Initialize($) {
|
||||
$modHash->{AttrList} =
|
||||
"disable:1,0 "
|
||||
. "disabledForIntervals "
|
||||
. "installerMode:update,developer "
|
||||
. "updateListReading:1,0 "
|
||||
. "implicitGlobalSearch:0,1 "
|
||||
. $readingFnAttributes;
|
||||
|
||||
return FHEM::Meta::InitMod( __FILE__, $modHash );
|
||||
@ -40,33 +40,34 @@ BEGIN {
|
||||
# Import from main::
|
||||
GP_Import(
|
||||
qw(
|
||||
readingsSingleUpdate
|
||||
readingsBulkUpdate
|
||||
readingsBulkUpdateIfChanged
|
||||
readingsBeginUpdate
|
||||
readingsEndUpdate
|
||||
ReadingsTimestamp
|
||||
defs
|
||||
modules
|
||||
cmds
|
||||
packages
|
||||
Log
|
||||
Log3
|
||||
Debug
|
||||
DoTrigger
|
||||
CommandAttr
|
||||
attr
|
||||
AttrVal
|
||||
ReadingsVal
|
||||
Value
|
||||
IsDisabled
|
||||
cmds
|
||||
CommandAttr
|
||||
Debug
|
||||
defs
|
||||
deviceEvents
|
||||
init_done
|
||||
gettimeofday
|
||||
InternalTimer
|
||||
RemoveInternalTimer
|
||||
LoadModule
|
||||
devspec2array
|
||||
DoTrigger
|
||||
FW_webArgs
|
||||
gettimeofday
|
||||
init_done
|
||||
InternalTimer
|
||||
IsDisabled
|
||||
LoadModule
|
||||
Log
|
||||
Log3
|
||||
modules
|
||||
packages
|
||||
readingsBeginUpdate
|
||||
readingsBulkUpdate
|
||||
readingsBulkUpdateIfChanged
|
||||
readingsEndUpdate
|
||||
readingsSingleUpdate
|
||||
ReadingsTimestamp
|
||||
ReadingsVal
|
||||
RemoveInternalTimer
|
||||
Value
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -111,8 +112,6 @@ sub Define($$) {
|
||||
$attr{$name}{room} = 'System';
|
||||
}
|
||||
|
||||
# __GetUpdatedata() unless ( defined($coreUpdate) );
|
||||
|
||||
readingsSingleUpdate( $hash, "state", "initialized", 1 )
|
||||
if ( ReadingsVal( $name, 'state', 'none' ) ne 'none' );
|
||||
|
||||
@ -226,15 +225,18 @@ sub Notify($$) {
|
||||
|
||||
#TODO
|
||||
# - filter out FHEM command modules from FHEMWEB view (+attribute) -> difficult as not pre-loaded
|
||||
# - disable FHEM automatic link to device instances in output
|
||||
sub Get($$@) {
|
||||
|
||||
my ( $hash, $name, @aa ) = @_;
|
||||
|
||||
my ( $cmd, @args ) = @aa;
|
||||
|
||||
if ( lc($cmd) eq 'search' ) {
|
||||
my $ret = CreateSearchList( $hash, $cmd, $args[0] );
|
||||
if ( lc($cmd) eq 'checkprereqs' ) {
|
||||
my $ret = CreatePrereqsList( $hash, $cmd, @args );
|
||||
return $ret;
|
||||
}
|
||||
elsif ( lc($cmd) eq 'search' ) {
|
||||
my $ret = CreateSearchList( $hash, $cmd, @args );
|
||||
return $ret;
|
||||
}
|
||||
elsif ( lc($cmd) eq 'showmoduleinfo' ) {
|
||||
@ -262,27 +264,55 @@ sub Get($$@) {
|
||||
return $ret;
|
||||
}
|
||||
else {
|
||||
my $installerMode = AttrVal( $name, 'installerMode', 'update' );
|
||||
my @fhemModules;
|
||||
foreach ( sort { "\L$a" cmp "\L$b" } keys %modules ) {
|
||||
next if ( $_ eq 'Global' );
|
||||
push @fhemModules, $_;
|
||||
}
|
||||
|
||||
my @fhemPackages;
|
||||
foreach ( sort { "\L$a" cmp "\L$b" } keys %packages ) {
|
||||
push @fhemPackages, $_;
|
||||
push @fhemModules, $_
|
||||
if ( $installerMode ne 'update'
|
||||
|| defined( $modules{$_}{LOADED} ) );
|
||||
}
|
||||
|
||||
my $list =
|
||||
'search'
|
||||
. ' showModuleInfo:FHEM,'
|
||||
. join( ',', @fhemModules )
|
||||
. ' showPackageInfo:'
|
||||
. join( ',', @fhemPackages )
|
||||
. ' zzGetModuleMETA.json:FHEM,'
|
||||
. join( ',', @fhemModules )
|
||||
. ' zzGetPackageMETA.json:'
|
||||
. join( ',', @fhemPackages );
|
||||
'search' . ' showModuleInfo:FHEM,' . join( ',', @fhemModules );
|
||||
|
||||
if ( $installerMode eq 'developer' ) {
|
||||
my @fhemPackages;
|
||||
foreach ( sort { "\L$a" cmp "\L$b" } keys %packages ) {
|
||||
push @fhemPackages, $_;
|
||||
}
|
||||
|
||||
$list .=
|
||||
' showPackageInfo:'
|
||||
. join( ',', @fhemPackages )
|
||||
. ' zzGetModuleMETA.json:FHEM,'
|
||||
. join( ',', @fhemModules )
|
||||
. ' zzGetPackageMETA.json:'
|
||||
. join( ',', @fhemPackages );
|
||||
}
|
||||
|
||||
$list .= " checkPrereqs";
|
||||
if ( $installerMode eq 'install' ) {
|
||||
my $dh;
|
||||
my $dir = $attr{global}{modpath};
|
||||
if ( opendir( $dh, $dir ) ) {
|
||||
my $counter = 0;
|
||||
foreach my $fn (
|
||||
grep { $_ ne "." && $_ ne ".." && !-d $_ && $_ =~ /\.cfg$/ }
|
||||
readdir($dh)
|
||||
)
|
||||
{
|
||||
$list .= ':' unless ($counter);
|
||||
$list .= ',' if ($counter);
|
||||
$list .= $fn;
|
||||
$counter++;
|
||||
}
|
||||
closedir($dh);
|
||||
}
|
||||
}
|
||||
elsif ( $installerMode eq 'update' ) {
|
||||
$list .= ':noArg';
|
||||
}
|
||||
|
||||
return "Unknown argument $cmd, choose one of $list";
|
||||
}
|
||||
@ -613,7 +643,8 @@ sub ExecuteFhemCommand($) {
|
||||
my $pkglist = join( ' ', @packages );
|
||||
return unless ( $pkglist ne '' );
|
||||
$installer->{npmuninstall} =~ s/%PACKAGES%/$pkglist/gi;
|
||||
print qq($installer->{npmuninstall}\n) if ( $installer->{debug} == 1 );
|
||||
print qq($installer->{npmuninstall}\n)
|
||||
if ( $installer->{debug} == 1 );
|
||||
$response = InstallerUninstall($installer);
|
||||
}
|
||||
elsif ( $cmd->{cmd} =~ /^update(?: (.+))?/ ) {
|
||||
@ -883,15 +914,387 @@ sub WriteReadings($$) {
|
||||
&& !defined( $decode_json->{error} ) );
|
||||
}
|
||||
|
||||
sub CreateSearchList ($$$) {
|
||||
my ( $hash, $getCmd, $search ) = @_;
|
||||
sub CreatePrereqsList {
|
||||
my $hash = shift;
|
||||
my $getCmd = shift;
|
||||
my $cfgfile = shift;
|
||||
my $mode = $cfgfile ? 'file' : 'live';
|
||||
$mode = 'list' if ( $cfgfile && defined( $modules{$cfgfile} ) );
|
||||
|
||||
my @defined;
|
||||
if ( $mode eq 'file' ) {
|
||||
@defined = __GetDefinedModulesFromFile($cfgfile);
|
||||
return
|
||||
'File '
|
||||
. $cfgfile
|
||||
. ' does not seem to contain any FHEM device configuration'
|
||||
unless ( @defined > 0 );
|
||||
}
|
||||
elsif ( $mode eq 'list' ) {
|
||||
@defined = @_;
|
||||
unshift @defined, $cfgfile;
|
||||
}
|
||||
Debug Dumper \@defined;
|
||||
|
||||
# disable automatic links to FHEM devices
|
||||
delete $FW_webArgs{addLinks};
|
||||
|
||||
my @ret;
|
||||
my $html =
|
||||
defined( $hash->{CL} ) && $hash->{CL}{TYPE} eq "FHEMWEB" ? 1 : 0;
|
||||
|
||||
my $header = '';
|
||||
my $footer = '';
|
||||
if ($html) {
|
||||
$header = '<html>';
|
||||
$footer = '</html>';
|
||||
}
|
||||
|
||||
my $tableOpen = '';
|
||||
my $rowOpen = '';
|
||||
my $rowOpenEven = '';
|
||||
my $rowOpenOdd = '';
|
||||
my $colOpen = '';
|
||||
my $txtOpen = '';
|
||||
my $txtClose = '';
|
||||
my $colClose = "\t\t\t";
|
||||
my $rowClose = '';
|
||||
my $tableClose = '';
|
||||
my $colorRed = '';
|
||||
my $colorGreen = '';
|
||||
my $colorClose = '';
|
||||
|
||||
if ($html) {
|
||||
$tableOpen = '<table class="block wide">';
|
||||
$rowOpen = '<tr class="column">';
|
||||
$rowOpenEven = '<tr class="column even">';
|
||||
$rowOpenOdd = '<tr class="column odd">';
|
||||
$colOpen = '<td>';
|
||||
$txtOpen = '<b>';
|
||||
$txtClose = '</b>';
|
||||
$colClose = '</td>';
|
||||
$rowClose = '</tr>';
|
||||
$tableClose = '</table>';
|
||||
$colorRed = '<span style="color:red">';
|
||||
$colorGreen = '<span style="color:green">';
|
||||
$colorClose = '</span>';
|
||||
}
|
||||
|
||||
my $space = $html ? ' ' : ' ';
|
||||
my $lb = $html ? '<br />' : "\n";
|
||||
my $lang = lc(
|
||||
AttrVal(
|
||||
$hash->{NAME}, 'language',
|
||||
AttrVal( 'global', 'language', 'EN' )
|
||||
)
|
||||
);
|
||||
|
||||
my $FW_CSRF = (
|
||||
defined( $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN} )
|
||||
? '&fwcsrf=' . $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN}
|
||||
: ''
|
||||
);
|
||||
|
||||
########
|
||||
# Getting Perl prereqs
|
||||
my $perlAnalyzed = 0;
|
||||
my %prereqs;
|
||||
|
||||
foreach my $modName ( keys %modules ) {
|
||||
next
|
||||
if ( $mode eq 'live'
|
||||
&& !defined( $modules{$modName}{LOADED} )
|
||||
&& $modName ne 'Installer' );
|
||||
next
|
||||
if ( $mode ne 'live'
|
||||
&& @defined > 0
|
||||
&& !grep ( /^$modName$/, @defined ) );
|
||||
|
||||
FHEM::Meta::Load($modName);
|
||||
|
||||
next
|
||||
unless ( defined( $modules{$modName}{META} ) );
|
||||
|
||||
if ( !defined( $modules{$modName}{META}{x_prereqs_src} ) ) {
|
||||
$perlAnalyzed = 2;
|
||||
next;
|
||||
}
|
||||
|
||||
next
|
||||
unless ( defined( $modules{$modName}{META}{prereqs} )
|
||||
&& defined( $modules{$modName}{META}{prereqs}{runtime} ) );
|
||||
my $modPreqs = $modules{$modName}{META}{prereqs}{runtime};
|
||||
|
||||
foreach my $mAttr (qw(requires recommends suggests)) {
|
||||
next
|
||||
unless ( defined( $modPreqs->{$mAttr} )
|
||||
&& keys %{ $modPreqs->{$mAttr} } > 0 );
|
||||
|
||||
foreach my $prereq ( keys %{ $modPreqs->{$mAttr} } ) {
|
||||
next
|
||||
if ( FHEM::Meta::ModuleIsPerlPragma($prereq)
|
||||
|| FHEM::Meta::ModuleIsPerlCore($prereq)
|
||||
|| FHEM::Meta::ModuleIsInternal($prereq) );
|
||||
|
||||
my $version = $modPreqs->{$mAttr}{$prereq};
|
||||
$version = '' if ( !defined($version) || $version eq '0' );
|
||||
|
||||
my $check = __IsInstalledPerl($prereq);
|
||||
my $installed = '';
|
||||
if ($check) {
|
||||
if ( $check ne '1' ) {
|
||||
my $nverReq =
|
||||
$version ne ''
|
||||
? version->parse($version)->numify
|
||||
: 0;
|
||||
my $nverInst = $check;
|
||||
|
||||
#TODO suport for version range:
|
||||
#https://metacpan.org/pod/CPAN::Meta::Spec#Version-Range
|
||||
if ( $nverReq > 0 && $nverInst < $nverReq ) {
|
||||
push @{ $prereqs{$prereq}{$mAttr}{by} },
|
||||
$modName
|
||||
unless (
|
||||
grep ( /^$modName$/,
|
||||
@{ $prereqs{$prereq}{$mAttr}{by} } )
|
||||
);
|
||||
push @{ $prereqs{$prereq}{$mAttr}{version} },
|
||||
$nverReq;
|
||||
|
||||
$perlAnalyzed = 1
|
||||
if ( $modules{$modName}{META}{x_prereqs_src} ne
|
||||
'META.json' && !$perlAnalyzed );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
push @{ $prereqs{$prereq}{$mAttr}{by} }, $modName
|
||||
unless (
|
||||
grep ( /^$modName$/,
|
||||
@{ $prereqs{$prereq}{$mAttr}{by} } ) );
|
||||
|
||||
$perlAnalyzed = 1
|
||||
if (
|
||||
$modules{$modName}{META}{x_prereqs_src} ne 'META.json'
|
||||
&& !$perlAnalyzed );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my %pending;
|
||||
my $found = 0;
|
||||
my $foundRequired = 0;
|
||||
my $foundRecommended = 0;
|
||||
my $foundSuggested = 0;
|
||||
my $foundRequiredPerl = 0;
|
||||
my $foundRecommendedPerl = 0;
|
||||
my $foundSuggestedPerl = 0;
|
||||
|
||||
# Consolidating prereqs
|
||||
foreach ( keys %prereqs ) {
|
||||
$found++;
|
||||
if ( defined( $prereqs{$_}{requires} ) ) {
|
||||
$foundRequired++;
|
||||
$foundRequiredPerl++;
|
||||
$pending{requires}{Perl}{$_} =
|
||||
$prereqs{$_}{requires}{by};
|
||||
|
||||
if ( defined( $prereqs{$_}{recommends} ) ) {
|
||||
foreach my $i ( @{ $prereqs{$_}{recommends}{by} } ) {
|
||||
push @{ $pending{requires}{Perl}{$_} }, $i
|
||||
unless (
|
||||
grep ( /^$i$/, @{ $pending{requires}{Perl}{$_} } ) );
|
||||
}
|
||||
}
|
||||
if ( defined( $prereqs{$_}{suggestes} ) ) {
|
||||
foreach my $i ( @{ $prereqs{$_}{suggestes}{by} } ) {
|
||||
push @{ $pending{suggestes}{Perl}{$_} }, $i
|
||||
unless (
|
||||
grep ( /^$i$/, @{ $pending{suggestes}{Perl}{$_} } ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( defined( $prereqs{$_}{recommends} ) ) {
|
||||
$foundRecommended++;
|
||||
$foundRecommendedPerl++;
|
||||
$pending{recommends}{Perl}{$_} =
|
||||
$prereqs{$_}{recommends}{by};
|
||||
|
||||
if ( defined( $prereqs{$_}{suggestes} ) ) {
|
||||
foreach my $i ( @{ $prereqs{$_}{suggestes}{by} } ) {
|
||||
push @{ $pending{suggestes}{Perl}{$_} }, $i
|
||||
unless (
|
||||
grep ( /^$i$/, @{ $pending{suggestes}{Perl}{$_} } ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$foundSuggested++;
|
||||
$foundSuggestedPerl++;
|
||||
$pending{suggests}{Perl}{$_} =
|
||||
$prereqs{$_}{suggests}{by};
|
||||
}
|
||||
}
|
||||
|
||||
# Display prereqs
|
||||
if ($found) {
|
||||
|
||||
foreach my $mAttr (qw(requires recommends suggests)) {
|
||||
next
|
||||
unless ( defined( $pending{$mAttr} )
|
||||
&& keys %{ $pending{$mAttr} } > 0 );
|
||||
|
||||
my $linecount = 1;
|
||||
my $importance = $mAttr;
|
||||
$importance = 'Required' if ( $mAttr eq 'requires' );
|
||||
$importance = 'Recommended' if ( $mAttr eq 'recommends' );
|
||||
$importance = 'Suggested' if ( $mAttr eq 'suggests' );
|
||||
|
||||
if ( $linecount == 1 ) {
|
||||
push @ret,
|
||||
'<a name="prereqResult'
|
||||
. $importance
|
||||
. '"></a><h3>'
|
||||
. $importance . '</h3>'
|
||||
. $lb;
|
||||
push @ret, $tableOpen . $rowOpen;
|
||||
push @ret, $colOpen . $txtOpen . 'Item' . $txtClose . $colClose;
|
||||
push @ret, $colOpen . $txtOpen . 'Type' . $txtClose . $colClose;
|
||||
push @ret,
|
||||
$colOpen . $txtOpen . 'Used by' . $txtClose . $colClose;
|
||||
push @ret, $rowClose;
|
||||
}
|
||||
|
||||
foreach my $area (qw(Perl)) {
|
||||
next
|
||||
unless ( defined( $pending{$mAttr}{$area} )
|
||||
&& keys %{ $pending{$mAttr}{$area} } > 0 );
|
||||
|
||||
foreach my $item (
|
||||
sort { "\L$a" cmp "\L$b" }
|
||||
keys %{ $pending{$mAttr}{$area} }
|
||||
)
|
||||
{
|
||||
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
|
||||
|
||||
my $linkitem = $item;
|
||||
$linkitem =
|
||||
'<a href="https://metacpan.org/pod/'
|
||||
. $item
|
||||
. '" target="_blank">'
|
||||
. $item . '</a>'
|
||||
if ($html);
|
||||
|
||||
my $linkmod = '';
|
||||
foreach ( sort { "\L$a" cmp "\L$b" }
|
||||
@{ $pending{$mAttr}{$area}{$item} } )
|
||||
{
|
||||
$linkmod .= ', ' unless ( $linkmod eq '' );
|
||||
if ($html) {
|
||||
$linkmod .=
|
||||
'<a href="?cmd=get '
|
||||
. $hash->{NAME}
|
||||
. ' showModuleInfo '
|
||||
. $_
|
||||
. $FW_CSRF . '">'
|
||||
. ( $_ eq 'Global' ? 'FHEM' : $_ ) . '</a>';
|
||||
}
|
||||
else {
|
||||
$linkmod .= ( $_ eq 'Global' ? 'FHEM' : $_ );
|
||||
}
|
||||
}
|
||||
|
||||
$l .= $colOpen . $linkitem . $colClose;
|
||||
$l .= $colOpen . $area . $colClose;
|
||||
$l .= $colOpen . $linkmod . $colClose;
|
||||
$l .= $rowClose;
|
||||
|
||||
push @ret, $l;
|
||||
$linecount++;
|
||||
}
|
||||
}
|
||||
|
||||
push @ret, $tableClose;
|
||||
}
|
||||
|
||||
unshift @ret,
|
||||
$lb
|
||||
. $space
|
||||
. $space
|
||||
. ( $html ? '<a href="#prereqResultSuggested">' : '' )
|
||||
. $foundSuggested
|
||||
. ' suggested '
|
||||
. ( $foundSuggested > 1 ? 'items' : 'item' )
|
||||
. ( $html ? '</a>' : '' )
|
||||
if ($foundSuggested);
|
||||
unshift @ret,
|
||||
$lb
|
||||
. $space
|
||||
. $space
|
||||
. ( $html ? '<a href="#prereqResultRecommended">' : '' )
|
||||
. $foundRecommended
|
||||
. ' recommended '
|
||||
. ( $foundRecommended > 1 ? 'items' : 'item' )
|
||||
. ( $html ? '</a>' : '' )
|
||||
if ($foundRecommended);
|
||||
unshift @ret,
|
||||
$lb
|
||||
. $space
|
||||
. $space
|
||||
. ( $html ? '<a href="#prereqResultRequired">' : '' )
|
||||
. $foundRequired
|
||||
. ' required '
|
||||
. ( $foundRequired > 1 ? 'items' : 'item' )
|
||||
. ( $html ? '</a>' : '' )
|
||||
if ($foundRequired);
|
||||
unshift @ret,
|
||||
$found
|
||||
. ' total missing '
|
||||
. ( $found > 1 ? 'prerequisites:' : 'prerequisite:' );
|
||||
}
|
||||
else {
|
||||
unshift @ret, 'Hooray! All prerequisites are met. 🥳';
|
||||
}
|
||||
|
||||
unshift @ret,
|
||||
'<a name="prereqResultTOP"></a><h2>'
|
||||
. ( $mode eq 'live' ? 'Live ' : '' )
|
||||
. 'System Prerequisites Check</h2>';
|
||||
|
||||
if ($perlAnalyzed) {
|
||||
push @ret,
|
||||
$lb
|
||||
. $txtOpen . 'Hint:'
|
||||
. $txtClose
|
||||
. ' Some of the used FHEM modules do not provide Perl prerequisites from its metadata.'
|
||||
. $lb;
|
||||
|
||||
if ( $perlAnalyzed == 1 ) {
|
||||
push @ret,
|
||||
'This check is based on automatic source code analysis and can be incorrect.';
|
||||
}
|
||||
elsif ( $perlAnalyzed == 2 ) {
|
||||
push @ret,
|
||||
'This check may be incomplete until you install Perl::PrereqScanner::NotQuiteLite.';
|
||||
}
|
||||
}
|
||||
|
||||
return $header . join( "\n", @ret ) . $footer;
|
||||
}
|
||||
|
||||
sub CreateSearchList ($$@) {
|
||||
my $hash = shift;
|
||||
my $getCmd = shift;
|
||||
my $search = join( '\s*', @_ );
|
||||
$search = '.+' unless ($search);
|
||||
|
||||
# disable automatic links to FHEM devices
|
||||
delete $FW_webArgs{addLinks};
|
||||
|
||||
my @ret;
|
||||
my $html = defined( $hash->{CL} ) && $hash->{CL}{TYPE} eq "FHEMWEB" ? 1 : 0;
|
||||
my $html =
|
||||
defined( $hash->{CL} ) && $hash->{CL}{TYPE} eq "FHEMWEB" ? 1 : 0;
|
||||
|
||||
my $header = '';
|
||||
my $footer = '';
|
||||
@ -923,8 +1326,8 @@ sub CreateSearchList ($$$) {
|
||||
$rowOpenEven = '<tr class="column even">';
|
||||
$rowOpenOdd = '<tr class="column odd">';
|
||||
$colOpen = '<td>';
|
||||
$txtOpen = "<b>";
|
||||
$txtClose = "</b>";
|
||||
$txtOpen = '<b>';
|
||||
$txtClose = '</b>';
|
||||
$colClose = '</td>';
|
||||
$rowClose = '</tr>';
|
||||
$tableClose = '</table>';
|
||||
@ -998,11 +1401,12 @@ sub CreateSearchList ($$$) {
|
||||
|
||||
$l .= $colOpen . $linkDev . $colClose;
|
||||
$l .= $colOpen . $linkMod . $colClose;
|
||||
$l .=
|
||||
$colOpen
|
||||
$l .= $colOpen
|
||||
. (
|
||||
defined( $defs{$device}{STATE} ) ? $defs{$device}{STATE} : '' )
|
||||
. $colClose;
|
||||
defined( $defs{$device}{STATE} )
|
||||
? $defs{$device}{STATE}
|
||||
: ''
|
||||
) . $colClose;
|
||||
|
||||
$l .= $rowClose;
|
||||
|
||||
@ -1385,6 +1789,10 @@ sub CreateSearchList ($$$) {
|
||||
. $cmdO
|
||||
. '</a> instead?';
|
||||
}
|
||||
|
||||
delete $hash->{CL}{'.iDefCmdOrigin'};
|
||||
delete $hash->{CL}{'.iDefCmdMethod'};
|
||||
delete $hash->{CL}{'.iDefCmdOverwrite'};
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
@ -1449,6 +1857,7 @@ sub CreateSearchList ($$$) {
|
||||
unshift @ret, 'Nothing found';
|
||||
}
|
||||
|
||||
$search =~ s/\\s\*/ /g;
|
||||
unshift @ret,
|
||||
'<a name="searchResultTOP"></a><h2>Search result: ' . $search . '</h2>';
|
||||
|
||||
@ -1499,7 +1908,8 @@ sub CreateMetadataList ($$$) {
|
||||
? $modules{$modName}{META}
|
||||
: $packages{$modName}{META};
|
||||
my @ret;
|
||||
my $html = defined( $hash->{CL} ) && $hash->{CL}{TYPE} eq "FHEMWEB" ? 1 : 0;
|
||||
my $html =
|
||||
defined( $hash->{CL} ) && $hash->{CL}{TYPE} eq "FHEMWEB" ? 1 : 0;
|
||||
|
||||
my $header = '';
|
||||
my $footer = '';
|
||||
@ -1531,8 +1941,8 @@ sub CreateMetadataList ($$$) {
|
||||
$rowOpenEven = '<tr class="column even">';
|
||||
$rowOpenOdd = '<tr class="column odd">';
|
||||
$colOpen = '<td>';
|
||||
$txtOpen = "<b>";
|
||||
$txtClose = "</b>";
|
||||
$txtOpen = '<b>';
|
||||
$txtClose = '</b>';
|
||||
$colClose = '</td>';
|
||||
$rowClose = '</tr>';
|
||||
$tableClose = '</table>';
|
||||
@ -1587,7 +1997,8 @@ sub CreateMetadataList ($$$) {
|
||||
|| $modMeta->{release_status} eq 'stable' )
|
||||
);
|
||||
next
|
||||
if ( $mAttr eq 'copyright' && !defined( $modMeta->{x_copyright} ) );
|
||||
if ( $mAttr eq 'copyright'
|
||||
&& !defined( $modMeta->{x_copyright} ) );
|
||||
next
|
||||
if (
|
||||
$mAttr eq 'abstract'
|
||||
@ -1779,22 +2190,10 @@ sub CreateMetadataList ($$$) {
|
||||
? $modMeta->{resources}{x_commandref}{title}
|
||||
: 'Online version';
|
||||
|
||||
my $url =
|
||||
$modMeta->{resources}{x_commandref}{web};
|
||||
|
||||
if (
|
||||
defined( $modMeta->{resources}{x_commandref}{modpath} )
|
||||
)
|
||||
{
|
||||
$url .=
|
||||
$modMeta->{resources}{x_commandref}{modpath};
|
||||
$url .= $modName eq 'Global' ? 'global' : $modName;
|
||||
}
|
||||
|
||||
$l .=
|
||||
( $webname ? ' | ' : '' )
|
||||
. '<a href="'
|
||||
. $url
|
||||
. $modMeta->{resources}{x_commandref}{web}
|
||||
. '" target="_blank">'
|
||||
. $title . '</a>';
|
||||
}
|
||||
@ -1820,12 +2219,11 @@ sub CreateMetadataList ($$$) {
|
||||
&& $modMeta->{resources}{x_wiki}{web} =~
|
||||
m/^(?:https?:\/\/)?wiki\.fhem\.de/i );
|
||||
|
||||
my $url =
|
||||
$modMeta->{resources}{x_wiki}{web};
|
||||
$url .= '/' unless ( $url =~ m/\/$/ );
|
||||
|
||||
$l .=
|
||||
'<a href="' . $url . '" target="_blank">' . $title . '</a>';
|
||||
'<a href="'
|
||||
. $modMeta->{resources}{x_wiki}{web}
|
||||
. '" target="_blank">'
|
||||
. $title . '</a>';
|
||||
}
|
||||
|
||||
elsif ($mAttr eq 'community_support'
|
||||
@ -2233,7 +2631,6 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
|
||||
push @ret, $tableClose;
|
||||
|
||||
# show FHEM modules who use this package
|
||||
# if ( $modType eq 'package' ) {
|
||||
@mAttrs = qw(
|
||||
requires
|
||||
recommends
|
||||
@ -2319,20 +2716,47 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
|
||||
|
||||
push @ret, $tableClose . $lb if ( $linecount > 1 );
|
||||
|
||||
# }
|
||||
if ( $modType eq 'module' && $modName ne 'Global' ) {
|
||||
push @ret, '<h3>Devices</h3>';
|
||||
|
||||
if ( defined( $modules{$modName}{LOADED} ) ) {
|
||||
my @instances = devspec2array( 'TYPE=' . $modName );
|
||||
if ( @instances > 0 ) {
|
||||
push @ret, $lb, $tableOpen . $rowOpen;
|
||||
|
||||
my $devices = '';
|
||||
foreach my $instance ( sort { "\L$a" cmp "\L$b" } @instances ) {
|
||||
next if ( defined( $defs{$instance}{TEMPORARY} ) );
|
||||
$devices .= ', ' unless ( $devices eq '' );
|
||||
if ($html) {
|
||||
$devices .=
|
||||
'<a href="?detail='
|
||||
. $instance . '">'
|
||||
. $instance . '</a>';
|
||||
}
|
||||
else {
|
||||
$devices .= $instance;
|
||||
}
|
||||
}
|
||||
|
||||
push @ret, $colOpen . $devices . $colClose;
|
||||
|
||||
push @ret, $rowClose . $tableClose;
|
||||
}
|
||||
else {
|
||||
push @ret,
|
||||
$lb
|
||||
. 'This module was once loaded into memory, '
|
||||
. 'but currently there is no device defined anymore.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
push @ret, $lb . 'This module is currently not in use.';
|
||||
}
|
||||
}
|
||||
|
||||
push @ret, '<h3>System Prerequisites</h3>';
|
||||
|
||||
if ( $modType eq 'module' ) {
|
||||
my $moduleUsage =
|
||||
defined( $modules{$modName}{LOADED} )
|
||||
? $colorGreen . 'IN USE' . $colorClose
|
||||
: $txtOpen . 'not' . $txtClose . ' in use';
|
||||
|
||||
push @ret, $lb . 'This FHEM module is currently ' . $moduleUsage . '.'
|
||||
unless ( $modName eq 'Global' );
|
||||
}
|
||||
|
||||
push @ret, '<h4>Perl Packages</h4>';
|
||||
if ( defined( $modMeta->{prereqs} )
|
||||
&& defined( $modMeta->{prereqs}{runtime} ) )
|
||||
@ -2421,8 +2845,10 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
|
||||
my $isPerlPragma = FHEM::Meta::ModuleIsPerlPragma($prereq);
|
||||
my $isPerlCore =
|
||||
$isPerlPragma ? 0 : FHEM::Meta::ModuleIsPerlCore($prereq);
|
||||
my $isFhem = $isPerlPragma
|
||||
|| $isPerlCore ? 0 : FHEM::Meta::ModuleIsInternal($prereq);
|
||||
my $isFhem =
|
||||
$isPerlPragma || $isPerlCore
|
||||
? 0
|
||||
: FHEM::Meta::ModuleIsInternal($prereq);
|
||||
if ( $isPerlPragma || $isPerlCore || $prereq eq 'perl' ) {
|
||||
$installed =
|
||||
$installed ne 'installed'
|
||||
@ -2522,7 +2948,9 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
|
||||
0 );
|
||||
|
||||
foreach my $prereq (
|
||||
sort keys %{ $modMeta->{x_prereqs_nodejs}{runtime}{$mAttr} } )
|
||||
sort
|
||||
keys %{ $modMeta->{x_prereqs_nodejs}{runtime}{$mAttr} }
|
||||
)
|
||||
{
|
||||
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
|
||||
|
||||
@ -2624,7 +3052,9 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
|
||||
0 );
|
||||
|
||||
foreach my $prereq (
|
||||
sort keys %{ $modMeta->{x_prereqs_python}{runtime}{$mAttr} } )
|
||||
sort
|
||||
keys %{ $modMeta->{x_prereqs_python}{runtime}{$mAttr} }
|
||||
)
|
||||
{
|
||||
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
|
||||
|
||||
@ -2672,8 +3102,10 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
|
||||
my $isPerlPragma = FHEM::Meta::ModuleIsPerlPragma($prereq);
|
||||
my $isPerlCore =
|
||||
$isPerlPragma ? 0 : FHEM::Meta::ModuleIsPerlCore($prereq);
|
||||
my $isFhem = $isPerlPragma
|
||||
|| $isPerlCore ? 0 : FHEM::Meta::ModuleIsInternal($prereq);
|
||||
my $isFhem =
|
||||
$isPerlPragma || $isPerlCore
|
||||
? 0
|
||||
: FHEM::Meta::ModuleIsInternal($prereq);
|
||||
if ( $isPerlPragma || $isPerlCore || $prereq eq 'perl' ) {
|
||||
$installed =
|
||||
$installed ne 'installed'
|
||||
@ -2758,6 +3190,30 @@ sub CreateRawMetaJson ($$$) {
|
||||
}
|
||||
}
|
||||
|
||||
sub __GetDefinedModulesFromFile($) {
|
||||
my ($filePath) = @_;
|
||||
my @modules;
|
||||
my $fh;
|
||||
|
||||
if ( open( $fh, '<' . $filePath ) ) {
|
||||
while ( my $l = <$fh> ) {
|
||||
if ( $l =~ /^define\s+\S+\s+(\S+).*/ ) {
|
||||
my $modName = $1;
|
||||
push @modules, $modName
|
||||
unless ( grep ( /^$modName$/, @modules ) );
|
||||
}
|
||||
}
|
||||
close($fh);
|
||||
}
|
||||
|
||||
if (wantarray) {
|
||||
return @modules;
|
||||
}
|
||||
elsif ( @modules > 0 ) {
|
||||
return join( ',', @modules );
|
||||
}
|
||||
}
|
||||
|
||||
# Checks whether a perl package is installed in the system
|
||||
sub __IsInstalledPerl($) {
|
||||
return 0 unless ( __PACKAGE__ eq caller(0) );
|
||||
@ -2867,8 +3323,18 @@ sub __aUniq {
|
||||
<br>
|
||||
<a name="Installerget" id="Installerget"></a><b>Get</b>
|
||||
<ul>
|
||||
<li>checkPrereqs - list all missing prerequisites. If no parameter was given, the running live system will be inspected. If the parameter is a FHEM cfg file, inspection will be based on devices from this file. If the parameter is a list of module names, those will be used for inspection.
|
||||
</li>
|
||||
<li>search - search FHEM for device names, module names, package names, keywords, authors and Perl package names.
|
||||
</li>
|
||||
<li>showModuleInfo - list information about a specific FHEM module
|
||||
</li>
|
||||
<li>showPackageInfo - list information about a specific FHEM package
|
||||
</li>
|
||||
<li>zzGetModuleMETA.json - prints raw meta information of a FHEM module in JSON format
|
||||
</li>
|
||||
<li>zzGetPackageMETA.json - prints raw meta information of a FHEM package in JSON format
|
||||
</li>
|
||||
</ul><br>
|
||||
<br>
|
||||
<a name="Installerattribut" id="Installerattribut"></a><b>Attributes</b>
|
||||
@ -2877,6 +3343,8 @@ sub __aUniq {
|
||||
</li>
|
||||
<li>disabledForIntervals - disable device for interval time (13:00-18:30 or 13:00-18:30 22:00-23:00)
|
||||
</li>
|
||||
<li>installerMode - sets the installation mode. May be update, developer or install with update being the default setting. Some get and/or set commands may be hidden or limited depending on this.
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
|
||||
@ -2907,7 +3375,7 @@ sub __aUniq {
|
||||
"abstract": "Modul zum Update von FHEM, zur Installation von Drittanbieter FHEM Modulen und der Verwaltung von Systemvoraussetzungen"
|
||||
}
|
||||
},
|
||||
"version": "v0.2.1",
|
||||
"version": "v0.3.0",
|
||||
"release_status": "testing",
|
||||
"author": [
|
||||
"Julian Pawlowski <julian.pawlowski@gmail.com>"
|
||||
|
@ -1946,7 +1946,8 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
|
||||
{
|
||||
if ( defined( $modMeta->{x_vcs} ) ) {
|
||||
$modMeta->{resources}{x_commandref}{web} =
|
||||
'https://fhem.de/commandref.html#' . $modName;
|
||||
'https://fhem.de/commandref.html#'
|
||||
. ( $modName eq 'Global' ? 'global' : $modName );
|
||||
}
|
||||
}
|
||||
|
||||
@ -3075,6 +3076,9 @@ sub __SetXVersion {
|
||||
"description": "FHEM® (eingetragene Marke) ist ein in Perl geschriebener, GPL lizensierter Server für die Heimautomatisierung. Man kann mit FHEM häufig auftretende Aufgaben automatisieren, wie z.Bsp. Lampen / Rollladen / Heizung / usw. schalten, oder Ereignisse wie Temperatur / Feuchtigkeit / Stromverbrauch protokollieren und visualisieren.\\nDas Programm läuft als Server, man kann es über WEB, dedizierte Smartphone Apps oder telnet bedienen, TCP Schnittstellen für JSON und XML existieren ebenfalls.\\nUm es zu verwenden benötigt man einen 24/7 Rechner (NAS, RPi, PC, Mac Mini, etc.) mit einem Perl Interpreter und angeschlossene Hardware-Komponenten wie CUL-, EnOcean-, Z-Wave-USB-Stick, etc. für einen Zugang zu den Aktoren und Sensoren.\\nAusgesprochen wird es ohne h, wie bei feminin."
|
||||
}
|
||||
},
|
||||
"resources": {
|
||||
"homepage": "https://fhem.de/"
|
||||
},
|
||||
"prereqs": {
|
||||
"runtime": {
|
||||
"requires": {
|
||||
|
Loading…
x
Reference in New Issue
Block a user