coral_core 0.2.23 → 0.2.24

Sign up to get free protection for your applications and to get access to all the features.
@@ -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