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. # --- 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 - 2006 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. $pid = open2($READ, $WRITE, 'tsort');
  177. # prepare topographic modules map
  178. for my $module (values %::MODULE) {
  179. my $related;
  180. if ($module->{kind} == CHOICE) {
  181. for (@{ $module->{options} }) {
  182. my $option = $_;
  183. for (@{exists $option->{deps} ? $option->{deps} : []} ) {
  184. my $dep = (m/"\$([^"]+)"/i)[0];
  185. print $WRITE "$dep $module->{var}\n";
  186. $related=1;
  187. }
  188. for (@{exists $option->{forced} ? $option->{forced} : []} ) {
  189. my $forced = (m/([^"]+)=/i)[0];
  190. print $WRITE "$module->{var} $forced\n";
  191. $related=1;
  192. }
  193. }
  194. } else {
  195. for (@{exists $module->{deps} ? $module->{deps} : []} ) {
  196. my $dep = (m/"\$([^"]+)"/i)[0];
  197. print $WRITE "$dep $module->{var}\n";
  198. $related=1;
  199. }
  200. for (@{exists $module->{forced} ? $module->{forced} : []} ) {
  201. my $forced = (m/([^"]+)=/i)[0];
  202. print $WRITE "$module->{var} $forced\n";
  203. $related=1;
  204. }
  205. }
  206. if (! $related) {
  207. print $WRITE "$module->{var} $module->{var}\n";
  208. }
  209. }
  210. close($WRITE);
  211. # and populate the sorted list
  212. my @sorted;
  213. while(<$READ>) {
  214. if (/(.*)\n/) { push @sorted, $1; }
  215. }
  216. waitpid $pid,0;
  217. die if $?;
  218. # and remember the sorted list
  219. $::MODULES=\@sorted;
  220. }
  221. sub process_folders {
  222. my ($READ,$WRITE,$pid);
  223. $pid = open2($READ, $WRITE, 'tsort | tac');
  224. # prepare topographic modules map
  225. for my $folder (values %::FOLDER) {
  226. for ( exists $folder->{children} ? grep(!/^SDECFG/, @{$folder->{children}}) : [] ) {
  227. print $WRITE "$folder->{var} $_\n";
  228. }
  229. }
  230. close($WRITE);
  231. # and populate the sorted list
  232. my @sorted;
  233. while(<$READ>) {
  234. if (/(.*)\n/) { push @sorted, $1; }
  235. }
  236. waitpid $pid,0;
  237. die if $?;
  238. # and remember the sorted list
  239. $::FOLDERS=\@sorted;
  240. }
  241. sub render_widgets_folder {
  242. my ($folder,$offset) = @_;
  243. for (@{$folder->{children}}) {
  244. if (/^CFGTEMP/) {
  245. my $subfolder=$::FOLDER{$_};
  246. print "\n${offset}# $_\n${offset}#\n";
  247. # opening
  248. print "${offset}if [ \"\$$subfolder->{var}\" == 1 ]; then\n";
  249. print "${offset}\tcomment '-- $subfolder->{desc}'\n";
  250. print "${offset}\tblock_begin 2\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}\tblock_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}\t. $conffile\n" if $conffile;
  271. print "${offset}fi\n";
  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}\t\[ \"\$$var\" == 1 \] && . $conffile\n" if $conffile;
  279. print "${offset}fi\n";
  280. } elsif ($conffile) {
  281. # ALL, only if $conffile
  282. print "${offset}if \[ -n \"\$$var\" \]; then\n";
  283. print "${offset}\t. $conffile\n" if $conffile;
  284. print "${offset}fi\n";
  285. }
  286. }
  287. }
  288. }
  289. sub render_widgets {
  290. open(my $FILE,'>',$_[0]);
  291. my $root="CFGTEMP_$_[1]";
  292. select $FILE;
  293. render_widgets_folder($::FOLDER{$root},'');
  294. select STDOUT;
  295. close($FILE);
  296. }
  297. sub pkgsel_parse {
  298. my ($action,$patternlist) = @_;
  299. if ($action eq 'X' or $action eq 'x' ) {
  300. $action = '$1="X"';
  301. } elsif ($action eq 'O' or $action eq 'o') {
  302. $action = '$1="O"';
  303. } elsif ($action eq '-') {
  304. $action = 'next';
  305. } else {
  306. $action = '{ exit; }';
  307. }
  308. my ($address,$first,$others)= ('','( ','&& ');
  309. for (split(/\s+/,$patternlist)) {
  310. if (! $address and $_ eq '!') {
  311. $address = '! ';
  312. $others = '|| $4"/"$5 ~';
  313. } else {
  314. $_="\*/$_" unless /\//;
  315. s,[^a-zA-Z0-9_/\*+\.-],,g;
  316. s,([/\.\+]),\\$1,g;
  317. s,\*,[^/]*,g;
  318. next unless $_;
  319. $address = "$address$first";
  320. $address = "$address / $_ /";
  321. $first = "$others";
  322. }
  323. =for nobody
  324. [ "$pattern" ] || continue
  325. address="$address$first"
  326. address="$address / $pattern /"
  327. first=" $others"
  328. =cut
  329. }
  330. print "\techo '$address ) { $action; }'\n";
  331. return 1;
  332. }
  333. sub render_awkgen {
  334. open(my $OUTPUT,'>',$_[0]);
  335. my $root="CFGTEMP_$_[1]";
  336. select $OUTPUT;
  337. # initially change packages $4 and $5 to be able to correctly match repo based.
  338. print "echo '{'\n";
  339. print "echo '\trepo=\$4 ;'\n";
  340. print "echo '\tpkg=\$5 ;'\n";
  341. print "echo '\t\$5 = \$4 \"/\" \$5 ;'\n";
  342. print "echo '\t\$4 = \"placeholder\" ;'\n";
  343. print "echo '}'\n";
  344. render_awkgen_folder($::FOLDER{$root});
  345. # ... restore $4 and $5, and print the resulting line
  346. print "echo '\n{'\n";
  347. print "echo '\t\$4=repo ;'\n";
  348. print "echo '\t\$5=pkg ;'\n";
  349. print "echo '\tprint ;'\n";
  350. print "echo '}'\n";
  351. select STDOUT;
  352. close($OUTPUT);
  353. }
  354. sub render_awkgen_folder {
  355. my ($folder) = @_;
  356. for (@{$folder->{children}}) {
  357. if (/^CFGTEMP/) {
  358. render_awkgen_folder($::FOLDER{$_});
  359. } else {
  360. my $module=$::MODULE{$_};
  361. if ($module->{kind} == CHOICE) {
  362. my %options;
  363. # the list of options
  364. for (@{ $module->{options} }) {
  365. my $option = $_;
  366. my @array=("\"\$$module->{var}\" == $_->{option}");
  367. $options{$_->{option}} = \@array;
  368. }
  369. # and their implyed options
  370. for (@{ $module->{options} }) {
  371. my $option = $_;
  372. for (@{exists $option->{imply}? $option->{imply} : [] }) {
  373. push @{$options{$_}},
  374. "\"\$$module->{var}\" == $option->{option}";
  375. }
  376. }
  377. print "\n";
  378. # and finally, render.
  379. for (@{ $module->{options} }) {
  380. print "if [ " . join(' -o ',@{ $options{ $_->{option} }}). " ]; then\n";
  381. open(my $FILE,'<',$_->{file});
  382. my $hasrules=0;
  383. while(<$FILE>) {
  384. next if /^#/;
  385. next if /^\s*$/;
  386. pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
  387. $hasrules=1;
  388. }
  389. close($FILE);
  390. print "\ttrue\n" unless $hasrules;
  391. print "fi\n";
  392. }
  393. } else {
  394. print "\nif [ \"\$$module->{var}\" == 1 ]; then\n";
  395. open(my $FILE,'<',$module->{file});
  396. my $hasrules=0;
  397. while(<$FILE>) {
  398. next if /^#/;
  399. next if /^\s*$/;
  400. pkgsel_parse($1,$2) if m/^([^\s]+)\s+(.*)\s*\n?$/i;
  401. $hasrules=1;
  402. }
  403. close($FILE);
  404. print "\ttrue\n" unless $hasrules;
  405. print "fi\n";
  406. }
  407. }
  408. }
  409. }
  410. sub render_rules_module {
  411. my ($module,$offset) = @_;
  412. my $var = $module->{var};
  413. if ($module->{kind} == CHOICE) {
  414. my $tmpvar = "CFGTEMP_$1" if $var =~ m/^SDECFG_(.*)/i;
  415. my $listvar = "$tmpvar\_LIST";
  416. my $defaultvar = "$tmpvar\_DEFAULT";
  417. my $default = "undefined";
  418. my $forcer;
  419. $default = $module->{default} if exists $module->{default};
  420. # initialize the list
  421. print "${offset}$listvar=\n";
  422. print "${offset}$defaultvar=$default\n";
  423. print "${offset}\[ -n \"\$$var\" \] || $var=$default\n\n";
  424. for ( @{ $module->{options} } ) {
  425. my $option = $_;
  426. (my $desc = $option->{desc}) =~ s/ /_/g;
  427. # has something to force?
  428. if (exists $option->{forced}) { $forcer = 1; }
  429. if (exists $option->{deps}) {
  430. print "${offset}if [ " .
  431. join(' -a ', @{ $option->{deps} } ) .
  432. " ]; then\n";
  433. print "${offset}\t$listvar=\"\$$listvar $option->{option} $desc\"\n";
  434. print "${offset}fi\n";
  435. } else {
  436. print "${offset}$listvar=\"\$$listvar $option->{option} $desc\"\n";
  437. }
  438. }
  439. # enable the folder display
  440. print "${offset}if \[ -n \"\$$listvar\" \]; then\n";
  441. print "${offset}\t$module->{folder}=1\n";
  442. print "${offset}else\n";
  443. print "${offset}\tunset $module->{var}\n";
  444. print "${offset}fi\n";
  445. # has something to force?
  446. if ($forcer) {
  447. print "\n${offset}case \"\$$var\" in\n";
  448. for ( @{ $module->{options} } ) {
  449. my $option = $_;
  450. if (exists $option->{forced}) {
  451. print "${offset}\t$option->{option})\n";
  452. for ( @{ $option->{forced} } ) {
  453. print "$offset\t\t$_\n";
  454. print "$offset\t\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
  455. }
  456. print "${offset}\t\t;;\n";
  457. }
  458. }
  459. print "${offset}esac\n";
  460. }
  461. # printref($var,$module,$offset);
  462. } elsif ($module->{kind} == ASK) {
  463. my $default=0;
  464. $default = $module->{default} if exists $module->{default};
  465. #enable the folder display
  466. print "$offset$module->{folder}=1\n";
  467. # and set the default value if none is set.
  468. print "$offset\[ -n \"\$$var\" \] || $var=$default\n";
  469. # if enabled, append pkgsel and force the forced
  470. if (exists $module->{forced}) {
  471. print "\n${offset}if [ \"\$$var\" == 1 ]; then\n";
  472. for ( @{ $module->{forced} } ) {
  473. print "$offset\t$_\n";
  474. print "$offset\tSDECFGSET_$1\n" if $_ =~ m/^SDECFG_(.*)/i;
  475. }
  476. print $offset."fi\n";
  477. }
  478. } else {
  479. # just enable the feature
  480. print "$offset$var=1\n";
  481. # forced list doesn't make sense for {kind} == ALL
  482. }
  483. }
  484. sub render_rules_nomodule {
  485. my ($module,$offset) = @_;
  486. my $var = $module->{var};
  487. # unset the choice list, and the var
  488. if ($module->{kind} == CHOICE) {
  489. my $listvar = "CFGTEMP_$1_LIST" if $var =~ m/^SDECFG_(.*)/i;
  490. print "${offset}unset $listvar\n";
  491. }
  492. print "${offset}unset SDECFGSET_$1\n" if $var =~ m/^SDECFG_(.*)/i;
  493. print "${offset}unset $var\n";
  494. }
  495. sub render_rules {
  496. open(my $FILE,'>',$_[0]);
  497. my $root="CFGTEMP_$_[1]";
  498. select $FILE;
  499. # clean folder enablers
  500. print "#\n# folder enablers\n#\n\n";
  501. for (@$::FOLDERS) { print "$_=\n" unless /^$root$/; }
  502. # pkgsel list
  503. for (@$::MODULES) {
  504. my $module = $::MODULE{$_};
  505. print "\n#\n# $module->{var} ("
  506. . ($module->{kind} == ALL ? "ALL" : ($module->{kind} == ASK ? "ASK" : "CHOICE" ) )
  507. . ")\n#\n";
  508. if (exists $module->{deps}) {
  509. print "if [ " . join(' -a ', @{ $module->{deps} } ) . " ]; then\n";
  510. render_rules_module($module,"\t");
  511. print "else\n";
  512. render_rules_nomodule($module,"\t");
  513. print "fi\n";
  514. } else {
  515. render_rules_module($module,"");
  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]);