├── .buildpath
├── .gitattributes
├── .gitignore
├── .project
├── .travis.yml
├── CHANGELOG.md
├── CONTRIBUTORS.md
├── Gemfile
├── LICENSE.txt
├── README.md
├── Rakefile
├── lib
├── nugrant.rb
└── nugrant
│ ├── bag.rb
│ ├── config.rb
│ ├── helper
│ ├── bag.rb
│ ├── env
│ │ ├── exporter.rb
│ │ └── namer.rb
│ ├── parameters.rb
│ ├── stack.rb
│ └── yaml.rb
│ ├── mixin
│ └── parameters.rb
│ ├── parameters.rb
│ ├── vagrant
│ ├── errors.rb
│ └── v2
│ │ ├── action.rb
│ │ ├── action
│ │ └── auto_export.rb
│ │ ├── command
│ │ ├── env.rb
│ │ ├── parameters.rb
│ │ ├── restricted_keys.rb
│ │ └── root.rb
│ │ ├── config
│ │ └── user.rb
│ │ ├── helper.rb
│ │ └── plugin.rb
│ └── version.rb
├── locales
├── en.yml
└── fr.yml
├── nugrant.gemspec
└── test
├── lib
├── nugrant
│ ├── helper
│ │ ├── env
│ │ │ └── test_exporter.rb
│ │ ├── test_bag.rb
│ │ ├── test_parameters.rb
│ │ └── test_stack.rb
│ ├── test_bag.rb
│ ├── test_config.rb
│ └── test_parameters.rb
└── test_helper.rb
└── resources
├── .vagrantuser
├── README.md
├── json
├── params_array.json
├── params_boolean.json
├── params_combinations.json
├── params_current_1.json
├── params_current_2.json
├── params_defaults_at_root.json
├── params_defaults_not_at_root.json
├── params_empty.json
├── params_list.json
├── params_simple.json
├── params_system_1.json
├── params_system_2.json
├── params_unix_eol.json
├── params_user_1.json
├── params_user_2.json
├── params_user_nil_values.json
└── params_windows_eol.json
├── vagrantfiles
├── v2.auto_export
├── v2.bag_inside_array
├── v2.defaults_mixed_string_symbols
├── v2.defaults_null_values_in_vagrantuser
├── v2.defaults_using_string
├── v2.defaults_using_symbol
├── v2.empty
├── v2.fake
├── v2.missing_parameter
└── v2.real
└── yaml
├── params_array.yml
├── params_boolean.yml
├── params_combinations.yml
├── params_current_1.yml
├── params_current_2.yml
├── params_defaults_at_root.yml
├── params_defaults_not_at_root.yml
├── params_empty.yml
├── params_list.yml
├── params_numeric_key.yml
├── params_simple.yml
├── params_system_1.yml
├── params_system_2.yml
├── params_unix_eol.yml
├── params_user_1.yml
├── params_user_2.yml
├── params_user_nil_values.yml
└── params_windows_eol.yml
/.buildpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Handle line endings automatically for files detected as text
2 | # and leave all files detected as binary untouched.
3 | * text=auto
4 |
5 | #
6 | # The above will handle all files NOT found below
7 | #
8 | # These files are text and should be normalized (Convert crlf => lf)
9 | Gemfile
10 | Rakefile
11 | Vagrantfile
12 | *.rb text
13 | *.md text
14 | *.gemspec text
15 | *.lock text
16 | *.txt text
17 | *.yml text
18 | *.yaml text
19 | *.prefs text
20 |
21 | # Eclipse specific files
22 | *.project text
23 | *.buildpath text
24 |
25 | # Those have specific eol for testing purpose
26 | test/resources/json/params_unix_eol.json eol=lf
27 | test/resources/json/params_windows_eol.json eol=crlf
28 | test/resources/yml/params_unix_eol.yml eol=lf
29 | test/resources/yml/params_windows_eol.yml eol=crlf
30 |
31 | # These files are binary and should be left untouched
32 | # (binary is a macro for -text -diff)
33 | *.gem binary
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | .yardoc
6 | .vagrant
7 | Gemfile.lock
8 | InstalledFiles
9 | _yardoc
10 | coverage
11 | doc/
12 | lib/nugrant_debug.rb
13 | lib/bundler/man
14 | pkg
15 | rdoc
16 | spec/reports
17 | test/tmp
18 | test/version_tmp
19 | tmp
20 | .idea
21 |
22 | test/resources/vagrantfiles/Vagrantfile
23 | test/resources/vagrantfiles/.vagrantuser
24 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | nugrant
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.dltk.core.scriptbuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.dltk.ruby.core.nature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 |
3 | rvm:
4 | - 2.0.0
5 | - 2.1
6 | - 2.2.3
7 |
8 | before_install:
9 | - rvm @global do gem uninstall bundler -a -x
10 | - rvm @global do gem install bundler -v 1.10.6
11 |
12 | install:
13 | - bundle install --without doc guard --jobs 3 --retry 3
14 |
15 | script: bundle exec rake
16 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 2.1.5 (In Progress)
2 |
3 | # 2.1.4 (November 12th, 2024)
4 |
5 | * Remove usage of `File.exists?` that has been removed and replace with `File.exist?`.
6 |
7 | # 2.1.3 (February 24th, 2016)
8 |
9 | * Ensures Unix line ending are used when generating env scripts
10 | (`autoenv` and `bash`).
11 |
12 | # 2.1.2 (January 12th, 2015)
13 |
14 | * Fixed indifferent access inside arrays. Array elements of type `Hash`
15 | are now converted to `Bag` instances (recursively). This fix the
16 | indifferent access of `Bag` elements inside arrays.
17 |
18 | Fixes [issue #27](https://github.com/maoueh/nugrant/issues/27).
19 |
20 | # 2.1.1 (December 2nd, 2014)
21 |
22 | * Permit numeric keys in bag. They are converted to symbol
23 | like others.
24 |
25 | Fixes [issue #26](https://github.com/maoueh/nugrant/issues/26).
26 |
27 | * Removed old code that was switching YAML engine to `syck` when
28 | it was available.
29 |
30 | Fixes [issue #14](https://github.com/maoueh/nugrant/issues/14) again.
31 |
32 | * Fixed auto export variables on `vagrant provision` feature. The
33 | initial release is not working correctly.
34 |
35 | * Changed how module shortcut is defined. The shortcut is now defined
36 | inside the class using it to avoid already defined warnings.
37 |
38 | Fixes [issue #24](https://github.com/maoueh/nugrant/issues/24).
39 |
40 | # 2.1.0 (November 1st, 2014)
41 |
42 | * Added possibility to specify the script path where to generate
43 | the environment commands (export/unset) when using the
44 | `vagrant user env` command.
45 |
46 | * Added possibility to automatically export variables on vagrant provision.
47 | This can be used by specifying `config.user.auto_export = ` in
48 | your Vagrantfile where can be one of:
49 |
50 | * `false` => No auto export (default value).
51 | * `:autoenv` => Export to [autoenv](https://github.com/kennethreitz/autoenv) script format.
52 | * `:script` => Export to a bash script file.
53 | * `[:autoenv, :script]` => export both format.
54 |
55 | The default generated script path is "./nugrant2env.sh". You can change
56 | the default script name by specifying the configuration key `config.user.auto_export_script_path`
57 | in your Vagrantfile:
58 |
59 | config.user.auto_export_script_path = "./script/example.sh"
60 |
61 | Contributed by [@ruifil](https://github.com/ruifil).
62 |
63 | # 2.0.2 (July 13th, 2014)
64 |
65 | * Fixed a bug when using some vagrant commands. The code to retrieve
66 | the Vagrantfile name was not accurate in respect to where it was
67 | copied. When the env variable `VAGRANT_VAGRANTFILE` is set, it
68 | then must be wrapped inside an array.
69 |
70 | Fixes [issue #21](https://github.com/maoueh/nugrant/issues/21).
71 |
72 | # 2.0.1 (July 10th, 2014)
73 |
74 | * Fixed a bug when using the plugin. A require clause was missing,
75 | it was working when doing commands but not when using Vagrant
76 | directly.
77 |
78 | Fixes [issue #20](https://github.com/maoueh/nugrant/issues/20).
79 |
80 | # 2.0.0 (July 9th, 2014)
81 |
82 | * Fixed retrieval of current directory for `.vagrantuser`. The directory
83 | is now that same as the one of the `Vagrantfile`. Rules have been
84 | copied for Vagrant's one, hence, the behavior should be the same.
85 |
86 | * Fixed bad implementation of config class `::Vagrant.plugin("2", :config)`
87 | where `merge` was not implemented and was causing errors. Now, all objects
88 | (i.e. `Config`, `Bag` and `Parameters` implements `merge` and `merge!`
89 | correctly).
90 |
91 | * Added possibility to change array merge strategy. This can
92 | be used in Vagrant by doing `config.user.array_merge_strategy = `
93 | where valid strategies are:
94 |
95 | * :replace => Replace current values by new ones
96 | * :extend => Merge current values with new ones
97 | * :concat => Append new values to current ones
98 |
99 | * Better handling in Vagrant of cases where the vagrant user
100 | file cannot be parsed correctly. This is now reported
101 | as an error in Vagrant an nicely displayed with the path
102 | of the offending file and the parser error message.
103 |
104 | * Better handling of how global Nugrant options are passed and
105 | handled. Everything is now located in the `Nugrant::Config`
106 | object and used by everything that need some configuration
107 | parameters.
108 |
109 | * It is now possible to customize key error handling by passing
110 | an options hash with key `:key_error` and a `Proc` value.
111 |
112 | * Improved command `vagrant user parameters`. The command now checks if
113 | restricted keys are used and prints a warning when it's the case.
114 |
115 | * Added a new command `vagrant user restricted-keys` that prints the keys that
116 | are restricted, i.e. that cannot be accessed using method access
117 | syntax.
118 |
119 | * Added possibility to specify merge strategy to use when merging
120 | two arrays together.
121 |
122 | ### Backward Incompatibilities
123 |
124 | * Removed deprecated `--script` argument from `vagrant user env` command.
125 |
126 | * Support for Ruby <= 1.9.2 has been dropped. This is not a problem when using
127 | Nugrant as a Vagrant plugin. Use branch `1.x` if you can't upgrade to
128 | Ruby >= 1.9.3.
129 |
130 | * Support for Vagrant 0.x has been dropped. This means that Nugrant 2.x will not
131 | load if installed in a Vagrant 0.x environment. Use branch `1.x` if you can't
132 | upgrade to Vagrant 1.x.
133 |
134 | * `Bag` and `Parameters` and Vagrant configuration object `config.user` are now
135 | [Enumerable](http://ruby-doc.org/core-2.0.0/Enumerable.html).
136 |
137 | This change has implications on the resolving process of the variables
138 | that are stored in the `Bag` when using the dot syntax `(config.user.email)`
139 | in your code and `Vagrantfiles`. By using this syntax with version 2.0, some keys
140 | will collapse with the internal object's methods. In fact, it was already the
141 | case before but to a much smaller scope because object were not enumerable.
142 |
143 | The number of conflicts should be rather low because the restricted keys
144 | are not commonly used as parameter name. The list of the restricted keys
145 | is the following:
146 |
147 | !, !=, !~, <=>, ==, ===, =~, [], __all, __current, __defaults,
148 | __id__, __send__, __system, __user, _detected_errors, _finalize!,
149 | all?, any?, chunk, class, clear!, clone, collect, collect_concat,
150 | compute_all!, compute_bags!, count, cycle, defaults, defaults=,
151 | define_singleton_method, detect, display, drop, drop_while, dup,
152 | each, each_cons, each_entry, each_slice, each_with_index,
153 | each_with_object, empty?, entries, enum_for, eql?, equal?, extend,
154 | finalize!, find, find_all, find_index, first, flat_map, freeze,
155 | frozen?, gem, grep, group_by, has?, hash, include?, inject,
156 | inspect, instance_eval, instance_exec, instance_of?,
157 | instance_variable_defined?, instance_variable_get,
158 | instance_variable_set, instance_variables, instance_variables_hash,
159 | is_a?, kind_of?, lazy, map, max, max_by, member?, merge, merge!,
160 | method, method_missing, methods, min, min_by, minmax, minmax_by,
161 | nil?, none?, object_id, one?, partition, private_methods,
162 | protected_methods, psych_to_yaml, public_method, public_methods,
163 | public_send, reduce, reject, remove_instance_variable, respond_to?,
164 | reverse_each, select, send, set_options, singleton_class,
165 | singleton_methods, slice_before, sort, sort_by, suppress_warnings,
166 | taint, tainted?, take, take_while, tap, to_a, to_enum, to_hash,
167 | to_json, to_s, to_set, to_yaml, to_yaml_properties, trust, untaint,
168 | untrust, untrusted?, validate, zip
169 |
170 | * The `Parameter` class has a new API.
171 |
172 | * The `Bag` class has a new API.
173 |
174 | # 1.4.2 (January 11th, 2014)
175 |
176 | * Fixed Vagrant `user` config class to make the `has?` method
177 | available to people using Vagrant. This considered has a bug
178 | fix because using `has?` was not working anyway before.
179 |
180 | # 1.4.1 (December 15th, 2013)
181 |
182 | * Fixed a superfluous warning message when using ruby >= 2.0.0 which is now the
183 | default when installing Vagrant >= 1.4.0 (at least on Windows).
184 |
185 | # 1.4.0 (November 28th, 2013)
186 |
187 | * Adding support to export to an [autoenv](https://github.com/kennethreitz/autoenv)
188 | file. See [GH-13](https://github.com/maoueh/nugrant/issues/13).
189 |
190 | * Deprecated usage of `-s, --script` option for command
191 | `vagrant user env`. This was replaced by the more generic
192 | and extensible `-f, --format FORMAT` option. The
193 | `-s, --script` option will be removed in 2.0.
194 |
195 | # 1.3.0 (November 19th, 2013)
196 |
197 | * Now using [minitest](https://github.com/seattlerb/minitest) as our
198 | testing library.
199 |
200 | * Added a new command that can be used either standalone or via
201 | a small bash script to easily export environment variables
202 | from your currently set parameters. See
203 | [GH-13](https://github.com/maoueh/nugrant/issues/13).
204 |
205 | * Keys associated to a null value are considered as being missing
206 | by the merge process. It is still possible to define a null
207 | parameter, but it will be overridden by any parameter and will not
208 | override any. See [GH-12](https://github.com/maoueh/nugrant/issues/12).
209 |
210 | * Fixed output of command `vagrant user parameters`, the keys were
211 | serialized as symbol instead of string.
212 |
213 | # 1.2.0 (October 24th, 2013)
214 |
215 | * Now showing better error message to the end-user when a parameter
216 | cannot be found. The message displays which key could not be found.
217 | Moreover, we show the context within the Vagrantfile where we think
218 | the error occurred:
219 |
220 | ```
221 | Nugrant: Parameter 'param' was not found, is it defined in
222 | your .vagrantuser file? Here where we think the error
223 | could be in your Vagrantfile:
224 |
225 | 1: Vagrant.configure("2") do |config|
226 | 2:>> puts config.user.param
227 | 3: end
228 | ```
229 |
230 | See [GH-8] (https://github.com/maoueh/nugrant/issues/8).
231 |
232 | * Ensured that keys used within a `Bag` are always symbol. This make
233 | sure that it is possible to retrieve a value with any access method.
234 | See [GH-9](https://github.com/maoueh/nugrant/issues/9).
235 |
236 | * Now using [multi_json](https://rubygems.org/gems/multi_json)
237 | for JSON handling.
238 |
239 | # 1.1.0 (May 17th, 2013)
240 |
241 | * Rewrite completely classes `Parameters` and `Bag`.
242 | * Reduced chances to have a parameter name collapsing with an
243 | implementation method.
244 |
245 | * Removed dependency on `deep_merge`. We do now perform
246 | our own merge.
247 |
248 | * Added possibility to iterate through keys by using
249 | `.each`:
250 |
251 | ```
252 | config.user.local.each do |name, value|
253 | puts "Key #{name}: #{value}"
254 | end
255 | ```
256 |
257 | ### Backward Incompatibilities
258 |
259 | * `Parameters` is not extending the `Bag` class anymore.
260 |
261 | * `Parameters` and `Bag` attributes and methods are now almost
262 | all prefixed with __ to reduce clashes to a minimum when
263 | accessing parameters with method-like syntax
264 | (i.e. `parameters.git.master` instead of `parameters['git']['master']`)
265 |
266 | # 1.0.1 (April 9th, 2013)
267 |
268 | * Fixed a crash when `user` config value is `nil` preventing `vagrant user parameters`
269 | from working as expected. See [GH-4](https://github.com/maoueh/nugrant/issues/4).
270 |
271 | * Fixed a bug preventing the version from being printed when doing `vagrant user -v`.
272 |
273 | # 1.0.0 (March 21th, 2013)
274 |
275 | * For now on, this gem will follow semantic versioning.
276 | * Refactored how Vagrant plugin is architectured.
277 | * Now supporting Vagrant 1.1.x (Plugin version "2").
278 |
279 | # 0.0.14
280 |
281 | * Renamed `ParameterBag` to `Bag`
282 |
283 | * Cleanup `Bag` api
284 | * Renamed method `has_param?` to `has_key?` in `Bag`
285 | * Removed method `get_params` from `Bag`
286 |
287 | # 0.0.13
288 |
289 | * Cleanup `Parameters` and `ParameterBag` interface
290 | * The method `defaults` has been removed from the bag
291 | * Setting defaults on `Parameters` now recompute the final bag
292 |
293 | * Improved `vagrant user parameters` command
294 | * Now using the exact config as seen by Vagrant, this includes defaults parameters
295 | * An option has been added to only see defaults parameters
296 |
297 | # 0.0.12
298 |
299 | * Added travis configuration file
300 |
301 | * Added travis build status icon to readme
302 |
303 | * Fixed a bug when `.vagrantuser` file is empty or not a hash type
304 |
305 | * Improved parameters command
306 | * The parameters command is now a proper subcommand
307 | * An option has been added to see system parameters
308 | * An option has been added to see user parameters
309 | * An option has been added to see project parameters
310 |
311 | # 0.0.11
312 |
313 | * Updated README file for installation via rubygems.org
314 |
315 | # 0.0.10
316 |
317 | * Added a subcommand `parameters` for vagrant command `user`
318 |
319 | * Added a vagrant command `vagrant user subcommand [options]`
320 |
321 | # 0.0.9
322 |
323 | * Fixed a bug with the new default values implementation
324 |
325 | # 0.0.8
326 |
327 | * Introduced possibility to set default values
328 |
329 | * Introduced restricted keys (For now, restricted keys are [`defaults`]).
330 |
331 | * Fixed a bug with system-wide parameters
332 |
333 | # 0.0.7
334 |
335 | * YAML is back as the default file format for parameters
336 |
337 | # 0.0.6
338 |
339 | * Fixed a bug on ruby 1.8.7 which doesn't have yaml included in its load path by default
340 |
341 | # 0.0.5
342 |
343 | * Introduced system-wide parameters file
344 |
345 | # 0.0.4
346 |
347 | * JSON is now the default file format for parameters (due to problem with YAML)
348 |
349 | * It is now possible to store parameters in the JSON format
350 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | # Contributors
2 |
3 | Thanks for this people who contributed some code to Nugrant:
4 |
5 | * Rui Filipe Da Cunha Alves ([@ruifil](https://github.com/ruifil))
6 | * Michał Sochoń ([@nvtkaszpir](https://github.com/nvtkaszpir))
7 | * jpegger ([@jpegger](https://github.com/jpegger))
8 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | group :development do
4 | gem "rake", "~> 10.3"
5 | gem "minitest", "~> 5.3"
6 | gem "minitest-reporters", "~> 1.0"
7 |
8 | gem "vagrant", :git => "https://github.com/mitchellh/vagrant.git", :branch => "master"
9 | end
10 |
11 | group :plugins do
12 | gem "nugrant", path: "."
13 | end
14 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2014 Matthieu Vachon
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nugrant
2 |
3 | [][gem]
4 | [][travis]
5 | [][gemnasium]
6 | [][codeclimate]
7 |
8 | [gem]: https://rubygems.org/gems/nugrant
9 | [travis]: http://travis-ci.org/maoueh/nugrant
10 | [gemnasium]: https://gemnasium.com/maoueh/nugrant
11 | [codeclimate]: https://codeclimate.com/github/maoueh/nugrant
12 |
13 | Nugrant is a library to easily handle parameters that need to be
14 | injected into an application via different sources (system, user,
15 | current, defaults). But foremost, a Vagrant plug-in that will enhance
16 | Vagrantfile to allow user specific configuration values.
17 |
18 | Supported platforms:
19 |
20 | * Vagrant 1.x
21 | * Ruby 1.9.3+
22 |
23 | ## Quick Start
24 |
25 | Using Nugrant as a plug-in provides an easy and hierarchical system to manage
26 | machine and user specific parameters.
27 |
28 | Let's start with an example. You need to distribute among your enterprise a
29 | `Vagrantfile` to start and provision an AWS EC2 instance (or for an open-source project).
30 | The `aws_access_key` and `aws_secret_key` should be configurable depending on the user
31 | running `vagrant up`.
32 |
33 | To achieve this, simply create a file named `.vagrantuser` that resides in the directory
34 | as your `Vagrantfile`:
35 |
36 | aws:
37 | access_key: "123456"
38 | secret_key: "abcdef"
39 |
40 | In your `Vagrantfile`, `Nugrant` will let you access the parameters via the
41 | `config.user` object:
42 |
43 | Vagrant.configure("2") do |config|
44 | ...
45 |
46 | config.vm.provider :aws do |aws, override|
47 | aws.access_key_id = config.user.aws.access_key
48 | aws.secret_access_key = config.user.aws.secret_key
49 |
50 | ...
51 | end
52 | end
53 |
54 | You then ignore the `.vagrantuser` file in your revision control, so each developer
55 | as a specific one with their own values. People often commit a `.vagrantuser.example`
56 | file in project's repository as an easy startup for the various parameters that
57 | must be filled in, something like:
58 |
59 | aws:
60 | access_key: ""
61 | secret_key: ""
62 |
63 | To find where your project `.vagrantuser` is located, Nugrant uses the directory
64 | where the `Vagrantfile` is located. It achieves this using the same set of
65 | rules as Vagrant meaning you can be in a nested directory and parameters
66 | will still be fetched correctly.
67 |
68 | Moreover, like other similar system, there is a hierarchy of `.vagrantuser` files
69 | that you can leverage:
70 |
71 | | Name | Location | Priority | Overrides |
72 | | ---------|-----------------------------------------|:---------:|--------------------------|
73 | | Defaults | [config.user.defaults](#default-values) | 4 | - |
74 | | System | $SYSTEM/.vagrantuser | 3 | Defaults |
75 | | User | ~/.vagrantuser | 2 | Defaults & System |
76 | | Project | .vagrantuser | 1 | Defaults & System & User |
77 |
78 | The project level directory is always the same as the directory where your
79 | `Vagrantfile` resides and same rules as Vagrant are used to find it.
80 | The `~` is the user's home directory and `$SYSTEM` is the platform dependent
81 | folder where system global can be put. Check [Hierarchy](#hierarchy) section
82 | for where `$SYSTEM` maps exactly.
83 |
84 | You can use the command `vagrant user parameters` to see the final merged
85 | hierarchy seen by Nugrant. This command also prints [restricted keys](#restricted-keys)
86 | defined in your hierarchy.
87 |
88 | Accessing parameters in your `Vagrantfile` can be done either by method access
89 | (i.e. `config.user.`) or by array access (i.e. `config.user[]`).
90 | This support is working for any deepness, only `config.user` is different
91 | because provided directly by `Vagrant` and not by this plugin.
92 |
93 | However, a drawback with method access, not present with array access, is its
94 | set of [restricted keys](#restricted-keys) for which usage is prohibited. These
95 | are in facts calls to method defined by the [Bag](lib/nugrant/bag.rb) class
96 | ([Bag](lib/nugrant/bag.rb) extends [Hash](http://ruby-doc.org/core-2.0/Hash.html)).
97 | It's plain Ruby, use it at your advantage like iterating through a collection
98 | using the `.each` method.
99 |
100 | This is where the quick start end. Continue to section [Installation](#installation)
101 | if you need so help on how to install Nugrant. Or jump to [Usage](#usage) section
102 | which describe in greater details all necessary information needed to deeply
103 | understand Nugrant and use it at its full potential.
104 |
105 | ## Installation
106 |
107 | ### Vagrant
108 |
109 | Vagrant's plug-in system is very well done and Nugrant supports
110 | the following plug-in API versions:
111 |
112 | * V2 => Vagrant 1.x
113 |
114 | To install the Nugrant as a Vagrant plug-in, simply type the following
115 | command in a terminal:
116 |
117 | vagrant plugin install nugrant
118 |
119 | #### Vagrant 0.x
120 |
121 | Vagrant 0.x is not supported anymore. If you still need support for
122 | Vagrant 0.x, please use release line `1.x` (branch [1.x](https://github.com/maoueh/nugrant/tree/1.x)).
123 |
124 | ### Library
125 |
126 | If you would like to use Nugrant as a library, simply reference
127 | it as a dependency of your application. Probably by adding it to
128 | your `Gemfile` or your `.gemspec` file.
129 |
130 | "nugrant", "~> 2.0"
131 |
132 | ## Usage
133 |
134 | Whether used as a library or a Vagrant plug-in, Nugrant has some
135 | common concepts that apply to both usages. The most important
136 | one is the parameters hierarchy.
137 |
138 | ### Common
139 |
140 | Nugrant can read parameters from various locations and will merge
141 | them all together in a single set. Merging is done in a fairly
142 | standard fashion.
143 |
144 | Here the precedence rules that apply when merging parameters
145 | from various location. List index indicate the priority of the
146 | entry. Entry with lower number has lower priority (values at this
147 | priority will be overridden by values defined on higher priorities).
148 |
149 | 1. Defaults
150 | 2. System
151 | 3. User
152 | 4. Current
153 |
154 | In text, this means that current parameters overrides user
155 | parameters, user parameters overrides system parameters and
156 | finally system parameters overrides defaults parameters.
157 |
158 | When two keys that are merged together points to Array values,
159 | the default operation is to replace current Array by
160 | overriding one. The default merge strategy can be customized.
161 |
162 | ### Vagrant
163 |
164 | All examples shown here are for Vagrant 1.1+. They have
165 | been tested with Vagrant 1.4.0. Keep this in mind when
166 | copying examples.
167 |
168 | Let start with a small use case. Say the git repository you want
169 | to share with your guest VM is not located under the root folder of
170 | your `Vagrantfile`. That means you will need to specify
171 | an absolute host path to share the folder on the guest VM.
172 |
173 | Your `Vagrantfile` would look like this:
174 |
175 | Vagrant.configure("2") do |config|
176 | config.vm.box = "base"
177 | config.vm.synced_folder "/home/user/work/git", "/git"
178 | end
179 |
180 | However, what happens when multiple developers
181 | need to share the same `Vagrantfile`? This is the main
182 | use case this plug-in try to address.
183 |
184 | When Vagrant starts, it loads all vagrant plug-ins it knows
185 | about. If you installed the plug-in with one of the two
186 | methods we listed above, Vagrant will know about Nugrant
187 | and will load it correctly.
188 |
189 | To use the plug-in, first create a YAML file named
190 | `.vagrantuser` in the same folder where your `Vagrantfile` is
191 | located. The file must be a valid YAML file:
192 |
193 | repository:
194 | project: "/home/user/work/git"
195 |
196 | The configuration hierarchy you define in the `.vagrantuser` file
197 | is imported into the `config` object of the `Vagrantfile`
198 | under the key `user`. So, with the `.vagrantuser` file above, you
199 | could have this `Vagrantfile` that abstract absolute paths.
200 |
201 | Vagrant.configure("2") do |config|
202 | config.vm.box = "base"
203 | config.vm.synced_folder config.user.repository.project, "/git"
204 | end
205 |
206 | This way, paths can be customized by every developer. They just
207 | have to add a `.vagrantuser` file where user specific configuration
208 | values can be specified. The `.vagrantuser` should be ignored by you
209 | version control system so it is to committed with the project.
210 |
211 | Additionally, you can also have a `.vagrantuser` under your user home
212 | directory. This way, you can set parameters that will be
213 | available to all your `Vagrantfile` files. The `.vagrantuser` located
214 | within the same folder as the `Vagrantfile` file will overrides
215 | parameters defined in the `.vagrantuser` file defined in the user
216 | home directory.
217 |
218 | For example, you have `.vagrantuser` file located at `~/.vagrantuser`
219 | that has the following content:
220 |
221 | ssh_port: 2223
222 | repository:
223 | project: "/home/user/work/git"
224 |
225 | And another `.vagrantuser` within the same folder as your `Vagrantfile`:
226 |
227 | ssh_port: 3332
228 | repository:
229 | personal: "/home/user/personal/git"
230 |
231 | Then, the `Vagrantfile` could be defined like this:
232 |
233 | Vagrant.configure("2") do |config|
234 | config.ssh.port config.user.ssh_port
235 |
236 | config.vm.synced_folder config.user.repository.project, "/git"
237 | config.vm.synced_folder config.user.repository.personal, "/personal"
238 | end
239 |
240 | That would be equivalent to:
241 |
242 | Vagrant.configure("2") do |config|
243 | config.ssh.port 3332
244 |
245 | config.vm.synced_folder "/home/user/work/git", "/git"
246 | config.vm.synced_folder "/home/user/personal/git", "/personal"
247 | end
248 |
249 | #### Hierarchy
250 |
251 | As you can see, the parameters defined in the second `.vagrantuser` file
252 | (the current one) overrides settings defined in the `.vagrantuser` found
253 | in the home directory (the user one).
254 |
255 | Here the list of locations where Nugrant looks for parameters:
256 |
257 | 1. Defaults (via `config.user.defaults` in `Vagrantfile`)
258 | 2. System (`/etc/.vagrantuser` on Unix, `%PROGRAMDATA%/.vagrantuser` or `%ALLUSERSPROFILE%/.vagrantuser` on Windows)
259 | 3. Home (`~/.vagrantuser`)
260 | 4. Project (`.vagrantuser` within the same folder as the `Vagrantfile`)
261 |
262 | #### Paths
263 |
264 | When you want to specify paths on, specially on Windows, it's probably
265 | better to only use forward slash (`/`). The main reason for this is because
266 | Ruby, which will be used at the end by Vagrant is able to deal with forward
267 | slash even on Windows. This is great because with this, you can avoid
268 | values escaping in YAML file. If you need to use backward slash (`\`), don't
269 | forget to properly escape it!
270 |
271 | value: "C:/Users/user/work/git"
272 | value: "C:\\Users\\user\\work\\git"
273 |
274 | Moreover, it is preferable that paths are specified in full
275 | (i.e. no `~` for HOME directory for example). Normally, they
276 | should be handled by `Vagrant` but it may happen that it's not
277 | the case. If your have an error with a specific parameter,
278 | either expand it in your config:
279 |
280 | project: "/home/joe/work/ruby/git"
281 |
282 | Of expand it in the `Vagrantfile`:
283 |
284 | config.vm.synced_folder File.expand_path(config.user.repository.project), "/git"
285 |
286 | #### Parameters access
287 |
288 | Parameters in the `Vagrantfile` can be retrieved via method call
289 | of array access.
290 |
291 | config.user['repository']['project'] # Array access
292 | config.user.repository.project # Method access
293 |
294 | You can even mix the two if you want, but we do not recommend
295 | it since its always better to be consistent:
296 |
297 | config.user['repository'].project # Mixed access
298 | config.user.repository['project'] # Mixed access
299 |
300 | Only the root key, i.e. `config.user`, cannot be access with
301 | both syntax, only the method syntax can be used since this
302 | is not provided by this plug-in but by Vagrant itself.
303 |
304 | ##### Tips
305 |
306 | Each non-final parameter (i.e a parameter that contains other parameters and
307 | not a scalar value) is in fact a [Bag](/lib/nugrant/bag.rb)
308 | object. You can call any defined methods on it. This object extends
309 | [Hash](http://ruby-doc.org/core-2.0/Hash.html) (itself including
310 | module [Enumerable](http://ruby-doc.org/core-2.0/Enumerable.html)). Hence,
311 | you can do neat things like iterating over your values or filtering them:
312 |
313 | config.user.application.users.each do |key, data|
314 | puts "Key #{key}: #{data}"
315 | end
316 |
317 | ##### Restricted keys
318 |
319 | Method access has the neat advantage of being beautiful to the
320 | eye. However, the drawback of using this retrieval syntax is
321 | that not all keys are permitted. As explained in the [Tips](#tips)
322 | section, the object you are calling when using method access
323 | is in fact of type [Bag](/lib/nugrant/bag.rb). Hence, if you
324 | are using a key which collapse with ones of Bag's keys, it will
325 | call the method instead of given you the value of you parameter.
326 | At best, you will get a weird behavior and at worst a stack
327 | trace when trying to access the parameter.
328 |
329 | If you really want to use one of the restricted keys, simply
330 | ensure to always use array access method.
331 |
332 | The list of restricted keys can be accessed using command
333 | `vagrant user restricted-keys`.
334 |
335 | #### Default values
336 |
337 | When using parameters, it is often needed so set default values
338 | for certain parameters so if the user does not define one, the
339 | default value will be picked up.
340 |
341 | For example, say you want a parameter that will hold the ssh
342 | port of the vm. This parameter will be accessible via the
343 | parameter `config.user.vm.ssh_port`.
344 |
345 | You can use the following snippet directly within your Vagrantfile
346 | to set a default value for this parameter:
347 |
348 | Vagrant.configure("2") do |config|
349 | config.user.defaults = {
350 | "vm" => {
351 | "ssh_port" => "3335"
352 | }
353 | }
354 |
355 | config.ssh.port config.user.vm.ssh_port
356 | end
357 |
358 | With this Vagrantfile, the parameter `config.user.vm.ssh_port`
359 | will default to `3335` in cases where it is not defined by the
360 | user.
361 |
362 | If the user decides to change it, he just has to set it in his
363 | own `.vagrantuser` and it will override the default value defined
364 | in the Vagrantfile.
365 |
366 | #### Array merge strategies
367 |
368 | As stated previously, when two arrays are merged together,
369 | the default strategy is to replace current array with new one.
370 |
371 | However, in some certain circumstances, you may need another
372 | behavior. Here the list of strategies that can be used.
373 |
374 | * `:replace` (*default*)
375 | With this strategy, the new array completely replace the
376 | current one.
377 |
378 | * `:concat`
379 | With this strategy, new array is appended to the end
380 | of current array when merged. The `Array` `+` operator
381 | is used to concatenante the two arrays.
382 |
383 | * `:extend`
384 | With this strategy, current array is extended with values
385 | from new one. The `Array` `|` (union) operator
386 | is used to extend the array.
387 |
388 | You can use the following snippet directly within your Vagrantfile
389 | to change the array merge strategy:
390 |
391 | Vagrant.configure("2") do |config|
392 | config.user.array_merge_strategy = :extend
393 |
394 | config.ssh.port config.user.vm.ssh_port
395 | end
396 |
397 | Note that you should change the array merge strategy before
398 | you access any keys because it's just once set that values
399 | are computed using the new strategy.
400 |
401 | If you specify an unsupported strategy, nothing will happen.
402 |
403 | #### Commands
404 |
405 | In this section, we describe the various vagrant commands defined
406 | by this plug-in that can be used to interact with it.
407 |
408 | ##### Parameters
409 |
410 | This command will print the currently defined parameters at the
411 | given location. All rules are respected when using this command.
412 | It is usefull to see what parameters are available and what are
413 | the current values of those parameters.
414 |
415 | Usage:
416 |
417 | > vagrant user parameters
418 | ---
419 | config:
420 | user:
421 | chef:
422 | cookbooks_path: /Users/Chef/kitchen/cookbooks
423 | nodes_path: /Users/Chef/kitchen/nodes
424 | roles_path: /Users/Chef/kitchen/roles
425 |
426 | Add flag `-h` (or `--help`) for description of the command and a
427 | list of available options.
428 |
429 | ##### Restricted Keys
430 |
431 | This command will print the keys that cannot be accessed using
432 | the method access syntax.
433 |
434 | Usage:
435 |
436 | > vagrant user restricted-keys
437 |
438 | ##### Env
439 |
440 | Sometimes, you would like to have acces to the different values
441 | stored in your `.vagrantuser` from environment variables: this is
442 | exactly what this section is meant to show you.
443 |
444 | By using one of the three methods below, you will be able to export
445 | (but also unset) environment variables from your current
446 | parameters as seen by Nugrant.
447 |
448 | You can see the commands that will be executed by simply
449 | calling the method:
450 |
451 | vagrant user env
452 |
453 | The name of the environment will be upper cased and full path of
454 | the key, without the `config.user` prefix, separated
455 | with `_`. For example, the key accessible using
456 | `config.user.db.user` and with value `root` would generate the
457 | export command:
458 |
459 | export DB_USER=root
460 |
461 | The value are escaped so it is possible to define value containing
462 | spaces for example.
463 |
464 | A last note about generate commands is that pre-existing environment
465 | variable are not taking in consideration by this command. So if
466 | an environment variable with name `DB_USER` already exist, it
467 | would be overwritten by an export command.
468 |
469 | Add flag `-h` (or `--help`) for description of the command and a
470 | list of available options.
471 |
472 | It's possible to export variables automatically on when Vagrant
473 | provision your VM. Refer to [Automatic Exporting section](#automatic-exporting)
474 | for more information.
475 |
476 | ###### Method #1
477 |
478 | If you plan to frequently use this feature, our best suggestion
479 | is to create a little bash script that will simply delegates
480 | to the real command. By having a bash script that calls the
481 | command, you will be able to easily export environment variables
482 | by sourcing the script.
483 |
484 | Create a file named `nugrant2env` somewhere accessible from
485 | the `$PATH` variable with the following content:
486 |
487 | #!/bin/env sh
488 |
489 | $(vagrant user env "$@")
490 |
491 | This script will simply delegates to the `vagrant user env`
492 | command and pass all arguments it receives to it. The
493 | magic happens because the command `vagrant user env` outputs
494 | the various export commands to the standard output.
495 |
496 | By sourcing the simple delegating bash script, the parameters
497 | seen by Nugrant will be available in your environment:
498 |
499 | . nugrant2env
500 |
501 | By default, export commands are generated. But you can pass
502 | some options to the `nugrant2env` script, For example, to
503 | generate the unset ones, add `--unset` (or simply `-u`).
504 |
505 | . nugrant2env --unset
506 |
507 | For a list of options, see the help of the command delegated
508 | to:
509 |
510 | vagrant user env -h
511 |
512 | ###### Method #2
513 |
514 | Use the command to generate a base script in the current
515 | directory that you will then source:
516 |
517 | vagrant user env --format script
518 |
519 | This will generate a script called `nugrant2env.sh` into the
520 | current directory. You then simply source this script:
521 |
522 | . nugrant2env.sh
523 |
524 | Using `vagrant user env -u --format script` will instead generate the bash
525 | script that will unset the environment variables. Don't forget
526 | to source it to unset variables.
527 |
528 | ###### Method #3
529 |
530 | Use the command to generate an [autoenv](https://github.com/kennethreitz/autoenv)
531 | file in the current directory. By using the [autoenv] project, anytime you
532 | will enter the project directory via the `cd` command, variables
533 | exported found in the `.env` file generated will be exported to
534 | your environment.
535 |
536 | vagrant user env --format autoenv
537 |
538 | This will generate a file called `.env` in the
539 | current directory. You then simply change to the directory
540 | where the `.env` file was generated to made exported variables
541 | available in your environment.
542 |
543 | cd ..
544 | cd
545 |
546 | Using `vagrant user env -u --format autoenv` will instead generate
547 | the autoenv file that will unset the environment variables.
548 |
549 | #### Automatic Exporting
550 |
551 | Running the right command each time variables change can be repetive
552 | for nothing. Why not let the computer do the hard work for us, they
553 | have been created for this after all.
554 |
555 | You can achieve this using the `config.user.auto_export` parameter.
556 | Defaulting to `false`, you can use it to export the variables
557 | to your desired format. When set to a valid value, each time
558 | vagrant will provision your VM, Nugrant will automatically
559 | export variables for your.
560 |
561 | Use the following configuration to export to [autoenv](https://github.com/kennethreitz/autoenv)
562 | script format.
563 |
564 | config.user.auto_export = :autoenv
565 |
566 | Use the following configuration to export to bash script.
567 |
568 | config.user.auto_export = :script
569 |
570 | You can also pass an array of formats if you would like to export to
571 | multiple formats at the same time.
572 |
573 | config.user.auto_export = [:autoenv, :script]
574 |
575 |
576 | The default filename for bash script (i.e. when using `:script` value) is
577 | `./nugrant2env.sh`. You can control this by using parameter
578 | `config.user.auto_export_script_path`:
579 |
580 | config.user.auto_export_script_path = "./script/env.sh"
581 |
582 | ### Library
583 |
584 | Using Nugrant as a library to handle parameters from various
585 | location is really easy. Two main classes need to be handled.
586 |
587 | First, you need to create a `Nugrant::Config` object. This
588 | configuration holds the values that needs to be customized
589 | by your own application. This includes the different parameters paths
590 | and the format of the parameters file.
591 |
592 | ## Contributing
593 |
594 | You can contribute by filling issues when something goes
595 | wrong or was not what you expected. I will do my best
596 | to fix the issue either in the code or in the documentation,
597 | where applicable.
598 |
599 | You can also send pull requests for any feature or improvement
600 | you think should be included in this plug-in. I will evaluate
601 | each of them and merge them as fast as possible.
602 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require "bundler/setup"
2 | require "rake/testtask"
3 |
4 | # Immediately sync all stdout so that tools like buildbot can
5 | # immediately load in the output.
6 | $stdout.sync = true
7 | $stderr.sync = true
8 |
9 | # Change to the directory of this file.
10 | Dir.chdir(File.expand_path("../", __FILE__))
11 |
12 | Bundler::GemHelper.install_tasks
13 |
14 | Rake::TestTask.new do |task|
15 | task.test_files = FileList['test/**/test*.rb']
16 | end
17 |
18 | desc "Run tests"
19 | task :default => :test
20 | task :tests => :test
21 |
22 |
--------------------------------------------------------------------------------
/lib/nugrant.rb:
--------------------------------------------------------------------------------
1 | require 'pathname'
2 | require 'nugrant/config'
3 | require 'nugrant/parameters'
4 |
5 | # 1.8 Compatibility check
6 | unless defined?(KeyError)
7 | class KeyError < IndexError
8 | end
9 | end
10 |
11 | module Nugrant
12 | def self.setup_i18n()
13 | I18n.load_path << File.expand_path("locales/en.yml", Nugrant.source_root)
14 | I18n.reload!
15 | end
16 |
17 | def self.source_root
18 | @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
19 | end
20 | end
21 |
22 | if defined?(Vagrant)
23 | Nugrant.setup_i18n()
24 |
25 | case
26 | when defined?(Vagrant::Plugin::V2)
27 | require 'nugrant/vagrant/v2/plugin'
28 | else
29 | raise RuntimeError, "Vagrant [#{Vagrant::VERSION}] is not supported by Nugrant."
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/lib/nugrant/bag.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/config'
2 |
3 | module Nugrant
4 | class Bag < Hash
5 |
6 | ##
7 | # Create a new Bag object which holds key/value pairs.
8 | # The Bag object inherits from the Hash object, the main
9 | # differences with a normal Hash are indifferent access
10 | # (symbol or string) and method access (via method call).
11 | #
12 | # Hash objects in the map are converted to Bag. This ensure
13 | # proper nesting of functionality.
14 | #
15 | # =| Arguments
16 | # * `elements`
17 | # The initial elements the bag should be built with it.'
18 | # Must be an object responding to `each` and accepting
19 | # a block with two arguments: `key, value`. Defaults to
20 | # the empty hash.
21 | #
22 | # * `config`
23 | # A Nugrant::Config object or hash passed to Nugrant::Config
24 | # constructor. Used for `key_error` handler.
25 | #
26 | def initialize(elements = {}, config = {})
27 | super()
28 |
29 | @__config = Config::convert(config)
30 |
31 | (elements || {}).each do |key, value|
32 | self[key] = value
33 | end
34 | end
35 |
36 | def config=(config)
37 | @__config = Config::convert(config)
38 | end
39 |
40 | def method_missing(method, *args, &block)
41 | self[method]
42 | end
43 |
44 | ##
45 | ### Enumerable Overridden Methods (for string & symbol indifferent access)
46 | ##
47 |
48 | def count(item)
49 | super(__try_convert_item(item))
50 | end
51 |
52 | def find_index(item = nil, &block)
53 | block_given? ? super(&block) : super(__try_convert_item(item))
54 | end
55 |
56 | ##
57 | ### Hash Overridden Methods (for string & symbol indifferent access)
58 | ##
59 |
60 | def [](input)
61 | key = __convert_key(input)
62 | return @__config.key_error.call(key) if not key?(key)
63 |
64 | super(key)
65 | end
66 |
67 | def []=(input, value)
68 | super(__convert_key(input), __convert_value(value))
69 | end
70 |
71 | def assoc(key)
72 | super(__convert_key(key))
73 | end
74 |
75 | def delete(key)
76 | super(__convert_key(key))
77 | end
78 |
79 | def fetch(key, default = nil)
80 | super(__convert_key(key), default)
81 | end
82 |
83 | def has_key?(key)
84 | super(__convert_key(key))
85 | end
86 |
87 | def include?(item)
88 | super(__try_convert_item(item))
89 | end
90 |
91 | def key?(key)
92 | super(__convert_key(key))
93 | end
94 |
95 | def member?(item)
96 | super(__try_convert_item(item))
97 | end
98 |
99 | def dup()
100 | self.class.new(self, @__config.dup())
101 | end
102 |
103 | def merge(other, options = {})
104 | result = dup()
105 | result.merge!(other)
106 | end
107 |
108 | def merge!(other, options = {})
109 | other.each do |key, value|
110 | current = __get(key)
111 | case
112 | when current == nil
113 | self[key] = value
114 |
115 | when current.kind_of?(Hash) && value.kind_of?(Hash)
116 | current.merge!(value, options)
117 |
118 | when current.kind_of?(Array) && value.kind_of?(Array)
119 | strategy = options[:array_merge_strategy]
120 | if not Nugrant::Config.supported_array_merge_strategy(strategy)
121 | strategy = @__config.array_merge_strategy
122 | end
123 |
124 | self[key] = send("__#{strategy}_array_merge", current, value)
125 |
126 | when value != nil
127 | self[key] = value
128 | end
129 | end
130 |
131 | self
132 | end
133 |
134 | def store(key, value)
135 | self[key] = value
136 | end
137 |
138 | def to_hash(options = {})
139 | return {} if empty?()
140 |
141 | use_string_key = options[:use_string_key]
142 |
143 | Hash[map do |key, value|
144 | key = use_string_key ? key.to_s() : key
145 | value = __convert_value_to_hash(value, options)
146 |
147 | [key, value]
148 | end]
149 | end
150 |
151 | def walk(path = [], &block)
152 | each do |key, value|
153 | nested_bag = value.kind_of?(Nugrant::Bag)
154 |
155 | value.walk(path + [key], &block) if nested_bag
156 | yield path + [key], key, value if not nested_bag
157 | end
158 | end
159 |
160 | alias_method :to_ary, :to_a
161 |
162 | ##
163 | ### Private Methods
164 | ##
165 |
166 | private
167 |
168 | def __convert_key(key)
169 | return key.to_s().to_sym() if !key.nil? && key.respond_to?(:to_s)
170 |
171 | raise ArgumentError, "Key cannot be nil" if key.nil?
172 | raise ArgumentError, "Key cannot be converted to symbol, current value [#{key}] (#{key.class.name})"
173 | end
174 |
175 | ##
176 | # This function change value convertible to Bag into actual Bag.
177 | # This trick enable deeply using all Bag functionalities and also
178 | # ensures at the same time a deeply preventive copy since a new
179 | # instance is created for this nested structure.
180 | #
181 | # In addition, it also transforms array elements of type Hash into
182 | # Bag instance also. This enable indifferent access inside arrays
183 | # also.
184 | #
185 | # @param value The value to convert to bag if necessary
186 | # @return The converted value
187 | #
188 | def __convert_value(value)
189 | case
190 | # Converts Hash to Bag instance
191 | when value.kind_of?(Hash)
192 | Bag.new(value, @__config)
193 |
194 | # Converts Array elements to Bag instances if needed
195 | when value.kind_of?(Array)
196 | value.map(&self.method(:__convert_value))
197 |
198 | # Keeps as-is other elements
199 | else
200 | value
201 | end
202 | end
203 |
204 | ##
205 | # This function does the reversion of value conversion to Bag
206 | # instances. It transforms Bag instances to Hash (using to_hash)
207 | # and array Bag elements to Hash (using to_hash).
208 | #
209 | # The options parameters are pass to the to_hash function
210 | # when invoked.
211 | #
212 | # @param value The value to convert to hash
213 | # @param options The options passed to the to_hash function
214 | # @return The converted value
215 | #
216 | def __convert_value_to_hash(value, options = {})
217 | case
218 | # Converts Bag instance to Hash
219 | when value.kind_of?(Bag)
220 | value.to_hash(options)
221 |
222 | # Converts Array elements to Hash instances if needed
223 | when value.kind_of?(Array)
224 | value.map { |value| __convert_value_to_hash(value, options) }
225 |
226 | # Keeps as-is other elements
227 | else
228 | value
229 | end
230 | end
231 |
232 | def __get(key)
233 | # Calls Hash method [__convert_key(key)], used internally to retrieve value without raising Undefined parameter
234 | self.class.superclass.instance_method(:[]).bind(self).call(__convert_key(key))
235 | end
236 |
237 | ##
238 | # The concat order is the reversed compared to others
239 | # because we assume that new values have precedence
240 | # over current ones. Hence, the are prepended to
241 | # current values. This is also logical for parameters
242 | # because of the order in which bags are merged.
243 | #
244 | def __concat_array_merge(current_array, new_array)
245 | new_array + current_array
246 | end
247 |
248 | def __extend_array_merge(current_array, new_array)
249 | current_array | new_array
250 | end
251 |
252 | def __replace_array_merge(current_array, new_array)
253 | new_array
254 | end
255 |
256 | def __try_convert_item(args)
257 | return [__convert_key(args[0]), args[1]] if args.kind_of?(Array)
258 |
259 | __convert_key(args)
260 | rescue
261 | args
262 | end
263 | end
264 | end
265 |
--------------------------------------------------------------------------------
/lib/nugrant/config.rb:
--------------------------------------------------------------------------------
1 | require 'rbconfig'
2 |
3 | module Nugrant
4 | class Config
5 | DEFAULT_ARRAY_MERGE_STRATEGY = :replace
6 | DEFAULT_PARAMS_FILENAME = ".nuparams"
7 | DEFAULT_PARAMS_FORMAT = :yaml
8 | DEFAULT_AUTO_EXPORT = false
9 |
10 | SUPPORTED_ARRAY_MERGE_STRATEGIES = [:concat, :extend, :replace]
11 | SUPPORTED_PARAMS_FORMATS = [:json, :yaml]
12 |
13 | attr_reader :params_filename, :params_format,
14 | :current_path, :user_path, :system_path,
15 | :array_merge_strategy, :auto_export, :auto_export_script_path,
16 | :key_error, :parse_error
17 |
18 | attr_writer :array_merge_strategy, :auto_export, :auto_export_script_path
19 |
20 | ##
21 | # Convenience method to easily accept either a hash that will
22 | # be converted to a Nugrant::Config object or directly a config
23 | # object.
24 | def self.convert(config = {})
25 | return config.kind_of?(Nugrant::Config) ? config : Nugrant::Config.new(config)
26 | end
27 |
28 | ##
29 | # Return the fully expanded path of the user parameters
30 | # default location that is used in the constructor.
31 | #
32 | def self.default_user_path()
33 | File.expand_path("~")
34 | end
35 |
36 | ##
37 | # Return the fully expanded path of the system parameters
38 | # default location that is used in the constructor.
39 | #
40 | def self.default_system_path()
41 | if Config.on_windows?
42 | return File.expand_path(ENV['PROGRAMDATA'] || ENV['ALLUSERSPROFILE'])
43 | end
44 |
45 | "/etc"
46 | end
47 |
48 | ##
49 | # Method to fix-up a received path. The fix-up do the follows
50 | # the following rules:
51 | #
52 | # 1. If the path is callable, call it to get the value.
53 | # 2. If value is nil, return default value.
54 | # 3. If value is a directory, return path + params_filename to it.
55 | # 4. Otherwise, return value
56 | #
57 | # @param path The path parameter received.
58 | # @param default The default path to use, can be a directory.
59 | # @param params_filename The params filename to append if path is a directory
60 | #
61 | # @return The fix-up path following rules defined above.
62 | #
63 | def self.fixup_path(path, default, params_filename)
64 | path = path.call if path.respond_to?(:call)
65 |
66 | path = File.expand_path(path || default)
67 | path = "#{path}/#{params_filename}" if ::File.directory?(path)
68 |
69 | path
70 | end
71 |
72 | def self.supported_array_merge_strategy(strategy)
73 | SUPPORTED_ARRAY_MERGE_STRATEGIES.include?(strategy)
74 | end
75 |
76 | def self.supported_params_format(format)
77 | SUPPORTED_PARAMS_FORMATS.include?(format)
78 | end
79 |
80 | ##
81 | # Return true if we are currently on a Windows platform.
82 | #
83 | def self.on_windows?()
84 | (RbConfig::CONFIG['host_os'].downcase =~ /mswin|mingw|cygwin/) != nil
85 | end
86 |
87 | ##
88 | # Creates a new config object that is used to configure an instance
89 | # of Nugrant::Parameters. See the list of options and how they interact
90 | # with Nugrant::Parameters.
91 | #
92 | # =| Options
93 | # * +:params_filename+ - The filename used to fetch parameters from. This
94 | # will be appended to various default locations.
95 | # Location are system, project and current that
96 | # can be tweaked individually by using the options
97 | # below.
98 | # Defaults => ".nuparams"
99 | # * +:params_format+ - The format in which parameters are to be parsed.
100 | # Presently supporting :yaml and :json.
101 | # Defaults => :yaml
102 | # * +:current_path+ - The current path has the highest precedence over
103 | # any other location. It can be be used for many purposes
104 | # depending on your usage.
105 | # * A path from where to read project parameters
106 | # * A path from where to read overriding parameters for a cli tool
107 | # * A path from where to read user specific settings not to be committed in a VCS
108 | # Defaults => "./#{@params_filename}"
109 | # * +:user_path+ - The user path is the location where the user
110 | # parameters should resides. The parameters loaded from this
111 | # location have the second highest precedence.
112 | # Defaults => "~/#{@params_filename}"
113 | # * +:system_path+ - The system path is the location where system wide
114 | # parameters should resides. The parameters loaded from this
115 | # location have the third highest precedence.
116 | # Defaults => Default system path depending on OS + @params_filename
117 | # * +:array_merge_strategy+ - This option controls how array values are merged together when merging
118 | # two Bag instances. Possible values are:
119 | # * :replace => Replace current values by new ones
120 | # * :extend => Merge current values with new ones
121 | # * :concat => Append new values to current ones
122 | # Defaults => The strategy :replace.
123 | # * +:key_error+ - A callback method receiving one argument, the key as a symbol, and that
124 | # deal with the error. If the callable does not
125 | # raise an exception, the result of it's execution is returned.
126 | # Defaults => A callable that throws a KeyError exception.
127 | # * +:parse_error+ - A callback method receiving two arguments, the offending filename and
128 | # the error object, that deal with the error. If the callable does not
129 | # raise an exception, the result of it's execution is returned.
130 | # Defaults => A callable that returns the empty hash.
131 | # * +:auto_export+ - Automatically export configuration to the specified format :autoenv or :script
132 | # * +:auto_export_script_path+ - The path where to write the export script, defaults to "./nugrant2env.sh"
133 | #
134 | def initialize(options = {})
135 | @params_filename = options[:params_filename] || DEFAULT_PARAMS_FILENAME
136 | @params_format = options[:params_format] || DEFAULT_PARAMS_FORMAT
137 | @auto_export = options[:auto_export] || DEFAULT_AUTO_EXPORT
138 | @auto_export_script_path = options[:auto_export_script_path] || false # use default
139 |
140 | @current_path = Config.fixup_path(options[:current_path], ".", @params_filename)
141 | @user_path = Config.fixup_path(options[:user_path], Config.default_user_path(), @params_filename)
142 | @system_path = Config.fixup_path(options[:system_path], Config.default_system_path(), @params_filename)
143 |
144 | @array_merge_strategy = options[:array_merge_strategy] || :replace
145 |
146 | @key_error = options[:key_error] || Proc.new do |key|
147 | raise KeyError, "Undefined parameter '#{key}'"
148 | end
149 |
150 | @parse_error = options[:parse_error] || Proc.new do |filename, error|
151 | {}
152 | end
153 |
154 | validate()
155 | end
156 |
157 | def ==(other)
158 | self.class.equal?(other.class) &&
159 | instance_variables.all? do |variable|
160 | instance_variable_get(variable) == other.instance_variable_get(variable)
161 | end
162 | end
163 |
164 | def [](key)
165 | instance_variable_get("@#{key}")
166 | rescue
167 | nil
168 | end
169 |
170 | def merge(other)
171 | result = dup()
172 | result.merge!(other)
173 | end
174 |
175 | def merge!(other)
176 | other.instance_variables.each do |variable|
177 | instance_variable_set(variable, other.instance_variable_get(variable)) if instance_variables.include?(variable)
178 | end
179 |
180 | self
181 | end
182 |
183 | def to_h()
184 | Hash[instance_variables.map do |variable|
185 | [variable[1..-1].to_sym, instance_variable_get(variable)]
186 | end]
187 | end
188 |
189 | alias_method :to_hash, :to_h
190 |
191 | def validate()
192 | raise ArgumentError,
193 | "Invalid value for :params_format. \
194 | The format [#{@params_format}] is currently not supported." if not Config.supported_params_format(@params_format)
195 |
196 | raise ArgumentError,
197 | "Invalid value for :array_merge_strategy. \
198 | The array merge strategy [#{@array_merge_strategy}] is currently not supported." if not Config.supported_array_merge_strategy(@array_merge_strategy)
199 | end
200 | end
201 | end
202 |
--------------------------------------------------------------------------------
/lib/nugrant/helper/bag.rb:
--------------------------------------------------------------------------------
1 | require 'multi_json'
2 | require 'yaml'
3 |
4 | require 'nugrant/bag'
5 |
6 | module Nugrant
7 | module Helper
8 | module Bag
9 | def self.read(filepath, filetype, config)
10 | Nugrant::Bag.new(parse_data(filepath, filetype, config), config)
11 | end
12 |
13 | def self.restricted_keys()
14 | Nugrant::Bag.instance_methods()
15 | end
16 |
17 | private
18 |
19 | def self.parse_data(filepath, filetype, config)
20 | return if not File.exist?(filepath)
21 |
22 | File.open(filepath, "rb") do |file|
23 | return send("parse_#{filetype}", file)
24 | end
25 | rescue => error
26 | config.parse_error.call(filepath, error)
27 | end
28 |
29 | def self.parse_json(io)
30 | MultiJson.load(io.read())
31 | end
32 |
33 | def self.parse_yaml(io)
34 | YAML.load(io.read())
35 | end
36 | end
37 | end
38 | end
39 |
--------------------------------------------------------------------------------
/lib/nugrant/helper/env/exporter.rb:
--------------------------------------------------------------------------------
1 | require 'shellwords'
2 |
3 | require 'nugrant/bag'
4 | require 'nugrant/helper/env/namer'
5 |
6 | module Nugrant
7 | module Helper
8 | module Env
9 | module Exporter
10 | DEFAULT_AUTOENV_PATH = "./.env"
11 | DEFAULT_SCRIPT_PATH = "./nugrant2env.sh"
12 |
13 | VALID_EXPORTERS = [:autoenv, :script, :terminal]
14 |
15 | ##
16 | # Returns true if the exporter name received is a valid
17 | # valid export, false otherwise.
18 | #
19 | # @param exporter The exporter name to check validity
20 | #
21 | # @return true if exporter is valid, false otherwise.
22 | def self.valid?(exporter)
23 | VALID_EXPORTERS.include?(exporter)
24 | end
25 |
26 | ##
27 | # Creates an autoenv script containing the commands that are required
28 | # to export or unset a bunch of environment variables taken from the
29 | # bag.
30 | #
31 | # @param bag The bag to create the script for.
32 | #
33 | # @return (side-effect) Creates a script file containing commands
34 | # to export or unset environment variables for
35 | # bag.
36 | #
37 | # Options:
38 | # * :autoenv_path => The path where to write the script, defaults to `./.env`.
39 | # * :escape_value => If true, escape the value to export (or unset), default to true.
40 | # * :io => The io where the command should be written, default to nil which create the autoenv on disk.
41 | # * :namer => The namer used to transform bag segments into variable name, default to Namer::default().
42 | # * :override => If true, variable a exported even when the override an existing env key, default to true.
43 | # * :type => The type of command, default to :export.
44 | #
45 | def self.autoenv_exporter(bag, options = {})
46 | io = options[:io] || (File.open(File.expand_path(options[:autoenv_path] || DEFAULT_AUTOENV_PATH), "wb"))
47 |
48 | terminal_exporter(bag, options.merge({:io => io}))
49 | ensure
50 | io.close() if io
51 | end
52 |
53 | ##
54 | # Creates a bash script containing the commands that are required
55 | # to export or unset a bunch of environment variables taken from the
56 | # bag.
57 | #
58 | # @param bag The bag to create the script for.
59 | #
60 | # @return (side-effect) Creates a script file containing commands
61 | # to export or unset environment variables for
62 | # bag.
63 | #
64 | # Options:
65 | # * :escape_value => If true, escape the value to export (or unset), default to true.
66 | # * :io => The io where the command should be written, default to nil which create the script on disk.
67 | # * :namer => The namer used to transform bag segments into variable name, default to Namer::default().
68 | # * :override => If true, variable a exported even when the override an existing env key, default to true.
69 | # * :script_path => The path where to write the script, defaults to `./nugrant2env.sh`.
70 | # * :type => The type of command, default to :export.
71 | #
72 | def self.script_exporter(bag, options = {})
73 | io = options[:io] || (File.open(File.expand_path(options[:script_path] || DEFAULT_SCRIPT_PATH), "wb"))
74 |
75 | io.puts("#!/bin/env sh")
76 | io.puts()
77 |
78 | terminal_exporter(bag, options.merge({:io => io}))
79 | ensure
80 | io.close() if io
81 | end
82 |
83 | ##
84 | # Export to terminal the commands that are required
85 | # to export or unset a bunch of environment variables taken from the
86 | # bag.
87 | #
88 | # @param bag The bag to create the script for.
89 | #
90 | # @return (side-effect) Outputs to io the commands generated.
91 | #
92 | # Options:
93 | # * :escape_value => If true, escape the value to export (or unset), default to true.
94 | # * :io => The io where the command should be displayed, default to $stdout.
95 | # * :namer => The namer used to transform bag segments into variable name, default to Namer::default().
96 | # * :override => If true, variable a exported even when the override an existing env key, default to true.
97 | # * :type => The type of command, default to :export.
98 | #
99 | def self.terminal_exporter(bag, options = {})
100 | io = options[:io] || $stdout
101 | type = options[:type] || :export
102 |
103 | export(bag, options) do |key, value|
104 | io.puts(command(type, key, value, options))
105 | end
106 | end
107 |
108 | ##
109 | # Generic function to export a bag. This walk the bag,
110 | # for each element, it creates the key using the namer
111 | # and then forward the key and value to the block if
112 | # the variable does not override an existing environment
113 | # variable or if options :override is set to true.
114 | #
115 | # @param bag The bag to export.
116 | #
117 | # @return (side-effect) Yields each key and value to a block
118 | #
119 | # Options:
120 | # * :namer => The namer used to transform bag parents into variable name, default to Namer::default().
121 | # * :override => If true, variable a exported even when the override an existing env key, default to true.
122 | #
123 | def self.export(bag, options = {})
124 | namer = options[:namer] || Env::Namer.default()
125 | override = options.fetch(:override, true)
126 |
127 | variables = {}
128 | bag.walk do |path, key, value|
129 | key = namer.call(path)
130 |
131 | variables[key] = value if override or not ENV[key]
132 | end
133 |
134 | variables.sort().each do |key, value|
135 | yield key, value
136 | end
137 | end
138 |
139 | ##
140 | # Given a key and a value, return a string representation
141 | # of the command type requested. Available types:
142 | #
143 | # * :export => A bash compatible export command
144 | # * :unset => A bash compatible export command
145 | #
146 | def self.command(type, key, value, options = {})
147 | # TODO: Replace by a map type => function name
148 | case
149 | when type == :export
150 | export_command(key, value, options)
151 | when type == :unset
152 | unset_command(key, value, options)
153 | end
154 | end
155 |
156 | ##
157 | # Returns a string representation of the command
158 | # that needs to be used on the current platform
159 | # to export an environment variable.
160 | #
161 | # @param key The key of the environment variable to export.
162 | # It cannot be nil.
163 | # @param value The value of the environment variable to export
164 | #
165 | # @return The export command, as a string
166 | #
167 | # Options:
168 | # * :escape_value (true) => If true, escape the value to export.
169 | #
170 | def self.export_command(key, value, options = {})
171 | value = value.to_s()
172 | value = Shellwords.escape(value) if options[:escape_value] == nil || options[:escape_value]
173 |
174 | # TODO: Handle platform differently
175 | "export #{key}=#{value}"
176 | end
177 |
178 | ##
179 | # Returns a string representation of the command
180 | # that needs to be used on the current platform
181 | # to unset an environment variable.
182 | #
183 | # @param key The key of the environment variable to export.
184 | # It cannot be nil.
185 | #
186 | # @return The unset command, as a string
187 | #
188 | def self.unset_command(key, value, options = {})
189 | # TODO: Handle platform differently
190 | "unset #{key}"
191 | end
192 | end
193 | end
194 | end
195 | end
196 |
--------------------------------------------------------------------------------
/lib/nugrant/helper/env/namer.rb:
--------------------------------------------------------------------------------
1 | module Nugrant
2 | module Helper
3 | module Env
4 | ##
5 | # A namer is a lambda taking as argument an array of segments
6 | # that should return a string representation of those segments.
7 | # How the segments are transformed to a string is up to the
8 | # namer. By using various namer, we can change how a bag key
9 | # is transformed into and environment variable name. This is
10 | # like the strategy pattern.
11 | #
12 | module Namer
13 |
14 | ##
15 | # Returns the default namer, which join segments together
16 | # using a character and upcase the result.
17 | #
18 | # @param `char` The character used to join segments together, default to `"_"`.
19 | #
20 | # @return A lambda that will simply joins segment using the `char` argument
21 | # and upcase the result.
22 | #
23 | def self.default(char = "_")
24 | lambda do |segments|
25 | segments.join(char).upcase()
26 | end
27 | end
28 |
29 | ##
30 | # Returns the prefix namer, which add a prefix to segments
31 | # and delegate its work to another namer.
32 | #
33 | # @param prefix The prefix to add to segments.
34 | # @param delegate_namer A namer that will be used to transform the prefixed segments.
35 | #
36 | # @return A lambda that will simply add prefix to segments and will call
37 | # the delegate_namer with those new segments.
38 | #
39 | def self.prefix(prefix, delegate_namer)
40 | lambda do |segments|
41 | delegate_namer.call([prefix] + segments)
42 | end
43 | end
44 | end
45 | end
46 | end
47 | end
48 |
--------------------------------------------------------------------------------
/lib/nugrant/helper/parameters.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/parameters'
2 |
3 | module Nugrant
4 | module Helper
5 | module Parameters
6 | def self.restricted_keys()
7 | methods = Nugrant::Parameters.instance_methods() + Nugrant::Bag.instance_methods()
8 | methods.uniq!
9 | end
10 | end
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/lib/nugrant/helper/stack.rb:
--------------------------------------------------------------------------------
1 | module Nugrant
2 | module Helper
3 | class Stack
4 | @@DEFAULT_MATCHER = /^(.+):([0-9]+)/
5 |
6 | def self.fetch_error_region(stack, options = {})
7 | entry = find_entry(stack, options)
8 | location = extract_error_location(entry, options)
9 |
10 | return (options[:unknown] || "Unknown") if not location[:file] and not location[:line]
11 | return location[:file] if not location[:line]
12 |
13 | fetch_error_region_from_location(location, options)
14 | end
15 |
16 | def self.fetch_error_region_from_location(location, options = {})
17 | prefix = options[:prefix] || " "
18 | width = options[:width] || 4
19 | file = File.new(location[:file], "r")
20 | line = location[:line]
21 |
22 | index = 0
23 |
24 | lines = []
25 | while (line_string = file.gets())
26 | index += 1
27 | next if (line - index).abs > width
28 |
29 | line_prefix = "#{prefix}#{index}:"
30 | line_prefix += (line == index ? ">> " : " ")
31 |
32 | lines << "#{line_prefix}#{line_string}"
33 | end
34 |
35 | lines.join().chomp()
36 | rescue
37 | return (options[:unknown] || "Unknown") if not location[:file] and not location[:line]
38 | return location[:file] if not location[:line]
39 |
40 | "#{location[:file]}:#{location[:line]}"
41 | ensure
42 | file.close() if file
43 | end
44 |
45 | ##
46 | # Search a stack list (as simple string array) for the first
47 | # entry that match the +:matcher+.
48 | #
49 | def self.find_entry(stack, options = {})
50 | matcher = options[:matcher] || @@DEFAULT_MATCHER
51 |
52 | stack.find do |entry|
53 | entry =~ matcher
54 | end
55 | end
56 |
57 | ##
58 | # Extract error location information from a stack entry using the
59 | # matcher received in arguments.
60 | #
61 | # The usual stack entry format is:
62 | # > /home/users/joe/work/lib/ruby.rb:4:Error message
63 | #
64 | # This function will extract the file and line information from
65 | # the stack entry using the matcher. The matcher is expected to
66 | # have two groups, the first for the file and the second for
67 | # line.
68 | #
69 | # The results is returned in form of a hash with two keys, +:file+
70 | # for the file information and +:line+ for the line information.
71 | #
72 | # If the matcher matched zero group, return +{:file => nil, :line => nil}+.
73 | # If the matcher matched one group, return +{:file => file, :line => nil}+.
74 | # If the matcher matched two groups, return +{:file => file, :line => line}+.
75 | #
76 | def self.extract_error_location(entry, options = {})
77 | matcher = options[:matcher] || @@DEFAULT_MATCHER
78 |
79 | result = matcher.match(entry)
80 | captures = result ? result.captures : []
81 |
82 | {:file => captures[0], :line => captures[1] ? captures[1].to_i() : nil}
83 | end
84 | end
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/lib/nugrant/helper/yaml.rb:
--------------------------------------------------------------------------------
1 | module Nugrant
2 | module Helper
3 | class Yaml
4 | def self.format(string, options = {})
5 | lines = string.send(string.respond_to?(:lines) ? :lines : :to_s).to_a
6 | lines = lines.drop(1)
7 |
8 | if options[:indent]
9 | indent_text = " " * options[:indent]
10 | lines = lines.map do |line|
11 | indent_text + line
12 | end
13 | end
14 |
15 | return lines.join("")
16 | end
17 | end
18 | end
19 | end
20 |
--------------------------------------------------------------------------------
/lib/nugrant/mixin/parameters.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/bag'
2 | require 'nugrant/config'
3 | require 'nugrant/helper/bag'
4 |
5 | module Nugrant
6 | module Mixin
7 | ##
8 | # Mixin module so it's possible to share parameters
9 | # logic between default Parameters class and Vagrant
10 | # implementation.
11 | #
12 | # This module delegates method missing to the final
13 | # bag hierarchy (@__all). This means that even if the class
14 | # including this module doesn't inherit Bag directly,
15 | # it act exactly like one.
16 | #
17 | # When including this module, you must respect an important
18 | # constraint.
19 | #
20 | # The including class must call `setup!` before starting using
21 | # parameters retrieval. This is usually performed in
22 | # the `initialize` method directly but could be in a different place
23 | # depending on the including class lifecycle. The call to `setup!` is
24 | # important to initialize all required instance variables.
25 | #
26 | # Here an example where `setup!` is called in constructor. Your constructor
27 | # does not need to have these arguments, they are there as an example.
28 | #
29 | # ```
30 | # def initialize(defaults = {}, config = {}, options = {})
31 | # setup!(defaults, config, options)
32 | # end
33 | # ```
34 | #
35 | module Parameters
36 | attr_reader :__config, :__current, :__user, :__system, :__defaults, :__all
37 |
38 | def method_missing(method, *args, &block)
39 | case
40 | when @__all.class.method_defined?(method)
41 | @__all.send(method, *args, &block)
42 | else
43 | @__all[method]
44 | end
45 | end
46 |
47 | def array_merge_strategy
48 | @__config.array_merge_strategy
49 | end
50 |
51 | def auto_export
52 | @__config.auto_export
53 | end
54 |
55 | def auto_export_script_path
56 | @__config.auto_export_script_path
57 | end
58 |
59 | ##
60 | # Change the current array merge strategy for this parameters.
61 | #
62 | # @param strategy The new strategy to use.
63 | def array_merge_strategy=(strategy)
64 | return if not Nugrant::Config.supported_array_merge_strategy(strategy)
65 |
66 | @__config.array_merge_strategy = strategy
67 |
68 | # When array_merge_strategy change, we need to recompute parameters hierarchy
69 | compute_all!()
70 | end
71 |
72 | def auto_export=(auto_export)
73 | @__config.auto_export = auto_export
74 | end
75 |
76 | def auto_export_script_path=(path)
77 | @__config.auto_export_script_path = path
78 | end
79 |
80 | def defaults()
81 | @__defaults
82 | end
83 |
84 | ##
85 | # Set the new default values for the
86 | # various parameters contain by this instance.
87 | # This will call `compute_all!` to recompute
88 | # correct precedences.
89 | #
90 | # =| Attributes
91 | # * +elements+ - The new default elements
92 | #
93 | def defaults=(elements)
94 | @__defaults = Bag.new(elements, @__config)
95 |
96 | # When defaults change, we need to recompute parameters hierarchy
97 | compute_all!()
98 | end
99 |
100 | def merge(other)
101 | result = dup()
102 | result.merge!(other)
103 | end
104 |
105 | def merge!(other)
106 | @__config.merge!(other.__config)
107 |
108 | # Updated Bags' config
109 | @__current.config = @__config
110 | @__user.config = @__config
111 | @__system.config = @__config
112 | @__defaults.config = @__config
113 |
114 | # Merge other into Bags
115 | @__current.merge!(other.__current, :array_merge_strategy => :replace)
116 | @__user.merge!(other.__user, :array_merge_strategy => :replace)
117 | @__system.merge!(other.__system, :array_merge_strategy => :replace)
118 | @__defaults.merge!(other.__defaults, :array_merge_strategy => :replace)
119 |
120 | # Recompute all from merged Bags
121 | compute_all!()
122 |
123 | self
124 | end
125 |
126 | ##
127 | # Setup instance variables of the mixin. It will compute all parameters bags
128 | # (current, user, system, default and all) and stored them to these respective
129 | # instance variables:
130 | #
131 | # * @__current
132 | # * @__user
133 | # * @__system
134 | # * @__defaults
135 | #
136 | # =| Arguments
137 | # * `defaults`
138 | # A hash that is used as the initial data for the defaults bag. Defaults
139 | # to an empty hash.
140 | #
141 | # * `config`
142 | # A Nugrant::Config object or hash passed to Nugrant::Config
143 | # convert method. Used to determine where to find the various
144 | # bag data sources and other configuration options.
145 | #
146 | # Passed to nested structures that requires a Nugrant::Config object
147 | # like the Bag object and Helper::Bag module.
148 | #
149 | # * `options`
150 | # Options hash used by this method exclusively. No options yet, added
151 | # for future improvements.
152 | #
153 | def setup!(defaults = {}, config = {}, options = {})
154 | @__config = Nugrant::Config::convert(config);
155 |
156 | @__defaults = Bag.new(defaults, @__config)
157 | @__current = Helper::Bag.read(@__config.current_path, @__config.params_format, @__config)
158 | @__user = Helper::Bag.read(@__config.user_path, @__config.params_format, @__config)
159 | @__system = Helper::Bag.read(@__config.system_path, @__config.params_format, @__config)
160 |
161 | compute_all!()
162 | end
163 |
164 | ##
165 | # Recompute the correct precedences by merging the various
166 | # bag in the right order and return the result as a Nugrant::Bag
167 | # object.
168 | #
169 | def compute_all!()
170 | @__all = Bag.new({}, @__config)
171 | @__all.merge!(@__defaults)
172 | @__all.merge!(@__system)
173 | @__all.merge!(@__user)
174 | @__all.merge!(@__current)
175 | end
176 | end
177 | end
178 | end
179 |
--------------------------------------------------------------------------------
/lib/nugrant/parameters.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/mixin/parameters'
2 |
3 | module Nugrant
4 | class Parameters
5 |
6 | include Mixin::Parameters
7 |
8 | ##
9 | # Create a new parameters object which holds completed
10 | # merged values. The following precedence is used to decide
11 | # which location has precedence over which location:
12 | #
13 | # (Highest) ------------------ (Lowest)
14 | # project < user < system < defaults
15 | #
16 | # =| Arguments
17 | # * `defaults`
18 | # Passed to Mixin::Parameters setup! method. See mixin
19 | # module for further information.
20 | #
21 | # * `config`
22 | # Passed to Mixin::Parameters setup! method. See mixin
23 | # module for further information.
24 | #
25 | def initialize(defaults = {}, config = {}, options = {})
26 | setup!(defaults, config, options)
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/errors.rb:
--------------------------------------------------------------------------------
1 | require 'vagrant/errors'
2 |
3 | require 'nugrant/helper/stack'
4 |
5 | module Nugrant
6 | module Vagrant
7 | module Errors
8 | class NugrantVagrantError < ::Vagrant::Errors::VagrantError
9 | error_namespace("nugrant.vagrant.errors")
10 |
11 | def compute_context()
12 | Helper::Stack.fetch_error_region(caller(), {
13 | :matcher => /(.+Vagrantfile):([0-9]+)/
14 | })
15 | end
16 | end
17 |
18 | class ParameterNotFoundError < NugrantVagrantError
19 | error_key(:parameter_not_found)
20 |
21 | def initialize(options = nil, *args)
22 | super({:context => compute_context()}.merge(options || {}), *args)
23 | end
24 | end
25 |
26 | class VagrantUserParseError < NugrantVagrantError
27 | error_key(:parse_error)
28 |
29 | def initialize(options = nil, *args)
30 | super(options, *args)
31 | end
32 | end
33 | end
34 | end
35 | end
36 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/action.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/vagrant/v2/action/auto_export'
2 |
3 | module Nugrant
4 | module Vagrant
5 | module V2
6 | module Action
7 | class << self
8 | def auto_export
9 | @auto_export ||= ::Vagrant::Action::Builder.new.tap do |builder|
10 | builder.use Nugrant::Vagrant::V2::Action::AutoExport
11 | end
12 | end
13 | end
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/action/auto_export.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant'
2 | require 'nugrant/helper/env/exporter'
3 | require 'nugrant/parameters'
4 |
5 | module Nugrant
6 | module Vagrant
7 | module V2
8 | module Action
9 | EnvExporter = Nugrant::Helper::Env::Exporter
10 |
11 | class AutoExport
12 | def initialize(app, env)
13 | @app = app
14 | @config = env[:machine].env.vagrantfile.config
15 | end
16 |
17 | def call(env)
18 | return @app.call(env) if not @config.user.auto_export
19 |
20 | options = {
21 | :type => :export,
22 | :script_path => @config.user.auto_export_script_path
23 | }
24 |
25 | Array(@config.user.auto_export).each do |exporter|
26 | if exporter == :terminal or not EnvExporter.valid?(exporter)
27 | env[:ui].warn("ERROR: Invalid config.user.auto_export value '#{exporter}'", :prefix => false)
28 | next
29 | end
30 |
31 | env[:ui].info("Configuration exported '#{exporter}'", :prefix => false)
32 |
33 | case
34 | when exporter == :script
35 | EnvExporter.script_exporter(@config.user.__all, options)
36 | when exporter == :autoenv
37 | EnvExporter.autoenv_exporter(@config.user.__all, options)
38 | end
39 | end
40 | end
41 | end
42 | end
43 | end
44 | end
45 | end
46 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/command/env.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant'
2 | require 'nugrant/helper/env/exporter'
3 | require 'nugrant/parameters'
4 |
5 | module Nugrant
6 | module Vagrant
7 | module V2
8 | module Command
9 | class Env < ::Vagrant.plugin("2", :command)
10 | EnvExporter = Nugrant::Helper::Env::Exporter
11 |
12 | def self.synopsis
13 | "env utilities to export config.user as environment variables in host machine"
14 | end
15 |
16 | def initialize(arguments, environment)
17 | super(arguments, environment)
18 |
19 | @unset = false
20 | @format = :terminal
21 | @script_path = false
22 | @show_help = false
23 | end
24 |
25 | def create_parser()
26 | return OptionParser.new do |parser|
27 | parser.banner = "Usage: vagrant user env []"
28 | parser.separator ""
29 |
30 | parser.separator "Outputs the commands that should be executed to export\n" +
31 | "the various parameter as environment variables. By default,\n" +
32 | "existing ones are overridden. The --format argument can be used\n" +
33 | "to choose in which format the variables should be displayed.\n" +
34 | "Changing the format will also change where they are displayed.\n"
35 | parser.separator ""
36 |
37 | parser.separator "Available options:"
38 | parser.separator ""
39 |
40 | parser.on("-u", "--unset", "Generates commands needed to unset environment variables, default false") do
41 | @unset = true
42 | end
43 |
44 | parser.on("-f", "--format FORMAT", "Determines in what format variables are output, default to terminal") do |format|
45 | @format = format.to_sym()
46 | end
47 |
48 | parser.on("-s", "--script-path PATH", "Specifies path of the generated bash script, default to #{EnvExporter::DEFAULT_SCRIPT_PATH}") do |path|
49 | @script_path = path
50 | end
51 |
52 | parser.on("-h", "--help", "Prints this help") do
53 | @show_help = true
54 | end
55 |
56 | parser.separator ""
57 | parser.separator "Available formats:"
58 | parser.separator " autoenv Write commands to a file named `.env` in the current directory."
59 | parser.separator " See https://github.com/kennethreitz/autoenv for more info."
60 | parser.separator " terminal Write commands to terminal so they can be sourced."
61 | parser.separator " script Write commands to a bash script named `nugrant2env.sh` so it can be sourced."
62 | parser.separator ""
63 | end
64 | end
65 |
66 | def error(message, parser)
67 | @env.ui.info("ERROR: #{message}", :prefix => false)
68 | @env.ui.info("", :prefix => false)
69 |
70 | help(parser)
71 |
72 | return 1
73 | end
74 |
75 | def help(parser)
76 | @env.ui.info(parser.help, :prefix => false)
77 | end
78 |
79 | def execute
80 | parser = create_parser()
81 | arguments = parse_options(parser)
82 |
83 | return error("Invalid format value '#{@format}'", parser) if not EnvExporter.valid?(@format)
84 | return help(parser) if @show_help
85 |
86 | @logger.debug("Nugrant 'Env'")
87 | with_target_vms(arguments) do |vm|
88 | parameters = vm.config.user
89 | if not parameters
90 | @env.ui.info("# Vm '#{vm.name}' : unable to retrieve `config.user`, report as bug https://github.com/maoueh/nugrant/issues", :prefix => false)
91 | next
92 | end
93 |
94 | bag = parameters.__all
95 |
96 | options = {
97 | :type => @unset ? :unset : :export,
98 | :script_path => @script_path
99 | }
100 |
101 | case
102 | when @format == :script
103 | EnvExporter.script_exporter(bag, options)
104 | when @format == :autoenv
105 | EnvExporter.autoenv_exporter(bag, options)
106 | when @format == :terminal
107 | EnvExporter.terminal_exporter(bag, options)
108 | end
109 |
110 | # No need to execute for the other VMs
111 | return 0
112 | end
113 | end
114 | end
115 | end
116 | end
117 | end
118 | end
119 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/command/parameters.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant'
2 | require 'nugrant/helper/yaml'
3 | require 'nugrant/vagrant/v2/helper'
4 |
5 | module Nugrant
6 | module Vagrant
7 | module V2
8 | module Command
9 | class Parameters < ::Vagrant.plugin("2", :command)
10 | def self.synopsis
11 | "prints parameters hierarchy as seen by Nugrant"
12 | end
13 |
14 | def initialize(arguments, environment)
15 | super(arguments, environment)
16 |
17 | @show_help = false
18 | @show_defaults = false
19 | @show_system = false
20 | @show_user = false
21 | @show_project = false
22 | end
23 |
24 | def create_parser()
25 | return OptionParser.new do |parser|
26 | parser.banner = "Usage: vagrant user parameters []"
27 | parser.separator ""
28 |
29 | parser.separator "Available options:"
30 | parser.separator ""
31 |
32 | parser.on("-h", "--help", "Prints this help") do
33 | @show_help = true
34 | end
35 |
36 | parser.on("-d", "--defaults", "Show only defaults parameters") do
37 | @show_defaults = true
38 | end
39 |
40 | parser.on("-s", "--system", "Show only system parameters") do
41 | @show_system = true
42 | end
43 |
44 | parser.on("-u", "--user", "Show only user parameters") do
45 | @show_user = true
46 | end
47 |
48 | parser.on("-p", "--project", "Show only project parameters") do
49 | @show_project = true
50 | end
51 |
52 | parser.separator ""
53 | parser.separator "When no options is provided, the command prints the names and values \n" +
54 | "of all parameters that would be available for usage in the Vagrantfile.\n" +
55 | "The hierarchy of the parameters is respected, so the final values are\n" +
56 | "displayed."
57 | end
58 | end
59 |
60 | def execute
61 | parser = create_parser()
62 | arguments = parse_options(parser)
63 |
64 | return help(parser) if @show_help
65 |
66 | @logger.debug("'Parameters' each target VM...")
67 | with_target_vms(arguments) do |vm|
68 | parameters = vm.config.user
69 | if not parameters
70 | @env.ui.info("# Vm '#{vm.name}' : unable to retrieve `config.user`, report as bug https://github.com/maoueh/nugrant/issues", :prefix => false)
71 | next
72 | end
73 |
74 | @env.ui.info("# Vm '#{vm.name}'", :prefix => false)
75 |
76 | defaults(parameters) if @show_defaults
77 | system(parameters) if @show_system
78 | user(parameters) if @show_user
79 | project(parameters) if @show_project
80 |
81 | all(parameters) if !@show_defaults && !@show_system && !@show_user && !@show_project
82 | end
83 |
84 | return 0
85 | end
86 |
87 | def help(parser)
88 | @env.ui.info(parser.help, :prefix => false)
89 | end
90 |
91 | def defaults(parameters)
92 | print_bag("Defaults", parameters.__defaults)
93 | end
94 |
95 | def system(parameters)
96 | print_bag("System", parameters.__system)
97 | end
98 |
99 | def user(parameters)
100 | print_bag("User", parameters.__user)
101 | end
102 |
103 | def project(parameters)
104 | print_bag("Project", parameters.__current)
105 | end
106 |
107 | def all(parameters)
108 | print_bag("All", parameters.__all)
109 | end
110 |
111 | def print_bag(kind, bag)
112 | if !bag || bag.empty?()
113 | print_header(kind)
114 | @env.ui.info(" Empty", :prefix => false)
115 | @env.ui.info("", :prefix => false)
116 | return
117 | end
118 |
119 | print_parameters(kind, {
120 | 'config' => {
121 | 'user' => bag.to_hash(:use_string_key => true)
122 | }
123 | })
124 | end
125 |
126 | def print_parameters(kind, hash)
127 | string = Nugrant::Helper::Yaml.format(hash.to_yaml, :indent => 1)
128 | used_restricted_keys = Helper::get_used_restricted_keys(hash, Helper::get_restricted_keys())
129 |
130 | print_warning(used_restricted_keys) if !used_restricted_keys.empty?()
131 |
132 | print_header(kind)
133 | @env.ui.info(string, :prefix => false)
134 | @env.ui.info("", :prefix => false)
135 | end
136 |
137 | def print_header(kind, length = 50)
138 | @env.ui.info(" #{kind.capitalize} Parameters", :prefix => false)
139 | @env.ui.info(" " + "-" * length, :prefix => false)
140 | end
141 |
142 | def print_warning(used_restricted_keys)
143 | @env.ui.info("", :prefix => false)
144 | @env.ui.info(" You are using some restricted keys. Method access (using .) will", :prefix => false)
145 | @env.ui.info(" not work, only array access ([]) will. Offending keys:", :prefix => false)
146 | @env.ui.info(" #{used_restricted_keys.join(", ")}", :prefix => false)
147 | @env.ui.info("", :prefix => false)
148 | end
149 | end
150 | end
151 | end
152 | end
153 | end
154 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/command/restricted_keys.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant'
2 | require 'nugrant/vagrant/v2/helper'
3 |
4 | module Nugrant
5 | module Vagrant
6 | module V2
7 | module Command
8 | class RestrictedKeys < ::Vagrant.plugin("2", :command)
9 | def self.synopsis
10 | "prints list of restricted keys for method access"
11 | end
12 |
13 | def initialize(arguments, environment)
14 | super(arguments, environment)
15 |
16 | @show_help = false
17 | end
18 |
19 | def create_parser()
20 | return OptionParser.new do |parser|
21 | parser.banner = "Usage: vagrant user restricted-keys"
22 | parser.separator ""
23 |
24 | parser.separator "Available options:"
25 | parser.separator ""
26 |
27 | parser.on("-h", "--help", "Prints this help") do
28 | @show_help = true
29 | end
30 |
31 | parser.separator ""
32 | parser.separator "Prints keys that cannot be accessed using the method access syntax\n" +
33 | "(`config.user.`). Use array access syntax (`config.user['']`)\n" +
34 | "if you really want to use of the restricted keys.\n"
35 | end
36 | end
37 |
38 | def execute
39 | parser = create_parser()
40 | arguments = parse_options(parser)
41 |
42 | return help(parser) if @show_help
43 |
44 | @env.ui.info("The following keys are restricted, i.e. that method access (`config.user.`)", :prefix => false)
45 | @env.ui.info("will not work. If you really want to use a restricted key, use array access ", :prefix => false)
46 | @env.ui.info("instead (`config.user['']`).", :prefix => false)
47 | @env.ui.info("", :prefix => false)
48 |
49 | @env.ui.info("You can run `vagrant user parameters` to check if your config currently defines", :prefix => false)
50 | @env.ui.info("one or more restricted keys shown below.", :prefix => false)
51 | @env.ui.info("", :prefix => false)
52 |
53 | restricted_keys = Helper::get_restricted_keys()
54 | @env.ui.info(restricted_keys.sort().join(", "), :prefix => false)
55 | end
56 |
57 | def help(parser)
58 | @env.ui.info(parser.help, :prefix => false)
59 | end
60 | end
61 | end
62 | end
63 | end
64 | end
65 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/command/root.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant'
2 | require 'nugrant/vagrant/v2/command/env'
3 | require 'nugrant/vagrant/v2/command/parameters'
4 | require 'nugrant/vagrant/v2/command/restricted_keys'
5 | require 'nugrant/version'
6 |
7 | module Nugrant
8 | module Vagrant
9 | module V2
10 | module Command
11 | class Root < ::Vagrant.plugin("2", :command)
12 | def self.synopsis
13 | "manage Nugrant user defined parameters (config.user)"
14 | end
15 |
16 | def initialize(arguments, environment)
17 | super(arguments, environment)
18 |
19 | @arguments, @subcommand, @subarguments = split_main_and_subcommand(arguments)
20 |
21 | # Change super class available arguments to main ones only
22 | @argv = @arguments
23 |
24 | @subcommands = ::Vagrant::Registry.new()
25 | @subcommands.register(:env) do
26 | Command::Env
27 | end
28 |
29 | @subcommands.register(:parameters) do
30 | Command::Parameters
31 | end
32 |
33 | @subcommands.register(:'restricted-keys') do
34 | Command::RestrictedKeys
35 | end
36 |
37 | @show_help = false
38 | @show_version = false
39 | end
40 |
41 | def create_parser()
42 | return OptionParser.new do |parser|
43 | parser.banner = "Usage: vagrant user [-h] [-v] []"
44 |
45 | parser.separator ""
46 | parser.on("-h", "--help", "Prints this help") do
47 | @show_help = true
48 | end
49 |
50 | parser.on("-v", "--version", "Prints plugin version and exit.") do
51 | @show_version = true
52 | end
53 |
54 | parser.separator ""
55 | parser.separator "Available subcommands:"
56 |
57 | keys = []
58 | @subcommands.each { |key, value| keys << key.to_s }
59 |
60 | keys.sort.each do |key|
61 | parser.separator " #{key}"
62 | end
63 |
64 | parser.separator ""
65 | parser.separator "For help on any individual command run `vagrant user -h`"
66 | end
67 | end
68 |
69 | def execute
70 | parser = create_parser()
71 | arguments = parse_options(parser)
72 |
73 | return version() if @show_version
74 | return help(parser) if @show_help
75 |
76 | command_class = @subcommands.get(@subcommand.to_sym) if @subcommand
77 | return help(parser) if !command_class || !@subcommand
78 |
79 | @logger.debug("Invoking nugrant command class: #{command_class} #{@subarguments.inspect}")
80 |
81 | command_class.new(@subarguments, @env).execute
82 | end
83 |
84 | def help(parser)
85 | @env.ui.info(parser.help, :prefix => false)
86 | end
87 |
88 | def version()
89 | @env.ui.info("Nugrant version #{Nugrant::VERSION}", :prefix => false)
90 | end
91 | end
92 | end
93 | end
94 | end
95 | end
96 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/config/user.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/mixin/parameters'
2 | require 'nugrant/vagrant/errors'
3 | require 'nugrant/vagrant/v2/helper'
4 |
5 | module Nugrant
6 | module Vagrant
7 | module V2
8 | module Config
9 | class User < ::Vagrant.plugin("2", :config)
10 |
11 | include Mixin::Parameters
12 |
13 | def initialize(defaults = {}, config = {})
14 | setup!(defaults,
15 | :params_filename => ".vagrantuser",
16 | :current_path => Helper.find_project_path(),
17 | :key_error => Proc.new do |key|
18 | raise Errors::ParameterNotFoundError, :key => key.to_s
19 | end,
20 | :parse_error => Proc.new do |filename, error|
21 | raise Errors::VagrantUserParseError, :filename => filename.to_s, :error => error
22 | end
23 | )
24 | end
25 | end
26 | end
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/helper.rb:
--------------------------------------------------------------------------------
1 | require 'pathname'
2 |
3 | require 'nugrant'
4 | require 'nugrant/bag'
5 | require 'nugrant/vagrant/v2/config/user'
6 |
7 | module Nugrant
8 | module Vagrant
9 | module V2
10 | class Helper
11 |
12 | ##
13 | # The project path is the path where the top-most (loaded last)
14 | # Vagrantfile resides. It can be considered the project root for
15 | # this environment.
16 | #
17 | # Copied from `lib\vagrant\environment.rb#532` (tag: v1.6.2)
18 | #
19 | # @return [String] The project path to use.
20 | #
21 | def self.find_project_path()
22 | vagrantfile_name = ENV["VAGRANT_VAGRANTFILE"]
23 | vagrantfile_name = [vagrantfile_name] if vagrantfile_name && !vagrantfile_name.is_a?(Array)
24 |
25 | root_finder = lambda do |path|
26 | vagrantfile = find_vagrantfile(path, vagrantfile_name)
27 |
28 | return path if vagrantfile
29 | return nil if path.root? || !File.exist?(path)
30 |
31 | root_finder.call(path.parent)
32 | end
33 |
34 | root_finder.call(get_vagrant_working_directory())
35 | end
36 |
37 | ##
38 | # Finds the Vagrantfile in the given directory.
39 | #
40 | # Copied from `lib\vagrant\environment.rb#732` (tag: v1.6.2)
41 | #
42 | # @param [Pathname] path Path to search in.
43 | # @return [Pathname]
44 | #
45 | def self.find_vagrantfile(search_path, filenames = nil)
46 | filenames ||= ["Vagrantfile", "vagrantfile"]
47 | filenames.each do |vagrantfile|
48 | current_path = search_path.join(vagrantfile)
49 | return current_path if current_path.file?
50 | end
51 |
52 | nil
53 | end
54 |
55 | ##
56 | # Returns Vagrant working directory to use.
57 | #
58 | # Copied from `lib\vagrant\environment.rb#80` (tag: v1.6.2)
59 | #
60 | # @return [Pathname] The working directory to start search in.
61 | #
62 | def self.get_vagrant_working_directory()
63 | cwd = nil
64 |
65 | # Set the default working directory to look for the vagrantfile
66 | cwd ||= ENV["VAGRANT_CWD"] if ENV.has_key?("VAGRANT_CWD")
67 | cwd ||= Dir.pwd
68 | cwd = Pathname.new(cwd)
69 |
70 | if !cwd.directory?
71 | raise Errors::EnvironmentNonExistentCWD, cwd: cwd.to_s
72 | end
73 |
74 | cwd = cwd.expand_path
75 | end
76 |
77 | def self.get_restricted_keys()
78 | bag_methods = Nugrant::Bag.instance_methods
79 | parameters_methods = V2::Config::User.instance_methods
80 |
81 | (bag_methods | parameters_methods).map(&:to_s)
82 | end
83 |
84 | def self.get_used_restricted_keys(hash, restricted_keys)
85 | keys = []
86 | hash.each do |key, value|
87 | keys << key if restricted_keys.include?(key)
88 | keys += get_used_restricted_keys(value, restricted_keys) if value.kind_of?(Hash)
89 | end
90 |
91 | keys.uniq
92 | end
93 | end
94 | end
95 | end
96 | end
97 |
--------------------------------------------------------------------------------
/lib/nugrant/vagrant/v2/plugin.rb:
--------------------------------------------------------------------------------
1 | require 'nugrant/vagrant/v2/action'
2 |
3 | module Nugrant
4 | module Vagrant
5 | module V2
6 | class Plugin < ::Vagrant.plugin("2")
7 | name "Nugrant"
8 | description <<-DESC
9 | Plugin to define and use user specific parameters from various location inside your Vagrantfile.
10 | DESC
11 |
12 | class << self
13 | def provision(hook)
14 | hook.before(::Vagrant::Action::Builtin::Provision, Nugrant::Vagrant::V2::Action.auto_export)
15 | end
16 | end
17 |
18 | action_hook(:nugrant_provision, :machine_action_up, &method(:provision))
19 | action_hook(:nugrant_provision, :machine_action_reload, &method(:provision))
20 | action_hook(:nugrant_provision, :machine_action_provision, &method(:provision))
21 |
22 | command "user" do
23 | require_relative "command/root"
24 | Command::Root
25 | end
26 |
27 | config "user" do
28 | require_relative "config/user"
29 | Config::User
30 | end
31 | end
32 | end
33 | end
34 | end
35 |
--------------------------------------------------------------------------------
/lib/nugrant/version.rb:
--------------------------------------------------------------------------------
1 | module Nugrant
2 | VERSION = "2.1.5.dev1"
3 | end
4 |
--------------------------------------------------------------------------------
/locales/en.yml:
--------------------------------------------------------------------------------
1 | en:
2 | nugrant:
3 | vagrant:
4 | errors:
5 | parameter_not_found: |-
6 | Nugrant: Parameter '%{key}' was not found, is it defined in
7 | your .vagrantuser file? Here where we think the error
8 | could be in your Vagrantfile:
9 |
10 | %{context}
11 |
12 | If you think the parameter '%{key}' should have been found, don't
13 | hesitate to fill an issue @ https://github.com/maoueh/nugrant/issues.
14 |
15 | parse_error: |-
16 | Nugrant: Vagrant user file could not be parsed correctly,
17 | the file is probably in an invalid state.
18 |
19 | File: %{filename}
20 | Error: %{error}
21 |
22 | If you think this is an error, don't hesitate to fill an
23 | issue @ https://github.com/maoueh/nugrant/issues.
24 |
25 |
--------------------------------------------------------------------------------
/locales/fr.yml:
--------------------------------------------------------------------------------
1 | en:
2 | nugrant:
3 | vagrant:
4 | errors:
5 | parameter_not_found: |-
6 | Nugrant: Le paramètre '%{key}' n'a pu être trouvé, est-il définie
7 | dans votre fichier .vagrantuser ? Voici où nous pensons que l'erreur
8 | se trouve dans votre fichier Vagrantfile:
9 |
10 | %{context}
11 |
12 | Si vous croyez que le paramètre '%{key}' devrait être trouvé, n'hésitez
13 | pas à rapporter le problème @ https://github.com/maoueh/nugrant/issues.
14 |
15 | parse_error: |-
16 | Nugrant: Le fichier de paramètres Vagrant n'a pu être lu correctement,
17 | le fichier contient probablement une erreur de syntaxe.
18 |
19 | File: %{filename}
20 | Error: %{error}
21 |
22 | Si vous croyez que ceci est un bug, n'hésitez pas à rapporter le
23 | problème @ https://github.com/maoueh/nugrant/issues.
24 |
25 |
--------------------------------------------------------------------------------
/nugrant.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | lib = File.expand_path('../lib', __FILE__)
3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4 |
5 | require 'nugrant/version'
6 |
7 | Gem::Specification.new do |gem|
8 | gem.name = "nugrant"
9 | gem.version = Nugrant::VERSION
10 | gem.authors = ["Matthieu Vachon"]
11 | gem.email = ["matthieu.o.vachon@gmail.com"]
12 | gem.homepage = "https://github.com/maoueh/nugrant"
13 | gem.summary = "Library to handle user specific parameters from various location."
14 | gem.description = <<-EOF
15 | Nugrant is a library to easily handle parameters that need to be
16 | injected into an application via different sources (system, user,
17 | project, defaults).
18 |
19 | Nugrant can also be directly used as a Vagrant plugin. By activating
20 | this gem with Vagrant, it will be possible to define user specific
21 | parameters that will be injected directly into the Vagrantfile. This
22 | is useful if you need to share a Vagrantfile to multiple developers
23 | but would like to customize some parameters for each user differently.
24 | EOF
25 |
26 | gem.files = `git ls-files`.split($/)
27 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
28 | gem.test_files = gem.files.grep(%r{^(test/lib)/})
29 | gem.require_paths = ["lib"]
30 |
31 | gem.add_dependency "multi_json", "~> 1.8"
32 | end
33 |
--------------------------------------------------------------------------------
/test/lib/nugrant/helper/env/test_exporter.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | require 'nugrant/bag'
4 | require 'nugrant/helper/env/exporter'
5 |
6 | module Nugrant
7 | module Helper
8 | module Env
9 | class TestExporter < ::Minitest::Test
10 | def create_bag(parameters)
11 | return Nugrant::Bag.new(parameters)
12 | end
13 |
14 | def assert_export(expected, key, value, options = {})
15 | actual = Env::Exporter.command(:export, key, value, options)
16 |
17 | assert_equal(expected, actual)
18 | end
19 |
20 | def assert_unset(expected, key, options = {})
21 | actual = Env::Exporter.command(:unset, key, options)
22 |
23 | assert_equal(expected, actual)
24 | end
25 |
26 | def assert_autoenv_exporter(expected, bag, options = {})
27 | io = StringIO.new()
28 | Env::Exporter.autoenv_exporter(bag, options.merge({:io => io}))
29 |
30 | actual = io.string().split(/\r?\n/)
31 |
32 | assert_equal(expected, actual)
33 | end
34 |
35 | def assert_script_exporter(expected, bag, options = {})
36 | io = StringIO.new()
37 | Env::Exporter.script_exporter(bag, options.merge({:io => io}))
38 |
39 | actual = io.string().split(/\r?\n/)
40 |
41 | assert_equal(expected, actual)
42 | end
43 |
44 | def assert_terminal_exporter(expected, bag, options = {})
45 | io = StringIO.new()
46 | Env::Exporter.terminal_exporter(bag, options.merge({:io => io}))
47 |
48 | actual = io.string().split(/\r?\n/)
49 |
50 | assert_equal(expected, actual)
51 | end
52 |
53 | def assert_unset_commands(expected, bag, options = {})
54 | actual = Env::Exporter.unset_commands(bag, options)
55 |
56 | assert_equal(expected, actual)
57 | end
58 |
59 | def test_valid_exporter
60 | assert_equal(true, Env::Exporter.valid?(:autoenv))
61 | assert_equal(true, Env::Exporter.valid?(:script))
62 | assert_equal(true, Env::Exporter.valid?(:terminal))
63 | assert_equal(false, Env::Exporter.valid?(:foreman))
64 | end
65 |
66 | def test_export_command
67 | assert_export("export TEST=\\\"running\\ with\\ space\\\"", "TEST", "\"running with space\"")
68 | assert_export("export TEST=running with space", "TEST", "running with space", :escape_value => false)
69 | end
70 |
71 | def test_unset_command
72 | assert_unset("unset TEST", "TEST")
73 | end
74 |
75 | def test_terminal_exporter_export
76 | bag = create_bag({
77 | :level1 => {
78 | :level2 => {
79 | :first => "first with space",
80 | :second => "\"second\\"
81 | },
82 | :third => "third"
83 | },
84 | :existing => "downcase",
85 | })
86 |
87 | stub_env(:existing => "exist", :EXISTING => "exist") do
88 | assert_terminal_exporter([
89 | "export EXISTING=downcase",
90 | "export LEVEL1_LEVEL2_FIRST=first\\ with\\ space",
91 | "export LEVEL1_LEVEL2_SECOND=\\\"second\\\\",
92 | "export LEVEL1_THIRD=third",
93 | ], bag)
94 |
95 | assert_terminal_exporter([
96 | "export LEVEL1_LEVEL2_FIRST=first\\ with\\ space",
97 | "export LEVEL1_LEVEL2_SECOND=\\\"second\\\\",
98 | "export LEVEL1_THIRD=third",
99 | ], bag, :override => false)
100 |
101 | assert_terminal_exporter([
102 | "export EXISTING=downcase",
103 | "export LEVEL1_LEVEL2_FIRST=first with space",
104 | "export LEVEL1_LEVEL2_SECOND=\"second\\",
105 | "export LEVEL1_THIRD=third",
106 | ], bag, :type => :export, :override => true, :escape_value => false)
107 |
108 | default_namer = Env::Namer.default(".")
109 | prefix_namer = Env::Namer.prefix("CONFIG", default_namer)
110 |
111 | assert_terminal_exporter([
112 | "export CONFIG.EXISTING=downcase",
113 | "export CONFIG.LEVEL1.LEVEL2.FIRST=first with space",
114 | "export CONFIG.LEVEL1.LEVEL2.SECOND=\"second\\",
115 | "export CONFIG.LEVEL1.THIRD=third",
116 | ], bag, :override => true, :escape_value => false, :namer => prefix_namer)
117 | end
118 | end
119 |
120 | def test_terminal_exporter_unset
121 | bag = create_bag({
122 | :level1 => {
123 | :level2 => {
124 | :first => "first",
125 | :second => "second"
126 | },
127 | :third => "third"
128 | },
129 | :existing => "downcase",
130 | })
131 |
132 | stub_env(:existing => "exist", :EXISTING => "exist") do
133 | assert_terminal_exporter([
134 | "unset EXISTING",
135 | "unset LEVEL1_LEVEL2_FIRST",
136 | "unset LEVEL1_LEVEL2_SECOND",
137 | "unset LEVEL1_THIRD",
138 | ], bag, :type => :unset)
139 |
140 | assert_terminal_exporter([
141 | "unset LEVEL1_LEVEL2_FIRST",
142 | "unset LEVEL1_LEVEL2_SECOND",
143 | "unset LEVEL1_THIRD",
144 | ], bag, :override => false, :type => :unset)
145 |
146 | default_namer = Env::Namer.default(".")
147 | prefix_namer = Env::Namer.prefix("CONFIG", default_namer)
148 |
149 | assert_terminal_exporter([
150 | "unset CONFIG.EXISTING",
151 | "unset CONFIG.LEVEL1.LEVEL2.FIRST",
152 | "unset CONFIG.LEVEL1.LEVEL2.SECOND",
153 | "unset CONFIG.LEVEL1.THIRD",
154 | ], bag, :override => true, :namer => prefix_namer, :type => :unset)
155 | end
156 | end
157 |
158 | def test_autoenv_exporter
159 | bag = create_bag({
160 | :level1 => {
161 | :level2 => {
162 | :first => "first",
163 | :second => "second"
164 | },
165 | :third => "third"
166 | },
167 | :existing => "downcase",
168 | })
169 |
170 | assert_autoenv_exporter([
171 | "export EXISTING=downcase",
172 | "export LEVEL1_LEVEL2_FIRST=first",
173 | "export LEVEL1_LEVEL2_SECOND=second",
174 | "export LEVEL1_THIRD=third",
175 | ], bag, :type => :export)
176 |
177 | assert_autoenv_exporter([
178 | "unset EXISTING",
179 | "unset LEVEL1_LEVEL2_FIRST",
180 | "unset LEVEL1_LEVEL2_SECOND",
181 | "unset LEVEL1_THIRD",
182 | ], bag, :type => :unset)
183 | end
184 |
185 | def test_script_exporter
186 | bag = create_bag({
187 | :level1 => {
188 | :level2 => {
189 | :first => "first",
190 | :second => "second"
191 | },
192 | :third => "third"
193 | },
194 | :existing => "downcase",
195 | })
196 |
197 | assert_script_exporter([
198 | "#!/bin/env sh",
199 | "",
200 | "export EXISTING=downcase",
201 | "export LEVEL1_LEVEL2_FIRST=first",
202 | "export LEVEL1_LEVEL2_SECOND=second",
203 | "export LEVEL1_THIRD=third",
204 | ], bag, :type => :export)
205 |
206 | assert_script_exporter([
207 | "#!/bin/env sh",
208 | "",
209 | "unset EXISTING",
210 | "unset LEVEL1_LEVEL2_FIRST",
211 | "unset LEVEL1_LEVEL2_SECOND",
212 | "unset LEVEL1_THIRD",
213 | ], bag, :type => :unset)
214 | end
215 |
216 | def replace_env(variables)
217 | ENV.clear()
218 |
219 | variables = Hash[variables.map do |name, value|
220 | [name.to_s, value]
221 | end]
222 |
223 | ENV.update(variables)
224 | end
225 |
226 | def stub_env(new = {})
227 | old = ENV.to_hash()
228 |
229 | replace_env(new)
230 | yield
231 |
232 | ensure
233 | replace_env(old)
234 | end
235 | end
236 | end
237 | end
238 | end
239 |
--------------------------------------------------------------------------------
/test/lib/nugrant/helper/test_bag.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | require 'nugrant/helper/bag'
4 |
5 | module Nugrant
6 | module Helper
7 | class TestBag < ::Minitest::Test
8 | def test_restricted_keys_contains_hash_ones
9 | keys = Helper::Bag.restricted_keys()
10 | Hash.instance_methods.each do |method|
11 | assert_includes(keys, method, "Restricted keys must include Hash method #{method}")
12 | end
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/test/lib/nugrant/helper/test_parameters.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | require 'nugrant/bag'
4 | require 'nugrant/helper/parameters'
5 |
6 | module Nugrant
7 | module Helper
8 | class TestParameters < ::Minitest::Test
9 | def test_restricted_keys_contains_hash_ones
10 | keys = Helper::Parameters.restricted_keys()
11 | Nugrant::Bag.instance_methods.each do |method|
12 | assert_includes(keys, method, "Restricted keys must include Nugrant::Bag method #{method}")
13 | end
14 | end
15 | end
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/test/lib/nugrant/helper/test_stack.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | require 'nugrant/helper/stack'
4 |
5 | module Nugrant
6 | module Helper
7 | class TestStack < ::Minitest::Test
8 | def create_stack(options = {})
9 | pattern = options[:pattern] || "Vagrantfile:%s"
10 | count = options[:count] || 4
11 |
12 | stack = []
13 | (0..count).each do |index|
14 | stack << pattern.gsub("%s", index.to_s())
15 | end
16 |
17 | stack
18 | end
19 |
20 | def create_location(name, line)
21 | resource_path = File.expand_path("#{File.dirname(__FILE__)}/../../../resources/vagrantfiles")
22 |
23 | {:file => "#{resource_path}/#{name}", :line => line}
24 | end
25 |
26 | def assert_error_location(expected, entry, matcher = nil)
27 | assert_equal(expected, Stack::extract_error_location(entry, :matcher => matcher), "Not exact error location")
28 | end
29 |
30 | def assert_error_region(expected, region)
31 | expected_lines = expected.split("\n")
32 | region_lines = region.split("\n")
33 |
34 | expected_count = expected_lines.length()
35 | actual_count = region_lines.length()
36 |
37 | assert_equal(expected_count, actual_count, "Region different line count")
38 |
39 | expected_lines.each_with_index do |expected_line, index|
40 | assert_equal(expected_line.strip(), region_lines[index].strip(), "Line ##{index} are not equals")
41 | end
42 | end
43 |
44 | def test_fetch_error_region_from_location()
45 | location = create_location("v2.defaults_using_symbol", 4)
46 | error_region = Stack::fetch_error_region_from_location(location)
47 | expected_region = <<-EOT
48 | 1: Vagrant.configure("2") do |config|
49 | 2: config.user.defaults = {
50 | 3: :single => 1,
51 | 4:>> :local => {
52 | 5: :first => "value1",
53 | 6: :second => "value2"
54 | 7: }
55 | 8: }
56 | EOT
57 |
58 | assert_error_region(expected_region, error_region)
59 | end
60 |
61 | def test_fetch_error_region_from_location_custom_prefix()
62 | location = create_location("v2.defaults_using_symbol", 4)
63 | error_region = Stack::fetch_error_region_from_location(location, :prefix => "**")
64 | expected_region = <<-EOT
65 | **1: Vagrant.configure(\"2\") do |config|
66 | **2: config.user.defaults = {
67 | **3: :single => 1,
68 | **4:>> :local => {
69 | **5: :first => "value1",
70 | **6: :second => "value2"
71 | **7: }
72 | **8: }
73 | EOT
74 |
75 | assert_error_region(expected_region, error_region)
76 | end
77 |
78 | def test_fetch_error_region_from_location_custom_width()
79 | location = create_location("v2.defaults_using_symbol", 4)
80 | error_region = Stack::fetch_error_region_from_location(location, :width => 2)
81 | expected_region = <<-EOT
82 | 2: config.user.defaults = {
83 | 3: :single => 1,
84 | 4:>> :local => {
85 | 5: :first => "value1",
86 | 6: :second => "value2"
87 | EOT
88 |
89 | assert_error_region(expected_region, error_region)
90 | end
91 |
92 | def test_fetch_error_region_from_location_wrong_location()
93 | location = {:file => nil, :line => nil}
94 | assert_equal("Unknown", Stack::fetch_error_region_from_location(location))
95 | assert_equal("Failed", Stack::fetch_error_region_from_location(location, :unknown => "Failed"))
96 |
97 | location = {:file => "Vagrantfile", :line => nil}
98 | assert_equal("Vagrantfile", Stack::fetch_error_region_from_location(location))
99 |
100 | location = {:file => "NonExistingVagrantfile", :line => 4}
101 | assert_equal("NonExistingVagrantfile:4", Stack::fetch_error_region_from_location(location))
102 | end
103 |
104 | def test_find_entry()
105 | entries = ["First", "Second:", "Third:a", "Fourth:4"]
106 |
107 | assert_equal("Fourth:4", Stack::find_entry(entries))
108 | assert_equal("Third:a", Stack::find_entry(entries, :matcher => /^(.+):([a-z]+)/))
109 | end
110 |
111 | def test_extract_error_location_default_matcher()
112 | # Matches
113 | assert_error_location({:file => "/work/irb/workspace.rb", :line => 80}, "/work/irb/workspace.rb:80:in `eval'")
114 | assert_error_location({:file => "workspace.rb", :line => 80}, "workspace.rb:80:in `eval'")
115 | assert_error_location({:file => "/work/irb/workspace.rb", :line => 80}, "/work/irb/workspace.rb:80")
116 |
117 | # No match
118 | assert_error_location({:file => nil, :line => nil}, "/work/irb/workspace.rb?80")
119 | assert_error_location({:file => nil, :line => nil}, "/work/irb/workspace.rb")
120 | assert_error_location({:file =>nil, :line => nil}, "")
121 | end
122 |
123 | def test_extract_error_location_custom_matcher()
124 | # Matches
125 | assert_error_location(
126 | {:file => "/work/Vagrantfile", :line => 80},
127 | "/work/Vagrantfile:80:in `eval'",
128 | /(.*Vagrantfile):([0-9]+)/
129 | )
130 |
131 | assert_error_location(
132 | {:file => "Vagrantfile", :line => 80},
133 | "Vagrantfile:80:in `eval'",
134 | /(.*Vagrantfile):([0-9]+)/
135 | )
136 |
137 | assert_error_location(
138 | {:file => "/work/irb/Vagrantfile", :line => 80},
139 | "/work/irb/Vagrantfile:80",
140 | /(.*Vagrantfile):([0-9]+)/
141 | )
142 |
143 | # Partial match
144 | assert_error_location(
145 | {:file => "/work/Vagrantfile", :line => nil},
146 | "/work/Vagrantfile:80:in `eval'",
147 | /(.*Vagrantfile)/
148 | )
149 | end
150 | end
151 | end
152 | end
153 |
--------------------------------------------------------------------------------
/test/lib/nugrant/test_bag.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | require 'nugrant/bag'
4 | require 'nugrant/helper/bag'
5 |
6 | module Nugrant
7 | class TestBag < ::Minitest::Test
8 | def run_test_bag(parameters)
9 | bag = create_bag(parameters)
10 |
11 | assert_bag_equal(parameters, bag)
12 | end
13 |
14 | def test_bag()
15 | run_test_bag({:first => "value1", :second => "value2"})
16 |
17 | run_test_bag({
18 | :first => {
19 | :level1 => "value1",
20 | :level2 => "value2",
21 | },
22 | :second => {
23 | :level1 => "value3",
24 | :level2 => "value4",
25 | },
26 | :third => "value5"
27 | })
28 |
29 | run_test_bag({
30 | :first => {
31 | :level1 => {
32 | :level11 => "value1",
33 | :level12 => "value2",
34 | },
35 | :level2 => {
36 | :level21 => "value3",
37 | :level22 => "value4",
38 | },
39 | :level3 => "value5",
40 | },
41 | :second => {
42 | :level1 => {
43 | :level11 => "value6",
44 | :level12 => "value7",
45 | },
46 | :level2 => {
47 | :level21 => "value8",
48 | :level22 => "value9",
49 | },
50 | :level3 => "value10",
51 | },
52 | :third => "value11"
53 | })
54 | end
55 |
56 | def test_undefined_value()
57 | bag = create_bag({:value => "one"})
58 |
59 | assert_raises(KeyError) do
60 | bag.invalid_value
61 | end
62 |
63 | assert_raises(KeyError) do
64 | bag["invalid_value"]
65 | end
66 |
67 | assert_raises(KeyError) do
68 | bag[:invalid_value]
69 | end
70 | end
71 |
72 | def test_to_hash()
73 | hash = create_bag({}).to_hash()
74 |
75 | assert_is_hash_exclusive(hash)
76 | assert_equal({}, hash)
77 |
78 | hash = create_bag({"value" => {:one => "value", "two" => "value"}}).to_hash()
79 |
80 | assert_is_hash_exclusive(hash)
81 | assert_is_hash_exclusive(hash[:value])
82 | assert_kind_of(String, hash[:value][:one])
83 | assert_kind_of(String, hash[:value][:two])
84 | assert_equal({:value => {:one => "value", :two => "value"}}, hash)
85 | end
86 |
87 | def test_to_hash_array_with_bag()
88 | hash = create_bag({:a => [{:b => "1", :c => [{"d" => "2"}]}]}).to_hash()
89 |
90 | assert_is_hash_exclusive(hash)
91 | assert_kind_of(Array, hash[:a])
92 | assert_is_hash_exclusive(hash[:a][0])
93 | assert_kind_of(String, hash[:a][0][:b])
94 | assert_kind_of(Array, hash[:a][0][:c])
95 | assert_is_hash_exclusive(hash[:a][0][:c][0])
96 | assert_kind_of(String, hash[:a][0][:c][0][:d])
97 |
98 | assert_equal({:a => [{:b => "1", :c => [{:d => "2"}]}]}, hash)
99 | end
100 |
101 | def test_to_hash_array_with_bag_string_key()
102 | hash = create_bag({:a => [{:b => "1", :c => [{"d" => "2"}]}]}).to_hash(use_string_key: true)
103 |
104 | assert_is_hash_exclusive(hash)
105 | assert_kind_of(Array, hash["a"])
106 | assert_is_hash_exclusive(hash["a"][0])
107 | assert_kind_of(String, hash["a"][0]["b"])
108 | assert_kind_of(Array, hash["a"][0]["c"])
109 | assert_is_hash_exclusive(hash["a"][0]["c"][0])
110 | assert_kind_of(String, hash["a"][0]["c"][0]["d"])
111 |
112 | assert_equal({"a" => [{"b" => "1", "c" => [{"d" => "2"}]}]}, hash)
113 | end
114 |
115 | def test_merge_array_replace()
116 | # Replace should be the default case
117 | bag1 = create_bag({"first" => [1, 2]})
118 | bag2 = create_bag({:first => [2, 3]})
119 |
120 | bag1.merge!(bag2);
121 |
122 | assert_equal({:first => [2, 3]}, bag1.to_hash())
123 |
124 | bag1 = create_bag({"first" => [1, 2]})
125 | bag2 = create_bag({:first => "string"})
126 |
127 | bag1.merge!(bag2);
128 |
129 | assert_equal({:first => "string"}, bag1.to_hash())
130 | end
131 |
132 | def test_merge_array_extend()
133 | bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :extend)
134 | bag2 = create_bag({:first => [2, 3]})
135 |
136 | bag1.merge!(bag2);
137 |
138 | assert_equal({:first => [1, 2, 3]}, bag1.to_hash())
139 |
140 | bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :extend)
141 | bag2 = create_bag({:first => "string"})
142 |
143 | bag1.merge!(bag2);
144 |
145 | assert_equal({:first => "string"}, bag1.to_hash())
146 | end
147 |
148 | def test_merge_array_concat()
149 | bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :concat)
150 | bag2 = create_bag({:first => [2, 3]})
151 |
152 | bag1.merge!(bag2);
153 |
154 | assert_equal({:first => [2, 3, 1, 2]}, bag1.to_hash())
155 |
156 | bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :concat)
157 | bag2 = create_bag({:first => "string"})
158 |
159 | bag1.merge!(bag2);
160 |
161 | assert_equal({:first => "string"}, bag1.to_hash())
162 | end
163 |
164 | def test_merge_hash_keeps_indifferent_access
165 | bag1 = create_bag({"first" => {:second => [1, 2]}})
166 | bag1.merge!({:third => "three", "first" => {:second => [3, 4]}})
167 |
168 | assert_equal({:first => {:second => [3, 4]}, :third => "three"}, bag1.to_hash())
169 |
170 | assert_indifferent_access_equal({:second => [3, 4]}, bag1, :first)
171 | assert_indifferent_access_equal([3, 4], bag1["first"], :second)
172 | end
173 |
174 | def test_set_a_slot_with_a_hash_keeps_indifferent_access
175 | bag1 = create_bag({})
176 | bag1["first"] = {:second => [1, 2]}
177 |
178 | assert_indifferent_access_equal({:second => [1, 2]}, bag1, :first)
179 | assert_indifferent_access_equal([1, 2], bag1["first"], :second)
180 | end
181 |
182 | def test_nil_key()
183 | assert_raises(ArgumentError) do
184 | create_bag({nil => "value"})
185 | end
186 |
187 | parameters = create_bag({})
188 |
189 | assert_raises(ArgumentError) do
190 | parameters[nil] = 1
191 | end
192 |
193 | assert_raises(ArgumentError) do
194 | parameters[nil]
195 | end
196 |
197 | assert_raises(ArgumentError) do
198 | parameters.method_missing(nil)
199 | end
200 | end
201 |
202 | def test_restricted_keys_are_still_accessible
203 | keys = Helper::Bag.restricted_keys()
204 | bag = create_bag(Hash[
205 | keys.map do |key|
206 | [key, "#{key.to_s} - value"]
207 | end
208 | ])
209 |
210 | keys.each do |key|
211 | assert_equal("#{key.to_s} - value", bag[key.to_s], "bag[#{key.to_s}]")
212 | assert_equal("#{key.to_s} - value", bag[key.to_sym], "bag[#{key.to_sym}]")
213 | end
214 | end
215 |
216 | def test_numeric_keys_converted_to_string
217 | bag1 = create_bag({1 => "value1"})
218 |
219 | assert_indifferent_access_equal("value1", bag1, :'1')
220 | end
221 |
222 | def test_custom_key_error_handler
223 | bag = create_bag({:value => "one"}, :key_error => Proc.new do |key|
224 | raise IndexError
225 | end)
226 |
227 | assert_raises(IndexError) do
228 | bag.invalid_value
229 | end
230 |
231 | assert_raises(IndexError) do
232 | bag["invalid_value"]
233 | end
234 |
235 | assert_raises(IndexError) do
236 | bag[:invalid_value]
237 | end
238 | end
239 |
240 | def test_custom_key_error_handler_returns_value
241 | bag = create_bag({:value => "one"}, :key_error => Proc.new do |key|
242 | "Some value"
243 | end)
244 |
245 | assert_indifferent_access_equal("Some value", bag, :invalid_value)
246 | end
247 |
248 | def test_walk_bag
249 | bag = create_bag({
250 | :first => {
251 | :level1 => "value1",
252 | :level2 => "value2",
253 | },
254 | :second => {
255 | :level1 => "value3",
256 | :level2 => "value4",
257 | },
258 | :third => "value5"
259 | })
260 |
261 | lines = []
262 | bag.walk do |path, key, value|
263 | lines << "Path (#{path}), Key (#{key}), Value (#{value})"
264 | end
265 |
266 | assert_equal([
267 | "Path ([:first, :level1]), Key (level1), Value (value1)",
268 | "Path ([:first, :level2]), Key (level2), Value (value2)",
269 | "Path ([:second, :level1]), Key (level1), Value (value3)",
270 | "Path ([:second, :level2]), Key (level2), Value (value4)",
271 | "Path ([:third]), Key (third), Value (value5)",
272 | ], lines)
273 | end
274 |
275 | def test_merge
276 | bag1 = create_bag({
277 | :first => {
278 | :level1 => "value1",
279 | :level2 => "value2",
280 | },
281 | :second => {
282 | :level1 => "value3",
283 | :level2 => "value4",
284 | },
285 | :third => "value5"
286 | })
287 |
288 | bag2 = create_bag({
289 | :first => {
290 | :level2 => "overriden2",
291 | },
292 | :second => {
293 | :level1 => "value3",
294 | :level2 => "value4",
295 | },
296 | :third => "overriden5"
297 | })
298 |
299 | bag3 = bag1.merge(bag2)
300 |
301 | refute_same(bag1, bag3)
302 | refute_same(bag2, bag3)
303 |
304 | assert_equal(Nugrant::Bag, bag3.class)
305 |
306 | assert_indifferent_access_equal("value1", bag3['first'], :level1)
307 | assert_indifferent_access_equal("overriden2", bag3['first'], :level2)
308 | assert_indifferent_access_equal("value3", bag3['second'], :level1)
309 | assert_indifferent_access_equal("value4", bag3['second'], :level2)
310 | assert_indifferent_access_equal("overriden5", bag3, :third)
311 | end
312 |
313 | def test_merge!
314 | bag1 = create_bag({
315 | :first => {
316 | :level1 => "value1",
317 | :level2 => "value2",
318 | },
319 | :second => {
320 | :level1 => "value3",
321 | :level2 => "value4",
322 | },
323 | :third => "value5"
324 | })
325 |
326 | bag2 = create_bag({
327 | :first => {
328 | :level2 => "overriden2",
329 | },
330 | :second => {
331 | :level1 => "value3",
332 | :level2 => "value4",
333 | },
334 | :third => "overriden5"
335 | })
336 |
337 | bag3 = bag1.merge!(bag2)
338 |
339 | assert_same(bag1, bag3)
340 | refute_same(bag2, bag3)
341 |
342 | assert_equal(Nugrant::Bag, bag3.class)
343 |
344 | assert_indifferent_access_equal("value1", bag3['first'], :level1)
345 | assert_indifferent_access_equal("overriden2", bag3['first'], :level2)
346 | assert_indifferent_access_equal("value3", bag3['second'], :level1)
347 | assert_indifferent_access_equal("value4", bag3['second'], :level2)
348 | assert_indifferent_access_equal("overriden5", bag3, :third)
349 | end
350 |
351 | def test_merge_hash()
352 | bag1 = create_bag({"first" => {:second => [1, 2]}}, :array_merge_strategy => :extend)
353 |
354 | bag1.merge!({"first" => {:second => [2, 3]}});
355 |
356 | assert_equal({:first => {:second => [1, 2, 3]}}, bag1.to_hash())
357 | end
358 |
359 | def test_merge_custom_array_merge_strategy()
360 | bag1 = create_bag({"first" => {:second => [1, 2]}}, :array_merge_strategy => :extend)
361 |
362 | bag1.merge!({"first" => {:second => [2, 3]}}, :array_merge_strategy => :replace);
363 |
364 | assert_equal({:first => {:second => [2, 3]}}, bag1.to_hash())
365 | end
366 |
367 | def test_merge_custom_invalid_array_merge_strategy()
368 | bag1 = create_bag({"first" => {:second => [1, 2]}}, :array_merge_strategy => :extend)
369 | bag2 = bag1.merge({"first" => {:second => [2, 3]}}, :array_merge_strategy => nil);
370 |
371 | assert_equal({:first => {:second => [1, 2, 3]}}, bag2.to_hash())
372 |
373 | bag2 = bag1.merge({"first" => {:second => [2, 3]}}, :array_merge_strategy => :invalid);
374 |
375 | assert_equal({:first => {:second => [1, 2, 3]}}, bag2.to_hash())
376 | end
377 |
378 | def test_change_config
379 | bag1 = create_bag({"first" => [1, 2]}, :array_merge_strategy => :extend)
380 | bag2 = create_bag({:first => [2, 3]})
381 |
382 | bag3 = bag1.merge!(bag2);
383 | bag3.config = {
384 | :array_merge_strategy => :concat
385 | }
386 |
387 | bag3.merge!({"first" => [1, 2, 3]})
388 |
389 | assert_equal([1, 2, 3, 1, 2, 3], bag3['first'])
390 | end
391 |
392 | def test_indifferent_access_in_array
393 | bag = create_bag({:a => [{:b => 1, :c => [{"d" => 1}]}]})
394 |
395 | assert_indifferent_access_equal(1, bag['a'][0]['c'][0], :d)
396 | end
397 |
398 | ## Helpers & Assertions
399 |
400 | def create_bag(elements, options = {})
401 | return Bag.new(elements, options)
402 | end
403 |
404 | def assert_is_hash_exclusive(input)
405 | assert_equal(true, input.kind_of?(Hash), "#{input} should be a kind of Hash")
406 | assert_equal(false, input.kind_of?(Bag), "#{input} should not be a kind of Bag")
407 | end
408 |
409 | def assert_indifferent_access_equal(expected, bag, key)
410 | assert_symbol_access_equal(expected, bag, key)
411 | assert_string_access_equal(expected, bag, key)
412 | end
413 |
414 | def assert_string_access_equal(expected, bag, key)
415 | assert_equal(expected, bag[key.to_s], "bag[#{key.to_s}]")
416 | end
417 |
418 | def assert_symbol_access_equal(expected, bag, key)
419 | assert_equal(expected, bag.method_missing(key.to_sym), "bag.#{key.to_sym}")
420 | assert_equal(expected, bag[key.to_sym], "bag[#{key.to_sym}]")
421 | end
422 |
423 | def assert_indifferent_access_bag_equal(expected, bag, key)
424 | assert_string_access_bag_equal(expected, bag, key)
425 | assert_symbol_access_bag_equal(expected, bag, key)
426 | end
427 |
428 | def assert_string_access_bag_equal(expected, bag, key)
429 | assert_bag_equal(expected, bag[key.to_s])
430 | end
431 |
432 | def assert_symbol_access_bag_equal(expected, bag, key)
433 | assert_bag_equal(expected, bag.method_missing(key.to_sym))
434 | assert_bag_equal(expected, bag[key.to_sym])
435 | end
436 |
437 | def assert_bag_equal(expected, bag)
438 | assert_kind_of(Bag, bag)
439 |
440 | expected.each do |key, expected_value|
441 | if not expected_value.kind_of?(Hash)
442 | assert_indifferent_access_equal(expected_value, bag, key)
443 | next
444 | end
445 |
446 | assert_indifferent_access_bag_equal(expected_value, bag, key)
447 | end
448 | end
449 | end
450 | end
451 |
--------------------------------------------------------------------------------
/test/lib/nugrant/test_config.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 | require 'tmpdir'
3 |
4 | require 'nugrant/config'
5 |
6 | module Nugrant
7 | class TestConfig < ::Minitest::Test
8 | def setup
9 | @default_param_filename = Nugrant::Config::DEFAULT_PARAMS_FILENAME
10 |
11 | @old_working_dir = Dir.getwd()
12 | @user_dir = Nugrant::Config.default_user_path()
13 | @system_dir = Nugrant::Config.default_system_path()
14 |
15 | Dir.chdir(Dir.tmpdir())
16 |
17 | @current_dir = Dir.getwd()
18 | end
19 |
20 | def teardown
21 | Dir.chdir(@old_working_dir)
22 |
23 | @old_working_dir = nil
24 | @current_dir = nil
25 | @user_dir = nil
26 | @system_dir = nil
27 | end
28 |
29 | def test_default_values
30 | config = Nugrant::Config.new()
31 |
32 | assert_equal(@default_param_filename, config.params_filename())
33 | assert_equal("#{@current_dir}/#{@default_param_filename}", config.current_path())
34 | assert_equal("#{@user_dir}/#{@default_param_filename}", config.user_path())
35 | assert_equal("#{@system_dir}/#{@default_param_filename}", config.system_path())
36 | end
37 |
38 | def test_custom_params_filename
39 | config = Nugrant::Config.new({:params_filename => ".customparams"})
40 |
41 | assert_equal(".customparams", config.params_filename())
42 | assert_equal("#{@current_dir}/.customparams", config.current_path())
43 | assert_equal("#{@user_dir}/.customparams", config.user_path())
44 | assert_equal("#{@system_dir}/.customparams", config.system_path())
45 | end
46 |
47 | def test_custom_current_path
48 | config = Nugrant::Config.new({
49 | :params_filename => ".customparams",
50 | :current_path => "#{@user_dir}/.currentcustomparams"
51 | })
52 |
53 | assert_equal(".customparams", config.params_filename())
54 | assert_equal("#{@user_dir}/.currentcustomparams", config.current_path())
55 | end
56 |
57 | def test_custom_current_path_without_filename
58 | config = Nugrant::Config.new({
59 | :params_filename => ".customparams",
60 | :current_path => "#{@user_dir}"
61 | })
62 |
63 | assert_equal(".customparams", config.params_filename())
64 | assert_equal("#{@user_dir}/.customparams", config.current_path())
65 | end
66 |
67 | def test_custom_current_path_using_callable
68 | config = Nugrant::Config.new({
69 | :params_filename => ".customparams",
70 | :current_path => lambda do ||
71 | "#{@user_dir}/"
72 | end
73 | })
74 |
75 | assert_equal(".customparams", config.params_filename())
76 | assert_equal("#{@user_dir}/.customparams", config.current_path())
77 | end
78 |
79 | def test_custom_user_path
80 | config = Nugrant::Config.new({
81 | :params_filename => ".customparams",
82 | :user_path => "#{@system_dir}/.usercustomparams"
83 | })
84 |
85 | assert_equal(".customparams", config.params_filename())
86 | assert_equal("#{@system_dir}/.usercustomparams", config.user_path()) end
87 |
88 | def test_custom_system_path
89 | config = Nugrant::Config.new({
90 | :params_filename => ".customparams",
91 | :system_path => "#{@current_dir}/.systemcustomparams"
92 | })
93 |
94 | assert_equal(".customparams", config.params_filename())
95 | assert_equal("#{@current_dir}/.systemcustomparams", config.system_path())
96 | end
97 |
98 | def test_custom_all
99 | config = Nugrant::Config.new({
100 | :params_filename => ".customparams",
101 | :current_path => "#{@user_dir}/.currentcustomparams",
102 | :user_path => "#{@system_dir}/.usercustomparams",
103 | :system_path => "#{@current_dir}/.systemcustomparams"
104 | })
105 |
106 | assert_equal(".customparams", config.params_filename())
107 | assert_equal("#{@user_dir}/.currentcustomparams", config.current_path())
108 | assert_equal("#{@system_dir}/.usercustomparams", config.user_path())
109 | assert_equal("#{@current_dir}/.systemcustomparams", config.system_path())
110 | end
111 |
112 | def test_nil_current
113 | config = Nugrant::Config.new({
114 | :params_filename => ".customparams",
115 | :current_path => nil,
116 | })
117 |
118 | assert_equal("#{@current_dir}/.customparams", config.current_path())
119 | end
120 |
121 | def test_nil_user
122 | config = Nugrant::Config.new({
123 | :params_filename => ".customparams",
124 | :user_path => nil,
125 | })
126 |
127 | assert_equal("#{@user_dir}/.customparams", config.user_path())
128 | end
129 |
130 | def test_nil_system
131 | config = Nugrant::Config.new({
132 | :params_filename => ".customparams",
133 | :system_path => nil,
134 | })
135 |
136 | assert_equal("#{@system_dir}/.customparams", config.system_path())
137 | end
138 |
139 | def test_invalid_format
140 | assert_raises(ArgumentError) do
141 | Nugrant::Config.new({:params_format => :invalid})
142 | end
143 | end
144 |
145 | def test_merge
146 | config1 = Nugrant::Config.new({
147 | :params_filename => ".customparams",
148 | :current_path => nil,
149 | })
150 |
151 | config2 = Nugrant::Config.new({
152 | :params_filename => ".overrideparams",
153 | :current_path => "something",
154 | })
155 |
156 | config3 = config1.merge(config2)
157 |
158 | refute_same(config1, config3)
159 | refute_same(config2, config3)
160 |
161 | assert_equal(Nugrant::Config.new({
162 | :params_filename => config2[:params_filename],
163 | :params_format => config2[:params_format],
164 | :current_path => config2[:current_path],
165 | :user_path => config2[:user_path],
166 | :system_path => config2[:system_path],
167 | :array_merge_strategy => config2[:array_merge_strategy],
168 | :key_error => config2[:key_error],
169 | :parse_error => config2[:parse_error],
170 | }), config3)
171 | end
172 |
173 | def test_merge!
174 | config1 = Nugrant::Config.new({
175 | :params_filename => ".customparams",
176 | :current_path => nil,
177 | })
178 |
179 | config2 = Nugrant::Config.new({
180 | :params_filename => ".overrideparams",
181 | :current_path => "something",
182 | })
183 |
184 | config3 = config1.merge!(config2)
185 |
186 | assert_same(config1, config3)
187 | refute_same(config2, config3)
188 |
189 | assert_equal(Nugrant::Config.new({
190 | :params_filename => config2[:params_filename],
191 | :params_format => config2[:params_format],
192 | :current_path => config2[:current_path],
193 | :user_path => config2[:user_path],
194 | :system_path => config2[:system_path],
195 | :array_merge_strategy => config2[:array_merge_strategy],
196 | :key_error => config2[:key_error],
197 | :parse_error => config2[:parse_error],
198 | }), config3)
199 | end
200 | end
201 | end
202 |
--------------------------------------------------------------------------------
/test/lib/nugrant/test_parameters.rb:
--------------------------------------------------------------------------------
1 | require 'minitest/autorun'
2 |
3 | require 'nugrant'
4 | require 'nugrant/helper/parameters'
5 | require 'nugrant/parameters'
6 |
7 | module Nugrant
8 | class TestParameters < ::Minitest::Test
9 |
10 | @@FORMATS = [:json, :yaml]
11 | @@INVALID_PATH = "impossible_file_path.yamljson.impossible"
12 |
13 | def test_params_level_1()
14 | formats.each do |format|
15 | parameters = create_parameters(format, "params_current_1", "params_user_1", "params_system_1")
16 |
17 | assert_level(parameters, {
18 | :'1.1.1' => "current",
19 | :'1.1.0' => "current",
20 | :'1.0.1' => "current",
21 | :'0.1.1' => "user",
22 | :'1.0.0' => "current",
23 | :'0.1.0' => "user",
24 | :'0.0.1' => "system",
25 | })
26 | end
27 | end
28 |
29 | def test_params_level_2()
30 | formats.each do |format|
31 | parameters = create_parameters(format, "params_current_2", "params_user_2", "params_system_2")
32 |
33 | run_second_level(parameters, :'1.1.1', {
34 | :'1.1.1' => "current",
35 | :'1.1.0' => "current",
36 | :'1.0.1' => "current",
37 | :'0.1.1' => "user",
38 | :'1.0.0' => "current",
39 | :'0.1.0' => "user",
40 | :'0.0.1' => "system",
41 | })
42 |
43 | run_second_level(parameters, :'1.1.0', {
44 | :'1.1.1' => "current",
45 | :'1.1.0' => "current",
46 | :'1.0.1' => "current",
47 | :'0.1.1' => "user",
48 | :'1.0.0' => "current",
49 | :'0.1.0' => "user",
50 | })
51 |
52 | run_second_level(parameters, :'1.0.1', {
53 | :'1.1.1' => "current",
54 | :'1.1.0' => "current",
55 | :'1.0.1' => "current",
56 | :'0.1.1' => "system",
57 | :'1.0.0' => "current",
58 | :'0.0.1' => "system",
59 | })
60 |
61 | run_second_level(parameters, :'0.1.1', {
62 | :'1.1.1' => "user",
63 | :'1.1.0' => "user",
64 | :'1.0.1' => "system",
65 | :'0.1.1' => "user",
66 | :'0.1.0' => "user",
67 | :'0.0.1' => "system",
68 | })
69 |
70 | run_second_level(parameters, :'1.0.0', {
71 | :'1.1.1' => "current",
72 | :'1.1.0' => "current",
73 | :'1.0.1' => "current",
74 | :'1.0.0' => "current",
75 | })
76 |
77 | run_second_level(parameters, :'0.1.0', {
78 | :'1.1.1' => "user",
79 | :'1.1.0' => "user",
80 | :'0.1.1' => "user",
81 | :'0.1.0' => "user",
82 | })
83 |
84 | run_second_level(parameters, :'0.0.1', {
85 | :'1.1.1' => "system",
86 | :'1.0.1' => "system",
87 | :'0.1.1' => "system",
88 | :'0.0.1' => "system",
89 | })
90 |
91 | assert_key_error(parameters, :'0.0.0')
92 | end
93 | end
94 |
95 | def run_second_level(parameters, key, results)
96 | assert_level(parameters.send(key), results)
97 | assert_level(parameters[key], results)
98 |
99 | assert_key_error(parameters, :'0.0.0')
100 | end
101 |
102 | def test_params_array()
103 | file_path = "params_array"
104 | formats.each do |format|
105 | parameters = create_parameters(format, file_path, invalid_path, invalid_path)
106 |
107 | assert_equal(["1", "2", "3"], parameters[:level1][:level2])
108 | end
109 | end
110 |
111 | def test_file_nil()
112 | run_test_file_invalid(nil)
113 | end
114 |
115 | def test_file_does_not_exist()
116 | run_test_file_invalid("impossible_file_path.yml.impossible")
117 | end
118 |
119 | def run_test_file_invalid(invalid_value)
120 | formats.each do |format|
121 | parameters = create_parameters(format, "params_simple", invalid_path, invalid_path)
122 | assert_all_access_equal("value", parameters, "test")
123 |
124 | parameters = create_parameters(format, invalid_path, "params_simple", invalid_path)
125 | assert_all_access_equal("value", parameters, "test")
126 |
127 | parameters = create_parameters(format, invalid_path, invalid_path, "params_simple")
128 | assert_all_access_equal("value", parameters, "test")
129 |
130 | parameters = create_parameters(format, invalid_path, invalid_path, invalid_path)
131 | assert(parameters)
132 | end
133 | end
134 |
135 | def test_params_windows_eol()
136 | run_test_params_eol("params_windows_eol")
137 | end
138 |
139 | def test_params_unix_eol()
140 | run_test_params_eol("params_unix_eol")
141 | end
142 |
143 | def run_test_params_eol(file_path)
144 | formats.each do |format|
145 | parameters = create_parameters(format, file_path, invalid_path, invalid_path)
146 |
147 | assert_all_access_equal("value1", parameters, 'level1')
148 | assert_all_access_equal("value2", parameters['level2'], 'first')
149 | end
150 | end
151 |
152 | def test_restricted_defaults_usage()
153 | formats.each do |format|
154 | parameters = create_parameters(format, "params_defaults_at_root", invalid_path, invalid_path)
155 |
156 | assert_all_access_equal("value", parameters, :defaults)
157 | end
158 |
159 | formats.each do |format|
160 | parameters = create_parameters(format, "params_defaults_not_at_root", invalid_path, invalid_path)
161 |
162 | assert_all_access_equal("value", parameters.level, :defaults)
163 | end
164 | end
165 |
166 | def test_defaults()
167 | formats.each do |format|
168 | parameters = create_parameters(format, "params_simple", invalid_path, invalid_path)
169 | parameters.defaults = {:test => "override1", :level => "new1"}
170 |
171 | assert_all_access_equal("value", parameters, 'test')
172 | assert_all_access_equal("new1", parameters, 'level')
173 | end
174 | end
175 |
176 | def test_empty_file()
177 | formats.each do |format|
178 | parameters = create_parameters(format, "params_empty", invalid_path, invalid_path)
179 | parameters.defaults = {:test => "value"}
180 |
181 | assert_all_access_equal("value", parameters, 'test')
182 | end
183 | end
184 |
185 | def test_file_not_hash()
186 | ["boolean", "list"].each do |wrong_type|
187 | formats.each do |format|
188 | parameters = create_parameters(format, "params_#{wrong_type}", invalid_path, invalid_path)
189 | parameters.defaults = {:test => "value"}
190 |
191 | assert_all_access_equal("value", parameters, 'test')
192 | end
193 | end
194 | end
195 |
196 | def test_nil_values()
197 | formats.each do |format|
198 | parameters = create_parameters(format, "params_user_nil_values", invalid_path, invalid_path)
199 | parameters.defaults = {:nil => "Not nil", :deep => {:nil => "Not nil", :deeper => {:nil => "Not nil"}}}
200 |
201 | assert_all_access_equal("Not nil", parameters[:deep][:deeper], :nil)
202 | assert_all_access_equal("Not nil", parameters[:deep], :nil)
203 | assert_all_access_equal("Not nil", parameters, :nil)
204 | end
205 |
206 | formats.each do |format|
207 | parameters = create_parameters(format, "params_user_nil_values", invalid_path, invalid_path)
208 |
209 | assert_all_access_equal(nil, parameters[:deep][:deeper], :nil)
210 | assert_all_access_equal(nil, parameters[:deep], :nil)
211 | assert_all_access_equal(nil, parameters, :nil)
212 | end
213 | end
214 |
215 | def test_restricted_keys_are_still_accessible
216 | keys = Helper::Parameters.restricted_keys()
217 | elements = Hash[
218 | keys.map do |key|
219 | [key, "#{key.to_s} - value"]
220 | end
221 | ]
222 |
223 | parameters = create_parameters(:json, invalid_path, invalid_path, invalid_path)
224 | parameters.defaults = elements
225 |
226 | keys.each do |key|
227 | assert_equal("#{key.to_s} - value", parameters[key.to_s], "parameters[#{key.to_s}]")
228 | assert_equal("#{key.to_s} - value", parameters[key.to_sym], "parameters[#{key.to_sym}]")
229 | end
230 | end
231 |
232 | def test_enumerable_method_insensitive()
233 | parameters = create_parameters(:json, "params_simple", invalid_path, invalid_path)
234 | parameters.defaults = {"test" => "override1", :level => :new1}
235 |
236 | assert_equal(1, parameters.count([:test, "value"]))
237 | assert_equal(1, parameters.count(["test", "value"]))
238 | assert_equal(0, parameters.count(["test"]))
239 | assert_equal(0, parameters.count([]))
240 | assert_equal(0, parameters.count(:a))
241 | assert_equal(0, parameters.count(nil))
242 |
243 | assert_equal(0, parameters.find_index([:test, "value"]))
244 | assert_equal(0, parameters.find_index(["test", "value"]))
245 | assert_equal(nil, parameters.find_index(["test"]))
246 | assert_equal(nil, parameters.find_index([]))
247 | assert_equal(nil, parameters.find_index(:a))
248 | assert_equal(nil, parameters.find_index(nil))
249 | assert_equal(0, parameters.find_index() { |key, value| key == :test and value == "value" })
250 |
251 | assert_equal(false, parameters.include?([:test, "value"]))
252 | assert_equal(false, parameters.include?(["test", "value"]))
253 | end
254 |
255 | def test_hash_method_insensitive()
256 | parameters = create_parameters(:json, "params_simple", invalid_path, invalid_path)
257 | parameters.defaults = {"test" => "override1", :level => :new1}
258 |
259 | assert_equal([:test, "value"], parameters.assoc("test"))
260 | assert_equal([:test, "value"], parameters.assoc(:test))
261 |
262 | # compare_by_identity ?
263 |
264 | parameters.delete("test")
265 | assert_equal(nil, parameters.assoc("test"))
266 | assert_equal(nil, parameters.assoc(:test))
267 |
268 | parameters = create_parameters(:json, "params_simple", invalid_path, invalid_path)
269 | parameters.defaults = {"test" => "override1", :level => :new1}
270 |
271 | assert_equal([[:test, "value"], [:level, :new1]], parameters.collect {|key, value| [key, value]})
272 |
273 | assert_equal("value", parameters.fetch("test"))
274 | assert_equal("value", parameters.fetch("test", "default"))
275 | assert_equal("default", parameters.fetch("unknown", "default"))
276 |
277 | assert_equal(true, parameters.has_key?("test"))
278 | assert_equal(true, parameters.has_key?(:test))
279 |
280 | assert_equal(true, parameters.include?("test"))
281 | assert_equal(true, parameters.include?(:test))
282 |
283 | assert_equal(true, parameters.member?("test"))
284 | assert_equal(true, parameters.member?(:test))
285 |
286 | parameters.store("another", "different")
287 | assert_equal(true, parameters.member?("another"))
288 | assert_equal(true, parameters.member?(:another))
289 | end
290 |
291 | def test_defaults_not_overwritten_on_array_merge_strategy_change
292 | parameters = create_parameters(:json, "params_array", invalid_path, invalid_path)
293 | parameters.defaults = {"level1" => {"level2" => ["4", "5", "6"]}}
294 |
295 | parameters.array_merge_strategy = :concat
296 |
297 | assert_equal(["4", "5", "6"], parameters.defaults().level1.level2)
298 | assert_equal(["1", "2", "3", "4", "5", "6"], parameters.level1.level2)
299 | end
300 |
301 | def test_merge()
302 | parameters1 = create_parameters(:json, "params_current_1", invalid_path, invalid_path, {
303 | "0.1.1" => "default",
304 | "0.1.0" => "default",
305 | "0.0.1" => "default",
306 | })
307 |
308 | parameters2 = create_parameters(:json, "params_current_1", invalid_path, "params_system_1", {
309 | "0.1.0" => "default_overriden",
310 | })
311 |
312 | parameters3 = parameters1.merge(parameters2)
313 |
314 | refute_same(parameters1, parameters3)
315 | refute_same(parameters2, parameters3)
316 |
317 | assert_equal(Nugrant::Parameters, parameters3.class)
318 |
319 | assert_level(parameters3, {
320 | :'1.1.1' => "current",
321 | :'1.1.0' => "current",
322 | :'1.0.1' => "current",
323 | :'0.1.1' => "system",
324 | :'1.0.0' => "current",
325 | :'0.1.0' => "default_overriden",
326 | :'0.0.1' => "system",
327 | })
328 | end
329 |
330 | def test_merge!()
331 | parameters1 = create_parameters(:json, "params_current_1", invalid_path, invalid_path, {
332 | "0.1.1" => "default",
333 | "0.1.0" => "default",
334 | "0.0.1" => "default",
335 | })
336 |
337 | parameters2 = create_parameters(:json, "params_current_1", invalid_path, "params_system_1", {
338 | "0.1.0" => "default_overriden",
339 | })
340 |
341 | parameters3 = parameters1.merge!(parameters2)
342 |
343 | assert_same(parameters1, parameters3)
344 | refute_same(parameters2, parameters3)
345 |
346 | assert_equal(Nugrant::Parameters, parameters3.class)
347 |
348 | assert_level(parameters3, {
349 | :'1.1.1' => "current",
350 | :'1.1.0' => "current",
351 | :'1.0.1' => "current",
352 | :'0.1.1' => "system",
353 | :'1.0.0' => "current",
354 | :'0.1.0' => "default_overriden",
355 | :'0.0.1' => "system",
356 | })
357 | end
358 |
359 | def test_merge_with_different_array_merge_strategy()
360 | parameters1 = create_parameters(:json, "params_array", invalid_path, invalid_path, {
361 | "level1" => {
362 | "level2" => ["3", "4", "5"]
363 | }
364 | }, :array_merge_strategy => :replace)
365 |
366 | parameters2 = create_parameters(:json, "params_array", invalid_path, invalid_path, {
367 | "level1" => {
368 | "level2" => ["3", "6", "7"]
369 | }
370 | }, :array_merge_strategy => :concat)
371 |
372 | parameters3 = parameters1.merge(parameters2)
373 |
374 | assert_equal(["1", "2", "3", "3", "6", "7"], parameters3.level1.level2)
375 | end
376 |
377 | def test_numeric_key_in_yaml_converted_to_symbol()
378 | parameters = create_parameters(:yaml, "params_numeric_key", invalid_path, invalid_path)
379 |
380 | assert_equal("value1", parameters.servers[:'1'])
381 | end
382 |
383 | ## Helpers & Assertions
384 |
385 | def create_parameters(format, current_filename, user_filename, system_filename, defaults = {}, options = {})
386 | extension = case format
387 | when :json
388 | "json"
389 | when :yml, :yaml
390 | "yml"
391 | else
392 | raise ArgumentError, "Format [#{format}] is currently not supported"
393 | end
394 |
395 | resource_path = File.expand_path("#{File.dirname(__FILE__)}/../../resources/#{format}")
396 |
397 | current_path = "#{resource_path}/#{current_filename}.#{extension}" if current_filename
398 | user_path = "#{resource_path}/#{user_filename}.#{extension}" if user_filename
399 | system_path = "#{resource_path}/#{system_filename}.#{extension}" if system_filename
400 |
401 | return Nugrant::Parameters.new(defaults, {
402 | :format => format,
403 | :current_path => current_path,
404 | :user_path => user_path,
405 | :system_path => system_path,
406 | :array_merge_strategy => options[:array_merge_strategy]
407 | })
408 | end
409 |
410 | def assert_all_access_equal(expected, parameters, key)
411 | assert_equal(expected, parameters.method_missing(key.to_sym), "parameters.#{key.to_s}")
412 | assert_equal(expected, parameters[key.to_s], "parameters[#{key.to_s}]")
413 | assert_equal(expected, parameters[key.to_sym], "parameters[#{key.to_sym}]")
414 | end
415 |
416 | def assert_level(parameters, results)
417 | results.each do |key, value|
418 | assert_all_access_equal(value, parameters, key)
419 | end
420 |
421 | assert_key_error(parameters, "0.0.0")
422 | end
423 |
424 | def assert_key_error(parameters, key)
425 | assert_raises(KeyError) do
426 | parameters[key]
427 | end
428 | end
429 |
430 | def formats()
431 | @@FORMATS
432 | end
433 |
434 | def invalid_path()
435 | @@INVALID_PATH
436 | end
437 | end
438 | end
439 |
--------------------------------------------------------------------------------
/test/lib/test_helper.rb:
--------------------------------------------------------------------------------
1 | require "minitest/reporters"
2 |
3 | Minitest::Reporters.use!
4 |
--------------------------------------------------------------------------------
/test/resources/.vagrantuser:
--------------------------------------------------------------------------------
1 | vm_port: 3332
2 | repository:
3 | personal: "/home/user/personal/git"
4 |
--------------------------------------------------------------------------------
/test/resources/README.md:
--------------------------------------------------------------------------------
1 | This readme give information on how to read resources file
2 | that test merge possibilities.
3 |
4 | Naming conventions
5 | -----------------
6 |
7 | The filename uses a specific convention:
8 |
9 | params_*kind*_*level*.[yml|json]
10 |
11 | The kind is one of: [`current`|`user`|`system`] and defines which
12 | responsibility they will hold. The order is `current` overrides
13 | `user` overrides `system`.
14 |
15 | Inside file, keys have special meaning. They define how
16 | the overrides take place. We used the binary format
17 | to represent each possibilities.
18 |
19 | key = "1.1.1"
20 |
21 | Each element represent a specific kind. Read from left to
22 | right, they are assigned to `current`, `user` and `system`
23 | respectively.
24 |
25 | So,
26 |
27 | `current` `user` `system`
28 | 1 . 1 . 1
29 |
30 | A 1 signify that the file kind *column* will have a key "1.1.1" set
31 | to value *kind*. A 0 means the key is not set. With this in mind,
32 | it is easy to reason about the value that will need to be asserted
33 | for key "1.1.1" on level file *level*.
34 |
35 | # params_current_1.yml file
36 | "1.1.1": "current"
37 |
38 | # params_user_1.yml file
39 | "1.1.1": "user"
40 |
41 | # params_system_1.yml file
42 | "1.1.1": "system"
43 |
44 | # Value to assert
45 | assert("current", parameters.get("1.1.1"))
46 |
47 | With the help of params_combinations, it is easy to create test file
48 | either for other formats or for more level. Copy the all keys expect
49 | "0.0.0" to the file. Say the file is of kind `current`, then for
50 | column `current`, each time a one is there, replace `base` by the
51 | kind (here `current`). The line that still have value base as the
52 | value must be deleted.
53 |
--------------------------------------------------------------------------------
/test/resources/json/params_array.json:
--------------------------------------------------------------------------------
1 | {
2 | "level1": {
3 | "level2": ["1", "2", "3"]
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/test/resources/json/params_boolean.json:
--------------------------------------------------------------------------------
1 | false
2 |
--------------------------------------------------------------------------------
/test/resources/json/params_combinations.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": "base",
3 | "1.1.0": "base",
4 | "1.0.1": "base",
5 | "0.1.1": "base",
6 | "1.0.0": "base",
7 | "0.1.0": "base",
8 | "0.0.1": "base",
9 |
10 | "1.1.1": {
11 | "1.1.1": "base",
12 | "1.1.0": "base",
13 | "1.0.1": "base",
14 | "0.1.1": "base",
15 | "1.0.0": "base",
16 | "0.1.0": "base",
17 | "0.0.1": "base"
18 | },
19 |
20 | "1.1.0": {
21 | "1.1.1": "base",
22 | "1.1.0": "base",
23 | "1.0.1": "base",
24 | "0.1.1": "base",
25 | "1.0.0": "base",
26 | "0.1.0": "base",
27 | "0.0.1": "base"
28 | },
29 |
30 | "1.0.1": {
31 | "1.1.1": "base",
32 | "1.1.0": "base",
33 | "1.0.1": "base",
34 | "0.1.1": "base",
35 | "1.0.0": "base",
36 | "0.1.0": "base",
37 | "0.0.1": "base"
38 | },
39 |
40 | "0.1.1": {
41 | "1.1.1": "base",
42 | "1.1.0": "base",
43 | "1.0.1": "base",
44 | "0.1.1": "base",
45 | "1.0.0": "base",
46 | "0.1.0": "base",
47 | "0.0.1": "base"
48 | },
49 |
50 | "1.0.0": {
51 | "1.1.1": "base",
52 | "1.1.0": "base",
53 | "1.0.1": "base",
54 | "0.1.1": "base",
55 | "1.0.0": "base",
56 | "0.1.0": "base",
57 | "0.0.1": "base"
58 | },
59 |
60 | "0.1.0": {
61 | "1.1.1": "base",
62 | "1.1.0": "base",
63 | "1.0.1": "base",
64 | "0.1.1": "base",
65 | "1.0.0": "base",
66 | "0.1.0": "base",
67 | "0.0.1": "base"
68 | },
69 |
70 | "0.0.1": {
71 | "1.1.1": "base",
72 | "1.1.0": "base",
73 | "1.0.1": "base",
74 | "0.1.1": "base",
75 | "1.0.0": "base",
76 | "0.1.0": "base",
77 | "0.0.1": "base"
78 | },
79 |
80 | "0.0.0": "do not put, key should not exist"
81 | }
82 |
--------------------------------------------------------------------------------
/test/resources/json/params_current_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": "current",
3 | "1.1.0": "current",
4 | "1.0.1": "current",
5 | "1.0.0": "current"
6 | }
7 |
--------------------------------------------------------------------------------
/test/resources/json/params_current_2.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": {
3 | "1.1.1": "current",
4 | "1.1.0": "current",
5 | "1.0.1": "current",
6 | "1.0.0": "current"
7 | },
8 |
9 | "1.1.0": {
10 | "1.1.1": "current",
11 | "1.1.0": "current",
12 | "1.0.1": "current",
13 | "1.0.0": "current"
14 | },
15 |
16 | "1.0.1": {
17 | "1.1.1": "current",
18 | "1.1.0": "current",
19 | "1.0.1": "current",
20 | "1.0.0": "current"
21 | },
22 |
23 | "1.0.0": {
24 | "1.1.1": "current",
25 | "1.1.0": "current",
26 | "1.0.1": "current",
27 | "1.0.0": "current"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/resources/json/params_defaults_at_root.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaults": "value"
3 | }
4 |
--------------------------------------------------------------------------------
/test/resources/json/params_defaults_not_at_root.json:
--------------------------------------------------------------------------------
1 | {
2 | "level": {
3 | "defaults": "value"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/test/resources/json/params_empty.json:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maoueh/nugrant/6276b3e81364c6ed204d958ec01c653a34a74464/test/resources/json/params_empty.json
--------------------------------------------------------------------------------
/test/resources/json/params_list.json:
--------------------------------------------------------------------------------
1 | ["value", "second"]
2 |
--------------------------------------------------------------------------------
/test/resources/json/params_simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "test": "value"
3 | }
4 |
--------------------------------------------------------------------------------
/test/resources/json/params_system_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": "system",
3 | "1.0.1": "system",
4 | "0.1.1": "system",
5 | "0.0.1": "system"
6 | }
7 |
--------------------------------------------------------------------------------
/test/resources/json/params_system_2.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": {
3 | "1.1.1": "system",
4 | "1.0.1": "system",
5 | "0.1.1": "system",
6 | "0.0.1": "system"
7 | },
8 |
9 | "1.0.1": {
10 | "1.1.1": "system",
11 | "1.0.1": "system",
12 | "0.1.1": "system",
13 | "0.0.1": "system"
14 | },
15 |
16 | "0.1.1": {
17 | "1.1.1": "system",
18 | "1.0.1": "system",
19 | "0.1.1": "system",
20 | "0.0.1": "system"
21 | },
22 |
23 | "0.0.1": {
24 | "1.1.1": "system",
25 | "1.0.1": "system",
26 | "0.1.1": "system",
27 | "0.0.1": "system"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/resources/json/params_unix_eol.json:
--------------------------------------------------------------------------------
1 | {
2 | "level1": "value1",
3 | "level2": {
4 | "first": "value2"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/test/resources/json/params_user_1.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": "user",
3 | "1.1.0": "user",
4 | "0.1.1": "user",
5 | "0.1.0": "user"
6 | }
7 |
--------------------------------------------------------------------------------
/test/resources/json/params_user_2.json:
--------------------------------------------------------------------------------
1 | {
2 | "1.1.1": {
3 | "1.1.1": "user",
4 | "1.1.0": "user",
5 | "0.1.1": "user",
6 | "0.1.0": "user"
7 | },
8 |
9 | "1.1.0": {
10 | "1.1.1": "user",
11 | "1.1.0": "user",
12 | "0.1.1": "user",
13 | "0.1.0": "user"
14 | },
15 |
16 | "0.1.1": {
17 | "1.1.1": "user",
18 | "1.1.0": "user",
19 | "0.1.1": "user",
20 | "0.1.0": "user"
21 | },
22 |
23 | "0.1.0": {
24 | "1.1.1": "user",
25 | "1.1.0": "user",
26 | "0.1.1": "user",
27 | "0.1.0": "user"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/test/resources/json/params_user_nil_values.json:
--------------------------------------------------------------------------------
1 | {
2 | "nil": null,
3 | "deep": {
4 | "nil": null,
5 | "deeper": {
6 | "nil": null
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/resources/json/params_windows_eol.json:
--------------------------------------------------------------------------------
1 | {
2 | "level1": "value1",
3 | "level2": {
4 | "first": "value2"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.auto_export:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.user.auto_export = [:autoenv, :script]
3 |
4 | config.user.defaults = {
5 | 'local' => {
6 | 'first' => "value1",
7 | },
8 | }
9 |
10 | #config.vm.box = "opscode_centos-7.0_x86-64"
11 |
12 | raise "You need to define `config.vm.box` for this test"
13 | end
14 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.bag_inside_array:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.user.defaults = {
3 | nodes: [
4 | {ip: '192.168.100.10'},
5 | {ip: '192.168.100.11'}
6 | ]
7 | }
8 |
9 | config.user.nodes.each_with_index do |node, index|
10 | puts "Node ##{index}, string: #{node['ip']}"
11 | puts "Node ##{index}, symbol: #{node[:ip]}"
12 | puts "Node ##{index}, method: #{node.ip}"
13 | puts ""
14 | end
15 | end
16 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.defaults_mixed_string_symbols:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.user.defaults = {
3 | 'single' => 1,
4 | :local => {
5 | 'first' => "value1",
6 | :second => "value2"
7 | }
8 | }
9 |
10 | puts config.user.single
11 | puts config.user[:single]
12 |
13 | puts config.user.local.first
14 | puts config.user[:local]["first"]
15 |
16 | puts config.user.local.second
17 | puts config.user["local"][:second]
18 | end
19 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.defaults_null_values_in_vagrantuser:
--------------------------------------------------------------------------------
1 | # Source from https://github.com/maoueh/nugrant/issues/12#issuecomment-27054150
2 | # but slightly modified
3 | Vagrant.configure('2') do |config|
4 | config.user.defaults = {
5 | "host" => {
6 | "rails_server_port" => 3000,
7 | "apps_folder" => "../../rails-apps/" },
8 | "plugins" => {
9 | "vagrant_cachier" => {
10 | "enabled" => false
11 | }
12 | }
13 | }
14 |
15 | puts "Host Rails Server Port: #{config.user.host.rails_server_port}"
16 | puts "Host App Folder: #{config.user.host.apps_folder}"
17 | puts "Gitconfig Name: #{config.user.gitconfig.name}"
18 | puts "Gitconfig Email: #{config.user.gitconfig.email}"
19 |
20 | if config.user.plugins.vagrant_cachier.enabled
21 | puts "Vagrant Cachier is Enabled!"
22 | end
23 | end
24 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.defaults_using_string:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.user.defaults = {
3 | 'single' => 1,
4 | 'local' => {
5 | 'first' => "value1",
6 | 'second' => "value2"
7 | }
8 | }
9 |
10 | puts config.user.single
11 | puts config.user[:single]
12 |
13 | puts config.user.local.first
14 | puts config.user[:local]["first"]
15 |
16 | puts config.user.local.second
17 | puts config.user["local"][:second]
18 | end
19 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.defaults_using_symbol:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.user.defaults = {
3 | :single => 1,
4 | :local => {
5 | :first => "value1",
6 | :second => "value2"
7 | }
8 | }
9 |
10 | puts config.user.single
11 | puts config.user[:single]
12 |
13 | puts config.user.local.first
14 | puts config.user[:local]["first"]
15 |
16 | puts config.user.local.second
17 | puts config.user["local"][:second]
18 | end
19 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.empty:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | end
3 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.fake:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.user.defaults = {
3 | 'local' => {
4 | 'first' => "value1",
5 | },
6 | 'array' => {
7 | 'level1' => [1, 2]
8 | },
9 | 'application' => {
10 | 'users' => {
11 | "joe" => {
12 | :full => "Joe Plumber"
13 | },
14 | "jane" => {
15 | :full => "Jane Cook"
16 | },
17 | }
18 | }
19 | }
20 |
21 | config.user.application.users.each do |key, data|
22 | puts "Key #{key}: #{data}"
23 | end
24 |
25 | config.user.array_merge_strategy = :concat
26 | config.user.auto_export = [:autoenv, :script]
27 |
28 | config.vm.box = "opscode_centos-7.0_x86-64"
29 | end
30 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.missing_parameter:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | puts config.user.unkown_for_sure
3 | end
4 |
--------------------------------------------------------------------------------
/test/resources/vagrantfiles/v2.real:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.vm.box = "base"
3 | config.vm.box_url = "http://domain.com/path/to/above.box"
4 |
5 | config.vm.network :forwarded_port, guest: 80, host: 8080
6 | config.vm.network :private_network, ip: "10.0.0.2"
7 |
8 | config.vm.synced_folder "C:/Users/Matt/nugrant", "/vagrant_data"
9 |
10 | config.vm.provider :virtualbox do |virtualbox|
11 | virtualbox.customize ["modifyvm", :id, "--memory", "256"]
12 | end
13 |
14 | config.vm.provision :chef_solo do |chef|
15 | chef.cookbooks_path = "C:\Users\Matt\Work\kitchen\cookbooks"
16 | chef.roles_path = "C:\Users\Matt\Work\kitchen\roles"
17 | chef.nodes_path = "C:\Users\Matt\Work\kitchen\nodes"
18 |
19 | chef.add_recipe "mysql"
20 | chef.add_role "web"
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_array.yml:
--------------------------------------------------------------------------------
1 | level1:
2 | level2:
3 | - "1"
4 | - "2"
5 | - "3"
6 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_boolean.yml:
--------------------------------------------------------------------------------
1 | false
2 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_combinations.yml:
--------------------------------------------------------------------------------
1 | "1.1.1": "base"
2 | "1.1.0": "base"
3 | "1.0.1": "base"
4 | "0.1.1": "base"
5 | "1.0.0": "base"
6 | "0.1.0": "base"
7 | "0.0.1": "base"
8 |
9 | "1.1.1":
10 | "1.1.1": "base"
11 | "1.1.0": "base"
12 | "1.0.1": "base"
13 | "0.1.1": "base"
14 | "1.0.0": "base"
15 | "0.1.0": "base"
16 | "0.0.1": "base"
17 |
18 | "1.1.0":
19 | "1.1.1": "base"
20 | "1.1.0": "base"
21 | "1.0.1": "base"
22 | "0.1.1": "base"
23 | "1.0.0": "base"
24 | "0.1.0": "base"
25 | "0.0.1": "base"
26 |
27 | "1.0.1":
28 | "1.1.1": "base"
29 | "1.1.0": "base"
30 | "1.0.1": "base"
31 | "0.1.1": "base"
32 | "1.0.0": "base"
33 | "0.1.0": "base"
34 | "0.0.1": "base"
35 |
36 | "0.1.1":
37 | "1.1.1": "base"
38 | "1.1.0": "base"
39 | "1.0.1": "base"
40 | "0.1.1": "base"
41 | "1.0.0": "base"
42 | "0.1.0": "base"
43 | "0.0.1": "base"
44 |
45 | "1.0.0":
46 | "1.1.1": "base"
47 | "1.1.0": "base"
48 | "1.0.1": "base"
49 | "0.1.1": "base"
50 | "1.0.0": "base"
51 | "0.1.0": "base"
52 | "0.0.1": "base"
53 |
54 | "0.1.0":
55 | "1.1.1": "base"
56 | "1.1.0": "base"
57 | "1.0.1": "base"
58 | "0.1.1": "base"
59 | "1.0.0": "base"
60 | "0.1.0": "base"
61 | "0.0.1": "base"
62 |
63 | "0.0.1":
64 | "1.1.1": "base"
65 | "1.1.0": "base"
66 | "1.0.1": "base"
67 | "0.1.1": "base"
68 | "1.0.0": "base"
69 | "0.1.0": "base"
70 | "0.0.1": "base"
71 |
72 | "0.0.0": "do not put key should not exist"
73 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_current_1.yml:
--------------------------------------------------------------------------------
1 | "1.1.1": "current"
2 | "1.1.0": "current"
3 | "1.0.1": "current"
4 | "1.0.0": "current"
5 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_current_2.yml:
--------------------------------------------------------------------------------
1 | "1.1.1":
2 | "1.1.1": "current"
3 | "1.1.0": "current"
4 | "1.0.1": "current"
5 | "1.0.0": "current"
6 |
7 | "1.1.0":
8 | "1.1.1": "current"
9 | "1.1.0": "current"
10 | "1.0.1": "current"
11 | "1.0.0": "current"
12 |
13 | "1.0.1":
14 | "1.1.1": "current"
15 | "1.1.0": "current"
16 | "1.0.1": "current"
17 | "1.0.0": "current"
18 |
19 | "1.0.0":
20 | "1.1.1": "current"
21 | "1.1.0": "current"
22 | "1.0.1": "current"
23 | "1.0.0": "current"
24 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_defaults_at_root.yml:
--------------------------------------------------------------------------------
1 | "defaults": "value"
2 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_defaults_not_at_root.yml:
--------------------------------------------------------------------------------
1 | "level":
2 | "defaults": "value"
3 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_empty.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/maoueh/nugrant/6276b3e81364c6ed204d958ec01c653a34a74464/test/resources/yaml/params_empty.yml
--------------------------------------------------------------------------------
/test/resources/yaml/params_list.yml:
--------------------------------------------------------------------------------
1 | - first
2 | - second
3 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_numeric_key.yml:
--------------------------------------------------------------------------------
1 | servers:
2 | 1: "value1"
3 | 2: "value2"
4 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_simple.yml:
--------------------------------------------------------------------------------
1 | test: "value"
2 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_system_1.yml:
--------------------------------------------------------------------------------
1 | "1.1.1": "system"
2 | "1.0.1": "system"
3 | "0.1.1": "system"
4 | "0.0.1": "system"
5 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_system_2.yml:
--------------------------------------------------------------------------------
1 | "1.1.1":
2 | "1.1.1": "system"
3 | "1.0.1": "system"
4 | "0.1.1": "system"
5 | "0.0.1": "system"
6 |
7 | "1.0.1":
8 | "1.1.1": "system"
9 | "1.0.1": "system"
10 | "0.1.1": "system"
11 | "0.0.1": "system"
12 |
13 | "0.1.1":
14 | "1.1.1": "system"
15 | "1.0.1": "system"
16 | "0.1.1": "system"
17 | "0.0.1": "system"
18 |
19 | "0.0.1":
20 | "1.1.1": "system"
21 | "1.0.1": "system"
22 | "0.1.1": "system"
23 | "0.0.1": "system"
24 |
25 |
26 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_unix_eol.yml:
--------------------------------------------------------------------------------
1 | level1: "value1"
2 | level2:
3 | first: "value2"
4 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_user_1.yml:
--------------------------------------------------------------------------------
1 | "1.1.1": "user"
2 | "1.1.0": "user"
3 | "0.1.1": "user"
4 | "0.1.0": "user"
5 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_user_2.yml:
--------------------------------------------------------------------------------
1 | "1.1.1":
2 | "1.1.1": "user"
3 | "1.1.0": "user"
4 | "0.1.1": "user"
5 | "0.1.0": "user"
6 |
7 | "1.1.0":
8 | "1.1.1": "user"
9 | "1.1.0": "user"
10 | "0.1.1": "user"
11 | "0.1.0": "user"
12 |
13 | "0.1.1":
14 | "1.1.1": "user"
15 | "1.1.0": "user"
16 | "0.1.1": "user"
17 | "0.1.0": "user"
18 |
19 | "0.1.0":
20 | "1.1.1": "user"
21 | "1.1.0": "user"
22 | "0.1.1": "user"
23 | "0.1.0": "user"
24 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_user_nil_values.yml:
--------------------------------------------------------------------------------
1 | nil:
2 | deep:
3 | nil:
4 | deeper:
5 | nil:
6 |
--------------------------------------------------------------------------------
/test/resources/yaml/params_windows_eol.yml:
--------------------------------------------------------------------------------
1 | level1: "value1"
2 | level2:
3 | first: "value2"
4 |
--------------------------------------------------------------------------------