File:  [LON-CAPA] / loncom / build / make_rpm.pl
Revision 1.20: download - view: text, annotated - select for diffs
Wed Jul 3 21:17:56 2002 UTC (21 years, 10 months ago) by harris41
Branches: MAIN
CVS tags: version_0_6_2, version_0_6, version_0_5_1, version_0_5, HEAD
adding initial pod tag

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>