Annotation of loncom/build/piml_parse.pl, revision 1.10
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.10 ! harris41 11: # $Id: piml_parse.pl,v 1.2 2002/12/03 22:32:39 sharrison 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.1 harris41 289: };
290:
291: my $text;
292: my $token;
1.6 harris41 293: undef($hloc);
294: undef(@hierarchy);
1.1 harris41 295: my $hloc;
296: my @hierarchy2;
1.10 ! harris41 297: while ($token = $parser->get_tag('piml'))
! 298: {
1.1 harris41 299: &format_piml(@{$token});
300: $text = &trim($parser->get_text('/piml'));
301: $token = $parser->get_tag('/piml');
1.6 harris41 302: print($piml);
303: print("\n");
304: print($text);
305: print("\n");
306: print(&end());
1.10 ! harris41 307: }
1.6 harris41 308: exit(0);
1.1 harris41 309:
310: # ---------- Functions (most all just format contents of different markup tags)
311:
312: # ------------------------ Final output at end of markup parsing and formatting
313: sub end {
1.2 harris41 314:
1.1 harris41 315: }
316:
317: # ----------------------- Take in string to parse and the separation expression
318: sub extract_array {
319: my ($stringtoparse,$sepexp) = @_;
320: my @a=split(/$sepexp/,$stringtoparse);
321: return \@a;
322: }
323:
324: # --------------------------------------------------------- Format piml section
325: sub format_piml {
326: my (@tokeninfo)=@_;
327: my $date=`date`; chop $date;
1.2 harris41 328: $piml=<<END;
329: #!/usr/bin/perl
1.1 harris41 330:
1.2 harris41 331: # Generated from a PIML (Post Installation Markup Language) document
1.1 harris41 332:
333: END
334: }
1.10 ! harris41 335:
1.1 harris41 336: # --------------------------------------------------- Format targetroot section
337: sub format_targetroot {
338: my $text=&trim($parser->get_text('/targetroot'));
339: $text=$targetroot if $targetroot;
340: $parser->get_tag('/targetroot');
1.6 harris41 341: return('# TARGET INSTALL LOCATION is "'.$targetroot."\"\n");
1.2 harris41 342: }
1.10 ! harris41 343:
1.2 harris41 344: # -------------------------------------------------- Format perl script section
345: sub format_perlscript {
346: my (@tokeninfo)=@_;
1.5 harris41 347: $mode=$tokeninfo[2]->{'mode'};
1.2 harris41 348: my $text=$parser->get_text('/perlscript');
349: $parser->get_tag('/perlscript');
1.5 harris41 350: if ($mode eq 'bg') {
1.6 harris41 351: open(OUT,">/tmp/piml$$.pl");
352: print(OUT $text);
353: close(OUT);
354: return(<<END);
1.5 harris41 355: # launch background process for $target
356: system("perl /tmp/piml$$.pl &");
357: END
358: }
359: else {
1.6 harris41 360: return($text);
1.5 harris41 361: }
1.1 harris41 362: }
1.10 ! harris41 363:
1.2 harris41 364: # --------------------------------------------------------------- Format TARGET
365: sub format_TARGET {
366: my (@tokeninfo)=@_;
367: $parser->get_tag('/TARGET');
1.6 harris41 368: return($target);
1.1 harris41 369: }
1.10 ! harris41 370:
1.1 harris41 371: # --------------------------------------------------- Format categories section
372: sub format_categories {
373: my $text=&trim($parser->get_text('/categories'));
374: $parser->get_tag('/categories');
1.6 harris41 375: return('# CATEGORIES'."\n".$text);
1.1 harris41 376: }
1.10 ! harris41 377:
1.1 harris41 378: # --------------------------------------------------- Format categories section
379: sub format_category {
380: my (@tokeninfo)=@_;
381: $category_att_name=$tokeninfo[2]->{'name'};
382: $category_att_type=$tokeninfo[2]->{'type'};
383: $abbreviation=''; $chmod='';$chown='';
384: $parser->get_text('/category');
385: $parser->get_tag('/category');
386: $fab{$category_att_name}=$abbreviation;
1.2 harris41 387: if ($category_att_type eq $categorytype) {
388: my ($user,$group)=split(/\:/,$chown);
389: $categoryhash{$category_att_name}='-o '.$user.' -g '.$group.
390: ' -m '.$chmod;
1.1 harris41 391: }
1.6 harris41 392: return('');
1.1 harris41 393: }
1.10 ! harris41 394:
1.1 harris41 395: # --------------------------------------------------- Format categories section
396: sub format_abbreviation {
397: my @tokeninfo=@_;
398: $abbreviation='';
399: my $text=&trim($parser->get_text('/abbreviation'));
400: if ($text) {
401: $parser->get_tag('/abbreviation');
402: $abbreviation=$text;
403: }
1.6 harris41 404: return('');
1.1 harris41 405: }
1.10 ! harris41 406:
1.1 harris41 407: # -------------------------------------------------------- Format chown section
408: sub format_chown {
409: my @tokeninfo=@_;
410: $chown='';
411: my $text=&trim($parser->get_text('/chown'));
412: if ($text) {
413: $parser->get_tag('/chown');
414: $chown=$text;
415: }
1.6 harris41 416: return('');
1.1 harris41 417: }
1.10 ! harris41 418:
1.1 harris41 419: # -------------------------------------------------------- Format chmod section
420: sub format_chmod {
421: my @tokeninfo=@_;
422: $chmod='';
423: my $text=&trim($parser->get_text('/chmod'));
424: if ($text) {
425: $parser->get_tag('/chmod');
426: $chmod=$text;
427: }
1.6 harris41 428: return('');
1.1 harris41 429: }
1.10 ! harris41 430:
1.1 harris41 431: # ------------------------------------------------- Format categoryname section
432: sub format_categoryname {
433: my @tokeninfo=@_;
434: $categoryname='';
435: my $text=&trim($parser->get_text('/categoryname'));
436: if ($text) {
437: $parser->get_tag('/categoryname');
438: $categoryname=$text;
439: }
1.6 harris41 440: return('');
1.1 harris41 441: }
1.10 ! harris41 442:
1.1 harris41 443: # -------------------------------------------------------- Format files section
444: sub format_files {
445: my $text=$parser->get_text('/files');
446: $parser->get_tag('/files');
1.6 harris41 447: return("\n".'# There are '.$file_count.' files this script works on'.
448: "\n\n".$text);
1.1 harris41 449: }
1.10 ! harris41 450:
1.1 harris41 451: # --------------------------------------------------------- Format file section
452: sub format_file {
453: my @tokeninfo=@_;
454: $file=''; $source=''; $target=''; $categoryname=''; $description='';
455: $note=''; $build=''; $status=''; $dependencies='';
456: my $text=&trim($parser->get_text('/file'));
457: $file_count++;
458: $categorycount{$categoryname}++;
1.2 harris41 459: $parser->get_tag('/file');
1.6 harris41 460: return("# File: $target\n".
461: "$text\n");
1.1 harris41 462: }
1.10 ! harris41 463:
1.1 harris41 464: # ------------------------------------------------------- Format target section
465: sub format_target {
466: my @tokeninfo=@_;
467: $target='';
468: my $text=&trim($parser->get_text('/target'));
469: if ($text) {
470: $parser->get_tag('/target');
1.2 harris41 471: $target=$targetrootarg.$text;
1.1 harris41 472: }
1.6 harris41 473: return('');
1.1 harris41 474: }
1.10 ! harris41 475:
1.1 harris41 476: # --------------------------------------------------------- Format note section
477: sub format_note {
478: my @tokeninfo=@_;
479: $note='';
480: my $aref;
481: my $text;
482: while ($aref=$parser->get_token()) {
483: if ($aref->[0] eq 'E' && $aref->[1] eq 'note') {
484: last;
485: }
486: elsif ($aref->[0] eq 'S') {
487: $text.=$aref->[4];
488: }
489: elsif ($aref->[0] eq 'E') {
490: $text.=$aref->[2];
491: }
492: else {
493: $text.=$aref->[1];
494: }
495: }
496: if ($text) {
497: $note=$text;
498: }
1.6 harris41 499: return('');
1.1 harris41 500: }
1.10 ! harris41 501:
1.1 harris41 502: # ------------------------------------------------- Format dependencies section
503: sub format_dependencies {
504: my @tokeninfo=@_;
505: $dependencies='';
506: my $text=&trim($parser->get_text('/dependencies'));
507: if ($text) {
508: $parser->get_tag('/dependencies');
509: $dependencies=join(';',
510: (map {s/^\s*//;s/\s$//;$_} split(/\;/,$text)));
511: }
1.6 harris41 512: return('');
1.1 harris41 513: }
1.10 ! harris41 514:
1.1 harris41 515: # ------------------------------------------------ Format specialnotice section
516: sub format_specialnotices {
517: $parser->get_tag('/specialnotices');
1.6 harris41 518: return('');
1.1 harris41 519: }
1.10 ! harris41 520:
1.1 harris41 521: # ------------------------------------------------ Format specialnotice section
522: sub format_specialnotice {
523: $parser->get_tag('/specialnotice');
1.6 harris41 524: return('');
1.1 harris41 525: }
1.10 ! harris41 526:
1.1 harris41 527: # ------------------------------------- Render less-than and greater-than signs
528: sub htmlsafe {
529: my $text=@_[0];
530: $text =~ s/</</g;
531: $text =~ s/>/>/g;
1.6 harris41 532: return($text);
1.1 harris41 533: }
1.10 ! harris41 534:
1.1 harris41 535: # --------------------------------------- remove starting and ending whitespace
536: sub trim {
1.6 harris41 537: my ($s)=@_; $s=~s/^\s*//; $s=~s/\s*$//; return($s);
538: }
1.1 harris41 539:
540: # ----------------------------------- POD (plain old documentation, CPAN style)
541:
1.6 harris41 542: =pod
543:
1.1 harris41 544: =head1 NAME
545:
1.10 ! harris41 546: piml_parse.pl - This is meant to parse files meeting the piml document type.
! 547: See piml.dtd. PIML=Post Installation Markup Language.
1.1 harris41 548:
549: =head1 SYNOPSIS
550:
551: Usage is for piml file to come in through standard input.
552:
553: =over 4
554:
555: =item *
556:
1.2 harris41 557: 1st argument is the category permissions to use (runtime or development)
1.1 harris41 558:
559: =item *
560:
1.2 harris41 561: 2nd argument is the distribution
1.10 ! harris41 562: (default,redhat6,debian2.2,redhat7,etc).
1.1 harris41 563:
564: =item *
565:
1.2 harris41 566: 3rd argument is to manually specify a targetroot.
1.1 harris41 567:
568: =back
569:
570: Only the 1st argument is mandatory for the program to run.
571:
572: Example:
573:
574: cat ../../doc/loncapafiles.piml |\\
1.10 ! harris41 575: perl piml_parse.pl development default /home/sherbert/loncapa
1.1 harris41 576:
577: =head1 DESCRIPTION
578:
579: I am using a multiple pass-through approach to parsing
580: the piml file. This saves memory and makes sure the server
581: will never be overloaded.
582:
583: =head1 README
584:
585: I am using a multiple pass-through approach to parsing
586: the piml file. This saves memory and makes sure the server
587: will never be overloaded.
588:
589: =head1 PREREQUISITES
590:
591: HTML::TokeParser
592:
593: =head1 COREQUISITES
594:
595: =head1 OSNAMES
596:
597: linux
598:
599: =head1 SCRIPT CATEGORIES
600:
601: Packaging/Administrative
1.6 harris41 602:
603: =head1 AUTHOR
604:
605: Scott Harrison
1.10 ! harris41 606: sharrison@users.sourceforge.net
1.6 harris41 607:
608: Please let me know how/if you are finding this script useful and
609: any/all suggestions. -Scott
1.1 harris41 610:
611: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>