File:  [LON-CAPA] / loncom / build / make_rpm.pl
Revision 1.21: download - view: text, annotated - select for diffs
Wed Dec 18 17:56:34 2002 UTC (21 years, 4 months ago) by harris41
Branches: MAIN
CVS tags: version_2_9_X, version_2_9_99_0, version_2_9_1, version_2_9_0, version_2_8_X, version_2_8_99_1, version_2_8_99_0, version_2_8_2, version_2_8_1, version_2_8_0, version_2_7_X, version_2_7_99_1, version_2_7_99_0, version_2_7_1, version_2_7_0, version_2_6_X, version_2_6_99_1, version_2_6_99_0, version_2_6_3, version_2_6_2, version_2_6_1, version_2_6_0, version_2_5_X, version_2_5_99_1, version_2_5_99_0, version_2_5_2, version_2_5_1, version_2_5_0, version_2_4_X, version_2_4_99_0, version_2_4_2, version_2_4_1, version_2_4_0, version_2_3_X, version_2_3_99_0, version_2_3_2, version_2_3_1, version_2_3_0, version_2_2_X, version_2_2_99_1, version_2_2_99_0, version_2_2_2, version_2_2_1, version_2_2_0, version_2_1_X, version_2_1_99_3, version_2_1_99_2, version_2_1_99_1, version_2_1_99_0, version_2_1_3, version_2_1_2, version_2_1_1, version_2_1_0, version_2_12_X, version_2_11_X, version_2_11_4_uiuc, version_2_11_4_msu, version_2_11_4, version_2_11_3_uiuc, version_2_11_3_msu, version_2_11_3, version_2_11_2_uiuc, version_2_11_2_msu, version_2_11_2_educog, version_2_11_2, version_2_11_1, version_2_11_0_RC3, version_2_11_0_RC2, version_2_11_0_RC1, version_2_11_0, version_2_10_X, version_2_10_1, version_2_10_0_RC2, version_2_10_0_RC1, version_2_10_0, version_2_0_X, version_2_0_99_1, version_2_0_2, version_2_0_1, version_2_0_0, version_1_99_3, version_1_99_2, version_1_99_1_tmcc, version_1_99_1, version_1_99_0_tmcc, version_1_99_0, version_1_3_X, version_1_3_3, version_1_3_2, version_1_3_1, version_1_3_0, version_1_2_X, version_1_2_99_1, version_1_2_99_0, version_1_2_1, version_1_2_0, version_1_1_X, version_1_1_99_5, version_1_1_99_4, version_1_1_99_3, version_1_1_99_2, version_1_1_99_1, version_1_1_99_0, version_1_1_3, version_1_1_2, version_1_1_1, version_1_1_0, version_1_0_99_3, version_1_0_99_2, version_1_0_99_1, version_1_0_99, version_1_0_3, version_1_0_2, version_1_0_1, version_1_0_0, version_0_99_5, version_0_99_4, version_0_99_3, version_0_99_2, version_0_99_1, version_0_99_0, loncapaMITrelate_1, language_hyphenation_merge, language_hyphenation, conference_2003, bz6209-base, bz6209, bz5969, bz5610, bz2851, PRINT_INCOMPLETE_base, PRINT_INCOMPLETE, HEAD, GCI_3, GCI_2, GCI_1, BZ5971-printing-apage, BZ5434-fox, BZ4492-merge, BZ4492-feature_horizontal_radioresponse, BZ4492-feature_Support_horizontal_radioresponse, BZ4492-Support_horizontal_radioresponse
using latest
http://www.cpan.org/authors/id/S/SH/SHARRISON/make_rpm-2.0.pl;
accepts release command-line argument in addition to version number;
broader character set for filenames; synchronized with
http://www.cpan.org/authors/id/S/SH/SHARRISON/RPM-Tools-0.8.tar.gz;
works on redhat 8 (supports rpm >4.1... also still supports rpm 3.x and
rpm 4.0.x)

    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.21 2002/12/18 17:56:34 harris41 Exp $
   12: #
   13: # Written by Scott Harrison, harris41@msu.edu
   14: #
   15: # Copyright Michigan State University Board of Trustees
   16: #
   17: # This file was written to help the LearningOnline Network with CAPA (LON-CAPA)
   18: # project.
   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
   41: # 1/4,1/8,1/9,2/13,4/7,12/18 - Scott Harrison
   42: #
   43: ###
   44: 
   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.
   48: 
   49: ###############################################################################
   50: ##                                                                           ##
   51: ## ORGANIZATION OF THIS PERL SCRIPT                                          ##
   52: ##                                                                           ##
   53: ## 1. Check to see if RPM builder application is available                   ##
   54: ## 2. Read in command-line arguments                                         ##
   55: ## 3. Generate temporary directories (subdirs of first command-line argument)##
   56: ## 4. Initialize some variables                                              ##
   57: ## 5. Create a stand-alone rpm building environment                          ##
   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                                                   ##
   65: ## 13. subroutines                                                           ##
   66: ## 13a. find_info - recursively gather information from a directory          ##
   67: ## 13b. grabtag - grab a tag from an XML string                              ##
   68: ## 14. Plain Old Documentation                                               ##
   69: ##                                                                           ##
   70: ###############################################################################
   71: 
   72: my $VERSION = 2.0;
   73: 
   74: use strict;
   75: 
   76: # ------------------------ Check to see if RPM builder application is available
   77: 
   78: unless (-e '/usr/lib/rpm/rpmrc') # part of the expected rpm software package
   79:   {
   80:     print(<<END);
   81: **** ERROR **** This script only works with a properly installed RPM builder
   82: application.  
   83: Cannot find /usr/lib/rpm/rpmrc, so cannot generate customized rpmrc file.
   84: Script aborting.
   85: END
   86:     exit(1);
   87:   }
   88: 
   89: # ---------------------------------------------- Read in command-line arguments
   90: 
   91: my ($tag,$version,$release,$configuration_files,$documentation_files,
   92:     $pathprefix,$customize)=@ARGV;
   93: @ARGV=(); # read standard input based on a pipe, not a command-line argument
   94: 
   95: # standardize pathprefix argument
   96: $pathprefix=~s/\/$//; # OTHERWISE THE BEGINNING SLASH MIGHT BE REMOVED
   97: 
   98: if (!$version) # version should be defined and string length greater than zero
   99:   {
  100:     print(<<END);
  101: See "perldoc make_rpm.pl" for more information.
  102: 
  103: Usage: 
  104:            <STDIN> | perl make_rpm.pl <TAG> <VERSION> <RELEASE>
  105: 	   [CONFIGURATION_FILES] [DOCUMENTATION_FILES] [PATHPREFIX]
  106: 	   [CUSTOMIZATION_XML]
  107: 
  108: Standard input provides the list of files to work with.
  109: TAG, required descriptive tag.  For example, a kerberos software
  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.)
  113: VERSION, required version.  Needed to generate version information
  114: for the RPM.  It is recommended that this be in the format N.M where N and
  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'.
  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,
  131: description, and pre-installation scripts (see more in the POD,
  132: "perldoc make_rpm.pl").
  133: END
  134:     exit(1);
  135:   }
  136: 
  137: # ----- Generate temporary directories (subdirs of first command-line argument)
  138: 
  139: # Do some error-checking related to important first command-line argument.
  140: if ($tag=~/[^\w-]/) # non-alphanumeric characters cause problems
  141:   {
  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);
  148:   }
  149: if (-e $tag) # do not overwrite or conflict with existing data
  150:   {
  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);
  156:   }
  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);
  167: 
  168: # -------------------------------------------------------- Initialize variables
  169: 
  170: my $file;
  171: my $binaryroot=$tag.'/BinaryRoot';
  172: my ($type,$size,$octalmode,$user,$group);
  173: 
  174: my $currentdir=`pwd`; chomp($currentdir); my $invokingdir=$currentdir;
  175: $currentdir.='/'.$tag;
  176: 
  177: # ------------------------------- Create a stand-alone rpm building environment
  178: 
  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");
  181: my @lines=<IN>;
  182: close(IN);
  183: 
  184: open(RPMRC,">$tag/SPECS/rpmrc");
  185: foreach my $line (@lines)
  186:   {
  187:     if ($line=~/^macrofiles/)
  188:       {
  189: 	chomp($line);
  190: 	$line.=":$currentdir/SPECS/rpmmacros\n";
  191:       }
  192:     print(RPMRC $line);
  193:   }
  194: close(RPMRC);
  195: 
  196: open(RPMMACROS,">$tag/SPECS/rpmmacros");
  197: print(RPMMACROS <<END);
  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
  204: close(RPMMACROS);
  205: 
  206: # ------------------------- Perform variable initializations and customizations
  207: 
  208: my $cu=''; # string that holds customization XML file contents
  209: if (length($customize)>0)
  210:   {
  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:     );
  217:     my @clines=(<IN>);
  218:     $cu=join('',@clines);
  219:     close(IN);
  220:   }
  221: 
  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,
  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: 
  233: # (When in doubt, be paranoid about overwriting things.)
  234: if (-e "$name-$version-1.i386.rpm")
  235:   {
  236:     print(`cd $invokingdir; rm -Rf $tag`); # clean temporary filespace in use
  237:     die("**** ERROR **** $name-$version-1.i386.rpm already exists.\n");
  238:   }
  239: 
  240: my $requires='';
  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: 
  251: my $summary='Files for the '.$name.' software package.';
  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: 
  256: my $autoreqprov='no';
  257: # read in autoreqprov from customization if available
  258: $tv=grabtag('autoreqprov',$cu,1); $autoreqprov=$tv if $tv;
  259: 
  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: 
  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;
  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: 
  280: my $pre='';
  281: # read in pre-installation script if available
  282: $tv=grabtag('pre',$cu,0); $pre=$tv if $tv;
  283: $pre=~s/\<tag \/\>/$tag/g;
  284: 
  285: # ------------------------------------- Print header information for .spec file
  286: print('Print header information for .spec file'."\n");
  287: 
  288: open(SPEC,">$tag/SPECS/$name-$version.spec");
  289: print(SPEC <<END);
  290: Summary: $summary
  291: Name: $name
  292: Version: $version
  293: Release: $release
  294: Vendor: $vendor
  295: BuildRoot: $currentdir/BuildRoot
  296: Copyright: $copyright
  297: Group: $rpmgroup
  298: Source: $name-$version.tar.gz
  299: AutoReqProv: $autoreqprov
  300: $requires
  301: # requires: filesystem
  302: \%description
  303: $description
  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
  317: $pre
  318: 
  319: \%post
  320: \%postun
  321: 
  322: \%files
  323: END
  324: 
  325: # ------------------------------------ Process file list and gather information
  326: print('Process standard input file list and gather information.'."\n");
  327: 
  328: my %BinaryRootMakefile;
  329: my %Makefile;
  330: my %dotspecfile;
  331: 
  332: foreach my $file (<>)
  333:   {
  334:     chomp($file);
  335:     my $comment="";
  336:     if ($file=~/\s+\#(.*)$/)
  337:       {
  338: 	$file=~s/\s+\#(.*)$//;
  339: 	$comment=$1;
  340:       }
  341:     my $directive="";
  342:     if ($comment=~/config\(noreplace\)/)
  343:       {
  344: 	$directive="\%config(noreplace) ";
  345:       }
  346:     elsif ($comment=~/config/)
  347:       {
  348: 	$directive="\%config ";
  349:       }
  350:     elsif ($comment=~/doc/)
  351:       {
  352: 	$directive="\%doc";
  353:       }
  354:     if (($type,$size,$octalmode,$user,$group)=find_info($file))
  355:       {
  356: 	$octalmode="0" . $octalmode if length($octalmode)<4;
  357: 	if ($pathprefix)
  358:           {
  359: 	    $file=~s/^$pathprefix//;
  360: 	  }
  361: 	if ($type eq "files")
  362:           {
  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");
  369: 	  }
  370: 	elsif ($type eq "directories")
  371:           {
  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");
  378: 	  }
  379: 	elsif ($type eq "links")
  380:           {
  381: 	    my $link=$size; # I use the size variable to pass the link value
  382:                             # from the subroutine find_info
  383: 	    $link=~s/^$pathprefix//;
  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");
  388: 	  }
  389:       }
  390:   }
  391: 
  392: # -------------------------------------- Generate SRPM and BinaryRoot Makefiles
  393: print('Generate SRPM and BinaryRoot Makefiles.'."\n");
  394: 
  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");
  402: foreach $type ("directories","files","links")
  403:   {
  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}}))
  409: 	if $BinaryRootMakefile{$type};
  410:     print(OUTB "\n");
  411:     print(SPEC join("",@{$dotspecfile{$type}})) if $dotspecfile{$type};
  412:   }
  413: close(OUTB);
  414: close(OUTS);
  415: 
  416: close(SPEC);
  417: 
  418: # ------------------ mirror copy (BinaryRoot) files under a temporary directory
  419: print('Mirror copy (BinaryRoot) files.'."\n");
  420: 
  421: `make -f $tag/BinaryRootMakefile directories`;
  422: `make -f $tag/BinaryRootMakefile files`;
  423: `make -f $tag/BinaryRootMakefile links`;
  424: 
  425: # ------------------------------------------------- roll everything into an RPM
  426: print('Build a tarball and then run the rpm -ba command.'."\n");
  427: my $command="cd $currentdir/SOURCES; tar czvf $name-$version.tar.gz ".
  428:     "$name-$version";
  429: print(`$command`);
  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/.";
  471: print(`$command`);
  472: 
  473: # --------------------------------------------------------- clean everything up
  474: print('Removing temporary ./'.$tag.' directory'."\n");
  475: print(`cd $invokingdir; rm -Rf $tag`);
  476: 
  477: # -------------------------------------------------------- Yeah! We're all done
  478: print('Success. Script complete.'."\n");
  479: 
  480: # ----------------------------------------------------------------- SUBROUTINES
  481: # ----- Subroutine: find_info - recursively gather information from a directory
  482: sub find_info
  483:   {
  484:     my ($file)=@_;
  485:     my $line='';
  486:     my $safefile = $file;
  487:     $safefile =~ s/\+/\\+/g; # Better regular expression matching.
  488:     if (($line=`find $file -type f -prune`)=~/^$safefile\n/)
  489:       {
  490: 	$line=`find $file -type f -prune -printf "\%s\t\%m\t\%u\t\%g"`;
  491: 	return("files",split(/\t/,$line));
  492:       }
  493:     elsif (($line=`find $file -type d -prune`)=~/^$safefile\n/)
  494:       {
  495: 	$line=`find $file -type d -prune -printf "\%s\t\%m\t\%u\t\%g"`;
  496: 	return("directories",split(/\t/,$line));
  497:       }
  498:     elsif (($line=`find $file -type l -prune`)=~/^$safefile\n/)
  499:       {
  500: 	$line=`find $file -type l -prune -printf "\%l\t\%m\t\%u\t\%g"`;
  501: 	return("links",split(/\t/,$line));
  502:       }
  503:     die("**** ERROR **** $file is neither a directory, soft link, or file.\n");
  504:   }
  505: 
  506: # ------------------------- Subroutine: grabtag - grab a tag from an xml string
  507: sub grabtag
  508:   {
  509:     my ($tag,$text,$clean)=@_;
  510:     # meant to be quick and dirty as opposed to a formal state machine parser
  511:     my $value='';
  512:     $cu=~/\<$tag\>(.*?)\<\/$tag\>/s; 
  513:     $value=$1; $value=~s/^\s+//;
  514:     if ($clean==1)
  515:       {
  516: 	$value=~s/\n\s/ /g;
  517: 	$value=~s/\s\n/ /g;
  518: 	$value=~s/\n/ /g;
  519: 	$value=~s/\s+$//;
  520:       }
  521:     return($value);
  522:   }
  523: 
  524: # ----------------------------------------------------- Plain Old Documentation
  525: 
  526: =pod
  527: 
  528: =head1 NAME
  529: 
  530: make_rpm.pl - cleanly generate an rpm in a simple one-line command
  531: 
  532: =head1 SYNOPSIS
  533: 
  534: Usage: <STDIN> | make_rpm.pl <TAG> <VERSION> <RELEASE>
  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.)
  596: 
  597: =head2 Description of command-line arguments
  598: 
  599: I<TAG> ($tag), B<required> descriptive tag.  For example, a kerberos software
  600: package might be tagged as "krb4".
  601: 
  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
  604: integers.
  605: 
  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: 
  610: I<CONFIGURATION_FILES>, B<optional> comma-separated listing of files to
  611: be treated as configuration files by RPM (and thus subject to saving
  612: during RPM upgrades).  Configuration files can also be specified in
  613: the standard input stream (as described in L<"The standard input stream">).
  614: 
  615: I<DOCUMENTATION_FILES>, B<optional> comma-separated listing of files to be
  616: treated as documentation files by RPM (and thus subject to being
  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">).
  620: 
  621: I<PATHPREFIX>, B<optional> path to be removed from file listing.  This
  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: 
  626: I<CUSTOMIZATION_XML>, B<optional> filename where XML-ish information exists.
  627: Allows for customizing various pieces of information such
  628: as vendor, summary, name, copyright, group, autoreqprov, requires, prereq,
  629: description, and pre-installation scripts
  630: (see L<"Customizing descriptive data of your RPM software package">).
  631: 
  632: =head2 Examples
  633: 
  634:  bash$ find /notreallyrootdir | perl make_rpm.pl \
  635:        makemoney 3.1 1 '' \
  636:        '/usr/doc/man/man3/makemoney.3' \
  637:        /notreallyrootdir
  638:  would generate makemoney-3.1-1.i386.rpm
  639: 
  640:  bash$ find /usr/local/bin | \
  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'.
  650: 
  651:  bash$ find /home/joe/romeodir/buildloc | \
  652:        perl make_rpm.pl romeo \
  653:        1.0 3 '' '' '/home/joe/romeodir/buildloc' customize.xml
  654:  would generate romeo with customizations from customize.xml.
  655:  Note that the generated romeo rpm would install files at the root
  656:  '/' directory (not underneath /home/joe/romedir/buildloc).
  657: 
  658: The I<CUSTOMIZATION_XML> argument represents a way to customize the
  659: numerous variables associated with RPMs.  This argument represents
  660: a file name.  (Parsing is done in an unsophisticated fashion using
  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">):
  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>
  738:  echo "************************************************************"
  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 " "
  749:  echo "The files in this package are for the <tag /> component."
  750:  echo "***********************************************************"
  751:  </pre>
  752: 
  753: =head1 DESCRIPTION
  754: 
  755: Automatically generate an RPM software package from a list of files.
  756: 
  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
  759: file intermediates left over!)
  760: 
  761: B<make_rpm.pl> generates and then deletes temporary
  762: files needed to build an RPM with.
  763: It works cleanly and independently from pre-existing
  764: directory trees such as F</usr/src/redhat/*>.
  765: 
  766: Input to the script is simple.  B<make_rpm.pl> accepts five kinds of
  767: information, three of which are mandatory:
  768: 
  769: =over 4
  770: 
  771: =item *
  772: 
  773: (required) a list of files that are to be part of the software package;
  774: 
  775: =item *
  776: 
  777: (required) the absolute filesystem location of these files
  778: (see L<"The standard input stream">);
  779: 
  780: =item *
  781: 
  782: (required) a descriptive tag, version tag, and release tag for the naming of
  783: the RPM software package;
  784: 
  785: =item *
  786: 
  787: (optional) documentation and configuration files;
  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: 
  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: 
  807:  cat file_list.txt | make_rpm.pl krb4 1.0 1
  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:
  839: 
  840: =over 4
  841: 
  842: =item *
  843: 
  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
  862: 
  863: =item *
  864: 
  865: SOURCE directory: / (your entire filesystem)
  866: 
  867: =item *
  868: 
  869: TARGET directory: F<./$tag/BinaryRoot/>
  870: 
  871: =back
  872: 
  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>.
  879: 
  880: B<make_rpm.pl> is compatible with either rpm version 3.* or rpm version 4.*.
  881: 
  882: =head1 README
  883: 
  884: Automatically generate an RPM software package from a list of files.
  885: 
  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.)
  888: 
  889: B<make_rpm.pl> generates and then deletes temporary
  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: 
  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
  931: 
  932: Linux
  933: 
  934: =head1 SCRIPT CATEGORIES
  935: 
  936: UNIX/System_administration
  937: 
  938: =cut
  939: 

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