File:  [LON-CAPA] / loncom / build / make_rpm.pl
Revision 1.14: download - view: text, annotated - select for diffs
Wed Jan 9 22:16:14 2002 UTC (22 years, 5 months ago) by harris41
Branches: MAIN
CVS tags: stable_2002_spring, HEAD
allow for customizing autoreqprov (whether or not provides and requires
data is automatically gathered during the rpm building process)

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

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