Diff for /loncom/build/make_rpm.pl between versions 1.1 and 1.20

version 1.1, 2000/10/02 14:07:53 version 1.20, 2002/07/03 21:17:56
Line 1 Line 1
 #!/usr/bin/perl  #!/usr/bin/perl
   
 # Scott Harrison, September 30  # -------------------------------------------------------- Documentation notice
 # Automatically generate RPM listing files  # Run "perldoc ./make_rpm.pl" in order to best view the software documentation
 # from file listing.  # internalized in this program.
   
 # GNU General Public License, Version 2, June 1991  # --------------------------------------------------------- License Information
 # See http://www.gnu.org/copyleft/gpl.html.  # The LearningOnline Network with CAPA
   # make_rpm.pl - make RedHat package manager file (A CLEAN AND CONFIGURABLE WAY)
 # This file currently does not actually "build" the RPM.  #
 # This has to be done with an RPM build environment and  # $Id$
 # commands like 'rpm -ba'.  #
   # Written by Scott Harrison, harris41@msu.edu
 # What this file DOES do is generate all the needed  #
 # files (and binary root directory tree) to build an RPM with.  # Copyright Michigan State University Board of Trustees
   #
 # I still need to implement the CONFIGURATION_FILES and  # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
 # DOCUMENTATION_FILES portion of the command line interface to this  #
 # script.  # 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
 # Take in a file list (from standard input),   # the Free Software Foundation; either version 2 of the License, or
 # a description tag and version tag from command line argument  # (at your option) any later version.
 # and generate a:  #
 #      RPM .spec file  # LON-CAPA is distributed in the hope that it will be useful,
 #      RPM Makefile  # but WITHOUT ANY WARRANTY; without even the implied warranty of
 #      SourceRoot  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   # GNU General Public License for more details.
 unless (-e "/usr/lib/rpm/rpmrc") {  #
     print <<END;  # You should have received a copy of the GNU General Public License
 ERROR: This script only works with a properly installed RPM builder application.    # 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,4/7 - 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 command-line arguments                                         ##
   ## 3. Generate temporary directories (subdirs of first command-line argument)##
   ## 4. Initialize some variables                                              ##
   ## 5. Create a stand-alone 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') { # part of the expected rpm software package
       print(<<END);
   **** ERROR **** This script only works with a properly installed RPM builder
   application.  
 Cannot find /usr/lib/rpm/rpmrc, so cannot generate customized rpmrc file.  Cannot find /usr/lib/rpm/rpmrc, so cannot generate customized rpmrc file.
 Script aborting.  Script aborting.
 END  END
       exit(1);
 }  }
   
 my ($tag,$version,$configuration_files,$documentation_files,$pathprefix)=@ARGV;  # ---------------------------------------------- Read in command-line arguments
 @ARGV=();  
 if (!$version) {  my ($tag,$version,$configuration_files,$documentation_files,
     print "Usage: <TAG> <VERSION> [CONFIGURATION_FILES] [DOCUMENTATION] [PATHPREFIX]\n";      $pathprefix,$customize)=@ARGV;
     print "Standard input provides the list of files to work with.\n";  @ARGV=(); # read standard input based on a pipe, not a command-line argument
     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";  # standardize pathprefix argument
     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";  $pathprefix=~s/\/$//; # OTHERWISE THE BEGINNING SLASH MIGHT BE REMOVED
     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";  if (!$version) {# version should be defined and string length greater than zero
     exit;      print(<<END);
 }  See "perldoc make_rpm.pl" for more information.
   
 mkdir $tag,0755;  Usage: 
 mkdir "$tag/BuildRoot",0755;             <STDIN> | perl make_rpm.pl <TAG> <VERSION> [CONFIGURATION_FILES]
 mkdir "$tag/SOURCES",0755;             [DOCUMENTATION_FILES] [PATHPREFIX] [CUSTOMIZATION_XML]
 mkdir "$tag/SOURCES/LON-CAPA-$tag-$version",0755;  
 mkdir "$tag/SPECS",0755;  Standard input provides the list of files to work with.
 mkdir "$tag/BUILD",0755;  TAG, required descriptive tag.  For example, a kerberos software
 mkdir "$tag/SRPMS",0755;  package might be tagged as "krb4". (This value is also used in
 mkdir "$tag/RPMS",0755;  the generation of a temporary directory; you cannot have
 mkdir "$tag/RPMS/i386",0755;  a pre-existing directory named ./TAG.)
   VERSION, required version.  Needed to generate version information
   for the RPM.  It is recommended that this 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_rpm.pl").
   END
       exit(1);
   }
   
   # ----- Generate temporary directories (subdirs of first command-line argument)
   
   # Do some error-checking related to important first command-line argument.
   if ($tag=~/\W/) { # non-alphanumeric characters cause problems
       print(<<END);
   **** ERROR **** Invalid tag name "$tag"
   (The first command-line argument must be alphanumeric characters without
   spaces.)
   END
       exit(1);
   }
   if (-e $tag) { # do not overwrite or conflict with existing data
       print(<<END);
   **** ERROR **** a file or directory "./$tag" already exists
   (This program needs to generate a temporary directory named "$tag".)
   END
       exit(1);
   }
   
   print('Generating temporary directory ./'.$tag."\n");
   mkdir($tag,0755) or die("**** ERROR **** cannot generate $tag directory\n");
   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 $file;
 my $binaryroot="$tag/BinaryRoot";  my $binaryroot=$tag.'/BinaryRoot';
 my ($type,$size,$octalmode,$user,$group);  my ($type,$size,$octalmode,$user,$group);
   
 $currentdir=`pwd`; chop $currentdir; $invokingdir=$currentdir; $currentdir.="/$tag";  my $currentdir=`pwd`; chomp($currentdir); my $invokingdir=$currentdir;
   $currentdir.='/'.$tag;
   
   # ------------------------------- Create a stand-alone rpm building environment
   
 open (IN,"</usr/lib/rpm/rpmrc") or die("Can't open /usr/lib/rpm/rpmrc");  print('Creating stand-alone rpm build environment.'."\n");
 @lines=<IN>;  open(IN,'</usr/lib/rpm/rpmrc') or die('Cannot open /usr/lib/rpm/rpmrc'."\n");
 close IN;  my @lines=<IN>;
   close(IN);
   
 open (RPMRC,">$tag/SPECS/rpmrc");  open(RPMRC,">$tag/SPECS/rpmrc");
 foreach $line (@lines) {  foreach my $line (@lines) {
     if ($line=~/^macrofiles/) {      if ($line=~/^macrofiles/) {
  chop $line;   chomp($line);
  $line.=":./rpmmacros\n";   $line.=":$currentdir/SPECS/rpmmacros\n";
     }      }
     print RPMRC $line;      print(RPMRC $line);
 }  }
 close RPMRC;  close(RPMRC);
   
 open (RPMMACROS,">$tag/SPECS/rpmmacros");  open(RPMMACROS,">$tag/SPECS/rpmmacros");
 print RPMMACROS <<END;  print(RPMMACROS <<END);
 \%_topdir $currentdir  \%_topdir $currentdir
 \%__spec_install_post    \\  \%__spec_install_post    \\
     /usr/lib/rpm/brp-strip \\      /usr/lib/rpm/brp-strip \\
     /usr/lib/rpm/brp-strip-comment-note \\      /usr/lib/rpm/brp-strip-comment-note \\
 \%{nil}  \%{nil}
 END  END
 close RPMMACROS;  close(RPMMACROS);
   
   # ------------------------- Perform variable initializations and customizations
   
   my $cu=''; # string that holds customization XML file contents
   if (length($customize)>0) {
       print('Reading in XML-formatted customizations from '.$customize."\n");
       open(IN,"<$customize") or
       (
        print(`cd $invokingdir; rm -Rf $tag`) and
        die('Cannot open customization file "'.$customize.'"'."\n")
       );
       my @clines=(<IN>);
       $cu=join('',@clines);
       close(IN);
   }
   
 open (SPEC,">$tag/SPECS/LON-CAPA-$tag-$version.spec");  # tv - temporary variable (if it exists inside the XML document) then use it,
   # otherwise don't overwrite existing values of variables
   my $tv='';
   
   # (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 \/\>/$tag/g;
   
   # (When in doubt, be paranoid about overwriting things.)
   if (-e "$name-$version-1.i386.rpm") {
       print(`cd $invokingdir; rm -Rf $tag`); # clean temporary filespace in use
       die("**** ERROR **** $name-$version-1.i386.rpm already exists.\n");
   }
   
 print SPEC <<END;  my $requires='';
 Summary: Files for the $tag component of LON-CAPA.  # read in relevant requires info from customization file (if applicable)
 Name: LON-CAPA-$tag  # 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*\<item\>\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 \/\>/$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 \/\>/$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 \/\>/$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 \/\>/$tag/g;
   
   my $pre='';
   # read in pre-installation script if available
   $tv=grabtag('pre',$cu,0); $pre=$tv if $tv;
   $pre=~s/\<tag \/\>/$tag/g;
   
   # ------------------------------------- Print header information for .spec file
   print('Print header information for .spec file'."\n");
   
   print(SPEC <<END);
   Summary: $summary
   Name: $name
 Version: $version  Version: $version
 Release: 1  Release: 1
 Vendor: Laboratory for Instructional Technology Education, Division of Science and Mathematics Education, Michigan State University.  Vendor: $vendor
 BuildRoot: $currentdir/BuildRoot  BuildRoot: $currentdir/BuildRoot
 Copyright: GNU General Public License. Version 2, June 1991.  Michigan State University patents may apply.  Copyright: $copyright
 Group: Utilities/System  Group: Utilities/System
 Source: LON-CAPA-$tag-$version.tar.gz  Source: $name-$version.tar.gz
 AutoReqProv: no  AutoReqProv: $autoreqprov
   $requires
 # requires: filesystem  # requires: filesystem
 \%description  \%description
 This package is automatically generated by the make_rpm.pl perl  $description
 script (written by the LON-CAPA development team, www.lon-capa.org,  
 Scott Harrison). This implements the $tag component for LON-CAPA.  
 For more on the LON-CAPA project, visit http://www.lon-capa.org/.  
   
 \%prep  \%prep
 \%setup  \%setup
