#!/usr/bin/env perl

use warnings;
use strict;

use Log::Report   'oodoc';

use Cwd               qw/getcwd realpath/;
use File::Copy        qw/move copy/;
use File::Glob        qw/bsd_glob/;
use File::Slurper     qw/read_text read_binary read_lines/;
use File::Spec::Functions qw/catfile rel2abs devnull/;
use File::Basename    qw/basename dirname/;
use Getopt::Long      qw/GetOptions :config gnu_getopt/;
use HTML::Entities    qw/encode_entities/;
use JSON              ();
use List::Util        qw/first/;
use POSIX             qw/strftime/;
use Software::LicenseUtils ();

use OODoc             ();
use OODoc::Parser     ();

###
### Some constants
###

my $tmpdir      = $ENV{TMPDIR} || '/tmp';

my $default_pmhead = <<'__PMHEAD';
This code is part of Perl distribution $distribution version $version.
The POD got stripped from this file by OODoc version $ooversion.
$contrib
${lictext}SPDX-License-Identifier: $spdx

__PMHEAD

my $default_podtail = <<'__PODTAIL';
=head1 SEE ALSO

This module is part of $distribution version $version,
built on $today.$web

=head1 LICENSE

$contrib
$lictext
__PODTAIL

my $makefile_example = 'https://github.com/markov2/perl5-OODoc/blob/master/Makefile.PL';
my $rt_issue_queue   = 'https://rt.cpan.org/Public/Dist/Display.html?Name=';

sub extract_manuals($$$);
sub extract_distro($%);
sub create_pod($$$);
sub create_html($$);
sub string_expand_values($$$);
sub create_readme($$);
sub create_meta($);
sub run_tests($);
sub prepare_release($);
sub publish_release($);
sub publish_raw($);
sub create_export($$);
sub read_makefile($);
sub read_meta($);

sub convert2version3();
sub config3();
sub merge3();
sub introduce2oodoc();

###
### Command-line parsing
###

Getopt::Long::Configure 'bundling';

GetOptions
	'all!'          => \(my $make_all),
	'exports!'      => \(my $make_exports),
	'release!'      => \(my $make_release),
	'export=s'      => \(my $make_export),
	'html!'         => \(my $make_html),
	'make|m=s'      => \(my $make_config = 'oodist'),
	'pod!'          => \(my $make_pod),
	'raw!'          => \(my $make_raw),
	'starter!'      => \(my $starter),
	'tests|t!'      => \(my $run_tests),
	'verbose|v+'    => \(my $verbose = 0),
	'workdir|w=s'   => \(my $distdir),

	'config3'       => \(my $config3),
	'merge3'        => \(my $merge3),
	or error __"stopped";

! @ARGV
	or error __x"No command-line arguments expected.";

my $any_requested = $make_release || $make_exports || $make_export || $make_html || $make_pod || $make_raw || $run_tests;
if($make_all || ! $any_requested)
{	# explicit all, but not -no-*
	$_ //= 1 for $make_release, $make_exports, $make_html, $make_pod, $make_raw, $run_tests;
}

dispatcher mode => $verbose, 'ALL';
my $silence = $verbose > 1 ? '' : ' >' . devnull;

my $ooversion = $OODoc::VERSION || 'devel';

###
### collect some project info
###

info "** Reading your project's configuration with Perl $]";

-f 'Makefile.PL'
	or error __x"This command must be run in the top directory of a Perl distribution.";

system "perl Makefile.PL$silence"
	and fault "cannot run Makefile.PL for basic information";

if($starter)
{	introduce2oodoc;
	exit 0;
}

my $makefile  = read_makefile 'Makefile';
my $meta      = read_meta 'MYMETA.json';

### Help people convert from OODoc2 to OODoc3

if($config3)  { config3; exit 0 }
if($merge3)   { merge3; exit 0 }

my $config    = $meta->{'x_' . $make_config} || $meta->{$make_config};
unless($config) {
	if($makefile->{DISTDIR})
	{	convert2version3;
		exit 1;
	}

	print <<'__INFO';

* INFO: you have not configured OODoc yet.  Let me tell you how you can
* bootstrap it by modifying your Makefile.PL (only).

__INFO

	introduce2oodoc;
	exit 1;
}

