builderator 1.0.0.pre.rc.9 → 1.0.0.pre.rc.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/VERSION +1 -1
- data/docs/configuration.md +117 -26
- data/lib/builderator/config.rb +9 -8
- data/lib/builderator/config/attributes.rb +58 -53
- data/lib/builderator/config/file.rb +8 -3
- data/lib/builderator/config/list.rb +63 -0
- data/lib/builderator/config/rash.rb +16 -11
- data/lib/builderator/tasks/vendor.rb +8 -4
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7e1986d4b7bb1afd09020158460d0ab35220850
|
4
|
+
data.tar.gz: 1545ff99c44cbb336fd0315d6f43d3121568a720
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 419b869cec9a0f1eca44d02e4aa125a7bb4a5e959f5caea5c093ef7477066d64f6a62c9aa1bc7423636d962920a5c9496a520260ce55fe575eb53762d37a6b5d
|
7
|
+
data.tar.gz: 2639dbc8a87bbd6a788a8960fbdda57a64a15dc6c498f6ccdc8a06789bad1b569c8966887f6f4b8c496e7213d26c2cfc963fed1e7bf4b650797e9e01e5f78e2f
|
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.0-rc.
|
1
|
+
1.0.0-rc.10
|
data/docs/configuration.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
Configuration DSL
|
2
2
|
=================
|
3
3
|
|
4
|
-
|
4
|
+
Builderator's configuration language is a Ruby DSL, composed of `attributes`, which are grouped into `namespaces`. A `namespace` may be singular, or it may be part of a `collection`, in which case more than one named entry may be defined with the same `namespace`.
|
5
5
|
|
6
|
-
Namespaces can accessed with blocks, or with a fluent interface:
|
6
|
+
Namespaces and collections can accessed with blocks, or with a fluent interface:
|
7
7
|
|
8
8
|
```ruby
|
9
9
|
aws do |a|
|
@@ -14,26 +14,119 @@ end
|
|
14
14
|
aws.region = 'us-west-1'
|
15
15
|
```
|
16
16
|
|
17
|
-
Collections are named
|
17
|
+
Collections are sets of named items. Like namespaces, they can be accessed with blocks, or a fluent interface:
|
18
18
|
|
19
19
|
```ruby
|
20
20
|
profile :default do |default_profile|
|
21
|
-
default_profile.chef.run_list 'apt:default', 'redis:server'
|
21
|
+
default_profile.chef.run_list 'apt:default', 'redis:server', 'app::server'
|
22
22
|
end
|
23
23
|
|
24
24
|
profile(:default).chef.environment 'development'
|
25
|
+
profile(:prod).chef.environment 'production'
|
25
26
|
```
|
26
27
|
|
27
|
-
In the example above, the same collection is accessed twice. The final result looks like:
|
28
|
+
In the example above, the same collection item is accessed twice. A second item is also defined in the same collection. The final result looks like:
|
28
29
|
|
29
30
|
```json
|
30
31
|
{
|
31
32
|
"profile": {
|
32
33
|
"default": {
|
33
34
|
"chef": {
|
34
|
-
"run_list": ["apt:default", "redis:server"],
|
35
|
+
"run_list": ["apt:default", "redis:server", "app::server"],
|
35
36
|
"environment": "development"
|
36
37
|
}
|
38
|
+
},
|
39
|
+
"prod": {
|
40
|
+
"chef": {
|
41
|
+
"environment": "production"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
48
|
+
Collections and namespaces may be nested indefinitely.
|
49
|
+
|
50
|
+
## Extending Collection Items
|
51
|
+
|
52
|
+
A collection item can extend another item using a hash-notation:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
profile :prod => Config.profile(:default) do |prod|
|
56
|
+
prod.chef.environment = 'production'
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
Following the example, above, the `prod` profile will now be pre-populated with all of the values in the `default` profile, which can be overridden:
|
61
|
+
|
62
|
+
```json
|
63
|
+
{
|
64
|
+
"profile": {
|
65
|
+
"default": {
|
66
|
+
"chef": {
|
67
|
+
"run_list": ["apt:default", "redis:server", "app::server"],
|
68
|
+
"environment": "development"
|
69
|
+
}
|
70
|
+
},
|
71
|
+
"prod": {
|
72
|
+
"chef": {
|
73
|
+
"run_list": ["apt:default", "redis:server", "app::server"],
|
74
|
+
"environment": "production"
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
```
|
80
|
+
|
81
|
+
## List-type Attributes
|
82
|
+
|
83
|
+
Some configuration attributes are actually ordered sets of values. These are referred to as `list-type` attributes, and have some additional options:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
chef.run_list 'apt:default', :mode => :override
|
87
|
+
```
|
88
|
+
|
89
|
+
The `:mode` parameter tells the configuration manager how how to compile a list-type attribute that is defined in two or more layers, or is modified in an extended collection item. Currently, two modes are implemented:
|
90
|
+
|
91
|
+
* `:override` - Instructs the compiler to discard any elements that have been loaded from lower layers. This does not have any effect upon the behavior of the same attribute in higher layers, meaning that the current layer's override may be appended to or overridden by future layers, according to their `mode` parameter.
|
92
|
+
* `:union` - Default behavior. Instructs the compiler to perform a set-union between the current layer's elements and the current set of elements compiled from lower layers.
|
93
|
+
|
94
|
+
List-type attributes may also have an `appender method`, which allows elements to be appended to the current set _in that layer_. **List-type attributes do not have an `=` setter.**
|
95
|
+
|
96
|
+
Because `chef.run_list` is a list-type attribute, we can tell Builderator to override the `default` profile's `run_list`:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
profile :prod => Config.profile(:default) do |prod|
|
100
|
+
prod.chef.environment = 'production'
|
101
|
+
prod.chef.run_list 'apt:default', 'redis:server', 'app::server', 'app::tls', :mode => :override
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
We could also append to `default`'s `run_list` without modifying `default`:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
profile :prod => Config.profile(:default) do |prod|
|
109
|
+
prod.chef.environment = 'production'
|
110
|
+
prod.chef.run_list_item 'app::tls'
|
111
|
+
end
|
112
|
+
```
|
113
|
+
|
114
|
+
Both of the above will result in the same compiled configuration:
|
115
|
+
|
116
|
+
```json
|
117
|
+
{
|
118
|
+
"profile": {
|
119
|
+
"default": {
|
120
|
+
"chef": {
|
121
|
+
"run_list": ["apt:default", "redis:server", "app::server"],
|
122
|
+
"environment": "development"
|
123
|
+
}
|
124
|
+
},
|
125
|
+
"prod": {
|
126
|
+
"chef": {
|
127
|
+
"run_list": ["apt:default", "redis:server", "app::server", "app::tls"],
|
128
|
+
"environment": "production"
|
129
|
+
}
|
37
130
|
}
|
38
131
|
}
|
39
132
|
}
|
@@ -46,9 +139,9 @@ In the example above, the same collection is accessed twice. The final result lo
|
|
46
139
|
|
47
140
|
* `vendored(name, path)` - Return the absolute path to `path` in the named vendor resource. _ Hint: Use this helper to reference Builderator policy files and Chef data_bag and environment sources in an external repository._
|
48
141
|
|
49
|
-
|
142
|
+
* `relative(path)` - Return the absolute path to `path` relative to the calling Buildfile _Hint: Use this helper to reference templates included with a vendored policy._
|
50
143
|
|
51
|
-
|
144
|
+
## Configuration Parameters
|
52
145
|
|
53
146
|
* [Namespace `cookbook`](configuration/cookbook.md)
|
54
147
|
* [Collection `profile`](configuration/profile.md)
|
@@ -60,14 +153,12 @@ Collections and namespaces may be nested indefinitely.
|
|
60
153
|
* `version` The version of this release of the build. Auto-populated by `autoversion` by default
|
61
154
|
* `cleanup` Enable post-build cleanup tasks. Default `true`
|
62
155
|
|
63
|
-
|
64
|
-
|
65
|
-
## Namespace `autoversion`
|
156
|
+
### Namespace `autoversion`
|
66
157
|
|
67
158
|
* `create_tags` During a release, automatically create and push new SCM tags
|
68
159
|
* `search_tags` Use SCM tags to determine the current version of the build
|
69
160
|
|
70
|
-
|
161
|
+
### Namespace `chef`
|
71
162
|
|
72
163
|
Global configurations for chef provisioners in Vagrant and Packer
|
73
164
|
|
@@ -75,28 +166,28 @@ Global configurations for chef provisioners in Vagrant and Packer
|
|
75
166
|
* `staging_directory` the path in VMs and images that Chef artifacts should be mounted/copied to. Defaults to `/var/chef`
|
76
167
|
* `version` The version of chef to install with Omnibus
|
77
168
|
|
78
|
-
|
169
|
+
### Namespace `local`
|
79
170
|
|
80
171
|
Local paths used for build tasks
|
81
172
|
|
82
173
|
* `cookbook_path` Path at which to vendor cookbooks. Default `.builderator/cookbooks`
|
83
174
|
* `data_bag_path` and `environment_path` Paths that Chef providers should load data-bag and environment documents from.
|
84
175
|
|
85
|
-
|
176
|
+
### Collection `policy`
|
86
177
|
|
87
178
|
Load additional attributes into the parent file from a relative path
|
88
179
|
|
89
180
|
* `path` Load a DSL file, relative => true
|
90
181
|
* `json` Load a JSON file relative => true
|
91
182
|
|
92
|
-
|
183
|
+
### Namespace `aws`
|
93
184
|
|
94
185
|
AWS API configurations. _Hint: Configure these in `$HOME/.builderator/Buildfile`, or use a built-in credential source, e.g. ~/.aws/config!_
|
95
186
|
|
96
187
|
* `region` The default AWS region to use
|
97
188
|
* `access_key` and `secret_key` A valid IAM key-pair
|
98
189
|
|
99
|
-
|
190
|
+
### Collection `vendor`
|
100
191
|
|
101
192
|
Fetch remote artifacts for builds
|
102
193
|
|
@@ -105,16 +196,16 @@ Fetch remote artifacts for builds
|
|
105
196
|
* `git` Fetch a git repository
|
106
197
|
* `github` Fetch a git repository from a GitHub URI (e.g. `OWNER/REPO`) using the SSH protocol. You must have a valid SSH key configuration for public GitHub.
|
107
198
|
* Git-specific parameters:
|
108
|
-
* `
|
109
|
-
* `
|
110
|
-
* `ref`
|
199
|
+
* `remote` - The name of the remote repository at `git` or `github`. Defaults to `origin`
|
200
|
+
* `branch` - The SCM branch to check out. Defaults to `master`
|
201
|
+
* `tag` or `ref` - A SHA-ish or SCM tag to check out. Overrides `branch`.
|
111
202
|
* `rel` Checkout a sub-directory of a git repository
|
112
203
|
|
113
|
-
|
204
|
+
### Namespace `cleaner`
|
114
205
|
|
115
206
|
Configuration parameters for `build-clean` tasks
|
116
207
|
|
117
|
-
|
208
|
+
#### Namespace `limits`
|
118
209
|
|
119
210
|
Maximum number of resources to remove without manual override
|
120
211
|
|
@@ -123,25 +214,25 @@ Maximum number of resources to remove without manual override
|
|
123
214
|
* `snapshots`
|
124
215
|
* `volumes`
|
125
216
|
|
126
|
-
|
217
|
+
### Namespace `generator`
|
127
218
|
|
128
219
|
Configurations for the `generator` task
|
129
220
|
|
130
|
-
|
221
|
+
#### Collection `project`
|
131
222
|
|
132
223
|
* `builderator.version` The version of Builderator to install with Bundler
|
133
224
|
* `ruby.version` The version of ruby to require for Bundler and `rbenv`/`rvm`
|
134
225
|
|
135
|
-
|
226
|
+
##### Namespace `vagrant`
|
136
227
|
|
137
228
|
* `install` Boolean, include the vagrant gem from GitHub `mitchellh/vagrant`
|
138
229
|
* `version` The version of Vagrant to use from GitHub, if `install` is true
|
139
230
|
|
140
|
-
|
231
|
+
###### Collection `plugin`
|
141
232
|
|
142
233
|
Vagrant plugins to install, either with the `build vagrant plugin` command, for a system-wide installation of Vagrant, or in the generated Gemfile if `install` is true
|
143
234
|
|
144
|
-
|
235
|
+
##### Collection `resource`
|
145
236
|
|
146
237
|
Add a managed file to the project definition
|
147
238
|
|
data/lib/builderator/config.rb
CHANGED
@@ -14,7 +14,7 @@ module Builderator
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def all_layers
|
17
|
-
([defaults] + layers + [overrides, argv])
|
17
|
+
([GLOBAL_DEFAULTS, defaults] + layers + [overrides, argv])
|
18
18
|
end
|
19
19
|
|
20
20
|
def defaults
|
@@ -51,22 +51,23 @@ module Builderator
|
|
51
51
|
compiled.unseal
|
52
52
|
compile_iterations = 0
|
53
53
|
|
54
|
-
##
|
54
|
+
## Inject GLOBAL_DEFAULTS before starting compile
|
55
55
|
compiled.merge(GLOBAL_DEFAULTS.compile)
|
56
56
|
|
57
57
|
## Automatically recompile while layers are dirty
|
58
58
|
loop do
|
59
59
|
fail "Re-compile iteration limit of #{max_iterations} has been exceeded" if compile_iterations >= max_iterations
|
60
60
|
|
61
|
-
## Reset flags before next iteration
|
62
|
-
compiled.clean
|
63
|
-
|
64
61
|
## Merge layers from lowest to highest. Compile, then merge.
|
65
|
-
all_layers.each(&:compile)
|
66
62
|
all_layers.each do |layer|
|
67
|
-
|
63
|
+
layer.compile
|
64
|
+
end
|
68
65
|
|
66
|
+
all_layers.each do |layer|
|
69
67
|
layer.policies.each { |_, policy| compiled.merge(policy) }
|
68
|
+
|
69
|
+
## Merge layer after its policy documents to allow overides
|
70
|
+
compiled.merge(layer)
|
70
71
|
end
|
71
72
|
|
72
73
|
break unless dirty?
|
@@ -79,7 +80,7 @@ module Builderator
|
|
79
80
|
alias_method :recompile, :compile
|
80
81
|
|
81
82
|
def dirty?
|
82
|
-
all_layers.any?(&:dirty)
|
83
|
+
all_layers.any?(&:dirty)
|
83
84
|
end
|
84
85
|
|
85
86
|
def compiled
|
@@ -2,6 +2,7 @@ require 'forwardable'
|
|
2
2
|
require 'json'
|
3
3
|
|
4
4
|
require_relative './rash'
|
5
|
+
require_relative './list'
|
5
6
|
|
6
7
|
module Builderator
|
7
8
|
module Config
|
@@ -18,31 +19,30 @@ module Builderator
|
|
18
19
|
# Helpers for Array-type attributes
|
19
20
|
##
|
20
21
|
if options[:type] == :list
|
21
|
-
|
22
|
+
define_method(attribute_name) do |*arg, **run_options|
|
23
|
+
## Instantiate List if it doesn't exist yet. `||=` will always return a new Rash.
|
24
|
+
@attributes[attribute_name] = Config::List.new(run_options) unless @attributes.has?(attribute_name, Config::List)
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
@attributes[attribute_name].set(*arg.flatten) unless arg.empty?
|
27
|
+
@attributes[attribute_name]
|
28
|
+
end
|
29
|
+
|
30
|
+
define_method(options[:singular]) do |*arg, **run_options|
|
31
|
+
send(attribute_name, run_options).push(*arg.flatten)
|
26
32
|
end if options.include?(:singular)
|
33
|
+
|
34
|
+
return
|
27
35
|
end
|
28
36
|
|
29
37
|
## Getter/Setter
|
30
38
|
define_method(attribute_name) do |*arg|
|
31
|
-
arg.
|
32
|
-
arg = arg.first unless options[:type] == :list
|
33
|
-
|
34
|
-
set_or_return(attribute_name, arg, default, options)
|
39
|
+
set_or_return(attribute_name, arg.first, default, options)
|
35
40
|
end
|
36
41
|
|
37
42
|
## Setter
|
38
43
|
define_method("#{attribute_name}=") do |arg|
|
39
44
|
set_if_valid(attribute_name, arg, options)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
## Add a method the DSL
|
44
|
-
def define(method_name, &block)
|
45
|
-
define_method(method_name, &block)
|
45
|
+
end
|
46
46
|
end
|
47
47
|
|
48
48
|
##
|
@@ -58,7 +58,7 @@ module Builderator
|
|
58
58
|
# end
|
59
59
|
# ```
|
60
60
|
#
|
61
|
-
# Multiple calls to the DSL method
|
61
|
+
# Multiple calls to the DSL method are safe and will
|
62
62
|
# update the same sub-node.
|
63
63
|
##
|
64
64
|
def namespace(namespace_name, &definition)
|
@@ -68,7 +68,7 @@ module Builderator
|
|
68
68
|
nodes[namespace_name] ||= namespace_class.new(
|
69
69
|
@attributes[namespace_name],
|
70
70
|
:name => namespace_name,
|
71
|
-
:parent => self, &block)
|
71
|
+
:parent => self, &block)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -85,16 +85,29 @@ module Builderator
|
|
85
85
|
# Multiple entities can be added to the collection by calling the DSL method
|
86
86
|
# with unique `name` arguments. Multiple calls to the DSL method with the
|
87
87
|
# same name argument will update the existing entity in place
|
88
|
+
#
|
89
|
+
# An entry can be defined as an extension of another node by passing a hash
|
90
|
+
# as the instance name: `name => Config.node(:name)`. This will use the values
|
91
|
+
# defined in `Config.node(:name)` as defaults for the new entry
|
88
92
|
##
|
89
93
|
def collection(collection_name, &definition)
|
90
94
|
collection_class = Collection.create(collection_name, &definition)
|
91
95
|
|
92
96
|
define_method(collection_name) do |instance_name = nil, &block|
|
97
|
+
extension_base = nil
|
98
|
+
|
99
|
+
## Allow extension to be defined as a key-value
|
100
|
+
if instance_name.is_a?(Hash)
|
101
|
+
extension_base = instance_name.first.last
|
102
|
+
instance_name = instance_name.first.first
|
103
|
+
end
|
104
|
+
|
93
105
|
nodes[collection_name] ||= collection_class.new(
|
94
|
-
@attributes[collection_name]
|
106
|
+
@attributes[collection_name],
|
107
|
+
:parent => self)
|
95
108
|
|
96
109
|
return nodes[collection_name] if instance_name.nil?
|
97
|
-
nodes[collection_name].fetch(instance_name, &block)
|
110
|
+
nodes[collection_name].fetch(instance_name, :extends => extension_base, &block)
|
98
111
|
end
|
99
112
|
end
|
100
113
|
end
|
@@ -118,14 +131,10 @@ module Builderator
|
|
118
131
|
end
|
119
132
|
|
120
133
|
## All dirty state should aggregate at the root node
|
121
|
-
def dirty
|
122
|
-
return @dirty if parent == self
|
123
|
-
parent.dirty
|
124
|
-
end
|
134
|
+
def dirty(update = false)
|
135
|
+
return @dirty ||= update if parent == self
|
125
136
|
|
126
|
-
|
127
|
-
return @dirty = set if parent == self
|
128
|
-
parent.dirty = set
|
137
|
+
parent.dirty(update)
|
129
138
|
end
|
130
139
|
|
131
140
|
def ==(other)
|
@@ -135,6 +144,7 @@ module Builderator
|
|
135
144
|
attr_reader :attributes
|
136
145
|
attr_reader :nodes
|
137
146
|
attr_reader :parent
|
147
|
+
attr_reader :extends
|
138
148
|
|
139
149
|
def initialize(attributes = {}, options = {}, &block)
|
140
150
|
@attributes = Rash.coerce(attributes)
|
@@ -143,24 +153,35 @@ module Builderator
|
|
143
153
|
|
144
154
|
## Track change status for consumers
|
145
155
|
@parent = options.fetch(:parent, self)
|
146
|
-
|
156
|
+
@extends = options[:extends]
|
157
|
+
@dirty = false
|
147
158
|
end
|
148
159
|
|
149
160
|
## Clear dirty state flag
|
150
161
|
def clean
|
151
|
-
|
162
|
+
@dirty = false
|
152
163
|
end
|
153
164
|
|
154
|
-
def compile
|
155
|
-
|
165
|
+
def compile(evaluate = true)
|
166
|
+
## Compile this node and its children
|
167
|
+
@block.call(self) if @block && evaluate
|
168
|
+
nodes.each { |_, node| node.compile }
|
169
|
+
|
170
|
+
## Underlay base values if present
|
171
|
+
if extends.is_a?(Attributes)
|
172
|
+
merged_atributes = extends.attributes.clone
|
173
|
+
merged_atributes.merge!(attributes)
|
174
|
+
|
175
|
+
attributes.merge!(merged_atributes)
|
176
|
+
end
|
177
|
+
|
156
178
|
self
|
157
179
|
end
|
158
180
|
|
159
181
|
def merge(other)
|
160
|
-
|
182
|
+
dirty(attributes.merge!(other.attributes))
|
161
183
|
self
|
162
184
|
end
|
163
|
-
alias_method :includes, :merge
|
164
185
|
|
165
186
|
def to_json(*_)
|
166
187
|
JSON.pretty_generate(to_hash)
|
@@ -182,24 +203,12 @@ module Builderator
|
|
182
203
|
## Unchanged
|
183
204
|
return if @attributes[key] == arg
|
184
205
|
|
185
|
-
|
206
|
+
dirty(true) ## A mutation has occured
|
186
207
|
@attributes[key] = arg
|
187
208
|
end
|
188
209
|
|
189
|
-
def append_if_valid(key, arg, default = Array, **options)
|
190
|
-
## TODO: define validation interface
|
191
|
-
|
192
|
-
attribute = set_or_return(key, nil, default, options)
|
193
|
-
arg.reject! { |item| attribute.include?(item) }
|
194
|
-
|
195
|
-
return if arg.empty?
|
196
|
-
|
197
|
-
@dirty |= true ## A mutation has occured
|
198
|
-
attribute.push(*arg)
|
199
|
-
end
|
200
|
-
|
201
210
|
def set_or_return(key, arg = nil, default = nil, **options)
|
202
|
-
if arg.nil?
|
211
|
+
if arg.nil?
|
203
212
|
return @attributes[key] if @attributes.has?(key)
|
204
213
|
|
205
214
|
## Default
|
@@ -249,11 +258,6 @@ module Builderator
|
|
249
258
|
@name = options.fetch(:name, self.class.name)
|
250
259
|
@collection = options[:collection]
|
251
260
|
end
|
252
|
-
|
253
|
-
def compile
|
254
|
-
@block.call(self) if @block
|
255
|
-
self
|
256
|
-
end
|
257
261
|
end
|
258
262
|
|
259
263
|
##
|
@@ -291,12 +295,13 @@ module Builderator
|
|
291
295
|
end
|
292
296
|
|
293
297
|
## Get namespace instances
|
294
|
-
def fetch(instance_name, &block)
|
295
|
-
self.class.namespace_class.new(
|
298
|
+
def fetch(instance_name, **options, &block)
|
299
|
+
nodes[instance_name] ||= self.class.namespace_class.new(
|
296
300
|
attributes[instance_name],
|
297
301
|
:collection => self,
|
298
302
|
:name => instance_name,
|
299
|
-
:parent => self,
|
303
|
+
:parent => self,
|
304
|
+
:extends => options[:extends], &block)
|
300
305
|
end
|
301
306
|
alias_method :[], :fetch
|
302
307
|
end
|
@@ -39,7 +39,7 @@ module Builderator
|
|
39
39
|
@type = options.fetch(:type, :code)
|
40
40
|
@source = options.fetch(:source, nil)
|
41
41
|
|
42
|
-
super(attributes, &block)
|
42
|
+
super(attributes, options, &block)
|
43
43
|
end
|
44
44
|
|
45
45
|
def compile
|
@@ -48,15 +48,19 @@ module Builderator
|
|
48
48
|
case @type
|
49
49
|
when :file
|
50
50
|
instance_eval(IO.read(source), source, 0)
|
51
|
+
super(false)
|
52
|
+
|
51
53
|
when :json
|
52
54
|
update = Rash.coerce(JSON.parse(IO.read(source)))
|
53
55
|
|
54
56
|
unless @attributes == update
|
55
|
-
|
57
|
+
dirty(true)
|
56
58
|
@attributes = update
|
57
59
|
end
|
58
60
|
else
|
59
61
|
instance_eval(&@block) if @block
|
62
|
+
super(false)
|
63
|
+
|
60
64
|
end
|
61
65
|
|
62
66
|
## Overlay policies
|
@@ -71,7 +75,7 @@ module Builderator
|
|
71
75
|
end
|
72
76
|
|
73
77
|
policies[name].compile
|
74
|
-
|
78
|
+
dirty(policies[name].dirty)
|
75
79
|
end
|
76
80
|
|
77
81
|
self
|
@@ -273,6 +277,7 @@ module Builderator
|
|
273
277
|
|
274
278
|
attribute :git
|
275
279
|
attribute :github
|
280
|
+
attribute :remote
|
276
281
|
attribute :branch
|
277
282
|
attribute :tag
|
278
283
|
attribute :ref
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Builderator
|
2
|
+
module Config
|
3
|
+
##
|
4
|
+
# Extend Array with context about how its values should be merged with other
|
5
|
+
# configuration layers. Possible modes are:
|
6
|
+
#
|
7
|
+
# * 'override' - Do not merge. Replace the other node's elements
|
8
|
+
# * 'union' - Perform a set-union on the elements of this and the other node
|
9
|
+
##
|
10
|
+
class List < Array
|
11
|
+
class << self
|
12
|
+
def coerce(somehting, options = {})
|
13
|
+
return somehting if somehting.is_a?(self)
|
14
|
+
return new(options).push(*somehting) if somehting.is_a?(Array)
|
15
|
+
|
16
|
+
## `somehting` is not a valid input. Just give back an instance.
|
17
|
+
new([], options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :mode
|
22
|
+
|
23
|
+
def initialize(from = nil, **options)
|
24
|
+
@mode = options.fetch(:mode, :union)
|
25
|
+
|
26
|
+
merge!(from) unless from.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
def clone
|
30
|
+
self.class.new(self, :mode => mode)
|
31
|
+
end
|
32
|
+
|
33
|
+
def set(*elements)
|
34
|
+
clear
|
35
|
+
push(*elements)
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Combine elements with `other` according to `other`'s `mode`
|
40
|
+
##
|
41
|
+
def merge!(other)
|
42
|
+
other = self.class.coerce(other)
|
43
|
+
|
44
|
+
case other.mode
|
45
|
+
when :override
|
46
|
+
return false if self == other
|
47
|
+
set(*other)
|
48
|
+
|
49
|
+
when :union
|
50
|
+
merged = self | other
|
51
|
+
return false if merged == self
|
52
|
+
|
53
|
+
set(*merged)
|
54
|
+
|
55
|
+
else
|
56
|
+
fail "Invalid List mode #{other.mode}!"
|
57
|
+
end
|
58
|
+
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative './list'
|
2
|
+
|
1
3
|
module Builderator
|
2
4
|
module Config
|
3
5
|
##
|
@@ -26,6 +28,10 @@ module Builderator
|
|
26
28
|
merge!(from) ## Clone a Rash or coerce a Hash to a new Rash
|
27
29
|
end
|
28
30
|
|
31
|
+
def clone
|
32
|
+
self.class.new(self, sealed)
|
33
|
+
end
|
34
|
+
|
29
35
|
def seal(action = true)
|
30
36
|
@sealed = action
|
31
37
|
each_value { |v| v.seal(action) if v.is_a?(self.class) }
|
@@ -35,7 +41,9 @@ module Builderator
|
|
35
41
|
seal(false)
|
36
42
|
end
|
37
43
|
|
38
|
-
|
44
|
+
def has?(key, klass = BasicObject)
|
45
|
+
include?(key) && fetch(key).is_a?(klass)
|
46
|
+
end
|
39
47
|
|
40
48
|
## Symbolize keys
|
41
49
|
[:include?, :[], :fetch, :[]=, :store].each do |m|
|
@@ -56,24 +64,21 @@ module Builderator
|
|
56
64
|
next if self[k] == v
|
57
65
|
|
58
66
|
## Merge Arrays
|
59
|
-
if
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
next self[k] |= v
|
67
|
+
if v.is_a?(Array)
|
68
|
+
self[k] = has?(k) ? Config::List.coerce(self[k]) : Config::List.new
|
69
|
+
dirty = self[k].merge!(v) || dirty
|
70
|
+
next
|
64
71
|
end
|
65
72
|
|
66
73
|
## Overwrite non-Hash values
|
67
74
|
unless v.is_a?(Hash)
|
68
|
-
dirty
|
75
|
+
dirty = true
|
69
76
|
next self[k] = v
|
70
77
|
end
|
71
78
|
|
72
|
-
## Replace `self[k]` with a new Rash unless it already is one
|
73
|
-
self[k] = self.class.new unless fetch(k, nil).is_a?(self.class)
|
74
|
-
|
75
79
|
## Merge recursivly coerces `v` to a Rash
|
76
|
-
|
80
|
+
self[k] = self.class.coerce(self[k])
|
81
|
+
dirty = self[k].merge!(v) || dirty
|
77
82
|
end
|
78
83
|
|
79
84
|
dirty
|
@@ -53,16 +53,20 @@ module Builderator
|
|
53
53
|
|
54
54
|
no_commands do
|
55
55
|
def _fetch_git(path, params)
|
56
|
-
|
56
|
+
## Ensure that there isn't already something there
|
57
|
+
unless path.join('.git').exist?
|
58
|
+
remove_dir path
|
59
|
+
empty_directory path
|
60
|
+
end
|
57
61
|
|
58
62
|
inside path do
|
59
63
|
## Initialize new repository
|
60
64
|
unless path.join('.git').exist?
|
61
65
|
run 'git init'
|
62
|
-
run "git remote add origin #{ params.git }"
|
66
|
+
run "git remote add #{ params.fetch(:remote, 'origin') } #{ params.git }"
|
63
67
|
end
|
64
68
|
|
65
|
-
run
|
69
|
+
run "git fetch #{ params.fetch(:remote, 'origin') } --tags --prune"
|
66
70
|
|
67
71
|
## Checkout reference
|
68
72
|
if params.has?(:tag) then run "git checkout #{ params.tag }"
|
@@ -71,7 +75,7 @@ module Builderator
|
|
71
75
|
run "git checkout #{ params.fetch(:branch, 'master') }"
|
72
76
|
|
73
77
|
## Only pull if a tracking branch is checked out
|
74
|
-
run
|
78
|
+
run "git pull #{ params.fetch(:remote, 'origin') } #{ params.fetch(:branch, 'master') }"
|
75
79
|
end
|
76
80
|
|
77
81
|
## Apply relative subdirectory
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: builderator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.rc.
|
4
|
+
version: 1.0.0.pre.rc.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Manero
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -183,6 +183,7 @@ files:
|
|
183
183
|
- lib/builderator/config/attributes.rb
|
184
184
|
- lib/builderator/config/defaults.rb
|
185
185
|
- lib/builderator/config/file.rb
|
186
|
+
- lib/builderator/config/list.rb
|
186
187
|
- lib/builderator/config/rash.rb
|
187
188
|
- lib/builderator/control/cleaner.rb
|
188
189
|
- lib/builderator/control/cookbook.rb
|
@@ -256,7 +257,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
256
257
|
version: 1.3.1
|
257
258
|
requirements: []
|
258
259
|
rubyforge_project:
|
259
|
-
rubygems_version: 2.4.5
|
260
|
+
rubygems_version: 2.4.5.1
|
260
261
|
signing_key:
|
261
262
|
specification_version: 4
|
262
263
|
summary: Tools to make CI Packer builds awesome
|