On Wed, 11 Dec 2019 at 15:30:43 +0000, Stuart Henderson wrote:
> The go.port.mk part of this breaks some existing ports e.g. net/dnscontrol,
> net/wireguard-go.
>
Here is a diff against the current ports tree - wireguard-go and dnscontrol
build fine.
I also tested other "MODGO_TYPE={bin,lib}" ports.
As a reminder - the `portgen go` stuff only works for Go projects that don't
import libs that have mixed case module names. Anything that uses something
like https://github.com/BurntSushi/toml will be unable to be "portgen"'d.
diff --git a/infrastructure/bin/portgen b/infrastructure/bin/portgen
index ad5ab17f3cf..b7316d42b64 100755
--- a/infrastructure/bin/portgen
+++ b/infrastructure/bin/portgen
@@ -32,6 +32,7 @@ use lib ( "$portdir/infrastructure/lib",
"$FindBin::Bin/../lib" );
use OpenBSD::PortGen::Port::CPAN;
use OpenBSD::PortGen::Port::PyPI;
use OpenBSD::PortGen::Port::Ruby;
+use OpenBSD::PortGen::Port::Go;
my ( $type, $module ) = @ARGV;
@@ -44,6 +45,8 @@ if ( $type eq 'p5' ) {
$o = OpenBSD::PortGen::Port::PyPI->new();
} elsif ( $type eq 'ruby' ) {
$o = OpenBSD::PortGen::Port::Ruby->new();
+} elsif ( $type eq 'go' ) {
+ $o = OpenBSD::PortGen::Port::Go->new();
} else {
die "unknown module type\n";
}
diff --git a/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm
b/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm
new file mode 100644
index 00000000000..8ef9280a506
--- /dev/null
+++ b/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm
@@ -0,0 +1,225 @@
+# $OpenBSD: Go.pm,v 1.16 2019/05/16 16:01:10 afresh1 Exp $
+#
+# Copyright (c) 2019 Aaron Bieber <[email protected]>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+package OpenBSD::PortGen::Port::Go;
+
+use 5.028;
+use utf8;
+use warnings;
+use strict;
+use warnings qw(FATAL utf8); # fatalize encoding glitches
+use open qw(:std :encoding(UTF-8)); # undeclared streams in UTF-8
+
+use parent 'OpenBSD::PortGen::Port';
+
+use Carp;
+use Cwd;
+use File::Temp qw/ tempdir /;
+use Data::Dumper;
+
+use OpenBSD::PortGen::Dependency;
+
+sub ecosystem_prefix
+{
+ my $self = shift;
+ return '';
+}
+
+sub base_url
+{
+ my $self = shift;
+ return 'https://proxy.golang.org/';
+}
+
+sub get_dist_info
+{
+ my ( $self, $module ) = @_;
+
+ my $json = $self->get_json( $module . '/@latest' );
+ $json->{Name} = ( split '/', $module )[-1];
+ $json->{Module} = $module;
+
+ my %mods;
+ for ( $self->_go_mod_graph($json) ) {
+ my ($direct, $ephemeral) = @{$_};
+
+ for my $d ( $direct, $ephemeral ) {
+ #next if $d->{Module} eq $module;
+ next unless $d->{Version};
+ $mods{ $d->{Module} }{ $d->{Version} } ||= $d;
+ }
+ }
+
+ # Filter dependencies to the one with the highest version
+ foreach my $mod ( sort keys %mods ) {
+ # Sort semver numerically then the rest alphanumeric.
+ # This is overkill for sorting, but I already wrote it
+ my @versions =
+ map { $_->[0] }
+ sort {
+ $a->[1] <=> $b->[1]
+ || $a->[2] <=> $b->[2]
+ || $a->[3] <=> $b->[3]
+ || $a->[4] cmp $b->[4]
+ }
+ map { $_->[1] =~ s/^v//; $_ }
+ map { [ $_, split /[\.-]/, $_, 4 ] }
+ keys %{ $mods{$mod} };
+
+ push @{ $json->{Dist} }, $mods{$mod}{ $versions[-1] };
+ push @{ $json->{Mods} }, map { $mods{$mod}{$_} } @versions;
+ }
+
+ carp Dumper $json;
+
+ return $json;
+}
+
+sub _go_mod_graph
+{
+ my ($self, $json) = @_;
+ my $dir = tempdir(CLEANUP => 1);
+
+ my $mod = $self->get("$json->{Module}/\@v/$json->{Version}.mod");
+ my ($module) = $mod =~ /\bmodule\s+(.*)\n/;
+ $module =~ s/\s+$//;
+ unless ( $json->{Module} eq $module ) {
+ my $msg = "Module $json->{Module} doesn't match $module";
+ warn "$msg\n";
+ croak $msg;
+ }
+
+ {
+ open my $fh, '>', $dir . "/go.mod" or die $!;
+ print $fh $mod;
+ close $fh;
+ }
+
+ my $old_cwd = getcwd();
+ chdir $dir or die "Unable to chdir '$dir': $!";
+
+ my @mods;
+ {
+ # Outputs: "direct_dep ephemeral_dep"
+ local $ENV{GOPATH} = "$dir/go";
+ open my $fh, '-|', qw< go mod graph >
+ or die "Unable to spawn 'go mod path': $!";
+ @mods = readline $fh;
+ close $fh
+ or die "Error closing pipe to 'go mod path': $!";
+ }
+
+ chdir $old_cwd or die "Unable to chdir '$old_cwd': $!";
+
+ chomp @mods;
+
+ # parse the graph into pairs of hashrefs
+ return map { [
+ map {
+ my ($m, $v) = split /@/;
+ { Module => $m, Version => $v };
+ } split /\s/
+ ] } grep { $_ } @mods;
+}
+
+sub get_ver_info
+{
+ my ( $self, $module ) = @_;
+ return $self->get_json( $module . '/@latest' );
+}
+
+sub name_new_port
+{
+ my ( $self, $di ) = @_;
+
+ my $name = $di->{Name};
+ $name = $self->SUPER::name_new_port($name);
+ $name = "go/$name" unless $name =~ m{/};
+
+ return $name;
+}
+
+sub fill_in_makefile
+{
+ my ( $self, $di, $vi ) = @_;
+
+ $self->set_modules('lang/go');
+ $self->set_comment("todo");
+ $self->set_descr("TODO");
+
+ # TODO: License information can be queried from:
+ # https://pkg.go.dev/${di->{MOdule}}?tab=licenses
+ $self->set_license("unknown license");
+
+ $self->set_other( MODGO_MODNAME => $di->{Module} );
+ $self->set_other( MODGO_VERSION => $di->{Version} );
+ $self->set_distname($di->{Name} . '-${MODGO_VERSION}');
+
+ my @parts = split("-", $di->{Version});
+ if (@parts > 1) {
+ $self->set_pkgname($di->{Name} . "-" . $parts[1])
+ if $parts[1] =~ m/\d{6}/;
+ } else {
+ $parts[0] =~ s/^v//;
+ $self->set_pkgname($di->{Name} . "-" . $parts[0]);
+ }
+
+ my @dist = map { [ $_->{Module}, $_->{Version} ] }
+ @{ $di->{Dist} || [] };
+ my @mods = map { [ $_->{Module}, $_->{Version} ] }
+ @{ $di->{Mods} };
+
+ # Turn the deps into tab separated columns
+ foreach my $s ( \@dist, \@mods ) {
+ next unless @{$s}; # if there aren't any, don't try
+ my ($length) = sort { $b <=> $a } map { length $_->[0] } @$s;
+ my $n = ( 1 + int $length / 8 );
+ @{$s} = map {
+ ( my $m = $_->[0] ) =~ s/\p{Upper}/!\L$&/g;
+ $m =~ s/[^\w\/\.]/sprintf "%%%02x", ord $&/ge;
+ my $tabs = "\t" x ( $n - int( length($m) / 8 ) );
+ "$m$tabs $_->[1]"
+ } @{$s};
+ }
+
+ carp Dumper \@mods;
+ $self->set_other( MODGO_MODULES => \@dist ) if @dist;
+ $self->set_other( MODGO_MODFILES => \@mods ) if @mods;
+}
+
+sub try_building
+{
+ my $self = shift;
+ $self->make_fake();
+}
+
+sub postextract
+{
+}
+
+sub get_deps
+{
+ my ( $self, $di, $wrksrc ) = @_;
+ my $deps = OpenBSD::PortGen::Dependency->new();
+
+ return $deps->format;
+}
+
+sub get_config_style
+{
+}
+
+1;
diff --git a/infrastructure/templates/Makefile.template
b/infrastructure/templates/Makefile.template
index 6be8b86b3ea..2ebf2d37880 100644
--- a/infrastructure/templates/Makefile.template
+++ b/infrastructure/templates/Makefile.template
@@ -22,7 +22,13 @@ COMMENT = ???
#
#MODPY_EGG_VERSION = ???
+# MODGO_MODNAME should be set to the 'module' specified in the 'go.mod' file.
+#MODGO_MODNAME = github.com/test/app
#
+# Version of port if using lang/go and MODGO_MODULES
+#
+#MODGO_VERSION = 0.1.1
+
# What port/package will be created
#
# DISTNAME should not include suffix (like .tar.gz .tgz .tar.bz2 etc.)
@@ -125,6 +131,15 @@ MASTER_SITES = ???
# If port is python3 only
#MODPY_VERSION = ${MODPY_DEFAULT_VERSION_3}
+#
+# MODGO_ settings for when using lang/go module
+#
+# Get source from proxy.golang.org
+#MODGO_MODULES = modulename version
+# These are needed for dependency resolution. We don't actually need the
+# coresponding code
+#MODGO_MODFILES = modulename version
+
# Dependencies
#BUILD_DEPENDS = ???
#RUN_DEPENDS = ???
diff --git a/lang/go/go.port.mk b/lang/go/go.port.mk
index 983c3990706..908b3f2426c 100644
--- a/lang/go/go.port.mk
+++ b/lang/go/go.port.mk
@@ -4,6 +4,13 @@ ONLY_FOR_ARCHS ?= ${GO_ARCHS}
MODGO_BUILDDEP ?= Yes
+MODGO_DIST_SUBDIR ?= go_modules
+
+MASTER_SITE_ATHENS = https://proxy.golang.org/
+
+MODGO_MASTER_SITESN = 9
+MASTER_SITES${MODGO_MASTER_SITESN} ?= ${MASTER_SITE_ATHENS}
+
MODGO_RUN_DEPENDS = lang/go
MODGO_BUILD_DEPENDS = lang/go
@@ -33,17 +40,12 @@ MODGO_TYPE ?= bin
MODGO_WORKSPACE ?= ${WRKDIR}/go
MODGO_GOCACHE ?= ${WRKDIR}/go-cache
MODGO_GOPATH ?= ${MODGO_WORKSPACE}:${MODGO_PACKAGE_PATH}
-MAKE_ENV += GOCACHE="${MODGO_GOCACHE}" \
- GOPATH="${MODGO_GOPATH}" \
- GO111MODULE=off
# We cannot assume that the maching running the built code will have SSE,
# even though the machine building the package has SSE. As such, we need
# to explicitly disable SSE on i386 builds.
MAKE_ENV += GO386=387
-# Ports are not allowed to fetch from the network at build time; point
-# GOPROXY at an unreachable host so that failures are also visible to
-# developers who don't have PORTS_PRIVSEP and a "deny .. _pbuild" PF rule.
-MAKE_ENV += GOPROXY=invalid://ports.should.not.fetch.at.buildtime/
+MAKE_ENV += GOCACHE="${MODGO_GOCACHE}"
+
MODGO_CMD ?= ${SETENV} ${MAKE_ENV} go
MODGO_BUILD_CMD = ${MODGO_CMD} install ${MODGO_FLAGS}
MODGO_TEST_CMD = ${MODGO_CMD} test ${MODGO_FLAGS} ${MODGO_TEST_FLAGS}
@@ -54,15 +56,34 @@ MODGO_BUILD_CMD += -ldflags="${MODGO_LDFLAGS}"
MODGO_TEST_CMD += -ldflags="${MODGO_LDFLAGS}"
.endif
-.if defined(GH_ACCOUNT) && defined(GH_PROJECT)
-ALL_TARGET ?= github.com/${GH_ACCOUNT}/${GH_PROJECT}
+.if defined(MODGO_MODNAME)
+EXTRACT_SUFX ?= .zip
+PKGNAME ?= ${DISTNAME:S/-v/-/}
+ALL_TARGET ?= ${MODGO_MODNAME}
+DISTFILES =
${DISTNAME}${EXTRACT_SUFX}{${MODGO_VERSION}${EXTRACT_SUFX}}
+MASTER_SITES ?= ${MASTER_SITE_ATHENS}${MODGO_MODNAME}/@v/
+. for _modname _modver in ${MODGO_MODULES}
+SUPDISTFILES +=
${MODGO_DIST_SUBDIR}/${_modname}/@v/${_modver}.zip{${_modname}/@v/${_modver}.zip}:${MODGO_MASTER_SITESN}
+. endfor
+. for _modname _modver in ${MODGO_MODFILES}
+SUPDISTFILES +=
${MODGO_DIST_SUBDIR}/${_modname}/@v/${_modver}.mod{${_modname}/@v/${_modver}.mod}:${MODGO_MASTER_SITESN}
+. endfor
+MAKE_ENV += GOPROXY=file://${DISTDIR}/${MODGO_DIST_SUBDIR}
+MAKE_ENV += GO111MODULE=on GOPATH="${MODGO_GOPATH}"
+.else
+# ports are not allowed to fetch from the network at build time; point
+# GOPROXY at an unreachable host so that failures are also visible to
+# developers who don't have PORTS_PRIVSEP and a "deny .. _pbuild" PF rule.
+MAKE_ENV += GOPROXY=invalid://ports.should.not.fetch.at.buildtime/
+MAKE_ENV += GO111MODULE=off GOPATH="${MODGO_GOPATH}"
+. if defined(GH_ACCOUNT) && defined(GH_PROJECT)
+ALL_TARGET ?= github.com/${GH_ACCOUNT}/${GH_PROJECT}
+. endif
.endif
-TEST_TARGET ?= ${ALL_TARGET}
-SEPARATE_BUILD ?= Yes
-WRKSRC ?= ${MODGO_WORKSPACE}/src/${ALL_TARGET}
+MODGO_TEST_TARGET ?= cd ${WRKSRC} && ${MODGO_CMD} test ${ALL_TARGET}
-MODGO_SETUP_WORKSPACE = mkdir -p ${WRKSRC:H}; mv ${MODGO_SUBDIR}
${WRKSRC};
+SEPARATE_BUILD ?= Yes
CATEGORIES += lang/go
@@ -76,6 +97,14 @@ MODGO_LDFLAGS += -s -w
MODGO_FLAGS += -x
.endif
+.if empty(MODGO_MODNAME)
+WRKSRC ?= ${MODGO_WORKSPACE}/src/${ALL_TARGET}
+MODGO_SETUP_WORKSPACE = mkdir -p ${WRKSRC:H}; mv ${MODGO_SUBDIR}
${WRKSRC};
+.else
+WRKSRC ?= ${WRKDIR}/${MODGO_MODNAME}@${MODGO_VERSION}
+MODGO_SETUP_WORKSPACE = ln -sf ${WRKSRC} ${WRKDIR}/${MODGO_MODNAME}
+.endif
+
INSTALL_STRIP =
.if ${MODGO_TYPE:L:Mbin}
MODGO_INSTALL_TARGET = ${INSTALL_PROGRAM_DIR} ${PREFIX}/${MODGO_BINDIR} && \
@@ -99,14 +128,13 @@ MODGO_INSTALL_TARGET += ${INSTALL_DATA_DIR}
${MODGO_PACKAGE_PATH} && \
RUN_DEPENDS += ${MODGO_RUN_DEPENDS}
.endif
-MODGO_TEST_TARGET = ${MODGO_TEST_CMD} ${TEST_TARGET}
-
.if empty(CONFIGURE_STYLE)
MODGO_pre-configure += ${MODGO_SETUP_WORKSPACE}
. if !target(do-build)
do-build:
- ${MODGO_BUILD_TARGET}
+ cd ${WRKSRC} && \
+ ${MODGO_BUILD_TARGET}
. endif
. if !target(do-install)
--
PGP: 0x1F81112D62A9ADCE / 3586 3350 BFEA C101 DB1A 4AF0 1F81 112D 62A9 ADCE