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