coral_core 0.2.23 → 0.2.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,226 @@
1
+
2
+ require 'json'
3
+
4
+ module Coral
5
+ class Memory < Repository
6
+
7
+ #-----------------------------------------------------------------------------
8
+ # Constructor / Destructor
9
+
10
+ def initialize(options = {})
11
+ config = Config.ensure(options)
12
+
13
+ super(config)
14
+
15
+ @absolute_config_file = ''
16
+ @config_file = ''
17
+
18
+ @properties = config.get(:properties, {})
19
+
20
+ @autoload = config.get(:autoload, true)
21
+ @autosave = config.get(:autosave, true)
22
+ @autocommit = config.get(:autocommit, true)
23
+ @commit_message = config.get(:commit_message, 'Saving state')
24
+
25
+ self.config_file = config.get(:config_file, '')
26
+ end
27
+
28
+ #---
29
+
30
+ def self.finalize(file_name)
31
+ proc do
32
+ Coral::Util::Disk.close(file_name)
33
+ end
34
+ end
35
+
36
+ #-----------------------------------------------------------------------------
37
+ # Property accessors / modifiers
38
+
39
+ attr_accessor :autoload, :autosave, :autocommit, :commit_message
40
+ attr_reader :config_file, :absolute_config_file
41
+
42
+ #---
43
+
44
+ def set_absolute_config_file
45
+ if @directory.empty? || @config_file.empty?
46
+ @absolute_config_file = ''
47
+ else
48
+ @absolute_config_file = ( ! @submodule.empty? ? File.join(@directory, @submodule, @config_file) : File.join(@directory, @config_file) )
49
+ ObjectSpace.define_finalizer(self, self.class.finalize(@absolute_config_file))
50
+ end
51
+ return self
52
+ end
53
+
54
+ #---
55
+
56
+ def config_file=file
57
+ unless Util::Data.empty?(file)
58
+ @config_file = ( file.is_a?(Array) ? file.join(File::SEPARATOR) : string(file) )
59
+ end
60
+
61
+ set_absolute_config_file
62
+ load if @autoload
63
+ end
64
+
65
+ #-----------------------------------------------------------------------------
66
+
67
+ def get(key, default = '', format = false)
68
+ value = default
69
+ key = string(key)
70
+
71
+ if ! @properties || ! @properties.is_a?(Hash)
72
+ @properties = {}
73
+ end
74
+ if @properties.has_key?(key)
75
+ value = @properties[key]
76
+ end
77
+ return filter(value, format)
78
+ end
79
+
80
+ #---
81
+
82
+ def set(key, value = '')
83
+ key = string(key)
84
+
85
+ if ! @properties || ! @properties.is_a?(Hash)
86
+ @properties = {}
87
+ end
88
+ @properties[key] = value
89
+ save if @autosave
90
+ return self
91
+ end
92
+
93
+ #---
94
+
95
+ def delete(key)
96
+ key = string(key)
97
+
98
+ if ! @properties || ! @properties.is_a?(Hash)
99
+ @properties = {}
100
+ end
101
+ @properties.delete(key)
102
+ save if @autosave
103
+ return self
104
+ end
105
+
106
+ #---
107
+
108
+ def get_group(group, name = '', key = nil, default = {}, format = false)
109
+ info = get(group, {})
110
+ value = info
111
+
112
+ if name
113
+ name = string(name)
114
+ if info.has_key?(name) && info[name].is_a?(Hash)
115
+ if key && ! key.empty?
116
+ key = string(key)
117
+ if info[name].has_key?(key)
118
+ value = info[name][key]
119
+ else
120
+ value = default
121
+ end
122
+ else
123
+ value = info[name]
124
+ end
125
+ else
126
+ value = default
127
+ end
128
+ end
129
+ return filter(value, format)
130
+ end
131
+
132
+ #---
133
+
134
+ def set_group(group, name, key = nil, value = {})
135
+ group = string(group)
136
+ name = string(name)
137
+
138
+ if ! @properties || ! @properties.is_a?(Hash)
139
+ @properties = {}
140
+ end
141
+ if ! @properties[group] || ! @properties[group].is_a?(Hash)
142
+ @properties[group] = {}
143
+ end
144
+
145
+ if key && ! key.empty?
146
+ key = string(key)
147
+ if ! @properties[group][name] || ! @properties[group][name].is_a?(Hash)
148
+ @properties[group][name] = {}
149
+ end
150
+ @properties[group][name][key] = value
151
+
152
+ else
153
+ @properties[group][name] = value
154
+ end
155
+ save if @autosave
156
+ return self
157
+ end
158
+
159
+ #---
160
+
161
+ def delete_group(group, name, key = nil)
162
+ group = string(group)
163
+ name = string(name)
164
+
165
+ if ! @properties || ! @properties.is_a?(Hash)
166
+ @properties = {}
167
+ end
168
+ if ! @properties[group] || ! @properties[group].is_a?(Hash)
169
+ @properties[group] = {}
170
+ end
171
+
172
+ if key && ! key.empty?
173
+ key = string(key)
174
+ if @properties[group][name] && @properties[group][name].is_a?(Hash)
175
+ @properties[group][name].delete(key)
176
+ end
177
+ else
178
+ @properties[group].delete(name)
179
+ end
180
+ save if @autosave
181
+ return self
182
+ end
183
+
184
+ #-----------------------------------------------------------------------------
185
+ # Import / Export
186
+
187
+ def export
188
+ return @properties
189
+ end
190
+
191
+ #-----------------------------------------------------------------------------
192
+ # Configuration loading / saving
193
+
194
+ def load
195
+ if can_persist?
196
+ config = Coral::Util::Disk.read(@absolute_config_file)
197
+ if config && ! config.empty?
198
+ @properties = JSON.parse(config)
199
+ end
200
+ end
201
+ return self
202
+ end
203
+
204
+ #---
205
+
206
+ def save(options = {})
207
+ if can_persist?
208
+ config = JSON.generate(@properties)
209
+ if config && ! config.empty?
210
+ Coral::Util::Disk.write(@absolute_config_file, config)
211
+ commit(@absolute_config_file, options) if @autocommit
212
+ end
213
+ end
214
+ return self
215
+ end
216
+
217
+ #-----------------------------------------------------------------------------
218
+ # Checks
219
+
220
+ def can_persist?
221
+ success = super
222
+ success = false if success && @absolute_config_file.empty?
223
+ return success
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,164 @@
1
+
2
+ module Coral
3
+ class Repository < Core
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Constructor / Destructor
7
+
8
+ def initialize(options = {})
9
+ config = Config.ensure(options)
10
+
11
+ super(config)
12
+
13
+ @name = config.get(:name, '')
14
+ @directory = config.get(:directory, '')
15
+ @submodule = config.get(:submodule, '')
16
+ @remote_dir = config.get(:remote_dir, '')
17
+
18
+ ensure_git(true)
19
+ end
20
+
21
+ #-----------------------------------------------------------------------------
22
+ # Property accessors / modifiers
23
+
24
+ attr_accessor :name, :remote_dir
25
+ attr_reader :directory, :submodule, :git
26
+
27
+ #---
28
+
29
+ def ensure_git(reset = false)
30
+ if reset || ! @git
31
+ if @directory.empty?
32
+ @git = nil
33
+ else
34
+ directory = @directory
35
+ unless Util::Data.empty?(@submodule)
36
+ directory = File.join(@directory, @submodule)
37
+ end
38
+ @git = Git.open(directory, {
39
+ :log => logger,
40
+ })
41
+ end
42
+ end
43
+ return self
44
+ end
45
+
46
+ #---
47
+
48
+ def set_repository(directory = '', submodule = '')
49
+ @directory = string(directory)
50
+ @submodule = string(submodule)
51
+ ensure_git(true)
52
+ return self
53
+ end
54
+
55
+ #-----------------------------------------------------------------------------
56
+
57
+ def set_remote(name, hosts, options = {})
58
+ config = Config.ensure(options)
59
+
60
+ if can_persist?
61
+ hosts = array(hosts)
62
+
63
+ delete_remote(name)
64
+ return self if hosts.empty?
65
+
66
+ if @remote_dir && ! config.get(:repo, false)
67
+ config[:repo] = @remote_dir
68
+ end
69
+
70
+ git.add_remote(name, Git.url(hosts.shift, config[:repo], options))
71
+
72
+ if ! hosts.empty?
73
+ remote = git.remote(name)
74
+
75
+ config[:add] = true
76
+
77
+ hosts.each do |host|
78
+ git_url = Git.url(host, config[:repo], config.options)
79
+ remote.set_url(git_url, config.options)
80
+ end
81
+ end
82
+ end
83
+ return self
84
+ end
85
+
86
+ #---
87
+
88
+ def delete_remote(name)
89
+ if can_persist?
90
+ remote = git.remote(name)
91
+ if remote && remote.url && ! remote.url.empty?
92
+ remote.remove
93
+ end
94
+ end
95
+ return self
96
+ end
97
+
98
+ #-----------------------------------------------------------------------------
99
+ # Git operations
100
+
101
+ def commit(files = '.', options = {})
102
+ config = Config.ensure(options)
103
+
104
+ if can_persist?
105
+ time = Time.new.strftime("%Y-%m-%d %H:%M:%S")
106
+ user = ENV['USER']
107
+ message = config.get(:message, 'Saving state')
108
+
109
+ config[:author] = config.get(:author, '')
110
+ config[:allow_empty] = config.get(:allow_empty, false)
111
+
112
+ unless user && ! user.empty?
113
+ user = 'UNKNOWN'
114
+ end
115
+
116
+ array(files).each do |file|
117
+ git.add(file) # Get all added and updated files
118
+ git.add(file, { :update => true }) # Get all deleted files
119
+ end
120
+
121
+ git.commit("#{time} by <#{user}> - #{message}", config.options)
122
+ end
123
+ return self
124
+ end
125
+
126
+ #-----------------------------------------------------------------------------
127
+
128
+ def push!(remote = 'origin', options = {})
129
+ config = Config.ensure(options)
130
+
131
+ if can_persist?
132
+ branch = config.get(:branch, 'master')
133
+ tags = config.get(:tags, false)
134
+
135
+ return Coral::Command.new({
136
+ :command => :git,
137
+ :data => { 'git-dir=' => git.repo.to_s },
138
+ :subcommand => {
139
+ :command => :push,
140
+ :flags => ( tags ? :tags : '' ),
141
+ :args => [ remote, branch ]
142
+ }
143
+ }).exec!(config) do |line|
144
+ block_given? ? yield(line) : true
145
+ end
146
+ end
147
+ end
148
+
149
+ #---
150
+
151
+ def push(remote = 'origin', options = {})
152
+ return push!(remote, options)
153
+ end
154
+
155
+ #-----------------------------------------------------------------------------
156
+ # Checks
157
+
158
+ def can_persist?
159
+ ensure_git
160
+ return true if @git
161
+ return false
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,243 @@
1
+
2
+ module Coral
3
+ module Resource
4
+
5
+ #-----------------------------------------------------------------------------
6
+ # Resource groups
7
+
8
+ @@resource_groups = {}
9
+
10
+ #---
11
+
12
+ def self.groups
13
+ return @@resource_groups
14
+ end
15
+
16
+ #---
17
+
18
+ def self.clear_groups
19
+ @@resource_groups = {}
20
+ end
21
+
22
+ #---
23
+
24
+ def self.add_members(group_name, resource_names)
25
+ @@resource_groups[group_name] = [] unless @@resource_groups[group_name].is_a?(Array)
26
+
27
+ unless resource_names.is_a?(Array)
28
+ resource_names = [ resource_names ]
29
+ end
30
+
31
+ resource_names.each do |name|
32
+ unless @@resource_groups[group_name].include?(name)
33
+ @@resource_groups[group_name] << name
34
+ end
35
+ end
36
+ end
37
+
38
+ #-----------------------------------------------------------------------------
39
+ # Resource operations
40
+
41
+ def self.normalize(type_name, resources, options)
42
+ clear_groups
43
+
44
+ config = Config.ensure(options)
45
+ resources = Util::Data.value(resources)
46
+
47
+ #dbg(resources, 'normalize -> init')
48
+
49
+ unless Util::Data.empty?(resources)
50
+ resources.keys.each do |name|
51
+ #dbg(name, 'normalize -> name')
52
+ if ! resources[name] || resources[name].empty? || ! resources[name].is_a?(Hash)
53
+ resources.delete(name)
54
+ else
55
+ normalize = true
56
+
57
+ namevar = namevar(type_name, name)
58
+ if resources[name].has_key?(namevar)
59
+ value = resources[name][namevar]
60
+ if Util::Data.empty?(value)
61
+ #dbg(value, "delete #{name}")
62
+ resources.delete(name)
63
+ normalize = false
64
+
65
+ elsif value.is_a?(Array)
66
+ value.each do |item|
67
+ item_name = "#{name}_#{item}".gsub(/\-/, '_')
68
+
69
+ new_resource = resources[name].clone
70
+ new_resource[namevar] = item
71
+
72
+ resources[item_name] = render(new_resource, config)
73
+ add_members(name, item_name)
74
+ end
75
+ resources.delete(name)
76
+ normalize = false
77
+ end
78
+ end
79
+
80
+ #dbg(resources, 'normalize -> resources')
81
+
82
+ if normalize
83
+ resources[name] = render(resources[name], config)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ return resources
89
+ end
90
+
91
+ #---
92
+
93
+ def self.render(resource, options = {})
94
+ resource = Core.string_map(resource.clone)
95
+ config = Config.ensure(options)
96
+
97
+ resource.keys.each do |name|
98
+ if match = name.match(/^(.+)_template$/)
99
+ target = match.captures[0]
100
+
101
+ #dbg(name, 'name')
102
+ #dbg(target, 'target')
103
+
104
+ config.set(:normalize_template, config.get("normalize_#{target}", true))
105
+ config.set(:interpolate_template, config.get("interpolate_#{target}", true))
106
+
107
+ resource[target] = Template.render(resource[name], resource[target], config)
108
+ resource.delete(name)
109
+ end
110
+ end
111
+
112
+ #dbg(resource, 'render exit')
113
+ return resource
114
+ end
115
+
116
+ #---
117
+
118
+ def self.translate(type_name, resources, options = {})
119
+ config = Config.ensure(options)
120
+ resources = Util::Data.value(resources)
121
+ results = {}
122
+
123
+ #dbg(resources, 'resources -> translate')
124
+
125
+ prefix = config.get(:resource_prefix, '')
126
+
127
+ name_map = {}
128
+ resources.keys.each do |name|
129
+ name_map[name] = true
130
+ end
131
+ config[:resource_names] = name_map
132
+
133
+ resources.each do |name, data|
134
+ #dbg(name, 'name')
135
+ #dbg(data, 'data')
136
+
137
+ resource = resources[name]
138
+ resource['before'] = translate_resource_refs(type_name, data['before'], config) if data.has_key?('before')
139
+ resource['notify'] = translate_resource_refs(type_name, data['notify'], config) if data.has_key?('notify')
140
+ resource['require'] = translate_resource_refs(type_name, data['require'], config) if data.has_key?('require')
141
+ resource['subscribe'] = translate_resource_refs(type_name, data['subscribe'], config) if data.has_key?('subscribe')
142
+
143
+ unless prefix.empty?
144
+ name = "#{prefix}_#{name}"
145
+ end
146
+ results[name] = resource
147
+ end
148
+ return results
149
+ end
150
+
151
+ #---
152
+
153
+ def self.translate_resource_refs(type_name, resource_refs, options = {})
154
+ return :undef if Util::Data.undef?(resource_refs)
155
+
156
+ config = Config.ensure(options)
157
+ resource_names = config.get(:resource_names, {})
158
+ title_prefix = config.get(:title_prefix, '')
159
+
160
+ title_pattern = config.get(:title_pattern, '^\s*([^\[\]]+)\s*$')
161
+ title_group = config.get(:title_var_group, 1)
162
+ title_flags = config.get(:title_flags, '')
163
+ title_regexp = Regexp.new(title_pattern, title_flags.split(''))
164
+
165
+ allow_single = config.get(:allow_single_return, true)
166
+
167
+ type_name = type_name.sub(/^\@?\@/, '')
168
+ values = []
169
+
170
+ case resource_refs
171
+ when String
172
+ if resource_refs.empty?
173
+ return :undef
174
+ else
175
+ resource_refs = resource_refs.split(/\s*,\s*/)
176
+ end
177
+
178
+ when Puppet::Resource
179
+ resource_refs = [ resource_refs ]
180
+ end
181
+
182
+ resource_refs.collect! do |value|
183
+ if value.is_a?(Puppet::Resource) || ! value.match(title_regexp)
184
+ value
185
+
186
+ elsif resource_names.has_key?(value)
187
+ if ! title_prefix.empty?
188
+ "#{title_prefix}_#{value}"
189
+ else
190
+ value
191
+ end
192
+
193
+ elsif groups.has_key?(value) && ! groups[value].empty?
194
+ results = []
195
+ groups[value].each do |resource_name|
196
+ unless title_prefix.empty?
197
+ resource_name = "#{title_prefix}_#{resource_name}"
198
+ end
199
+ results << resource_name
200
+ end
201
+ results
202
+
203
+ else
204
+ nil
205
+ end
206
+ end
207
+
208
+ resource_refs.flatten.each do |ref|
209
+ #dbg(ref, 'reference -> init')
210
+ unless ref.nil?
211
+ unless ref.is_a?(Puppet::Resource)
212
+ ref = ref.match(title_regexp) ? Puppet::Resource.new(type_name, ref) : Puppet::Resource.new(ref)
213
+ end
214
+ #dbg(ref, 'reference -> final')
215
+ values << ref unless ref.nil?
216
+ end
217
+ end
218
+ return values[0] if allow_single && values.length == 1
219
+ return values
220
+ end
221
+
222
+ #-----------------------------------------------------------------------------
223
+ # Utilities
224
+
225
+ def self.type_name(value) # Basically borrowed from Puppet (damn private methods!)
226
+ return :main if value == :main
227
+ return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"
228
+ return value.to_s.split("::").collect { |s| s.capitalize }.join("::")
229
+ end
230
+
231
+ #---
232
+
233
+ def self.namevar(type_name, resource_name) # Basically borrowed from Puppet (damn private methods!)
234
+ resource = Puppet::Resource.new(type_name.sub(/^\@?\@/, ''), resource_name)
235
+
236
+ if resource.builtin_type? and type = resource.resource_type and type.key_attributes.length == 1
237
+ return type.key_attributes.first.to_s
238
+ else
239
+ return 'name'
240
+ end
241
+ end
242
+ end
243
+ end