Annotation of loncom/build/make_rpm.pl, revision 1.21
1.1 harris41 1: #!/usr/bin/perl
2:
1.16 harris41 3: # -------------------------------------------------------- Documentation notice
4: # Run "perldoc ./make_rpm.pl" in order to best view the software documentation
5: # internalized in this program.
6:
7: # --------------------------------------------------------- License Information
1.12 harris41 8: # The LearningOnline Network with CAPA
1.13 harris41 9: # make_rpm.pl - make RedHat package manager file (A CLEAN AND CONFIGURABLE WAY)
1.12 harris41 10: #
1.21 ! harris41 11: # $Id$
1.12 harris41 12: #
13: # Written by Scott Harrison, harris41@msu.edu
14: #
15: # Copyright Michigan State University Board of Trustees
16: #
1.21 ! harris41 17: # This file was written to help the LearningOnline Network with CAPA (LON-CAPA)
! 18: # project.
1.12 harris41 19: #
20: # LON-CAPA is free software; you can redistribute it and/or modify
21: # it under the terms of the GNU General Public License as published by
22: # the Free Software Foundation; either version 2 of the License, or
23: # (at your option) any later version.
24: #
25: # LON-CAPA is distributed in the hope that it will be useful,
26: # but WITHOUT ANY WARRANTY; without even the implied warranty of
27: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28: # GNU General Public License for more details.
29: #
30: # You should have received a copy of the GNU General Public License
31: # along with LON-CAPA; if not, write to the Free Software
32: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33: #
34: # http://www.lon-capa.org/
35: #
36: # YEAR=2000
37: # 9/30,10/2,12/11,12/12,12/21 - Scott Harrison
38: # YEAR=2001
39: # 1/8,1/10,1/13,1/23,5/16 - Scott Harrison
40: # YEAR=2002
1.21 ! harris41 41: # 1/4,1/8,1/9,2/13,4/7,12/18 - Scott Harrison
1.12 harris41 42: #
43: ###
44:
1.15 harris41 45: # make_rpm.pl automatically generate RPM software packages
46: # from a target image directory and file listing. POD
47: # documentation is at the end of this file.
1.1 harris41 48:
1.13 harris41 49: ###############################################################################
50: ## ##
51: ## ORGANIZATION OF THIS PERL SCRIPT ##
52: ## ##
53: ## 1. Check to see if RPM builder application is available ##
1.16 harris41 54: ## 2. Read in command-line arguments ##
55: ## 3. Generate temporary directories (subdirs of first command-line argument)##
1.13 harris41 56: ## 4. Initialize some variables ##
1.16 harris41 57: ## 5. Create a stand-alone rpm building environment ##
1.13 harris41 58: ## 6. Perform variable initializations and customizations ##
59: ## 7. Print header information for .spec file ##
60: ## 8. Process file list and generate information ##
61: ## 9. Generate SRPM and BinaryRoot Makefiles ##
62: ## 10. mirror copy (BinaryRoot) files under a temporary directory ##
63: ## 11. roll everything into an rpm ##
64: ## 12. clean everything up ##
1.15 harris41 65: ## 13. subroutines ##
66: ## 13a. find_info - recursively gather information from a directory ##
67: ## 13b. grabtag - grab a tag from an XML string ##
1.13 harris41 68: ## 14. Plain Old Documentation ##
69: ## ##
70: ###############################################################################
71:
1.21 ! harris41 72: my $VERSION = 2.0;
! 73:
1.13 harris41 74: use strict;
75:
76: # ------------------------ Check to see if RPM builder application is available
77:
1.21 ! harris41 78: unless (-e '/usr/lib/rpm/rpmrc') # part of the expected rpm software package
! 79: {
1.16 harris41 80: print(<<END);
81: **** ERROR **** This script only works with a properly installed RPM builder
1.12 harris41 82: application.
1.1 harris41 83: Cannot find /usr/lib/rpm/rpmrc, so cannot generate customized rpmrc file.
84: Script aborting.
85: END
1.16 harris41 86: exit(1);
1.21 ! harris41 87: }
1.1 harris41 88:
1.16 harris41 89: # ---------------------------------------------- Read in command-line arguments
1.13 harris41 90:
1.21 ! harris41 91: my ($tag,$version,$release,$configuration_files,$documentation_files,
1.13 harris41 92: $pathprefix,$customize)=@ARGV;
1.16 harris41 93: @ARGV=(); # read standard input based on a pipe, not a command-line argument
1.18 harris41 94:
95: # standardize pathprefix argument
96: $pathprefix=~s/\/$//; # OTHERWISE THE BEGINNING SLASH MIGHT BE REMOVED
1.3 harris41 97:
1.21 ! harris41 98: if (!$version) # version should be defined and string length greater than zero
! 99: {
1.16 harris41 100: print(<<END);
1.13 harris41 101: See "perldoc make_rpm.pl" for more information.
102:
1.15 harris41 103: Usage:
1.21 ! harris41 104: <STDIN> | perl make_rpm.pl <TAG> <VERSION> <RELEASE>
! 105: [CONFIGURATION_FILES] [DOCUMENTATION_FILES] [PATHPREFIX]
! 106: [CUSTOMIZATION_XML]
1.15 harris41 107:
1.13 harris41 108: Standard input provides the list of files to work with.
109: TAG, required descriptive tag. For example, a kerberos software
1.16 harris41 110: package might be tagged as "krb4". (This value is also used in
111: the generation of a temporary directory; you cannot have
112: a pre-existing directory named ./TAG.)
1.13 harris41 113: VERSION, required version. Needed to generate version information
1.16 harris41 114: for the RPM. It is recommended that this be in the format N.M where N and
1.21 ! harris41 115: M are integers. For example, 0.3, 4.1, and 8.9 are all valid version numbers.
! 116: RELEASE, required release number. Needed to generate release information
! 117: for the RPM. This is typically an integer, but can also be given descriptive
! 118: text such as 'rh7' or 'mandrake8a'.
1.13 harris41 119: CONFIGURATION_FILES, optional comma-separated listing of files to
120: be treated as configuration files by RPM (and thus subject to saving
121: during RPM upgrades).
122: DOCUMENTATION_FILES, optional comma-separated listing of files to be
123: treated as documentation files by RPM (and thus subject to being
124: placed in the /usr/doc/RPM-NAME directory during RPM installation).
125: PATHPREFIX, optional path to be removed from file listing. This
126: is in case you are building an RPM from files elsewhere than
127: root-level. Note, this still depends on a root directory hierarchy
128: after PATHPREFIX.
129: CUSTOMIZATION_XML, allows for customizing various pieces of information such
130: as vendor, summary, name, copyright, group, autoreqprov, requires, prereq,
1.16 harris41 131: description, and pre-installation scripts (see more in the POD,
132: "perldoc make_rpm.pl").
1.13 harris41 133: END
1.16 harris41 134: exit(1);
1.21 ! harris41 135: }
1.1 harris41 136:
1.16 harris41 137: # ----- Generate temporary directories (subdirs of first command-line argument)
138:
139: # Do some error-checking related to important first command-line argument.
1.21 ! harris41 140: if ($tag=~/[^\w-]/) # non-alphanumeric characters cause problems
! 141: {
1.16 harris41 142: print(<<END);
143: **** ERROR **** Invalid tag name "$tag"
144: (The first command-line argument must be alphanumeric characters without
145: spaces.)
146: END
147: exit(1);
1.21 ! harris41 148: }
! 149: if (-e $tag) # do not overwrite or conflict with existing data
! 150: {
1.16 harris41 151: print(<<END);
152: **** ERROR **** a file or directory "./$tag" already exists
153: (This program needs to generate a temporary directory named "$tag".)
154: END
155: exit(1);
1.21 ! harris41 156: }
1.16 harris41 157:
158: print('Generating temporary directory ./'.$tag."\n");
159: mkdir($tag,0755) or die("**** ERROR **** cannot generate $tag directory\n");
160: mkdir("$tag/BuildRoot",0755);
161: mkdir("$tag/SOURCES",0755);
162: mkdir("$tag/SPECS",0755);
163: mkdir("$tag/BUILD",0755);
164: mkdir("$tag/SRPMS",0755);
165: mkdir("$tag/RPMS",0755);
166: mkdir("$tag/RPMS/i386",0755);
1.1 harris41 167:
1.13 harris41 168: # -------------------------------------------------------- Initialize variables
169:
1.1 harris41 170: my $file;
1.16 harris41 171: my $binaryroot=$tag.'/BinaryRoot';
1.1 harris41 172: my ($type,$size,$octalmode,$user,$group);
173:
1.16 harris41 174: my $currentdir=`pwd`; chomp($currentdir); my $invokingdir=$currentdir;
175: $currentdir.='/'.$tag;
1.1 harris41 176:
1.16 harris41 177: # ------------------------------- Create a stand-alone rpm building environment
1.13 harris41 178:
1.16 harris41 179: print('Creating stand-alone rpm build environment.'."\n");
180: open(IN,'</usr/lib/rpm/rpmrc') or die('Cannot open /usr/lib/rpm/rpmrc'."\n");
1.13 harris41 181: my @lines=<IN>;
1.16 harris41 182: close(IN);
1.1 harris41 183:
1.16 harris41 184: open(RPMRC,">$tag/SPECS/rpmrc");
1.21 ! harris41 185: foreach my $line (@lines)
! 186: {
! 187: if ($line=~/^macrofiles/)
! 188: {
1.16 harris41 189: chomp($line);
1.11 harris41 190: $line.=":$currentdir/SPECS/rpmmacros\n";
1.21 ! harris41 191: }
1.16 harris41 192: print(RPMRC $line);
1.21 ! harris41 193: }
1.16 harris41 194: close(RPMRC);
1.1 harris41 195:
1.16 harris41 196: open(RPMMACROS,">$tag/SPECS/rpmmacros");
197: print(RPMMACROS <<END);
1.1 harris41 198: \%_topdir $currentdir
199: \%__spec_install_post \\
200: /usr/lib/rpm/brp-strip \\
201: /usr/lib/rpm/brp-strip-comment-note \\
202: \%{nil}
203: END
1.16 harris41 204: close(RPMMACROS);
1.1 harris41 205:
1.13 harris41 206: # ------------------------- Perform variable initializations and customizations
207:
1.16 harris41 208: my $cu=''; # string that holds customization XML file contents
1.21 ! harris41 209: if (length($customize)>0)
! 210: {
1.16 harris41 211: print('Reading in XML-formatted customizations from '.$customize."\n");
212: open(IN,"<$customize") or
213: (
214: print(`cd $invokingdir; rm -Rf $tag`) and
215: die('Cannot open customization file "'.$customize.'"'."\n")
216: );
1.13 harris41 217: my @clines=(<IN>);
218: $cu=join('',@clines);
1.16 harris41 219: close(IN);
1.21 ! harris41 220: }
1.13 harris41 221:
1.16 harris41 222: # tv - temporary variable (if it exists inside the XML document) then use it,
223: # otherwise don't overwrite existing values of variables
224: my $tv='';
225:
226: # (Sure. We could use HTML::TokeParser here... but that wouldn't be fun now,
1.13 harris41 227: # would it?)
228: my $name=$tag;
229: # read in name from customization if available
230: $tv=grabtag('name',$cu,1); $name=$tv if $tv;
231: $name=~s/\<tag \/\>/$tag/g;
232:
1.16 harris41 233: # (When in doubt, be paranoid about overwriting things.)
1.21 ! harris41 234: if (-e "$name-$version-1.i386.rpm")
! 235: {
1.16 harris41 236: print(`cd $invokingdir; rm -Rf $tag`); # clean temporary filespace in use
237: die("**** ERROR **** $name-$version-1.i386.rpm already exists.\n");
1.21 ! harris41 238: }
1.13 harris41 239:
1.16 harris41 240: my $requires='';
1.13 harris41 241: # read in relevant requires info from customization file (if applicable)
242: # note that "PreReq: item" controls order of CD-ROM installation (if you
243: # are making a customized CD-ROM)
244: # "Requires: item" just enforces dependencies from the command-line invocation
245: $tv=grabtag('requires',$cu,1); $requires=$tv if $tv;
246: # do more require processing here
247: $requires=~s/\s*\<\/item\>\s*//g;
248: $requires=~s/\s*\<item\>\s*/\n/g;
249: $requires=~s/^\s+//s;
250:
1.16 harris41 251: my $summary='Files for the '.$name.' software package.';
1.13 harris41 252: # read in summary from customization if available
253: $tv=grabtag('summary',$cu,1); $summary=$tv if $tv;
254: $summary=~s/\<tag \/\>/$tag/g;
255:
1.14 harris41 256: my $autoreqprov='no';
257: # read in autoreqprov from customization if available
258: $tv=grabtag('autoreqprov',$cu,1); $autoreqprov=$tv if $tv;
259:
1.13 harris41 260: my $copyright="not specified here";
261: # read in copyright from customization if available
262: $tv=grabtag('copyright',$cu,1); $copyright=$tv if $tv;
263: $copyright=~s/\<tag \/\>/$tag/g;
264:
1.21 ! harris41 265: my $rpmgroup="Utilities/System";
! 266: # read in copyright from customization if available
! 267: $tv=grabtag('group',$cu,1); $rpmgroup=$tv if $tv;
! 268: $rpmgroup=~s/\<tag \/\>/$tag/g;
1.13 harris41 269:
270: my $vendor='Me';
271: # read in vendor from customization if available
272: $tv=grabtag('vendor',$cu,1); $vendor=$tv if $tv;
273: $vendor=~s/\<tag \/\>/$tag/g;
274:
275: my $description="$name software package";
276: # read in description from customization if available
277: $tv=grabtag('description',$cu,0); $description=$tv if $tv;
278: $description=~s/\<tag \/\>/$tag/g;
279:
1.16 harris41 280: my $pre='';
1.13 harris41 281: # read in pre-installation script if available
282: $tv=grabtag('pre',$cu,0); $pre=$tv if $tv;
283: $pre=~s/\<tag \/\>/$tag/g;
1.1 harris41 284:
1.13 harris41 285: # ------------------------------------- Print header information for .spec file
1.19 harris41 286: print('Print header information for .spec file'."\n");
1.12 harris41 287:
1.21 ! harris41 288: open(SPEC,">$tag/SPECS/$name-$version.spec");
1.16 harris41 289: print(SPEC <<END);
1.13 harris41 290: Summary: $summary
291: Name: $name
1.1 harris41 292: Version: $version
1.21 ! harris41 293: Release: $release
1.12 harris41 294: Vendor: $vendor
1.1 harris41 295: BuildRoot: $currentdir/BuildRoot
1.13 harris41 296: Copyright: $copyright
1.21 ! harris41 297: Group: $rpmgroup
1.13 harris41 298: Source: $name-$version.tar.gz
1.14 harris41 299: AutoReqProv: $autoreqprov
1.7 harris41 300: $requires
1.1 harris41 301: # requires: filesystem
302: \%description
1.13 harris41 303: $description
1.1 harris41 304:
305: \%prep
306: \%setup
307:
308: \%build
309: rm -Rf "$currentdir/BuildRoot"
310:
311: \%install
312: make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" directories
313: make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" files
314: make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" links
315:
316: \%pre
1.13 harris41 317: $pre
1.1 harris41 318:
319: \%post
320: \%postun
321:
322: \%files
323: END
324:
1.13 harris41 325: # ------------------------------------ Process file list and gather information
1.19 harris41 326: print('Process standard input file list and gather information.'."\n");
1.13 harris41 327:
328: my %BinaryRootMakefile;
329: my %Makefile;
330: my %dotspecfile;
331:
1.21 ! harris41 332: foreach my $file (<>)
! 333: {
1.16 harris41 334: chomp($file);
1.4 harris41 335: my $comment="";
1.21 ! harris41 336: if ($file=~/\s+\#(.*)$/)
! 337: {
1.4 harris41 338: $file=~s/\s+\#(.*)$//;
339: $comment=$1;
1.21 ! harris41 340: }
1.13 harris41 341: my $directive="";
1.21 ! harris41 342: if ($comment=~/config\(noreplace\)/)
! 343: {
1.13 harris41 344: $directive="\%config(noreplace) ";
1.21 ! harris41 345: }
! 346: elsif ($comment=~/config/)
! 347: {
1.13 harris41 348: $directive="\%config ";
1.21 ! harris41 349: }
! 350: elsif ($comment=~/doc/)
! 351: {
1.13 harris41 352: $directive="\%doc";
1.21 ! harris41 353: }
! 354: if (($type,$size,$octalmode,$user,$group)=find_info($file))
! 355: {
1.1 harris41 356: $octalmode="0" . $octalmode if length($octalmode)<4;
1.21 ! harris41 357: if ($pathprefix)
! 358: {
1.1 harris41 359: $file=~s/^$pathprefix//;
1.21 ! harris41 360: }
! 361: if ($type eq "files")
! 362: {
1.16 harris41 363: push(@{$BinaryRootMakefile{$type}},"\tinstall -D -m $octalmode ".
364: "$pathprefix$file $binaryroot$file\n");
365: push(@{$Makefile{$type}},"\tinstall -D -m $octalmode ".
366: "\$(SOURCE)$file \$(ROOT)$file\n");
367: push(@{$dotspecfile{$type}},"$directive\%attr($octalmode,$user,".
368: "$group) $file\n");
1.21 ! harris41 369: }
! 370: elsif ($type eq "directories")
! 371: {
1.16 harris41 372: push(@{$BinaryRootMakefile{$type}},"\tinstall -m $octalmode -d ".
373: "$binaryroot$file\n");
374: push(@{$Makefile{$type}},"\tinstall -m $octalmode -d ".
375: "\$(SOURCE)$file \$(ROOT)$file\n");
376: push(@{$dotspecfile{$type}},"\%dir \%attr($octalmode,$user,".
377: "$group) $file\n");
1.21 ! harris41 378: }
! 379: elsif ($type eq "links")
! 380: {
1.12 harris41 381: my $link=$size; # I use the size variable to pass the link value
382: # from the subroutine find_info
1.1 harris41 383: $link=~s/^$pathprefix//;
1.16 harris41 384: push(@{$BinaryRootMakefile{$type}},
385: "\tln -s $link $binaryroot$file\n");
386: push(@{$Makefile{$type}},"\tln -s $link \$(ROOT)$file\n");
387: push(@{$dotspecfile{$type}},"\%attr(-,$user,$group) $file\n");
1.21 ! harris41 388: }
! 389: }
! 390: }
1.1 harris41 391:
1.13 harris41 392: # -------------------------------------- Generate SRPM and BinaryRoot Makefiles
1.19 harris41 393: print('Generate SRPM and BinaryRoot Makefiles.'."\n");
1.13 harris41 394:
1.16 harris41 395: # Generate a much needed directory.
396: # This directory is meant to hold all source code information
397: # necessary for converting .src.rpm files into .i386.rpm files.
398: mkdir("$tag/SOURCES/$name-$version",0755);
399:
400: open(OUTS,">$tag/SOURCES/$name-$version/Makefile");
401: open(OUTB, ">$tag/BinaryRootMakefile");
1.21 ! harris41 402: foreach $type ("directories","files","links")
! 403: {
1.16 harris41 404: print(OUTS "$type\:\n");
405: print(OUTS join("",@{$Makefile{$type}})) if $Makefile{$type};
406: print(OUTS "\n");
407: print(OUTB "$type\:\n");
408: print(OUTB join("",@{$BinaryRootMakefile{$type}}))
1.13 harris41 409: if $BinaryRootMakefile{$type};
1.16 harris41 410: print(OUTB "\n");
411: print(SPEC join("",@{$dotspecfile{$type}})) if $dotspecfile{$type};
1.21 ! harris41 412: }
1.16 harris41 413: close(OUTB);
414: close(OUTS);
1.1 harris41 415:
1.16 harris41 416: close(SPEC);
1.1 harris41 417:
1.13 harris41 418: # ------------------ mirror copy (BinaryRoot) files under a temporary directory
1.19 harris41 419: print('Mirror copy (BinaryRoot) files.'."\n");
1.1 harris41 420:
421: `make -f $tag/BinaryRootMakefile directories`;
422: `make -f $tag/BinaryRootMakefile files`;
423: `make -f $tag/BinaryRootMakefile links`;
424:
1.13 harris41 425: # ------------------------------------------------- roll everything into an RPM
1.16 harris41 426: print('Build a tarball and then run the rpm -ba command.'."\n");
1.13 harris41 427: my $command="cd $currentdir/SOURCES; tar czvf $name-$version.tar.gz ".
428: "$name-$version";
1.16 harris41 429: print(`$command`);
1.21 ! harris41 430:
! 431: # ----------------------------------------- Define commands to be executed.
! 432: # command1a works for rpm version <=4.0.2
! 433: # command1b works for rpm version >4.0.4
! 434:
! 435: my $arch = 'i386';
! 436:
! 437: my $command1a="cd $currentdir/SPECS; rpm --rcfile=./rpmrc --target=$arch -ba ".
! 438: "$name-$version.spec";
! 439:
! 440: my $rpmcommand = 'rpm';
! 441: if (`rpmbuild --version`) {$rpmcommand = 'rpmbuild';}
! 442: my $command1b="cd $currentdir/SPECS; $rpmcommand --rcfile=./rpmrc ".
! 443: "-ba --target $arch ".
! 444: "$name-$version.spec";
! 445:
! 446: # ---------------------------------------------- Run the "rpm -ba" command.
! 447: # The strategy here is to...try one approach, and then the other.
! 448: print "$command1a\n";
! 449: print (`$command1a`);
! 450: if ($?!=0)
! 451: {
! 452: print(<<END);
! 453: **** WARNING **** RPM compilation failed for rpm version 4.0.2 command syntax
! 454: (...trying another command syntax...)
! 455: END
! 456: print "$command1b\n";
! 457: print (`$command1b`);
! 458: if ($?!=0)
! 459: {
! 460: print(<<END);
! 461: **** ERROR **** RPM compilation failed for rpm version 4.0.4 command syntax
! 462: (...no more syntax choices to try...)
! 463: END
! 464: exit(1);
! 465: }
! 466: }
! 467:
! 468: # -------------------------------------------------------- Retrieve binary rpm.
! 469: $command="cd $currentdir/RPMS/$arch; cp -v ".
! 470: "$name-$version-$release.$arch.rpm $invokingdir/.";
1.16 harris41 471: print(`$command`);
1.13 harris41 472:
473: # --------------------------------------------------------- clean everything up
1.16 harris41 474: print('Removing temporary ./'.$tag.' directory'."\n");
475: print(`cd $invokingdir; rm -Rf $tag`);
1.13 harris41 476:
1.16 harris41 477: # -------------------------------------------------------- Yeah! We're all done
478: print('Success. Script complete.'."\n");
1.1 harris41 479:
1.15 harris41 480: # ----------------------------------------------------------------- SUBROUTINES
1.13 harris41 481: # ----- Subroutine: find_info - recursively gather information from a directory
1.21 ! harris41 482: sub find_info
! 483: {
1.1 harris41 484: my ($file)=@_;
1.16 harris41 485: my $line='';
1.21 ! harris41 486: my $safefile = $file;
! 487: $safefile =~ s/\+/\\+/g; # Better regular expression matching.
! 488: if (($line=`find $file -type f -prune`)=~/^$safefile\n/)
! 489: {
1.1 harris41 490: $line=`find $file -type f -prune -printf "\%s\t\%m\t\%u\t\%g"`;
1.16 harris41 491: return("files",split(/\t/,$line));
1.21 ! harris41 492: }
! 493: elsif (($line=`find $file -type d -prune`)=~/^$safefile\n/)
! 494: {
1.1 harris41 495: $line=`find $file -type d -prune -printf "\%s\t\%m\t\%u\t\%g"`;
1.16 harris41 496: return("directories",split(/\t/,$line));
1.21 ! harris41 497: }
! 498: elsif (($line=`find $file -type l -prune`)=~/^$safefile\n/)
! 499: {
1.6 harris41 500: $line=`find $file -type l -prune -printf "\%l\t\%m\t\%u\t\%g"`;
1.16 harris41 501: return("links",split(/\t/,$line));
1.21 ! harris41 502: }
1.16 harris41 503: die("**** ERROR **** $file is neither a directory, soft link, or file.\n");
1.21 ! harris41 504: }
1.13 harris41 505:
506: # ------------------------- Subroutine: grabtag - grab a tag from an xml string
1.21 ! harris41 507: sub grabtag
! 508: {
1.13 harris41 509: my ($tag,$text,$clean)=@_;
510: # meant to be quick and dirty as opposed to a formal state machine parser
1.16 harris41 511: my $value='';
1.13 harris41 512: $cu=~/\<$tag\>(.*?)\<\/$tag\>/s;
513: $value=$1; $value=~s/^\s+//;
1.21 ! harris41 514: if ($clean==1)
! 515: {
1.13 harris41 516: $value=~s/\n\s/ /g;
517: $value=~s/\s\n/ /g;
518: $value=~s/\n/ /g;
519: $value=~s/\s+$//;
1.21 ! harris41 520: }
1.16 harris41 521: return($value);
1.21 ! harris41 522: }
1.13 harris41 523:
524: # ----------------------------------------------------- Plain Old Documentation
1.20 harris41 525:
526: =pod
1.13 harris41 527:
528: =head1 NAME
529:
1.16 harris41 530: make_rpm.pl - cleanly generate an rpm in a simple one-line command
1.13 harris41 531:
532: =head1 SYNOPSIS
533:
1.21 ! harris41 534: Usage: <STDIN> | make_rpm.pl <TAG> <VERSION> <RELEASE>
1.16 harris41 535: [CONFIGURATION_FILES] [DOCUMENTATION_FILES]
536: [PATHPREFIX] [CUSTOMIZATION_XML]
537:
538: =head2 The standard input stream
539:
540: I<STDIN>, the standard input stream, provides the list of files to work
541: with. This list of file names must give the complete filesystem
542: path starting from '/'.
543:
544: =over 4
545:
546: =item * For instance, the following is invalid:
547:
548: romeodir/file1.txt # ** INVALID! ** missing leading filesystem path
549: romeodir/file2.txt
550: romeodir/file3.txt
551:
552: =item * Whereas, the following is valid:
553:
554: /home/joe/romeodir/file1.txt
555: /home/joe/romeodir/file2.txt
556: /home/joe/romeodir/file3.txt
557:
558: =item * In terms of the B<find> command,
559:
560: "find romeodir | perl make_rpm.pl [COMMAND-LINE ARGUMENTS]"
561:
562: is incorrect, whereas
563:
564: "find /home/joe/romeodir |perl make_rpm.pl [COMMAND-LINE ARGUMENTS]"
565:
566: or
567:
568: "find `pwd`/romeodir |perl make_rpm.pl [COMMAND-LINE ARGUMENTS]"
569:
570: is correct.
571:
572: =back
573:
574: The standard input stream can also
575: specify configuration files and documentation files through
576: '#'-style commenting.
577:
578: For example, the following file listing encodes some of these directives:
579:
580: /home/joe/romeodir/buildloc/etc/romeo/user.conf # config(noreplace)
581: /home/joe/romeodir/buildloc/etc/romeo/juliet.conf # config
582: /home/joe/romeodir/buildloc/doc/man/man.1/romeo.1 # doc
583: /home/joe/romeodir/buildloc/doc/man/man.1/romeo_talks.1 # doc
584: /home/joe/romeodir/buildloc/usr/local/bin/where_art_thou
585: /home/joe/romeodir/buildloc/usr/local/bin/romeo_talks
586:
587: The I<config> directive controls how files are replaced
588: and/or backed up when a user attempts to install (B<rpm -i>) the F<.rpm>
589: file generated by B<make_rpm.pl>. The I<doc> directive controls how a
590: given file is placed inside special documentation directories
591: on the filesystem during rpm installation (B<rpm -i>).
592: (If you want to learn more on how the B<rpm> tool gives configuration and
593: documentation files special treatment, you should read about "Directives"
594: in Edward Bailey's well-known "Maximum RPM" book available online
595: at http://www.rpm.org/max-rpm/s1-rpm-inside-files-list-directives.html.)
1.13 harris41 596:
1.16 harris41 597: =head2 Description of command-line arguments
1.13 harris41 598:
1.16 harris41 599: I<TAG> ($tag), B<required> descriptive tag. For example, a kerberos software
1.13 harris41 600: package might be tagged as "krb4".
601:
1.16 harris41 602: I<VERSION> ($version), B<required> version. Needed to generate version
603: information for the RPM. This should be in the format N.M where N and M are
1.13 harris41 604: integers.
605:
1.21 ! harris41 606: I<RELEASE> ($release), B<required> release number. Needed to generate release
! 607: information for the RPM. This is typically an integer, but can also be given
! 608: descriptive text such as 'rh7' or 'mandrake8a'.
! 609:
1.16 harris41 610: I<CONFIGURATION_FILES>, B<optional> comma-separated listing of files to
1.13 harris41 611: be treated as configuration files by RPM (and thus subject to saving
1.16 harris41 612: during RPM upgrades). Configuration files can also be specified in
613: the standard input stream (as described in L<"The standard input stream">).
1.13 harris41 614:
1.16 harris41 615: I<DOCUMENTATION_FILES>, B<optional> comma-separated listing of files to be
1.13 harris41 616: treated as documentation files by RPM (and thus subject to being
1.16 harris41 617: placed in the F</usr/doc/RPM-NAME> directory during RPM installation).
618: Documentation files can also be specified in
619: the standard input stream (as described in L<"The standard input stream">).
1.13 harris41 620:
1.16 harris41 621: I<PATHPREFIX>, B<optional> path to be removed from file listing. This
1.13 harris41 622: is in case you are building an RPM from files elsewhere than
623: root-level. Note, this still depends on a root directory hierarchy
624: after PATHPREFIX.
625:
1.16 harris41 626: I<CUSTOMIZATION_XML>, B<optional> filename where XML-ish information exists.
627: Allows for customizing various pieces of information such
1.13 harris41 628: as vendor, summary, name, copyright, group, autoreqprov, requires, prereq,
1.16 harris41 629: description, and pre-installation scripts
630: (see L<"Customizing descriptive data of your RPM software package">).
1.13 harris41 631:
1.16 harris41 632: =head2 Examples
1.13 harris41 633:
1.16 harris41 634: bash$ find /notreallyrootdir | perl make_rpm.pl \
1.21 ! harris41 635: makemoney 3.1 1 '' \
1.16 harris41 636: '/usr/doc/man/man3/makemoney.3' \
637: /notreallyrootdir
1.13 harris41 638: would generate makemoney-3.1-1.i386.rpm
639:
1.16 harris41 640: bash$ find /usr/local/bin | \
1.21 ! harris41 641: perl make_rpm.pl mybinfiles 1.0 2
! 642: would generate mybinfiles-1.0-2.i386.rpm
! 643:
! 644: bash$ echo '/sycamore33/tree.txt' | \
! 645: perl make_rpm.pl sycamore 1.0 2 '' '' '/sycamore33'
! 646: would generate sycamore-1.0-2.i386.rpm
! 647: Note that the generated sycamore rpm would install files at the root
! 648: '/' directory (not underneath /sycamore33); thus a file named
! 649: '/tree.txt' is created, NOT '/sycamore33/tree.txt'.
1.13 harris41 650:
1.16 harris41 651: bash$ find /home/joe/romeodir/buildloc | \
652: perl make_rpm.pl romeo \
1.21 ! harris41 653: 1.0 3 '' '' '/home/joe/romeodir/buildloc' customize.xml
1.13 harris41 654: would generate romeo with customizations from customize.xml.
1.21 ! harris41 655: Note that the generated romeo rpm would install files at the root
! 656: '/' directory (not underneath /home/joe/romedir/buildloc).
1.13 harris41 657:
1.16 harris41 658: The I<CUSTOMIZATION_XML> argument represents a way to customize the
1.13 harris41 659: numerous variables associated with RPMs. This argument represents
660: a file name. (Parsing is done in an unsophisticated fashion using
1.16 harris41 661: regular expressions.) See
662: L<"Customizing descriptive data of your RPM software package">.
663:
664: =head1 Customizing descriptive data of your RPM software package
665:
666: RPMS can be (and often are) packaged with descriptive data
667: describing authorship, dependencies, descriptions, etc.
668:
669: The following values can be tagged inside an XML file
670: (specified by the 6th command-line argument)
671: and made part of the RPM package information
672: (B<rpm -qi E<lt>package-nameE<gt>>).
673:
674: =over 4
675:
676: =item * vendor
677:
678: =item * summary
679:
680: =item * name
681:
682: (overrides the <TAG> argument value; see
683: L<"Description of command-line arguments>)
684:
685: =item * copyright
686:
687: =item * group
688:
689: (the software package group;
690: e.g. Applications/System, User Interface/X, Development/Libraries,
691: etc.)
692:
693: =item * requires
694:
695: Contains all the dependency information (see the example below).
696:
697: =item * description
698:
699: =item * pre
700:
701: Commands to be executed prior to software package installation.
702:
703: =back
704:
705: Here is an example (note that B<make_rpm.pl> automatically substitutes
706: any "<tag />" string with the first command-line argument described
707: in L<"Description of command-line arguments">):
1.13 harris41 708:
709: <vendor>
710: Laboratory for Instructional Technology Education, Division of
711: Science and Mathematics Education, Michigan State University.
712: </vendor>
713: <summary>Files for the <tag /> component of LON-CAPA</summary>
714: <name>LON-CAPA-<tag /></name>
715: <copyright>Michigan State University patents may apply.</copyright>
716: <group>Utilities/System</group>
717: <AutoReqProv>no</AutoReqProv>
718: <requires tag='setup'>
719: <item>PreReq: setup</item>
720: <item>PreReq: passwd</item>
721: <item>PreReq: util-linux</item>
722: </requires>
723: <requires tag='base'>
724: <item>PreReq: LON-CAPA-setup</item>
725: <item>PreReq: apache</item>
726: <item>PreReq: /etc/httpd/conf/access.conf</item>
727: </requires>
728: <requires>
729: <item>Requires: LON-CAPA-base</item>
730: </requires>
731: <description>
732: This package is automatically generated by the make_rpm.pl perl
733: script (written by the LON-CAPA development team, www.lon-capa.org,
734: Scott Harrison). This implements the <tag /> component for LON-CAPA.
735: For more on the LON-CAPA project, visit http://www.lon-capa.org/.
736: </description>
737: <pre>
1.16 harris41 738: echo "************************************************************"
1.13 harris41 739: echo "LON-CAPA LearningOnline with CAPA"
740: echo "http://www.lon-capa.org/"
741: echo " "
742: echo "Laboratory for Instructional Technology Education"
743: echo "Michigan State University"
744: echo " "
745: echo "** Michigan State University patents may apply **"
746: echo " "
747: echo "This installation assumes an installation of Redhat 6.2"
748: echo " "
1.16 harris41 749: echo "The files in this package are for the <tag /> component."
750: echo "***********************************************************"
1.13 harris41 751: </pre>
752:
753: =head1 DESCRIPTION
754:
755: Automatically generate an RPM software package from a list of files.
756:
1.16 harris41 757: B<make_rpm.pl> builds the RPM in a very clean and configurable fashion.
758: (Finally! Making RPMs outside of F</usr/src/redhat> without a zillion
1.15 harris41 759: file intermediates left over!)
1.13 harris41 760:
1.16 harris41 761: B<make_rpm.pl> generates and then deletes temporary
1.15 harris41 762: files needed to build an RPM with.
763: It works cleanly and independently from pre-existing
1.16 harris41 764: directory trees such as F</usr/src/redhat/*>.
1.13 harris41 765:
1.16 harris41 766: Input to the script is simple. B<make_rpm.pl> accepts five kinds of
767: information, three of which are mandatory:
1.15 harris41 768:
769: =over 4
770:
771: =item *
772:
1.16 harris41 773: (required) a list of files that are to be part of the software package;
1.15 harris41 774:
1.16 harris41 775: =item *
776:
777: (required) the absolute filesystem location of these files
778: (see L<"The standard input stream">);
779:
780: =item *
1.15 harris41 781:
1.21 ! harris41 782: (required) a descriptive tag, version tag, and release tag for the naming of
! 783: the RPM software package;
1.15 harris41 784:
785: =item *
786:
1.16 harris41 787: (optional) documentation and configuration files;
1.15 harris41 788:
789: =item *
790:
791: and (optional) an XML file that defines the additional metadata
792: associated with the RPM software package.
793:
794: =back
795:
1.16 harris41 796: A temporary directory named $tag (first argument described in
797: L<"Description of command-line arguments">) is
798:
799: =over 4
800:
801: =item *
802:
803: generated under the directory from which you run B<make_rpm.pl>.
804:
805: For example, user "joe" running
806:
1.21 ! harris41 807: cat file_list.txt | make_rpm.pl krb4 1.0 1
1.16 harris41 808:
809: would temporarily generate F</home/joe/krb4/>.
810:
811: =item *
812:
813: F</home/joe/krb4/> is deleted after the *.rpm
814: file is generated.
815:
816: =back
817:
818: The RPM will typically be named $name-$version.i386.rpm
819: where $name=$tag. (The $name can be overridden in the customization
820: XML file; see
821: L<"Customizing descriptive data of your RPM software package">.)
822:
823: Here are some of the items are generated inside
824: the $tag directory during the construction of an RPM:
825:
826: =over 4
827:
828: =item *
829:
830: RPM .spec file (F<./$tag/SPECS/$name-$version.spec>)
831:
832: =item *
833:
834: RPM Makefile (F<./$tag/SOURCES/$name-$version/Makefile>)
835:
836: This is the Makefile that is called by the rpm
837: command in building the .i386.rpm from the .src.rpm.
838: The following directories are generated and/or used:
1.15 harris41 839:
840: =over 4
841:
842: =item *
843:
1.16 harris41 844: SOURCE directory: F<./$tag/BinaryRoot/>
845:
846: =item *
847:
848: TARGET directory: F<./$tag/BuildRoot/>
849:
850: =back
851:
852: =item *
853:
854: BinaryRootMakefile (F<./$tag/BinaryRootMakefile>)
855:
856: This is the Makefile that this script creates and calls
857: to build the F<$tag/BinaryRoot/> directory from the existing
858: filesystem.
859: The following directories are generated and/or used:
860:
861: =over 4
1.15 harris41 862:
863: =item *
864:
1.16 harris41 865: SOURCE directory: / (your entire filesystem)
1.15 harris41 866:
867: =item *
868:
1.16 harris41 869: TARGET directory: F<./$tag/BinaryRoot/>
1.15 harris41 870:
871: =back
1.13 harris41 872:
1.16 harris41 873: =back
874:
875: The final output of B<make_rpm.pl> is a binary F<.rpm> file.
876: The F<./tag> directory is deleted (along with the F<.src.rpm>
877: file). The typical file name generated by B<make_rpm.pl> is
878: F<$tag-$version.i386.rpm>.
1.13 harris41 879:
1.16 harris41 880: B<make_rpm.pl> is compatible with either rpm version 3.* or rpm version 4.*.
1.15 harris41 881:
1.13 harris41 882: =head1 README
883:
884: Automatically generate an RPM software package from a list of files.
885:
1.16 harris41 886: B<make_rpm.pl> builds the RPM in a very clean and configurable fashion.
887: (Making RPMs "the simple way" in a one-line command.)
1.13 harris41 888:
1.16 harris41 889: B<make_rpm.pl> generates and then deletes temporary
1.13 harris41 890: files (and binary root directory tree) to build an RPM with.
891: It is designed to work cleanly and independently from pre-existing
892: directory trees such as /usr/src/redhat/*.
893:
894: =head1 PREREQUISITES
895:
896: This script requires the C<strict> module.
897:
1.16 harris41 898: =head1 AUTHOR
899:
900: Scott Harrison
901: harris41@msu.edu
902:
903: Please let me know how/if you are finding this script useful and
904: any/all suggestions. -Scott
905:
906: =head1 LICENSE
907:
908: Written by Scott Harrison, harris41@msu.edu
909:
910: Copyright Michigan State University Board of Trustees
911:
912: This file is part of the LearningOnline Network with CAPA (LON-CAPA).
913:
914: This is free software; you can redistribute it and/or modify
915: it under the terms of the GNU General Public License as published by
916: the Free Software Foundation; either version 2 of the License, or
917: (at your option) any later version.
918:
919: This file is distributed in the hope that it will be useful,
920: but WITHOUT ANY WARRANTY; without even the implied warranty of
921: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
922: GNU General Public License for more details.
923:
924: The GNU Public License is available for review at
925: http://www.gnu.org/copyleft/gpl.html.
926:
927: For information on the LON-CAPA project, please visit
928: http://www.lon-capa.org/.
929:
930: =head1 OSNAMES
1.13 harris41 931:
1.15 harris41 932: Linux
1.13 harris41 933:
1.16 harris41 934: =head1 SCRIPT CATEGORIES
1.13 harris41 935:
1.17 harris41 936: UNIX/System_administration
1.13 harris41 937:
938: =cut
1.16 harris41 939:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>