#!/usr/bin/perl

#    Copyright (c) 2009 Dominique Dumont.
#
#    This library is free software; you can redistribute it and/or
#    modify it under the terms of the GNU Lesser Public License as
#    published by the Free Software Foundation; either version 2.1 of
#    the License, or (at your option) any later version.
#
#    Config-Model is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    Lesser Public License for more details.
#
#    You should have received a copy of the GNU Lesser Public License
#    along with Config-Model; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
#    02110-1301 USA

# dh_config_model_upgrade file provided by libconfig-model-perl package

# See /usr/share/doc/debhelper/PROGRAMMING for debhelper details

use warnings;
use strict;
use File::Find ;

use Debian::Debhelper::Dh_Lib ;

$dh{model_name} = ''; # avoids undef warnings
$dh{edit_option} = '';

init(options => { "model_name|mn=s"    => \$dh{model_name}, 
		  "model_package|mp=s" => \$dh{model_package},
		  "model_version|mv=s" => \$dh{model_version},
		  "edit_option=s"      => \$dh{edit_option},
		}
    );


# See debhelper(7)
if ($dh{NO_ACT}) {
  exit;
}

if ($ENV{DEB_BUILD_OPTIONS} =~ /noconfigmodel/) {
  warn "dh_config_model_upgrade: DEB_BUILD_OPTIONS specifies 'noconfigmodel',  exiting ...\n";
  exit;
}

my @do_packages = @{$dh{DOPACKAGES}} ;

unless (@do_packages) {
    @do_packages = map { m!debian/(.*)\.config-model!; $1; }
      glob("debian/*.config-model") ;
}

# debian/config file: foo.config-model
foreach my $package (@do_packages) {

    verbose_print("dh_config_model_upgrade: package $package") ;

    my $metaconf = "debian/$package.config-model" ;

    my %cm_config = map {  $_ => $dh{$_} ; } 
                        qw/model_name model_version model_package/;

    # declare model name to load ($model below)
    # declare which package provides the model (optional)
    if (-e $metaconf) {
	open my $meta,$metaconf || die "Can't open $metaconf:$!";
	foreach (<$meta>) {
	    chomp;
	    my ($k,$v) = split /\s*?[:= ]\s*/ ;
	    foreach my $cmhk (keys %cm_config) {
		$cm_config{$cmhk} ||= $v if $k eq $cmhk ;
	    }
	}
	close $meta ;
    }

    next unless defined $dh{model_name} ;

    # add dependency 
    addsubstvar($package,'misc:Depends', 'libconfig-model-perl', '>= 0.637') ;

    if (defined $cm_config{model_package}) {
	# add dependency in misc:Depends control file
  	addsubstvar($package,'misc:Depends', 
		    $cm_config{model_package},
		    '>= '.$cm_config{model_version}) ;
    }
    else {
	# should we check that model file is declared in *.install ?
    }

    my $model_sed = 's/%MODEL%/'.$dh{model_name}.'/ ; ' ;
    my $pack_sed  = 's/%PACKAGE%/'.$package.'/ ; ' ;
    my $opt_sed   = 's/%OPTION%/'.$dh{edit_option}.'/ ; ' ;

    # calls autoscript to update pkg.postinst with config-edit command
    autoscript($package,postinst => 'postinst-config-model',
	       $model_sed.$pack_sed.$opt_sed ) ;

}

__END__

=head1 NAME

dh_config_model_upgrade - add Config::Model based configuration merge

=head1 SYNOPSIS

 dh_config_model_upgrade [ debhelper options ] [ --model_name xx ] \
  [ --model_package xx [ --model_version yy ] ] \
  [ --edit_option "..." ] [ -p pkg ]

=head1 DESCRIPTION

B<dh_config_model_upgrade is experimental>

dh_config_model_upgrade is a debhelper that will modify the package
script to perform configuration merge on package upgrade. This merge
is based on L<config-edit> from L<Config::Model>.

