Annotation of loncom/build/piml_parse.pl, revision 1.11
1.1 harris41 1: #!/usr/bin/perl
2:
1.6 harris41 3: # -------------------------------------------------------- Documentation notice
1.10 harris41 4: # Run "perldoc ./piml_parse.pl" in order to best view the software
1.6 harris41 5: # documentation internalized in this program.
6:
7: # --------------------------------------------------------- License Information
1.1 harris41 8: # The LearningOnline Network with CAPA
9: # piml_parse.pl - Linux Packaging Markup Language parser
10: #
1.11 ! albertel 11: # $Id: piml_parse.pl,v 1.10 2002/12/03 22:36:32 harris41 Exp $
1.1 harris41 12: #
1.6 harris41 13: # Written by Scott Harrison, codeharrison@yahoo.com
1.1 harris41 14: #
15: # Copyright Michigan State University Board of Trustees
16: #
17: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
18: #
19: # LON-CAPA is free software; you can redistribute it and/or modify
20: # it under the terms of the GNU General Public License as published by
21: # the Free Software Foundation; either version 2 of the License, or
22: # (at your option) any later version.
23: #
24: # LON-CAPA is distributed in the hope that it will be useful,
25: # but WITHOUT ANY WARRANTY; without even the implied warranty of
26: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27: # GNU General Public License for more details.
28: #
29: # You should have received a copy of the GNU General Public License
30: # along with LON-CAPA; if not, write to the Free Software
31: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32: #
33: # /home/httpd/html/adm/gpl.txt
34: #
35: # http://www.lon-capa.org/
36: #
37: # YEAR=2002
1.6 harris41 38: # 1/28,1/29,1/30,1/31,2/5,4/8 - Scott Harrison
1.1 harris41 39: #
40: ###
41:
42: ###############################################################################
43: ## ##
44: ## ORGANIZATION OF THIS PERL SCRIPT ##
45: ## 1. Notes ##
46: ## 2. Get command line arguments ##
47: ## 3. First pass through (grab distribution-specific information) ##
48: ## 4. Second pass through (parse out what is not necessary) ##
49: ## 5. Third pass through (translate markup according to specified mode) ##
50: ## 6. Functions (most all just format contents of different markup tags) ##
51: ## 7. POD (plain old documentation, CPAN style) ##
52: ## ##
53: ###############################################################################
54:
55: # ----------------------------------------------------------------------- Notes
56: #
57: # I am using a multiple pass-through approach to parsing
58: # the piml file. This saves memory and makes sure the server
59: # will never be overloaded.
60: #
61: # This is meant to parse files meeting the piml document type.
62: # See piml.dtd. PIML=Post Installation Markup Language.
63:
1.10 harris41 64: # To reduce system dependencies, I'm using a lightweight
65: # parser. At some point, I need to get serious with a
66: # better xml parsing engine and stylesheet usage.
1.1 harris41 67: use HTML::TokeParser;
68:
1.6 harris41 69: my $usage=(<<END);
1.1 harris41 70: **** ERROR ERROR ERROR ERROR ****
71: Usage is for piml file to come in through standard input.
1.9 harris41 72: 1st argument is the category permissions to use (runtime or development)
1.10 harris41 73: 2nd argument is the distribution (default,redhat6,debian2.2,redhat7,etc).
1.9 harris41 74: 3rd argument is to manually specify a targetroot
1.1 harris41 75:
1.9 harris41 76: Only the 1st argument is mandatory for the program to run.
1.1 harris41 77:
78: Example:
79:
1.10 harris41 80: cat ../../doc/sanitycheck.piml |\\
81: perl piml_parse.pl development default /home/sherbert/loncapa
1.1 harris41 82: END
83:
84: # ------------------------------------------------- Grab command line arguments
85:
1.10 harris41 86: # If number of arguments is incorrect, then give up and print usage message.
87: unless (@ARGV == 3)
88: {
89: @ARGV=();shift(@ARGV);
1.1 harris41 90: while(<>){} # throw away the input to avoid broken pipes
1.10 harris41 91: print($usage); # print usage message
1.1 harris41 92: exit -1; # exit with error status
1.10 harris41 93: }
1.1 harris41 94:
95: my $categorytype;
1.10 harris41 96: if (@ARGV)
97: {
98: $categorytype = shift(@ARGV);
99: }
1.1 harris41 100:
101: my $dist;
1.10 harris41 102: if (@ARGV)
103: {
104: $dist = shift(@ARGV);
105: }
1.1 harris41 106:
107: my $targetroot;
108: my $targetrootarg;
1.10 harris41 109: if (@ARGV)
110: {
111: $targetroot = shift(@ARGV);
112: }
113:
1.1 harris41 114: $targetroot=~s/\/$//;
115: $targetrootarg=$targetroot;
116:
117: my $logcmd='| tee -a WARNINGS';
118:
119: my $invocation;
120: # --------------------------------------------------- Record program invocation
1.10 harris41 121: if ($mode eq 'install' or $mode eq 'configinstall' or $mode eq 'build')
122: {
1.1 harris41 123: $invocation=(<<END);
124: # Invocation: STDINPUT | piml_parse.pl
1.2 harris41 125: # 1st argument (category type) is: $categorytype
126: # 2nd argument (distribution) is: $dist
127: # 3rd argument (targetroot) is: described below
1.1 harris41 128: END
1.10 harris41 129: }
1.1 harris41 130:
131: # ---------------------------------------------------- Start first pass through
132: my @parsecontents = <>;
133: my $parsestring = join('',@parsecontents);
1.6 harris41 134: my $outstring='';
1.1 harris41 135:
136: # Need to make a pass through and figure out what defaults are
137: # overrided. Top-down overriding strategy (leaves don't know
138: # about distant leaves).
139:
140: my @hierarchy;
141: $hierarchy[0]=0;
142: my $hloc=0;
1.6 harris41 143: my $token='';
1.1 harris41 144: $parser = HTML::TokeParser->new(\$parsestring) or
145: die('can\'t create TokeParser object');
146: $parser->xml_mode('1');
147: my %hash;
148: my $key;
1.10 harris41 149: while ($token = $parser->get_token())
150: {
151: if ($token->[0] eq 'S')
152: {
1.1 harris41 153: $hloc++;
154: $hierarchy[$hloc]++;
155: $key=$token->[1].join(',',@hierarchy[0..($hloc-1)]);
156: my $thisdist=' '.$token->[2]{'dist'}.' ';
1.10 harris41 157: if ($thisdist eq ' default ')
158: {
1.1 harris41 159: $hash{$key}=1; # there is a default setting for this key
1.10 harris41 160: }
161: elsif ($dist && $hash{$key}==1 && $thisdist=~/\s$dist\s/)
162: {
1.1 harris41 163: $hash{$key}=2; # disregard default setting for this key if
164: # there is a directly requested distribution match
1.10 harris41 165: }
166: }
167: if ($token->[0] eq 'E')
168: {
1.1 harris41 169: $hloc--;
1.10 harris41 170: }
171: }
1.1 harris41 172:
173: # --------------------------------------------------- Start second pass through
174: undef $hloc;
175: undef @hierarchy;
176: undef $parser;
177: $hierarchy[0]=0;
178: $parser = HTML::TokeParser->new(\$parsestring) or
179: die('can\'t create TokeParser object');
180: $parser->xml_mode('1');
181: my $cleanstring;
182: while ($token = $parser->get_token()) {
183: if ($token->[0] eq 'S') {
184: $hloc++;
185: $hierarchy[$hloc]++;
186: $key=$token->[1].join(',',@hierarchy[0..($hloc-1)]);
187: my $thisdist=' '.$token->[2]{'dist'}.' ';
188: # This conditional clause is set up to ignore two sets
189: # of invalid conditions before accepting entry into
190: # the cleanstring.
191: if ($hash{$key}==2 and
192: !($thisdist eq ' ' or $thisdist =~/\s$dist\s/)) {
193: if ($token->[4]!~/\/>$/) {
194: $parser->get_tag('/'.$token->[1]);
195: $hloc--;
196: }
197: }
198: elsif ($thisdist ne ' ' and $thisdist!~/\s$dist\s/ and
199: !($thisdist eq ' default ' and $hash{$key}!=2)) {
200: if ($token->[4]!~/\/>$/) {
201: $parser->get_tag('/'.$token->[1]);
202: $hloc--;
203: }
204: }
205: else {
206: $cleanstring.=$token->[4];
207: }
208: if ($token->[4]=~/\/>$/) {
1.4 harris41 209: # $hloc--;
1.1 harris41 210: }
211: }
212: if ($token->[0] eq 'E') {
213: $cleanstring.=$token->[2];
214: $hloc--;
215: }
216: if ($token->[0] eq 'T') {
217: $cleanstring.=$token->[1];
218: }
219: }
220: $cleanstring=&trim($cleanstring);
221: $cleanstring=~s/\>\s*\n\s*\</\>\</g;
222:
223: # ---------------------------------------------------- Start final pass through
224:
225: # storage variables
226: my $piml;
227: my $categories;
228: my @categorynamelist;
229: my $category;
230: my $category_att_name;
231: my $category_att_type;
232: my $chown;
233: my $chmod;
234: my $abbreviation; # space-free abbreviation; esp. for image names
235: my $categoryname;
236: my $description;
237: my $files;
238: my $file;
239: my $target;
240: my $note;
241: my $commands;
242: my $command;
243: my $dependencies;
244: my @links;
245: my %categoryhash;
246: my $dpathlength;
247: my %fab; # file category abbreviation
248: my $directory_count;
249: my $file_count;
250: my $link_count;
251: my $fileglob_count;
252: my $fileglobnames_count;
253: my %categorycount;
254:
1.4 harris41 255: my $mode;
256:
1.1 harris41 257: my @buildall;
258: my @buildinfo;
259:
260: my @configall;
261:
262: # Make new parser with distribution specific input
1.6 harris41 263: undef($parser);
1.1 harris41 264: $parser = HTML::TokeParser->new(\$cleanstring) or
265: die('can\'t create TokeParser object');
266: $parser->xml_mode('1');
267:
268: # Define handling methods for mode-dependent text rendering
269:
270: $parser->{textify}={
271: specialnotices => \&format_specialnotices,
272: specialnotice => \&format_specialnotice,
273: targetroot => \&format_targetroot,
274: categories => \&format_categories,
275: category => \&format_category,
276: abbreviation => \&format_abbreviation,
277: chown => \&format_chown,
278: chmod => \&format_chmod,
279: categoryname => \&format_categoryname,
280: files => \&format_files,
281: file => \&format_file,
282: target => \&format_target,
283: note => \&format_note,
284: build => \&format_build,
285: dependencies => \&format_dependencies,
286: filenames => \&format_filenames,
1.2 harris41 287: perlscript => \&format_perlscript,
288: TARGET => \&format_TARGET,
1.11 ! albertel 289: DIST => \&format_DIST,
1.1 harris41 290: };
291:
292: my $text;
293: my $token;
1.6 harris41 294: undef($hloc);
295: undef(@hierarchy);
1.1 harris41 296: my $hloc;
297: my @hierarchy2;
1.10 harris41 298: while ($token = $parser->get_tag('piml'))
299: {
1.1 harris41 300: &format_piml(@{$token});
301: $text = &trim($parser->get_text('/piml'));
302: $token = $parser->get_tag('/piml');
1.6 harris41 303: print($piml);
304: print("\n");
305: print($text);
306: print("\n");
307: print(&end());
1.10 harris41 308: }
1.6 harris41 309: exit(0);
1.1 harris41 310:
311: # ---------- Functions (most all just format contents of different markup tags)
312:
313: # ------------------------ Final output at end of markup parsing and formatting
314: sub end {
1.2 harris41 315:
1.1 harris41 316: }
317:
318: # ----------------------- Take in string to parse and the separation expression
319: sub extract_array {
320: my ($stringtoparse,$sepexp) = @_;
321: my @a=split(/$sepexp/,$stringtoparse);
322: return \@a;
323: }
324:
325: # --------------------------------------------------------- Format piml section
326: sub format_piml {
327: my (@tokeninfo)=@_;
328: my $date=`date`; chop $date;
1.2 harris41 329: $piml=<<END;
330: #!/usr/bin/perl
1.1 harris41 331:
1.2 harris41 332: # Generated from a PIML (Post Installation Markup Language) document
1.1 harris41 333:
334: END
335: }
1.10 harris41 336:
1.1 harris41 337: # --------------------------------------------------- Format targetroot section
338: sub format_targetroot {
339: my $text=&trim($parser->get_text('/targetroot'));
340: $text=$targetroot if $targetroot;
341: $parser->get_tag('/targetroot');
1.6 harris41 342: return('# TARGET INSTALL LOCATION is "'.$targetroot."\"\n");
1.2 harris41 343: }
1.10 harris41 344:
1.2 harris41 345: # -------------------------------------------------- Format perl script section
346: sub format_perlscript {
347: my (@tokeninfo)=@_;
1.5 harris41 348: $mode=$tokeninfo[2]->{'mode'};
1.2 harris41 349: my $text=$parser->get_text('/perlscript');
350: $parser->get_tag('/perlscript');
1.5 harris41 351: if ($mode eq 'bg') {
1.6 harris41 352: open(OUT,">/tmp/piml$$.pl");
353: print(OUT $text);
354: close(OUT);
355: return(<<END);
1.5 harris41 356: # launch background process for $target
357: system("perl /tmp/piml$$.pl &");
358: END
359: }
360: else {
1.6 harris41 361: return($text);
1.5 harris41 362: }
1.1 harris41 363: }
1.10 harris41 364:
1.2 harris41 365: # --------------------------------------------------------------- Format TARGET
366: sub format_TARGET {
367: my (@tokeninfo)=@_;
368: $parser->get_tag('/TARGET');
1.6 harris41 369: return($target);
1.1 harris41 370: }
1.10 harris41 371:
1.11 ! albertel 372: # ----------------------------------------------------------------- Format DIST
! 373: sub format_DIST {
! 374: my (@tokeninfo)=@_;
! 375: $parser->get_tag('/DIST');
! 376: return($dist);
! 377: }
! 378:
1.1 harris41 379: # --------------------------------------------------- Format categories section
380: sub format_categories {
381: my $text=&trim($parser->get_text('/categories'));
382: $parser->get_tag('/categories');
1.6 harris41 383: return('# CATEGORIES'."\n".$text);
1.1 harris41 384: }
1.10 harris41 385:
1.1 harris41 386: # --------------------------------------------------- Format categories section
387: sub format_category {
388: my (@tokeninfo)=@_;
389: $category_att_name=$tokeninfo[2]->{'name'};
390: $category_att_type=$tokeninfo[2]->{'type'};
391: $abbreviation=''; $chmod='';$chown='';
392: $parser->get_text('/category');
393: $parser->get_tag('/category');
394: $fab{$category_att_name}=$abbreviation;
1.2 harris41 395: if ($category_att_type eq $categorytype) {
396: my ($user,$group)=split(/\:/,$chown);
397: $categoryhash{$category_att_name}='-o '.$user.' -g '.$group.
398: ' -m '.$chmod;
1.1 harris41 399: }
1.6 harris41 400: return('');
1.1 harris41 401: }
1.10 harris41 402:
1.1 harris41 403: # --------------------------------------------------- Format categories section
404: sub format_abbreviation {
405: my @tokeninfo=@_;
406: $abbreviation='';
407: my $text=&trim($parser->get_text('/abbreviation'));
408: if ($text) {
409: $parser->get_tag('/abbreviation');
410: $abbreviation=$text;
411: }
1.6 harris41 412: return('');
1.1 harris41 413: }
1.10 harris41 414:
1.1 harris41 415: # -------------------------------------------------------- Format chown section
416: sub format_chown {
417: my @tokeninfo=@_;
418: $chown='';
419: my $text=&trim($parser->get_text('/chown'));
420: if ($text) {
421: $parser->get_tag('/chown');
422: $chown=$text;
423: }
1.6 harris41 424: return('');
1.1 harris41 425: }
1.10 harris41 426:
1.1 harris41 427: # -------------------------------------------------------- Format chmod section
428: sub format_chmod {
429: my @tokeninfo=@_;
430: $chmod='';
431: my $text=&trim($parser->get_text('/chmod'));
432: if ($text) {
433: $parser->get_tag('/chmod');
434: $chmod=$text;
435: }
1.6 harris41 436: return('');
1.1 harris41 437: }
1.10 harris41 438:
1.1 harris41 439: # ------------------------------------------------- Format categoryname section
440: sub format_categoryname {
441: my @tokeninfo=@_;
442: $categoryname='';
443: my $text=&trim($parser->get_text('/categoryname'));
444: if ($text) {
445: $parser->get_tag('/categoryname');
446: $categoryname=$text;
447: }
1.6 harris41 448: return('');
1.1 harris41 449: }
1.10 harris41 450:
1.1 harris41 451: # -------------------------------------------------------- Format files section
452: sub format_files {
453: my $text=$parser->get_text('/files');
454: $parser->get_tag('/files');
1.6 harris41 455: return("\n".'# There are '.$file_count.' files this script works on'.
456: "\n\n".$text);
1.1 harris41 457: }
1.10 harris41 458:
1.1 harris41 459: # --------------------------------------------------------- Format file section
460: sub format_file {
461: my @tokeninfo=@_;
462: $file=''; $source=''; $target=''; $categoryname=''; $description='';
463: $note=''; $build=''; $status=''; $dependencies='';
464: my $text=&trim($parser->get_text('/file'));
465: $file_count++;
466: $categorycount{$categoryname}++;
1.2 harris41 467: $parser->get_tag('/file');
1.6 harris41 468: return("# File: $target\n".
469: "$text\n");
1.1 harris41 470: }
1.10 harris41 471:
1.1 harris41 472: # ------------------------------------------------------- Format target section
473: sub format_target {
474: my @tokeninfo=@_;
475: $target='';
476: my $text=&trim($parser->get_text('/target'));
477: if ($text) {
478: $parser->get_tag('/target');
1.2 harris41 479: $target=$targetrootarg.$text;
1.1 harris41 480: }
1.6 harris41 481: return('');
1.1 harris41 482: }
1.10 harris41 483:
1.1 harris41 484: # --------------------------------------------------------- Format note section
485: sub format_note {
486: my @tokeninfo=@_;
487: $note='';
488: my $aref;
489: my $text;
490: while ($aref=$parser->get_token()) {
491: if ($aref->[0] eq 'E' && $aref->[1] eq 'note') {
492: last;
493: }
494: elsif ($aref->[0] eq 'S') {
495: $text.=$aref->[4];
496: }
497: elsif ($aref->[0] eq 'E') {
498: $text.=$aref->[2];
499: }
500: else {
501: $text.=$aref->[1];
502: }
503: }
504: if ($text) {
505: $note=$text;
506: }
1.6 harris41 507: return('');
1.1 harris41 508: }
1.10 harris41 509:
1.1 harris41 510: # ------------------------------------------------- Format dependencies section
511: sub format_dependencies {
512: my @tokeninfo=@_;
513: $dependencies='';
514: my $text=&trim($parser->get_text('/dependencies'));
515: if ($text) {
516: $parser->get_tag('/dependencies');
517: $dependencies=join(';',
518: (map {s/^\s*//;s/\s$//;$_} split(/\;/,$text)));
519: }
1.6 harris41 520: return('');
1.1 harris41 521: }
1.10 harris41 522:
1.1 harris41 523: # ------------------------------------------------ Format specialnotice section
524: sub format_specialnotices {
525: $parser->get_tag('/specialnotices');
1.6 harris41 526: return('');
1.1 harris41 527: }
1.10 harris41 528:
1.1 harris41 529: # ------------------------------------------------ Format specialnotice section
530: sub format_specialnotice {
531: $parser->get_tag('/specialnotice');
1.6 harris41 532: return('');
1.1 harris41 533: }
1.10 harris41 534:
1.1 harris41 535: # ------------------------------------- Render less-than and greater-than signs
536: sub htmlsafe {
537: my $text=@_[0];
538: $text =~ s/</</g;
539: $text =~ s/>/>/g;
1.6 harris41 540: return($text);
1.1 harris41 541: }
1.10 harris41 542:
1.1 harris41 543: # --------------------------------------- remove starting and ending whitespace
544: sub trim {
1.6 harris41 545: my ($s)=@_; $s=~s/^\s*//; $s=~s/\s*$//; return($s);
546: }
1.1 harris41 547:
548: # ----------------------------------- POD (plain old documentation, CPAN style)
549:
1.6 harris41 550: =pod
551:
1.1 harris41 552: =head1 NAME
553:
1.10 harris41 554: piml_parse.pl - This is meant to parse files meeting the piml document type.
555: See piml.dtd. PIML=Post Installation Markup Language.
1.1 harris41 556:
557: =head1 SYNOPSIS
558:
559: Usage is for piml file to come in through standard input.
560:
561: =over 4
562:
563: =item *
564:
1.2 harris41 565: 1st argument is the category permissions to use (runtime or development)
1.1 harris41 566:
567: =item *
568:
1.2 harris41 569: 2nd argument is the distribution
1.10 harris41 570: (default,redhat6,debian2.2,redhat7,etc).
1.1 harris41 571:
572: =item *
573:
1.2 harris41 574: 3rd argument is to manually specify a targetroot.
1.1 harris41 575:
576: =back
577:
578: Only the 1st argument is mandatory for the program to run.
579:
580: Example:
581:
582: cat ../../doc/loncapafiles.piml |\\
1.10 harris41 583: perl piml_parse.pl development default /home/sherbert/loncapa
1.1 harris41 584:
585: =head1 DESCRIPTION
586:
587: I am using a multiple pass-through approach to parsing
588: the piml file. This saves memory and makes sure the server
589: will never be overloaded.
590:
591: =head1 README
592:
593: I am using a multiple pass-through approach to parsing
594: the piml file. This saves memory and makes sure the server
595: will never be overloaded.
596:
597: =head1 PREREQUISITES
598:
599: HTML::TokeParser
600:
601: =head1 COREQUISITES
602:
603: =head1 OSNAMES
604:
605: linux
606:
607: =head1 SCRIPT CATEGORIES
608:
609: Packaging/Administrative
1.6 harris41 610:
611: =head1 AUTHOR
612:
613: Scott Harrison
1.10 harris41 614: sharrison@users.sourceforge.net
1.6 harris41 615:
616: Please let me know how/if you are finding this script useful and
617: any/all suggestions. -Scott
1.1 harris41 618:
619: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>