Mnemosyne is a abstract distribution originally designed for ROCKLinux, but currently only support the trunk of OpenSDE.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

675 lines
16 KiB

#!/usr/bin/perl
# --- SDE-COPYRIGHT-NOTE-BEGIN ---
# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
#
# Filename: target/mnemosyne/mnemosyne.pl
# Copyright (C) 2002 - 2006 Alejandro Mery
#
# More information can be found in the files COPYING and README.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License. A copy of the
# GNU General Public License can be found in the file COPYING.
# --- SDE-COPYRIGHT-NOTE-END ---
use warnings;
use strict;
use IPC::Open2;
use constant {ALL => 0, ASK => 1, CHOICE => 2 };
%::FOLDER=();
%::MODULE=();
sub scandir {
my ($pkgseldir,$prefix) = @_;
my %current=('location', $pkgseldir, 'var', "CFGTEMP_$prefix");
# $current{desc,var} for sub-pkgsel dirs
if ($pkgseldir ne $::ROOT) {
my ($relative,$dirvar,$dirname);
$_ = $pkgseldir;
$relative = (m/^$::ROOT\/(.*)/i)[0];
$dirvar = "CFGTEMP_$prefix\_$relative";
$dirvar =~ tr,a-z\/ ,A-Z__,;
$dirname=$relative;
$dirname=~ s/.*\///g;
($current{desc} = $dirname) =~ s/_/ /g;
$current{var} = $dirvar;
}
# make this folder global
$::FOLDER{$current{var}} = \%current;
{
# make scandir recursive
my @children;
opendir(my $DIR, $pkgseldir);
foreach( grep { ! /^\./ } sort readdir($DIR) ) {
$_ = "$pkgseldir/$_";
if ( -d $_ ) {
my $subdir = scandir($_,$prefix);
push @children,$subdir;
} else {
my $module=scanmodule($_,$prefix,$current{var});
if ($module) {
push @children,$module unless grep(/^$module$/,@children);
}
}
}
closedir $DIR;
$current{children} = \@children;
return $current{var};
}
}
sub scanmodule {
my ($file,$prefix,$folder)=@_;
my (%current,$FILE);
# this defines dir,key,option and kind acording to the following format.
# $dir/[$prio-]$var[$option].$kind
do {
my ($dir,$key,$option,$kind);
m/^(.*)\/(\d+-)?([^\.]*).?([^\.]*)?\.([^\/\.]*)/i;
($dir,$key,$option,$kind) = ($1,$3,$4,$5);
if ($kind eq 'choice') { $current{kind} = CHOICE; $current{option} = $option; }
elsif ($kind eq 'all') { $current{kind} = ALL; }
elsif ($kind eq 'ask') { $current{kind} = ASK; }
else { return; }
$current{location} = $dir;
$current{key} = $key;
$current{file} = $file;
} for $file;
open($FILE,'<',$file);
while(<$FILE>) {
if (/^#[^#: ]+: /) {
my ($field,$value) = m/^#([^#: ]+): (.*)$/i;
if ($field eq 'Description') {
$current{desc} = $value;
} elsif ($field eq 'Variable') {
$current{var} = $value;
} elsif ($field eq 'Default') {
$current{default} = $value;
} elsif ($field eq 'Forced') {
$current{forced} = $value;
} elsif ($field eq 'Imply') {
$current{imply} = $value;
} elsif ($field eq 'Dependencies') {
$current{deps} = $value;
# } else {
# print "$file:$field:$value.\n";
}
}
}
close($FILE);
# var name
$current{var} = uc $current{key}
unless exists $current{var};
$current{var} = "SDECFG_$prefix\_" . $current{var}
unless $current{var} =~ /^SDECFG_$prefix\_/;
# for choices, we use $option instead of $key as description
($current{desc} = $current{option}) =~ s/_/ /g
if exists $current{option} && ! exists $current{desc};
($current{desc} = $current{key}) =~ s/_/ /g
unless exists $current{desc};
# dependencies
# NOTE: don't use spaces on the pkgsel file, only to delimite different dependencies
if (exists $current{deps}) {
my @deps;
for ( split (/\s+/,$current{deps}) ) {
$_="SDECFG_$prefix\_$_" unless /^(SDECFG|CFGTEMP)/;
if (/=/) {
m/(.*?)(==|!=|=)(.*)/i;
$_="\"\$$1\" $2 $3";
} else {
$_="\"\$$_\" == 1";
}
push @deps,$_;
}
$current{deps} = \@deps;
}
# forced modules
if (exists $current{forced}) {
my @forced;
for ( split (/\s+/,$current{forced}) ) {
$_="SDECFG_$prefix\_$_" unless /^SDECFG/;
$_="$_=1" unless /=/;
push @forced,$_;
}
$current{forced} = \@forced;
}
# implied options
if (exists $current{imply}) {
my @imply = split (/\s+/,$current{imply});
$current{imply} = \@imply;
}
# make this module global
if ( $current{kind} == CHOICE ) {
# prepare the option for this choice
my %option;
for ('desc','forced','imply','deps','option','file') {
$option{$_}=$current{$_} if exists $current{$_};
}
if ( exists $::MODULE{$current{var}} ) {
push @{ $::MODULE{$current{var}}{options} },\%option;
} else {
# prepare and add this choice module
my @options = (\%option);
$::MODULE{$current{var}} = {
'kind', CHOICE,
'options', \@options,
};
for ('key','location','var') {
$::MODULE{$current{var}}{$_}=$current{$_}
if exists $current{$_};
}
}
} else {
$::MODULE{$current{var}} = {};
for ('key','location','var','desc','forced','deps','file','kind') {
$::MODULE{$current{var}}{$_}=$current{$_}
if exists $current{$_};
}
}
# default value
$::MODULE{$current{var}}{folder} = $folder;
$::MODULE{$current{var}}{default} = $current{default}
if exists $current{default};
return $current{var};
}
sub process_modules {
my ($READ,$WRITE,$pid);
my $i=0;
$pid = open2($READ, $WRITE, 'tsort');
# prepare topographic modules map
for my $module (values %::MODULE) {
my $related;
if ($module->{kind} == CHOICE) {
for (@{ $module->{options} }) {
my $option = $_;
for (@{exists $option->{deps} ? $option->{deps} : []} ) {
my $dep = (m/"\$([^"]+)"/i)[0];
print $WRITE "$dep $module->{var}\n";
$related=1;
}
for (@{exists $option->{forced} ? $option->{forced} : []} ) {
my $forced = (m/([^"]+)=/i)[0];
print $WRITE "$module->{var} $forced\n";
$related=1;
}
}
} else {
for (@{exists $module->{deps} ? $module->{deps} : []} ) {
my $dep = (m/"\$([^"]+)"/i)[0];
print $WRITE "$dep $module->{var}\n";
$related=1;
}
for (@{exists $module->{forced} ? $module->{forced} : []} ) {
my $forced = (m/([^"]+)=/i)[0];
print $WRITE "$module->{var} $forced\n";
$related=1;
}
}
if (! $related) {
print $WRITE "$module->{var} $module->{var}\n";
}
}
close($WRITE);
# and populate the sorted list
my @sorted;
while(<$READ>) {
if (/(.*)\n/) { push @sorted, $1; }
}
waitpid $pid,0;
die if $?;
# and remember the sorted list
$::MODULES=\@sorted;
}
sub process_folders {
my ($READ,$WRITE,$pid);
$pid = open2($READ, $WRITE, 'tsort | tac');
# prepare topographic modules map
for my $folder (values %::FOLDER) {
for ( exists $folder->{children} ? grep(!/^SDECFG/, @{$folder->{children}}) : [] ) {
print $WRITE "$folder->{var} $_\n";
}
}
close($WRITE);
# and populate the sorted list
my @sorted;
while(<$READ>) {
if (/(.*)\n/) { push @sorted, $1; }
}
waitpid $pid,0;
die if $?;
# and remember the sorted list
$::FOLDERS=\@sorted;
}
sub render_widgets_folder {
my ($folder,$offset) = @_;
for (@{$folder->{children}}) {
if (/^CFGTEMP/) {
my $subfolder=$::FOLDER{$_};
print "\n${offset}# $_\n${offset}#\n";
# opening
print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
print "${offset}\tmenu_begin $subfolder->{var} '$subfolder->{desc}'\n";
print "${offset}fi\n";
render_widgets_folder($::FOLDER{$_},"$offset\t");
# closing
print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
print "${offset}\tmenu_end\n";
print "${offset}fi\n";
} else {
my $module=$::MODULE{$_};
my $var=$module->{var};
my $conffile="$module->{location}/$module->{key}.conf"
if -f "$module->{location}/$module->{key}.conf";
my $noconffile="$module->{location}/$module->{key}-no.conf"
if -f "$module->{location}/$module->{key}-no.conf";
print "${offset}# $var\n";
if ($module->{kind} == CHOICE) {
# CHOICE
my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
my $listvar = "$tmpvar\_LIST";
my $defaultvar = "$tmpvar\_DEFAULT";
print "${offset}if \[ -n \"\$$var\" \]; then\n";
print "${offset}\tchoice $var \$$defaultvar \$$listvar\n";
print "${offset}\t. $conffile\n" if $conffile;
print "${offset}\telse\n" if $noconffile;
print "${offset}\t. $noconffile\n" if $noconffile;
print "${offset}fi\n";
} elsif ($module->{kind} == ASK) {
# ASK
my $default=0;
$default = $module->{default} if exists $module->{default};
print "${offset}if \[ -n \"\$$var\" \]; then\n";
print "${offset}\tbool '$module->{desc}' $module->{var} $default\n";
print "${offset}\t\[ \"\$$var\" == 1 \] && . $conffile\n" if $conffile;
print "${offset}\t\[ \"\$$var\" != 1 \] && . $noconffile\n" if $noconffile;
print "${offset}fi\n";
} elsif ($conffile) {
# ALL, only if $conffile
print "${offset}if \[ -n \"\$$var\" \]; then\n";
print "${offset}\t. $conffile\n" if $conffile;
print "${offset}\telse\n" if $noconffile;
print "${offset}\t. $noconffile\n" if $noconffile;
print "${offset}fi\n";
}
}
}
}
sub render_widgets {
open(my $FILE,'>',$_[0]);
my $root="CFGTEMP_$_[1]";
select $FILE;
render_widgets_folder($::FOLDER{$root},'');
select STDOUT;
close($FILE);
}
sub pkgsel_parse {
my ($action,$patternlist) = @_;
if ($action eq 'X' or $action eq 'x' ) {
$action = '$1="X"';
} elsif ($action eq 'O' or $action eq 'o') {
$action = '$1="O"';
} elsif ($action eq '-') {
$action = 'next';
} else {
$action = '{ exit; }';
}
my ($address,$first,$others)= ('','( ','&& ');
for (split(/\s+/,$patternlist)) {
if (! $address and $_ eq '!') {
$address = '! ';
$others = '|| $4"/"$5 ~';
} else {
$_="\*/$_" unless /\//;
s,[^a-zA-Z0-9_/\*+\.-],,g;
s,([/\.\+]),\\$1,g;
s,\*,[^/]*,g;
next unless $_;
$address = "$address$first";
$address = "$address / $_ /";
$first = "$others";
}
=for nobody
[ "$pattern" ] || continue
address="$address$first"
address="$address / $pattern /"
first=" $others"
=cut
}
print "\techo '$address ) { $action; }'\n";
return 1;
}
sub render_awkgen {
open(my $OUTPUT,'>',$_[0]);
my $root="CFGTEMP_$_[1]";
select $OUTPUT;
# initially change packages $4 and $5 to be able to correctly match repo based.
print "echo '{'\n";
print "echo '\trepo=\$4 ;'\n";
print "echo '\tpkg=\$5 ;'\n";
print "echo '\t\$5 = \$4 \"/\" \$5 ;'\n";
print "echo '\t\$4 = \"placeholder\" ;'\n";
print "echo '}'\n";
render_awkgen_folder($::FOLDER{$root});
# ... restore $4 and $5, and print the resulting line
print "echo '\n{'\n";
print "echo '\t\$4=repo ;'\n";
print "echo '\t\$5=pkg ;'\n";
print "echo '\tprint ;'\n";
print "echo '}'\n";
select STDOUT;
close($OUTPUT);
}
sub render_awkgen_folder {
my ($folder) = @_;
for (@{$folder->{children}}) {
if (/^CFGTEMP/) {
render_awkgen_folder($::FOLDER{$_});
} else {
my $module=$::MODULE{$_};
if ($module->{kind} == CHOICE) {
my %options;
# the list of options
for (@{ $module->{options} }) {
my $option = $_;
my @array=("\"\$$module->{var}\" == $_->{option}");
$options{$_->{option}} = \@array;
}
# and their implyed options
for (@{ $module->{options} }) {
my $option = $_;
for (@{exists $option->{imply}? $option->{imply} : [] }) {
push @{$options{$_}},
"\"\$$module->{var}\" == $option->{option}";
}
}
print "\n";
# and finally, render.
for (@{ $module->{options} }) {
print "if [ " . join(' -o ',@{ $options{ $_->{option} }}). " ]; then\n";
open(my $FILE,'<',$_->{file});
my $hasrules=0;
while(<$FILE>) {
next if /^#/;
next if /^\s*$/;
pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
$hasrules=1;
}
close($FILE);
print "\ttrue\n" unless $hasrules;
print "fi\n";
}
} else {
print "\nif [ \"\$$module->{var}\" == 1 ]; then\n";
open(my $FILE,'<',$module->{file});
my $hasrules=0;
while(<$FILE>) {
next if /^#/;
next if /^\s*$/;
pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
$hasrules=1;
}
close($FILE);
print "\ttrue\n" unless $hasrules;
print "fi\n";
}
}
}
}
sub render_rules_module {
my ($module,$offset) = @_;
my $var = $module->{var};
if ($module->{kind} == CHOICE) {
my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
my $listvar = "$tmpvar\_LIST";
my $defaultvar = "$tmpvar\_DEFAULT";
my $default = "undefined";
my $forcer;
$default = $module->{default} if exists $module->{default};
# initialize the list
print "${offset}$listvar=\n";
print "${offset}$defaultvar=$default\n";
print "${offset}\[ -n \"\$$var\" \] || $var=$default\n\n";
for ( @{ $module->{options} } ) {
my $option = $_;
(my $desc = $option->{desc}) =~ s/ /_/g;
# has something to force?
if (exists $option->{forced}) { $forcer = 1; }
if (exists $option->{deps}) {
print "${offset}if [ " .
join(' -a ', @{ $option->{deps} } ) .
" ]; then\n";
print "${offset}\t$listvar=\"\$$listvar $option->{option} $desc\"\n";
print "${offset}fi\n";
} else {
print "${offset}$listvar=\"\$$listvar $option->{option} $desc\"\n";
}
}
# enable the folder display
print "${offset}if \[ -n \"\$$listvar\" \]; then\n";
print "${offset}\t$module->{folder}=1\n";
print "${offset}else\n";
print "${offset}\tunset $module->{var}\n";
print "${offset}fi\n";
# has something to force?
if ($forcer) {
print "\n${offset}case \"\$$var\" in\n";
for ( @{ $module->{options} } ) {
my $option = $_;
if (exists $option->{forced}) {
print "${offset}\t$option->{option})\n";
for ( @{ $option->{forced} } ) {
print "$offset\t\t$_\n";
print "$offset\t\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
}
print "${offset}\t\t;;\n";
}
}
print "${offset}esac\n";
}
# printref($var,$module,$offset);
} elsif ($module->{kind} == ASK) {
my $default=0;
$default = $module->{default} if exists $module->{default};
#enable the folder display
print "$offset$module->{folder}=1\n";
# and set the default value if none is set.
print "$offset\[ -n \"\$$var\" \] || $var=$default\n";
# if enabled, append pkgsel and force the forced
if (exists $module->{forced}) {
print "\n${offset}if [ \"\$$var\" == 1 ]; then\n";
for ( @{ $module->{forced} } ) {
print "$offset\t$_\n";
print "$offset\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
}
print $offset."fi\n";
}
} else {
# just enable the feature
print "$offset$var=1\n";
# forced list doesn't make sense for {kind} == ALL
}
}
sub render_rules_nomodule {
my ($module,$offset) = @_;
my $var = $module->{var};
# unset the choice list, and the var
if ($module->{kind} == CHOICE) {
my $listvar = "CFGTEMP_$1_LIST" if $var =~ m/^SDECFG_(.*)/i;
print "${offset}unset $listvar\n";
}
print "${offset}unset SDECFGSET_$1\n" if $var =~ m/^SDECFG_(.*)/i;
print "${offset}unset $var\n";
}
sub render_rules {
open(my $FILE,'>',$_[0]);
my $root="CFGTEMP_$_[1]";
select $FILE;
# clean folder enablers
print "#\n# folder enablers\n#\n\n";
for (@$::FOLDERS) { print "$_=\n" unless /^$root$/; }
# pkgsel list
for (@$::MODULES) {
if (exists $::MODULE{$_}) {
my $module = $::MODULE{$_};
print "\n#\n# $module->{var} ("
. ($module->{kind} == ALL ? "ALL" : ($module->{kind} == ASK ? "ASK" : "CHOICE" ) )
. ")\n#\n";
if (exists $module->{deps}) {
print "if [ " . join(' -a ', @{ $module->{deps} } ) . " ]; then\n";
render_rules_module($module,"\t");
print "else\n";
render_rules_nomodule($module,"\t");
print "fi\n";
} else {
render_rules_module($module,"");
}
}
}
print "\n#\n# enable folder with enabled subfolders\n#\n";
for (@$::FOLDERS) {
my $folder = $::FOLDER{$_};
my @subdirs = grep(/^CFGTEMP/,@{$folder->{children}});
if ( @subdirs ) {
print "if [ -n \"\$".join('$', @subdirs )."\" ]; then\n";
print "\t$folder->{var}=1\n";
print "fi\n";
}
}
select STDOUT;
close($FILE);
}
# print the content of a hash
sub printref {
my ($name,$ref,$offset) = @_;
my $typeof = ref($ref);
print "$offset$name:";
if ($typeof eq '') {
print " '$ref'\n";
} elsif ($typeof eq 'HASH') {
print "\n";
for (sort keys %{ $ref }) {
printref($_,$ref->{$_},"$offset\t");
}
} elsif ($typeof eq 'ARRAY') {
my $i=0;
print "\n";
for (@{ $ref }) {
printref("[$i]",$_,"$offset\t");
$i++;
}
} else {
print " -> $typeof\n";
}
}
if ($#ARGV != 4) {
print "Usage mnemosyne.pl: <pkgseldir> <prefix> <configfile> <rulesfile> <awkgenerator>\n";
exit (1);
}
$| = 1;
$::ROOT=$ARGV[0];
scandir($ARGV[0],$ARGV[1]);
process_modules();
process_folders();
render_rules($ARGV[3],$ARGV[1]);
render_widgets($ARGV[2],$ARGV[1]);
render_awkgen($ARGV[4],$ARGV[1]);