4 # Take a perl tarball and make a specfile for it. Now with bundles.
6 # Copyright 2000,2001 Simon Wilkinson. All rights reserved.
8 # 10/18/2001 - <jesse@bestpractical.com>
9 # Added resolution of prereq_pm modules
11 # This program is free software; you can redistribute it
12 # and/or modify it under the same terms as Perl itself.
23 use vars qw ($DEBUG $ARCH $builddir $seen @report);
40 Usage: cpan2rpm [--release <release>] [--builddir <rpm build dir>] <Perl::Module>
43 <release> is the release number of the RPM you wish to produce
44 <Perl::Module> is the name of the module to build
50 my $ret=GetOptions("release" => \$release,
51 "builddir=s" => \$builddir);
55 $release=1 if !$release;
58 $builddir=ExtractRpmMacro($ENV{HOME}."/.rpmmacros","_topdir") if !$builddir;
59 $builddir=ExtractRpmMacro("/etc/rpm/macros","_topdir") if !$builddir;
60 $builddir=getcwd() if !$builddir;
62 die "Build directory $builddir doesn't look like an RPM build root\n"
63 if ((! -d "$builddir/SPECS") || (! -d "$builddir/SOURCES"));
65 process($package,$release);
67 print join("\n",@report)."\n";
70 my ($infile,$release)=@_;
74 # Convert our installation list into an unbundled one
77 print "Building $infile\n";
79 cpan2rpm($infile,$builddir,$release);
83 # Given a Module, try to split it into its required components - this
84 # currently only handles Bundles, but could also be extended to deal with
90 if ($item=~/Bundle::/) {
91 my $obj=CPAN::Shell->expand('Bundle',$item);
93 foreach my $kid ($obj->contains) {
94 process($kid,$release);
101 my ($infile,$builddir,$release) = @_;
105 my $obj=CPAN::Shell->expand('Module',$infile);
107 print "CPAN tells us the following about $infile:\n",$obj->as_string if ($DEBUG);
109 $ret=fetch_source($obj,$builddir);
110 $ret=build_specfile($obj,$builddir,$release) if !$ret;
115 # FIXME: Some error handling in the function below wouldn't go amiss ...
117 my ($obj,$builddir)=@_;
119 # Minor Sanity checks
122 return "Error: No file for $id\n"
123 if $obj->cpan_file eq "N/A";
124 return "Error: $id says 'Contact Author'\n"
125 if $obj->cpan_file =~ /^Contact Author/;
126 return "Error: $id is contained within Perl itself!\n"
127 if ($obj->cpan_file =~/perl-5\.\d?\.\d?\.tar\.gz/xo);
129 # We do this so we can take advantage of CPAN's object caching. This is
130 # pinched from the CPAN::Distribution::get method, which we can't use
131 # directly, as it untars the package as well - which we let RPM do.
133 my $dist = $CPAN::META->instance('CPAN::Distribution',$obj->cpan_file);
137 MM->catfile($CPAN::Config->{keep_source_where},
140 split("/",$dist->{ID})
143 my $local_file = CPAN::FTP->localize("authors/id/$dist->{ID}", $local_wanted);
145 $dist->{localfile} = $local_file;
147 $dist->verifyMD5 if ($CPAN::META->has_inst('MD5'));
150 # Find all the prereqs for this distribution, then build em.
151 # TODO this should be somewhere else
154 build_prereqs( $dist->prereq_pm());
158 my $infile=basename($obj->cpan_file);
160 File::Copy::copy($local_file,"$builddir/SOURCES/$infile");
166 sub build_prereqs($) {
169 foreach my $prereq (keys %{$prereqs}) {
170 process ($prereq, $release);
173 sub build_specfile($$$) {
174 my ($obj,$builddir,$release) = @_;
176 my $source=basename($obj->cpan_file);
178 # don't go through dependencies on something we've already dealt with
179 return() if ($seen->{$source});
180 $seen->{$source} = 1;
182 my ($name,$version)=($source=~/(.*)-(.*)\.tar\.gz/);
183 return "Couldn't get a name for $source\n" if !$name;
184 return "Couldn't get a version for $source\n" if !$version;
186 my $summary="$name module for perl";
187 my $description=$obj->{description};
188 $description= $summary if !$description;
190 open(SPEC, ">$builddir/SPECS/perl-$name.spec")
191 or die "Couldn't open perl-$name.spec for writing.";
198 Copyright: distributable
199 Group: Applications/CPAN
201 Url: http://www.cpan.org
202 BuildRoot: /var/tmp/perl-${name}-buildroot/
206 This is a perl module, autogenerated by cpan2rpm. The original package's
212 %setup -q -n $name-%{version}
215 CFLAGS="\$RPM_OPT_FLAGS" perl Makefile.PL
219 rm -rf \$RPM_BUILD_ROOT
222 rm -rf \$RPM_BUILD_ROOT
223 eval `perl '-V:installarchlib'`
224 mkdir -p \$RPM_BUILD_ROOT/\$installarchlib
225 make PREFIX=\$RPM_BUILD_ROOT/usr install
226 /usr/lib/rpm/brp-compress
227 find \$RPM_BUILD_ROOT/usr -type f -print | sed "s\@^\$RPM_BUILD_ROOT\@\@g" | grep -v perllocal.pod > $name-$version-filelist
229 %files -f ${name}-${version}-filelist
230 %defattr(-,root,root)
234 print SPEC "* ",POSIX::strftime("%a %b %d %Y",localtime()), " ",$ENV{USER}," <",$ENV{USER},"\@",hostname(),">\n";
235 print SPEC "- Spec file automatically generated by cpan2rpm\n";
239 system("rpm -ba $builddir/SPECS/perl-$name.spec >/dev/null") == 0
240 or push (@report, "RPM of $source failed with : $!\n");
242 system("rpm -Uvh $builddir/RPMS/$ARCH/perl-$name-$version-$release.$ARCH.rpm") == 0
243 or warn "RPM of $source could not be installed: $!\n";
245 push (@report, "Built perl-$name-$version-$release.$ARCH.rpm");
248 sub ExtractRpmMacro {
249 my ($file,$macro) = @_;
251 my $handle=new IO::File;
253 if (!$handle->open($file)) {
258 if (/\%$macro (.*)/) {
268 cpan2rpm - fetch and convert CPAN packages to RPMs
272 cpan2rpm --release <release> <package>
276 cpan2rpm provides a quick way of creating RPM packages from perl modules
277 published on CPAN. It interfaces with the perl CPAN module to fetch the
278 file from the selected mirror, and then creates a spec file from the
279 information in CPAN, and invokes RPM on that spec file.
281 Files are created in the users RPM build root.
289 Sets the release number of the created RPMs.
299 Simon Wilkinson <sxw@sxw.org.uk>