File Coverage

blib/lib/HiPi/Utils/Config.pm
Criterion Covered Total %
statement 24 90 26.6
branch 0 24 0.0
condition 0 3 0.0
subroutine 8 16 50.0
pod 0 3 0.0
total 32 136 23.5


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         30  
14 1     1   6 use warnings;
  1         2  
  1         27  
15 1     1   5 use parent qw( HiPi::Class );
  1         2  
  1         4  
16 1     1   52 use File::Path ( );
  1         2  
  1         37  
17              
18 1     1   7 use JSON;
  1         1  
  1         6  
19 1     1   100 use Try::Tiny;
  1         2  
  1         61  
20 1     1   705 use Storable;
  1         3397  
  1         55  
21 1     1   7 use Carp;
  1         1  
  1         947  
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 0 0         my $fileroot = ( $> ) ? qq($ENV{HOME}/.hipi-perl) : '/etc/hipi-perl';
46 0 0         my $filename = ( $> ) ? 'user.conf' : 'global.conf';
47            
48 0           my $dirpath = qq($fileroot/$params{configclass});
49            
50 0 0         File::Path::make_path($dirpath , { mode => 0700 } ) unless( -d $dirpath );
51            
52 0           $params{filepath} = $dirpath . '/' . $filename;
53            
54 0           my $self = $class->SUPER::new( %params );
55            
56 0 0         if( -f $self->filepath ) {
57 0           $self->read_config;
58             # update any new defaults
59 0           my $conf = $self->config;
60 0           my $updatedefaults = 0;
61 0           for my $itemname ( keys %{ $params{default} } ) {
  0            
62 0 0 0       if( !exists( $conf->{$itemname} ) || !defined($conf->{$itemname}) ) {
63 0           $conf->{$itemname} = $params{default}->{$itemname};
64 0           $updatedefaults = 1;
65             }
66             }
67 0 0         $self->write_config if $updatedefaults;
68            
69             } else {
70 0           $self->config( $self->default );
71 0           $self->write_config;
72             }
73            
74 0           return $self;
75             }
76              
77             sub read_config {
78 0     0 0   my $self = shift;
79 0 0         open ( my $fh, '<:encoding(UTF-8)', $self->filepath ) or croak( qq(failed to open config file : $!) );
80 0           read( $fh, my $input, -s $fh);
81 0           close( $fh );
82 0           my $json = JSON->new;
83             my $conf = try {
84 0     0     my $decoded = $json->decode( $input );
85 0           return $decoded;
86             } catch {
87 0     0     carp q(failed to decode configuration ) . $_;
88 0           return { config_ok => 0 };
89 0           };
90            
91 0           $Storable::canonical = 1;
92 0           my $ckey = Storable::nfreeze( $conf );
93 0           $Storable::canonical = 0;
94 0           $self->_configkey( $ckey );
95 0           $self->config( $conf );
96 0           return 1;
97             }
98              
99             sub write_config {
100 0     0 0   my $self = shift;
101            
102 0           $Storable::canonical = 1;
103            
104 0           my $ckey = Storable::nfreeze( $self->config );
105 0           $Storable::canonical = 0;
106 0 0         if($ckey eq $self->_configkey) {
107             # no need to write an unchanged config
108 0           return 1;
109             }
110            
111 0           $self->config->{epoch} = time();
112 0           $ckey = Storable::nfreeze( $self->config );
113 0           $self->_configkey( $ckey );
114            
115 0 0         open ( my $fh, '>:encoding(UTF-8)', $self->filepath ) or croak( qq(failed to open config file : $!) );
116 0           my $json = JSON->new;
117             my $output = try {
118 0     0     my $encoded = $json->pretty->canonical->encode( $self->config );
119 0           return $encoded;
120             } catch {
121 0     0     carp q(failed to encode configuration ) . $_;
122 0           return '';
123 0           };
124 0 0         if( $output ) {
125 0           print $fh $output;
126             }
127 0           close( $fh );
128 0           return 1;
129             }
130              
131             sub DESTROY {
132             # don't call super
133 0     0     my $self = shift;
134 0 0         if( $threads::threads ) {
135 0 0         if( threads->tid == 0 ) {
136 0           $self->write_config;
137             }
138             } else {
139 0           $self->write_config;
140             }
141             }
142              
143              
144             1;
145              
146             __END__