my $email     = $meta->{email}   || $1;

my $project   = $meta->{name};
my $version   = $meta->{version};
my $distvname = "$project-$version";

$distdir ||= "$tmpdir/$project";
-d $distdir || mkdir $distdir
	or fault __x"Cannot create workdir at {dir}", dir => $distdir;

info "*  producing $project release $version";

###
### Start OODoc
###

my $doc  = OODoc->new(
	distribution => $project,
	version      => $version,  # version of whole
);

# Reading all the manual pages
my $source  = realpath '.';
my %distros = ($project => $meta);
extract_manuals $source, $distdir, $config;  # produces $distdir

info "** Merge the manuals into one documentation set";
$doc->prepare;

# Generate various products
foreach my $gen (@{$config->{generate} || []})
{
	if(my $format = $gen->{format})
	{	if($format =~ /^pod/)
		{	create_pod $doc, $gen, $distdir if $make_pod;
		}
		elsif($format =~ /^html/)
		{	create_html $doc, $gen if $make_html;
		}
		else
		{	error __x"unknown format '{format}' to generate.", format => $format;
		}
	}
	elsif(my $export = $gen->{export})
	{	if($make_exports && (!$make_export || $export eq $make_export))
		{	create_export $doc, $gen;
		}
	}
	else
	{	error __x"unknown generation type in configuration.";
	}
}

# Produce release

if($run_tests || $make_release || $make_raw)
{
	prepare_release $distdir;

	run_tests $distdir
		if $run_tests;

	publish_release $distdir
		if $make_release;

	publish_raw $source
		if $make_raw;
}

info "** Ready";
exit 0;

### extract($release_dir, $publish_dir, $config)
#   Extract documentation from all manuals.  When the manual is part of the
#   release to be made, it will produce a stripped pm's into $publish_dir
#   at the same time.

sub extract_manuals($$$)
{	my ($indir, $outdir, $config) = @_;

	info "** Extracting manuals from distributions";
	extract_distro $source, release_dir => $outdir, config => $config, recurse => 1;

	info $doc->stats;
}

my %included_dirs;

sub extract_distro($%)
{	my ($dir, %args) = @_;
	return if $included_dirs{$dir};

	chdir $dir
		or fault __x"cannot go to {dir} to extract distribution";

	my $lib       = "$dir/lib";
	push @INC, $lib unless grep $_ eq $lib, @INC;

	# Do not run Makefile.PL because the included distry may be in broken state.
	my $outdir    = delete $args{release_dir};
	my $is_root   = defined $outdir;
	my $dist_meta = $is_root ? $meta : read_meta "$dir/MYMETA.json";
	my $dist_name = $dist_meta->{name};
	my $version   = $dist_meta->{version};

	$included_dirs{$dir} = $dist_name;
	$distros{$dist_name} = $dist_meta;

	my $dist_config = delete $args{config} || $dist_meta->{x_oodist} || $dist_meta->{oodist};
	unless($dist_config)
	{	warning __x"distribution {name} is not yet converted to OODoc v3, hence ignored.", name => $dist_name;
		return;
	}

	if($args{recurse})
	{
		foreach my $include (@{$dist_config->{include} || []})
		{	my $absdir = realpath (rel2abs $include, $dir);
			extract_distro $absdir, %args, recurse => 1;
		}

		foreach my $use (@{$dist_config->{use} || []})
		{	my $absdir = realpath (rel2abs $use, $dir);
			extract_distro $absdir, %args, recurse => 0;
		}
	}

	chdir $dir;

	info "*  processing files of $dist_name $version from $dir";

	# Every distribution may have different parser rules.
	my $p_config = $dist_config->{parser} || { };
	my $pmheadfn = rel2abs delete $p_config->{pmhead} || 'PMHEAD.txt', $dir;
	my $select   = delete $p_config->{select} || qr[^ lib/ .*? \.(?:pod|pm) $ ]x;
	my $parser   = OODoc::Parser->new(%$p_config);

	if($is_root)
	{	my $pmhead   = -f $pmheadfn ? read_text $pmheadfn : $default_pmhead;

		$doc->processFiles(
			version    => $version,
			workdir    => $outdir,
			parser     => $parser,
			select     => $select,
			notice     => string_expand_values($pmhead, $dir, $dist_meta),
		);
	}
	else
	{	$doc->processFiles(
	        distribution => $dist_name,
			version    => $version,
			parser     => $parser,
			select     => $select,
		);
	}
}

