| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/env perl |
|
2
|
|
|
|
|
|
|
## no critic (ControlStructures::ProhibitPostfixControls) |
|
3
|
|
|
|
|
|
|
## no critic (ValuesAndExpressions::ProhibitConstantPragma) |
|
4
|
8
|
|
|
8
|
|
50694
|
use strict; |
|
|
8
|
|
|
|
|
17
|
|
|
|
8
|
|
|
|
|
425
|
|
|
5
|
8
|
|
|
8
|
|
35
|
use warnings; |
|
|
8
|
|
|
|
|
18
|
|
|
|
8
|
|
|
|
|
654
|
|
|
6
|
8
|
|
|
8
|
|
188
|
use 5.010; |
|
|
8
|
|
|
|
|
28
|
|
|
7
|
8
|
|
|
8
|
|
4302
|
use open ':std', IO => ':encoding(UTF-8)'; |
|
|
8
|
|
|
|
|
12044
|
|
|
|
8
|
|
|
|
|
52
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# ABSTRACT: Read .env file and turn its content into environment variables for different shells. |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# PODNAME: envdot |
|
12
|
|
|
|
|
|
|
|
|
13
|
8
|
|
|
|
|
914491
|
our $VERSION = '0.020'; |
|
14
|
|
|
|
|
|
|
|
|
15
|
8
|
|
|
8
|
|
214047
|
use English qw( -no_match_vars ); # Avoids regex performance penalty in perl 5.18 and earlier |
|
|
8
|
|
|
|
|
28272
|
|
|
|
8
|
|
|
|
|
48
|
|
|
16
|
8
|
|
|
8
|
|
9421
|
use Getopt::Long qw( :config auto_version auto_help ); |
|
|
8
|
|
|
|
|
149028
|
|
|
|
8
|
|
|
|
|
56
|
|
|
17
|
8
|
|
|
8
|
|
2063
|
use Carp; |
|
|
8
|
|
|
|
|
15
|
|
|
|
8
|
|
|
|
|
638
|
|
|
18
|
8
|
|
|
8
|
|
88
|
use Errno; |
|
|
8
|
|
|
|
|
16
|
|
|
|
8
|
|
|
|
|
341
|
|
|
19
|
8
|
|
|
8
|
|
4446
|
use Pod::Usage; |
|
|
8
|
|
|
|
|
475580
|
|
|
|
8
|
|
|
|
|
1145
|
|
|
20
|
|
|
|
|
|
|
|
|
21
|
8
|
|
|
8
|
|
4896
|
use Env::Dot::Functions qw(:all); |
|
|
8
|
|
|
|
|
39
|
|
|
|
8
|
|
|
|
|
1399
|
|
|
22
|
8
|
|
|
8
|
|
4152
|
use Env::Dot::ScriptFunctions qw( convert_variables_into_commands ); |
|
|
8
|
|
|
|
|
25
|
|
|
|
8
|
|
|
|
|
1026
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
8
|
|
|
|
|
69
|
local $OUTPUT_AUTOFLUSH = 1; |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
use constant { |
|
27
|
8
|
50
|
|
|
|
687228
|
DEFAULT_OPTION_DOTENV_FILENAME => '.env', |
|
|
|
50
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
DEFAULT_OPTION_SHELL => q{sh}, |
|
29
|
|
|
|
|
|
|
DEFAULT_OPTION_READ_FROM_STDIN => 0, |
|
30
|
|
|
|
|
|
|
EXIT_SUCCESS => 0, |
|
31
|
|
|
|
|
|
|
EXIT_ERROR_NO_FILE => ( exists &Errno::ENOENT ? Errno::ENOENT : 255 ), |
|
32
|
|
|
|
|
|
|
EXIT_ERROR_OTHER_ERROR => ( exists &Errno::EINVAL ? Errno::EINVAL : 255 ), |
|
33
|
8
|
|
|
8
|
|
54
|
}; |
|
|
8
|
|
|
|
|
10
|
|
|
34
|
|
|
|
|
|
|
|
|
35
|
8
|
|
|
|
|
104
|
my %SHELL_ALTERNATIVES = ( |
|
36
|
|
|
|
|
|
|
sh => 'sh', |
|
37
|
|
|
|
|
|
|
bash => 'sh', |
|
38
|
|
|
|
|
|
|
dash => 'sh', |
|
39
|
|
|
|
|
|
|
ksh => 'sh', |
|
40
|
|
|
|
|
|
|
csh => 'csh', |
|
41
|
|
|
|
|
|
|
tcsh => 'csh', |
|
42
|
|
|
|
|
|
|
fish => 'fish', |
|
43
|
|
|
|
|
|
|
); |
|
44
|
|
|
|
|
|
|
|
|
45
|
8
|
|
|
|
|
17
|
my $man = 0; |
|
46
|
8
|
|
|
|
|
16
|
my $export = 1; |
|
47
|
8
|
|
50
|
|
|
1026
|
my $shell = $SHELL_ALTERNATIVES{ $ENV{SHELL} } // DEFAULT_OPTION_SHELL; |
|
48
|
8
|
|
|
|
|
40
|
my $dotenv_filepath = DEFAULT_OPTION_DOTENV_FILENAME; |
|
49
|
8
|
|
|
|
|
18
|
my $read_from_stdin = DEFAULT_OPTION_READ_FROM_STDIN; |
|
50
|
8
|
50
|
|
|
|
94
|
GetOptions( |
|
51
|
|
|
|
|
|
|
'man' => \$man, |
|
52
|
|
|
|
|
|
|
'export!' => \$export, |
|
53
|
|
|
|
|
|
|
'shell|s=s' => \$shell, |
|
54
|
|
|
|
|
|
|
'dotenv|e=s' => \$dotenv_filepath, |
|
55
|
|
|
|
|
|
|
'' => \$read_from_stdin, ## no critic (ValuesAndExpressions::ProhibitEmptyQuotes) |
|
56
|
|
|
|
|
|
|
) or pod2usage(2); |
|
57
|
6
|
50
|
|
|
|
6455
|
pod2usage( -exitval => 0, -verbose => 2 ) if $man; |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub main { |
|
60
|
6
|
|
|
6
|
|
40
|
my $var_name = get_envdot_filepaths_var_name(); |
|
61
|
6
|
|
|
|
|
14
|
my @dotenv_filepaths; |
|
62
|
6
|
100
|
|
|
|
111
|
if ( exists $ENV{$var_name} ) { |
|
|
|
50
|
|
|
|
|
|
|
63
|
2
|
|
|
|
|
11
|
@dotenv_filepaths = interpret_dotenv_filepath_var( $ENV{$var_name} ); |
|
64
|
|
|
|
|
|
|
} |
|
65
|
|
|
|
|
|
|
elsif ($read_from_stdin) { |
|
66
|
0
|
|
|
|
|
0
|
croak 'Error: Option not implemented'; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
else { |
|
69
|
4
|
100
|
|
|
|
171
|
if ( !-f $dotenv_filepath ) { |
|
70
|
1
|
50
|
|
|
|
2
|
print {*STDERR} "Error: File not found: '$dotenv_filepath'\n" |
|
|
1
|
|
|
|
|
8
|
|
|
71
|
|
|
|
|
|
|
or croak 'Cannot print error message'; |
|
72
|
1
|
|
|
|
|
0
|
return EXIT_ERROR_NO_FILE; |
|
73
|
|
|
|
|
|
|
} |
|
74
|
3
|
|
|
|
|
11
|
@dotenv_filepaths = ($dotenv_filepath); # The CLI parameter |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
|
|
77
|
5
|
|
|
|
|
30
|
my @vars; |
|
78
|
5
|
|
|
|
|
13
|
foreach my $dotenv_filepath ( reverse @dotenv_filepaths ) { |
|
79
|
5
|
|
|
|
|
61
|
local $EVAL_ERROR = undef; |
|
80
|
5
|
|
|
|
|
9
|
my @these_vars; |
|
81
|
5
|
100
|
|
|
|
12
|
eval { @these_vars = get_dotenv_vars($dotenv_filepath); 1; } or do { |
|
|
5
|
|
|
|
|
27
|
|
|
|
4
|
|
|
|
|
18
|
|
|
82
|
1
|
|
|
|
|
4
|
my $e = $EVAL_ERROR; |
|
83
|
1
|
|
|
|
|
4
|
my ( $err, $l, $fp ) = extract_error_msg($e); |
|
84
|
1
|
50
|
|
|
|
2
|
print {*STDERR} 'Error: ' . $err . ( $l ? qq{ line $l} : q{} ) . ( $fp ? qq{ file '$fp'} : q{} ) . "\n" |
|
|
1
|
50
|
|
|
|
14
|
|
|
|
|
50
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
or croak 'Cannot print error message'; |
|
86
|
1
|
|
|
|
|
0
|
return EXIT_ERROR_OTHER_ERROR; |
|
87
|
|
|
|
|
|
|
}; |
|
88
|
4
|
|
|
|
|
12
|
push @vars, @these_vars; |
|
89
|
|
|
|
|
|
|
} |
|
90
|
4
|
|
|
|
|
22
|
$_->{'opts'}->{'export'} = $export foreach (@vars); |
|
91
|
|
|
|
|
|
|
|
|
92
|
4
|
50
|
|
|
|
8
|
print {*STDOUT} convert_variables_into_commands( $shell, @vars ) |
|
|
4
|
|
|
|
|
33
|
|
|
93
|
|
|
|
|
|
|
or croak 'Cannot print variables to STDOUT'; |
|
94
|
|
|
|
|
|
|
|
|
95
|
4
|
|
|
|
|
|
return EXIT_SUCCESS; |
|
96
|
|
|
|
|
|
|
} |
|
97
|
|
|
|
|
|
|
|
|
98
|
6
|
|
|
|
|
31
|
exit main(@ARGV); |
|
99
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
__END__ |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=pod |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=encoding UTF-8 |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
=head1 NAME |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
envdot - Read .env file and turn its content into environment variables for different shells. |
|
109
|
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=head1 VERSION |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
version 0.020 |
|
113
|
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
envdot [options] |
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
eval `envdot` |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
Options: |
|
121
|
|
|
|
|
|
|
--help |
|
122
|
|
|
|
|
|
|
--man |
|
123
|
|
|
|
|
|
|
--version |
|
124
|
|
|
|
|
|
|
--export --no-export |
|
125
|
|
|
|
|
|
|
--shell -s |
|
126
|
|
|
|
|
|
|
--dotenv -e |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=head2 CLI interface without dependencies |
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
The F<envdot> command is also available |
|
131
|
|
|
|
|
|
|
as a self contained executable. |
|
132
|
|
|
|
|
|
|
You can download it and run it as it is without |
|
133
|
|
|
|
|
|
|
additional installation of CPAN packages. |
|
134
|
|
|
|
|
|
|
Of course, you still need Perl, but Perl comes with any |
|
135
|
|
|
|
|
|
|
normal Linux installation. |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
This can be convenient if you want to, for instance, |
|
138
|
|
|
|
|
|
|
include F<envdot> in a docker container build. |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
curl -LSs -o envdot https://raw.githubusercontent.com/mikkoi/env-dot/main/envdot.self-contained |
|
141
|
|
|
|
|
|
|
chmod +x ./envdot |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
144
|
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
B<envdot> reads your F<.env> file and converts it |
|
146
|
|
|
|
|
|
|
into environment variable commands suitable for |
|
147
|
|
|
|
|
|
|
different shells (shell families): B<sh>, B<csh> and B<fish>. |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
F<.env> files can be written in different flavors. |
|
150
|
|
|
|
|
|
|
B<envdot> supports the often used B<sh> compatible flavor and |
|
151
|
|
|
|
|
|
|
the B<docker> flavor which are not compatible with each other. |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
If you have several F<.env> files, you can read them in at one go |
|
154
|
|
|
|
|
|
|
with the help of the environment variable B<ENVDOT_FILEPATHS>. |
|
155
|
|
|
|
|
|
|
Separate the full paths with 'B<:>' character. |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Env::Dot will load the files in the B<reverse order>, |
|
158
|
|
|
|
|
|
|
starting from the last. This is the same ordering as used in B<PATH> variable: |
|
159
|
|
|
|
|
|
|
the first overrules the following ones, that is, when reading from the last path |
|
160
|
|
|
|
|
|
|
to the first path, if same variable is present in more than one file, the later |
|
161
|
|
|
|
|
|
|
one replaces the one already read. |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
If you have set the variable ENVDOT_FILEPATHS, then B<envdot> will use that. |
|
164
|
|
|
|
|
|
|
Otherwise, it uses the command line parameter. |
|
165
|
|
|
|
|
|
|
If no parameter, then default value is used. Default is the file |
|
166
|
|
|
|
|
|
|
F<.env> in the current directory. |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=for stopwords dotenv env envdot shdotenv subshells |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
=head1 NAME |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
envdot - Read .env file and turn its content into environment variables for different shells. |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
=head1 OPTIONS |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=over 8 |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=item B<--help> |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
Print a brief help message and exits. |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=item B<--man> |
|
183
|
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
Prints the manual page and exits. |
|
185
|
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=item B<--version> |
|
187
|
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Prints the version and exits. |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
=item B<--export>, B<--no-export> |
|
191
|
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
Write commands to set variables for local shell or for exporting them. |
|
193
|
|
|
|
|
|
|
You usually want to export the variables |
|
194
|
|
|
|
|
|
|
to all subsequent programs and subshells, i.e. |
|
195
|
|
|
|
|
|
|
make them into I<environment variables>. |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Default: export |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=item B<-s>, B<--shell> |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
Which shell (family) are you using? Supported: sh, csh, fish. |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
Default: sh |
|
204
|
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=item B<-e>, B<--dotenv> |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
Path to F<.env> file. |
|
208
|
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
Default: current directory F<.env> |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=back |
|
212
|
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
=head1 EXAMPLES |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
eval `envdot --no-export --shell csh` |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
eval `envdot --dotenv subdir/.env` |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
ENVDOT_FILEPATHS='../.env:subdir/.env:.env' eval `envdot` |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 DEPENDENCIES |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
No external dependencies outside Perl's standard distribution. |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
L<Env::Assert> will verify that you certainly have those environmental |
|
228
|
|
|
|
|
|
|
variables you need. It also has an executable which can, for example, |
|
229
|
|
|
|
|
|
|
perform the check in the beginning of a B<docker> container run. |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
L<Dotenv> and L<ENV::Util|https://metacpan.org/pod/ENV::Util> |
|
232
|
|
|
|
|
|
|
are packages which also implement functionality to use |
|
233
|
|
|
|
|
|
|
F<.env> files in Perl. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
L<Config::ENV> and L<Config::Layered::Source::ENV> provide other means |
|
236
|
|
|
|
|
|
|
to configure application with the help of environment variables. |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
L<shdotenv|https://github.com/ko1nksm/shdotenv> is a project to provide dotenv |
|
239
|
|
|
|
|
|
|
for shells with support for POSIX-compliant and multiple .env file syntax. |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head1 AUTHOR |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
Mikko Koivunalho <mikkoi@cpan.org> |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
|
246
|
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
This software is copyright (c) 2023 by Mikko Koivunalho. |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
This is free software; you can redistribute it and/or modify it under |
|
250
|
|
|
|
|
|
|
the same terms as the Perl 5 programming language system itself. |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=cut |