Line 118  make ROOT="\$RPM_BUILD_ROOT" SOURCE="$cu Line 295  make ROOT="\$RPM_BUILD_ROOT" SOURCE="$cu
 make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" links  make ROOT="\$RPM_BUILD_ROOT" SOURCE="$currentdir/BinaryRoot" links
   
 \%pre  \%pre
 echo "***********************************************************************"  $pre
 echo "LON-CAPA  LearningOnline with CAPA"  
 echo "http://www.lon-capa.org/"  
 echo "Gerd Kortemeyer, et al"  
 echo "Laboratory for Instructional Technology Education"  
 echo "Michigan State University"  
 echo "General Public License, Version 2, June 1991"  
 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 $tag component."  
 echo "Configuration files are sometimes part of the LON-CAPA-base RPM."  
 echo "***********************************************************************"  
   
 \%post  \%post
 \%postun  \%postun
Line 141  echo "********************************** Line 303  echo "**********************************
 \%files  \%files
 END  END
   
 foreach $file (<>) {  # ------------------------------------ Process file list and gather information
     chop $file;  print('Process standard input file list and gather information.'."\n");
   
   my %BinaryRootMakefile;
   my %Makefile;
   my %dotspecfile;
   
   foreach my $file (<>) {
       chomp($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)) {      if (($type,$size,$octalmode,$user,$group)=find_info($file)) {
  $octalmode="0" . $octalmode if length($octalmode)<4;   $octalmode="0" . $octalmode if length($octalmode)<4;
  if ($pathprefix) {   if ($pathprefix) {
     $file=~s/^$pathprefix//;      $file=~s/^$pathprefix//;
  }   }
  if ($type eq "files") {   if ($type eq "files") {
     push @{$BinaryRootMakefile{$type}},"\tinstall -D -m $octalmode $pathprefix$file $binaryroot$file\n";      push(@{$BinaryRootMakefile{$type}},"\tinstall -D -m $octalmode ".
     push @{$Makefile{$type}},"\tinstall -D -m $octalmode \$(SOURCE)$file \$(ROOT)$file\n";   "$pathprefix$file $binaryroot$file\n");
     push @{$dotspecfile{$type}},"\%attr($octalmode,$user,$group) $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") {   elsif ($type eq "directories") {
     push @{$BinaryRootMakefile{$type}},"\tinstall -m $octalmode -d $binaryroot$file\n";      push(@{$BinaryRootMakefile{$type}},"\tinstall -m $octalmode -d ".
     push @{$Makefile{$type}},"\tinstall -m $octalmode -d \$(SOURCE)$file \$(ROOT)$file\n";   "$binaryroot$file\n");
     push @{$dotspecfile{$type}},"\%dir \%attr($octalmode,$user,$group) $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") {   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//;      $link=~s/^$pathprefix//;
     push @{$BinaryRootMakefile{$type}},"\tln -s $link $binaryroot$file\n";      push(@{$BinaryRootMakefile{$type}},
     push @{$Makefile{$type}},"\tln -s $link \$(ROOT)$file\n";           "\tln -s $link $binaryroot$file\n");
     push @{$dotspecfile{$type}},"\%attr(-,$user,$group) $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";  # -------------------------------------- Generate SRPM and BinaryRoot Makefiles
 open OUT2, ">$tag/BinaryRootMakefile";  print('Generate SRPM and BinaryRoot Makefiles.'."\n");
   
   # Generate a much needed directory.
   # This directory is meant to hold all source code information
   # necessary for converting .src.rpm files into .i386.rpm files.
   mkdir("$tag/SOURCES/$name-$version",0755);
   
   open(OUTS,">$tag/SOURCES/$name-$version/Makefile");
   open(OUTB, ">$tag/BinaryRootMakefile");
 foreach $type ("directories","files","links") {  foreach $type ("directories","files","links") {
     print OUT "$type\:\n";      print(OUTS "$type\:\n");
     print OUT join("",@{$Makefile{$type}});      print(OUTS join("",@{$Makefile{$type}})) if $Makefile{$type};
     print OUT "\n";      print(OUTS "\n");
     print OUT2 "$type\:\n";      print(OUTB "$type\:\n");
     print OUT2 join("",@{$BinaryRootMakefile{$type}});      print(OUTB join("",@{$BinaryRootMakefile{$type}}))
     print OUT2 "\n";   if $BinaryRootMakefile{$type};
     print SPEC join("",@{$dotspecfile{$type}});      print(OUTB "\n");
       print(SPEC join("",@{$dotspecfile{$type}})) if $dotspecfile{$type};
 }  }
 close OUT2;  close(OUTB);
 close OUT;  close(OUTS);
   
   close(SPEC);
   
 close SPEC;  # ------------------ mirror copy (BinaryRoot) files under a temporary directory
   print('Mirror copy (BinaryRoot) files.'."\n");
   
 `make -f $tag/BinaryRootMakefile directories`;  `make -f $tag/BinaryRootMakefile directories`;
 `make -f $tag/BinaryRootMakefile files`;  `make -f $tag/BinaryRootMakefile files`;
 `make -f $tag/BinaryRootMakefile links`;  `make -f $tag/BinaryRootMakefile links`;
   
 print `cd $currentdir/SOURCES; tar czvf LON-CAPA-$tag-$version.tar.gz LON-CAPA-$tag-$version`;  # ------------------------------------------------- roll everything into an RPM
 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('Build a tarball and then run the rpm -ba command.'."\n");
 print `cd $invokingdir; rm -Rf $tag`;  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 -v ".
       "$name-$version-1.i386.rpm $invokingdir/.";
   print(`$command`);
   
   # --------------------------------------------------------- clean everything up
   print('Removing temporary ./'.$tag.' directory'."\n");
   print(`cd $invokingdir; rm -Rf $tag`);
   
   # -------------------------------------------------------- Yeah! We're all done
   print('Success. Script complete.'."\n");
   
   # ----------------------------------------------------------------- SUBROUTINES
   # ----- Subroutine: find_info - recursively gather information from a directory
 sub find_info {  sub find_info {
     # only look for  
     my ($file)=@_;      my ($file)=@_;
     my $line;      my $line='';
     if (($line=`find $file -type f -prune`)=~/^$file\n/) {      if (($line=`find $file -type f -prune`)=~/^$file\n/) {
  $line=`find $file -type f -prune -printf "\%s\t\%m\t\%u\t\%g"`;   $line=`find $file -type f -prune -printf "\%s\t\%m\t\%u\t\%g"`;
  return ("files",split(/\t/,$line));   return("files",split(/\t/,$line));
     }      }
     elsif (($line=`find $file -type d -prune`)=~/^$file\n/) {      elsif (($line=`find $file -type d -prune`)=~/^$file\n/) {
  $line=`find $file -type d -prune -printf "\%s\t\%m\t\%u\t\%g"`;   $line=`find $file -type d -prune -printf "\%s\t\%m\t\%u\t\%g"`;
  return ("directories",split(/\t/,$line));   return("directories",split(/\t/,$line));
     }      }
     elsif (($line=`find $file -type l -prune`)=~/^$file\n/) {      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));   return("links",split(/\t/,$line));
     }      }
       die("**** ERROR **** $file is neither a directory, soft link, or file.\n");
   }
   
   # ------------------------- 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==1) {
    $value=~s/\n\s/ /g;
    $value=~s/\s\n/ /g;
    $value=~s/\n/ /g;
    $value=~s/\s+$//;
       }
       return($value);
 }  }
   
   # ----------------------------------------------------- Plain Old Documentation
   
   =pod
   
   =head1 NAME
   
   make_rpm.pl - cleanly generate an rpm in a simple one-line command
   
   =head1 SYNOPSIS
   
   Usage: <STDIN> | make_rpm.pl <TAG> <VERSION>
          [CONFIGURATION_FILES] [DOCUMENTATION_FILES]
          [PATHPREFIX] [CUSTOMIZATION_XML]
   
   =head2 The standard input stream
   
   I<STDIN>, the standard input stream, provides the list of files to work
   with.  This list of file names must give the complete filesystem
   path starting from '/'.
   
   =over 4
   
   =item * For instance, the following is invalid:
   
    romeodir/file1.txt # ** INVALID! ** missing leading filesystem path
    romeodir/file2.txt
    romeodir/file3.txt
   
   =item * Whereas, the following is valid:
   
    /home/joe/romeodir/file1.txt
    /home/joe/romeodir/file2.txt
    /home/joe/romeodir/file3.txt
   
   =item * In terms of the B<find> command,
   
    "find romeodir | perl make_rpm.pl [COMMAND-LINE ARGUMENTS]"
   
   is incorrect, whereas
   
    "find /home/joe/romeodir |perl make_rpm.pl [COMMAND-LINE ARGUMENTS]"
   
   or
   
    "find `pwd`/romeodir |perl make_rpm.pl [COMMAND-LINE ARGUMENTS]"
   
   is correct.
   
   =back
   
   The standard input stream can also
   specify configuration files and documentation files through
   '#'-style commenting.
   
   For example, the following file listing encodes some of these directives:
   
    /home/joe/romeodir/buildloc/etc/romeo/user.conf # config(noreplace)
    /home/joe/romeodir/buildloc/etc/romeo/juliet.conf # config
    /home/joe/romeodir/buildloc/doc/man/man.1/romeo.1 # doc
    /home/joe/romeodir/buildloc/doc/man/man.1/romeo_talks.1 # doc
    /home/joe/romeodir/buildloc/usr/local/bin/where_art_thou
    /home/joe/romeodir/buildloc/usr/local/bin/romeo_talks
   
   The I<config> directive controls how files are replaced
   and/or backed up when a user attempts to install (B<rpm -i>) the F<.rpm>
   file generated by B<make_rpm.pl>.  The I<doc> directive controls how a
   given file is placed inside special documentation directories
   on the filesystem during rpm installation (B<rpm -i>).
   (If you want to learn more on how the B<rpm> tool gives configuration and
   documentation files special treatment, you should read about "Directives"
   in Edward Bailey's well-known "Maximum RPM" book available online
   at http://www.rpm.org/max-rpm/s1-rpm-inside-files-list-directives.html.)
   
   =head2 Description of command-line arguments
   
   I<TAG> ($tag), B<required> descriptive tag.  For example, a kerberos software
   package might be tagged as "krb4".
   
   I<VERSION> ($version), B<required> version.  Needed to generate version
   information for the RPM.  This should be in the format N.M where N and M are
   integers.
   
   I<CONFIGURATION_FILES>, B<optional> comma-separated listing of files to
   be treated as configuration files by RPM (and thus subject to saving
   during RPM upgrades).  Configuration files can also be specified in
   the standard input stream (as described in L<"The standard input stream">).
   
   I<DOCUMENTATION_FILES>, B<optional> comma-separated listing of files to be
   treated as documentation files by RPM (and thus subject to being
   placed in the F</usr/doc/RPM-NAME> directory during RPM installation).
   Documentation files can also be specified in
   the standard input stream (as described in L<"The standard input stream">).
   
   I<PATHPREFIX>, B<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.
   
   I<CUSTOMIZATION_XML>, B<optional> filename where XML-ish information exists.
   Allows for customizing various pieces of information such
   as vendor, summary, name, copyright, group, autoreqprov, requires, prereq,
   description, and pre-installation scripts
   (see L<"Customizing descriptive data of your RPM software package">).
   
   =head2 Examples
   
    bash$ find /notreallyrootdir | perl make_rpm.pl \
          makemoney 3.1 '' \
          '/usr/doc/man/man3/makemoney.3' \
          /notreallyrootdir
    would generate makemoney-3.1-1.i386.rpm
   
    bash$ find /usr/local/bin | \
          perl make_rpm.pl mybinfiles 1.0
    would generate mybinfiles-1.0-1.i386.rpm
   
    bash$ find /home/joe/romeodir/buildloc | \
          perl make_rpm.pl romeo \
          1.0 '' '' '/home/joe/romeodir/buildloc' customize.xml
    would generate romeo with customizations from customize.xml.
   
   The I<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.)  See
   L<"Customizing descriptive data of your RPM software package">.
   
   =head1 Customizing descriptive data of your RPM software package
   
   RPMS can be (and often are) packaged with descriptive data 
   describing authorship, dependencies, descriptions, etc.
   
   The following values can be tagged inside an XML file
   (specified by the 6th command-line argument)
   and made part of the RPM package information
   (B<rpm -qi E<lt>package-nameE<gt>>).
   
   =over 4
   
   =item * vendor
   
   =item * summary
   
   =item * name
   
   (overrides the <TAG> argument value; see 
   L<"Description of command-line arguments>)
   
   =item * copyright
   
   =item * group
   
   (the software package group;
   e.g. Applications/System, User Interface/X, Development/Libraries,
   etc.)
   
   =item * requires
   
   Contains all the dependency information (see the example below).
   
   =item * description
   
   =item * pre
   
   Commands to be executed prior to software package installation.
   
   =back
   
   Here is an example (note that B<make_rpm.pl> automatically substitutes
   any "<tag />" string with the first command-line argument described
   in L<"Description of command-line arguments">):
   
    <vendor>
    Laboratory for Instructional Technology Education, Division of
    Science and Mathematics Education, Michigan State University.
    </vendor>
    <summary>Files for the <tag /> component of LON-CAPA</summary>
    <name>LON-CAPA-<tag /></name>
    <copyright>Michigan State University patents may apply.</copyright>
    <group>Utilities/System</group>
    <AutoReqProv>no</AutoReqProv>
    <requires tag='setup'>
    <item>PreReq: setup</item>
    <item>PreReq: passwd</item>
    <item>PreReq: util-linux</item>
    </requires>
    <requires tag='base'>
    <item>PreReq: LON-CAPA-setup</item>
    <item>PreReq: apache</item>
    <item>PreReq: /etc/httpd/conf/access.conf</item>
    </requires>
    <requires>
    <item>Requires: LON-CAPA-base</item>
    </requires>
    <description>
    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 <tag /> component for LON-CAPA.
    For more on the LON-CAPA project, visit http://www.lon-capa.org/.
    </description>
    <pre>
    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 files in this package are for the <tag /> component."
    echo "***********************************************************"
    </pre>
   
   =head1 DESCRIPTION
   
   Automatically generate an RPM software package from a list of files.
   
   B<make_rpm.pl> builds the RPM in a very clean and configurable fashion.
   (Finally!  Making RPMs outside of F</usr/src/redhat> without a zillion
   file intermediates left over!)
   
   B<make_rpm.pl> generates and then deletes temporary
   files needed to build an RPM with.
   It works cleanly and independently from pre-existing
   directory trees such as F</usr/src/redhat/*>.
   
   Input to the script is simple.  B<make_rpm.pl> accepts five kinds of
   information, three of which are mandatory:
   
   =over 4
   
   =item *
   
   (required) a list of files that are to be part of the software package;
   
   =item *
   
   (required) the absolute filesystem location of these files
   (see L<"The standard input stream">);
   
   =item *
   
   (required) a descriptive tag and a version tag for the naming of the
   RPM software package;
   
   =item *
   
   (optional) documentation and configuration files;
   
   =item *
   
   and (optional) an XML file that defines the additional metadata
   associated with the RPM software package.
   
   =back
   
   A temporary directory named $tag (first argument described in
   L<"Description of command-line arguments">) is
   
   =over 4
   
   =item *
   
   generated under the directory from which you run B<make_rpm.pl>.
   
   For example, user "joe" running
   
    cat file_list.txt | make_rpm.pl krb4 1.0
   
   would temporarily generate F</home/joe/krb4/>.
   
   =item *
   
   F</home/joe/krb4/> is deleted after the *.rpm
   file is generated.
   
   =back
   
   The RPM will typically be named $name-$version.i386.rpm
   where $name=$tag.  (The $name can be overridden in the customization
   XML file; see
   L<"Customizing descriptive data of your RPM software package">.)
   
   Here are some of the items are generated inside
   the $tag directory during the construction of an RPM:
   
   =over 4
   
   =item *
   
   RPM .spec file (F<./$tag/SPECS/$name-$version.spec>)
   
   =item *
   
   RPM Makefile (F<./$tag/SOURCES/$name-$version/Makefile>)
   
   This is the Makefile that is called by the rpm
   command in building the .i386.rpm from the .src.rpm.
   The following directories are generated and/or used:
   
   =over 4
   
   =item *
   
   SOURCE directory: F<./$tag/BinaryRoot/>
   
   =item *
   
   TARGET directory: F<./$tag/BuildRoot/>
   
   =back
   
   =item *
   
   BinaryRootMakefile (F<./$tag/BinaryRootMakefile>)
   
   This is the Makefile that this script creates and calls
   to build the F<$tag/BinaryRoot/> directory from the existing
   filesystem.
   The following directories are generated and/or used:
   
   =over 4
   
   =item *
   
   SOURCE directory: / (your entire filesystem)
   
   =item *
   
   TARGET directory: F<./$tag/BinaryRoot/>
   
   =back
   
   =back
   
   The final output of B<make_rpm.pl> is a binary F<.rpm> file.
   The F<./tag> directory is deleted (along with the F<.src.rpm>
   file).  The typical file name generated by B<make_rpm.pl> is
   F<$tag-$version.i386.rpm>.
   
   B<make_rpm.pl> is compatible with either rpm version 3.* or rpm version 4.*.
   
   =head1 README
   
   Automatically generate an RPM software package from a list of files.
   
   B<make_rpm.pl> builds the RPM in a very clean and configurable fashion.
   (Making RPMs "the simple way" in a one-line command.)
   
   B<make_rpm.pl> 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<strict> module.
   
   =head1 AUTHOR
   
    Scott Harrison
    harris41@msu.edu
   
   Please let me know how/if you are finding this script useful and
   any/all suggestions.  -Scott
   
   =head1 LICENSE
   
   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).
   
   This 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.
   
   This file 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.
   
   The GNU Public License is available for review at
   http://www.gnu.org/copyleft/gpl.html.
   
   For information on the LON-CAPA project, please visit
   http://www.lon-capa.org/.
   
   =head1 OSNAMES
   
   Linux
   
   =head1 SCRIPT CATEGORIES
   
   UNIX/System_administration
   
   =cut
   

Removed from v.1.1  
changed lines
  Added in v.1.20


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