toggle 0.0.0.alpha → 1.0.0.rc
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CONTRIBUTING.md +14 -0
- data/Gemfile +1 -1
- data/LICENSE +13 -0
- data/README.md +304 -8
- data/Rakefile +27 -0
- data/bin/toggle +200 -0
- data/defaults/config.yml.default +23 -0
- data/defaults/key.yml.default +15 -0
- data/lib/toggle.rb +76 -3
- data/lib/toggle/compiler.rb +31 -0
- data/lib/toggle/parser.rb +17 -0
- data/lib/toggle/parser/yaml.rb +12 -0
- data/lib/toggle/version.rb +2 -2
- data/script/ci +42 -0
- data/spec/cli_spec.rb +427 -0
- data/spec/parser/yaml_spec.rb +16 -0
- data/spec/parser_spec.rb +39 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/test/fixtures/cli/.gitkeep +0 -0
- data/spec/test/fixtures/config.yml +9 -0
- data/spec/test/fixtures/flat-key-local +1 -0
- data/spec/test/fixtures/key-local.yml +2 -0
- data/spec/toggle_spec.rb +94 -0
- data/toggle.gemspec +15 -11
- metadata +104 -11
- data/LICENSE.txt +0 -22
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Contributing
|
2
|
+
============
|
3
|
+
|
4
|
+
If you would like to contribute code to Toggle you can do so through GitHub by
|
5
|
+
forking the repository and sending a pull request.
|
6
|
+
|
7
|
+
When submitting code, please make every effort to follow existing conventions
|
8
|
+
and style in order to keep the code as readable as possible.
|
9
|
+
|
10
|
+
Before your code can be accepted into the project you must also sign the
|
11
|
+
[Individual Contributor License Agreement (CLA)][1].
|
12
|
+
|
13
|
+
|
14
|
+
[1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
|
data/Gemfile
CHANGED
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2013 Square Inc.
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
CHANGED
@@ -1,6 +1,37 @@
|
|
1
1
|
# Toggle
|
2
2
|
|
3
|
-
Toggle
|
3
|
+
Toggle provides an organized and flexible framework to set up, manage, and
|
4
|
+
switch between different configuration settings in your Ruby scripts.
|
5
|
+
|
6
|
+
## Why?
|
7
|
+
|
8
|
+
Ensuring that a script has the correct configuration settings can become a real
|
9
|
+
headache. Have you ever had to run a script under different environment
|
10
|
+
specifications or had to share a script that requires different settings based
|
11
|
+
on who is running the code?
|
12
|
+
|
13
|
+
You may have resorted to storing configuration information in a hash to the top
|
14
|
+
of a given script to provide some flexibility. This can work for a script or
|
15
|
+
two and when your on a small team, but as you write more code or increase your
|
16
|
+
team's size the need for organization while still maintaining flexibility
|
17
|
+
quickly arises.
|
18
|
+
|
19
|
+
Having a common pattern around how per-project configurations are handled
|
20
|
+
becomes a big plus. Projects like [rbenv-vars](https://github.com/sstephenson/rbenv-vars)
|
21
|
+
came about to help solve issues like these.
|
22
|
+
|
23
|
+
Toggle provides a project with rbenv-vars-like functionality with two main
|
24
|
+
additions:
|
25
|
+
|
26
|
+
1. rbenv is not required
|
27
|
+
2. you can specify *multiple* environment setups instead of just one on a
|
28
|
+
per-project basis, each of which is easily switchable to either programmatically
|
29
|
+
or at runtime.
|
30
|
+
|
31
|
+
Additionally, Toggle provides a command line interface to facilitate setting up
|
32
|
+
this framework along with a set of options to quickly inspect which variables are
|
33
|
+
available within a project and what each variable is set to for a given environment
|
34
|
+
specification.
|
4
35
|
|
5
36
|
## Installation
|
6
37
|
|
@@ -16,14 +47,279 @@ Or install it yourself as:
|
|
16
47
|
|
17
48
|
$ gem install toggle
|
18
49
|
|
19
|
-
## Usage
|
50
|
+
## Basic Usage
|
51
|
+
|
52
|
+
To start using Toggle you first need a configuration file. This file
|
53
|
+
will typically be in YAML format and can contain inline ERB. The file's content
|
54
|
+
will include all the different configuration sections you want to be able to toggle to.
|
55
|
+
Each section should be namespaced appropriately.
|
56
|
+
|
57
|
+
As an example let's say we have two different script configurations we'd like to
|
58
|
+
have available and we name each `alpha` and `beta` respectively. Then our
|
59
|
+
configuration file might look like:
|
60
|
+
|
61
|
+
```yaml
|
62
|
+
# Sample config.yml demonstrating Toggle usage.
|
63
|
+
# Notice that each section contains the same keys but the values vary.
|
64
|
+
:alpha:
|
65
|
+
:name: mr_alpha
|
66
|
+
:secret: <%= ENV['ALPHA_SECRET'] %> # pretend this is "alpha-secret"
|
67
|
+
|
68
|
+
:beta:
|
69
|
+
:name: mr_beta
|
70
|
+
:secret: <%= ENV['BETA_SECRET'] %> # pretend this is "beta-secret"
|
71
|
+
```
|
72
|
+
|
73
|
+
Now in any script we can leverage Toggle to toggle between each configuration
|
74
|
+
section by setting the `key` attribute, which will load the corresponding
|
75
|
+
configuration section:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
require 'toggle'
|
79
|
+
toggle = Toggle.new config_filepath: './config.yml'
|
80
|
+
|
81
|
+
toggle.key = :alpha
|
82
|
+
puts "#{toggle[:name]} has a secret: #{toggle[:secret]}!"
|
83
|
+
#=> mr_alpha has a secret: alpha-secret
|
84
|
+
|
85
|
+
toggle.key = :beta
|
86
|
+
puts "#{toggle[:name]} has a secret: #{toggle[:secret]}!"
|
87
|
+
#=> mr_beta has a secret: beta-secret
|
88
|
+
```
|
89
|
+
|
90
|
+
Toggle also supports temporary access to a configuration section by passing a
|
91
|
+
block to `#using`:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
require 'toggle'
|
95
|
+
|
96
|
+
toggle = Toggle.new config_filepath: './config.yml',
|
97
|
+
key: :beta
|
98
|
+
|
99
|
+
toggle.using(:alpha) do |s|
|
100
|
+
puts "#{s[:name]} has a secret: #{s[:secret]}!"
|
101
|
+
#=> mr_alpha has a secret: alpha-secret
|
102
|
+
end
|
103
|
+
|
104
|
+
puts "#{toggle[:name]} has a secret: #{toggle[:secret]}!"
|
105
|
+
#=> mr_beta has a secret: beta-secret
|
106
|
+
```
|
107
|
+
|
108
|
+
As an alternative to specifying the `key` attribute programmatically, you can
|
109
|
+
create a key file:
|
110
|
+
|
111
|
+
```yaml
|
112
|
+
# sample key.yml file
|
113
|
+
alpha
|
114
|
+
```
|
115
|
+
|
116
|
+
and then set Toggle's `key_filepath` attribute to specify where the `key`'s
|
117
|
+
value should be derived from:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
require 'toggle'
|
121
|
+
|
122
|
+
toggle = Toggle.new config_filepath: './config.yml',
|
123
|
+
key_filepath: './key.yml'
|
124
|
+
|
125
|
+
puts "#{toggle[:name]} has a secret: #{toggle[:secret]}!"
|
126
|
+
#=> mr_alpha has a secret: alpha-secret
|
127
|
+
```
|
128
|
+
|
129
|
+
## Realworld Use Case: Runtime Toggling
|
130
|
+
|
131
|
+
Let's say there is a developer named Jane and she wants to author a script that
|
132
|
+
connects to a database server, pulls in data and does some processing, and then
|
133
|
+
emails the results to her team.
|
134
|
+
|
135
|
+
As she developes the script she wants to pull data from a staging database and
|
136
|
+
just email the results to herself so she can see how the final product would
|
137
|
+
look without bothering the whole team until the finished product is ready.
|
138
|
+
|
139
|
+
Once everything is complete she wants to pull data from a production database
|
140
|
+
and send the email.
|
141
|
+
|
142
|
+
With Toggle, this is easy:
|
143
|
+
|
144
|
+
```yaml
|
145
|
+
# Jane's sample config.yml
|
146
|
+
:development:
|
147
|
+
:who_to_email: 'jane@company.com'
|
148
|
+
|
149
|
+
:database:
|
150
|
+
:host: https://staging.data.company.com
|
151
|
+
:name: some_staging_db
|
152
|
+
:table: some_staging_table
|
153
|
+
:username: jane
|
154
|
+
:password: <%= ENV['DATABASE_PASSWORD'] %>
|
155
|
+
|
156
|
+
:production:
|
157
|
+
:who_to_email: 'team@company.com'
|
158
|
+
|
159
|
+
:database:
|
160
|
+
:host: https://prod.data.company.com
|
161
|
+
:name: some_prod_db
|
162
|
+
:table: some_prod_table
|
163
|
+
:username: jane
|
164
|
+
:password: <%= ENV['DATABASE_PASSWORD'] %>
|
165
|
+
```
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
# Jane's sample email_data.rb script
|
169
|
+
require 'toggle'
|
170
|
+
|
171
|
+
toggle = Toggle.new config_filepath: './config.yml',
|
172
|
+
key: ENV['key']
|
173
|
+
|
174
|
+
connection = SomeDBDriver.connect host: toggle[:database][:host]
|
175
|
+
username: toggle[:database][:username]
|
176
|
+
password: toggle[:database][:password]
|
20
177
|
|
21
|
-
|
178
|
+
data = connection.get_data_from database: toggle[:database][:name],
|
179
|
+
table: toggle[:database][:table]
|
180
|
+
|
181
|
+
SomeEmailer.send to: toggle[:who_to_email],
|
182
|
+
what: data
|
183
|
+
```
|
184
|
+
|
185
|
+
Now running `email_data.rb` under the development configuration settings is a
|
186
|
+
snap:
|
187
|
+
|
188
|
+
$ key=development ruby email_data.rb
|
189
|
+
# => will connect to the staging db + just email jane
|
190
|
+
|
191
|
+
And when it's deemed ready for primetime it can be run with the production
|
192
|
+
configuration settings via:
|
193
|
+
|
194
|
+
$ key=production ruby email_data.rb
|
195
|
+
# => will connect to the prod db + email the team
|
196
|
+
|
197
|
+
## Realworld Use Case: Abstracted Configuration and Sharing
|
198
|
+
|
199
|
+
Continuing with our example from above, let's say that Jane needs to share the
|
200
|
+
script with John who is another developer on her team so he can work on it
|
201
|
+
(perhaps he wants to add in logic that does not send an email if no data is
|
202
|
+
returned so the team doesn't receive an empty email).
|
203
|
+
|
204
|
+
Jane can further abstract her `config.yml` file to faciliate quick sharing
|
205
|
+
between co-workers:
|
206
|
+
|
207
|
+
```yaml
|
208
|
+
# Jane's new sample config.yml
|
209
|
+
#
|
210
|
+
# Notice that we have abstracted out the email address, database username and
|
211
|
+
# password into ENV vars
|
212
|
+
:development:
|
213
|
+
:who_to_email: <%= ENV['USER_EMAIL'] %>
|
214
|
+
|
215
|
+
:database:
|
216
|
+
:host: https://staging.data.company.com
|
217
|
+
:name: some_staging_db
|
218
|
+
:table: some_staging_table
|
219
|
+
:username: <%= ENV['DATABASE_USERNAME'] %>
|
220
|
+
:password: <%= ENV['DATABASE_PASSWORD'] %>
|
221
|
+
|
222
|
+
:production:
|
223
|
+
:who_to_email: 'team@company.com'
|
224
|
+
|
225
|
+
:database:
|
226
|
+
:host: https://prod.data.company.com
|
227
|
+
:name: some_prod_db
|
228
|
+
:table: some_prod_table
|
229
|
+
:username: <%= ENV['DATABASE_USERNAME'] %>
|
230
|
+
:password: <%= ENV['DATABASE_PASSWORD'] %>
|
231
|
+
```
|
232
|
+
|
233
|
+
John is a `git clone` (or whatever vcs he is using) away from having the
|
234
|
+
script downloaded locally and ready to run without requiring any configuration
|
235
|
+
edits.
|
236
|
+
|
237
|
+
In fact, anyone that has `DATABASE_USERNAME`, `DATABASE_PASSWORD`
|
238
|
+
and `USER_EMAIL` set in their environment can run this script without requiring
|
239
|
+
any configuration adjustments.
|
240
|
+
|
241
|
+
In general if your team uses any common variables you should consider
|
242
|
+
abstracting each into environment variables and including them via ERB. Toggle
|
243
|
+
comes with an easy way to set this up on a per-computer basis. First, run:
|
244
|
+
|
245
|
+
$ toggle --init-local
|
246
|
+
|
247
|
+
This will create `~/.toggle.local`, which you can then edit to `export` any
|
248
|
+
variables you want to be available in your environment. Finally, make sure
|
249
|
+
you source this file so your variables are ready to go.
|
250
|
+
|
251
|
+
## Ignoring the Config and Key Files
|
252
|
+
|
253
|
+
If you can effectively abstract out all configuration settings in environment
|
254
|
+
variables, you may be able to just commit your `config.yml` and your `key.yml`
|
255
|
+
files to source control.
|
256
|
+
|
257
|
+
However, consider .gitignore-ing each and providing a `config.yml.default` and
|
258
|
+
key.yml.default` in their place. With these default files in place you provide
|
259
|
+
runtime guidance, but allow each developer to make any local adjustments without
|
260
|
+
running the risk of having these changes committed back to the project's repo
|
261
|
+
and breaking someone else's settings when they pull in the latest changes.
|
262
|
+
|
263
|
+
Again, borrowing from the above example, if Jane were to instead provide
|
264
|
+
`config.yml.default` and `key.yml.default` files in her repo, anyone that
|
265
|
+
downloaded her repo would need to copy each file to their appropriate location
|
266
|
+
(`config.yml` and `key.yml` respectively) so the script could run. This can be
|
267
|
+
easily accomplished via:
|
268
|
+
|
269
|
+
$ toggle --copy-defaults project/path
|
270
|
+
|
271
|
+
or you can do this manually via:
|
272
|
+
|
273
|
+
$ cp project/path/config.yml.default project/project/config.yml
|
274
|
+
$ cp project/path/key.yml.default project/project/key.yml
|
275
|
+
|
276
|
+
## Toggle CLI
|
277
|
+
|
278
|
+
Toggle comes bundled with a commandline interface:
|
279
|
+
|
280
|
+
```
|
281
|
+
$ toggle --help
|
282
|
+
Usage: toggle <args>
|
283
|
+
|
284
|
+
Specific arguments:
|
285
|
+
-g, --init-local [PATH] Adds [PATH]/.toggle.local with var placeholders. Default is $HOME.
|
286
|
+
-k, --keys file Show available keys for the specified config FILE
|
287
|
+
--values FILE,KEY Show values for the KEY in the config FILE
|
288
|
+
--copy-config-defaults [PATH]
|
289
|
+
Copy all toggle config defaults to actuals in PATH. Default is pwd.
|
290
|
+
-c, --copy-defaults [PATH] Copy all .toggle.default to .toggle for PATH. Default is pwd.
|
291
|
+
--ensure-key [PATH] Copies the default key in [PATH] if actual key is not present, does nothing otherwise. Default [PATH] is pwd.
|
292
|
+
-m, --make-defaults [PATH] Create [PATH]/{config|key}{,.*}.default. Default is pwd.
|
293
|
+
-v, --version Show version
|
294
|
+
-h, --help Show this message
|
295
|
+
```
|
22
296
|
|
23
297
|
## Contributing
|
24
298
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
299
|
+
If you would like to contribute code to Toggle you can do so through GitHub by
|
300
|
+
forking the repository and sending a pull request.
|
301
|
+
|
302
|
+
When submitting code, please make every effort to follow existing conventions
|
303
|
+
and style in order to keep the code as readable as possible.
|
304
|
+
|
305
|
+
Before your code can be accepted into the project you must also sign the
|
306
|
+
[Individual Contributor License Agreement (CLA)][1].
|
307
|
+
|
308
|
+
|
309
|
+
[1]: https://spreadsheets.google.com/spreadsheet/viewform?formkey=dDViT2xzUHAwRkI3X3k5Z0lQM091OGc6MQ&ndplr=1
|
310
|
+
|
311
|
+
## License
|
312
|
+
|
313
|
+
Copyright 2013 Square Inc.
|
314
|
+
|
315
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
316
|
+
you may not use this file except in compliance with the License.
|
317
|
+
You may obtain a copy of the License at
|
318
|
+
|
319
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
320
|
+
|
321
|
+
Unless required by applicable law or agreed to in writing, software
|
322
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
323
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
324
|
+
See the License for the specific language governing permissions and
|
325
|
+
limitations under the License.
|
data/Rakefile
CHANGED
@@ -1 +1,28 @@
|
|
1
|
+
#!/usr/bin/env rake
|
1
2
|
require "bundler/gem_tasks"
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
7
|
+
t.rspec_opts = '-b'
|
8
|
+
end
|
9
|
+
|
10
|
+
task default: :spec
|
11
|
+
rescue LoadError
|
12
|
+
$stderr.puts "rspec not available, spec task not provided"
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'cane/rake_task'
|
17
|
+
|
18
|
+
desc "Run cane to check quality metrics"
|
19
|
+
Cane::RakeTask.new(:quality) do |cane|
|
20
|
+
cane.abc_max = 10
|
21
|
+
cane.style_glob = "lib/**/*.rb"
|
22
|
+
cane.no_doc = true
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :quality
|
26
|
+
rescue LoadError
|
27
|
+
warn "cane not available, quality task not provided."
|
28
|
+
end
|
data/bin/toggle
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
4
|
+
|
5
|
+
require 'toggle'
|
6
|
+
require 'optparse'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
def default_key_filepath
|
10
|
+
File.expand_path('../../defaults/key.yml.default', __FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
def default_config_filepath
|
14
|
+
File.expand_path('../../defaults/config.yml.default', __FILE__)
|
15
|
+
end
|
16
|
+
|
17
|
+
def wants_to_force_copy? current_file
|
18
|
+
respond_yes_to? "File #{current_file} exists. Replace?"
|
19
|
+
end
|
20
|
+
|
21
|
+
def actual_key_in path
|
22
|
+
find_file_in path, /^(key(\.yml))?$/
|
23
|
+
end
|
24
|
+
|
25
|
+
def actual_config_in path
|
26
|
+
find_file_in path, /^config\.yml$/
|
27
|
+
end
|
28
|
+
|
29
|
+
# finds the first file in "path" arg that matches "regex" pattern
|
30
|
+
# returns path + filename
|
31
|
+
def find_file_in path, regex
|
32
|
+
file = Dir[File.join(path, '*')].map { |filepath|
|
33
|
+
File.basename filepath
|
34
|
+
}.find { |filename|
|
35
|
+
filename =~ regex
|
36
|
+
}
|
37
|
+
|
38
|
+
file ? File.join(path, file) : nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns true if response starts with a 'y' or 'Y' (as in 'yes')
|
42
|
+
# Returns false if response starts with a 'n' or 'N' (as in 'no')
|
43
|
+
# Aborts if response starts with a 'q' or 'Q' (as in 'quit')
|
44
|
+
def respond_yes_to? prompt
|
45
|
+
print "#{prompt} (y/n/q) "
|
46
|
+
normalized_response = gets[0].chomp.downcase
|
47
|
+
normalized_response.eql?('q') ? abort('... quitting') : normalized_response.eql?('y')
|
48
|
+
end
|
49
|
+
|
50
|
+
# The reference file is guaranteed to exist
|
51
|
+
def identical_files? reference_file, other_file
|
52
|
+
File.exists?(other_file) && FileUtils.identical?(reference_file, other_file)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Method requires a path and file_pattern and recursively searchs for matching
|
56
|
+
# files.
|
57
|
+
#
|
58
|
+
# When a match is found, method detects if the default is the same as the
|
59
|
+
# "actual" (the same filename just without the .default).
|
60
|
+
#
|
61
|
+
# If the files are identical, the method does nothing. If the actual file does
|
62
|
+
# not exist OR the user opts to clobber the existing, the default will replace
|
63
|
+
# the actual. Otherwise, the actual is left as is.
|
64
|
+
def recursively_copy_defaults path, file_pattern, options = {}
|
65
|
+
defaults = {attempt_force_copy: true}
|
66
|
+
options = defaults.merge(options)
|
67
|
+
|
68
|
+
attempt_force_copy = options[:attempt_force_copy]
|
69
|
+
|
70
|
+
Dir[File.join(path, '/**/', file_pattern)].each do |default_file|
|
71
|
+
file = default_file.slice(/(.*)\.default$/, 1)
|
72
|
+
|
73
|
+
if identical_files? default_file, file
|
74
|
+
puts "Default is identical to #{file}, skipping!"
|
75
|
+
elsif !File.exists?(file) || (attempt_force_copy && wants_to_force_copy?(file))
|
76
|
+
puts "Copying #{file} from default"
|
77
|
+
FileUtils.cp default_file, file
|
78
|
+
else
|
79
|
+
puts "Not changing #{file}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
opt_parser = OptionParser.new do |opts|
|
85
|
+
opts.banner = "Usage: toggle <args>"
|
86
|
+
opts.separator ""
|
87
|
+
opts.separator "Specific arguments:"
|
88
|
+
|
89
|
+
opts.on('-g', '--init-local [PATH]', String, 'Adds [PATH]/.toggle.local with var placeholders. Default is $HOME.') do |path|
|
90
|
+
path ||= ENV['HOME']
|
91
|
+
|
92
|
+
if path && path.empty?
|
93
|
+
raise RuntimeError, 'You must specify a PATH or have HOME env set!'
|
94
|
+
end
|
95
|
+
|
96
|
+
local_config = File.join(path, '.toggle.local')
|
97
|
+
sourcing_bash_instructions = "if [ -s ~/.toggle.local ] ; then source ~/.toggle.local ; fi"
|
98
|
+
|
99
|
+
if !File.exists?(local_config) || wants_to_force_copy?(local_config)
|
100
|
+
content = <<-EOS.strip_heredoc
|
101
|
+
# Add any variables that you'd like below.
|
102
|
+
#
|
103
|
+
# We've included a few suggestions, but please feel free
|
104
|
+
# to modify as needed.
|
105
|
+
#
|
106
|
+
# Make sure that you source this file in your ~/.bash_profile
|
107
|
+
# or ~/.bashrc (or whereever you'd like) via:
|
108
|
+
#
|
109
|
+
# #{sourcing_bash_instructions}
|
110
|
+
export DATABASE_HOST=''
|
111
|
+
export DATABASE_NAME=''
|
112
|
+
export DATABASE_USERNAME=''
|
113
|
+
export DATABASE_PASSWORD=''
|
114
|
+
export USER_EMAIL=''
|
115
|
+
EOS
|
116
|
+
|
117
|
+
%x(echo "#{content}" > #{local_config})
|
118
|
+
puts "Local toggle config added at #{local_config}"
|
119
|
+
puts "Now edit the file and source it from ~/.bash_profile or ~/.bashrc via: #{sourcing_bash_instructions}"
|
120
|
+
else
|
121
|
+
puts "Not changing #{local_config}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
opts.on("-k", "--keys file", String, "Show available keys for the specified config FILE") do |file|
|
126
|
+
opts.banner = "Usage: toggle --keys FILE"
|
127
|
+
|
128
|
+
if File.exists? file
|
129
|
+
toggle = Toggle::Compiler.new(file).parsed_content
|
130
|
+
puts toggle.keys.map{|k| "- #{k}"}.join("\n")
|
131
|
+
else
|
132
|
+
puts "toggle config file not found, please check specified path"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# TODO: remove yaml preamble
|
137
|
+
opts.on("--values FILE,KEY", Array, "Show values for the KEY in the config FILE") do |params|
|
138
|
+
opts.banner = "Usage: toggle --values FILE,KEY"
|
139
|
+
|
140
|
+
if File.exists?(file = params[0])
|
141
|
+
toggle = Toggle::Compiler.new(file).parsed_content
|
142
|
+
if toggle.keys.include?(key = params[1].to_sym)
|
143
|
+
puts toggle[key].to_yaml.gsub(/(:password:).+/, "\\1 [redacted]")
|
144
|
+
else
|
145
|
+
puts "#{key} not found in #{file}"
|
146
|
+
end
|
147
|
+
else
|
148
|
+
puts "toggle config file not found, please check specified path"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on('--copy-config-defaults [PATH]', String, 'Copy all toggle config defaults to actuals in PATH. Default is pwd.') do |path|
|
153
|
+
path ||= Dir.pwd
|
154
|
+
recursively_copy_defaults(path, 'config{,.*}.default')
|
155
|
+
end
|
156
|
+
|
157
|
+
opts.on('-c', '--copy-defaults [PATH]', String, 'Copy all .toggle.default to .toggle for PATH. Default is pwd.') do |path|
|
158
|
+
path ||= Dir.pwd
|
159
|
+
recursively_copy_defaults(path, '{key,config}{,.*}.default')
|
160
|
+
end
|
161
|
+
|
162
|
+
opts.on('--ensure-key [PATH]', String, 'Copies the default key in [PATH] if actual key is not present, does nothing otherwise. Default [PATH] is pwd.') do |path|
|
163
|
+
path ||= Dir.pwd
|
164
|
+
recursively_copy_defaults(path, 'key{,.*}.default', attempt_force_copy: false)
|
165
|
+
end
|
166
|
+
|
167
|
+
opts.on('-m', '--make-defaults [PATH]', String, 'Create [PATH]/{config|key}{,.*}.default. Default is pwd.') do |path|
|
168
|
+
path ||= Dir.pwd
|
169
|
+
|
170
|
+
default_key = actual_key_in(path) || default_key_filepath
|
171
|
+
default_config = actual_config_in(path) || default_config_filepath
|
172
|
+
|
173
|
+
key_destination = File.join(path, 'key.yml.default')
|
174
|
+
config_destination = File.join(path, 'config.yml.default')
|
175
|
+
|
176
|
+
if !File.exists?(key_destination) || wants_to_force_copy?(key_destination)
|
177
|
+
FileUtils.cp(default_key, key_destination) unless identical_files?(default_key, key_destination)
|
178
|
+
puts "Default key written to #{key_destination}"
|
179
|
+
puts "Now go edit it!"
|
180
|
+
end
|
181
|
+
|
182
|
+
if !File.exists?(config_destination) || wants_to_force_copy?(config_destination)
|
183
|
+
FileUtils.cp(default_config, config_destination) unless identical_files?(default_config, key_destination)
|
184
|
+
puts "Default config written to #{config_destination}"
|
185
|
+
puts "Now go edit it!"
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
opts.on_tail("-v", "--version", "Show version") do
|
190
|
+
puts "Toggle version #{Toggle::VERSION}"
|
191
|
+
exit
|
192
|
+
end
|
193
|
+
|
194
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
195
|
+
puts opts
|
196
|
+
exit
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
opt_parser.parse!
|