File Coverage

blib/lib/EasyDNS/DDNS/Config.pm
Criterion Covered Total %
statement 87 97 89.6
branch 12 30 40.0
condition 37 72 51.3
subroutine 12 12 100.0
pod 0 1 0.0
total 148 212 69.8


line stmt bran cond sub pod time code
1             package EasyDNS::DDNS::Config;
2              
3 3     3   295391 use strict;
  3         12  
  3         123  
4 3     3   19 use warnings;
  3         5  
  3         204  
5              
6 3     3   1803 use Config::Tiny;
  3         5743  
  3         177  
7 3     3   27 use File::Spec ();
  3         6  
  3         95  
8 3     3   16 use Cwd ();
  3         4  
  3         57  
9              
10 3     3   1602 use EasyDNS::DDNS::Util ();
  3         11  
  3         4846  
11              
12             sub load {
13 3     3 0 263897 my ($class, %args) = @_;
14              
15 3   50     17 my $env = $args{env} || {};
16 3   50     12 my $cli = $args{cli} || {};
17              
18 3         10 my $default_cfg_path = _default_config_path();
19 3         7 my $cfg_path = $args{config_path};
20 3 50 33     23 $cfg_path = $default_cfg_path if !defined($cfg_path) || $cfg_path eq '';
21 3         9 $cfg_path = _expand_tilde($cfg_path);
22              
23 3         8 my $ini = {};
24 3 50       67 if (-f $cfg_path) {
25 3         33 my $ct = Config::Tiny->read($cfg_path);
26 3 50       1027 if (!$ct) {
27             return {
28 0         0 ok => 0,
29             exit_code => 2,
30             error => "Failed to read config '$cfg_path': " . Config::Tiny->errstr,
31             };
32             }
33 3         11 $ini = $ct;
34             }
35              
36             # --- Config values ---
37 3   50     24 my $cfg_user = EasyDNS::DDNS::Util::trim($ini->{easydns}{username} // '');
38 3   50     16 my $cfg_token = EasyDNS::DDNS::Util::trim($ini->{easydns}{token} // '');
39              
40 3   50     16 my $cfg_hosts = EasyDNS::DDNS::Util::trim($ini->{update}{hosts} // '');
41 3   50     13 my $cfg_ip_url = EasyDNS::DDNS::Util::trim($ini->{update}{ip_url} // '');
42 3   50     28 my $cfg_timeout= EasyDNS::DDNS::Util::trim($ini->{update}{timeout} // '');
43              
44 3   50     14 my $cfg_state_path = EasyDNS::DDNS::Util::trim($ini->{state}{path} // '');
45              
46             # Allow ${ENVVAR} expansion in config values
47 3         12 $cfg_user = _expand_env($cfg_user, $env);
48 3         8 $cfg_token = _expand_env($cfg_token, $env);
49 3         10 $cfg_ip_url = _expand_env($cfg_ip_url, $env);
50 3         8 $cfg_state_path = _expand_env($cfg_state_path, $env);
51              
52 3         22 my @hosts_from_cfg = _split_hosts($cfg_hosts);
53              
54             # --- ENV values ---
55 3   100     17 my $env_user = EasyDNS::DDNS::Util::trim($env->{EASYDNS_USER} // '');
56 3   100     26 my $env_token = EasyDNS::DDNS::Util::trim($env->{EASYDNS_TOKEN} // '');
57 3   100     20 my $env_state = EasyDNS::DDNS::Util::trim($env->{SDS_EASYDYN_STATE} // '');
58              
59             # --- CLI values ---
60 3         7 my @hosts_from_cli = ();
61 3 50 33     58 if ($cli->{hosts} && ref($cli->{hosts}) eq 'ARRAY') {
62 3         7 for my $h (@{ $cli->{hosts} }) {
  3         10  
63 0 0       0 if (ref $h eq 'ARRAY') {
64 0         0 push @hosts_from_cli, @$h;
65             } else {
66 0         0 push @hosts_from_cli, $h;
67             }
68             }
69 3 0       9 @hosts_from_cli = grep { defined($_) && $_ ne '' } @hosts_from_cli;
  0         0  
70             }
71              
72 3   50     12 my $cli_ip = EasyDNS::DDNS::Util::trim($cli->{ip} // '');
73 3   100     13 my $cli_ip_url = EasyDNS::DDNS::Util::trim($cli->{ip_url} // '');
74 3         9 my $cli_timeout = $cli->{timeout};
75 3   100     14 my $cli_state = EasyDNS::DDNS::Util::trim($cli->{state_path} // '');
76              
77             # --- Defaults ---
78 3         7 my $def_ip_url = 'https://api.ipify.org';
79 3         43 my $def_timeout = 10;
80 3         25 my $def_state_path = _default_state_path();
81              
82             # Precedence: CLI > ENV > config > defaults
83 3   66     14 my $username = $env_user || $cfg_user;
84              
85 3 50       12 my @hosts = @hosts_from_cli ? @hosts_from_cli : @hosts_from_cfg;
86              
87 3   33     16 my $ip_url = $cli_ip_url || $cfg_ip_url || $def_ip_url;
88              
89 3         5 my $timeout = $def_timeout;
90 3 50 33     32 if (defined $cfg_timeout && $cfg_timeout ne '' && $cfg_timeout =~ /^\d+$/) {
      33        
91 3         9 $timeout = int($cfg_timeout);
92             }
93 3 50 66     28 if (defined $cli_timeout && $cli_timeout =~ /^\d+$/ && $cli_timeout > 0) {
      66        
94 0         0 $timeout = int($cli_timeout);
95             }
96              
97 3   33     38 my $state_path = $cli_state || $env_state || $cfg_state_path || $def_state_path;
98 3         9 $state_path = _expand_tilde($state_path);
99              
100             # Secret token (do not expose in resolved)
101 3   66     11 my $token = $env_token || $cfg_token;
102              
103 3 50       27 my $resolved = {
104             config_path => $cfg_path,
105             username => $username,
106             token_set => ($token ? 1 : 0),
107             hosts => \@hosts,
108             ip => $cli_ip,
109             ip_url => $ip_url,
110             timeout => $timeout,
111             state_path => $state_path,
112             };
113              
114             return {
115 3         63 ok => 1,
116             resolved => $resolved,
117             secrets => { token => $token },
118             };
119             }
120              
121             sub _default_config_path {
122 3   33 3   15 my $home = $ENV{HOME} || Cwd::getcwd();
123 3         51 return File::Spec->catfile($home, '.config', 'sdseasydyn', 'config.ini');
124             }
125              
126             sub _default_state_path {
127 3   33 3   15 my $home = $ENV{HOME} || Cwd::getcwd();
128 3         48 return File::Spec->catfile($home, '.local', 'state', 'sdseasydyn', 'last_ip');
129             }
130              
131             sub _expand_tilde {
132 6     6   15 my ($path) = @_;
133 6 50 33     30 return $path if !defined $path || $path eq '';
134 6 50       27 return $path if $path !~ m{^~(/|$)};
135 0   0     0 my $home = $ENV{HOME} || '';
136 0         0 $path =~ s{^~}{$home};
137 0         0 return $path;
138             }
139              
140             sub _expand_env {
141 12     12   24 my ($s, $env) = @_;
142 12 50       23 return $s if !defined $s;
143 12 0       26 $s =~ s/\$\{([A-Z0-9_]+)\}/exists $env->{$1} ? $env->{$1} : ''/ge;
  0         0  
144 12         23 return $s;
145             }
146              
147             sub _split_hosts {
148 3     3   7 my ($s) = @_;
149 3 50 33     27 return () if !defined($s) || $s eq '';
150 3         57 my @h = split /\s*,\s*/, $s;
151 3         10 @h = map { EasyDNS::DDNS::Util::trim($_) } @h;
  4         11  
152 3         8 @h = grep { $_ ne '' } @h;
  4         14  
153 3         8 return @h;
154             }
155              
156             1;
157              
158             __END__