Model information can be specified by command options or a
configuration file: C<debian/foo.config-model>

A Model must be either :

=over

=item *

Delivered in the package in C<debian/config-model/models/> directory

=item *

Provided by another package

=back

=head1 REQUIREMENTS

For this program to work, package maintainer must ensure that:

=over

=item *

ensure that *.postinst and *.config have a #DEBHELPER#  line (if these files exist)

=item *

ensure that control file has a dependency on ${misc:Depends}

=back

=head1 OPTIONS

=head2 --model_name XX

Specifies the model name ( la C<Config::Model>) that will be used to
perform the upgrade. Without this information,
C<dh_config_model_upgrade> will do nothing. (shortcut C<--mn>)

=head2 --model_for "xx yy"

Specifies the package to act upon. Without this option,
C<dh_config_model_upgrade> will do nothing. To specify several
packages, list the packages between quotes.  (shortcut C<--mf>)

=head2 --model_package XX

Specifies the debian package that provide the model specified bu
C<-model_name>. (shortcut C<--mp>)

=head2 --model_version YY

Specifies the minimal version of the package that provides the model.
(shortcut C<--mv>)

=head2 --edit_option "..."

Specify a list of options or command that will be passed verbatim to
L<config-edit> during upgrade. Be sure to use quotes.

=head2 -p

debhelper option to specify which package(s) to act on.

=head1 Usage

C<dh_config_model_upgrade> can be used with only command line
options. For instance

 dh_config_model_upgrade --model_name Sshd  -p openssh-server \
           --model_package lib-config-model-openssh-perl --model_version 1.206

Alternatively, you can specify relevant information in
configuration files. For instance:

 $ cat debian/openssh-server.config-model
 model_name: Sshd
 model_package: lib-config-model-openssh-perl
 model_version: 1.206
 $ cat debian/openssh-client.config-model
 model_name: Ssh
 model_package: lib-config-model-openssh-perl
 model_version: 1.206

In this case, C<dh_config_model_upgrade> will be invoked this way

 dh_config_model_upgrade

If the model are delivered within the package, you will have to
specify them in xx.install file.

Here's a example based on C<approx> package where the model file and
the parser/writer are delivered in approx package.

Debian dir contains:

  debian/config-model/Approx.pm
  debian/config-model/models/Approx.pl

C<debian/approx.install> contains:

  debian/config-model/Approx.pm usr/share/perl5/Config/Model
  debian/config-model/models/Approx.pl usr/share/perl5/Config/Model/models

dh_config_model_upgrade is invoked as :

  dh_config_model_upgrade -model_name Approx

=head1 debian files setup

C<dh_config_model_upgrade> will work if:

=over 4

=item *

C<control> file contains a C<S{misc:Depends}> variable in C<Depends> line

=item *

C<rules> contains a C<#DEBHELPER#> line to insert generated postinst snippet

=back 


=head1 EXAMPLES

C<dh_config_model_upgrade> can be called in the rules file via the dh
command (no options are possible, you will have to specify
C<debian/*.config_model> files):

 %:
   dh --with config_model

Or directly at the start of the build with

 build:
   dh_config_model_upgrade -model_name FooBar

Here's an example to avoid using Augeas when upgrading

 build:
   dh_config_model_upgrade -model_name Sshd -edit_option "-backend custom"

=head1 CAVEATS

Using options with a single dash (e.g. C<-model_name> instead of
C<--model_name>) will lead to "C<Unknown option>" errors.

=head1 ENVIRONMENT

This program will exit(0) if C<DH_NO_ACT> is set or if C<DEB_BUILD_OPTIONS>
contains C<noconfigmodel>.

=head1 SEE ALSO

L<debhelper>

This program is an addendum to debhelper (part of libconfig-model-perl).

=head1 AUTHOR

Dominique Dumont <ddumont@cpan.org>

=cut