#
# Create pods
# Only for the manuals in the source distribution.
#

sub create_pod($$$)
{	my ($doc, $gen, $outdir) = @_;

	my $format = $gen->{format};
	info "** Creating POD files with $format";

	my $podtailfn = rel2abs +($gen->{podtail} || 'PODTAIL.txt'), $source;
	my $podtail   = -f $podtailfn ? read_text $podtailfn : $default_podtail;

	$doc->formatter($format,
		workdir => $outdir,
	)->createPages(
	    select  => sub { my $manual = shift; $manual->distribution eq $project },
	    append  => string_expand_values($podtail, $source, $meta),
	);

	# The POD output is not published separately, but as part of the release.
}

#
# Create html
#

sub create_html($$)
{	my ($doc, $gen) = @_;

	my $format    = $gen->{format};
	my $webpages  = $gen->{webpages}
		or error __x"html generation needs a location for the webpages.";

	info "* Creating HTML with $format, files in $webpages";

	chdir $source or panic;

	my $templates = $gen->{templates} // 'html';

	$doc->formatter($format,
		workdir         => $webpages,
	 	html_root       => $gen->{docroot}    // '/',
		html_stylesheet => $gen->{stylesheet},
	)->createPages(
		manual_format    => [],
		manual_templates => "$templates/manual",
		other_templates  => "$templates/other",
	);

	# Only continue when the combined HTML is to be packaged.
	my $dest     = $gen->{publish} or return;
	-d $dest || mkdir $dest
		or fault __x"cannot create {dir}", dir => $dest;

	my $htmlfile = "$distvname-html.tar.gz";

	info "*  building html package $htmlfile";
	unlink $htmlfile;

	local $" = ' ';
	system "tar czf $htmlfile *"
		and fault __x"cannot produce {file} with tar", file => $htmlfile;

	return if $dest eq $source;

	info "*  publish HTML package to $dest/$htmlfile";

	move $htmlfile, $dest
		or fault __x"cannot move {from} to {to}", from => $htmlfile, to=>$dest;
}

#
# string_expand_values($$$)
# The pmhead and podtail are flexible texts, which can have some values filled-in.
# These names are have not changed in v3, but more information is provided.

sub _get_licenses($$)
{	my ($dist_meta, $config) = @_;

	my $year  = strftime "%Y", localtime;
	if(my $firstyear = $config->{first_year})
	{	$year = $firstyear =~ m/$year$/ ? $firstyear
		      : $firstyear =~ m/\D$/    ? $firstyear.$year
		      : "$firstyear-$year";
	}

	my $liccodes = $dist_meta->{license}
		or error __x"The distribution does not specify a license (required)";

	my $meta_spec = $dist_meta->{'meta-spec'}{version} || 1;

	my @licenses;
	foreach my $liccode (@$liccodes)
	{	my ($class) = Software::LicenseUtils->guess_license_from_meta_key($liccode, $meta_spec)
			or error __x"cannot find license code '{code}'", code => $liccode;

		my $authors = $dist_meta->{author};
		push @licenses, $class->new({
			holder  => $dist_meta->{license_holder} || $authors->[0] =~ s/\s+\<(.*?)\>//r,
			year    => $year,
			program => $dist_meta->{name},
			Program => ucfirst($dist_meta->{name}),
		});
	}

	@licenses;
}

