Aaron Bieber writes:

> Hola,
>
> This change addresses a few issues, the most important being missing
> dependencies. Now we use 'go list -m all' to get a list of "hard" deps
> (hard meaning we need the actual code [.zip files] to build the
> package).
>
> The list created by 'go mod graph' is now pruned to exclude the list
> from 'go list' and is treated as the source of .mod files (needed for go
> to re-calculate the build dependencies).
>
> It also:
>    - De-duplicates the MODGO_MOD* lists so Makefiles are no longer 3k
>      lines long!
>    - Puts the chdir stuff into a child process (requested by espie@).
>    - Puts MODGO_MOD{ULES,FILES} values on a new line so less space is
>      used (also requested by espie@).
>    - Reduces the quality of the perl used (sorry afresh1@ <3).
>
> Now things like 'github.com/gruntwork-io/terragrunt' and
> 'github.com/coredns/coredns` are able to be portgen'd!
>
> OK?
>
> Cheers,
> Aaron
>

Previous version suffered from some issues. It didn't handle redirects (
https://github.com/gohugoio/hugo/blob/master/go.mod#L71 ) and the map{}
bits were hard to debug.

This version reduces the # of lines in www/hugo from 658 to 403!

diff --git a/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm b/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm
index 96e81252dcf..4089df3edc9 100644
--- a/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm
+++ b/infrastructure/lib/OpenBSD/PortGen/Port/Go.pm
@@ -91,90 +91,124 @@ sub get_dist_info
 	my ( $self, $module ) = @_;
 
 	my $json = $self->_go_determine_name($module);
+	my ($dist, $mods) = $self->_go_mod_info($json);
+	$json->{License} = $self->_go_lic_info($module);
 
-	my %mods;
-	for ( $self->_go_mod_graph($json) ) {
-		my ($direct, $ephemeral) = @{$_};
+	$json->{Dist} = $dist if @$dist > 0;
+	$json->{Mods} = $mods if @$mods > 0;
 
-		for my $d ( $direct, $ephemeral ) {
-			next unless $d->{Version};
-			$mods{ $d->{Module} }{ $d->{Version} } ||= $d;
-		}
-	}
+	return $json;
+}
+
+sub _run
+{
+	my ($self, $cmd, $dir) = @_;
+	my $fh;
 
-	# 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;
+	my $pid = open($fh, "-|");
+	if (!defined $pid) {
+		 die "unable to fork";
 	}
 
-	$json->{License} = $self->_go_lic_info($module);
+	if ($pid == 0) {
+		chdir $dir or die "Unable to chdir '$dir': $!";
+		$ENV{GOPATH} = "$dir/go";
+		$ENV{GO111MODULE} = "on";
+		# Outputs: "dep version"
+		exec ($cmd);
+		die "exec didn't work: $!";
+	}
 
-	return $json;
+	my @output = <$fh>;
+	chomp @output;
+	close $fh or die "Unable to close pipe '$cmd': $!";
+	return @output;
 }
 
