2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-14 21:49:12 +00:00

98_Installer: add FHEM package support

git-svn-id: https://svn.fhem.de/fhem/trunk@18993 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jpawlowski 2019-03-22 17:03:29 +00:00
parent 3652069621
commit 0512bbf5e2
2 changed files with 931 additions and 357 deletions

View File

@ -47,6 +47,7 @@ BEGIN {
ReadingsTimestamp
defs
modules
packages
Log
Log3
Debug
@ -240,12 +241,24 @@ sub Get($$@) {
my $ret = CreateMetadataList( $hash, $cmd, $args[0] );
return $ret;
}
elsif ( lc($cmd) eq 'zzgetmeta.json' ) {
elsif ( lc($cmd) eq 'showpackageinfo' ) {
return "usage: $cmd PACKAGE" if ( @args != 1 );
my $ret = CreateMetadataList( $hash, $cmd, $args[0] );
return $ret;
}
elsif ( lc($cmd) eq 'zzgetmodulemeta.json' ) {
return "usage: $cmd MODULE" if ( @args != 1 );
my $ret = CreateRawMetaJson( $hash, $cmd, $args[0] );
return $ret;
}
elsif ( lc($cmd) eq 'zzgetpackagemeta.json' ) {
return "usage: $cmd PACKAGE" if ( @args != 1 );
my $ret = CreateRawMetaJson( $hash, $cmd, $args[0] );
return $ret;
}
else {
my @fhemModules;
foreach ( sort { "\L$a" cmp "\L$b" } keys %modules ) {
@ -253,12 +266,21 @@ sub Get($$@) {
push @fhemModules, $_;
}
my @fhemPackages;
foreach ( sort { "\L$a" cmp "\L$b" } keys %packages ) {
push @fhemPackages, $_;
}
my $list =
'search'
. ' showModuleInfo:FHEM,'
. join( ',', @fhemModules )
. ' zzGetMETA.json:FHEM,'
. join( ',', @fhemModules );
. ' showPackageInfo:'
. join( ',', @fhemPackages )
. ' zzGetModuleMETA.json:FHEM,'
. join( ',', @fhemModules )
. ' zzGetPackageMETA.json:'
. join( ',', @fhemPackages );
return "Unknown argument $cmd, choose one of $list";
}
@ -275,11 +297,11 @@ sub Event ($$) {
m/^(install|uninstall|update)(?: (.+))/i );
my $cmd = $1;
my $packages = $2;
my $pkgs = $2;
my $list;
foreach my $package ( split / /, $packages ) {
foreach my $package ( split / /, $pkgs ) {
next
unless (
$package =~ /^(?:@([\w-]+)\/)?([\w-]+)(?:@([\d\.=<>]+|latest))?$/ );
@ -917,8 +939,6 @@ sub CreateSearchList ($$$) {
)
);
my $webname =
AttrVal( $hash->{CL}{SNAME}, 'webname', 'fhem' );
my $FW_CSRF = (
defined( $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN} )
? '&fwcsrf=' . $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN}
@ -947,7 +967,7 @@ sub CreateSearchList ($$$) {
. $txtClose
. $colClose;
push @ret,
$colOpen . $txtOpen . 'Module Name' . $txtClose . $colClose;
$colOpen . $txtOpen . 'Device Type' . $txtClose . $colClose;
}
$found++;
$foundDevices++;
@ -958,9 +978,7 @@ sub CreateSearchList ($$$) {
my $linkDev = $device;
$linkDev =
'<a href="/'
. $webname
. '?detail='
'<a href="?detail='
. $device
. $FW_CSRF . '">'
. $device . '</a>'
@ -968,9 +986,7 @@ sub CreateSearchList ($$$) {
my $linkMod = $defs{$device}{TYPE};
$linkMod =
'<a href="/'
. $webname
. '?cmd=get '
'<a href="?cmd=get '
. $hash->{NAME}
. ' showModuleInfo '
. $defs{$device}{TYPE}
@ -1020,9 +1036,7 @@ sub CreateSearchList ($$$) {
my $link = $module;
$link =
'<a href="/'
. $webname
. '?cmd=get '
'<a href="?cmd=get '
. $hash->{NAME}
. ' showModuleInfo '
. $module
@ -1042,6 +1056,57 @@ sub CreateSearchList ($$$) {
}
push @ret, $tableClose if ($foundModules);
# search for matching module
my $foundPackages = 0;
$linecount = 1;
foreach my $package ( sort { "\L$a" cmp "\L$b" } keys %packages ) {
if ( $package =~ m/^.*$search.*$/i ) {
unless ($foundPackages) {
push @ret, '<h3>Packages</h3>' . $lb;
push @ret, $tableOpen;
push @ret,
$colOpenMinWidth
. $txtOpen
. 'Package Name'
. $txtClose
. $colClose;
push @ret,
$colOpen . $txtOpen . 'Abstract' . $txtClose . $colClose;
}
$found++;
$foundPackages++;
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
FHEM::Meta::Load($package);
my $abstract = '';
$abstract = $packages{$package}{META}{abstract}
if ( defined( $packages{$package}{META} )
&& defined( $packages{$package}{META}{abstract} ) );
my $link = $package;
$link =
'<a href="?cmd=get '
. $hash->{NAME}
. ' showPackageInfo '
. $package
. $FW_CSRF . '">'
. $package . '</a>'
if ($html);
$l .= $colOpenMinWidth . $link . $colClose;
$l .=
$colOpen . ( $abstract eq 'n/a' ? '' : $abstract ) . $colClose;
$l .= $rowClose;
push @ret, $l;
$linecount++;
}
}
push @ret, $tableClose if ($foundPackages);
# search for matching keyword
my $foundKeywords = 0;
$linecount = 1;
@ -1053,7 +1118,11 @@ sub CreateSearchList ($$$) {
$found++;
$foundKeywords++;
push @ret, '<h4># ' . $keyword . '</h4>';
my $descr = FHEM::Meta::GetKeywordDesc( $keyword, $lang );
push @ret,
'<h4'
. ( $descr ne '' ? ' title="' . $descr . '"' : '' ) . '># '
. $keyword . '</h4>';
my @mAttrs = qw(
modules
@ -1093,11 +1162,13 @@ sub CreateSearchList ($$$) {
my $link = $item;
$link =
'<a href="/'
. $webname
. '?cmd=get '
'<a href="?cmd=get '
. $hash->{NAME}
. ' showModuleInfo '
. (
$type eq 'Module'
? ' showModuleInfo '
: ' showPackageInfo '
)
. $item
. $FW_CSRF . '">'
. $item . '</a>'
@ -1123,106 +1194,163 @@ sub CreateSearchList ($$$) {
# search for matching maintainer
my $foundMaintainers = 0;
my %maintainerInfo;
$linecount = 1;
foreach my $maintainer (
sort { "\L$a" cmp "\L$b" }
keys %FHEM::Meta::maintainerModules
keys %FHEM::Meta::maintainers
)
{
if ( $maintainer =~ m/^.*$search.*$/i ) {
$maintainerInfo{$maintainer}{modules} =
$FHEM::Meta::maintainerModules{$maintainer};
}
}
foreach my $maintainer (
sort { "\L$a" cmp "\L$b" }
keys %FHEM::Meta::maintainerPackages
)
{
if ( $maintainer =~ m/^.*$search.*$/i ) {
$maintainerInfo{$maintainer}{packages} =
$FHEM::Meta::maintainerPackages{$maintainer};
}
}
foreach my $maintainer ( sort { "\L$a" cmp "\L$b" } keys %maintainerInfo ) {
next
unless ( defined( $maintainerInfo{$maintainer}{modules} )
|| defined( $maintainerInfo{$maintainer}{packages} ) );
unless ($foundMaintainers) {
push @ret, '<h3>Authors & Maintainers</h3>' . $lb;
push @ret, $tableOpen;
push @ret,
$colOpenMinWidth . $txtOpen . 'Author' . $txtClose . $colClose;
push @ret, $colOpen . $txtOpen . 'Modules' . $txtClose . $colClose;
push @ret, $colOpen . $txtOpen . 'Packages' . $txtClose . $colClose;
$colOpenMinWidth . $txtOpen . 'Name' . $txtClose . $colClose;
push @ret,
$colOpen . $txtOpen . 'Modules' . $txtClose . $colClose;
push @ret,
$colOpen . $txtOpen . 'Packages' . $txtClose . $colClose;
}
$found++;
$foundMaintainers++;
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
my $modules = '';
my $packages = '';
my $mods = '';
if ( defined( $FHEM::Meta::maintainers{$maintainer}{modules} ) ) {
my $counter = 0;
foreach my $module ( sort { "\L$a" cmp "\L$b" }
@{ $maintainerInfo{$maintainer}{modules} } )
foreach my $mod ( sort { "\L$a" cmp "\L$b" }
@{ $FHEM::Meta::maintainers{$maintainer}{modules} } )
{
$modules .= $lb if ($counter);
$counter++;
if ($html) {
$modules .=
'<a href="/'
. $webname
. '?cmd=get '
$mods .= '<br />' if ($counter);
$mods .=
'<a href="?cmd=get '
. $hash->{NAME}
. ' showModuleInfo '
. $module
. $mod
. $FW_CSRF . '">'
. $module . '</a>';
. $mod . '</a>';
}
else {
$modules .= $module;
$mods .= "\n" unless ($counter);
$mods .= $mod;
}
}
$counter = 0;
foreach my $package ( sort { "\L$a" cmp "\L$b" }
@{ $maintainerInfo{$maintainer}{packages} } )
{
$packages .= $lb if ($counter);
$counter++;
# if ($html) {
# $packages .=
# '<a href="/'
# . $webname
# . '?cmd=get '
# . $hash->{NAME}
# . ' showPackageInfo '
# . $package
# . $FW_CSRF . '">'
# . $package . '</a>';
# }
# else {
$packages .= $package;
# }
}
}
my $pkgs = '';
if ( defined( $FHEM::Meta::maintainers{$maintainer}{packages} ) ) {
my $counter = 0;
foreach my $pkg ( sort { "\L$a" cmp "\L$b" }
@{ $FHEM::Meta::maintainers{$maintainer}{packages} } )
{
if ($html) {
$pkgs .= '<br />' if ($counter);
$pkgs .=
'<a href="?cmd=get '
. $hash->{NAME}
. ' showPackageInfo '
. $pkg
. $FW_CSRF . '">'
. $pkg . '</a>';
}
else {
$pkgs .= "\n" unless ($counter);
$pkgs .= $pkg;
}
$counter++;
}
}
$l .= $colOpenMinWidth . $maintainer . $colClose;
$l .= $colOpen . $modules . $colClose;
$l .= $colOpen . $packages . $colClose;
$l .= $colOpen . $mods . $colClose;
$l .= $colOpen . $pkgs . $colClose;
$l .= $rowClose;
push @ret, $l;
$linecount++;
}
}
push @ret, $tableClose if ($foundMaintainers);
# search for matching Perl package
my $foundPerl = 0;
$linecount = 1;
foreach my $dependent (
sort { "\L$a" cmp "\L$b" }
keys %{ $FHEM::Meta::dependents{pkgs} }
)
{
next if ( FHEM::Meta::ModuleIsPerlCore($dependent) );
next if ( FHEM::Meta::ModuleIsPerlPragma($dependent) );
next if ( FHEM::Meta::ModuleIsInternal($dependent) );
if ( $dependent =~ m/^.*$search.*$/i ) {
unless ($foundPerl) {
push @ret, '<h3>Perl packages</h3>' . $lb;
push @ret, $tableOpen;
push @ret,
$colOpenMinWidth . $txtOpen . 'Name' . $txtClose . $colClose;
push @ret,
$colOpen
. $txtOpen
. 'Referenced from'
. $txtClose
. $colClose;
}
$found++;
$foundPerl++;
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
my $references = '';
my $counter = 0;
foreach my $pkgReq (qw(requires recommends suggests)) {
next
unless (
defined(
$FHEM::Meta::dependents{pkgs}{$dependent}{$pkgReq}
)
);
foreach my $mod ( sort { "\L$a" cmp "\L$b" }
@{ $FHEM::Meta::dependents{pkgs}{$dependent}{$pkgReq} } )
{
if ($html) {
$references .= '<br />' if ($counter);
$references .=
'<a href="?cmd=get '
. $hash->{NAME}
. (
FHEM::Meta::ModuleIsInternal($mod) eq 'module'
? ' showModuleInfo '
: ' showPackageInfo '
)
. $mod
. $FW_CSRF . '">'
. $mod . '</a>';
}
else {
$references .= "\n" unless ($counter);
$references .= $mod;
}
$counter++;
}
}
$l .= $colOpenMinWidth . $dependent . $colClose;
$l .= $colOpen . $references . $colClose;
$l .= $rowClose;
push @ret, $l;
$linecount++;
}
}
push @ret, $tableClose if ($foundPerl);
return $header . join( "\n", @ret ) . $footer;
}
@ -1235,20 +1363,40 @@ sub CreateSearchList ($$$) {
sub CreateMetadataList ($$$) {
my ( $hash, $getCmd, $modName ) = @_;
$modName = 'Global' if ( uc($modName) eq 'FHEM' );
my $modType = lc($getCmd) eq 'showmoduleinfo' ? 'module' : 'package';
# disable automatic links to FHEM devices
delete $FW_webArgs{addLinks};
return 'Unknown module ' . $modName
unless ( defined( $modules{$modName} ) );
if ( $modType eq 'module' && !defined( $modules{$modName} ) );
FHEM::Meta::Load($modName);
return 'No metadata found about module ' . $modName
unless ( defined( $modules{$modName}{META} )
&& scalar keys %{ $modules{$modName}{META} } > 0 );
return 'Unknown package ' . $modName
if ( $modType eq 'package'
&& !defined( $packages{$modName} ) );
my $modMeta = $modules{$modName}{META};
return 'No metadata found about module '
. $modName
if (
$modType eq 'module'
&& ( !defined( $modules{$modName}{META} )
|| scalar keys %{ $modules{$modName}{META} } == 0 )
);
return 'No metadata found about package '
. $modName
if (
$modType eq 'package'
&& ( !defined( $packages{$modName}{META} )
|| scalar keys %{ $packages{$modName}{META} } == 0 )
);
my $modMeta =
$modType eq 'module'
? $modules{$modName}{META}
: $packages{$modName}{META};
my @ret;
my $html = defined( $hash->{CL} ) && $hash->{CL}{TYPE} eq "FHEMWEB" ? 1 : 0;
@ -1320,6 +1468,11 @@ sub CreateMetadataList ($$$) {
AttrVal( 'global', 'language', 'EN' )
)
);
my $FW_CSRF = (
defined( $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN} )
? '&fwcsrf=' . $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN}
: ''
);
push @ret, $tableOpen;
@ -1401,6 +1554,9 @@ sub CreateMetadataList ($$$) {
next
if ( $mAttr eq 'release_date'
&& ( !defined( $modMeta->{x_vcs} ) ) );
next
if ( $mAttr eq 'command_reference'
&& $modType eq 'package' );
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
my $mAttrName = $mAttr;
@ -1409,11 +1565,6 @@ sub CreateMetadataList ($$$) {
my $webname =
AttrVal( $hash->{CL}{SNAME}, 'webname', 'fhem' );
my $FW_CSRF = (
defined( $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN} )
? '&fwcsrf=' . $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN}
: ''
);
$l .= $colOpenMinWidth . $txtOpen . $mAttrName . $txtClose . $colClose;
@ -1850,7 +2001,9 @@ sub CreateMetadataList ($$$) {
# Add filename to module name
$mAttrVal .= ' (' . $modMeta->{x_file}[2] . ')'
if ( $mAttr eq 'name' && $modName ne 'Global' );
if ( $modType eq 'module'
&& $mAttr eq 'name'
&& $modName ne 'Global' );
$l .= $mAttrVal . $colClose;
}
@ -1895,9 +2048,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
if ( $alias eq $authorName ) {
$authorNameEmail =
'<a href="/'
. $webname
. '?cmd=get '
'<a href="?cmd=get '
. $hash->{NAME}
. ' search '
. $alias
@ -1910,9 +2061,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
if ($html) {
$authorNameEmail =
$authorName
. ', alias <a href="/'
. $webname
. '?cmd=get '
. ', alias <a href="?cmd=get '
. $hash->{NAME}
. ' search '
. $alias
@ -1945,16 +2094,21 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
my $counter = 0;
foreach my $keyword ( @{ $modMeta->{$mAttr} } ) {
$l .= ', ' if ($counter);
my $descr = FHEM::Meta::GetKeywordDesc( $keyword, $lang );
if ($html) {
$l .=
'<a href="/'
. $webname
. '?cmd=get '
'<a href="?cmd=get '
. $hash->{NAME}
. ' search '
. $keyword
. $FW_CSRF . '">'
. $FW_CSRF . '"'
. (
$descr ne ''
? ' title="' . $descr . '"'
: ''
)
. '>'
. $keyword . '</a>';
}
else {
@ -1984,8 +2138,100 @@ 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
suggests
);
$linecount = 1;
foreach my $mAttr (@mAttrs) {
next
unless ( defined( $FHEM::Meta::dependents{pkgs}{$modName}{$mAttr} )
&& ref( $FHEM::Meta::dependents{pkgs}{$modName}{$mAttr} ) eq
'ARRAY'
&& @{ $FHEM::Meta::dependents{pkgs}{$modName}{$mAttr} } > 0 );
my $dependents = '';
my $counter = 0;
foreach my $dependant ( sort { "\L$a" cmp "\L$b" }
@{ $FHEM::Meta::dependents{pkgs}{$modName}{$mAttr} } )
{
my $link = $dependant;
$link =
'<a href="?cmd=get '
. $hash->{NAME}
. (
FHEM::Meta::ModuleIsInternal($dependant) eq 'module'
? ' showModuleInfo '
: ' showPackageInfo '
)
. $dependant
. $FW_CSRF . '">'
. $dependant . '</a>'
if ($html);
$dependents .= ', ' if ($counter);
$dependents .= $link;
$counter++;
}
if ( $dependents ne '' ) {
if ( $linecount == 1 ) {
push @ret, '<h4>FHEM internal dependencies</h4>';
push @ret,
$txtOpen . 'Hint:'
. $txtClose
. $lb
. 'Dependents can only be shown here if they were loaded into the metadata cache before.'
. $lb
. $lb;
push @ret, $tableOpen;
push @ret,
$colOpenMinWidth
. $txtOpen
. 'Importance'
. $txtClose
. $colClose;
push @ret,
$colOpenMinWidth
. $txtOpen
. 'Dependent Modules'
. $txtClose
. $colClose;
}
my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd;
my $importance = $mAttr;
$importance = 'required' if ( $mAttr eq 'requires' );
$importance = 'recommended' if ( $mAttr eq 'recommends' );
$importance = 'suggested' if ( $mAttr eq 'suggests' );
$l .= $colOpenMinWidth . $importance . $colClose;
$l .= $colOpenMinWidth . $dependents . $colClose;
$l .= $rowClose;
push @ret, $l;
$linecount++;
}
}
push @ret, $tableClose . $lb if ( $linecount > 1 );
# }
push @ret, '<h3>System Prerequisites</h3>';
if ( $modType eq 'module' ) {
my $moduleUsage =
defined( $modules{$modName}{LOADED} )
? $colorGreen . 'IN USE' . $colorClose
@ -1993,6 +2239,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
push @ret, $lb . 'This FHEM module is currently ' . $moduleUsage . '.'
unless ( $modName eq 'Global' );
}
push @ret, '<h4>Perl Packages</h4>';
if ( defined( $modMeta->{prereqs} )
@ -2012,7 +2259,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
if ( defined( $modMeta->{x_prereqs_src} )
&& $modMeta->{x_prereqs_src} ne 'META.json' );
my @mAttrs = qw(
@mAttrs = qw(
requires
recommends
suggests
@ -2028,7 +2275,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
push @ret,
$colOpenMinWidth . $txtOpen . 'Status' . $txtClose . $colClose;
my $linecount = 1;
$linecount = 1;
foreach my $mAttr (@mAttrs) {
next
unless ( defined( $modMeta->{prereqs}{runtime}{$mAttr} )
@ -2111,6 +2358,20 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
&& !$isPerlPragma
&& $prereq ne 'perl' );
$prereq =
'<a href="?cmd=get '
. $hash->{NAME}
. (
$isFhem eq 'module'
? ' showModuleInfo '
: ' showPackageInfo '
)
. $prereq
. $FW_CSRF . '">'
. $prereq . '</a>'
if ( $html
&& $isFhem );
$l .=
$colOpenMinWidth
. $prereq
@ -2161,7 +2422,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
push @ret,
$colOpenMinWidth . $txtOpen . 'Status' . $txtClose . $colClose;
my $linecount = 1;
$linecount = 1;
foreach my $mAttr (@mAttrs) {
next
unless ( defined( $modMeta->{x_prereqs_nodejs}{runtime}{$mAttr} )
@ -2263,7 +2524,7 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
push @ret,
$colOpenMinWidth . $txtOpen . 'Status' . $txtClose . $colClose;
my $linecount = 1;
$linecount = 1;
foreach my $mAttr (@mAttrs) {
next
unless ( defined( $modMeta->{x_prereqs_python}{runtime}{$mAttr} )
@ -2376,21 +2637,33 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/
sub CreateRawMetaJson ($$$) {
my ( $hash, $getCmd, $modName ) = @_;
$modName = 'Global' if ( uc($modName) eq 'FHEM' );
return '{}'
unless ( defined( $modules{$modName} ) );
my $modType = lc($getCmd) eq 'zzgetmodulemeta.json' ? 'module' : 'package';
FHEM::Meta::Load($modName);
return '{}'
unless ( defined( $modules{$modName}{META} )
&& scalar keys %{ $modules{$modName}{META} } > 0 );
unless (
(
$modType eq 'module'
&& defined( $modules{$modName}{META} )
&& scalar keys %{ $modules{$modName}{META} } > 0
)
|| ( $modType eq 'package'
&& defined( $packages{$modName}{META} )
&& scalar keys %{ $packages{$modName}{META} } > 0 )
);
my $j = JSON->new;
$j->allow_nonref;
$j->canonical;
$j->pretty;
if ( $modType eq 'module' ) {
return $j->encode( $modules{$modName}{META} );
}
else {
return $j->encode( $packages{$modName}{META} );
}
}
# Checks whether a perl package is installed in the system
@ -2404,6 +2677,23 @@ sub __IsInstalledPerl($) {
return FHEM::Meta->VERSION()
if ( $pkg eq 'FHEM::Meta' || $pkg eq 'Meta' );
my $fname = $pkg;
$fname =~ s/^.*://g; # strip away any parent module names
# This is an internal Perl package
if ( defined( $packages{$fname} ) ) {
return $packages{$fname}{META}{version}
if ( defined( $packages{$fname}{META} ) );
return 1;
}
# This is an internal Perl package
if ( defined( $modules{$fname} ) ) {
return $modules{$fname}{META}{version}
if ( defined( $modules{$fname}{META} ) );
return 1;
}
eval "require $pkg;";
return 0
@ -2525,7 +2815,7 @@ sub __aUniq {
"abstract": "Modul zum Update von FHEM, zur Installation von Drittanbieter FHEM Modulen und der Verwaltung von Systemvoraussetzungen"
}
},
"version": "v0.1.0",
"version": "v0.2.0",
"release_status": "testing",
"author": [
"Julian Pawlowski <julian.pawlowski@gmail.com>"

View File

@ -85,8 +85,7 @@ our %supportForumCategories = (
boardId => 18,
},
'Automatisierung' => {
description =>
'Themen um Aufgaben mit FHEM zu automatisieren (at,notify,structure,watchdog,etc.)',
description => 'Aufgaben mit FHEM automatisieren',
boardId => 20,
'DOIF' => {
@ -103,8 +102,7 @@ our %supportForumCategories = (
boardId => 52,
},
'Frontends' => {
description =>
'Themen zu FHEM Frontends wie z.B. FHEMWEB, FLOORPLAN, etc.',
description => 'FHEM Frontends',
boardId => 19,
'FHEMWEB' => {
@ -137,50 +135,50 @@ our %supportForumCategories = (
boardId => 37,
},
'Sonstiges' => {
description => 'Sonstige Themen mit Bezug zu FHEM',
description => 'Sonstiger Bezug zu FHEM',
boardId => 46,
},
},
'FHEM - Hausautomations-Systeme' => {
'1Wire' => {
description => 'Themen zu 1Wire',
description => '1Wire',
boardId => 26,
},
'EnOcean' => {
description => 'Themen zu EnOcean',
description => 'EnOcean',
boardId => 27,
},
'Home Connect' => {
description =>
'Themen zu Geräten, API und Modulentwicklung rund um Home Connect in FHEM',
'Geräte, API und Modulentwicklung rund um Home Connect',
boardId => 97,
},
'Homematic' => {
description => 'Themen zu HomeMatic und Zubehör',
description => 'HomeMatic und Zubehör',
boardId => 22,
},
'InterTechno' => {
description => 'Themen zu InterTechno',
description => 'InterTechno',
boardId => 24,
},
'KNX/EIB' => {
description => 'Themen zu KNX/EIB',
description => 'KNX/EIB',
boardId => 51,
},
'MAX' => {
description => 'Themen zu MAX',
description => 'MAX',
boardId => 23,
},
'MQTT' => {
description => 'Themen zu MQTT',
description => 'MQTT',
boardId => 94,
},
'RFXTRX' => {
description => 'Themen zu RFXTRX',
description => 'RFXTRX',
boardId => 25,
},
'SlowRF' => {
description => 'Themen zu FS20, FHT, EM, WS, HMS',
description => 'FS20, FHT, EM, WS, HMS',
boardId => 21,
},
'Zigbee' => {
@ -188,7 +186,7 @@ our %supportForumCategories = (
boardId => 99,
},
'ZWave' => {
description => 'Themen zu ZWave',
description => 'ZWave',
boardId => 28,
},
'Sonstige Systeme' => {
@ -196,8 +194,7 @@ our %supportForumCategories = (
boardId => 29,
},
'Unterstützende Dienste' => {
description =>
'Themen zu unterstützenden Diensten und Modulen wie z.B. Calendar, HCS, Twilight, Weather, etc.',
description => 'unterstützende Dienste und Module',
boardId => 44,
'Kalendermodule' => {
@ -210,28 +207,28 @@ our %supportForumCategories = (
},
'FHEM - Hardware' => {
'FRITZ!Box' => {
description => 'FHEM auf AVM FRITZ!Box',
description => 'AVM FRITZ!Box',
boardId => 31,
},
'Network Attached Storage (NAS)' => {
description => 'FHEM auf NAS-Systemen (Synology, etc.)',
description => 'NAS-Systeme (Synology, etc.)',
boardId => 30,
},
'Einplatinencomputer' => {
description =>
'FHEM auf Einplatinencomputern (z.B. Raspberry Pi, Beagle Bone, etc.)',
'Einplatinencomputer (z.B. Raspberry Pi, Beagle Bone, etc.)',
boardId => 32,
},
'Server - Linux' => {
description => 'FHEM auf Linux Servern',
description => 'Linux Server',
boardId => 33,
},
'Server - Mac' => {
description => 'FHEM auf macOS',
description => 'Apple macOS',
boardId => 63,
},
'Server - Windows' => {
description => 'FHEM auf Windows Server',
description => 'Microsoft Windows Server',
boardId => 34,
},
},
@ -246,13 +243,11 @@ our %supportForumCategories = (
boardId => 60,
},
'Multimedia' => {
description =>
'Themen zu Multimediageräten, TV, Fernbedienungen, etc.',
description => 'Multimediageräte, TV, Fernbedienungen, etc.',
boardId => 53,
},
'Solaranlagen' => {
description =>
'Themen rund um Solaranlagen zur Wärme- oder Stromgewinnung',
description => 'Solaranlagen zur Wärme- oder Stromgewinnung',
boardId => 61,
},
},
@ -276,8 +271,7 @@ our %supportForumCategories = (
boardId => 6,
},
'Hard- und Firmware' => {
description =>
'Themen in Bezug auf die CUL Hard- und Firmware. Dazu zählen alle Geräte der CUL und CUN Familie.',
description => 'CUL/CUN Hard- und Firmware',
boardId => 47,
},
},
@ -299,7 +293,7 @@ our %supportForumCategories = (
'Verschiedenes' => {
'Bastelecke' => {
description =>
'Projekte für Bastler, die gerne auch mal zum Lötkolben greifen.',
'Projekte für Bastler, die gerne auch mal zum Lötkolben greifen',
boardId => 17,
'ESP8266' => {
@ -324,11 +318,9 @@ our %supportForumCategories = (
boardId => 67,
},
'Marktplatz - Kommerzielle Güter' => {
description => '',
boardId => 101,
},
'Marktplatz - Kommerzielle Dienstleistungen' => {
description => '',
boardId => 100,
},
'Off-Topic' => {
@ -347,13 +339,10 @@ our %supportForumCategories = (
}
);
our %moduleMaintainers;
our %packageMaintainers;
our %fileMaintainers;
our %maintainerModules;
our %maintainerPackages;
our %maintainerFile;
our %maintainers; # maintainers and what they maintain
our %moduleMaintainers; # modules and who maintains them
our %packageMaintainers; # packages and who maintains them
our %fileMaintainers; # files and who maintains them
our $coreUpdate;
our %corePackageUpdates;
@ -364,6 +353,79 @@ our %packageUpdates;
our %fileUpdates;
our %keywords;
our %keywordDescription = (
'fhem-core' => {
'en' => 'Belongs to the official FHEM core software',
'de' => 'Gehört zum offiziellen Kern von FHEM',
},
'fhem-3rdparty' => {
'en' =>
'Originates from a source outside of the official FHEM core software',
'de' =>
'Stammt aus einer Quelle außerhalb des offiziellen Kern von FHEM',
},
'fhem-commercial' => {
'en' => 'commercial relation',
'de' => 'kommerzieller Zusammenhang',
},
'fhem-mod' => {
'en' => 'FHEM module',
'de' => 'FHEM Modul',
},
'fhem-pkg' => {
'en' => 'FHEM development package that is used by FHEM modules',
'de' => 'FHEM Entwickler Paket, welches in FHEM Modulen verwendet wird',
},
'fhem-mod-3rdparty' => {
'en' =>
'FHEM module that originates from a source outside of the official FHEM core software',
'de' =>
'FHEM Modul, welches aus einer Quelle außerhalb des offiziellen Kern von FHEM stammt',
},
'fhem-pkg-3rdparty' => {
'en' =>
'FHEM development package that originates from a source outside of the official FHEM core software',
'de' =>
'FHEM Entwickler Paket, welches aus einer Quelle außerhalb des offiziellen Kern von FHEM stammt',
},
'fhem-mod-commercial' => {
'en' =>
'commercial FHEM module that originates from a source outside of the official FHEM core software',
'de' =>
'kommerzielles FHEM Modul, welches aus einer Quelle außerhalb des offiziellen Kern von FHEM stammt',
},
'fhem-pkg-commercial' => {
'en' =>
'commercial FHEM development package that originates from a source outside of the official FHEM core software',
'de' =>
'kommerzielles FHEM Entwickler Paket, welches aus einer Quelle außerhalb des offiziellen Kern von FHEM stammt',
},
'fhem-mod-local' => {
'en' => 'FHEM module that is maintained locally on the machine',
'de' => 'FHEM Modul, welches lokal auf der Maschine verwaltet wird',
},
'fhem-pkg-local' => {
'en' =>
'FHEM development package that is maintained locally on the machine',
'de' =>
'FHEM Entwickler Paket, welches lokal auf der Maschine verwaltet wird',
},
'fhem-mod-command' => {
'en' => 'FHEM console text command w/o any FHEM device object visible',
'de' =>
'FHEM Konsolen Text Kommando ohne sichtbares FHEM Geräte-Objekt',
},
'fhem-mod-device' => {
'en' => 'represents a physical device',
'de' => 'repräsentiert ein physisches Gerät',
},
'fhem-mod-helper' => {
'en' => 'logical, non-physical device',
'de' => 'logisches, nicht physisches Gerät',
},
);
our %dependents;
# Package internal variables
#
@ -538,6 +600,7 @@ my @perlCoreModules = qw(
subs
utf8
vars
version
vmsish
warnings
warnings::register
@ -700,12 +763,20 @@ sub Load(;$$) {
}
foreach my $modName (@lmodules) {
$modName = 'Global' if ( uc($modName) eq 'FHEM' );
my $type;
my $type = (
exists( $modules{$modName} )
? 'module'
: ( exists( $packages{$modName} ) ? 'package' : undef )
);
if ( exists( $modules{$modName} ) && !exists( $packages{$modName} ) ) {
$type = 'module';
}
elsif ( exists( $packages{$modName} ) && !exists( $modules{$modName} ) )
{
$type = 'package';
}
elsif ( exists( $packages{$modName} ) && exists( $modules{$modName} ) )
{
$type = 'module+package';
}
next unless ($type);
# Abort when module file was not indexed by
@ -727,19 +798,27 @@ sub Load(;$$) {
&& !$reload
&& defined( $packages{$modName}{META} )
&& ref( $packages{$modName}{META} ) eq "HASH" );
next
if ( $type eq 'module+package'
&& !$reload
&& defined( $modules{$modName}{META} )
&& ref( $modules{$modName}{META} ) eq "HASH"
&& defined( $packages{$modName}{META} )
&& ref( $packages{$modName}{META} ) eq "HASH" );
if ( $type eq 'module'
if ( ( $type eq 'module' || $type eq 'module+package' )
&& defined( $modules{$modName}{META} ) )
{
delete $modules{$modName}{META};
}
elsif ( $type eq 'package'
if ( ( $type eq 'package' || $type eq 'module+package' )
&& defined( $packages{$modName}{META} ) )
{
delete $packages{$modName}{META};
}
foreach my $type ( split( '\+', $type ) ) {
my $filePath;
if ( $modName eq 'Global' ) {
$filePath = $attr{global}{modpath} . "/fhem.pl";
@ -755,10 +834,13 @@ sub Load(;$$) {
. $modName . '.pm';
}
my $ret =
InitMod( $filePath,
( $type eq 'module' ? $modules{$modName} : $packages{$modName} ),
1 );
my $ret = InitMod(
$filePath,
(
$type eq 'module' ? $modules{$modName} : $packages{$modName}
),
1
);
push @rets, $@ if ( $@ && $@ ne '' );
push @rets, $ret if ( $ret && $ret ne '' );
@ -781,6 +863,7 @@ sub Load(;$$) {
&& defined( $packages{$modName}{META} ) );
}
}
}
if (@rets) {
$@ = join( "\n", @rets );
@ -853,6 +936,22 @@ sub GetModuleSourceOrigin {
return '';
}
sub GetKeywordDesc {
my ( $keyword, $lang ) = @_;
$lang = 'en' unless ($lang);
return '' unless ( defined( $keywordDescription{$keyword} ) );
# turn fallback language around
$lang = 'de'
if ( !defined( $keywordDescription{$keyword}{$lang} )
&& $lang eq 'en' );
return $keywordDescription{$keyword}{$lang}
if ( defined( $keywordDescription{$keyword}{$lang} ) );
return '';
}
sub ModuleIsCore {
my ($module) = @_;
return GetModuleSourceOrigin($module) eq 'fhem' ? 1 : 0;
@ -860,19 +959,32 @@ sub ModuleIsCore {
sub ModuleIsInternal {
my ($module) = @_;
return 1
return 0 if ( ModuleIsPerlCore($module) || ModuleIsPerlPragma($module) );
return 'module'
if ( $module eq 'fhem.pl'
|| $module eq 'FHEM'
|| $module eq 'Global'
|| $module eq 'FHEM::Meta'
|| $module eq 'Meta' );
|| $module eq 'Global' );
my $fname = $module;
$fname =~ s/^.*://g; # strip away any parent module names
return 'package'
if ( $fname eq 'Meta' );
return 'module'
if ( defined( $modules{$fname} ) && !defined( $packages{$fname} ) );
return 'package'
if ( defined( $packages{$fname} ) && !defined( $modules{$fname} ) );
return 'module+package'
if ( defined( $modules{$fname} ) && defined( $packages{$fname} ) );
my $p = GetModuleFilepath($module);
# if module has a relative path,
# assume it is part of FHEM
return $p && ( $p =~ m/^(\.\/)?FHEM\/.+/ || $p =~ m/^(\.\/)?[^\/]+\.pm$/ )
? 1
? 'file'
: 0;
}
@ -981,10 +1093,11 @@ sub __GetMetadata {
my $versionFrom;
my $authorName; # not in use, see below
my $authorMail; # not in use, see below
my $item_modtype;
my $item_modsubtype;
my $item_summary;
my $item_summary_DE;
my $modName;
my $modType;
# Static meta information
$modMeta->{dynamic_config} = 1;
@ -1014,6 +1127,7 @@ sub __GetMetadata {
$modMeta->{x_file} = \@file;
$modName = $file[4];
$modType = $file[3] || $file[2] eq 'fhem.pl' ? 'mod' : 'pkg';
}
# grep info from file content
@ -1131,12 +1245,12 @@ m/(->\{VERSION\}\s+=\s+[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?:\.\d{1,3})?)))/i
# read items from POD
elsif ($skip
&& !$item_modtype
&& !$item_modsubtype
&& $l =~ m/^=item\s+(device|helper|command)\s*$/i )
{
return "=item (device|helper|command) pod must occur only once"
if ($item_modtype);
$item_modtype = lc($1);
if ($item_modsubtype);
$item_modsubtype = lc($1);
}
elsif ($skip
&& !$item_summary_DE
@ -1391,7 +1505,7 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
# used by this FHEM module.
# We're not going deeper down for Meta.pm itself,
# that means Meta.pm manual prereqs need to cover this.
if ( $modMeta->{x_file}[4] ne 'Meta'
if ( $modName ne 'Meta'
&& defined( $modMeta->{prereqs} )
&& defined( $modMeta->{prereqs}{runtime} ) )
{
@ -1403,6 +1517,24 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
my $pkg ( keys %{ $modMeta->{prereqs}{runtime}{$pkgReq} } )
{
# Add to dependency index:
# packages to FHEM modules/packages
push @{ $dependents{pkgs}{$pkg}{$pkgReq} }, $modName
unless (
grep ( /^$modName$/,
@{ $dependents{pkgs}{$pkg}{$pkgReq} } ) );
# dependents list
push @{ $dependents{$pkgReq}{$pkg} },
$modName
unless (
ModuleIsInternal($pkg)
|| ( defined( $dependents{$pkgReq} )
&& defined( $dependents{$pkgReq}{$pkg} )
&& grep ( /^$modName$/,
@{ $dependents{$pkgReq}{$pkg} } ) )
);
# Found prereq that is a FHEM package
if ( exists( $packages{$pkg} ) ) {
Load($pkg);
@ -1493,9 +1625,10 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
$modMeta->{x_vcs} = \@vcs;
# if there is no maintainer, we will assign someone acting
if ( !defined( $moduleMaintainers{ $modMeta->{x_file}[4] } )
&& !defined( $packageMaintainers{ $modMeta->{x_file}[4] } )
&& $modMeta->{x_file}[4] ne 'Meta' )
if ( !defined( $moduleMaintainers{$modName} )
&& !defined( $packageMaintainers{$modName} )
&& GetModuleSourceOrigin($modName) ne ''
&& $modName ne 'Meta' )
{
Log 4,
__PACKAGE__
@ -1505,24 +1638,82 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
. "Added acting maintainer with limited support status";
# add acting maintainer
#TODO detect if module or package
$moduleMaintainers{ $modMeta->{x_file}[4] }[0][0] =
if ( $modType eq 'mod' ) {
$moduleMaintainers{$modName}[0][0] =
$modMeta->{x_file}[0];
$moduleMaintainers{ $modMeta->{x_file}[4] }[0][1] =
$moduleMaintainers{$modName}[0][1] =
$modMeta->{x_file}[1];
$moduleMaintainers{ $modMeta->{x_file}[4] }[0][2] =
$moduleMaintainers{$modName}[0][2] =
$modMeta->{x_file}[2];
$moduleMaintainers{ $modMeta->{x_file}[4] }[0][3] =
$moduleMaintainers{$modName}[0][3] =
$modMeta->{x_file}[3];
$moduleMaintainers{ $modMeta->{x_file}[4] }[0][4] =
$modMeta->{x_file}[4];
$moduleMaintainers{ $modMeta->{x_file}[4] }[0][5] =
$moduleMaintainers{$modName}[0][4] =
$modName;
$moduleMaintainers{$modName}[0][5] =
$modMeta->{x_file}[5];
$moduleMaintainers{ $modMeta->{x_file}[4] }[1] =
'rudolfkoenig (acting)';
$moduleMaintainers{ $modMeta->{x_file}[4] }[2] = 'limited';
$moduleMaintainers{ $modMeta->{x_file}[4] }[3] =
$moduleMaintainers{$modName}[1] = 'rudolfkoenig (acting)';
$moduleMaintainers{$modName}[2] = 'limited';
$moduleMaintainers{$modName}[3] =
__GetSupportForum('Sonstiges');
# add acting maintainer to maintainer hashes
my $lastEditor = 'rudolfkoenig (acting)';
push @{ $maintainers{$lastEditor}{modules} },
$modName
unless (
defined( $maintainers{$lastEditor} )
&& grep( m/^$lastEditor$/i,
@{ $maintainers{$lastEditor}{modules} } )
);
# add last committer to maintainer hashes
$lastEditor = $modMeta->{x_vcs}[15];
push @{ $maintainers{$lastEditor}{modules} },
$modName
unless (
defined( $maintainers{$lastEditor} )
&& grep( m/^$lastEditor$/i,
@{ $maintainers{$lastEditor}{modules} } )
);
}
else {
$packageMaintainers{$modName}[0][0] =
$modMeta->{x_file}[0];
$packageMaintainers{$modName}[0][1] =
$modMeta->{x_file}[1];
$packageMaintainers{$modName}[0][2] =
$modMeta->{x_file}[2];
$packageMaintainers{$modName}[0][3] =
$modMeta->{x_file}[3];
$packageMaintainers{$modName}[0][4] =
$modName;
$packageMaintainers{$modName}[0][5] =
$modMeta->{x_file}[5];
$packageMaintainers{$modName}[1] = 'rudolfkoenig (acting)';
$packageMaintainers{$modName}[2] = 'limited';
$packageMaintainers{$modName}[3] =
__GetSupportForum('Sonstiges');
# add acting maintainer to maintainer hashes
my $lastEditor = 'rudolfkoenig (acting)';
push @{ $maintainers{$lastEditor}{packages} },
$modName
unless (
defined( $maintainers{$lastEditor} )
&& grep( m/^$lastEditor$/i,
@{ $maintainers{$lastEditor}{packages} } )
);
# add last committer to maintainer hashes
$lastEditor = $modMeta->{x_vcs}[15];
push @{ $maintainers{$lastEditor}{packages} },
$modName
unless (
defined( $maintainers{$lastEditor} )
&& grep( m/^$lastEditor$/i,
@{ $maintainers{$lastEditor}{packages} } )
);
}
}
}
@ -1567,19 +1758,18 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
# meta name
unless ( defined( $modMeta->{name} ) ) {
if ( $modMeta->{x_file}[4] eq 'Global' ) {
if ( $modName eq 'Global' ) {
$modMeta->{name} = 'FHEM';
}
else {
$modMeta->{name} = $modMeta->{x_file}[1];
$modMeta->{name} =~ s/^\.\///;
$modMeta->{name} =~ s/\/$//;
$modMeta->{name} =~ s/FHEM\/lib//;
$modMeta->{name} =~ s/\//::/g;
}
if ( $modMeta->{x_file}[4] ne 'Global' ) {
if ( $modName ne 'Global' ) {
$modMeta->{name} .= '::' if ( $modMeta->{name} );
$modMeta->{name} .= $modMeta->{x_file}[4];
$modMeta->{name} .= $modName;
}
}
@ -1606,41 +1796,39 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
}
# Fill mandatory attributes
unless ( $modMeta->{abstract} ) {
$modMeta->{abstract} = 'n/a';
}
unless ( $modMeta->{description} ) {
$modMeta->{description} = 'n/a';
}
unless ( $modMeta->{release_status} ) {
$modMeta->{release_status} = 'stable';
}
unless ( $modMeta->{license} ) {
$modMeta->{license} = 'unknown';
}
unless ( $modMeta->{author} ) {
$modMeta->{author} = ['unknown <>'];
}
unless ( defined( $modMeta->{x_support_status} ) ) {
if ( defined( $moduleMaintainers{$modName} )
&& ref( $moduleMaintainers{$modName} ) eq 'ARRAY'
&& defined( $moduleMaintainers{$modName}[2] ) )
{
$modMeta->{x_support_status} =
$moduleMaintainers{$modName}[2];
}
elsif ( defined( $modMeta->{resources} )
&& $modMeta->{resources}{x_support_community} )
{
$modMeta->{x_support_status} = 'supported';
unless ( defined( $modMeta->{abstract} ) ) {
if ( $modType eq 'pkg' ) {
$modMeta->{abstract} =
'FHEM development package that is used by FHEM modules';
}
else {
$modMeta->{x_support_status} = 'unknown';
$modMeta->{abstract} = 'n/a';
}
}
unless ( defined( $modMeta->{description} ) ) {
if ( $modType eq 'pkg' ) {
$modMeta->{description} =
'This is a FHEM-included Perl package that does not show up as a '
. 'regular device in FHEM. \\n'
. 'That is because it provides additional functionality that can be used by real '
. 'FHEM modules in order to share the same code basis.';
}
else {
$modMeta->{description} = 'n/a';
}
}
unless ( defined( $modMeta->{release_status} ) ) {
$modMeta->{release_status} = 'stable';
}
unless ( defined( $modMeta->{license} ) ) {
$modMeta->{license} = 'unknown';
}
unless ( defined( $modMeta->{author} ) ) {
$modMeta->{author} = ['unknown <>'];
}
# Generate META information for FHEM core modules
if ( GetModuleSourceOrigin( $modMeta->{x_file}[4] ) eq 'fhem' ) {
if ( GetModuleSourceOrigin($modName) eq 'fhem' ) {
if ( !$modMeta->{release_status}
|| $modMeta->{release_status} eq 'stable' )
@ -1660,17 +1848,30 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
}
if ( !$modMeta->{author} || $modMeta->{author}[0] eq 'unknown <>' ) {
if ( defined( $moduleMaintainers{ $modMeta->{x_file}[4] } ) ) {
if ( defined( $moduleMaintainers{$modName} ) ) {
shift @{ $modMeta->{author} }
if ( $modMeta->{author}
&& $modMeta->{author}[0] eq 'unknown <>' );
foreach (
split(
'/|,', $moduleMaintainers{ $modMeta->{x_file}[4] }[1]
)
)
{
foreach ( split( '/|,', $moduleMaintainers{$modName}[1] ) ) {
push @{ $modMeta->{author} }, "$_ <>";
}
# last update was not by one of the named authors
if ( defined( $modMeta->{x_vcs} ) ) {
my $lastEditor = $modMeta->{x_vcs}[15] . ' <>';
push @{ $modMeta->{author} },
$modMeta->{x_vcs}[15] . ' (last release only) <>'
unless (
grep( m/^$lastEditor$/i, @{ $modMeta->{author} } ) );
}
}
elsif ( defined( $packageMaintainers{$modName} ) ) {
shift @{ $modMeta->{author} }
if ( $modMeta->{author}
&& $modMeta->{author}[0] eq 'unknown <>' );
foreach ( split( '/|,', $packageMaintainers{$modName}[1] ) ) {
push @{ $modMeta->{author} }, "$_ <>";
}
@ -1685,13 +1886,24 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
}
}
unless ( $modMeta->{x_fhem_maintainer} ) {
if ( defined( $moduleMaintainers{ $modMeta->{x_file}[4] } ) ) {
foreach (
split(
'/|,', $moduleMaintainers{ $modMeta->{x_file}[4] }[1]
)
)
{
if ( defined( $moduleMaintainers{$modName} ) ) {
foreach ( split( '/|,', $moduleMaintainers{$modName}[1] ) ) {
push @{ $modMeta->{x_fhem_maintainer} }, $_;
}
# last update was not by one of the named authors
if ( defined( $modMeta->{x_vcs} ) ) {
my $lastEditor = $modMeta->{x_vcs}[15];
push @{ $modMeta->{x_fhem_maintainer} },
$modMeta->{x_vcs}[15]
unless (
grep( m/^$lastEditor$/i,
@{ $modMeta->{x_fhem_maintainer} } )
);
}
}
elsif ( defined( $packageMaintainers{$modName} ) ) {
foreach ( split( '/|,', $packageMaintainers{$modName}[1] ) ) {
push @{ $modMeta->{x_fhem_maintainer} }, $_;
}
@ -1726,13 +1938,15 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
}
}
unless ( defined( $modMeta->{resources} )
unless (
$modType ne 'mod'
|| ( defined( $modMeta->{resources} )
&& defined( $modMeta->{resources}{x_commandref} ) )
)
{
if ( defined( $modMeta->{x_vcs} ) ) {
$modMeta->{resources}{x_commandref}{web} =
'https://fhem.de/commandref.html';
$modMeta->{resources}{x_commandref}{modpath} = '#';
'https://fhem.de/commandref.html#' . $modName;
}
}
@ -1801,25 +2015,51 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(?
delete $modMeta->{x_fhem_maintainer_github};
}
unless ( defined( $modMeta->{x_support_status} ) ) {
if ( defined( $moduleMaintainers{$modName} )
&& ref( $moduleMaintainers{$modName} ) eq 'ARRAY'
&& defined( $moduleMaintainers{$modName}[2] ) )
{
$modMeta->{x_support_status} =
$moduleMaintainers{$modName}[2];
}
elsif (defined( $packageMaintainers{$modName} )
&& ref( $packageMaintainers{$modName} ) eq 'ARRAY'
&& defined( $packageMaintainers{$modName}[2] ) )
{
$modMeta->{x_support_status} =
$packageMaintainers{$modName}[2];
}
elsif ( defined( $modMeta->{resources} )
&& $modMeta->{resources}{x_support_community} )
{
$modMeta->{x_support_status} = 'supported';
}
else {
$modMeta->{x_support_status} = 'unknown';
}
}
# Filter keywords that are reserved for FHEM core
if ( defined( $modMeta->{keywords} ) && @{ $modMeta->{keywords} } > 0 ) {
my @filtered;
foreach ( @{ $modMeta->{keywords} } ) {
push @filtered, lc($_)
unless ( lc($_) eq 'fhem-core'
|| lc($_) eq 'fhem-mod'
|| lc($_) eq 'fhem-pkg'
|| lc($_) eq 'fhem-3rdparty'
|| lc($_) eq 'fhem-mod-3rdparty'
|| lc($_) eq 'fhem-pkg-3rdparty'
|| lc($_) eq 'fhem-mod-local'
|| lc($_) eq 'fhem-pkg-local'
|| lc($_) eq 'fhem-commercial'
|| lc($_) eq 'fhem-mod-commercial'
|| lc($_) eq 'fhem-pkg-commercial' );
foreach my $keyword ( @{ $modMeta->{keywords} } ) {
push @filtered, lc($keyword)
unless ( lc($keyword) eq 'fhem-core'
|| lc($keyword) eq 'fhem-mod'
|| lc($keyword) eq 'fhem-pkg'
|| lc($keyword) eq 'fhem-3rdparty'
|| lc($keyword) eq 'fhem-mod-3rdparty'
|| lc($keyword) eq 'fhem-pkg-3rdparty'
|| lc($keyword) eq 'fhem-mod-local'
|| lc($keyword) eq 'fhem-pkg-local'
|| lc($keyword) eq 'fhem-commercial'
|| lc($keyword) eq 'fhem-mod-commercial'
|| lc($keyword) eq 'fhem-pkg-commercial' );
}
delete $modMeta->{keywords};
$modMeta->{keywords} = \@filtered;
}
@ -1843,35 +2083,37 @@ 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->{resources} )
&& defined( $modMeta->{resources}{x_support_commercial} ) )
{
my $modType = $modMeta->{x_file}[3] ? 'mod' : 'pkg';
push @{ $modMeta->{keywords} }, "fhem-$modType-commercial";
}
# add legacy POD info as Metadata
if ($item_modtype) {
$item_modtype = 'fhem-mod-' . $item_modtype;
push @{ $modMeta->{keywords} }, $item_modtype
if ($item_modsubtype) {
$item_modsubtype = "fhem-$modType-" . $item_modsubtype;
push @{ $modMeta->{keywords} }, $item_modsubtype
if ( !defined( $modMeta->{keywords} )
|| !grep ( /^$item_modtype$/i, @{ $modMeta->{keywords} } ) );
|| !grep ( /^$item_modsubtype$/i, @{ $modMeta->{keywords} } ) );
}
else {
push @{ $modMeta->{keywords} }, "fhem-$modType"
if ( !defined( $modMeta->{keywords} )
|| !grep ( /^fhem-$modType$/i, @{ $modMeta->{keywords} } ) );
}
# Add some keywords about the module origin
my $modType = $modMeta->{x_file}[3] ? 'mod' : 'pkg';
if ( GetModuleSourceOrigin( $modMeta->{x_file}[4] ) eq 'fhem' ) {
if ( GetModuleSourceOrigin($modName) eq 'fhem' ) {
push @{ $modMeta->{keywords} }, 'fhem-core';
}
elsif ( GetModuleSourceOrigin( $modMeta->{x_file}[4] ) ne '' ) {
elsif ( GetModuleSourceOrigin($modName) ne '' ) {
push @{ $modMeta->{keywords} }, "fhem-$modType-3rdparty";
}
else {
my $modType = $modMeta->{x_file}[3] ? 'mod' : 'pkg';
push @{ $modMeta->{keywords} }, "fhem-$modType-local";
}
# Add keywords to global index
if ( @{ $modMeta->{keywords} } > 0 ) {
foreach ( @{ $modMeta->{keywords} } ) {
if ( $modMeta->{x_file}[3] ) {
if ( $modType eq 'mod' ) {
push @{ $keywords{$_}{modules} }, $modName
if ( !defined( $keywords{$_}{modules} )
|| !grep ( /^$modName$/i, @{ $keywords{$_}{modules} } ) );
@ -1914,7 +2156,23 @@ sub __GenerateKeywordsFromSupportCommunity {
$tag =~ s/ +/-/g;
foreach ( split '/', $tag ) {
push @keywords, ( $_ =~ /^$prefix/ ? '' : $prefix ) . $_;
my $t = ( $_ =~ /^$prefix/ ? '' : $prefix ) . $_;
my $desc =
defined( $community->{subCommunity}{description} )
? $community->{subCommunity}{description}
: (
defined( $community->{description} )
? $community->{description}
: ''
);
push @keywords, $t;
$keywordDescription{$t}{de} = $desc
unless (
$desc eq ''
|| ( defined( $keywordDescription{$t} )
&& defined( $keywordDescription{$t}{de} ) )
);
}
}
@ -1923,7 +2181,23 @@ sub __GenerateKeywordsFromSupportCommunity {
$tag =~ s/ +/-/g;
foreach ( split '/', $tag ) {
push @keywords, ( $_ =~ /^$prefix/ ? '' : $prefix ) . $_;
my $t = ( $_ =~ /^$prefix/ ? '' : $prefix ) . $_;
my $desc =
defined( $community->{subCommunity} )
&& defined( $community->{subCommunity}{description} )
? $community->{subCommunity}{description}
: (
defined( $community->{description} ) ? $community->{description}
: ''
);
push @keywords, $t;
$keywordDescription{$t}{de} = $desc
unless (
$desc eq ''
|| ( defined( $keywordDescription{$t} )
&& defined( $keywordDescription{$t}{de} ) )
);
}
}
@ -1936,7 +2210,18 @@ sub __GenerateKeywordsFromSupportCommunity {
$tag =~ s/ +/-/g;
foreach ( split '/', $tag ) {
push @keywords, $_;
my $desc =
defined( $community->{description} )
? $community->{description}
: '';
push @keywords, $tag;
$keywordDescription{$tag}{de} = $desc
unless (
$desc eq ''
|| ( defined( $keywordDescription{$tag} )
&& defined( $keywordDescription{$tag}{de} ) )
);
}
}
@ -2065,7 +2350,8 @@ sub __GetMaintainerdata {
# Register in global maintainer index
foreach ( split '/|,', $maintainer[1] ) {
push @{ $maintainerModules{$_} }, $maintainer[0][4];
push @{ $maintainers{$_}{modules} },
$maintainer[0][4];
}
# Generate keywords for global index
@ -2152,7 +2438,7 @@ sub __GetMaintainerdata {
# Register in global maintainer index
foreach ( split '/|,', $maintainer[1] ) {
push @{ $maintainerPackages{$_} },
push @{ $maintainers{$_}{packages} },
$maintainer[0][4];
}
@ -2668,15 +2954,13 @@ sub __SetXVersion {
=for :application/json;q=META.json Meta.pm
{
"abstract": "FHEM component module to enable Metadata support",
"description": "n/a",
"abstract": "FHEM development package to enable Metadata support",
"x_lang": {
"de": {
"abstract": "FHEM Modul Komponente, um Metadaten Unterstützung zu aktivieren",
"description": "n/a"
"abstract": "FHEM Entwickler Paket, um Metadaten Unterstützung zu aktivieren"
}
},
"version": "v0.3.2",
"version": "v0.4.0",
"release_status": "testing",
"author": [
"Julian Pawlowski <julian.pawlowski@gmail.com>"