#!/usr/bin/perl
# Copyright 2026 Juan Manuel Méndez Rey <juan.mendezr@proton.me>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

=encoding utf8

=head1 NAME

dh_scala - substitution variables for Scala libraries built with scala-debian-helper

=head1 SYNOPSIS

B<dh_scala> [S<I<debhelper options>>]

=head1 DESCRIPTION

B<dh_scala> reads F<debian/scala-build> (see L<scala-build(5)>) and, for each
binary package that receives a jar, adds these substitution variables:

=over

=item B<${scala:Depends}>

The standard library package of the Scala version the jar was built for
(B<scala-library (E<gt>= 2.12~)>, B<scala-library-2.13>, B<scala3-library>;
none for a Java module, B<Cross-Version: none>),
the package that ships each B<Classpath> jar, and the package of each
B<@>I<Artifact> entry built from the same source (at the same version).

=item B<${scala:BinaryVersion}>

The Scala binary version: B<2.12>, B<2.13> or B<3>. It is set as an optional
substitution variable (B<?=>), so dpkg-gencontrol does not warn when a
package does not use it.

=back

It runs before B<dh_gencontrol> when B<dh-sequence-scala> is in
Build-Depends. It stops the build when a jar it should describe was not built,
which happens when B<debian/rules> does not pass B<--buildsystem=scala>.

=head1 FILES

=over

=item F<debian/scala-build>

What is built, see L<scala-build(5)>.

=item F<debian/.dh-scala/>I<id>F</>

What the build system made for each artifact: the jar and the POM it
installs.

=back

=head1 SEE ALSO

L<scala-debian-helper(7)>, L<scala-build(5)>, L<Debian::Debhelper::Buildsystem::scala(3pm)>

=cut

# PROMISE: DH NOOP WITHOUT path(debian/scala-build) cli-options()

use strict;
use warnings;
use Debian::Debhelper::Dh_Lib;
use Debian::DhScala qw(read_config compiler_for resolve_classpath where);
use Dpkg::Substvars;

init();

# Package that ships $path (dpkg-query -S), for Classpath entries.
my %owner_of;

sub owner_of {
	my ($path) = @_;
	return $owner_of{$path} //= do {
		my $out = eval { qx_cmd('dpkg-query', '-S', $path) };
		error("no installed package ships $path") if $@ || !$out;
		my ($pkgs) = split /: /, $out, 2;
		my ($p)    = split /, /, $pkgs;
		$p =~ s/:.*$//;
		$p;
	};
}

# ${scala:BinaryVersion} is for descriptions and most packages do not use it:
# set it as optional, so that dpkg-gencontrol does not warn when it is unused.
sub set_binary_version_substvar {
	my ($pkg, @binvers) = @_;
	return if $dh{NO_ACT};
	my $file = 'debian/' . pkgext($pkg) . 'substvars';
	my $sv   = Dpkg::Substvars->new($file);
	$sv->set_as_optional('scala:BinaryVersion', join(', ', @binvers));
	$sv->save($file);
	return;
}

my %built;
my %binvers;
for my $s (read_config()) {
	my $acting = $s->{install} && process_pkg($s->{package});
	# Classpath jars come from Build-Depends of the packages built in this
	# run only (with dh -a, those of arch:all packages may be missing).
	my @cp = $acting ? resolve_classpath($s, \%built) : ();
	$s->{resolved_classpath} = \@cp;
	$built{ $s->{id} } = $s;
	next unless $acting;
	my $pkg = $s->{package};
	# Without --buildsystem=scala, dh_auto_build compiles nothing and the
	# package would be built empty.
	error(where($s)
		  . ": $s->{builddir}/$s->{id}.jar was not built; "
		  . "does debian/rules call dh with --buildsystem=scala?")
	  unless -f "$s->{builddir}/$s->{id}.jar";
	# A Java module (Cross-Version: none) does not need the Scala library.
	if ($s->{cross} ne 'none') {
		addsubstvar($pkg, 'scala:Depends', @{ compiler_for($s->{binver})->{stdlib_dep} });
	}
	# the direct dependencies only: theirs come with their own Depends
	for my $e (grep { !$_->{transitive} } @cp) {
		if ($e->{stanza}) {
			my $other = $e->{stanza}{package};
			addsubstvar($pkg, 'scala:Depends', $other, '= ${binary:Version}')
			  if $other ne $pkg;
		} else {
			addsubstvar($pkg, 'scala:Depends', owner_of($e->{path}));
		}
	}
	push @{ $binvers{$pkg} }, $s->{binver}
	  unless grep { $_ eq $s->{binver} } @{ $binvers{$pkg} // [] };
}
set_binary_version_substvar($_, @{ $binvers{$_} }) for sort keys %binvers;