sub string_expand_values($$$)
{	my ($string, $dir, $dist_meta) = @_;
	my $config  = $dist_meta->{x_oodist} || $dist_meta->{oodist};

	my $website = $dist_meta->{resources}{homepage};
	my $authors = $dist_meta->{author} or panic "no author";
	my $email   = $authors->[0] =~ m! \<(.*?)\>! ? $1 : undef;
	$email      = $config->{email} if exists $config->{email};
	my $author  = join ', ', map s/ \<(.*?)\>$//r, @$authors;   # names only

	my $log     = first { m/^(?:change|contrib)/i } bsd_glob '*';
	my $contrib = $log ? "For contributors see file $log.\n" : "";

	my ($license) = _get_licenses $dist_meta, $config;
	my $year      = $license->year;

	my %vars = (
		author    => " by $author",
	    changelog => $log,
		contrib   => $contrib,
		email     => $email || '',
	    lictext   => $license->notice,
		ooversion => $ooversion,  # OODoc's version which produces this docs
		project   => $project,    # overall project name
		spdx      => $license->spdx_expression,
		today     => (strftime "%B %d, %Y", localtime),
		version   => $dist_meta->{version},
	 	web       => $website ? " Website: F<$website>" : '',
		website   => $website,
		year      => $license->year,       # license year range, backwards compatible name

		distribution  => $dist_meta->{name},
		license_years => $license->year,
	);

	$string =~ s/(?: \$(\w+) | \$\{(\w+)\} )/
		my $key = $+;
	    exists $vars{$key} or error __x"unknown pmhead or podtail field '{name}'.", name => $key;
	    $vars{$key};
	 /grxe;
}

#
# create_readme()
# When the README file is missing, something useful gets added.

sub create_readme($$)
{	my ($release, $distdir) = @_;
	my @toplevel = bsd_glob "$distdir/*";

	my $readme_basefn = 'README.txt';
	my $take = $release->{readme};
	if($take)
	{	$readme_basefn = basename $take;
	}
	elsif(first { /\breadme(?:\..*)$/i } @toplevel)
	{	# No readme added when there exists one
		return 1;
	}

	info "*  adding $readme_basefn";

	my $manifn = first { /\bmanifest$/i } @toplevel;
	open my $manifest, '>>', $manifn
		or fault __x"cannot append to {file}", file => $manifn;
	$manifest->print("$readme_basefn\n");
	$manifest->close;

	my $readmefn = catfile $distdir, $readme_basefn;
	if($take)
	{	# user provided README
		info "* copying $take as README\n";

		copy $take, $readmefn
			or fault __x"cannot copy {from} to {to}", from => $take, to => $readmefn;

		return 1;
	}

	# Produce a README text

	open my $readme, '>:encoding(utf8)', $readmefn
		or fault __x"cannot write to {file}", file => $readmefn;

	my $date = localtime;

	$readme->print(<<__README);
=== README for $project version $version
=   Generated on $date by OODoc $ooversion

There are various ways to install this module:

 (1) if you have a command-line, you can do:
       cpan -i <any package from this distribution>'

 (2) if you use Windows, have a look at https://strawberryperl.com

 (3) if you have downloaded this module manually (as root/administrator)
       tar -xzf $project-$version.tar.gz
       cd $project-$version
       perl Makefile.PL
       make          # optional
       make test     # optional
       make install

References:

  * For usage, see the included manual-pages or https://metacpan.org/dist/$project
__README

	my $resources = $meta->{resources} || { repository => {} };
	if(my $homepage = $resources->{homepage}) { $readme->print(<<__HOMEPAGE) }
  * This project has a website at $homepage
__HOMEPAGE

	my $web = $resources->{repository}{web};
	if($web) { $readme->print(<<__REPO) }
  * The source repository can be found at $web
__REPO

	my $issues = $web =~ m/github.com/ ? "$web/issues" : "$rt_issue_queue$project";
	$readme->print(<<__ISSUES);
  * Please report issues via $issues
__ISSUES

	$readme->close;

	1;
}

# Since ExtUtils::MakeMaker, the META files only get updated when
# they already exist.
sub create_meta($)
{	my ($doc) = @_;
	my $manifest = first { /\bmanifest$/i } bsd_glob "*";
	$manifest or panic "No manifest";

	foreach my $fn ('META.yml', 'META.json')
	{	next if -f $fn;
		info "adding $fn";
		open META, '>>', $fn and close META;

		open MANIFEST, '>>', $manifest
			or fault __x"cannot append to {file}", file => $manifest;

		print MANIFEST "$fn\n";
		close MANIFEST;
	}
}

#
# Run tests
#

