pkgsrc/pkgtools/url2pkg/files/url2pkg.pl
rillig 630df34f70 Added PKG_DESTDIR_SUPPORT, as suggested by Kamel Ibn Hassen Derouiche on
tech-pkg.

Commented out the LICENSE definition, since pkg_admin is very picky
about invalid values. Having either "" or "LICENSE" as the value doesn't
let you even fetch and extract the distfiles.
2009-07-31 22:27:04 +00:00

447 lines
11 KiB
Prolog

#! @PERL@
# $NetBSD: url2pkg.pl,v 1.14 2009/07/31 22:27:04 rillig Exp $
#
use strict;
use warnings;
#
# Build-time Configuration.
#
my $make = '@MAKE@';
my $perllibdir = '@PERLLIBDIR@';
use constant true => 1;
use constant false => 0;
#
# Some helper subroutines.
#
sub run_editor($$) {
my ($fname, $lineno) = @_;
my $editor = $ENV{"PKGEDITOR"} || $ENV{"EDITOR"} || "vi";
system { $editor } ($editor, "+${lineno}", $fname);
}
sub get_maintainer() {
return $ENV{"PKGMAINTAINER"} || $ENV{"REPLYTO"} || "INSERT_YOUR_MAIL_ADDRESS_HERE";
}
sub print_section($$) {
my ($f, $vars) = @_;
if (scalar(@{$vars}) == 0) {
return;
}
my $width = 0;
foreach my $var (@{$vars}) {
my $len = length($var->[0]);
$width = ($len > $width) ? $len : $width;
}
foreach my $var (@{$vars}) {
my $len = length($var->[0]) + 1;
my $adjlen = (($width + 1 + 1) + 7) &-8;
my $ntabs = (7 + $adjlen - $len) / 8;
printf $f ("%s=%s%s\n", $var->[0], "\t" x $ntabs, $var->[1]);
}
printf $f ("\n");
}
#
# Introduction to the magic_* subroutines.
#
# The following routines are called after the distfiles have been
# downloaded and extracted. They may inspect the extracted files
# to automatically define some variables in the package Makefile.
#
# The following variables may be used in the magic_* subroutines:
# $distname contains the package name, including the version number.
# $abs_wrkdir is an absolute pathname to the working directory, which
# contains the extracted distfiles. $abs_wrksrc is the absolute pathname
# to a subdirectory of $abs_wrkdir, in which you can usually find the
# package-provided Makefiles or configure scripts.
#
# The following lists may be extended by the magic_* routines and
# will later appear in the package Makefile: @depends and @build_depends
# contain the dependencies of the package, in the form
# "package>=version". @includes is a list of pathnames relative to the
# package path. All these files will be included at the bottom of the
# Makefile. @build_vars is a list of [varname, value] items that contain
# variables that will be defined in the fourth paragraph of the package
# Makefile, where the build configuration takes place. The @extra_vars
# are similar to the @build_vars, but separated by an empty line in the
# Makefile. The @todo items are inserted below the second paragraph in
# the Makefile.
#
my ($distname, $abs_wrkdir, $abs_wrksrc);
my (@wrksrc_files, @wrksrc_dirs);
my (@depends, @build_depends, @includes, @build_vars, @extra_vars, @todo);
my ($pkgname);
#
# And now to the real magic_* subroutines.
#
sub magic_configure() {
my $gnu_configure = false;
open(CONF, "<", "${abs_wrksrc}/configure") or return;
while (defined(my $line = <CONF>)) {
if ($line =~ qr"autoconf|Free Software Foundation"i) {
$gnu_configure = true;
last;
}
}
close(CONF);
my $varname = ($gnu_configure ? "GNU_CONFIGURE" : "HAS_CONFIGURE");
push(@build_vars, [$varname, "yes"]);
}
sub magic_gconf2_schemas() {
my @gconf2_files = grep(/schemas(?:\.in.*)$/, @wrksrc_files);
if (@gconf2_files) {
foreach my $f (@gconf2_files) {
if ($f =~ qr"(.*schemas)") {
push(@extra_vars, ["GCONF_SCHEMAS+", $1]);
}
}
push(@includes, "../../devel/GConf/schemas.mk");
}
}
sub magic_libtool() {
if (-f "${abs_wrksrc}/ltconfig" || -f "${abs_wrksrc}/ltmain.sh") {
push(@build_vars, ["USE_LIBTOOL", "yes"]);
}
if (-d "${abs_wrksrc}/libltdl") {
push(@includes, "../../devel/libltdl/convenience.mk");
}
}
sub magic_perlmod() {
if (-f "${abs_wrksrc}/Build.PL") {
# It's a Module::Build module. Dependencies cannot yet be
# extracted automatically.
push(@todo, "Look for the dependencies in Build.PL.");
push(@build_vars, ["PERL5_MODULE_TYPE", "Module::Build"]);
} elsif (-f "${abs_wrksrc}/Makefile.PL") {
open(DEPS, "cd ${abs_wrksrc} && perl -I${perllibdir} Makefile.PL |") or die;
while (defined(my $dep = <DEPS>)) {
chomp($dep);
if ($dep =~ qr"\.\./\.\./") {
# Many Perl modules write other things to
# stdout, so filter them out.
push(@depends, $dep);
}
}
close(DEPS) or die;
} else {
return;
}
my $packlist = $distname;
$packlist =~ s/-[0-9].*//;
$packlist =~ s/-/\//g;
push(@build_vars, ["PERL5_PACKLIST", "auto/${packlist}/.packlist"]);
push(@includes, "../../lang/perl5/module.mk");
$pkgname = "p5-\${DISTNAME}";
}
sub magic_pkg_config() {
my @pkg_config_files = grep { /\.pc\.in$/ && ! /-uninstalled\.pc\.in$/ } @wrksrc_files;
if (@pkg_config_files) {
push(@build_vars, ["USE_TOOLS+", "pkg-config"]);
}
foreach my $f (@pkg_config_files) {
push(@extra_vars, ["PKGCONFIG_OVERRIDE+", $f]);
}
}
sub magic_po() {
if (grep(/\.g?mo$/, @wrksrc_files)) {
push(@build_vars, ["USE_PKGLOCALEDIR", "yes"]);
}
}
sub magic_use_languages() {
my @languages;
grep(/\.(c|xs)$/, @wrksrc_files) and push(@languages, "c");
grep(/\.(cpp|c\+\+|cxx|cc|C)$/, @wrksrc_files) and push(@languages, "c++");
grep(/\.f$/, @wrksrc_files) and push(@languages, "fortran");
my $use_languages = join(" ", @languages);
if ($use_languages eq "") {
$use_languages = "# none";
}
if ($use_languages ne "c") {
push(@build_vars, ["USE_LANGUAGES", $use_languages]);
}
}
#
# Subroutines for generating the initial package and adjusting it after
# the distfiles have been extracted.
#
sub generate_initial_package($) {
my ($url) = @_;
my ($found, $master_site);
my ($master_sites, $distfile, $homepage, $dist_sufx, $category);
$found = false;
open(SITES, "<", "../../mk/fetch/sites.mk") or die;
while (defined(my $line = <SITES>)) {
chomp($line);
if ($line =~ qr"^(MASTER_SITE_.*)\+=") {
$master_site = $1;
} elsif ($line =~ qr"^\t(.*?)(?:\s+\\)$") {
my ($site) = ($1);
if (index($url, $site) == 0) {
$found = true;
if ($url =~ qr"^\Q${site}\E(.+)/([^/]+)$") {
my $subdir = $1;
$distfile = $2;
$master_sites = "\${${master_site}:=${subdir}/}";
if ($master_site eq "MASTER_SITE_SOURCEFORGE") {
$homepage = "http://${subdir}.sourceforge.net/";
} elsif ($master_site eq "MASTER_SITE_GNU") {
$homepage = "http://www.gnu.org/software/${subdir}/";
} else {
$homepage = substr($url, 0, -length($distfile));
}
} else {
$master_sites = "\${${master_site}}";
}
}
}
}
if (!$found) {
if ($url =~ qr"^http://(?:pr)?downloads\.sourceforge\.net/([^/]*)/([^/?]+)(?:\?(?:download|use_mirror=.*))?$") {
my $pkgbase = $1;
$distfile = $2;
$master_sites = "\${MASTER_SITE_SOURCEFORGE:=${pkgbase}/}";
$homepage = "http://${pkgbase}.sourceforge.net/";
$found = true;
}
}
if (!$found) {
if ($url =~ qr"^(.*/)(.*)$") {
($master_sites, $distfile) = ($1, $2);
$homepage = $master_sites;
} else {
die("$0: ERROR: Invalid URL: ${url}\n");
}
}
if ($distfile =~ qr"^(.*)(\.tgz|\.tar\.Z|\.tar\.gz|\.tar\.bz2)$") {
($distname, $dist_sufx) = ($1, $2);
} elsif ($distfile =~ qr"^(.*)(\.[^.]+)$") {
($distname, $dist_sufx) = ($1, $2);
} else {
($distname, $dist_sufx) = ($distfile, "# none");
}
# ignore errors.
rename("Makefile", "Makefile-url2pkg.bak");
`pwd` =~ qr".*/([^/]+)/[^/]+$" or die;
$category = $1;
open(MF, ">", "Makefile") or die;
print MF ("# \$NetBSD" . "\$\n");
print MF ("#\n");
print MF ("\n");
print_section(*MF, [
["DISTNAME", $distname],
["CATEGORIES", $category],
["MASTER_SITES", $master_sites],
($dist_sufx ne ".tar.gz"
? ["EXTRACT_SUFX", $dist_sufx]
: ())
]);
print_section(*MF, [
["MAINTAINER", get_maintainer()],
["HOMEPAGE", $homepage],
["COMMENT", "TODO: Short description of the package"],
["#LICENSE", "# TODO: (see mk/license.mk)"],
]);
print_section(*MF, [
["PKG_DESTDIR_SUPPORT", "user-destdir"],
]);
print MF ("# url2pkg-marker (please do not remove this line.)\n");
print MF (".include \"../../mk/bsd.pkg.mk\"\n");
close(MF) or die;
open(PLIST, ">", "PLIST") or die;
print PLIST ("\@comment \$NetBSD\$\n");
close(PLIST) or die;
open(DI, ">", "distinfo") or die;
close(DI) or die;
open(DESCR, ">", "DESCR") or die;
close(DESCR) or die;
run_editor("Makefile", 5);
print ("url2pkg> Running \"make makesum\" ...\n");
(system { $make } ($make, "makesum")) == 0 or die;
print ("url2pkg> Running \"make extract\" ...\n");
(system { $make } ($make, "extract")) == 0 or die;
}
sub adjust_package_from_extracted_distfiles()
{
my ($seen_marker);
chomp($abs_wrkdir = `${make} show-var VARNAME=WRKDIR`);
#
# Determine the value of WRKSRC.
#
my @files = ();
opendir(WRKDIR, $abs_wrkdir) or die;
while (defined(my $f = readdir(WRKDIR))) {
next if $f =~ qr"^\.";
push(@files, $f);
}
closedir(WRKDIR);
if (@files == 1) {
if ($files[0] ne $distname) {
push(@build_vars, ["WRKSRC", "\${WRKDIR}/$files[0]"]);
}
$abs_wrksrc = "${abs_wrkdir}/$files[0]";
} else {
push(@build_vars, ["WRKSRC", "\${WRKDIR}" .
((@files > 1) ? " # More than one possibility -- please check manually." : "")]);
$abs_wrksrc = $abs_wrkdir;
}
chomp(@wrksrc_files = `cd "${abs_wrksrc}" && find * -type f`);
chomp(@wrksrc_dirs = `cd "${abs_wrksrc}" && find * -type d`);
magic_configure();
magic_gconf2_schemas();
magic_libtool();
magic_perlmod();
magic_pkg_config();
magic_po();
magic_use_languages();
print("url2pkg> Adjusting the Makefile.\n");
open(MF1, "<", "Makefile") or die;
open(MF2, ">", "Makefile-url2pkg.new") or die;
# Copy the user-edited part of the Makefile.
while (defined(my $line = <MF1>)) {
if ($line =~ qr"^# url2pkg-marker\b") {
$seen_marker = true;
last;
}
print MF2 ($line);
# Note: This is not elegant, but works.
if (defined($pkgname) && $line =~ qr"^DISTNAME=(\t+)") {
print MF2 ("PKGNAME=$1${pkgname}\n");
}
}
if (@todo) {
foreach my $todo (@todo) {
print MF2 ("# TODO: ${todo}\n");
}
print MF2 ("\n");
}
my @depend_vars;
foreach my $bd (@build_depends) {
push(@depend_vars, ["BUILD_DEPENDS+", $bd]);
}
foreach my $d (@depends) {
push(@depend_vars, ["DEPENDS+", $d]);
}
print_section(*MF2, \@depend_vars);
print_section(*MF2, \@build_vars);
print_section(*MF2, \@extra_vars);
foreach my $f (@includes) {
print MF2 (".include \"${f}\"\n");
}
# Copy the rest of the user-edited part of the Makefile.
while (defined(my $line = <MF1>)) {
print MF2 ($line);
}
close(MF1);
close(MF2) or die;
if ($seen_marker) {
rename("Makefile-url2pkg.new", "Makefile") or die;
} else {
unlink("Makefile-url2pkg.new");
die("$0: ERROR: didn't find the url2pkg marker in the file.\n");
}
}
sub main() {
my $url;
if (!-f "../../mk/bsd.pkg.mk") {
die("$0 must be run from a package directory (.../pkgsrc/category/package).");
}
my @extract_cookie = <w*/.extract_done>;
if (scalar(@extract_cookie) == 0) {
if (scalar(@ARGV) == 0) {
print("URL: ");
# Pressing Ctrl-D is considered equivalent to
# aborting the process.
if (!defined($url = <STDIN>)) {
print("\n");
print("No URL given -- aborting.\n");
exit(0);
}
} else {
$url = shift(@ARGV);
}
generate_initial_package($url);
} else {
chomp($distname = `${make} show-var VARNAME=DISTNAME`);
}
adjust_package_from_extracted_distfiles();
print("\n");
print("Remember to correct CATEGORIES, HOMEPAGE, COMMENT, and DESCR when you're done!\n");
print("\n");
print("Good luck! (See pkgsrc/doc/pkgsrc.txt for some more help :-)\n");
}
main();