dotenv 0.9.0 → 2.7.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f9897791ad9e8b033e9bf66513f4f53bd1afb7fa2d925995bcd4f46c6edff8f7
4
+ data.tar.gz: 4bff08bdfbdc9f5709626ab2b46ed098d5c602ccfcb8063457f238dabf459f43
5
+ SHA512:
6
+ metadata.gz: 9594d44181f64067dd47b0e4a86a534620aa09278774ad8c86f08bb6d2d35f45d27a724a16207aee9189f508e00f102686c562d85f2feffd45fe506b6451f828
7
+ data.tar.gz: 9352577bba48b8f713914b1688f17355fc543b4b004a918889ffc1a83dda939e60597ea49c6ef9f3aad7dfcc48fd837fefa4746dfa783088429ea96ffb7fbaed
data/README.md CHANGED
@@ -1,44 +1,90 @@
1
- # dotenv [![Build Status](https://secure.travis-ci.org/bkeepers/dotenv.png)](https://travis-ci.org/bkeepers/dotenv)
1
+ # dotenv [![Build Status](https://secure.travis-ci.org/bkeepers/dotenv.svg?branch=master)](https://travis-ci.org/bkeepers/dotenv) [![Gem Version](https://badge.fury.io/rb/dotenv.svg)](https://badge.fury.io/rb/dotenv) [![Join the chat at https://gitter.im/bkeepers/dotenv](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bkeepers/dotenv?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
2
2
 
3
- Dotenv loads environment variables from `.env` into `ENV`.
3
+ Shim to load environment variables from `.env` into `ENV` in *development*.
4
4
 
