File Coverage

blib/lib/HiPi/Utils/Config.pm
Criterion Covered Total %
statement 27 93 29.0
branch 0 24 0.0
condition 0 3 0.0
subroutine 9 17 52.9
pod 0 3 0.0
total 36 140 25.7


line stmt bran cond sub pod time code
1             #########################################################################################
2             # Package HiPi::Utils::Config
3             # Description : Config File Wrapper
4             # Copyright : Copyright (c) 2017 Mark Dootson
5             # License : This is free software; you can redistribute it and/or modify it under
6             # the same terms as the Perl 5 programming language system itself.
7             #########################################################################################
8              
9             package HiPi::Utils::Config;
10              
11             #########################################################################################
12              
13 1     1   7 use strict;
  1         2  
  1         28  
14 1     1   6 use warnings;
  1         2  
  1         26  
15 1     1   5 use parent qw( HiPi::Class );
  1         2  
  1         4  
16 1     1   51 use File::Path ( );
  1         2  
  1         31  
17              
18 1     1   7 use JSON;
  1         2  
  1         9  
19 1     1   116 use Try::Tiny;
  1         2  
  1         59  
20 1     1   761 use Storable;
  1         3602  
  1         57  
21 1     1   12 use Carp;
  1         3  
  1         157  
22              
23             __PACKAGE__->create_ro_accessors( qw( configclass filepath default ) );
24             __PACKAGE__->create_accessors( qw( config _configkey ) );
25              
26             our $VERSION ='0.81';
27              
28             sub new {
29 0     0 0   my( $class, %userparams ) = @_;
30            
31 0           my %params = (
32             configclass => 'hipi',
33             default => {},
34             );
35            
36             # get user params
37 0           foreach my $key( keys (%userparams) ) {
38 0           $params{$key} = $userparams{$key};
39             }
40            
41 0           $params{'_configkey'} = '';
42            
43 0           $params{default}->{'hipi-config-version'} = $VERSION;
44            
45 1     1   717 use Data::Dumper;
  1         7029  
  1         783  
46            
47 0 0         my $fileroot = ( $> ) ? qq($ENV{HOME}/.hipi-perl) : '/etc/hipi-perl';
48 0 0         my $filename = ( $> ) ? 'user.conf' : 'global.conf';
49            
50 0           my $dirpath = qq($fileroot/$params{configclass});
51            
52 0 0         File::Path::make_path($dirpath , { mode => 0700 } ) unless( -d $dirpath );
53            
54 0           $params{filepath} = $dirpath . '/' . $filename;
55            
56 0           my $self = $class->SUPER::new( %params );
57            
58 0 0         if( -f $self->filepath ) {
59 0           $self->read_config;
60             # update any new defaults
61 0           my $conf = $self->config;
62 0           my $updatedefaults = 0;
63 0           for my $itemname ( keys %{ $params{default} } ) {
  0            
64 0 0 0       if( !exists( $conf->{$itemname} ) || !defined($conf->{$itemname}) ) {
65 0           $conf->{$itemname} = $params{default}->{$itemname};
66 0           $updatedefaults = 1;
67             }
68             }
69 0 0         $self->write_config if $updatedefaults;
70            
71             } else {
72 0           $self->config( $self->default );
73 0           $self->write_config;
74             }
75            
76 0           return $self;
77             }
78              
79             sub read_config {
80 0     0 0   my $self = shift;
81 0 0         open ( my $fh, '<:encoding(UTF-8)', $self->filepath ) or croak( qq(failed to open config file : $!) );
82 0           read( $fh, my $input, -s $fh);
83 0           close( $fh );
84 0           my $json = JSON->new;
85             my $conf = try {
86 0     0     my $decoded = $json->decode( $input );
87 0           return $decoded;
88             } catch {
89 0     0     carp q(failed to decode configuration ) . $_;
90 0           return { config_ok => 0 };
91 0           };
92            
93 0           $Storable::canonical = 1;
94 0           my $ckey = Storable::nfreeze( $conf );
95 0           $Storable::canonical = 0;
96 0           $self->_configkey( $ckey );
97 0           $self->config( $conf );
98 0           return 1;
99             }
100              
101             sub write_config {
102 0     0 0   my $self = shift;
103            
104 0           $Storable::canonical = 1;
105            
106 0           my $ckey = Storable::nfreeze( $self->config );
107 0           $Storable::canonical = 0;
108 0 0         if($ckey eq $self->_configkey) {
109             # no need to write an unchanged config
110 0           return 1;
111             }
112            
113 0           $self->config->{epoch} = time();
114 0           $ckey = Storable::nfreeze( $self->config );
115 0           $self->_configkey( $ckey );
116            
117 0 0         open ( my $fh, '>:encoding(UTF-8)', $self->filepath ) or croak( qq(failed to open config file : $!) );
118 0           my $json = JSON->new;
119             my $output = try {
120 0     0     my $encoded = $json->pretty->canonical->encode( $self->config );
121 0           return $encoded;
122             } catch {
123 0     0     carp q(failed to encode configuration ) . $_;
124 0           return '';
125 0           };
126 0 0         if( $output ) {
127 0           print $fh $output;
128             }
129 0           close( $fh );
130 0           return 1;
131             }
132              
133             sub DESTROY {
134             # don't call super
135 0     0     my $self = shift;
136 0 0         if( $threads::threads ) {
137 0 0         if( threads->tid == 0 ) {
138 0           $self->write_config;
139             }
140             } else {
141 0           $self->write_config;
142             }
143             }
144              
145              
146             1;
147              
148             __END__