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.

667 lines
16 KiB

  1. #!/usr/bin/perl
  2. # --- SDE-COPYRIGHT-NOTE-BEGIN ---
  3. # This copyright note is auto-generated by ./scripts/Create-CopyPatch.
  4. #
  5. # Filename: target/mnemosyne/mnemosyne.pl
  6. # Copyright (C) 2008 The OpenSDE Project
  7. # Copyright (C) 2002 - 2006 Alejandro Mery
  8. #
  9. # More information can be found in the files COPYING and README.
  10. #
  11. # This program is free software; you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as published by
  13. # the Free Software Foundation; version 2 of the License. A copy of the
  14. # GNU General Public License can be found in the file COPYING.
  15. # --- SDE-COPYRIGHT-NOTE-END ---
  16. use warnings;
  17. use strict;
  18. use IPC::Open2;
  19. use constant {ALL => 0, ASK => 1, CHOICE => 2 };
  20. %::FOLDER=();
  21. %::MODULE=();
  22. sub scandir {
  23. my ($pkgseldir,$prefix) = @_;
  24. my %current=('location', $pkgseldir, 'var', "CFGTEMP_$prefix");
  25. # $current{desc,var} for sub-pkgsel dirs
  26. if ($pkgseldir ne $::ROOT) {
  27. my ($relative,$dirvar,$dirname);
  28. $_ = $pkgseldir;
  29. $relative = (m/^$::ROOT\/(.*)/i)[0];
  30. $dirvar = "CFGTEMP_$prefix\_$relative";
  31. $dirvar =~ tr,a-z\/ ,A-Z__,;
  32. $dirname=$relative;
  33. $dirname=~ s/.*\///g;
  34. ($current{desc} = $dirname) =~ s/_/ /g;
  35. $current{var} = $dirvar;
  36. }
  37. # make this folder global
  38. $::FOLDER{$current{var}} = \%current;
  39. {
  40. # make scandir recursive
  41. my @children;
  42. opendir(my $DIR, $pkgseldir);
  43. foreach( grep { ! /^\./ } sort readdir($DIR) ) {
  44. $_ = "$pkgseldir/$_";
  45. if ( -d $_ ) {
  46. my $subdir = scandir($_,$prefix);
  47. push @children,$subdir;
  48. } else {
  49. my $module=scanmodule($_,$prefix,$current{var});
  50. if ($module) {
  51. push @children,$module unless grep(/^$module$/,@children);
  52. }
  53. }
  54. }
  55. closedir $DIR;
  56. $current{children} = \@children;
  57. return $current{var};
  58. }
  59. }
  60. sub scanmodule {
  61. my ($file,$prefix,$folder)=@_;
  62. my (%current,$FILE);
  63. # this defines dir,key,option and kind acording to the following format.
  64. # $dir/[$prio-]$var[$option].$kind
  65. do {
  66. my ($dir,$key,$option,$kind);
  67. m/^(.*)\/(\d+-)?([^\.]*).?([^\.]*)?\.([^\/\.]*)/i;
  68. ($dir,$key,$option,$kind) = ($1,$3,$4,$5);
  69. if ($kind eq 'choice') { $current{kind} = CHOICE; $current{option} = $option; }
  70. elsif ($kind eq 'all') { $current{kind} = ALL; }
  71. elsif ($kind eq 'ask') { $current{kind} = ASK; }
  72. else { return; }
  73. $current{location} = $dir;
  74. $current{key} = $key;
  75. $current{file} = $file;
  76. } for $file;
  77. open($FILE,'<',$file);
  78. while(<$FILE>) {
  79. if (/^#[^#: ]+: /) {
  80. my ($field,$value) = m/^#([^#: ]+): (.*)$/i;
  81. if ($field eq 'Description') {
  82. $current{desc} = $value;
  83. } elsif ($field eq 'Variable') {
  84. $current{var} = $value;
  85. } elsif ($field eq 'Default') {
  86. $current{default} = $value;
  87. } elsif ($field eq 'Forced') {
  88. $current{forced} = $value;
  89. } elsif ($field eq 'Imply') {
  90. $current{imply} = $value;
  91. } elsif ($field eq 'Dependencies') {
  92. $current{deps} = $value;
  93. # } else {
  94. # print "$file:$field:$value.\n";
  95. }
  96. }
  97. }
  98. close($FILE);
  99. # var name
  100. $current{var} = uc $current{key}
  101. unless exists $current{var};
  102. $current{var} = "SDECFG_$prefix\_" . $current{var}
  103. unless $current{var} =~ /^SDECFG_$prefix\_/;
  104. # for choices, we use $option instead of $key as description
  105. ($current{desc} = $current{option}) =~ s/_/ /g
  106. if exists $current{option} && ! exists $current{desc};
  107. ($current{desc} = $current{key}) =~ s/_/ /g
  108. unless exists $current{desc};
  109. # dependencies
  110. # NOTE: don't use spaces on the pkgsel file, only to delimite different dependencies
  111. if (exists $current{deps}) {
  112. my @deps;
  113. for ( split (/\s+/,$current{deps}) ) {
  114. $_="SDECFG_$prefix\_$_" unless /^(SDECFG|CFGTEMP)/;
  115. if (/=/) {
  116. m/(.*?)(==|!=|=)(.*)/i;
  117. $_="\"\$$1\" $2 $3";
  118. } else {
  119. $_="\"\$$_\" == 1";
  120. }
  121. push @deps,$_;
  122. }
  123. $current{deps} = \@deps;
  124. }
  125. # forced modules
  126. if (exists $current{forced}) {
  127. my @forced;
  128. for ( split (/\s+/,$current{forced}) ) {
  129. $_="SDECFG_$prefix\_$_" unless /^SDECFG/;
  130. $_="$_=1" unless /=/;
  131. push @forced,$_;
  132. }
  133. $current{forced} = \@forced;
  134. }
  135. # implied options
  136. if (exists $current{imply}) {
  137. my @imply = split (/\s+/,$current{imply});
  138. $current{imply} = \@imply;
  139. }
  140. # make this module global
  141. if ( $current{kind} == CHOICE ) {
  142. # prepare the option for this choice
  143. my %option;
  144. for ('desc','forced','imply','deps','option','file') {
  145. $option{$_}=$current{$_} if exists $current{$_};
  146. }
  147. if ( exists $::MODULE{$current{var}} ) {
  148. push @{ $::MODULE{$current{var}}{options} },\%option;
  149. } else {
  150. # prepare and add this choice module
  151. my @options = (\%option);
  152. $::MODULE{$current{var}} = {
  153. 'kind', CHOICE,
  154. 'options', \@options,
  155. };
  156. for ('key','location','var') {
  157. $::MODULE{$current{var}}{$_}=$current{$_}
  158. if exists $current{$_};
  159. }
  160. }
  161. } else {
  162. $::MODULE{$current{var}} = {};
  163. for ('key','location','var','desc','forced','deps','file','kind') {
  164. $::MODULE{$current{var}}{$_}=$current{$_}
  165. if exists $current{$_};
  166. }
  167. }
  168. # default value
  169. $::MODULE{$current{var}}{folder} = $folder;
  170. $::MODULE{$current{var}}{default} = $current{default}
  171. if exists $current{default};
  172. return $current{var};
  173. }
  174. sub process_modules {
  175. my ($READ,$WRITE,$pid);
  176. my $i=0;
  177. $pid = open2($READ, $WRITE, 'tsort');
  178. # prepare topographic modules map
  179. for my $module (values %::MODULE) {
  180. my $related;
  181. if ($module->{kind} == CHOICE) {
  182. for (@{ $module->{options} }) {
  183. my $option = $_;
  184. for (@{exists $option->{deps} ? $option->{deps} : []} ) {
  185. my $dep = (m/"\$([^"]+)"/i)[0];
  186. print $WRITE "$dep $module->{var}\n";
  187. $related=1;
  188. }
  189. for (@{exists $option->{forced} ? $option->{forced} : []} ) {
  190. my $forced = (m/([^"]+)=/i)[0];
  191. print $WRITE "$module->{var} $forced\n";
  192. $related=1;
  193. }
  194. }
  195. } else {
  196. for (@{exists $module->{deps} ? $module->{deps} : []} ) {
  197. my $dep = (m/"\$([^"]+)"/i)[0];
  198. print $WRITE "$dep $module->{var}\n";
  199. $related=1;
  200. }
  201. for (@{exists $module->{forced} ? $module->{forced} : []} ) {
  202. my $forced = (m/([^"]+)=/i)[0];
  203. print $WRITE "$module->{var} $forced\n";
  204. $related=1;
  205. }
  206. }
  207. if (! $related) {
  208. print $WRITE "$module->{var} $module->{var}\n";
  209. }
  210. }
  211. close($WRITE);
  212. # and populate the sorted list
  213. my @sorted;
  214. while(<$READ>) {
  215. if (/(.*)\n/) { push @sorted, $1; }
  216. }
  217. waitpid $pid,0;
  218. die if $?;
  219. # and remember the sorted list
  220. $::MODULES=\@sorted;
  221. }
  222. sub process_folders {
  223. my ($READ,$WRITE,$pid);
  224. $pid = open2($READ, $WRITE, 'tsort | tac');
  225. # prepare topographic modules map
  226. for my $folder (values %::FOLDER) {
  227. for ( exists $folder->{children} ? grep(!/^SDECFG/, @{$folder->{children}}) : [] ) {
  228. print $WRITE "$folder->{var} $_\n";
  229. }
  230. }
  231. close($WRITE);
  232. # and populate the sorted list
  233. my @sorted;
  234. while(<$READ>) {
  235. if (/(.*)\n/) { push @sorted, $1; }
  236. }
  237. waitpid $pid,0;
  238. die if $?;
  239. # and remember the sorted list
  240. $::FOLDERS=\@sorted;
  241. }
  242. sub render_widgets_folder {
  243. my ($folder,$offset) = @_;
  244. for (@{$folder->{children}}) {
  245. if (/^CFGTEMP/) {
  246. my $subfolder=$::FOLDER{$_};
  247. print "\n${offset}# $_\n${offset}#\n";
  248. # opening
  249. print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
  250. print "${offset}\tmenu_begin $subfolder->{var} '$subfolder->{desc}'\n";
  251. print "${offset}fi\n";
  252. render_widgets_folder($::FOLDER{$_},"$offset\t");
  253. # closing
  254. print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
  255. print "${offset}\tmenu_end\n";
  256. print "${offset}fi\n";
  257. } else {
  258. my $module=$::MODULE{$_};
  259. my $var=$module->{var};
  260. my $conffile="$module->{location}/$module->{key}.conf"
  261. if -f "$module->{location}/$module->{key}.conf";
  262. print "${offset}# $var\n";
  263. if ($module->{kind} == CHOICE) {
  264. # CHOICE
  265. my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
  266. my $listvar = "$tmpvar\_LIST";
  267. my $defaultvar = "$tmpvar\_DEFAULT";
  268. print "${offset}if \[ -n \"\$$var\" \]; then\n";
  269. print "${offset}\tchoice $var \$$defaultvar \$$listvar\n";
  270. print "${offset}fi\n";
  271. print "${offset}. $conffile \"$var\" \"\$$var\" \n" if $conffile;
  272. } elsif ($module->{kind} == ASK) {
  273. # ASK
  274. my $default=0;
  275. $default = $module->{default} if exists $module->{default};
  276. print "${offset}if \[ -n \"\$$var\" \]; then\n";
  277. print "${offset}\tbool '$module->{desc}' $module->{var} $default\n";
  278. print "${offset}fi\n";
  279. print "${offset}. $conffile \"$var\" \"\$$var\" \n" if $conffile;
  280. } elsif ($conffile) {
  281. # ALL, only if $conffile
  282. print "${offset}. $conffile \"$var\" \"\$$var\" \n";
  283. }
  284. }
  285. }
  286. }
  287. sub render_widgets {
  288. open(my $FILE,'>',$_[0]);
  289. my $root="CFGTEMP_$_[1]";
  290. select $FILE;
  291. render_widgets_folder($::FOLDER{$root},'');
  292. select STDOUT;
  293. close($FILE);
  294. }
  295. sub pkgsel_parse {
  296. my ($action,$patternlist) = @_;
  297. if ($action eq 'X' or $action eq 'x' ) {
  298. $action = '$1="X"';
  299. } elsif ($action eq 'O' or $action eq 'o') {
  300. $action = '$1="O"';
  301. } elsif ($action eq '-') {
  302. $action = 'next';
  303. } else {
  304. $action = '{ exit; }';
  305. }
  306. my ($address,$first,$others)= ('','( ','&& ');
  307. for (split(/\s+/,$patternlist)) {
  308. if (! $address and $_ eq '!') {
  309. $address = '! ';
  310. $others = '|| $4"/"$5 ~';
  311. } else {
  312. $_="\*/$_" unless /\//;
  313. s,[^a-zA-Z0-9_/\*+\.-],,g;
  314. s,([/\.\+]),\\$1,g;
  315. s,\*,[^/]*,g;
  316. next unless $_;
  317. $address = "$address$first";
  318. $address = "$address / $_ /";
  319. $first = "$others";
  320. }
  321. =for nobody
  322. [ "$pattern" ] || continue
  323. address="$address$first"
  324. address="$address / $pattern /"
  325. first=" $others"
  326. =cut
  327. }
  328. print "\techo '$address ) { $action; }'\n";
  329. return 1;
  330. }
  331. sub render_awkgen {
  332. open(my $OUTPUT,'>',$_[0]);
  333. my $root="CFGTEMP_$_[1]";
  334. select $OUTPUT;
  335. # initially change packages $4 and $5 to be able to correctly match repo based.
  336. print "echo '{'\n";
  337. print "echo '\trepo=\$4 ;'\n";
  338. print "echo '\tpkg=\$5 ;'\n";
  339. print "echo '\t\$5 = \$4 \"/\" \$5 ;'\n";
  340. print "echo '\t\$4 = \"placeholder\" ;'\n";
  341. print "echo '}'\n";
  342. render_awkgen_folder($::FOLDER{$root});
  343. # ... restore $4 and $5, and print the resulting line
  344. print "echo '\n{'\n";
  345. print "echo '\t\$4=repo ;'\n";
  346. print "echo '\t\$5=pkg ;'\n";
  347. print "echo '\tprint ;'\n";
  348. print "echo '}'\n";
  349. select STDOUT;
  350. close($OUTPUT);
  351. }
  352. sub render_awkgen_folder {
  353. my ($folder) = @_;
  354. for (@{$folder->{children}}) {
  355. if (/^CFGTEMP/) {
  356. render_awkgen_folder($::FOLDER{$_});
  357. } else {
  358. my $module=$::MODULE{$_};
  359. if ($module->{kind} == CHOICE) {
  360. my %options;
  361. # the list of options
  362. for (@{ $module->{options} }) {
  363. my $option = $_;
  364. my @array=("\"\$$module->{var}\" == $_->{option}");
  365. $options{$_->{option}} = \@array;
  366. }
  367. # and their implyed options
  368. for (@{ $module->{options} }) {
  369. my $option = $_;
  370. for (@{exists $option->{imply}? $option->{imply} : [] }) {
  371. push @{$options{$_}},
  372. "\"\$$module->{var}\" == $option->{option}";
  373. }
  374. }
  375. print "\n";
  376. # and finally, render.
  377. for (@{ $module->{options} }) {
  378. print "if [ " . join(' -o ',@{ $options{ $_->{option} }}). " ]; then\n";
  379. open(my $FILE,'<',$_->{file});
  380. my $hasrules=0;
  381. while(<$FILE>) {
  382. next if /^#/;
  383. next if /^\s*$/;
  384. pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
  385. $hasrules=1;
  386. }
  387. close($FILE);
  388. print "\ttrue\n" unless $hasrules;
  389. print "fi\n";
  390. }
  391. } else {
  392. print "\nif [ \"\$$module->{var}\" == 1 ]; then\n";
  393. open(my $FILE,'<',$module->{file});
  394. my $hasrules=0;
  395. while(<$FILE>) {
  396. next if /^#/;
  397. next if /^\s*$/;
  398. pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
  399. $hasrules=1;
  400. }
  401. close($FILE);
  402. print "\ttrue\n" unless $hasrules;
  403. print "fi\n";
  404. }
  405. }
  406. }
  407. }
  408. sub render_rules_module {
  409. my ($module,$offset) = @_;
  410. my $var = $module->{var};
  411. if ($module->{kind} == CHOICE) {
  412. my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
  413. my $listvar = "$tmpvar\_LIST";
  414. my $defaultvar = "$tmpvar\_DEFAULT";
  415. my $default = "undefined";
  416. my $forcer;
  417. $default = $module->{default} if exists $module->{default};
  418. # initialize the list
  419. print "${offset}$listvar=\n";
  420. print "${offset}$defaultvar=$default\n";
  421. print "${offset}\[ -n \"\$$var\" \] || $var=$default\n\n";
  422. for ( @{ $module->{options} } ) {
  423. my $option = $_;
  424. (my $desc = $option->{desc}) =~ s/ /_/g;
  425. # has something to force?
  426. if (exists $option->{forced}) { $forcer = 1; }
  427. if (exists $option->{deps}) {
  428. print "${offset}if [ " .
  429. join(' -a ', @{ $option->{deps} } ) .
  430. " ]; then\n";
  431. print "${offset}\t$listvar=\"\$$listvar $option->{option} $desc\"\n";
  432. print "${offset}fi\n";
  433. } else {
  434. print "${offset}$listvar=\"\$$listvar $option->{option} $desc\"\n";
  435. }
  436. }
  437. # enable the folder display
  438. print "${offset}if \[ -n \"\$$listvar\" \]; then\n";
  439. print "${offset}\t$module->{folder}=1\n";
  440. print "${offset}else\n";
  441. print "${offset}\tunset $module->{var}\n";
  442. print "${offset}fi\n";
  443. # has something to force?
  444. if ($forcer) {
  445. print "\n${offset}case \"\$$var\" in\n";
  446. for ( @{ $module->{options} } ) {
  447. my $option = $_;
  448. if (exists $option->{forced}) {
  449. print "${offset}\t$option->{option})\n";
  450. for ( @{ $option->{forced} } ) {
  451. print "$offset\t\t$_\n";
  452. print "$offset\t\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
  453. }
  454. print "${offset}\t\t;;\n";
  455. }
  456. }
  457. print "${offset}esac\n";
  458. }
  459. # printref($var,$module,$offset);
  460. } elsif ($module->{kind} == ASK) {
  461. my $default=0;
  462. $default = $module->{default} if exists $module->{default};
  463. #enable the folder display
  464. print "$offset$module->{folder}=1\n";
  465. # and set the default value if none is set.
  466. print "$offset\[ -n \"\$$var\" \] || $var=$default\n";
  467. # if enabled, append pkgsel and force the forced
  468. if (exists $module->{forced}) {
  469. print "\n${offset}if [ \"\$$var\" == 1 ]; then\n";
  470. for ( @{ $module->{forced} } ) {
  471. print "$offset\t$_\n";
  472. print "$offset\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
  473. }
  474. print $offset."fi\n";
  475. }
  476. } else {
  477. # just enable the feature
  478. print "$offset$var=1\n";
  479. # forced list doesn't make sense for {kind} == ALL
  480. }
  481. }
  482. sub render_rules_nomodule {
  483. my ($module,$offset) = @_;
  484. my $var = $module->{var};
  485. # unset the choice list, and the var
  486. if ($module->{kind} == CHOICE) {
  487. my $listvar = "CFGTEMP_$1_LIST" if $var =~ m/^SDECFG_(.*)/i;
  488. print "${offset}unset $listvar\n";
  489. }
  490. print "${offset}unset SDECFGSET_$1\n" if $var =~ m/^SDECFG_(.*)/i;
  491. print "${offset}unset $var\n";
  492. }
  493. sub render_rules {
  494. open(my $FILE,'>',$_[0]);
  495. my $root="CFGTEMP_$_[1]";
  496. select $FILE;
  497. # clean folder enablers
  498. print "#\n# folder enablers\n#\n\n";
  499. for (@$::FOLDERS) { print "$_=\n" unless /^$root$/; }
  500. # pkgsel list
  501. for (@$::MODULES) {
  502. if (exists $::MODULE{$_}) {
  503. my $module = $::MODULE{$_};
  504. print "\n#\n# $module->{var} ("
  505. . ($module->{kind} == ALL ? "ALL" : ($module->{kind} == ASK ? "ASK" : "CHOICE" ) )
  506. . ")\n#\n";
  507. if (exists $module->{deps}) {
  508. print "if [ " . join(' -a ', @{ $module->{deps} } ) . " ]; then\n";
  509. render_rules_module($module,"\t");
  510. print "else\n";
  511. render_rules_nomodule($module,"\t");
  512. print "fi\n";
  513. } else {
  514. render_rules_module($module,"");
  515. }
  516. }
  517. }
  518. print "\n#\n# enable folder with enabled subfolders\n#\n";
  519. for (@$::FOLDERS) {
  520. my $folder = $::FOLDER{$_};
  521. my @subdirs = grep(/^CFGTEMP/,@{$folder->{children}});
  522. if ( @subdirs ) {
  523. print "if [ -n \"\$".join('$', @subdirs )."\" ]; then\n";
  524. print "\t$folder->{var}=1\n";
  525. print "fi\n";
  526. }
  527. }
  528. select STDOUT;
  529. close($FILE);
  530. }
  531. # print the content of a hash
  532. sub printref {
  533. my ($name,$ref,$offset) = @_;
  534. my $typeof = ref($ref);
  535. print "$offset$name:";
  536. if ($typeof eq '') {
  537. print " '$ref'\n";
  538. } elsif ($typeof eq 'HASH') {
  539. print "\n";
  540. for (sort keys %{ $ref }) {
  541. printref($_,$ref->{$_},"$offset\t");
  542. }
  543. } elsif ($typeof eq 'ARRAY') {
  544. my $i=0;
  545. print "\n";
  546. for (@{ $ref }) {
  547. printref("[$i]",$_,"$offset\t");
  548. $i++;
  549. }
  550. } else {
  551. print " -> $typeof\n";
  552. }
  553. }
  554. if ($#ARGV != 4) {
  555. print "Usage mnemosyne.pl: <pkgseldir> <prefix> <configfile> <rulesfile> <awkgenerator>\n";
  556. exit (1);
  557. }
  558. $| = 1;
  559. $::ROOT=$ARGV[0];
  560. scandir($ARGV[0],$ARGV[1]);
  561. process_modules();
  562. process_folders();
  563. render_rules($ARGV[3],$ARGV[1]);
  564. render_widgets($ARGV[2],$ARGV[1]);
  565. render_awkgen($ARGV[4],$ARGV[1]);