package DPKG::Make; # Scott Harrison # In order to view the documentation internal to this module, # please type "perldoc ./Make.pm" use vars qw( $VERSION ); $VERSION='0.1'; # ----------------------------------------------------- Plain Old Documentation =pod =head1 NAME DPKG::Make - cleanly generate an Debian package (.dpkg) =head1 SYNOPSIS use DPKG::Make; # The "Manifest": list of files that will comprise the software package. my @filelist=('tmproot/file1.txt', 'tmproot/file2.txt', 'tmproot/file3.txt', 'tmproot/file4.txt'); my %doc; my %conf; my %metadata; # Define special handling of files. $doc{'tmproot/file1.txt'}=1; $conf{'tmproot/file2.txt'}=1; # Bare minimum metadata (descriptive data of the software package). my $pathprefix='tmproot'; my $tag='test'; # cannot use uppercase characters my $version='0.1'; my $release='1'; # Highly descriptive metadata. %metadata=( 'vendor'=>'Excellence in Perl Laboratory', 'summary'=>'a Test Software Package', 'name'=>$tag, 'copyrightname'=>'...', 'group'=>'base', 'AutoReqProv'=>'no', 'requires=>[()], 'email'=>'joe@somewhere.com', 'description'=>'This package is generated by DPKG::Make. '. 'This implements the '.$tag.' software package', 'pre'=>'echo "You are installing a package built by DPKG::Make; '. 'DPKG::Make is available at http://www.cpan.org/."', ); # Temporary "sandbox" (this should not be /tmp because this is deleted!). my $buildloc='TempBuildLoc'; # The "execute" subroutine coordinates all of the DPKG building steps. DPKG::Make::execute($tag,$version,$release,$arch,$buildloc,$pathprefix, \@filelist,\%doc,\%conf, \%metadata); # You can also build a DPKG in more atomic steps; these three smaller # steps are equivalent to the execute command. # Step 1: Generate the rpm source location. DPKG::Make::dpkgsrc($tag,$version,$release,$arch,$buildloc,$pathprefix, \@filelist,\%doc,\%conf, \%metadata); # Step 2: Build the rpm and copy into the invoking directory. DPKG::Make::compiledpkg($buildloc,$metadata{'name'},$version, $release,$arch, $currentdir,$invokingdir); # Step 3: clean the location used to gather and build the rpm. DPKG::Make::cleanbuildloc($buildloc); =cut =pod =head1 SUBROUTINES =cut use strict; ############################################################################### =pod =head2 DPKG::Make::testsystem() Check to see if DPKG builder application is available =over 4 =item INPUT n/a =item OUTPUT n/a =item ERROR if necessary commands do not exist (dpkg, debuild, etc), print error and exit =item NOTE To date, this testing action has been fully adequate, though imperfect. =cut sub testsystem { # ----------- If needed software does not exist, then print error and exit. unless (qx{dpkg --version} and qx{debuild --version}) { # needed software print(<$binaryroot/Makefile"); print(OUTS <$buildloc/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"); } close(OUTB); print(OUTS <$binaryroot/debian/dirs"); foreach (keys %dirlist) { print(DIRSFILE "$_\n"); } print(DIRSFILE "tmp\n"); # need at least one entry for debuild working close(DIRSFILE); # --------------------------------- Print information for debian/conffiles file print "Altering the debian/conffiles file...\n"; open(CONFFILES,">$binaryroot/debian/conffiles"); foreach (keys %dirlist) { print(CONFFILES "$_\n"); } close(CONFFILES); # ----------------------------------- Print information for debian/control file print "Altering the debian/control file...\n"; my %orig_control_hash; open(CONTROL,"<$binaryroot/debian/control"); while() { chomp; if (/\:\s/) { my ($key,$value)=split(/\:\s/); $orig_control_hash{$key}=$value; } } close(CONTROL); my $policy=$orig_control_hash{'Standards-Version'}; open(CONTROL,">$binaryroot/debian/control"); print(CONTROL < Standards-Version: $policy Package: $name Architecture: $arch Depends: \${shlibs:Depends} Description: $summary $description END close(CONTROL); return $name; } ############################################################################### =pod =head2 DPKG::Make::compiledpkg($buildloc,$name,$version,$release,$arch,$currentdir,$invokingdir); Properly assemble the DPKG source location. =over 4 =item INPUT 7 scalar strings =item OUTPUT n/a =item ERROR None captured. debuild warning and exit status is ignored for now... (debuild is stringent about pgp-signing which I do not think is totally necessary). =item NOTE Should be called after &rpmsrc and before &cleanbuildloc. =cut sub compiledpkg { my ($buildloc,$name,$version,$release,$arch,$currentdir,$invokingdir)=@_; # --------------------------- Is there rpm building software on the system? &testsystem(); # ------------------------------------------ Execute the 'debuild' command. my $binaryroot=$buildloc.'/'.$name.'-'.$version; unless (-d "$binaryroot/debian") { die("Cannot find $binaryroot/debian directory"); } print "cd $binaryroot/debian; debuild\n"; print `cd $binaryroot/debian; debuild 2>\&1`; # ----------------------------------- Copy files to the invoking directory. print `cp -v $buildloc/*.tar.gz .`; print `cp -v $buildloc/*.dsc .`; print `cp -v $buildloc/*.deb .`; print `cp -v $buildloc/*.changes .`; return; } ############################################################################### =pod =head2 DPKG::Make::cleanbuildloc($buildloc); Clean build location - usually F. =over 4 =item INPUT 1 scalar string =item OUTPUT n/a =item ERROR If the input argument is empty, then abort. Also should abort if cannot remove the location specified by the input argument. =item NOTE Should be called after &dpkgsrc and after &compiledpkg. =cut sub cleanbuildloc { my ($buildloc)=@_; # ----------------------------- Make sure that the input argument is valid. if (!length($buildloc)) { print(< builds the RPM in a very clean and configurable fashion. (Finally! Making RPMs outside of F without a zillion file intermediates left over!) B 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. B accepts five kinds of information, three of which are significant: =over 4 =item * (significant) a list of files that are to be part of the software package; =item * (significant) the filesystem location of these files; =item * (significant) a descriptive tag and a version tag for the naming of the DPKG software package; =item * documentation and configuration files; =item * and additional metadata associated with the Debian software package. =back When using DPKG::Make::execute, a temporary directory named $buildloc is =over 4 =item * generated under the directory from which you run your script, =item * and then deleted after the *.deb file and 3 other files are generated. =back The DPKG will typically be named "$metadata{'name'}-$version.deb". If $metadata{'name'} is not specified, then $tag is used. Here are some of the items are generated inside the $buildloc directory during the construction of an Debian package (DPKG): =over 4 =item * Debian control file (F<./$buildloc/$name-$version/debian/control>) =item * package Makefile (F<./$buildloc/$name-$version/Makefile>) This is the Makefile that is called by the debuild command in building the .deb file from source and contents of the debian/ directory. The following directories are generated and/or used: =over 4 =item * SOURCE directory: F<./$buildloc/$name-$version/> =item * TARGET directory: F<./$buildloc/$name-$version/tmp/> =back =item * BinaryRootMakefile (F<./$buildloc/BinaryRootMakefile>) This is the Makefile that this script creates and calls to build the F<$buildloc/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<./$buildloc/$name-$version/> =back =back The final output of B is a binary F<.deb> file (as well as F<.dsc>, F<.tar.gz>, and F<.changes> files). The F<./buildloc> directory is deleted (along with the F<./buildloc/*/debian> directory). The typical file name generated by B is F<$tag-$version.deb>. =head1 README Automatically generate a DPKG software package from a list of files. B builds the Debian package in a very clean and configurable fashion without requiring knowledge of Debian package building internals. B generates and then deletes temporary files (and binary root directory tree) to build an Debian package with. So far, this module has been tested on Debian v2.2. It still is not as mature as B (see RPM-Tools at www.cpan.org), but is in a basic working condition right now. I need to do more to streamline everything associated with generating a debian package according to the many debian "policies". =head1 PREREQUISITES This script requires the C module. =head1 AUTHOR Scott Harrison sharrison@users.sourceforge.net Please let me know how/if you are finding this module useful and any/all suggestions. -Scott =head1 LICENSE Written by Scott Harrison, sharrison@users.sourceforge.net 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 STATUS This module is new. Its API is similar to B which comes from RPM-Tools. =head1 OSNAMES Linux =cut