File Coverage

blib/lib/AWS/CLI/Config.pm
Criterion Covered Total %
statement 86 93 92.4
branch 25 36 69.4
condition 22 54 40.7
subroutine 20 22 90.9
pod 2 2 100.0
total 155 207 74.8


line stmt bran cond sub pod time code
1             package AWS::CLI::Config;
2              
3 5     5   95848 use 5.008001;
  5         28  
4 5     5   41 use strict;
  5         15  
  5         155  
5 5     5   49 use warnings;
  5         16  
  5         214  
6              
7 5     5   39 use Carp ();
  5         25  
  5         121  
8 5     5   35 use File::Spec;
  5         14  
  5         138  
9 5     5   3047 use autodie;
  5         81155  
  5         31  
10              
11             our $VERSION = '0.05';
12              
13             my $DEFAULT_PROFILE = 'default';
14              
15             my $CREDENTIALS;
16             my %CREDENTIALS_PROFILE_OF;
17             my $CONFIG;
18             my %CONFIG_PROFILE_OF;
19              
20             BEGIN: {
21             my %attributes = (
22             access_key_id => {
23             env => 'AWS_ACCESS_KEY_ID',
24             key => 'aws_access_key_id'
25             },
26             secret_access_key => {
27             env => 'AWS_SECRET_ACCESS_KEY',
28             key => 'aws_secret_access_key',
29             },
30             session_token => {
31             env => 'AWS_SESSION_TOKEN',
32             key => 'aws_session_token',
33             },
34             region => { env => 'AWS_DEFAULT_REGION' },
35             output => {},
36             );
37              
38             while (my ($name, $opts) = each %attributes) {
39 5     5   41684 no strict 'refs';
  5         13  
  5         4257  
40             *{__PACKAGE__ . "::$name"} = _mk_accessor($name, %{$opts});
41             }
42             }
43              
44             sub _mk_accessor {
45 25     25   40 my $attr = shift;
46 25         64 my %opt = @_;
47              
48 25         48 my $env_var = $opt{env};
49 25   66     93 my $profile_key = $opt{key} || $attr;
50              
51             return sub {
52 5 100 66 5   10649 if ($env_var && exists $ENV{$env_var} && $ENV{$env_var}) {
      66        
53 1         10 return $ENV{$env_var};
54             }
55              
56 4   33     23 my $profile = shift || _default_profile();
57              
58 4         17 my $credentials = credentials($profile);
59 4 100 66     42 if ($credentials && $credentials->$profile_key) {
60 2         13 return $credentials->$profile_key;
61             }
62              
63 2         10 my $config = config($profile);
64 2 50 33     18 if ($config && $config->$profile_key) {
65 2         9 return $config->$profile_key;
66             }
67              
68 0         0 return undef;
69 25         104 };
70             }
71              
72             sub credentials {
73 0   0 0 1 0 my $profile = shift || _default_profile();
74              
75             $CREDENTIALS ||= _parse(
76             (exists $ENV{AWS_CONFIG_FILE} and $ENV{AWS_CONFIG_FILE})
77             ? $ENV{AWS_CONFIG_FILE}
78 0 0 0     0 : File::Spec->catfile(_default_dir(), 'credentials')
      0        
79             );
80              
81 0 0       0 return unless (exists $CREDENTIALS->{$profile});
82             $CREDENTIALS_PROFILE_OF{$profile} ||=
83 0   0     0 AWS::CLI::Config::Profile->new($CREDENTIALS->{$profile});
84 0         0 return $CREDENTIALS_PROFILE_OF{$profile};
85             }
86              
87             sub config {
88 3   66 3 1 6829 my $profile = shift || _default_profile();
89              
90             $CONFIG ||= _parse(
91             (exists $ENV{AWS_CONFIG_FILE} and $ENV{AWS_CONFIG_FILE})
92             ? $ENV{AWS_CONFIG_FILE}
93 3 50 33     26 : File::Spec->catfile(_default_dir(), 'config')
      66        
94             );
95              
96 3 100       20 return unless (exists $CONFIG->{$profile});
97             $CONFIG_PROFILE_OF{$profile} ||=
98 2   33     25 AWS::CLI::Config::Profile->new($CONFIG->{$profile});
99 2         8 return $CONFIG_PROFILE_OF{$profile};
100             }
101              
102             sub _base_dir {
103 2 100   2   3187 ($^O eq 'MSWin32') ? $ENV{USERPROFILE} : $ENV{HOME};
104             }
105              
106             sub _default_dir {
107 0     0   0 File::Spec->catdir(_base_dir(), '.aws');
108             }
109              
110             sub _default_profile {
111             (exists $ENV{AWS_DEFAULT_PROFILE} && $ENV{AWS_DEFAULT_PROFILE})
112             ? $ENV{AWS_DEFAULT_PROFILE}
113 6 50 33 6   55 : $DEFAULT_PROFILE;
114             }
115              
116             # This only supports one level of nesting, but it seems AWS config files
117             # themselves only have but one level
118             sub _parse {
119 1     1   3 my $file = shift;
120 1   33     4 my $profile = shift || _default_profile();
121              
122 1         2 my $hash = {};
123 1         2 my $nested = {};
124              
125 1 50       18 return +{} unless -r $file;
126              
127 1         3 my $contents;
128             {
129 1         2 local $/ = undef;
  1         19  
130 1         8 open my $fh, '<', $file;
131 1         2665 $contents = <$fh>;
132 1         21 close( $fh );
133             }
134              
135 1         950 foreach my $line (split /\n/, $contents) {
136 8         14 chomp $line;
137              
138 8 100       27 $profile = $1 if $line =~ /^\[(?:profile )?([\w]+)\]/;
139 8         30 my ($indent, $key, $value) = $line =~ /^(\s*)([\w]+)\s*=\s*(.*)/;
140              
141 8 100 66     34 next if !defined $key or $key eq q{};
142              
143 6 100       16 if (length $indent) {
144 1         4 $nested->{$key} = $value;
145             }
146             else {
147             # Reset nested hash
148 5 50       6 $nested = {} if keys %{$nested};
  5         14  
149 5 100 66     29 $hash->{$profile}{$key} = ($key and $value) ? $value : $nested;
150             }
151             }
152              
153 1         6 return $hash;
154             }
155              
156             PROFILE: {
157             package AWS::CLI::Config::Profile;
158              
159 5     5   125 use 5.008001;
  5         42  
160 5     5   34 use strict;
  5         18  
  5         119  
161 5     5   80 use warnings;
  5         14  
  5         926  
162              
163             sub new {
164 6     6   46 my $class = shift;
165 6 50       29 my $data = @_ ? @_ > 1 ? { @_ } : shift : {};
    50          
166 6         30 return bless $data, $class;
167             }
168              
169             sub AUTOLOAD {
170 9     9   31 our $AUTOLOAD;
171 9         29 my $self = shift;
172              
173 9 100       70 return if $AUTOLOAD =~ /DESTROY/;
174 5         19 my $method = $AUTOLOAD;
175 5         42 $method =~ s/.*:://;
176              
177 5     5   40 no strict 'refs';
  5         12  
  5         549  
178 5         26 *{$AUTOLOAD} = sub {
179 8     8   69 return shift->{$method}
180 5         35 };
181              
182 5         44 return $self->{$method};
183             }
184             }
185              
186             1;
187              
188             __END__