--- loncom/build/make_rpm.pl 2000/12/12 16:51:39 1.4 +++ loncom/build/make_rpm.pl 2002/01/09 02:24:14 1.13 @@ -1,16 +1,50 @@ #!/usr/bin/perl -# Scott Harrison, September 30 -# Automatically generate RPM listing files -# from file listing. +# The LearningOnline Network with CAPA +# make_rpm.pl - make RedHat package manager file (A CLEAN AND CONFIGURABLE WAY) +# +# $Id: make_rpm.pl,v 1.13 2002/01/09 02:24:14 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 - Scott Harrison +# +### -# GNU General Public License, Version 2, June 1991 -# See http://www.gnu.org/copyleft/gpl.html. +# Automatically generate RPM files +# from file listing. -# This script does actually "build" the RPM. +# This script builds the RPM. # This script also 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/*. # I still need to implement the CONFIGURATION_FILES and # DOCUMENTATION_FILES portion of the command line interface to this @@ -25,53 +59,105 @@ # A resulting .rpm file is generated. -unless (-e "/usr/lib/rpm/rpmrc") { +############################################################################### +## ## +## 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. find_info - recursively gather information from a directory ## +## 14. Plain Old Documentation ## +## ## +############################################################################### + +use strict; + +# ------------------------ Check to see if RPM builder application is available + +unless (-e '/usr/lib/rpm/rpmrc') { print < [CONFIGURATION_FILES] [DOCUMENTATION] [PATHPREFIX]\n"; - print "Standard input provides the list of files to work with.\n"; - print "TAG, required descriptive tag. For example, a kerberos software package might be tagged as \"krb4\".\n"; - print "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.\n"; - print "CONFIGURATION_FILES, optional comma-separated listing of files to be treated as configuration files by RPM (and thus subject to saving during RPM upgrades).\n"; - print "DOCUMENTATION, 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).\n"; - print "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.\n"; + print < [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/SOURCES/LON-CAPA-$tag-$version",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); -$currentdir=`pwd`; chop $currentdir; $invokingdir=$currentdir; $currentdir.="/$tag"; +my $currentdir=`pwd`; chop $currentdir; my $invokingdir=$currentdir; +$currentdir.="/$tag"; -open (IN,"; +# -------------------------------- Create a standalone rpm building environment + +open (IN,'; close IN; open (RPMRC,">$tag/SPECS/rpmrc"); -foreach $line (@lines) { +foreach my $line (@lines) { if ($line=~/^macrofiles/) { chop $line; - $line.=":./rpmmacros\n"; + $line.=":$currentdir/SPECS/rpmmacros\n"; } print RPMRC $line; } @@ -87,25 +173,82 @@ print RPMMACROS <$tag/SPECS/LON-CAPA-$tag-$version.spec"); +# ------------------------- Perform variable initializations and customizations + +my $cu; +if ($customize) { + open (IN,"<$customize") or die("Cannot open $customize"); + my @clines=(); + $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 $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=""; @@ -149,9 +283,15 @@ foreach $file (<>) { $file=~s/\s+\#(.*)$//; $comment=$1; } - my $config=""; - if ($comment=~/config/i) { - $config="\%config "; + 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; @@ -159,50 +299,73 @@ foreach $file (<>) { $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}},"$config\%attr($octalmode,$user,$group) $file\n"; + 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"; + 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 + 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 @{$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"; } } } -open OUT, ">$tag/SOURCES/LON-CAPA-$tag-$version/Makefile"; -open OUT2, ">$tag/BinaryRootMakefile"; +# -------------------------------------- Generate SRPM and BinaryRoot Makefiles + +open OUTS, ">$tag/SOURCES/$name-$version/Makefile"; +open OUTB, ">$tag/BinaryRootMakefile"; foreach $type ("directories","files","links") { - print OUT "$type\:\n"; - print OUT join("",@{$Makefile{$type}}); - print OUT "\n"; - print OUT2 "$type\:\n"; - print OUT2 join("",@{$BinaryRootMakefile{$type}}); - print OUT2 "\n"; - print SPEC join("",@{$dotspecfile{$type}}); + 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 OUT2; -close OUT; - +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`; -print `cd $currentdir/SOURCES; tar czvf LON-CAPA-$tag-$version.tar.gz LON-CAPA-$tag-$version`; -print `cd $currentdir/SPECS; rpm --rcfile=./rpmrc -ba LON-CAPA-$tag-$version.spec; cd ../RPMS/i386; cp LON-CAPA-$tag-$version-1.i386.rpm $invokingdir/.`; -# print `cd $invokingdir; rm -Rf $tag`; +# ------------------------------------------------- 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`; + +# ----- Subroutine: find_info - recursively gather information from a directory sub find_info { # only look for my ($file)=@_; @@ -216,8 +379,173 @@ sub find_info { return ("directories",split(/\t/,$line)); } elsif (($line=`find $file -type l -prune`)=~/^$file\n/) { - $line=`find $file -type l -prune -printf "\%h/\%l\t\%m\t\%u\t\%g"`; + $line=`find $file -type l -prune -printf "\%l\t\%m\t\%u\t\%g"`; return ("links",split(/\t/,$line)); } } + +# ------------------------- 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 the simple 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/*. + +Take in a file list (from standard input), +a description tag and version tag from command line argument +and temporarily generate a: + RPM .spec file + RPM Makefile + SourceRoot + +A resulting .rpm file is generated. + +=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. +(Finally! Making RPMs the simple 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 + +any + +=pod SCRIPT CATEGORIES + +UNIX/System Administration + +=cut