#!/usr/bin/perl # The LearningOnline Network with CAPA # make_rpm.pl - make RedHat package manager file (A CLEAN AND CONFIGURABLE WAY) # # $Id: make_rpm.pl,v 1.15 2002/02/16 19:53:46 harris41 Exp $ # # Written by Scott Harrison, harris41@msu.edu # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # http://www.lon-capa.org/ # # YEAR=2000 # 9/30,10/2,12/11,12/12,12/21 - Scott Harrison # YEAR=2001 # 1/8,1/10,1/13,1/23,5/16 - Scott Harrison # YEAR=2002 # 1/4,1/8,1/9,2/13 - Scott Harrison # ### # make_rpm.pl automatically generate RPM software packages # from a target image directory and file listing. POD # documentation is at the end of this file. ############################################################################### ## ## ## ORGANIZATION OF THIS PERL SCRIPT ## ## ## ## 1. Check to see if RPM builder application is available ## ## 2. Read in arguments ## ## 3. Generate temporary directories ## ## 4. Initialize some variables ## ## 5. Create a standalone rpm building environment ## ## 6. Perform variable initializations and customizations ## ## 7. Print header information for .spec file ## ## 8. Process file list and generate information ## ## 9. Generate SRPM and BinaryRoot Makefiles ## ## 10. mirror copy (BinaryRoot) files under a temporary directory ## ## 11. roll everything into an rpm ## ## 12. clean everything up ## ## 13. subroutines ## ## 13a. find_info - recursively gather information from a directory ## ## 13b. grabtag - grab a tag from an XML string ## ## 14. Plain Old Documentation ## ## ## ############################################################################### use strict; # ------------------------ Check to see if RPM builder application is available unless (-e '/usr/lib/rpm/rpmrc') { print < | perl make_rpm.pl [CONFIGURATION_FILES] [DOCUMENTATION_FILES] [PATHPREFIX] [CUSTOMIZATION_XML] Standard input provides the list of files to work with. TAG, required descriptive tag. For example, a kerberos software package might be tagged as "krb4". VERSION, required version. Needed to generate version information for the RPM. This should be in the format N.M where N and M are integers. CONFIGURATION_FILES, optional comma-separated listing of files to be treated as configuration files by RPM (and thus subject to saving during RPM upgrades). DOCUMENTATION_FILES, optional comma-separated listing of files to be treated as documentation files by RPM (and thus subject to being placed in the /usr/doc/RPM-NAME directory during RPM installation). PATHPREFIX, optional path to be removed from file listing. This is in case you are building an RPM from files elsewhere than root-level. Note, this still depends on a root directory hierarchy after PATHPREFIX. CUSTOMIZATION_XML, allows for customizing various pieces of information such as vendor, summary, name, copyright, group, autoreqprov, requires, prereq, description, and pre-installation scripts (see more in the POD; perldoc make_rpml.pl). END exit; } mkdir $tag,0755; mkdir "$tag/BuildRoot",0755; mkdir "$tag/SOURCES",0755; mkdir "$tag/SPECS",0755; mkdir "$tag/BUILD",0755; mkdir "$tag/SRPMS",0755; mkdir "$tag/RPMS",0755; mkdir "$tag/RPMS/i386",0755; # -------------------------------------------------------- Initialize variables my $file; my $binaryroot="$tag/BinaryRoot"; my ($type,$size,$octalmode,$user,$group); my $currentdir=`pwd`; chop $currentdir; my $invokingdir=$currentdir; $currentdir.="/$tag"; # -------------------------------- Create a standalone rpm building environment open (IN,'; close IN; open (RPMRC,">$tag/SPECS/rpmrc"); foreach my $line (@lines) { if ($line=~/^macrofiles/) { chop $line; $line.=":$currentdir/SPECS/rpmmacros\n"; } print RPMRC $line; } close RPMRC; open (RPMMACROS,">$tag/SPECS/rpmmacros"); print RPMMACROS <); $cu=join('',@clines); close IN; } my $tv; # tag value variable for storing retrievals from $cu # (Sure. We could use HTML::TokeParser here.. but that wouldn't be fun now, # would it?) my $name=$tag; # read in name from customization if available $tv=grabtag('name',$cu,1); $name=$tv if $tv; $name=~s/\/$tag/g; # okay.. now we can generate this needed directory mkdir "$tag/SOURCES/$name-$version",0755; my $requires=""; # read in relevant requires info from customization file (if applicable) # note that "PreReq: item" controls order of CD-ROM installation (if you # are making a customized CD-ROM) # "Requires: item" just enforces dependencies from the command-line invocation $tv=grabtag('requires',$cu,1); $requires=$tv if $tv; # do more require processing here $requires=~s/\s*\<\/item\>\s*//g; $requires=~s/\s*\\s*/\n/g; $requires=~s/^\s+//s; my $summary="Files for the $name software package."; # read in summary from customization if available $tv=grabtag('summary',$cu,1); $summary=$tv if $tv; $summary=~s/\/$tag/g; my $autoreqprov='no'; # read in autoreqprov from customization if available $tv=grabtag('autoreqprov',$cu,1); $autoreqprov=$tv if $tv; my $copyright="not specified here"; # read in copyright from customization if available $tv=grabtag('copyright',$cu,1); $copyright=$tv if $tv; $copyright=~s/\/$tag/g; open (SPEC,">$tag/SPECS/$name-$version.spec"); my $vendor='Me'; # read in vendor from customization if available $tv=grabtag('vendor',$cu,1); $vendor=$tv if $tv; $vendor=~s/\/$tag/g; my $description="$name software package"; # read in description from customization if available $tv=grabtag('description',$cu,0); $description=$tv if $tv; $description=~s/\/$tag/g; my $pre=""; # read in pre-installation script if available $tv=grabtag('pre',$cu,0); $pre=$tv if $tv; $pre=~s/\/$tag/g; # ------------------------------------- Print header information for .spec file print SPEC <) { chop $file; my $comment=""; if ($file=~/\s+\#(.*)$/) { $file=~s/\s+\#(.*)$//; $comment=$1; } my $directive=""; if ($comment=~/config\(noreplace\)/) { $directive="\%config(noreplace) "; } elsif ($comment=~/config/) { $directive="\%config "; } elsif ($comment=~/doc/) { $directive="\%doc"; } if (($type,$size,$octalmode,$user,$group)=find_info($file)) { $octalmode="0" . $octalmode if length($octalmode)<4; if ($pathprefix) { $file=~s/^$pathprefix//; } if ($type eq "files") { push @{$BinaryRootMakefile{$type}},"\tinstall -D -m $octalmode ". "$pathprefix$file $binaryroot$file\n"; push @{$Makefile{$type}},"\tinstall -D -m $octalmode ". "\$(SOURCE)$file \$(ROOT)$file\n"; push @{$dotspecfile{$type}},"$directive\%attr($octalmode,$user,". "$group) $file\n"; } elsif ($type eq "directories") { push @{$BinaryRootMakefile{$type}},"\tinstall -m $octalmode -d ". "$binaryroot$file\n"; push @{$Makefile{$type}},"\tinstall -m $octalmode -d ". "\$(SOURCE)$file \$(ROOT)$file\n"; push @{$dotspecfile{$type}},"\%dir \%attr($octalmode,$user,". "$group) $file\n"; } elsif ($type eq "links") { my $link=$size; # I use the size variable to pass the link value # from the subroutine find_info $link=~s/^$pathprefix//; push @{$BinaryRootMakefile{$type}}, "\tln -s $link $binaryroot$file\n"; push @{$Makefile{$type}},"\tln -s $link \$(ROOT)$file\n"; push @{$dotspecfile{$type}},"\%attr(-,$user,$group) $file\n"; } } } # -------------------------------------- Generate SRPM and BinaryRoot Makefiles open OUTS, ">$tag/SOURCES/$name-$version/Makefile"; open OUTB, ">$tag/BinaryRootMakefile"; foreach $type ("directories","files","links") { print OUTS "$type\:\n"; print OUTS join("",@{$Makefile{$type}}) if $Makefile{$type}; print OUTS "\n"; print OUTB "$type\:\n"; print OUTB join("",@{$BinaryRootMakefile{$type}}) if $BinaryRootMakefile{$type}; print OUTB "\n"; print SPEC join("",@{$dotspecfile{$type}}) if $dotspecfile{$type}; } close OUTB; close OUTS; close SPEC; # ------------------ mirror copy (BinaryRoot) files under a temporary directory `make -f $tag/BinaryRootMakefile directories`; `make -f $tag/BinaryRootMakefile files`; `make -f $tag/BinaryRootMakefile links`; # ------------------------------------------------- roll everything into an RPM my $command="cd $currentdir/SOURCES; tar czvf $name-$version.tar.gz ". "$name-$version"; print `$command`; $command="cd $currentdir/SPECS; rpm --rcfile=./rpmrc -ba ". "$name-$version.spec; cd ../RPMS/i386; cp ". "$name-$version-1.i386.rpm $invokingdir/."; print `$command`; # --------------------------------------------------------- clean everything up print `cd $invokingdir; rm -Rf $tag`; # ----------------------------------------------------------------- SUBROUTINES # ----- Subroutine: find_info - recursively gather information from a directory sub find_info { my ($file)=@_; my $line; if (($line=`find $file -type f -prune`)=~/^$file\n/) { $line=`find $file -type f -prune -printf "\%s\t\%m\t\%u\t\%g"`; return ("files",split(/\t/,$line)); } elsif (($line=`find $file -type d -prune`)=~/^$file\n/) { $line=`find $file -type d -prune -printf "\%s\t\%m\t\%u\t\%g"`; return ("directories",split(/\t/,$line)); } elsif (($line=`find $file -type l -prune`)=~/^$file\n/) { $line=`find $file -type l -prune -printf "\%l\t\%m\t\%u\t\%g"`; return ("links",split(/\t/,$line)); } die("**** ERROR **** $file is neither a directory, soft link, or file"); } # ------------------------- Subroutine: grabtag - grab a tag from an xml string sub grabtag { my ($tag,$text,$clean)=@_; # meant to be quick and dirty as opposed to a formal state machine parser my $value; $cu=~/\<$tag\>(.*?)\<\/$tag\>/s; $value=$1; $value=~s/^\s+//; if ($clean) { $value=~s/\n\s/ /g; $value=~s/\s\n/ /g; $value=~s/\n/ /g; $value=~s/\s+$//; } return $value; } # ----------------------------------------------------- Plain Old Documentation =head1 NAME make_rpm.pl - automatically generate an RPM software package =head1 SYNOPSIS Usage: [CONFIGURATION_FILES] [DOCUMENTATION_FILES] [PATHPREFIX] [CUSTOMIZATION_XML] Standard input provides the list of files to work with. TAG, required descriptive tag. For example, a kerberos software package might be tagged as "krb4". VERSION, required version. Needed to generate version information for the RPM. This should be in the format N.M where N and M are integers. CONFIGURATION_FILES, optional comma-separated listing of files to be treated as configuration files by RPM (and thus subject to saving during RPM upgrades). DOCUMENTATION_FILES, optional comma-separated listing of files to be treated as documentation files by RPM (and thus subject to being placed in the /usr/doc/RPM-NAME directory during RPM installation). PATHPREFIX, optional path to be removed from file listing. This is in case you are building an RPM from files elsewhere than root-level. Note, this still depends on a root directory hierarchy after PATHPREFIX. CUSTOMIZATION_XML, allows for customizing various pieces of information such as vendor, summary, name, copyright, group, autoreqprov, requires, prereq, description, and pre-installation scripts (see more in the POD; perldoc make_rpml.pl). Examples: [prompt] find notreallyrootdir | perl make_rpm.pl makemoney 3.1 '' \ '/usr/doc/man/man3/makemoney.3' notreallyrootdir would generate makemoney-3.1-1.i386.rpm [prompt] find /usr/local/bin | perl make_rpm.pl mybinfiles 1.0 would generate mybinfiles-1.0-1.i386.rpm [prompt] find romeo | perl make_rpm.pl romeo 1.0 '' '' '' customize.xml would generate romeo with customizations from customize.xml. The CUSTOMIZATION_XML argument represents a way to customize the numerous variables associated with RPMs. This argument represents a file name. (Parsing is done in an unsophisticated fashion using regular expressions.) Here are example contents of such a file: Laboratory for Instructional Technology Education, Division of Science and Mathematics Education, Michigan State University. Files for the component of LON-CAPA LON-CAPA- Michigan State University patents may apply. Utilities/System no PreReq: setup PreReq: passwd PreReq: util-linux PreReq: LON-CAPA-setup PreReq: apache PreReq: /etc/httpd/conf/access.conf Requires: LON-CAPA-base This package is automatically generated by the make_rpm.pl perl script (written by the LON-CAPA development team, www.lon-capa.org, Scott Harrison). This implements the component for LON-CAPA. For more on the LON-CAPA project, visit http://www.lon-capa.org/.
 echo "***********************************************************************"
 echo "LON-CAPA  LearningOnline with CAPA"
 echo "http://www.lon-capa.org/"
 echo " "
 echo "Laboratory for Instructional Technology Education"
 echo "Michigan State University"
 echo " "
 echo "** Michigan State University patents may apply **"
 echo " "
 echo "This installation assumes an installation of Redhat 6.2"
 echo " "
 echo "The server computer should be currently connected to the ethernet"
 echo " "
 echo "The files in this package are only those for the  component."
 echo "Configuration files are sometimes part of the LON-CAPA-base RPM."
 echo "***********************************************************************"
 