5
- Storing [configuration in the environment](http://www.12factor.net/config) is one of the tenets of a [twelve-factor app](http://www.12factor.net/). Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
5
+ Storing [configuration in the environment](http://12factor.net/config) is one of the tenets of a [twelve-factor app](http://12factor.net). Anything that is likely to change between deployment environments–such as resource handles for databases or credentials for external services–should be extracted from the code into environment variables.
6
6
 
7
- But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. Dotenv load variables from a `.env` file into ENV when the environment is bootstrapped.
7
+ But it is not always practical to set environment variables on development machines or continuous integration servers where multiple projects are run. dotenv loads variables from a `.env` file into `ENV` when the environment is bootstrapped.
8
8
 
9
9
  ## Installation
10
10
 
11
11
  ### Rails
12
12
 
13
- Add this line to your application's Gemfile:
13
+ Add this line to the top of your application's Gemfile:
14
14
 
15
15
  ```ruby
16
- gem 'dotenv-rails', :groups => [:development, :test]
16
+ gem 'dotenv-rails', groups: [:development, :test]
17
17
  ```
18
18
 
19
19
  And then execute:
20
20
 
21
- $ bundle
21
+ ```shell
22
+ $ bundle
23
+ ```
24
+
25
+ #### Note on load order
26
+
27
+ dotenv is initialized in your Rails app during the `before_configuration` callback, which is fired when the `Application` constant is defined in `config/application.rb` with `class Application < Rails::Application`. If you need it to be initialized sooner, you can manually call `Dotenv::Railtie.load`.
28
+
29
+ ```ruby
30
+ # config/application.rb
31
+ Bundler.require(*Rails.groups)
32
+
33
+ Dotenv::Railtie.load
34
+
35
+ HOSTNAME = ENV['HOSTNAME']
36
+ ```
37
+
38
+ If you use gems that require environment variables to be set before they are loaded, then list `dotenv-rails` in the `Gemfile` before those other gems and require `dotenv/rails-now`.
39
+
40
+ ```ruby
41
+ gem 'dotenv-rails', require: 'dotenv/rails-now'
42
+ gem 'gem-that-requires-env-variables'
43
+ ```
22
44
 
23
45
  ### Sinatra or Plain ol' Ruby
24
46
 
25
47
  Install the gem:
26
48
 
27
- $ gem install dotenv
49
+ ```shell
50
+ $ gem install dotenv
51
+ ```
28
52
 
29
53
  As early as possible in your application bootstrap process, load `.env`:
30
54
 
31
55
  ```ruby
56
+ require 'dotenv/load'
57
+
58
+ # or
32
59
  require 'dotenv'
33
60
  Dotenv.load
34
61
  ```
35
62
 
63
+ By default, `load` will look for a file called `.env` in the current working directory. Pass in multiple files and they will be loaded in order. The first value set for a variable will win.
64
+
65
+ ```ruby
66
+ require 'dotenv'
67
+ Dotenv.load('file1.env', 'file2.env')
68
+ ```
69
+
70
+ Alternatively, you can use the `dotenv` executable to launch your application:
71
+
72
+ ```shell
73
+ $ dotenv ./script.rb
74
+ ```
75
+
76
+ The `dotenv` executable also accepts a single flag, `-f`. Its value should be a comma-separated list of configuration files, in the order of most important to least. All of the files must exist. There _must_ be a space between the flag and its value.
77
+
78
+ ```
79
+ $ dotenv -f ".env.local,.env" ./script.rb
80
+ ```
81
+
36
82
  To ensure `.env` is loaded in rake, load the tasks:
37
83
 
38
84
  ```ruby
39
85
  require 'dotenv/tasks'
40
86
 
41
- task :mytask => :dotenv do
87
+ task mytask: :dotenv do
42
88
  # things that require .env
43
89
  end
44
90
  ```
@@ -52,42 +98,159 @@ S3_BUCKET=YOURS3BUCKET
52
98
  SECRET_KEY=YOURSECRETKEYGOESHERE
53
99
  ```
54
100
 
55
- You can also create files per environment, such as `.env.test`.
101
+ Whenever your application loads, these variables will be available in `ENV`:
102
+
103
+ ```ruby
104
+ config.fog_directory = ENV['S3_BUCKET']
105
+ ```
106
+
107
+ You may also add `export` in front of each line so you can `source` the file in bash:
56
108
 
57
109
  ```shell
58
- S3_BUCKET=tests3bucket
59
- SECRET_KEY=testsecretkey
110
+ export S3_BUCKET=YOURS3BUCKET
111
+ export SECRET_KEY=YOURSECRETKEYGOESHERE
60
112
  ```
61
113
 
62
- An alternate yaml-like syntax is supported:
114
+ ### Multi-line values
115
+
116
+ If you need multiline variables, for example private keys, you can double quote strings and use the `\n` character for newlines:
63
117
 
64
- ```yaml
65
- S3_BUCKET: yamlstyleforyours3bucket
66
- SECRET_KEY: thisisalsoanokaysecret
118
+ ```shell
119
+ PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\nHkVN9...\n-----END DSA PRIVATE KEY-----\n"
67
120
  ```
68
121
 
69
- Whenever your application loads, these variables will be available in `ENV`:
122
+ Alternatively, multi-line values with line breaks are now supported for quoted values.
123
+
124
+ ```shell
125
+ PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
126
+ ...
127
+ HkVN9...
128
+ ...
129
+ -----END DSA PRIVATE KEY-----"
130
+ ```
131
+
132
+ This is particularly helpful when using the Heroku command line plugin [`heroku-config`](https://github.com/xavdid/heroku-config) to pull configuration variables down that may have line breaks.
133
+
134
+ ### Command Substitution
135
+
136
+ You need to add the output of a command in one of your variables? Simply add it with `$(your_command)`:
137
+
138
+ ```shell
139
+ DATABASE_URL="postgres://$(whoami)@localhost/my_database"
140
+ ```
141
+
142
+ ### Variable Substitution
143
+
144
+ You need to add the value of another variable in one of your variables? You can reference the variable with `${VAR}` or often just `$VAR` in unqoted or double-quoted values.
145
+
146
+ ```shell
147
+ DATABASE_URL="postgres://${USER}@localhost/my_database"
148
+ ```
149
+
150
+ If a value contains a `$` and it is not intended to be a variable, wrap it in single quotes.
151
+
152
+ ```shell
153
+ PASSWORD='pas$word'
154
+ ```
155
+
156
+ ### Comments
157
+
158
+ Comments may be added to your file as such:
159
+
160
+ ```shell
161
+ # This is a comment
162
+ SECRET_KEY=YOURSECRETKEYGOESHERE # comment
163
+ SECRET_HASH="something-with-a-#-hash"
164
+ ```
165
+
166
+ ### Required Keys
167
+
168
+ If a particular configuration value is required but not set, it's appropriate to raise an error.
169
+
170
+ To require configuration keys:
70
171
 
71
172
  ```ruby
72
- config.fog_directory = ENV['S3_BUCKET']
173
+ # config/initializers/dotenv.rb
174
+
175
+ Dotenv.require_keys("SERVICE_APP_ID", "SERVICE_KEY", "SERVICE_SECRET")
73
176
  ```
74
177
 
75
- ## Capistrano integration
178
+ If any of the configuration keys above are not set, your application will raise an error during initialization. This method is preferred because it prevents runtime errors in a production application due to improper configuration.
179
+
180
+ ### Parsing
76
181
 
77
- In your `config/deploy.rb` file:
182
+ To parse a list of env files for programmatic inspection without modifying the ENV:
78
183
 
79
184
  ```ruby
80
- require "dotenv/capistrano"
185
+ Dotenv.parse(".env.local", ".env")
186
+ # => {'S3_BUCKET' => 'YOURS3BUCKET', 'SECRET_KEY' => 'YOURSECRETKEYGOESHERE', ...}
81
187
  ```
82
188
 
83
- It will symlink the `.env` located in `/path/to/shared` in the new release.
189
+ This method returns a hash of the ENV var name/value pairs.
190
+
191
+ ## Frequently Answered Questions
192
+
193
+ ### Can I use dotenv in production?
194
+
195
+ dotenv was originally created to load configuration variables into `ENV` in *development*. There are typically better ways to manage configuration in production environments - such as `/etc/environment` managed by [Puppet](https://github.com/puppetlabs/puppet) or [Chef](https://github.com/chef/chef), `heroku config`, etc.
196
+
197
+ However, some find dotenv to be a convenient way to configure Rails applications in staging and production environments, and you can do that by defining environment-specific files like `.env.production` or `.env.test`.
84
198
 
85
- ## Should I commit my .env file?
199
+ If you use this gem to handle env vars for multiple Rails environments (development, test, production, etc.), please note that env vars that are general to all environments should be stored in `.env`. Then, environment specific env vars should be stored in `.env.<that environment's name>`.
86
200
 
87
- It is recommended that you store development-only settings in your `.env` file, and commit it to your repository. Make sure that all your credentials for your development environment are different from your other deployments. This makes it easy for other developers to get started on your project, without compromising your credentials for other environments.
201
+ ### What other .env* files can I use?
202
+
203
+ `dotenv-rails` will override in the following order (highest defined variable overrides lower):
204
+
205
+ | Hierarchy Priority | Filename | Environment | Should I `.gitignore`it? | Notes |
206
+ | ------------------ | ------------------------ | -------------------- | --------------------------------------------------- | ------------------------------------------------------------ |
207
+ | 1st (highest) | `.env.development.local` | Development | Yes! | Local overrides of environment-specific settings. |
208
+ | 1st | `.env.test.local` | Test | Yes! | Local overrides of environment-specific settings. |
209
+ | 1st | `.env.production.local` | Production | Yes! | Local overrides of environment-specific settings. |
210
+ | 2nd | `.env.local` | Wherever the file is | Definitely. | Local overrides. This file is loaded for all environments _except_ `test`. |
211
+ | 3rd | `.env.development` | Development | No. | Shared environment-specific settings |
212
+ | 3rd | `.env.test` | Test | No. | Shared environment-specific settings |
213
+ | 3rd | `.env.production` | Production | No. | Shared environment-specific settings |
214
+ | Last | `.env` | All Environments | Depends (See [below](#should-i-commit-my-env-file)) | The Original® |
215
+
216
+
217
+ ### Should I commit my .env file?
218
+
219
+ Credentials should only be accessible on the machines that need access to them. Never commit sensitive information to a repository that is not needed by every development machine and server.
220
+
221
+
222
+ You can use the `-t` or `--template` flag on the dotenv cli to create a template of your `.env` file.
223
+ ```shell
224
+ $ dotenv -t .env
225
+ ```
226
+ A template will be created in your working directory named `{FINAME}.template`. So in the above example, it would create a `.env.template` file.
227
+
228
+ The template will contain all the environment variables in your `.env` file but with their values set to the variable names.
229
+
230
+ ```shell
231
+ # .env
232
+ S3_BUCKET=YOURS3BUCKET
233
+ SECRET_KEY=YOURSECRETKEYGOESHERE
234
+ ```
235
+
236
+ Would become
237
+
238
+ ```shell
239
+ # .env.template
240
+ S3_BUCKET=S3_BUCKET
241
+ SECRET_KEY=SECRET_KEY
242
+ ```
243
+
244
+ Personally, I prefer to commit the `.env` file with development-only settings. This makes it easy for other developers to get started on the project without compromising credentials for other environments. If you follow this advice, make sure that all the credentials for your development environment are different from your other deployments and that the development credentials do not have access to any confidential data.
245
+
246
+ ### Why is it not overriding existing `ENV` variables?
247
+
248
+ By default, it **won't** overwrite existing environment variables as dotenv assumes the deployment environment has more knowledge about configuration than the application does. To overwrite existing environment variables you can use `Dotenv.overload`.
88
249
 
89
250
  ## Contributing
90
251
 
252
+ If you want a better idea of how dotenv works, check out the [Ruby Rogues Code Reading of dotenv](https://www.youtube.com/watch?v=lKmY_0uY86s).
253
+
91
254
  1. Fork it
92
255
  2. Create your feature branch (`git checkout -b my-new-feature`)
93
256
  3. Commit your changes (`git commit -am 'Added some feature'`)
data/bin/dotenv CHANGED
@@ -1,12 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "dotenv"
4
-
5
- begin
6
- Dotenv.load!
7
- rescue Errno::ENOENT => e
8
- warn e.message
9
- exit 1
10
- else
11
- exec *ARGV
12
- end
3
+ require "dotenv/cli"
4
+ Dotenv::CLI.new(ARGV).run
data/lib/dotenv.rb CHANGED
@@ -1,25 +1,86 @@
1
- require 'dotenv/environment'
1
+ require "dotenv/parser"
2
+ require "dotenv/environment"
3
+ require "dotenv/missing_keys"
2
4
 
5
+ # The top level Dotenv module. The entrypoint for the application logic.
3
6
  module Dotenv
4
- def self.load(*filenames)
5
- default_if_empty(filenames).inject({}) do |hash, filename|
6
- filename = File.expand_path filename
7
- hash.merge(File.exists?(filename) ? Environment.new(filename).apply : {})
7
+ class << self
8
+ attr_accessor :instrumenter
9
+ end
10
+
11
+ module_function
12
+
13
+ def load(*filenames)
14
+ with(*filenames) do |f|
15
+ ignoring_nonexistent_files do
16
+ env = Environment.new(f, true)
17
+ instrument("dotenv.load", env: env) { env.apply }
18
+ end
8
19
  end
9
20
  end
10
21
 
11
22
  # same as `load`, but raises Errno::ENOENT if any files don't exist
12
- def self.load!(*filenames)
13
- load(
14
- *default_if_empty(filenames).each do |filename|
15
- filename = File.expand_path filename
16
- raise(Errno::ENOENT.new(filename)) unless File.exists?(filename)
23
+ def load!(*filenames)
24
+ with(*filenames) do |f|
25
+ env = Environment.new(f, true)
26
+ instrument("dotenv.load", env: env) { env.apply }
27
+ end
28
+ end
29
+
30
+ # same as `load`, but will override existing values in `ENV`
31
+ def overload(*filenames)
32
+ with(*filenames) do |f|
33
+ ignoring_nonexistent_files do
34
+ env = Environment.new(f, false)
35
+ instrument("dotenv.overload", env: env) { env.apply! }
36
+ end
37
+ end
38
+ end
39
+
40
+ # same as `overload`, but raises Errno::ENOENT if any files don't exist
41
+ def overload!(*filenames)
42
+ with(*filenames) do |f|
43
+ env = Environment.new(f, false)
44
+ instrument("dotenv.overload", env: env) { env.apply! }
45
+ end
46
+ end
47
+
48
+ # returns a hash of parsed key/value pairs but does not modify ENV
49
+ def parse(*filenames)
50
+ with(*filenames) do |f|
51
+ ignoring_nonexistent_files do
52
+ Environment.new(f, false)
17
53
  end
18
- )
54
+ end
55
+ end
56
+
57
+ # Internal: Helper to expand list of filenames.
58
+ #
59
+ # Returns a hash of all the loaded environment variables.
60
+ def with(*filenames)
61
+ filenames << ".env" if filenames.empty?
62
+
63
+ filenames.reduce({}) do |hash, filename|
64
+ hash.merge!(yield(File.expand_path(filename)) || {})
65
+ end
66
+ end
67
+
68
+ def instrument(name, payload = {}, &block)
69
+ if instrumenter
70
+ instrumenter.instrument(name, payload, &block)
71
+ else
72
+ yield
73
+ end
74
+ end
75
+
76
+ def require_keys(*keys)
77
+ missing_keys = keys.flatten - ::ENV.keys
78
+ return if missing_keys.empty?
79
+ raise MissingKeys, missing_keys
19
80
  end
20
81
 
21
- protected
22
- def self.default_if_empty(filenames)
23
- filenames.empty? ? (filenames << '.env') : filenames
82
+ def ignoring_nonexistent_files
83
+ yield
84
+ rescue Errno::ENOENT
24
85
  end
25
86
  end
data/lib/dotenv/cli.rb ADDED
@@ -0,0 +1,80 @@
1
+ require "dotenv"
2
+ require "dotenv/version"
3
+ require "dotenv/template"
4
+ require "optparse"
5
+
6
+ module Dotenv
7
+ # The CLI is a class responsible of handling all the command line interface
8
+ # logic.
9
+ class CLI
10
+ attr_reader :argv, :filenames
11
+
12
+ def initialize(argv = [])
13
+ @argv = argv.dup
14
+ @filenames = []
15
+ end
16
+
17
+ def run
18
+ parse_argv!(@argv)
19
+
20
+ begin
21
+ Dotenv.load!(*@filenames)
22
+ rescue Errno::ENOENT => e
23
+ abort e.message
24
+ else
25
+ exec(*@argv) unless @argv.empty?
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def parse_argv!(argv)
32
+ parser = create_option_parser
33
+ add_options(parser)
34
+ parser.order!(argv)
35
+
36
+ @filenames
37
+ end
38
+
39
+ def add_options(parser)
40
+ add_files_option(parser)
41
+ add_help_option(parser)
42
+ add_version_option(parser)
43
+ add_template_option(parser)
44
+ end
45
+
46
+ def add_files_option(parser)
47
+ parser.on("-f FILES", Array, "List of env files to parse") do |list|
48
+ @filenames = list
49
+ end
50
+ end
51
+
52
+ def add_help_option(parser)
53
+ parser.on("-h", "--help", "Display help") do
54
+ puts parser
55
+ exit
56
+ end
57
+ end
58
+
59
+ def add_version_option(parser)
60
+ parser.on("-v", "--version", "Show version") do
61
+ puts "dotenv #{Dotenv::VERSION}"
62
+ exit
63
+ end
64
+ end
65
+
66
+ def add_template_option(parser)
67
+ parser.on("-t", "--template=FILE", "Create a template env file") do |file|
68
+ template = Dotenv::EnvTemplate.new(file)
69
+ template.create_template
70
+ end
71
+ end
72
+
73
+ def create_option_parser
74
+ OptionParser.new do |parser|
75
+ parser.banner = "Usage: dotenv [options]"
76
+ parser.separator ""
77
+ end
78
+ end
79
+ end
80
+ end