# Copyright © 2010 Julian Blake Kongslie # Licensed under the BSD 3-clause license. use strict; use warnings; package Piny::Config; use Moose; use MooseX::StrictConstructor; use Carp; use Config::Simple qw( ); # Attributes has 'confpath' => ( is => 'ro' , isa => 'Str' , predicate => 'has_confpath' ); has '_conf' => ( is => 'ro' , isa => 'HashRef[Str]' , lazy_build => 1 , clearer => 'clear_conf' , init_arg => undef ); # Builder methods # If constructed with just one argument, then treat it as a config path. around BUILDARGS => sub { my ( $orig, $class ) = ( shift, shift ); if ( @_ == 1 && ! ref $_[0] ) { return $class->$orig( confpath => $_[0] ); } else { return $class->$orig( @_ ); }; }; sub _build__conf { my ( $s ) = @_; my $conf; if ( $s->has_confpath and -e $s->confpath ) { $conf = Config::Simple->new( $s->confpath )->vars; } else { $conf = { }; }; if ( -e "/etc/piny-default.conf" ) { my $default = Config::Simple->new( "/etc/piny-default.conf" )->vars; foreach my $key ( keys %$default ) { if ( not exists $conf->{$key} ) { $conf->{$key} = $default->{$key}; }; }; }; if ( -e "/etc/piny-override.conf" ) { my $override = Config::Simple->new( "/etc/piny-override.conf" )->vars; foreach my $key ( keys %$override ) { $conf->{$key} = $override->{$key}; }; }; return $conf; }; # Save the config sub save { my ( $s ) = @_; if ( not $s->has_confpath ) { croak "Can't save a Piny::Config if the confpath is not set!"; }; if ( -e "/etc/piny-override.conf" ) { my $override = Config::Simple->new( "/etc/piny-override.conf" )->vars; foreach my $key ( keys %$override ) { if ( exists $s->_conf->{$key} and $s->_conf->{$key} eq $override->{$key} ) { delete $s->_conf->{$key}; }; }; }; if ( -e "/etc/piny-default.conf" ) { my $default = Config::Simple->new( "/etc/piny-default.conf" )->vars; foreach my $key ( keys %$default ) { if ( exists $s->_conf->{$key} and $s->_conf->{$key} eq $default->{$key} ) { delete $s->_conf->{$key}; }; }; }; my $cs = Config::Simple->new( syntax => "ini" ); foreach my $key ( keys %{$s->_conf} ) { $cs->param( $key, $s->_conf->{$key} ); }; $cs->write( $s->confpath ); }; # Tweakable helper sub tweakable { my ( $attr, $default ) = @_; my $attrname = $attr; $attrname =~ s/_/./g; has $attr => ( is => 'rw' , isa => 'Str' , lazy_build => 1 , trigger => sub { my ( $s, $old, $new ) = @_; $s->_conf->{$attrname} = $new; if ( $s->has_confpath ) { $s->save; $s->clear_conf; } else { carp "Attribute $attrname modification ignored!"; $s->clear_conf; my $clearer = "clear_$attr"; $s->$clearer; }; } ); my $builder = sub { my ( $s ) = @_; if ( exists $s->_conf->{$attrname} ) { return $s->_conf->{$attrname}; } else { return $default; }; }; { no strict "refs"; *{"_build_" . $attr} = $builder; }; }; # The tweakables tweakable "piny_ikiwiki_destdir" => "/srv/www/piny.be/"; tweakable "piny_ikiwiki_srcdir" => "/srv/ikiwiki/"; tweakable "piny_ikiwiki_url" => "http://piny.be/"; tweakable "piny_ikiwiki_secure_url" => "https://secure.piny.be/"; tweakable "piny_ikiwiki_secure_path" => "/srv/www/secure.piny.be/"; tweakable "receive_denyNonFastforwards" => "true"; # Moose boilerplate __PACKAGE__->meta->make_immutable; 1;