=head1 DESCRIPTION Automatically generate an RPM software package from a list of files. This script builds the RPM in a very clean and configurable fashion. (Finally! Making RPMs outside of /usr/src/redhat without a zillion file intermediates left over!) This script generates and then deletes temporary files needed to build an RPM with. It works cleanly and independently from pre-existing directory trees such as /usr/src/redhat/*. The script is also simple. It accepts four kinds of information, two of which are mandatory: =over 4 =item * a list of files that are to be part of the software package; =item * the location of these files; =item * (optional) a descriptive tag and a version tag; =item * and (optional) an XML file that defines the additional metadata associated with the RPM software package. =back The following items are initially and temporarily generated during the construction of an RPM: =over 4 =item * RPM .spec file =item * RPM Makefile =item * SourceRoot =back A resulting .rpm file is generated. make_rpm.pl is compatible with both rpm version 3.* and rpm version 4.*. =head1 README Automatically generate an RPM software package from a list of files. This script builds the RPM in a very clean and configurable fashion. (Making RPMs the simple and right way!) This script generates and then deletes temporary files (and binary root directory tree) to build an RPM with. It is designed to work cleanly and independently from pre-existing directory trees such as /usr/src/redhat/*. =head1 PREREQUISITES This script requires the C module. =pod OSNAMES Linux =pod SCRIPT CATEGORIES UNIX/System Administration =cut