#!/usr/bin/env perl

use feature say;
use strict;
use Debian::Debhelper::Buildsystem::R qw(parse_deps);
use Dpkg::Control;
use Dpkg::Deps qw(deps_concat deps_parse);
use Getopt::Long;
use Pod::Usage;

sub maybe_write {
    my $fname = shift;
    my $content = shift;
    if ( -e $fname ) {
        say "W: $fname already exists, not rewriting";
        return 0;
    } else {
        open(my $fh, ">", $fname);
        say $fh $content;
        close $fh;
        say "I: writing $fname";
        return 1;
    }
}


my $opt_team = '';
my $opt_repo = '';
my $opt_help = 0;
my $opt_tests = '';

GetOptions('team=s' => \$opt_team, 'repo=s' => \$opt_repo,
           'help|?' => \$opt_help, 'tests=s' => \$opt_tests);
pod2usage(1) if $opt_help;

( -e "DESCRIPTION") or die "No DESCRIPTION file, is this an R package?";
my $desc = Dpkg::Control->new(type => Dpkg::Control::CTRL_UNKNOWN);
$desc->load("DESCRIPTION");

my $repo = "CRAN";
if ($opt_repo) {
    $repo = $opt_repo;
    say "I: Using repo=$repo from --repo";
} elsif (length $desc->{Repo}) {
    # this appears to be set ("CRAN") for packages originating from CRAN,
    # but is not set for bioconductor, nor for packages direct from upstream
    $repo = $desc->{Repo};
    say "I: Using repo=$repo from DESCRIPTION::Repository";
} elsif (length $desc->{biocViews}) {
    # however, biocViews is (presumably) only going to be set for bioconductor
    # packages, so nonzero should identify
    $repo = "BIOC";
    say "I: Using repo=$repo due to existence of DESCRIPTION::biocViews";
} else {
    say "I: Using repo=$repo by default";
}

my $debname = "r-" . lc $repo . "-" . lc $desc->{Package};
say "I: Package source and binary name: $debname";

my @aptavail = qx/grep-aptavail -P -s Package -n -e ^r-/;
my %apthash;
@apthash{@aptavail} = ();

my $rdepends = deps_concat(Debian::Debhelper::Buildsystem::R::parse_depends("Depends", $desc->{Depends}, \%apthash));
my $rrecommends = deps_concat(Debian::Debhelper::Buildsystem::R::parse_depends("Recommends", $desc->{Recommends}, \%apthash));
my $rsuggests = deps_concat(Debian::Debhelper::Buildsystem::R::parse_depends("Suggests", $desc->{Suggests}, \%apthash));
my $rimports = deps_concat(Debian::Debhelper::Buildsystem::R::parse_depends("Imports", $desc->{Imports}, \%apthash));
my $builddeps;
if ( $rdepends ) {
    $builddeps = deps_concat("debhelper (>= 10)", "dh-r", "r-base-dev", $rdepends, $rimports);
} else {
    $builddeps = deps_concat("debhelper (>= 10)", "dh-r", "r-base-dev", $rimports);
}

say "I: Package depends: $rdepends";
say "I: Package imports: $rimports";
say "I: Package recommends: $rrecommends";
say "I: Package suggests: $rsuggests";
say "I: Package build-depends: $builddeps";

my $year = 1900 + (localtime)[5];
my $compiled = lc $desc->{NeedsCompilation} eq "yes";
my $arch =  $compiled ? "any" : "all";
if ($compiled) {
    say "W: This package NeedsCompilation: there are probably extra dependencies required";
    say "W: Package SystemRequirements: '$desc->{SystemRequirements}'";
}

my $longdesc = $desc->{Description};
$longdesc =~ s/^\s*/ /gm;

my $homepage = "";
if ($repo eq "CRAN") {
    $homepage = "https://cran.r-project.org/package=$desc->{Package}";
} elsif ($repo eq "BIOC") {
    $homepage = "https://bioconductor.org/packages/$desc->{Package}/";
}

my $maintainer = "$ENV{DEBFULLNAME} <$ENV{DEBEMAIL}>";
my $uploaders = "";
my $vcs = "";

if ($opt_team eq "science") {
    say "I: Generating maintainers, uploaders, VCS entries for debian-science team";
    $uploaders = $maintainer;
    $maintainer = "Debian Science Maintainers <debian-science-maintainers\@lists.alioth.debian.org>";
    $vcs = "https://anonscm.debian.org/git/debian-science/packages/$debname.git";
} elsif ($opt_team eq "med") {
    say "I: Generating maintainers, uploaders, VCS entries for debian-med team";
    $uploaders = $maintainer;
    $maintainer = "Debian Med Packaging Team <debian-med-packaging\@lists.alioth.debian.org>";
    $vcs = "https://anonscm.debian.org/git/debian-med/$debname.git"
}


if (! -d "debian" ) {
    mkdir "debian";
    mkdir "debian/source";
    mkdir "debian/tests";
    say "I: Creating debian/";
}

my $dcontrol = <<"EOF";
Source: $debname
Section: gnu-r
Priority: optional
Maintainer: $maintainer
Uploaders: $uploaders
Build-Depends: $builddeps
Standards-Version: 3.9.8
Homepage: $homepage
Vcs-Browser: $vcs
Vcs-Git: $vcs

Package: $debname
Architecture: $arch
Depends: \${R:Depends}, \${shlibs:Depends}, \${misc:Depends}
Recommends: \${R:Recommends}
Suggests: \${R:Suggests}
Description: $desc->{Title}
$longdesc
EOF

maybe_write("debian/control", $dcontrol);
maybe_write("debian/compat", "10");
maybe_write("debian/source/format", "3.0 (quilt)");

