Annotation of pkgsrc/pkgtools/url2pkg/files/url2pkg.pl, Revision 1.36
1.1 rillig 1: #! @PERL@
1.36 ! rillig 2: # $NetBSD: url2pkg.pl,v 1.35 2018/01/07 11:20:18 rillig Exp $
1.1 rillig 3: #
4:
1.16 rillig 5: # Copyright (c) 2010 The NetBSD Foundation, Inc.
6: # All rights reserved.
7: #
8: # This code is derived from software contributed to The NetBSD Foundation
9: # by Roland Illig.
10: #
11: # Redistribution and use in source and binary forms, with or without
12: # modification, are permitted provided that the following conditions
13: # are met:
14: # 1. Redistributions of source code must retain the above copyright
15: # notice, this list of conditions and the following disclaimer.
16: # 2. Redistributions in binary form must reproduce the above copyright
17: # notice, this list of conditions and the following disclaimer in the
18: # documentation and/or other materials provided with the distribution.
19: # 3. All advertising materials mentioning features or use of this software
20: # must display the following acknowledgement:
21: # This product includes software developed by the NetBSD
22: # Foundation, Inc. and its contributors.
23: # 4. Neither the name of The NetBSD Foundation nor the names of its
24: # contributors may be used to endorse or promote products derived
25: # from this software without specific prior written permission.
26: #
27: # THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: # ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: # POSSIBILITY OF SUCH DAMAGE.
38:
1.25 rodent 39: use feature qw{ switch };
1.1 rillig 40: use strict;
41: use warnings;
42:
43: #
44: # Build-time Configuration.
45: #
46:
47: my $make = '@MAKE@';
48: my $perllibdir = '@PERLLIBDIR@';
49:
50: use constant true => 1;
51: use constant false => 0;
52:
53: #
54: # Some helper subroutines.
55: #
56:
57: sub run_editor($$) {
58: my ($fname, $lineno) = @_;
59:
60: my $editor = $ENV{"PKGEDITOR"} || $ENV{"EDITOR"} || "vi";
61:
62: system { $editor } ($editor, "+${lineno}", $fname);
63: }
64:
65: sub get_maintainer() {
66:
67: return $ENV{"PKGMAINTAINER"} || $ENV{"REPLYTO"} || "INSERT_YOUR_MAIL_ADDRESS_HERE";
68: }
69:
70: sub print_section($$) {
71: my ($f, $vars) = @_;
72:
73: if (scalar(@{$vars}) == 0) {
74: return;
75: }
76:
77: my $width = 0;
78: foreach my $var (@{$vars}) {
1.36 ! rillig 79: my $varname = $var->[0];
! 80: my $len = (length("$varname= ") + 7) & -8;
1.1 rillig 81: $width = ($len > $width) ? $len : $width;
82: }
83:
84: foreach my $var (@{$vars}) {
1.36 ! rillig 85: my ($varname, $varvalue) = @$var;
! 86: my $ntabs = ($width - length("$varname=") + 7) / 8;
! 87: printf $f ("%s=%s%s\n", $varname, "\t" x $ntabs, $varvalue);
1.1 rillig 88: }
89: printf $f ("\n");
90: }
91:
1.35 rillig 92: # The following magic_* subroutines are called after the distfiles have
93: # been downloaded and extracted. They inspect the extracted files
1.1 rillig 94: # to automatically define some variables in the package Makefile.
95: #
96: # The following variables may be used in the magic_* subroutines:
1.35 rillig 97: #
98: # $distname
99: # contains the package name, including the version number.
100: # $abs_wrkdir
101: # the absolute pathname to the working directory, containing
102: # the extracted distfiles.
103: # $abs_wrksrc
104: # the absolute pathname to a subdirectory of $abs_wrkdir,
105: # typically containing package-provided Makefiles or configure
106: # scripts.
1.1 rillig 107: #
108: # The following lists may be extended by the magic_* routines and
1.35 rillig 109: # will later appear in the package Makefile:
1.1 rillig 110: #
1.35 rillig 111: # @depends
112: # @build_depends
113: # the dependencies of the package, in the form "package>=version".
114: # @includes
115: # a list of pathnames relative to the package path.
116: # All these files will be included at the bottom of the Makefile.
117: # @build_vars
118: # a list of [varname, value] items that contain variables that
119: # will be defined in the fourth paragraph of the package Makefile,
120: # where the build configuration takes place.
121: # @extra_vars
122: # similar to the @build_vars, but separated by an empty line in
123: # the Makefile, therefore forming the fifth paragraph.
124: # @todo
125: # these are inserted below the second paragraph in the Makefile.
1.1 rillig 126:
127: my ($distname, $abs_wrkdir, $abs_wrksrc);
1.3 rillig 128: my (@wrksrc_files, @wrksrc_dirs);
1.1 rillig 129: my (@depends, @build_depends, @includes, @build_vars, @extra_vars, @todo);
130: my ($pkgname);
1.27 rodent 131: my ($dist_subdir);
1.1 rillig 132:
133: #
134: # And now to the real magic_* subroutines.
135: #
136:
137: sub magic_configure() {
138: my $gnu_configure = false;
139:
140: open(CONF, "<", "${abs_wrksrc}/configure") or return;
141: while (defined(my $line = <CONF>)) {
142: if ($line =~ qr"autoconf|Free Software Foundation"i) {
143: $gnu_configure = true;
144: last;
145: }
146: }
147: close(CONF);
148:
149: my $varname = ($gnu_configure ? "GNU_CONFIGURE" : "HAS_CONFIGURE");
150: push(@build_vars, [$varname, "yes"]);
151: }
152:
1.18 cheusov 153: sub magic_cmake() {
154: open(CONF, "<", "${abs_wrksrc}/CMakeLists.txt") or return;
155: close(CONF);
156:
157: push(@build_vars, ["USE_CMAKE", "yes"]);
158: }
159:
1.1 rillig 160: sub magic_gconf2_schemas() {
1.3 rillig 161: my @gconf2_files = grep(/schemas(?:\.in.*)$/, @wrksrc_files);
162: if (@gconf2_files) {
163: foreach my $f (@gconf2_files) {
164: if ($f =~ qr"(.*schemas)") {
1.11 wiz 165: push(@extra_vars, ["GCONF_SCHEMAS+", $1]);
1.3 rillig 166: }
1.1 rillig 167: }
1.10 wiz 168: push(@includes, "../../devel/GConf/schemas.mk");
1.1 rillig 169: }
170: }
171:
172: sub magic_libtool() {
173: if (-f "${abs_wrksrc}/ltconfig" || -f "${abs_wrksrc}/ltmain.sh") {
174: push(@build_vars, ["USE_LIBTOOL", "yes"]);
175: }
176: if (-d "${abs_wrksrc}/libltdl") {
177: push(@includes, "../../devel/libltdl/convenience.mk");
178: }
179: }
180:
181: sub magic_perlmod() {
182: if (-f "${abs_wrksrc}/Build.PL") {
183:
184: # It's a Module::Build module. Dependencies cannot yet be
185: # extracted automatically.
186: push(@todo, "Look for the dependencies in Build.PL.");
187:
188: push(@build_vars, ["PERL5_MODULE_TYPE", "Module::Build"]);
189:
190: } elsif (-f "${abs_wrksrc}/Makefile.PL") {
1.23 ryoon 191: # To avoid fix_up_makefile error, generate Makefile previously.
192: # Ignore exit status (no "or die").
193: system("cd ${abs_wrksrc} && perl Makefile.PL");
1.1 rillig 194: open(DEPS, "cd ${abs_wrksrc} && perl -I${perllibdir} Makefile.PL |") or die;
195: while (defined(my $dep = <DEPS>)) {
196: chomp($dep);
1.2 rillig 197: if ($dep =~ qr"\.\./\.\./") {
198: # Many Perl modules write other things to
199: # stdout, so filter them out.
200: push(@depends, $dep);
201: }
1.1 rillig 202: }
203: close(DEPS) or die;
204:
205: } else {
206: return;
207: }
208:
209: my $packlist = $distname;
210: $packlist =~ s/-[0-9].*//;
211: $packlist =~ s/-/\//g;
212: push(@build_vars, ["PERL5_PACKLIST", "auto/${packlist}/.packlist"]);
213: push(@includes, "../../lang/perl5/module.mk");
214: $pkgname = "p5-\${DISTNAME}";
215: }
216:
217: sub magic_pkg_config() {
1.3 rillig 218: my @pkg_config_files = grep { /\.pc\.in$/ && ! /-uninstalled\.pc\.in$/ } @wrksrc_files;
219: if (@pkg_config_files) {
1.1 rillig 220: push(@build_vars, ["USE_TOOLS+", "pkg-config"]);
221: }
1.3 rillig 222: foreach my $f (@pkg_config_files) {
1.1 rillig 223: push(@extra_vars, ["PKGCONFIG_OVERRIDE+", $f]);
224: }
225: }
226:
227: sub magic_po() {
1.3 rillig 228: if (grep(/\.g?mo$/, @wrksrc_files)) {
1.1 rillig 229: push(@build_vars, ["USE_PKGLOCALEDIR", "yes"]);
230: }
231: }
232:
233: sub magic_use_languages() {
1.2 rillig 234: my @languages;
1.1 rillig 235:
1.7 rillig 236: grep(/\.(c|xs)$/, @wrksrc_files) and push(@languages, "c");
1.3 rillig 237: grep(/\.(cpp|c\+\+|cxx|cc|C)$/, @wrksrc_files) and push(@languages, "c++");
238: grep(/\.f$/, @wrksrc_files) and push(@languages, "fortran");
1.1 rillig 239:
1.2 rillig 240: my $use_languages = join(" ", @languages);
1.1 rillig 241: if ($use_languages eq "") {
242: $use_languages = "# none";
243: }
244: if ($use_languages ne "c") {
245: push(@build_vars, ["USE_LANGUAGES", $use_languages]);
246: }
247: }
248:
249: #
250: # Subroutines for generating the initial package and adjusting it after
251: # the distfiles have been extracted.
252: #
253:
254: sub generate_initial_package($) {
255: my ($url) = @_;
256: my ($found, $master_site);
257: my ($master_sites, $distfile, $homepage, $dist_sufx, $category);
1.27 rodent 258: my ($gh_project, $gh_tag, $gh_release);
1.1 rillig 259:
260: $found = false;
261: open(SITES, "<", "../../mk/fetch/sites.mk") or die;
262: while (defined(my $line = <SITES>)) {
263: chomp($line);
264:
265: if ($line =~ qr"^(MASTER_SITE_.*)\+=") {
266: $master_site = $1;
267:
268: } elsif ($line =~ qr"^\t(.*?)(?:\s+\\)$") {
269: my ($site) = ($1);
270:
271: if (index($url, $site) == 0) {
272: $found = true;
273:
274: if ($url =~ qr"^\Q${site}\E(.+)/([^/]+)$") {
275: my $subdir = $1;
276: $distfile = $2;
277:
278: $master_sites = "\${${master_site}:=${subdir}/}";
279: if ($master_site eq "MASTER_SITE_SOURCEFORGE") {
280: $homepage = "http://${subdir}.sourceforge.net/";
281: } elsif ($master_site eq "MASTER_SITE_GNU") {
282: $homepage = "http://www.gnu.org/software/${subdir}/";
283: } else {
284: $homepage = substr($url, 0, -length($distfile));
285: }
286: } else {
287: $master_sites = "\${${master_site}}";
288: }
289: }
290: }
291: }
292:
293: if (!$found) {
1.8 rillig 294: if ($url =~ qr"^http://(?:pr)?downloads\.sourceforge\.net/([^/]*)/([^/?]+)(?:\?(?:download|use_mirror=.*))?$") {
1.1 rillig 295: my $pkgbase = $1;
296: $distfile = $2;
297:
298: $master_sites = "\${MASTER_SITE_SOURCEFORGE:=${pkgbase}/}";
299: $homepage = "http://${pkgbase}.sourceforge.net/";
300: $found = true;
301: }
302: }
303:
304: if (!$found) {
1.18 cheusov 305: if ($url =~ qr"^http://([^.]*).googlecode\.com/files/(.*$)") {
306: my $pkgbase = $1;
307: $distfile = $2;
308: $master_sites = "http://${pkgbase}.googlecode.com/files/";
309: $homepage = "http://code.google.com/p/${pkgbase}/";
310: $found = true;
311: }
312: }
313:
314: if (!$found) {
1.27 rodent 315: if ($url =~ qr"^https?://github\.com/") {
316: if ($url =~ qr"^https?://github\.com/(.*)/(.*)/archive/(.*)(\.tar\.gz|\.zip)$") {
317: $master_sites = "\${MASTER_SITE_GITHUB:=$1/}";
1.33 wiz 318: $homepage = "https://github.com/$1/$2/";
1.27 rodent 319: $gh_project = $2;
320: $gh_tag = $3;
321: if (index($gh_tag, $gh_project) == -1 ) {
322: $pkgname = '${GITHUB_PROJECT}-${DISTNAME}';
323: $dist_subdir = '${GITHUB_PROJECT}';
324: }
325: $distfile = "$3$4";
326: $found = true;
327: } elsif ($url =~ qr"^https?://github\.com/(.*)/(.*)/releases/download/(.*)/(.*)(\.tar\.gz|\.zip)$") {
328: $master_sites = "\${MASTER_SITE_GITHUB:=$1/}";
1.34 wiz 329: $homepage = "https://github.com/$1/$2/";
1.27 rodent 330: if (index($4, $2) == -1) {
331: $gh_project = $2;
332: $dist_subdir = '${GITHUB_PROJECT}';
333: }
334: if ($3 eq $4) {
335: $gh_release = '${DISTNAME}';
336: } else {
337: $gh_release = $3;
338: }
339: $distfile = "$4$5";
340: $found = true;
341: } else {
1.30 wiz 342: print("$0: ERROR: Invalid GitHub URL: ${url}, handling as normal URL\n");
1.27 rodent 343: }
1.29 wiz 344: } else {
345: $gh_project = ""; $gh_release = ""; $dist_subdir = "";
1.27 rodent 346: }
347: }
348:
349: if (!$found) {
1.1 rillig 350: if ($url =~ qr"^(.*/)(.*)$") {
351: ($master_sites, $distfile) = ($1, $2);
352: $homepage = $master_sites;
353: } else {
354: die("$0: ERROR: Invalid URL: ${url}\n");
355: }
356: }
357:
1.21 ryoon 358: if ($distfile =~ qr"^(.*)(\.tgz|\.tar\.Z|\.tar\.gz|\.tar\.bz2|\.tar\.xz|\.tar\.7z)$") {
1.1 rillig 359: ($distname, $dist_sufx) = ($1, $2);
360: } elsif ($distfile =~ qr"^(.*)(\.[^.]+)$") {
361: ($distname, $dist_sufx) = ($1, $2);
362: } else {
363: ($distname, $dist_sufx) = ($distfile, "# none");
364: }
365:
366: # ignore errors.
367: rename("Makefile", "Makefile-url2pkg.bak");
368:
369: `pwd` =~ qr".*/([^/]+)/[^/]+$" or die;
370: $category = $1;
371:
372: open(MF, ">", "Makefile") or die;
1.17 joerg 373: print MF ("# \$Net" . "BSD\$\n");
1.1 rillig 374: print MF ("\n");
375: print_section(*MF, [
1.27 rodent 376: (($gh_project ne "")
377: ? ["GITHUB_PROJECT", $gh_project]
378: : ()),
1.1 rillig 379: ["DISTNAME", $distname],
380: ["CATEGORIES", $category],
381: ["MASTER_SITES", $master_sites],
1.27 rodent 382: (($gh_release ne "")
383: ? ["GITHUB_RELEASE", $gh_release]
384: : ()),
1.25 rodent 385: (($dist_sufx ne ".tar.gz" && $dist_sufx ne ".gem")
1.1 rillig 386: ? ["EXTRACT_SUFX", $dist_sufx]
1.27 rodent 387: : ()),
388: (($dist_subdir ne "")
389: ? ["DIST_SUBDIR", $dist_subdir]
1.1 rillig 390: : ())
391: ]);
392: print_section(*MF, [
393: ["MAINTAINER", get_maintainer()],
394: ["HOMEPAGE", $homepage],
1.14 rillig 395: ["COMMENT", "TODO: Short description of the package"],
396: ["#LICENSE", "# TODO: (see mk/license.mk)"],
397: ]);
1.1 rillig 398: print MF ("# url2pkg-marker (please do not remove this line.)\n");
399: print MF (".include \"../../mk/bsd.pkg.mk\"\n");
400: close(MF) or die;
401:
402: open(PLIST, ">", "PLIST") or die;
1.17 joerg 403: print PLIST ("\@comment \$Net" . "BSD\$\n");
1.1 rillig 404: close(PLIST) or die;
405:
406: open(DESCR, ">", "DESCR") or die;
407: close(DESCR) or die;
408:
409: run_editor("Makefile", 5);
410:
1.15 rillig 411: print ("url2pkg> Running \"make distinfo\" ...\n");
412: (system { $make } ($make, "distinfo")) == 0 or die;
1.1 rillig 413:
414: print ("url2pkg> Running \"make extract\" ...\n");
415: (system { $make } ($make, "extract")) == 0 or die;
416: }
417:
418: sub adjust_package_from_extracted_distfiles()
419: {
420: my ($seen_marker);
421:
422: chomp($abs_wrkdir = `${make} show-var VARNAME=WRKDIR`);
423:
424: #
425: # Determine the value of WRKSRC.
426: #
427: my @files = ();
428: opendir(WRKDIR, $abs_wrkdir) or die;
429: while (defined(my $f = readdir(WRKDIR))) {
1.26 schmonz 430: no if $] >= 5.018, warnings => "experimental::smartmatch";
1.25 rodent 431: given ($f) {
432: next when qr"^\.";
433: next when 'pax_global_header';
1.28 rodent 434: next when 'package.xml';
1.25 rodent 435: next when qr".*\.gemspec";
436: default { push(@files, $f) }
437: }
1.1 rillig 438: }
439: closedir(WRKDIR);
440: if (@files == 1) {
441: if ($files[0] ne $distname) {
442: push(@build_vars, ["WRKSRC", "\${WRKDIR}/$files[0]"]);
443: }
444: $abs_wrksrc = "${abs_wrkdir}/$files[0]";
445: } else {
1.5 rillig 446: push(@build_vars, ["WRKSRC", "\${WRKDIR}" .
447: ((@files > 1) ? " # More than one possibility -- please check manually." : "")]);
1.1 rillig 448: $abs_wrksrc = $abs_wrkdir;
449: }
450:
1.4 rillig 451: chomp(@wrksrc_files = `cd "${abs_wrksrc}" && find * -type f`);
452: chomp(@wrksrc_dirs = `cd "${abs_wrksrc}" && find * -type d`);
1.3 rillig 453:
1.1 rillig 454: magic_configure();
1.18 cheusov 455: magic_cmake();
1.1 rillig 456: magic_gconf2_schemas();
457: magic_libtool();
458: magic_perlmod();
459: magic_pkg_config();
460: magic_po();
461: magic_use_languages();
462:
463: print("url2pkg> Adjusting the Makefile.\n");
464:
465: open(MF1, "<", "Makefile") or die;
466: open(MF2, ">", "Makefile-url2pkg.new") or die;
467:
468: # Copy the user-edited part of the Makefile.
469: while (defined(my $line = <MF1>)) {
470: if ($line =~ qr"^# url2pkg-marker\b") {
471: $seen_marker = true;
472: last;
473: }
474: print MF2 ($line);
475:
476: # Note: This is not elegant, but works.
477: if (defined($pkgname) && $line =~ qr"^DISTNAME=(\t+)") {
478: print MF2 ("PKGNAME=$1${pkgname}\n");
479: }
480: }
481:
1.3 rillig 482: if (@todo) {
1.1 rillig 483: foreach my $todo (@todo) {
484: print MF2 ("# TODO: ${todo}\n");
485: }
486: print MF2 ("\n");
487: }
488:
489: my @depend_vars;
490: foreach my $bd (@build_depends) {
491: push(@depend_vars, ["BUILD_DEPENDS+", $bd]);
492: }
493: foreach my $d (@depends) {
494: push(@depend_vars, ["DEPENDS+", $d]);
495: }
496: print_section(*MF2, \@depend_vars);
497:
498: print_section(*MF2, \@build_vars);
499: print_section(*MF2, \@extra_vars);
500:
501: foreach my $f (@includes) {
502: print MF2 (".include \"${f}\"\n");
503: }
504:
505: # Copy the rest of the user-edited part of the Makefile.
506: while (defined(my $line = <MF1>)) {
507: print MF2 ($line);
508: }
509:
510: close(MF1);
511: close(MF2) or die;
512: if ($seen_marker) {
513: rename("Makefile-url2pkg.new", "Makefile") or die;
514: } else {
515: unlink("Makefile-url2pkg.new");
516: die("$0: ERROR: didn't find the url2pkg marker in the file.\n");
517: }
518: }
519:
520: sub main() {
521: my $url;
522:
523: if (!-f "../../mk/bsd.pkg.mk") {
1.32 rillig 524: die("ERROR: $0 must be run from a package directory (.../pkgsrc/category/package).\n");
1.1 rillig 525: }
526:
527: my @extract_cookie = <w*/.extract_done>;
528: if (scalar(@extract_cookie) == 0) {
529: if (scalar(@ARGV) == 0) {
530: print("URL: ");
1.4 rillig 531: # Pressing Ctrl-D is considered equivalent to
532: # aborting the process.
533: if (!defined($url = <STDIN>)) {
534: print("\n");
535: print("No URL given -- aborting.\n");
536: exit(0);
537: }
1.1 rillig 538: } else {
539: $url = shift(@ARGV);
540: }
541:
542: generate_initial_package($url);
543: } else {
544: chomp($distname = `${make} show-var VARNAME=DISTNAME`);
545: }
546:
547: adjust_package_from_extracted_distfiles();
548:
549: print("\n");
550: print("Remember to correct CATEGORIES, HOMEPAGE, COMMENT, and DESCR when you're done!\n");
551: print("\n");
552: print("Good luck! (See pkgsrc/doc/pkgsrc.txt for some more help :-)\n");
553: }
554:
555: main();
CVSweb <webmaster@jp.NetBSD.org>