sub run_tests($)
{	my ($distdir) = @_;

 	info "** Running tests";

	my $tests = $config->{tests}   # no configuration params yet
		or (info "tests are not configured to be run."), return;

	chdir $distdir
		or fault __x"cannot chdir to run tests in {dir}", dir => $distdir;

	foreach my $testdir (qw/t tests xt/)
	{	-d $testdir or next;

		info "*  running tests in $distdir/$testdir";

		system "make test TEST_FILES=$testdir/*.t$silence"
			and fault __x"make test in {dir} failed", dir => $distdir;
	}
}

#
# Create a distribution
#

sub prepare_release($)
{	my ($distdir) = @_;

	info "** Creating the release for $distvname";

	info "*  prepare release in $distdir";

	chdir $distdir
		or fault __x"cannot chdir to prepare release in {dir}", dir => $distdir;

	system "perl Makefile.PL$silence"
		and fault __x"perl Makefile.PL failed";

	system "make clean$silence"
		and fault __x"make clean failed";

	move 'Makefile.old', 'Makefile'
		or fault __x"cannot reinstate Makefile";

	system "make distdir$silence"
	   and fault __x"make distdir failed";
}

sub publish_release($)
{	my ($distdir) = @_;

 	info "** Publish release";

	my $release = $config->{release}
		or (info "release output not configured."), return;

	chdir $distdir
		or fault __x"cannot chdir to publish release in {dir}", dir => $distdir;

	my $dest = rel2abs +($release->{publish} // '.'), $source;
	-d $dest || mkdir $dest
		or fault __x"cannot create release directory {dir}", dir => $dest;

	create_readme $release, $distdir;

	my $distfile = "$distvname.tar.gz";

	info "*  building distribution in $distfile";
	unlink $distfile;

	system "make dist >/dev/null"
		and fault __x"make dist in {dir} failed", dir => $distdir;

	return if $dest eq $distdir;

	info "*  publish release in $dest";

	-f $distfile
		or error __x"cannot find produced {file}", file => $distfile;

	-d $dest or mkdir $dest
		or fault __x"cannot create {dir}", dir => $dest;

	move $distfile, $dest
		or fault __x"cannot move {from} to {to}", from => $distfile, to=>$dest;
}

#
# Publish RAW
#

sub publish_raw($)
{	my ($distdir) = @_;

	info "** Create package with raw distribution";

	my $raw     = $config->{raw}
		or (info "raw output not configured."), return;

	chdir $distdir
		or fault __x"cannot chdir to publish raw in {dir}", dir => $distdir;

	my $rawname = "$distvname-raw";
	my $rawfile = "$rawname.tar.gz";

	info "*  building raw package $rawfile";
	unlink $rawfile;

	my %include;
	foreach my $manifest (bsd_glob "MANIFEST*")
	{	foreach (read_lines $manifest)
		{	s/\s{3,}.*$//;
		    next if m/^#/;
		    next unless length;
		    chomp;
		    $include{$_}++;
		}
	}

	my @include = map "$rawname/$_", sort keys %include;
	symlink('.', $rawname) || readlink $rawname eq '.'
		or fault __x"cannot create temp symlink {name}", name => $rawname;

	local $" = ' ';
	system "tar czf $rawfile @include"
		and fault __x"cannot produce {file} with tar", file => $rawfile;

	unlink $rawname;

	my $dest = rel2abs +($raw->{publish} // '.'), $source;
	-d $dest or mkdir $dest
		or fault __x"cannot create {dir}", dir => $dest;

	info "*  publish raw package to $dest";

	move $rawfile, $dest
		or fault __x"cannot move {from} to {to}", from => $rawfile, to => $dest;
}

#
# Create EXPORT
#

sub create_export($$)
{	my ($doc, $gen) = @_;

	my $name   = $gen->{export};
	my $markup = $gen->{markup}     //= 'html';
	my $dest   = $gen->{publish}    //= '-';
	my $serial = $gen->{serializer} //= 'json';

	info "** Export data-set $name.";

	my $filters = $gen->{include_manuals} || [];
	my $manuals;
	if(@$filters)
	{	my %manuals;
		foreach my $filter (@$filters)
		{	my @found = grep /^ \Q$filter\E (?: \:\: | $) /ix, map $_->name, $doc->manuals;
			@found or warning __x"No manuals match filter '{filter}'.", filter => $filter;
			$manuals{$_}++ for @found;
		}
		$manuals = [ sort keys %manuals ];
	}

	info "*  creating export with markup $markup." ;

	require OODoc::Export;
	my $exporter = OODoc::Export->new(serializer => $serial, markup => $markup);

#	my $tail = oodist_meta $makefile;
#	$tail->{license_year_range} = delete $tail->{year};  # naming improvement

	my $tree = $exporter->tree($doc,
		manuals       => $manuals,
		distributions => \%distros,
#		meta     => $tail,      # only flat key-value, where value is a string
	);

	-d $dest || mkdir $dest
		or fault __x"cannot create export directory {dir}", dir => $dest;

	my $exportfn = catfile $dest, "$distvname-$name.$serial";

	info "** Publish export into $exportfn" ;
	$exporter->write($exportfn, $tree, pretty_print => 1);

	1;
}

# read_makefile($makefile)
# Collect values of variable defined in the specified MAKEFILE, which was
# produced by "perl Makefile.PL"

sub read_makefile($)
{	my $makefile = shift;

	open MAKEFILE, '<', $makefile
	   or fault __x"cannot open produced Makefile: {file}", file => $makefile;

	my %makefile;
	while( <MAKEFILE> )
	{	$_ .= <MAKEFILE> while !eof MAKEFILE && s/\\$//; # continuations
		s/\n\t*/ /g;

		$makefile{$1} = $2 if m/^([A-Z_][A-Z\d_]+)\s*\=\s*(.*?)\s*$/;

		if(m/^#\s+([A-Z_][A-Z\d_]+)\s*\=>\s*(.*?)\s*$/)
		{	# important information which ended-up in comments ;(
		    my ($key, $v) = ($1, $2);
		    $v =~ s/q\[([^\]]*)\]/$1/g;  # remove q[]
		    $makefile{$key} = $v;
		}
	}

	close MAKEFILE;
	\%makefile;
}

# read_meta($json_file)
# Read a META.json or MYMETA.json file into a Perl structure.

sub read_meta($)
{	my $fn = shift;
	JSON->new->utf8(1)->decode(read_binary $fn);
}

###
### convert2version3()
#   OODoc versions before 3.0 used fields in the Makefile.PL to configure
#   the documentation generation process.  But it got too complex, with
#   growing needs.  Help people convert (help myself to convert 70+ Perl
#   distributions ;-)

sub convert2version3()
{
	print <<__EXPLAIN;
*** Your configuration is based on an old OODoc version: you need to convert
*** to a (more convenient) new structure.  This only impacts the configuration:
*** no need to change your documentation.

  ===> 1. Add the output of this to the top of your Makefile.PL:

      $0 --config3
      (hint:  vi Makefile.PL   :r! oodist --config3)

  ===> 2. Merge the following into your "WriteMakefile" call in Makefile.PL

      $0 --merge3
      (hint:  vi Makefile.PL   :r! oodist --merge3)

  ===> 3. Remove the "PREAMBLE" with OODoc values from the Makefile.PL

  ===> 4. Be warned that some command-line options to 'oodist' have changed

*** Merge the above with your Makefile.PL.  Be smart with it.  A documented
*** example can be found in
***    $makefile_example
__EXPLAIN
}

sub config3()
{
	my $p = sub {
		my $x = $_[0];
		my $y =
			! defined $x    ? "undef"
		  :	$x =~ m!^\d+$!  ? $x                 # int
		  : $x =~ m/^\["']/ ? $x                 # quoted string
		  :   ('"' . ($x =~ s/(["@])/\\$1/gr) . '"');  # do quote string
		\$y;
	};

	my $dist         = $makefile->{DISTDIR};
	my $distro       = $makefile->{NAME} =~ s/\:\:/-/gr;

	my $html_output  = $makefile->{HTML_OUTPUT}  // '';
	my $html_docroot = $makefile->{HTML_DOCROOT} // '/';
	my $email        = $makefile->{EMAIL}
	  || ($meta->{author} && $meta->{author} =~ m/ \<(.*?)\>/ ? $1 : undef);

	print <<__HEAD;
This is an attempt to automatically convert you configuration parameters.

# Use command 'oodist' to produce the documentation before the software release.
__HEAD

	if($html_output) {
		my $webpages = $html_output =~ s/\Q$html_docroot\E$//r;
		print "my \$webpages = ${ $p->($webpages) }\n";
	}

	my $git          = qx(git config --get remote.origin.url 2>/dev/null);
	if(defined $git && length $git)
	{	chomp $git;
		$git =~ s/\.git$//;
		$git =~ s,^.*?:,https://github.com/, if $git =~ m!^git\@github.com!;
	}
	else
	{	$git = 'https://github.com/XXX';
	}

	my $publish      = $dist ? (dirname $dist) : "../public_html/\L$distro";

	print <<__CONFIG;
my \$git      = ${ $p->($git) };
my \$publish  = ${ $p->($publish) };
my \$homepage = ${ $p->($makefile->{WEBSITE} // 'https://XXX') };

my \%oodist   = (
	oodoc_version => $ooversion,
	first_year => ${ $p->($makefile->{FIRST_YEAR} || (strftime "%Y", localtime)) },
	email    => ${ $p->($email) },
__CONFIG

	my @include = map "\t\t'$_',\n", sort split /[\: ]+/, $makefile->{EXTENDS} // '';
	print <<__INCLUDE;

	include  => [\n@include\t],

	use      => [\n\t],
__INCLUDE

	my @links   = map "\t\t'$_',\n", sort split /[\: ]+/, $makefile->{SKIP_LINKS} // '';
	my $pmhead  = $makefile->{PMHEAD} // (-f 'PMHEAD.txt'  ? 'PMHEAD.txt'  : undef);

	print <<__PARSER;

	parser   => {
		syntax         => 'markov',
		skip_links     => [ @links],
		pmhead         => ${ $p->($pmhead) },
	},
__PARSER

	print <<__RELEASE;

	tests    => {
	},

	release  => {
		publish        => "\$publish/${$dist ? \basename $dist : \'releases' }",
	},
__RELEASE

	# Raw output is not interesting since we have git.
	if(my $r = $makefile->{RAWDIR}) { print <<__RAW }

	raw      => {
		publish        => "\$publish/${ \basename $r }",
	},
__RAW

	my @generate;
	my $podtail = $makefile->{PODTAIL} // (-f 'PODTAIL.txt' ? 'PODTAIL.txt' : undef);

	push @generate, <<__POD;
	  {	# Add real pod to the releases
		format         => 'pod3',
		podtail        => ${ $p->($podtail) },
	  },
__POD

	push @generate, $html_output ? <<__HTML : <<'__MAY_HTML';
	  {	format         => 'html',
		webpages       => "\$webpages${ $html_docroot eq '/' ? \'' : \$html_docroot },
		publish        => "\$publish/${ \basename $makefile->{HTML_PACKAGE}}",
		docroot        => ${ $p->($html_docroot) },
		templates      => ${ $p->($makefile->{HTML_TEMPLATES}  // 'html') },
		stylesheet     => ${ $p->($makefile->{HTML_STYLESHEET} // '/oodoc.css') },
	  },
__HTML
	  # You may add HTML formatters here.
__MAY_HTML

	push @generate, <<'__MAY_EXPORT';
	  # You may add exporter configurations here.
__MAY_EXPORT

	print <<__TAIL;

	generate => [\n@generate\t],
);

__TAIL
}

sub merge3()
{
	print <<__MERGE

WriteMakefile
	...
	META_MERGE => {
		'meta-spec' => { version => 2 },
		resources   => {
			repository => {
				type => 'git',
				url  => "\$git.git",
				web  => \$git,
			},
			homepage => \$homepage,
			license  => [ 'http//dev.perl.org/licenses/' ],
		},
		prereqs => {
			develop => {
				requires => {
					'OODoc' => '3.00',
				}
			},
			test => {
				requires => {
					'Test::More' => 1.00,
					'Test::Pod'  => 1.00,
				}
			},
		},

		# You may use multiple set-ups, see "oodist --make"
		x_oodist => \\\%oodist,
	};
__MERGE
}

###
### introduce2oodoc()
#   Help people configure OODoc

sub introduce2oodoc()
{
	print <<__EXPLAIN;
To start with OODoc, on an existing release which may already contain
standard POD, do:

  ===> 1. Add the output of this to the top of your Makefile.PL:

      $0 --config3
      (hint:  vi Makefile.PL   :r! oodist --config3)

  ===> 2. Merge the following into your "WriteMakefile" call in Makefile.PL

      $0 --merge3
      (hint:  vi Makefile.PL   :r! oodist --merge3)

* Merge the above with your Makefile.PL.  Be smart with it.  A documented
* example with more options can be found in
*     $makefile_example

__EXPLAIN
}

__END__

=head1 NAME

oodist - create perl distributions with OODoc

=head1 SYNOPSIS

 cd $yourmodule
 oodist [OPTIONS]

   OPTION:                 DEFAULT:
   --all                     produce everything except '--no-'
   --dist    or --no-dist    package release
   --exports or --no-exports produce all exports
   --export <name>           produce a JSON dump of the parsed docs
   --html    or --no-html    produce html
   --pod     or --no-pod     produce pod in the release
   --raw     or --no-raw     produce package with raw files
   --tests   or --no-tests   run tests

  OPTIONS general:
   --make     | -m <tag>     select configuration in MYMETA.json
   --verbose  | -v  -vv      be verbose or even more verbose
   --workdir  | -w <dir>     /tmp/<distname>

  OPTIONS to help convert OODoc2 to OODoc3 style configuration
   --config3                 settings rewrite
   --merge3                  merge meta block
   --starter                 show instructions how to init OODoc use

=head1 DESCRIPTION

This script produces documentation from Perl sources, using the OODoc
module.  It can produce better POD, HTML via templates, and exports
from parsed manuals.  As source, it can use real POD or Markov pod
with Object Orientation support extensions.  You may also write your
own documentation parsers, formatters, and exporters.

=head2 Configuring

Since version 3.0, OODoc requires the configuration to end-up in
the C<MYMETA.json> file, usually via C<META_MERGE> in the C<Makefile.PL>.
You can best have a look at the C<Makefile.PL> of the C<OODoc> package
for an example...

When you have used OODoc before 3.0, then a nice suggestion is produced
on your first call to C<oodist>.

=head2 Component enabling options

The process is controlled by four main options.  All options are by
default C<on>.

=over 4

=item --all
Create all products, except when expliticly disable with C<--no->.
This is the default, unless any product is enabled explicitly.

=item --dist or --no-dist
Create a distribution, containing all files from the MANIFEST plus
produced files.
Even with C<nodist>, you will end-up with these archives in the
working directory (see C<--workdir>).

=item --exports or --no-exports
Produce all exports.

=item --export C<name>
Create a documentation tree (kind of AST) in a certain serialization
type.  At the moment, only C<json> serialization is supported.  You
may multiple export definitions.

=item --html or --no-html
Create html manual pages.  The C<--html-templates> options must
point to an existing directory (defaults to the C<html/> sub-directory).

=item --pod or --no-pod or --nopod
Produce pod files in the working directory and in the distribution.

=item --raw  or --no-raw
Create a package which contains the files which are needed to produce
the distribution: the pm files still including the oodoc markup.

=item --tests or --no-tests
Run the tests on the produced release, before packaging.
=back

=back

=head2 General options

The other options in detail

=over 4

=item --make | -m <tag>
By default, the C<MYMETA.json> configuration at C<x_oodist> or C<oodist>
is taken.  But you may want different configurations, for instance
a development version which is much simpler (hence easier to understand).

=item --starter
Show instructions how to add OODoc to your existing module.  This will
also be shown when oodist is called where no configuration can be
detected automatically.

=item --verbose  | -v | -vv
Shows what happens during the process.  More v's will result in more
output.

=item --workdir  | -w <dir>
The processing will take place in a seperate directory: the stripped pm's
and produced pod files will end-up there.

If not provided, that directory will be named after the project, and
located in C<$ENV{TMPDIR}>, which defaults to C</tmp>.  For instance
C</tmp/OODoc/>

=back
