diff --git a/FHEM/98_Installer.pm b/FHEM/98_Installer.pm index 99af43599..ffbd8c462 100644 --- a/FHEM/98_Installer.pm +++ b/FHEM/98_Installer.pm @@ -230,7 +230,11 @@ sub Get($$@) { my ( $cmd, @args ) = @aa; - if ( lc($cmd) eq 'showmoduleinfo' ) { + if ( lc($cmd) eq 'search' ) { + my $ret = CreateSearchList( $hash, $cmd, $args[0] ); + return $ret; + } + elsif ( lc($cmd) eq 'showmoduleinfo' ) { return "usage: $cmd MODULE" if ( @args != 1 ); my $ret = CreateMetadataList( $hash, $cmd, $args[0] ); @@ -242,17 +246,38 @@ sub Get($$@) { my $ret = CreateRawMetaJson( $hash, $cmd, $args[0] ); return $ret; } - else { - my $fhemModules; + elsif ( lc($cmd) eq 'zzgetmaintainer.json' ) { + return "usage: $cmd MAINTAINER" if ( @args != 1 ); + my $ret = CreateRawMaintainerJson( $hash, $cmd, $args[0] ); + return $ret; + } + else { + my @fhemModules; foreach ( sort { "\L$a" cmp "\L$b" } keys %modules ) { next if ( $_ eq 'Global' ); - $fhemModules .= ',' if ($fhemModules); - $fhemModules .= $_; + push @fhemModules, $_; + } + + my @fhemMaintainers; + foreach ( keys %FHEM::Meta::maintainerModules ) { + push @fhemMaintainers, $_; + } + foreach ( keys %FHEM::Meta::maintainerPackages ) { + push @fhemMaintainers, $_; + } + foreach ( keys %FHEM::Meta::maintainerFile ) { + push @fhemMaintainers, $_; } my $list = - "zzGetMETA.json:FHEM,$fhemModules showModuleInfo:FHEM,$fhemModules"; + 'search' + . ' showModuleInfo:FHEM,' + . join( ',', @fhemModules ) + . ' zzGetMaintainer.json:' + . join( ',', sort { "\L$a" cmp "\L$b" } __aUniq(@fhemMaintainers) ) + . ' zzGetMETA.json:FHEM,' + . join( ',', @fhemModules ); return "Unknown argument $cmd, choose one of $list"; } @@ -342,7 +367,7 @@ sub ProcessUpdateTimer($) { or ReadingsVal( $name, 'state', 'none' ) eq 'initialized' ); if ( - ToDay() ne ( + __ToDay() ne ( split( ' ', ReadingsTimestamp( $name, 'outdated', '1970-01-01' ) ) @@ -793,7 +818,7 @@ sub WriteReadings($$) { : 'check failed' ) ); - $hash->{helper}{lastSync} = ToDay(); + $hash->{helper}{lastSync} = __ToDay(); } readingsBulkUpdateIfChanged( $hash, 'updatesAvailable', @@ -853,6 +878,269 @@ sub WriteReadings($$) { && !defined( $decode_json->{error} ) ); } +sub CreateSearchList ($$$) { + my ( $hash, $getCmd, $search ) = @_; + $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 $header = ''; + my $footer = ''; + if ($html) { + $header = ''; + $footer = ''; + } + + my $tableOpen = ''; + my $rowOpen = ''; + my $rowOpenEven = ''; + my $rowOpenOdd = ''; + my $colOpen = ''; + my $colOpenMinWidth = ''; + my $txtOpen = ''; + my $txtClose = ''; + my $colClose = "\t\t\t"; + my $rowClose = ''; + my $tableClose = ''; + my $colorRed = ''; + my $colorGreen = ''; + my $colorClose = ''; + + if ($html) { + $tableOpen = ''; + $rowOpen = ''; + $rowOpenEven = ''; + $rowOpenOdd = ''; + $colOpen = ''; + $rowClose = ''; + $tableClose = '
'; + $colOpenMinWidth = ''; + $txtOpen = ""; + $txtClose = ""; + $colClose = '
'; + $colorRed = ''; + $colorGreen = ''; + $colorClose = ''; + } + + my $space = $html ? ' ' : ' '; + my $lb = $html ? '
' : "\n"; + my $lang = lc( + AttrVal( + $hash->{NAME}, 'language', + AttrVal( 'global', 'language', 'EN' ) + ) + ); + + my $webname = + AttrVal( $hash->{CL}{SNAME}, 'webname', 'fhem' ); + my $FW_CSRF = ( + defined( $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN} ) + ? '&fwcsrf=' . $defs{ $hash->{CL}{SNAME} }{CSRFTOKEN} + : '' + ); + + push @ret, '

Search result: ' . $search . '

'; + my $found = 0; + + # search for matching device + my $foundDevices = 0; + my $linecount = 1; + foreach my $device ( sort keys %defs ) { + next + unless ( defined( $defs{$device}{TYPE} ) + && defined( $modules{ $defs{$device}{TYPE} } ) ); + + if ( $device =~ m/^.*$search.*$/i ) { + unless ($foundDevices) { + push @ret, '

Devices

' . $lb; + push @ret, $tableOpen; + push @ret, + $colOpenMinWidth + . $txtOpen + . 'Device Name' + . $txtClose + . $colClose; + push @ret, + $colOpen . $txtOpen . 'Module Name' . $txtClose . $colClose; + } + $found++; + $foundDevices++; + + my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd; + + FHEM::Meta::Load( $modules{ $defs{$device}{TYPE} } ); + + my $linkDev = $device; + $linkDev = + '' + . $device . '' + if ($html); + + my $linkMod = $defs{$device}{TYPE}; + $linkMod = + '' + . $defs{$device}{TYPE} . '' + if ($html); + + $l .= $colOpenMinWidth . $linkDev . $colClose; + $l .= $colOpen . $linkMod . $colClose; + + $l .= $rowClose; + + push @ret, $l; + $linecount++; + } + } + push @ret, $tableClose if ($foundDevices); + + # search for matching module + my $foundModules = 0; + $linecount = 1; + foreach my $module ( sort keys %modules ) { + if ( $module =~ m/^.*$search.*$/i ) { + unless ($foundModules) { + push @ret, '

Modules

' . $lb; + push @ret, $tableOpen; + push @ret, + $colOpenMinWidth + . $txtOpen + . 'Module Name' + . $txtClose + . $colClose; + push @ret, + $colOpen . $txtOpen . 'Abstract' . $txtClose . $colClose; + } + $found++; + $foundModules++; + + my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd; + + FHEM::Meta::Load($module); + + my $abstract = ''; + $abstract = $modules{$module}{META}{abstract} + if ( defined( $modules{$module}{META} ) + && defined( $modules{$module}{META}{abstract} ) ); + + my $link = $module; + $link = + '' + . $module . '' + if ($html); + + $l .= $colOpenMinWidth . $link . $colClose; + $l .= + $colOpen . ( $abstract eq 'n/a' ? '' : $abstract ) . $colClose; + + $l .= $rowClose; + + push @ret, $l; + $linecount++; + } + } + push @ret, $tableClose if ($foundModules); + + # search for matching keyword + my $foundKeywords = 0; + $linecount = 1; + foreach my $keyword (%FHEM::Meta::keywords) { + if ( $keyword =~ m/^.*$search.*$/i ) { + push @ret, '

Keywords

' unless ($foundKeywords); + $found++; + $foundKeywords++; + + push @ret, '

' . $keyword . '

'; + + my @mAttrs = qw( + modules + packages + ); + + push @ret, $tableOpen; + + push @ret, + $colOpenMinWidth . $txtOpen . 'Name' . $txtClose . $colClose; + + push @ret, $colOpen . $txtOpen . 'Type' . $txtClose . $colClose; + + push @ret, $colOpen . $txtOpen . 'Abstract' . $txtClose . $colClose; + + foreach my $mAttr (@mAttrs) { + next + unless ( defined( $FHEM::Meta::keywords{$keyword}{$mAttr} ) + && @{ $FHEM::Meta::keywords{$keyword}{$mAttr} } > 0 ); + + foreach my $item ( sort { "\L$a" cmp "\L$b" } + @{ $FHEM::Meta::keywords{$keyword}{$mAttr} } ) + { + my $l = $linecount % 2 == 0 ? $rowOpenEven : $rowOpenOdd; + + my $type = $mAttr; + $type = 'Module' if ( $mAttr eq 'modules' ); + $type = 'Perl Package' if ( $mAttr eq 'packages' ); + + FHEM::Meta::Load($item); + + my $abstract = ''; + $abstract = $modules{$item}{META}{abstract} + if ( defined( $modules{$item} ) + && defined( $modules{$item}{META} ) + && defined( $modules{$item}{META}{abstract} ) ); + + my $link = $item; + $link = + '' + . $item . '' + if ($html); + + $l .= $colOpenMinWidth . $link . $colClose; + $l .= $colOpen . $type . $colClose; + $l .= + $colOpen + . ( $abstract eq 'n/a' ? '' : $abstract ) + . $colClose; + + $l .= $rowClose; + + push @ret, $l; + $linecount++; + } + } + + push @ret, $tableClose; + } + } + + return $header . join( "\n", @ret ) . $footer; +} + #TODO # - show master/slave dependencies # - show parent/child dependencies @@ -992,12 +1280,6 @@ sub CreateMetadataList ($$$) { && ( !defined( $modMeta->{resources} ) || !defined( $modMeta->{resources}{x_wiki} ) ) ); - next - if ( - $mAttr eq 'command_reference' - && ( !defined( $modMeta->{resources} ) - || !defined( $modMeta->{resources}{x_commandref} ) ) - ); next if ( $mAttr eq 'community_support' @@ -1040,6 +1322,14 @@ sub CreateMetadataList ($$$) { $mAttrName =~ s/_/$space/g; $mAttrName =~ s/([\w'&]+)/\u\L$1/g; + 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; # these attributes do not exist under that name in META.json @@ -1130,14 +1420,10 @@ sub CreateMetadataList ($$$) { } elsif ( $mAttr eq 'command_reference' ) { - my $webname; - if ( defined( $hash->{CL} ) && defined( $hash->{CL}{TYPE} ) && $hash->{CL}{TYPE} eq 'FHEMWEB' ) { - $webname = - AttrVal( $hash->{CL}{SNAME}, 'webname', 'fhem' ); $l .= '{description} ) - ? ' title="' . $board->{description} . '"' - : '' + ? ' title="' + . $board->{description} + . '"' + : ( + defined( + $modMeta->{resources}{x_support_community} + {description} + ) + ? ' title="' + . $modMeta->{resources}{x_support_community} + {description} . '"' + : '' + ) ) . '>' . $title . ''; @@ -1536,6 +1833,29 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/ $counter++; } } + elsif ( $mAttr eq 'keywords' ) { + my $counter = 0; + foreach my $keyword ( @{ $modMeta->{$mAttr} } ) { + $l .= ', ' if ($counter); + + if ($html) { + $l .= + '' + . $keyword . ''; + } + else { + $l .= $keyword; + } + + $counter++; + } + } else { $l .= join ', ', @{ $modMeta->{$mAttr} }; } @@ -1622,10 +1942,10 @@ m/^([^<>\n\r]+?)(?:\s+(\(last release only\)))?(?:\s+(?:<(.*)>))?$/ my $check = __IsInstalledPerl($prereq); my $installed = ''; if ($check) { - if ( $check =~ m/^\d+\./ ) { + if ( $check ne '1' ) { my $nverReq = - $version ne '' - ? $version + $version ne '' + ? version->parse($version)->numify : 0; my $nverInst = $check; @@ -1965,6 +2285,33 @@ sub CreateRawMetaJson ($$$) { return $j->encode( $modules{$modName}{META} ); } +sub CreateRawMaintainerJson ($$$) { + my ( $hash, $getCmd, $maintainer ) = @_; + my %ret = (); + + $ret{fhem_modules} = $FHEM::Meta::maintainerModules{$maintainer} + if ( defined( $FHEM::Meta::maintainerModules{$maintainer} ) ); + + $ret{fhem_packages} = $FHEM::Meta::maintainerPackages{$maintainer} + if ( defined( $FHEM::Meta::maintainerPackages{$maintainer} ) ); + + $ret{fhem_files} = $FHEM::Meta::maintainerFile{$maintainer} + if ( defined( $FHEM::Meta::maintainerFile{$maintainer} ) ); + + if ( scalar keys %ret > 0 ) { + $ret{fhem_maintainer} = $maintainer; + } + else { + return '{}'; + } + + my $j = JSON->new; + $j->allow_nonref; + $j->canonical; + $j->pretty; + return $j->encode( \%ret ); +} + # Checks whether a perl package is installed in the system sub __IsInstalledPerl($) { return 0 unless ( __PACKAGE__ eq caller(0) ); @@ -2009,8 +2356,7 @@ sub __IsInstalledPython($) { return 0; } -#### my little helper -sub ToDay() { +sub __ToDay() { my ( $sec, $min, $hour, $mday, $month, $year, $wday, $yday, $isdst ) = localtime( gettimeofday() ); @@ -2023,6 +2369,11 @@ sub ToDay() { return $today; } +sub __aUniq { + my %seen; + grep !$seen{$_}++, @_; +} + 1; =pod @@ -2093,7 +2444,7 @@ sub ToDay() { "abstract": "Modul zum Update von FHEM, zur Installation von Drittanbieter FHEM Modulen und der Verwaltung von Systemvoraussetzungen" } }, - "version": "v0.0.3", + "version": "v0.1.0", "release_status": "testing", "author": [ "Julian Pawlowski " diff --git a/FHEM/Meta.pm b/FHEM/Meta.pm index 1ef8f3605..4edae16e7 100644 --- a/FHEM/Meta.pm +++ b/FHEM/Meta.pm @@ -372,6 +372,8 @@ our %moduleUpdates; our %packageUpdates; our %fileUpdates; +our %keywords; + # Package internal variables # @@ -1476,14 +1478,16 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? # Other modules shall get this added elsewhere for performance reasons if ( $modMeta->{name} eq __PACKAGE__ ) { $modMeta->{generated_by} = - $modMeta->{name} . ' ' . $modMeta->{version} . ', ' . TimeNow(); + $modMeta->{name} . ' ' + . version->parse( $modMeta->{version} )->normal . ', ' + . TimeNow(); } # If we are not running in loop, this is not time consuming for us here elsif ( !$runInLoop ) { $modMeta->{generated_by} = $packages{Meta}{name} . ' ' - . __PACKAGE__->VERSION() . ', ' + . version->parse( __PACKAGE__->VERSION() )->normal . ', ' . TimeNow(); } @@ -1549,16 +1553,16 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? foreach ( split( - '/', $moduleMaintainers{ $modMeta->{x_file}[4] }[1] + '/|,', $moduleMaintainers{ $modMeta->{x_file}[4] }[1] ) ) { - push @{ $modMeta->{author} }, $_; + push @{ $modMeta->{author} }, "$_ <>"; } # last update was not by one of the named authors if ( defined( $modMeta->{x_vcs} ) ) { - my $lastEditor = $modMeta->{x_vcs}[15]; + my $lastEditor = $modMeta->{x_vcs}[15] . ' <>'; push @{ $modMeta->{author} }, $modMeta->{x_vcs}[15] . ' (last release only) <>' unless ( @@ -1570,7 +1574,7 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? if ( defined( $moduleMaintainers{ $modMeta->{x_file}[4] } ) ) { foreach ( split( - '/', $moduleMaintainers{ $modMeta->{x_file}[4] }[1] + '/|,', $moduleMaintainers{ $modMeta->{x_file}[4] }[1] ) ) { @@ -1670,12 +1674,7 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? : '' ); $modMeta->{resources}{repository}{x_raw} = - 'https://svn.fhem.de/fhem/trunk/' - . ( - $modMeta->{resources}{repository}{x_filepath} =~ /\/$/ - ? $modMeta->{resources}{repository}{x_filepath} - : $modMeta->{resources}{repository}{x_filepath} . '/' - ) + 'https://svn.fhem.de/fhem/trunk/fhem/' . $modMeta->{x_file}[1] . $modMeta->{x_file}[2]; } @@ -1712,67 +1711,15 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? && defined( $modMeta->{resources}{x_support_community} ) && $modMeta->{x_file}[2] ne 'fhem.pl' ) { - if ( defined( $modMeta->{resources}{x_support_community}{board} ) - && $modMeta->{resources}{x_support_community}{board} ne '' ) + foreach ( + __GenerateKeywordsFromSupportCommunity( + $modMeta->{resources}{x_support_community} + ) + ) { - if ( - defined( - $modMeta->{resources}{x_support_community}{subCommunity} - ) - && defined( - $modMeta->{resources}{x_support_community}{subCommunity} - {board} - ) - && $modMeta->{resources}{x_support_community}{subCommunity} - {board} ne '' - ) - { - my $parent = - lc( $modMeta->{resources}{x_support_community}{board} ); - my $tag = - lc( $modMeta->{resources}{x_support_community}{subCommunity} - {board} ); - - $tag =~ s/$parent\s+-\s+|$parent\s+»\s+//g; - $tag =~ s/ - |»/ /g; - $tag =~ s/ +/-/g; - $tag = 'fhem-' . $tag - if ( $modMeta->{resources}{x_support_community}{cat} =~ - /^FHEM/i ); - $tag = 'cul-' . $tag - if ( $modMeta->{resources}{x_support_community}{cat} =~ - /^CUL/i ); - - push @{ $modMeta->{keywords} }, $tag - if ( !defined( $modMeta->{keywords} ) - || !grep ( m/^$tag$/i, @{ $modMeta->{keywords} } ) ); - } - - my $tag = lc( $modMeta->{resources}{x_support_community}{board} ); - $tag =~ s/ - |»/ /g; - $tag =~ s/ +/-/g; - $tag = 'fhem-' . $tag - if ( - $modMeta->{resources}{x_support_community}{cat} =~ /^FHEM/i ); - $tag = 'cul-' . $tag - if ( $modMeta->{resources}{x_support_community}{cat} =~ /^CUL/i ); - - push @{ $modMeta->{keywords} }, $tag + push @{ $modMeta->{keywords} }, $_ if ( !defined( $modMeta->{keywords} ) - || !grep ( m/^$tag$/i, @{ $modMeta->{keywords} } ) ); - } - - if ( defined( $modMeta->{resources}{x_support_community}{cat} ) - && $modMeta->{resources}{x_support_community}{cat} ne '' - && $modMeta->{resources}{x_support_community}{cat} ne 'FHEM' ) - { - my $tag = lc( $modMeta->{resources}{x_support_community}{cat} ); - $tag =~ s/ - |»/ /g; - $tag =~ s/ +/-/g; - - push @{ $modMeta->{keywords} }, $tag - if ( !defined( $modMeta->{keywords} ) - || !grep ( m/^$tag$/i, @{ $modMeta->{keywords} } ) ); + || !grep ( m/^$_$/i, @{ $modMeta->{keywords} } ) ); } } @@ -1803,6 +1750,22 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? push @{ $modMeta->{keywords} }, "fhem-$modType-local"; } + # Add keywords to global index + if ( @{ $modMeta->{keywords} } > 0 ) { + foreach ( @{ $modMeta->{keywords} } ) { + if ( $modMeta->{x_file}[3] ) { + push @{ $keywords{$_}{modules} }, $modName + if ( !defined( $keywords{$_}{modules} ) + || !grep ( /^$modName$/i, @{ $keywords{$_}{modules} } ) ); + } + else { + push @{ $keywords{$_}{packages} }, $modName + if ( !defined( $keywords{$_}{packages} ) + || !grep ( /^$modName$/i, @{ $keywords{$_}{packages} } ) ); + } + } + } + # generate x_version __SetXVersion($modMeta); @@ -1810,6 +1773,58 @@ m/(^#\s+(?:\d{1,2}\.\d{1,2}\.(?:\d{2}|\d{4})\s+)?[^v\d]*(v?(?:\d{1,3}\.\d{1,3}(? return undef; } +sub __GenerateKeywordsFromSupportCommunity { + my ($community) = @_; + my @keywords; + + if ( defined( $community->{board} ) + && $community->{board} ne '' ) + { + my $prefix; + $prefix = lc($1) . '-' + if ( $community->{cat} =~ /^(\w+)/ ); + + if ( defined( $community->{subCommunity} ) + && defined( $community->{subCommunity}{board} ) + && $community->{subCommunity}{board} ne '' ) + { + my $parent = lc( $community->{board} ); + my $tag = lc( $community->{subCommunity}{board} ); + + $tag =~ s/$parent\s+-\s+|$parent\s+»\s+//g; + $tag =~ s/ - |»/ /g; + $tag =~ s/ +/-/g; + + foreach ( split '/', $tag ) { + push @keywords, $prefix . $_; + } + } + + my $tag = lc( $community->{board} ); + $tag =~ s/ - |»/ /g; + $tag =~ s/ +/-/g; + + foreach ( split '/', $tag ) { + push @keywords, $prefix . $_; + } + } + + if ( defined( $community->{cat} ) + && $community->{cat} ne '' + && $community->{cat} ne 'FHEM' ) + { + my $tag = lc( $community->{cat} ); + $tag =~ s/ - |»/ /g; + $tag =~ s/ +/-/g; + + foreach ( split '/', $tag ) { + push @keywords, $_; + } + } + + return @keywords; +} + sub __GetMaintainerdata { return 0 unless ( __PACKAGE__ eq caller(0) ); my $fh; @@ -1847,6 +1862,16 @@ sub __GetMaintainerdata { || ( $4 && $2 eq 'FHEM/' ) ) { + my $type = $4 ? 'module' : 'package'; + + if ( !-f $1 && !-f $1 . '.pm' ) { + Log 4, + __PACKAGE__ + . "::__GetMaintainerdata ERROR: Orphan $type entry:\n " + . join( ' ', @line ); + next; + } + $maintainer[0][0] = $1; # complete match $maintainer[0][1] = $2; # relative file path $maintainer[0][2] = $3; # file name @@ -1860,6 +1885,8 @@ sub __GetMaintainerdata { ? 'deprecated' : 'supported'; # Lifecycle status + my $modName = $maintainer[0][4]; + $line[2] =~ s/\s*\(.*\)\s*$//; # remove all comments $maintainer[3] = $maintainer[2] eq 'deprecated' @@ -1869,18 +1896,49 @@ sub __GetMaintainerdata { if ( defined( $moduleMaintainers{ $maintainer[0][4] } ) ) { Log 1, __PACKAGE__ - . "::__GetMaintainerdata ERROR: Duplicate entry:\n" - . ' 1st: ' + . "::__GetMaintainerdata ERROR: Duplicate $type entry:\n" + . ' 1st: ' . $moduleMaintainers{ $maintainer[0][4] }[0][0] . ' ' . $moduleMaintainers{ $maintainer[0][4] }[1] . ' ' . $moduleMaintainers{ $maintainer[0][4] }[2] - . "\n 2nd: " + . "\n 2nd: " . join( ' ', @line ); } else { + # Register in global FHEM module index $moduleMaintainers{ $maintainer[0][4] } = \@maintainer; - push @{ $maintainerModules{ $maintainer[1] } }, - $maintainer[0][4]; + + # Register in global maintainer index + foreach ( split '/|,', $maintainer[1] ) { + push @{ $maintainerModules{$_} }, $maintainer[0][4]; + } + + # Generate keywords for global index + foreach ( + __GenerateKeywordsFromSupportCommunity( + $maintainer[3] + ) + ) + { + if ( $type eq 'module' ) { + push @{ $keywords{$_}{modules} }, + $modName + if ( + !defined( $keywords{$_}{modules} ) + || !grep ( /^$modName$/i, + @{ $keywords{$_}{modules} } ) + ); + } + else { + push @{ $keywords{$_}{packages} }, + $modName + if ( + !defined( $keywords{$_}{packages} ) + || !grep ( /^$modName$/i, + @{ $keywords{$_}{packages} } ) + ); + } + } } } @@ -1888,6 +1946,17 @@ sub __GetMaintainerdata { # used by FHEM modules. # Packages must provide file extension here. elsif ( $2 && $2 eq 'FHEM/' && $6 eq 'pm' ) { + + my $type = 'package'; + + if ( !-f $1 && !-f $1 . '.pm' ) { + Log 4, + __PACKAGE__ + . "::__GetMaintainerdata ERROR: Orphan $type entry:\n " + . join( ' ', @line ); + next; + } + $maintainer[0][0] = $1; # complete match $maintainer[0][1] = $2; # relative file path $maintainer[0][2] = $3; # file name @@ -1896,23 +1965,53 @@ sub __GetMaintainerdata { $maintainer[0][4] = $5; # FHEM package name $maintainer[0][5] = $6; # file extension $maintainer[1] = $line[1]; # Maintainer alias name - $maintainer[2] = $line[2]; # Forum support section + $maintainer[2] = + $line[2] =~ m/\(deprecated\)/i + ? 'deprecated' + : 'supported'; # Lifecycle status + + my $modName = $maintainer[0][4]; + + $line[2] =~ s/\s*\(.*\)\s*$//; # remove all comments + $maintainer[3] = + $maintainer[2] eq 'deprecated' + ? () + : __GetSupportForum( $line[2] ); # Forum support section if ( defined( $packageMaintainers{ $maintainer[0][4] } ) ) { Log 1, __PACKAGE__ - . "::__GetMaintainerdata ERROR: Duplicate entry:\n" - . ' 1st: ' + . "::__GetMaintainerdata ERROR: Duplicate $type entry:\n" + . ' 1st: ' . $packageMaintainers{ $maintainer[0][4] }[0][0] . ' ' . $packageMaintainers{ $maintainer[0][4] }[1] . ' ' . $packageMaintainers{ $maintainer[0][4] }[2] - . "\n 2nd: " + . "\n 2nd: " . join( ' ', @line ); } else { + # Register in global FHEM package index $packageMaintainers{ $maintainer[0][4] } = \@maintainer; - push @{ $maintainerPackages{ $maintainer[1] } }, - $maintainer[0][4]; + + # Register in global maintainer index + foreach ( split '/|,', $maintainer[1] ) { + push @{ $maintainerPackages{$_} }, + $maintainer[0][4]; + } + + # Generate keywords for global index + foreach ( + __GenerateKeywordsFromSupportCommunity( + $maintainer[3] + ) + ) + { + push @{ $keywords{$_}{packages} }, $modName + if ( !defined( $keywords{$_}{packages} ) + || ! + grep ( /^$modName$/i, + @{ $keywords{$_}{packages} } ) ); + } } } @@ -2417,7 +2516,7 @@ sub __SetXVersion { "description": "n/a" } }, - "version": "v0.2.0", + "version": "v0.3.0", "release_status": "testing", "author": [ "Julian Pawlowski "