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.

647 lines
16 KiB

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