Annotation of loncom/build/make_rpm.pl, revision 1.15
1.1 harris41 1: #!/usr/bin/perl
2:
1.12 harris41 3: # The LearningOnline Network with CAPA
1.13 harris41 4: # make_rpm.pl - make RedHat package manager file (A CLEAN AND CONFIGURABLE WAY)
1.12 harris41 5: #
1.15 ! harris41 6: # $Id: make_rpm.pl,v 1.14 2002/01/09 22:16:14 harris41 Exp $
1.12 harris41 7: #
8: # Written by Scott Harrison, harris41@msu.edu
9: #
10: # Copyright Michigan State University Board of Trustees
11: #
12: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
13: #
14: # LON-CAPA is free software; you can redistribute it and/or modify
15: # it under the terms of the GNU General Public License as published by
16: # the Free Software Foundation; either version 2 of the License, or
17: # (at your option) any later version.
18: #
19: # LON-CAPA is distributed in the hope that it will be useful,
20: # but WITHOUT ANY WARRANTY; without even the implied warranty of
21: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22: # GNU General Public License for more details.
23: #
24: # You should have received a copy of the GNU General Public License
25: # along with LON-CAPA; if not, write to the Free Software
26: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27: #
28: # http://www.lon-capa.org/
29: #
30: # YEAR=2000
31: # 9/30,10/2,12/11,12/12,12/21 - Scott Harrison
32: # YEAR=2001
33: # 1/8,1/10,1/13,1/23,5/16 - Scott Harrison
34: # YEAR=2002
1.15 ! harris41 35: # 1/4,1/8,1/9,2/13 - Scott Harrison
1.12 harris41 36: #
37: ###
38:
1.15 ! harris41 39: # make_rpm.pl automatically generate RPM software packages
! 40: # from a target image directory and file listing. POD
! 41: # documentation is at the end of this file.
1.1 harris41 42:
1.13 harris41 43: ###############################################################################
44: ## ##
45: ## ORGANIZATION OF THIS PERL SCRIPT ##
46: ## ##
47: ## 1. Check to see if RPM builder application is available ##
48: ## 2. Read in arguments ##
49: ## 3. Generate temporary directories ##
50: ## 4. Initialize some variables ##
51: ## 5. Create a standalone rpm building environment ##
52: ## 6. Perform variable initializations and customizations ##
53: ## 7. Print header information for .spec file ##
54: ## 8. Process file list and generate information ##
55: ## 9. Generate SRPM and BinaryRoot Makefiles ##
56: ## 10. mirror copy (BinaryRoot) files under a temporary directory ##
57: ## 11. roll everything into an rpm ##
58: ## 12. clean everything up ##
1.15 ! harris41 59: ## 13. subroutines ##
! 60: ## 13a. find_info - recursively gather information from a directory ##
! 61: ## 13b. grabtag - grab a tag from an XML string ##
1.13 harris41 62: ## 14. Plain Old Documentation ##
63: ## ##
64: ###############################################################################
65:
66: use strict;
67:
68: # ------------------------ Check to see if RPM builder application is available
69:
70: unless (-e '/usr/lib/rpm/rpmrc') {
1.1 harris41 71: print <<END;
1.12 harris41 72: ERROR: This script only works with a properly installed RPM builder
73: application.
1.1 harris41 74: Cannot find /usr/lib/rpm/rpmrc, so cannot generate customized rpmrc file.
75: Script aborting.
76: END
77: }
78:
1.13 harris41 79: # ----------------------------------------------------------- Read in arguments
80:
81: my ($tag,$version,$configuration_files,$documentation_files,
82: $pathprefix,$customize)=@ARGV;
1.1 harris41 83: @ARGV=();
1.3 harris41 84:
1.1 harris41 85: if (!$version) {
1.13 harris41 86: print <<END;
87: See "perldoc make_rpm.pl" for more information.
88:
1.15 ! harris41 89: Usage:
! 90: <STDIN> | perl make_rpm.pl <TAG> <VERSION> [CONFIGURATION_FILES]
1.13 harris41 91: [DOCUMENTATION_FILES] [PATHPREFIX] [CUSTOMIZATION_XML]
1.15 ! harris41 92:
1.13 harris41 93: Standard input provides the list of files to work with.
94: TAG, required descriptive tag. For example, a kerberos software
95: package might be tagged as "krb4".
96: VERSION, required version. Needed to generate version information
97: for the RPM. This should be in the format N.M where N and M are
98: integers.
99: CONFIGURATION_FILES, optional comma-separated listing of files to
100: be treated as configuration files by RPM (and thus subject to saving
101: during RPM upgrades).
102: DOCUMENTATION_FILES, optional comma-separated listing of files to be
103: treated as documentation files by RPM (and thus subject to being
104: placed in the /usr/doc/RPM-NAME directory during RPM installation).
105: PATHPREFIX, optional path to be removed from file listing. This
106: is in case you are building an RPM from files elsewhere than
107: root-level. Note, this still depends on a root directory hierarchy
108: after PATHPREFIX.
109: CUSTOMIZATION_XML, allows for customizing various pieces of information such
110: as vendor, summary, name, copyright, group, autoreqprov, requires, prereq,
111: description, and pre-installation scripts (see more in the POD;
112: perldoc make_rpml.pl).
113: END
1.1 harris41 114: exit;
115: }
116:
117: mkdir $tag,0755;
118: mkdir "$tag/BuildRoot",0755;
119: mkdir "$tag/SOURCES",0755;
120: mkdir "$tag/SPECS",0755;
121: mkdir "$tag/BUILD",0755;
122: mkdir "$tag/SRPMS",0755;
123: mkdir "$tag/RPMS",0755;
124: mkdir "$tag/RPMS/i386",0755;
125:
1.13 harris41 126: # -------------------------------------------------------- Initialize variables
127:
1.1 harris41 128: my $file;
129: my $binaryroot="$tag/BinaryRoot";
130: my ($type,$size,$octalmode,$user,$group);
131:
1.13 harris41 132: my $currentdir=`pwd`; chop $currentdir; my $invokingdir=$currentdir;
1.12 harris41 133: $currentdir.="/$tag";
1.1 harris41 134:
1.13 harris41 135: # -------------------------------- Create a standalone rpm building environment
136:
137: open (IN,'</usr/lib/rpm/rpmrc') or die('Cannot open /usr/lib/rpm/rpmrc');
138: my @lines=<IN>;
1.1 harris41 139: close IN;
140:
141: open (RPMRC,">$tag/SPECS/rpmrc");
1.13 harris41 142: foreach my $line (@lines) {
1.1 harris41 143: if ($line=~/^macrofiles/) {
144: chop $line;
1.11 harris41 145: $line.=":$currentdir/SPECS/rpmmacros\n";
1.1 harris41 146: }
147: print RPMRC $line;
148: }
149: close RPMRC;
150:
151: open (RPMMACROS,">$tag/SPECS/rpmmacros");
152: print RPMMACROS <<END;
153: \%_topdir $currentdir
154: \%__spec_install_post \\
155: /usr/lib/rpm/brp-strip \\
156: /usr/lib/rpm/brp-strip-comment-note \\
157: \%{nil}
158: END
159: close RPMMACROS;
160:
1.13 harris41 161: # ------------------------- Perform variable initializations and customizations
162:
163: my $cu;
164: if ($customize) {
165: open (IN,"<$customize") or die("Cannot open $customize");
166: my @clines=(<IN>);
167: $cu=join('',@clines);
168: close IN;
169: }
170: my $tv; # tag value variable for storing retrievals from $cu
171:
172: # (Sure. We could use HTML::TokeParser here.. but that wouldn't be fun now,
173: # would it?)
174: my $name=$tag;
175: # read in name from customization if available
176: $tv=grabtag('name',$cu,1); $name=$tv if $tv;
177: $name=~s/\<tag \/\>/$tag/g;
178:
179: # okay.. now we can generate this needed directory
180: mkdir "$tag/SOURCES/$name-$version",0755;
181:
1.7 harris41 182: my $requires="";
1.13 harris41 183: # read in relevant requires info from customization file (if applicable)
184: # note that "PreReq: item" controls order of CD-ROM installation (if you
185: # are making a customized CD-ROM)
186: # "Requires: item" just enforces dependencies from the command-line invocation
187: $tv=grabtag('requires',$cu,1); $requires=$tv if $tv;
188: # do more require processing here
189: $requires=~s/\s*\<\/item\>\s*//g;
190: $requires=~s/\s*\<item\>\s*/\n/g;
191: $requires=~s/^\s+//s;
192:
193: my $summary="Files for the $name software package.";
194: # read in summary from customization if available
195: $tv=grabtag('summary',$cu,1); $summary=$tv if $tv;
196: $summary=~s/\<tag \/\>/$tag/g;
197:
1.14 harris41 198: my $autoreqprov='no';
199: # read in autoreqprov from customization if available
200: $tv=grabtag('autoreqprov',$cu,1); $autoreqprov=$tv if $tv;
201:
1.13 harris41 202: my $copyright="not specified here";
203: # read in copyright from customization if available
204: $tv=grabtag('copyright',$cu,1); $copyright=$tv if $tv;
205: $copyright=~s/\<tag \/\>/$tag/g;
206:
207: open (SPEC,">$tag/SPECS/$name-$version.spec");
208:
209: my $vendor='Me';
210: # read in vendor from customization if available
211: $tv=grabtag('vendor',$cu,1); $vendor=$tv if $tv;
212: $vendor=~s/\<tag \/\>/$tag/g;
213:
214: my $description="$name software package";
215: # read in description from customization if available
216: $tv=grabtag('description',$cu,0); $description=$tv if $tv;
217: $description=~s/\<tag \/\>/$tag/g;
218:
219: my $pre="";
220: # read in pre-installation script if available
221: $tv=grabtag('pre',$cu,0); $pre=$tv if $tv;
222: $pre=~s/\<tag \/\>/$tag/g;
1.1 harris41 223:
1.13 harris41 224: # ------------------------------------- Print header information for .spec file
1.12 harris41 225:
1.1 harris41 226: print SPEC <<END;
1.13 harris41 227: Summary: $summary
228: Name: $name
1.1 harris41 229: Version: $version
230: Release: 1
1.12 harris41 231: Vendor: $vendor
1.1 harris41 232: BuildRoot: $currentdir/BuildRoot
1.13 harris41 233: Copyright: $copyright
1.1 harris41 234: Group: Utilities/System
1.13 harris41 235: Source: $name-$version.tar.gz
1.14 harris41 236: AutoReqProv: $autoreqprov
1.7 harris41 237: $requires
1.1 harris41 238: # requires: filesystem
239: \%description
1.13 harris41 240: $description
1.1 harris41 241:
242: \%prep
243: \%setup
244:
245: \%build
246: rm -Rf "$currentdir/BuildRoot"
247:
248: \%install
249: make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" directories
250: make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" files
251: make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" links
252:
253: \%pre
1.13 harris41 254: $pre
1.1 harris41 255:
256: \%post
257: \%postun
258:
259: \%files
260: END
261:
1.13 harris41 262: # ------------------------------------ Process file list and gather information
263:
264: my %BinaryRootMakefile;
265: my %Makefile;
266: my %dotspecfile;
267:
1.1 harris41 268: foreach $file (<>) {
269: chop $file;
1.4 harris41 270: my $comment="";
271: if ($file=~/\s+\#(.*)$/) {
272: $file=~s/\s+\#(.*)$//;
273: $comment=$1;
274: }
1.13 harris41 275: my $directive="";
276: if ($comment=~/config\(noreplace\)/) {
277: $directive="\%config(noreplace) ";
278: }
279: elsif ($comment=~/config/) {
280: $directive="\%config ";
281: }
282: elsif ($comment=~/doc/) {
283: $directive="\%doc";
1.4 harris41 284: }
1.1 harris41 285: if (($type,$size,$octalmode,$user,$group)=find_info($file)) {
286: $octalmode="0" . $octalmode if length($octalmode)<4;
287: if ($pathprefix) {
288: $file=~s/^$pathprefix//;
289: }
290: if ($type eq "files") {
1.12 harris41 291: push @{$BinaryRootMakefile{$type}},"\tinstall -D -m $octalmode ".
292: "$pathprefix$file $binaryroot$file\n";
293: push @{$Makefile{$type}},"\tinstall -D -m $octalmode ".
294: "\$(SOURCE)$file \$(ROOT)$file\n";
1.13 harris41 295: push @{$dotspecfile{$type}},"$directive\%attr($octalmode,$user,".
1.12 harris41 296: "$group) $file\n";
1.1 harris41 297: }
298: elsif ($type eq "directories") {
1.12 harris41 299: push @{$BinaryRootMakefile{$type}},"\tinstall -m $octalmode -d ".
300: "$binaryroot$file\n";
301: push @{$Makefile{$type}},"\tinstall -m $octalmode -d ".
302: "\$(SOURCE)$file \$(ROOT)$file\n";
303: push @{$dotspecfile{$type}},"\%dir \%attr($octalmode,$user,".
304: "$group) $file\n";
1.1 harris41 305: }
306: elsif ($type eq "links") {
1.12 harris41 307: my $link=$size; # I use the size variable to pass the link value
308: # from the subroutine find_info
1.1 harris41 309: $link=~s/^$pathprefix//;
1.12 harris41 310: push @{$BinaryRootMakefile{$type}},
311: "\tln -s $link $binaryroot$file\n";
1.1 harris41 312: push @{$Makefile{$type}},"\tln -s $link \$(ROOT)$file\n";
313: push @{$dotspecfile{$type}},"\%attr(-,$user,$group) $file\n";
314: }
315: }
316: }
317:
1.13 harris41 318: # -------------------------------------- Generate SRPM and BinaryRoot Makefiles
319:
320: open OUTS, ">$tag/SOURCES/$name-$version/Makefile";
321: open OUTB, ">$tag/BinaryRootMakefile";
1.1 harris41 322: foreach $type ("directories","files","links") {
1.13 harris41 323: print OUTS "$type\:\n";
324: print OUTS join("",@{$Makefile{$type}}) if $Makefile{$type};
325: print OUTS "\n";
326: print OUTB "$type\:\n";
327: print OUTB join("",@{$BinaryRootMakefile{$type}})
328: if $BinaryRootMakefile{$type};
329: print OUTB "\n";
330: print SPEC join("",@{$dotspecfile{$type}}) if $dotspecfile{$type};
1.1 harris41 331: }
1.13 harris41 332: close OUTB;
333: close OUTS;
1.1 harris41 334:
1.13 harris41 335: close SPEC;
1.1 harris41 336:
1.13 harris41 337: # ------------------ mirror copy (BinaryRoot) files under a temporary directory
1.1 harris41 338:
339: `make -f $tag/BinaryRootMakefile directories`;
340: `make -f $tag/BinaryRootMakefile files`;
341: `make -f $tag/BinaryRootMakefile links`;
342:
1.13 harris41 343: # ------------------------------------------------- roll everything into an RPM
344:
345: my $command="cd $currentdir/SOURCES; tar czvf $name-$version.tar.gz ".
346: "$name-$version";
1.12 harris41 347: print `$command`;
348: $command="cd $currentdir/SPECS; rpm --rcfile=./rpmrc -ba ".
1.13 harris41 349: "$name-$version.spec; cd ../RPMS/i386; cp ".
350: "$name-$version-1.i386.rpm $invokingdir/.";
1.12 harris41 351: print `$command`;
1.13 harris41 352:
353: # --------------------------------------------------------- clean everything up
354:
1.5 harris41 355: print `cd $invokingdir; rm -Rf $tag`;
1.1 harris41 356:
1.15 ! harris41 357: # ----------------------------------------------------------------- SUBROUTINES
1.13 harris41 358: # ----- Subroutine: find_info - recursively gather information from a directory
1.1 harris41 359: sub find_info {
360: my ($file)=@_;
361: my $line;
362: if (($line=`find $file -type f -prune`)=~/^$file\n/) {
363: $line=`find $file -type f -prune -printf "\%s\t\%m\t\%u\t\%g"`;
364: return ("files",split(/\t/,$line));
365: }
366: elsif (($line=`find $file -type d -prune`)=~/^$file\n/) {
367: $line=`find $file -type d -prune -printf "\%s\t\%m\t\%u\t\%g"`;
368: return ("directories",split(/\t/,$line));
369: }
370: elsif (($line=`find $file -type l -prune`)=~/^$file\n/) {
1.6 harris41 371: $line=`find $file -type l -prune -printf "\%l\t\%m\t\%u\t\%g"`;
1.1 harris41 372: return ("links",split(/\t/,$line));
373: }
1.15 ! harris41 374: die("**** ERROR **** $file is neither a directory, soft link, or file");
1.1 harris41 375: }
1.13 harris41 376:
377: # ------------------------- Subroutine: grabtag - grab a tag from an xml string
378: sub grabtag {
379: my ($tag,$text,$clean)=@_;
380: # meant to be quick and dirty as opposed to a formal state machine parser
381: my $value;
382: $cu=~/\<$tag\>(.*?)\<\/$tag\>/s;
383: $value=$1; $value=~s/^\s+//;
384: if ($clean) {
385: $value=~s/\n\s/ /g;
386: $value=~s/\s\n/ /g;
387: $value=~s/\n/ /g;
388: $value=~s/\s+$//;
389: }
390: return $value;
391: }
392:
393: # ----------------------------------------------------- Plain Old Documentation
394:
395: =head1 NAME
396:
397: make_rpm.pl - automatically generate an RPM software package
398:
399: =head1 SYNOPSIS
400:
401: Usage: <TAG> <VERSION> [CONFIGURATION_FILES]
402: [DOCUMENTATION_FILES] [PATHPREFIX] [CUSTOMIZATION_XML]
403:
404: Standard input provides the list of files to work with.
405:
406: TAG, required descriptive tag. For example, a kerberos software
407: package might be tagged as "krb4".
408:
409: VERSION, required version. Needed to generate version information
410: for the RPM. This should be in the format N.M where N and M are
411: integers.
412:
413: CONFIGURATION_FILES, optional comma-separated listing of files to
414: be treated as configuration files by RPM (and thus subject to saving
415: during RPM upgrades).
416:
417: DOCUMENTATION_FILES, optional comma-separated listing of files to be
418: treated as documentation files by RPM (and thus subject to being
419: placed in the /usr/doc/RPM-NAME directory during RPM installation).
420:
421: PATHPREFIX, optional path to be removed from file listing. This
422: is in case you are building an RPM from files elsewhere than
423: root-level. Note, this still depends on a root directory hierarchy
424: after PATHPREFIX.
425:
426: CUSTOMIZATION_XML, allows for customizing various pieces of information such
427: as vendor, summary, name, copyright, group, autoreqprov, requires, prereq,
428: description, and pre-installation scripts (see more in the POD;
429: perldoc make_rpml.pl).
430:
431: Examples:
432:
433: [prompt] find notreallyrootdir | perl make_rpm.pl makemoney 3.1 '' \
434: '/usr/doc/man/man3/makemoney.3' notreallyrootdir
435: would generate makemoney-3.1-1.i386.rpm
436:
437: [prompt] find /usr/local/bin | perl make_rpm.pl mybinfiles 1.0
438: would generate mybinfiles-1.0-1.i386.rpm
439:
440: [prompt] find romeo | perl make_rpm.pl romeo 1.0 '' '' '' customize.xml
441: would generate romeo with customizations from customize.xml.
442:
443: The CUSTOMIZATION_XML argument represents a way to customize the
444: numerous variables associated with RPMs. This argument represents
445: a file name. (Parsing is done in an unsophisticated fashion using
446: regular expressions.) Here are example contents of such a file:
447:
448: <vendor>
449: Laboratory for Instructional Technology Education, Division of
450: Science and Mathematics Education, Michigan State University.
451: </vendor>
452: <summary>Files for the <tag /> component of LON-CAPA</summary>
453: <name>LON-CAPA-<tag /></name>
454: <copyright>Michigan State University patents may apply.</copyright>
455: <group>Utilities/System</group>
456: <AutoReqProv>no</AutoReqProv>
457: <requires tag='setup'>
458: <item>PreReq: setup</item>
459: <item>PreReq: passwd</item>
460: <item>PreReq: util-linux</item>
461: </requires>
462: <requires tag='base'>
463: <item>PreReq: LON-CAPA-setup</item>
464: <item>PreReq: apache</item>
465: <item>PreReq: /etc/httpd/conf/access.conf</item>
466: </requires>
467: <requires>
468: <item>Requires: LON-CAPA-base</item>
469: </requires>
470: <description>
471: This package is automatically generated by the make_rpm.pl perl
472: script (written by the LON-CAPA development team, www.lon-capa.org,
473: Scott Harrison). This implements the <tag /> component for LON-CAPA.
474: For more on the LON-CAPA project, visit http://www.lon-capa.org/.
475: </description>
476: <pre>
477: echo "***********************************************************************"
478: echo "LON-CAPA LearningOnline with CAPA"
479: echo "http://www.lon-capa.org/"
480: echo " "
481: echo "Laboratory for Instructional Technology Education"
482: echo "Michigan State University"
483: echo " "
484: echo "** Michigan State University patents may apply **"
485: echo " "
486: echo "This installation assumes an installation of Redhat 6.2"
487: echo " "
488: echo "The server computer should be currently connected to the ethernet"
489: echo " "
490: echo "The files in this package are only those for the <tag /> component."
491: echo "Configuration files are sometimes part of the LON-CAPA-base RPM."
492: echo "***********************************************************************"
493: </pre>
494:
495: =head1 DESCRIPTION
496:
497: Automatically generate an RPM software package from a list of files.
498:
499: This script builds the RPM in a very clean and configurable fashion.
1.15 ! harris41 500: (Finally! Making RPMs outside of /usr/src/redhat without a zillion
! 501: file intermediates left over!)
1.13 harris41 502:
503: This script generates and then deletes temporary
1.15 ! harris41 504: files needed to build an RPM with.
! 505: It works cleanly and independently from pre-existing
1.13 harris41 506: directory trees such as /usr/src/redhat/*.
507:
1.15 ! harris41 508: The script is also simple. It accepts four kinds of information,
! 509: two of which are mandatory:
! 510:
! 511: =over 4
! 512:
! 513: =item *
! 514:
! 515: a list of files that are to be part of the software package;
! 516:
! 517: =item *
! 518:
! 519: the location of these files;
! 520:
! 521: =item *
! 522:
! 523: (optional) a descriptive tag and a version tag;
! 524:
! 525: =item *
! 526:
! 527: and (optional) an XML file that defines the additional metadata
! 528: associated with the RPM software package.
! 529:
! 530: =back
! 531:
! 532: The following items are initially and temporarily generated during the
! 533: construction of an RPM:
! 534:
! 535: =over 4
! 536:
! 537: =item *
! 538:
! 539: RPM .spec file
! 540:
! 541: =item *
! 542:
! 543: RPM Makefile
! 544:
! 545: =item *
! 546:
! 547: SourceRoot
! 548:
! 549: =back
1.13 harris41 550:
551: A resulting .rpm file is generated.
552:
1.15 ! harris41 553: make_rpm.pl is compatible with both rpm version 3.* and rpm version 4.*.
! 554:
1.13 harris41 555: =head1 README
556:
557: Automatically generate an RPM software package from a list of files.
558:
559: This script builds the RPM in a very clean and configurable fashion.
1.15 ! harris41 560: (Making RPMs the simple and right way!)
1.13 harris41 561:
562: This script generates and then deletes temporary
563: files (and binary root directory tree) to build an RPM with.
564: It is designed to work cleanly and independently from pre-existing
565: directory trees such as /usr/src/redhat/*.
566:
567: =head1 PREREQUISITES
568:
569: This script requires the C<strict> module.
570:
571: =pod OSNAMES
572:
1.15 ! harris41 573: Linux
1.13 harris41 574:
575: =pod SCRIPT CATEGORIES
576:
577: UNIX/System Administration
578:
579: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>