my $drules = <<"EOF";
#!/usr/bin/make -f

%:
\tdh \$\@ --buildsystem R
EOF

maybe_write("debian/rules", $drules);
chmod 0755, "debian/rules";

my $dwatch = "";
if ($repo eq "CRAN") {
    $dwatch = "version=4\nhttps://cran.r-project.org/src/contrib/" . $desc->{Package} . '_([-\d.]*)\.tar\.gz';
} elsif ($repo eq "BIOC") {
    $dwatch = "version=4\n" . 'opts=downloadurlmangle=s?^(.*)\.\.?https:$1packages/release/bioc? \\' . "\nhttps://bioconductor.org/packages/release/bioc/html/$desc->{Package}.html .*/$desc->{Package}_(.*).tar.gz";
}

maybe_write("debian/watch", $dwatch);

my $dcopy = <<"EOF";
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: $desc->{Package}
Upstream-Contact: $desc->{Maintainer}
Source: $homepage

Files: *
Copyright: $desc->{Author}
License: $desc->{License}
Comment: $desc->{Copyright}

Files: debian/*
Copyright: $year $ENV{DEBFULLNAME} <$ENV{DEBEMAIL}>
License: $desc->{License}
Comment: Same license as upstream package

License: $desc->{License}
  TODO: insert the appropriate license text
EOF

maybe_write("debian/copyright", $dcopy);

if ( -e "debian/changelog") {
    say "W: debian/changelog already exists, not rewriting";
} else {
    qx/dch --create --package $debname -v $desc->{Version}-1 "Initial release (closes: #xxxxxx)"/;
    say "I: Writing debian/changelog";
}

my $test_generic = <<'EOF';
#!/bin/sh -e

for testfile in tests/*.R; do
    echo "BEGIN TEST $testfile"
    LC_ALL=C R --no-save < $testfile
done
EOF

my $test_run_unit_test = <<"EOF";
#!/bin/sh -e

pkgname=$desc->{Package}
debname=$debname

if [ "\$ADTTMP" = "" ] ; then
    ADTTMP=`mktemp -d /tmp/\${debname}-test.XXXXXX`
    trap "rm -rf \$ADTTMP" 0 INT QUIT ABRT PIPE TERM
fi
cd \$ADTTMP
cp -a /usr/share/doc/\$debname/tests/* \$ADTTMP
gunzip -r *
for testfile in *.R; do
    echo "BEGIN TEST \$testfile"
    LC_ALL=C R --no-save < \$testfile
done
EOF

my $test_bioc = <<"EOF";
#!/bin/sh -e

LC_ALL=C R --no-save -e 'BiocGenerics:::testPackage("$desc->{Package}")'
EOF

my $test_vignette = <<"EOF";
#!/bin/sh -e

for vignette in \$(find vignettes -iname '*.rnw' -or -iname '*.rmd'); do
    echo "BEGIN VIGNETTE \$vignette"
    LC_ALL=C R CMD Sweave \$vignette
done
EOF

my %autopkgtests;

# detect common test dependencies
my $testpkgs = "@,";
if ($rsuggests =~ /testthat/) {
    $testpkgs .= " r-cran-testthat,";
}
if ($rsuggests =~ /runit/) {
    $testpkgs .= " r-cran-runit,";
}

if ($opt_tests =~ /generic/) {
    maybe_write("debian/tests/generic", $test_generic);
    $autopkgtests{"generic"} = $testpkgs;
}
if ($opt_tests =~ /run-unit-test/) {
    maybe_write("debian/tests/run-unit-test", $test_run_unit_test);
    maybe_write("debian/$debname.docs", "debian/tests/run-unit-test\ntests");
    $autopkgtests{"run-unit-test"} = $testpkgs;
}
if ($opt_tests =~ /bioc/) {
    maybe_write("debian/tests/bioc", $test_bioc);
    $autopkgtests{"bioc"} = $testpkgs . " r-bioc-biocgenerics";
}
if ($opt_tests =~ /vignette/) {
    maybe_write("debian/tests/vignette", $test_vignette);
    if ($rsuggests =~ /knitr/) {
        $autopkgtests{"vignette"} = "@, r-cran-knitr";
    } else {
        $autopkgtests{"vignette"} = "@";
    }
}

my $testcontrol = "";
foreach my $key (keys %autopkgtests) {
    $testcontrol .= "Tests: $key\n";
    $testcontrol .= "Depends: $autopkgtests{$key}\n";
    $testcontrol .= "Restrictions: allow-stderr\n\n";
}

maybe_write("debian/tests/control", $testcontrol);


__END__

=head1 NAME

dh-make-R - Generates a debian/ directory skeleton for R packages

=head1 SYNOPSIS

dh-make-R [options]

 Options:
    --help
    --team TEAM          Set packaging team
    --repo REPO          Override R repository detection
    --tests TEST1,TEST2  Generate autopkgtest templates

=head1 OPTIONS

=over 8

=item B<--help>

Print this help message.

=item B<--team>

Generate default maintainer, uploaders, VCS URLs for the given packaging team.
Understood values are "science" and "med" for debian-science and debian-med
respectively.

=item B<--repo>

Set the R repository (used in the package name), overriding automatic detection.

=item B<--tests>

Comma-separated list of test templates to generate. Understood values are
"generic" (run tests/*.R), "run-unit-test" (installs tests as documentation,
can be run outside autopkgtest), "bioc" (runs BiocGenerics::testPackage) and
"vignette" (attempts to rebuild documentation).

=back

=head1 DESCRIPTION

B<dh-make-R> should be run from the root of an unpacked R tarball (ie, the
directory containing DESCRIPTION). Values from this are used to generate
default control, compat, copyright, rules, source/format and watch files.