-sub _go_mod_graph
+sub _go_mod_info
 {
 	my ($self, $json) = @_;
 	my $dir = tempdir(CLEANUP => 0);
 
 	my $mod = $self->get("$json->{Module}/\@v/$json->{Version}.mod");
 	my ($module) = $mod =~ /\bmodule\s+(.*?)\s/;
-	#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;
+	open my $fh, '>', $dir . "/go.mod" or die $!;
+	print $fh $mod;
+	close $fh;
+
+	# Outputs: "dep version"
+	my @raw_deps = $self->_run("go list -m all", $dir);
+	my @deps;
+	my $all_deps = {};
+	foreach my $dep (@raw_deps) {
+		next if $dep eq $json->{Module};
+		if ($dep =~ m/=>/) {
+			foreach my $d (split(/ => /, $dep)) {
+				my $smod = $self->_go_mod_normalize($d);
+				push @deps, $smod unless defined $all_deps->{$smod};
+				$all_deps->{$smod} = 1;
+			}
+		} else {
+			my $nmod = $self->_go_mod_normalize($dep);
+			push @deps, $nmod unless defined $all_deps->{$nmod};
+			$all_deps->{$nmod} = 1;
+		}
 	}
 
-	my $old_cwd = getcwd();
-	chdir $dir or die "Unable to chdir '$dir': $!";
-
+	# Outputs: "dep@version subdep@version"
+	my @raw_mods =  $self->_run("go mod graph", $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': $!";
+
+	foreach my $mod (@raw_mods) {
+		carp Dumper $mod if ($mod =~ m/markbates/);
+		foreach my $m (split(/ /, $mod)) {
+			$m =~ s/@/ /;
+			$m = $self->_go_mod_normalize($m);
+			if (! defined $all_deps->{$m}) {
+				push @mods, $m unless $m eq $json->{Module};
+				$all_deps->{$m} = 1;
+			}
+		}
 	}
 
-	chdir $old_cwd or die "Unable to chdir '$old_cwd': $!";
+	foreach my $fl ( \@deps, \@mods ) {
+		next unless @$fl > 0; # if there aren't any, don't try
+		my @s = map {
+			my @f = split(/ /, $_);
+			[$f[0], $f[1]];
+		} @$fl;
+		my ($length) = sort { $b <=> $a } map { length $_->[0] } @s;
+		my $n = ( 1 + int $length / 8 );
+		@s = map {
+			my $tabs = "\t" x ( $n - int( length($_->[0]) / 8 ) );
+			"\t$_->[0]$tabs $_->[1]"
+		} @s;
+		@$fl = @s;
+	}
+
+
+	@deps = sort @deps;
+	@mods = sort @mods;
 
-	chomp @mods;
+	return ( \@deps, \@mods );
+}
 
-	# parse the graph into pairs of hashrefs
-	return map { [
-	    map {
-	        my ($m, $v) = split /@/;
-	        { Module => $m, Version => $v };
-	    } split /\s/
-	] } grep { $_ } @mods;
+sub _go_mod_normalize
+{
+	my ( $self, $line) = @_;
+	chomp $line;
+	$line =~ s/\p{Upper}/!\L$&/g;
+	$line =~ s/\s+/ /g;
+	return $line;
 }
 
+
 sub get_ver_info
 {
 	my ( $self, $module ) = @_;
@@ -236,25 +270,8 @@ sub fill_in_makefile
 		$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 $l = $_->[0] ) =~ s/\p{Upper}/!\L$&/g;
-		    my $tabs = "\t" x ( $n - int( length($l) / 8 ) );
-		    "$l$tabs $_->[1]"
-		 } @{$s};
-	}
-
-	$self->set_other( MODGO_MODULES  => \@dist ) if @dist;
-	$self->set_other( MODGO_MODFILES => \@mods ) if @mods;
+	$self->set_other( MODGO_MODULES  => "\\\n" . join(" \\\n", @{$di->{Dist}})) if $di->{Dist};
+	$self->set_other( MODGO_MODFILES => "\\\n" . join(" \\\n", @{$di->{Mods}})) if $di->{Mods};
 }
 
 sub try_building
diff --git a/lang/go/go.port.mk b/lang/go/go.port.mk
index a432e157b80..9db9faac652 100644
--- a/lang/go/go.port.mk
+++ b/lang/go/go.port.mk
@@ -65,6 +65,7 @@ EXTRACT_ONLY =		${DISTNAME}${EXTRACT_SUFX}
 MASTER_SITES ?=		${MASTER_SITE_ATHENS}${MODGO_MODNAME}/@v/
 .  for _modpath _modver in ${MODGO_MODULES}
 DISTFILES +=	${MODGO_DIST_SUBDIR}/${_modpath}/@v/${_modver}.zip{${_modpath}/@v/${_modver}.zip}:${MODGO_MASTER_SITESN}
+DISTFILES +=	${MODGO_DIST_SUBDIR}/${_modpath}/@v/${_modver}.mod{${_modpath}/@v/${_modver}.mod}:${MODGO_MASTER_SITESN}
 .  endfor
 .  for _modpath _modver in ${MODGO_MODFILES}
 DISTFILES +=	${MODGO_DIST_SUBDIR}/${_modpath}/@v/${_modver}.mod{${_modpath}/@v/${_modver}.mod}:${MODGO_MASTER_SITESN}
-- 
PGP: 0x1F81112D62A9ADCE / 3586 3350 BFEA C101 DB1A  4AF0 1F81 112D 62A9 ADCE

Reply via email to