nucleon 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/Gemfile +4 -8
  2. data/Gemfile.lock +0 -28
  3. data/README.rdoc +13 -5
  4. data/Rakefile +9 -1
  5. data/VERSION +1 -1
  6. data/bin/nucleon +55 -0
  7. data/lib/core/codes.rb +107 -0
  8. data/lib/core/config/collection.rb +57 -0
  9. data/lib/core/config/options.rb +70 -0
  10. data/lib/core/config.rb +342 -0
  11. data/lib/core/core.rb +54 -0
  12. data/lib/core/errors.rb +84 -0
  13. data/lib/core/facade.rb +283 -0
  14. data/lib/core/gems.rb +80 -0
  15. data/lib/core/manager.rb +594 -0
  16. data/lib/core/mixin/action/commit.rb +58 -0
  17. data/lib/core/mixin/action/project.rb +53 -0
  18. data/lib/core/mixin/action/push.rb +52 -0
  19. data/lib/core/mixin/config/collection.rb +53 -0
  20. data/lib/core/mixin/config/options.rb +39 -0
  21. data/lib/core/mixin/macro/object_interface.rb +361 -0
  22. data/lib/core/mixin/macro/plugin_interface.rb +380 -0
  23. data/lib/core/mixin/settings.rb +46 -0
  24. data/lib/core/mixin/sub_config.rb +148 -0
  25. data/lib/core/mod/hash.rb +29 -0
  26. data/lib/core/plugin/action.rb +371 -0
  27. data/lib/core/plugin/base.rb +313 -0
  28. data/lib/core/plugin/command.rb +98 -0
  29. data/lib/core/plugin/event.rb +53 -0
  30. data/lib/core/plugin/extension.rb +12 -0
  31. data/lib/core/plugin/project.rb +890 -0
  32. data/lib/core/plugin/template.rb +80 -0
  33. data/lib/core/plugin/translator.rb +38 -0
  34. data/lib/core/util/cli.rb +353 -0
  35. data/lib/core/util/console.rb +237 -0
  36. data/lib/core/util/data.rb +404 -0
  37. data/lib/core/util/disk.rb +114 -0
  38. data/lib/core/util/git.rb +43 -0
  39. data/lib/core/util/liquid.rb +17 -0
  40. data/lib/core/util/logger.rb +147 -0
  41. data/lib/core/util/package.rb +93 -0
  42. data/lib/core/util/shell.rb +239 -0
  43. data/lib/nucleon/action/add.rb +69 -0
  44. data/lib/nucleon/action/create.rb +52 -0
  45. data/lib/nucleon/action/extract.rb +49 -0
  46. data/lib/nucleon/action/remove.rb +51 -0
  47. data/lib/nucleon/action/save.rb +53 -0
  48. data/lib/nucleon/action/update.rb +37 -0
  49. data/lib/nucleon/command/bash.rb +146 -0
  50. data/lib/nucleon/event/regex.rb +52 -0
  51. data/lib/nucleon/project/git.rb +465 -0
  52. data/lib/nucleon/project/github.rb +108 -0
  53. data/lib/nucleon/template/json.rb +16 -0
  54. data/lib/nucleon/template/wrapper.rb +16 -0
  55. data/lib/nucleon/template/yaml.rb +16 -0
  56. data/lib/nucleon/translator/json.rb +27 -0
  57. data/lib/nucleon/translator/yaml.rb +27 -0
  58. data/lib/nucleon.rb +18 -15
  59. data/locales/en.yml +3 -132
  60. data/nucleon.gemspec +66 -27
  61. data/spec/core/util/console_spec.rb +489 -0
  62. metadata +109 -96
@@ -0,0 +1,404 @@
1
+
2
+ module Nucleon
3
+ module Util
4
+ class Data
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Type checking
8
+
9
+ def self.undef?(value)
10
+ if value.nil? ||
11
+ (value.is_a?(Symbol) && value == :undef || value == :undefined) ||
12
+ (value.is_a?(String) && value.match(/^\s*(undef|UNDEF|Undef|nil|NIL|Nil)\s*$/))
13
+ return true
14
+ end
15
+ return false
16
+ end
17
+
18
+ #---
19
+
20
+ def self.true?(value)
21
+ if value == true ||
22
+ (value.is_a?(String) && value.match(/^\s*(true|TRUE|True)\s*$/))
23
+ return true
24
+ end
25
+ return false
26
+ end
27
+
28
+ #---
29
+
30
+ def self.false?(value)
31
+ if value == false ||
32
+ (value.is_a?(String) && value.match(/^\s*(false|FALSE|False)\s*$/))
33
+ return true
34
+ end
35
+ return false
36
+ end
37
+
38
+ #---
39
+
40
+ def self.empty?(value)
41
+ if undef?(value) || false?(value) || (value.respond_to?('empty?') && value.empty?)
42
+ return true
43
+ end
44
+ return false
45
+ end
46
+
47
+ #---
48
+
49
+ def self.exists?(data, keys, check_empty = false)
50
+ if keys.is_a?(String) || keys.is_a?(Symbol)
51
+ keys = [ keys ]
52
+ end
53
+ key = keys.shift.to_sym
54
+
55
+ if data.has_key?(key)
56
+ value = data[key]
57
+
58
+ if keys.empty?
59
+ return false if check_empty && empty?(value)
60
+ return true
61
+ else
62
+ return exists?(data[key], keys)
63
+ end
64
+ end
65
+ return false
66
+ end
67
+
68
+ #-----------------------------------------------------------------------------
69
+ # Translation
70
+
71
+ def self.symbol_map(data)
72
+ results = {}
73
+ return data unless data
74
+
75
+ case data
76
+ when Hash
77
+ data.each do |key, value|
78
+ results[key.to_sym] = symbol_map(value)
79
+ end
80
+ else
81
+ results = data
82
+ end
83
+ return results
84
+ end
85
+
86
+ #---
87
+
88
+ def self.string_map(data)
89
+ results = {}
90
+ return data unless data
91
+
92
+ case data
93
+ when Hash
94
+ data.each do |key, value|
95
+ results[key.to_s] = string_map(value)
96
+ end
97
+ else
98
+ results = data
99
+ end
100
+ return results
101
+ end
102
+
103
+ #---
104
+
105
+ def self.parse_json(json_text)
106
+ return MultiJson.load(json_text)
107
+ end
108
+
109
+ #---
110
+
111
+ def self.to_json(data, pretty = true)
112
+ return MultiJson.dump(data, :pretty => pretty)
113
+ end
114
+
115
+ #---
116
+
117
+ def self.parse_yaml(yaml_text)
118
+ return YAML.load(yaml_text)
119
+ end
120
+
121
+ #---
122
+
123
+ def self.to_yaml(data)
124
+ return YAML.dump(data)
125
+ end
126
+
127
+ #---
128
+
129
+ def self.value(value)
130
+ case value
131
+ when String
132
+ if undef?(value)
133
+ value = nil
134
+ elsif true?(value)
135
+ value = true
136
+ elsif false?(value)
137
+ value = false
138
+ end
139
+
140
+ when Array
141
+ value.each_with_index do |item, index|
142
+ value[index] = value(item)
143
+ end
144
+
145
+ when Hash
146
+ value.each do |key, data|
147
+ value[key] = value(data)
148
+ end
149
+ end
150
+ return value
151
+ end
152
+
153
+ #---
154
+
155
+ def self.filter(data, method = false)
156
+ if method && method.is_a?(Symbol) &&
157
+ [ :array, :hash, :string, :symbol, :test ].include?(method.to_sym)
158
+ return send(method, data)
159
+ end
160
+ return data
161
+ end
162
+
163
+ #---
164
+
165
+ def self.array(data, default = [], split_string = false)
166
+ result = default
167
+ if data
168
+ case data
169
+ when Array
170
+ result = data
171
+ when String
172
+ result = [ ( split_string ? data.split(/\s*,\s*/) : data ) ]
173
+ else
174
+ result = [ data ]
175
+ end
176
+ end
177
+ return result
178
+ end
179
+
180
+ #---
181
+
182
+ def self.hash(data, default = {})
183
+ result = default
184
+ if data
185
+ case data
186
+ when Hash
187
+ result = data
188
+ else
189
+ result = {}
190
+ end
191
+ end
192
+ return result
193
+ end
194
+
195
+ #---
196
+
197
+ def self.string(data, default = '')
198
+ result = default
199
+ if data
200
+ case data
201
+ when String
202
+ result = data
203
+ else
204
+ result = data.to_s
205
+ end
206
+ end
207
+ return result
208
+ end
209
+
210
+ #---
211
+
212
+ def self.symbol(data, default = :undefined)
213
+ result = default
214
+ if data
215
+ case data
216
+ when Symbol
217
+ result = data
218
+ when String
219
+ result = data.to_sym
220
+ else
221
+ result = data.class.to_sym
222
+ end
223
+ end
224
+ return result
225
+ end
226
+
227
+ #---
228
+
229
+ def self.test(data)
230
+ return false if Util::Data.empty?(data)
231
+ return true
232
+ end
233
+
234
+ #-----------------------------------------------------------------------------
235
+ # Operations
236
+
237
+ def self.clean(data)
238
+ data.keys.each do |key|
239
+ data.delete(key) if data[key].nil?
240
+ end
241
+ data
242
+ end
243
+
244
+ #---
245
+
246
+ def self.merge(data, force = true)
247
+ value = data
248
+
249
+ # Special case because this method is called from within Config.new so we
250
+ # can not use Config.ensure, as that would cause an infinite loop.
251
+ force = force.is_a?(Nucleon::Config) ? force.get(:force, true) : force
252
+
253
+ if data.is_a?(Array)
254
+ value = undef?(data[0]) ? nil : data.shift.clone
255
+
256
+ data.each do |item|
257
+ item = undef?(item) ? nil : item.clone
258
+
259
+ case value
260
+ when Hash
261
+ begin
262
+ require 'deep_merge'
263
+ value = force ? value.deep_merge!(item) : value.deep_merge(item)
264
+
265
+ rescue LoadError
266
+ if item.is_a?(Hash) # Non recursive top level by default.
267
+ value = value.merge(item)
268
+ elsif force
269
+ value = item
270
+ end
271
+ end
272
+ when Array
273
+ if item.is_a?(Array)
274
+ value = value.concat(item).uniq
275
+ elsif force
276
+ value = item
277
+ end
278
+
279
+ else
280
+ value = item if force || item.is_a?(String) || item.is_a?(Symbol)
281
+ end
282
+ end
283
+ end
284
+
285
+ return value
286
+ end
287
+
288
+ #---
289
+
290
+ def self.interpolate(value, scope, options = {})
291
+
292
+ pattern = ( options.has_key?(:pattern) ? options[:pattern] : '\$(\{)?([a-zA-Z0-9\_\-]+)(\})?' )
293
+ group = ( options.has_key?(:var_group) ? options[:var_group] : 2 )
294
+ flags = ( options.has_key?(:flags) ? options[:flags] : '' )
295
+
296
+ if scope.is_a?(Hash)
297
+ regexp = Regexp.new(pattern, flags.split(''))
298
+
299
+ replace = lambda do |item|
300
+ matches = item.match(regexp)
301
+ result = nil
302
+
303
+ #dbg(item, 'item')
304
+ #dbg(matches, 'matches')
305
+
306
+ unless matches.nil?
307
+ replacement = scope.search(matches[group], options)
308
+ result = item.gsub(matches[0], replacement) unless replacement.nil?
309
+ end
310
+ return result
311
+ end
312
+
313
+ case value
314
+ when String
315
+ #dbg(value, 'interpolate (string) -> init')
316
+ while (temp = replace.call(value))
317
+ #dbg(temp, 'interpolate (string) -> replacement')
318
+ value = temp
319
+ end
320
+
321
+ when Hash
322
+ #dbg(value, 'interpolate (hash) -> init')
323
+ value.each do |key, data|
324
+ #dbg(data, "interpolate (#{key}) -> data")
325
+ value[key] = interpolate(data, scope, options)
326
+ end
327
+ end
328
+ end
329
+ #dbg(value, 'interpolate -> result')
330
+ return value
331
+ end
332
+
333
+ #---
334
+
335
+ def self.rm_keys(data, keys)
336
+ keys = [ keys ] unless keys.is_a?(Array)
337
+ keys.each do |key|
338
+ data.delete(key)
339
+ end
340
+ data
341
+ end
342
+
343
+ #---
344
+
345
+ def self.subset(data, keys)
346
+ keys = [ keys ] unless keys.is_a?(Array)
347
+ new_data = {}
348
+ keys.each do |key|
349
+ new_data[key] = data[key] if data.has_key?(key)
350
+ end
351
+ new_data
352
+ end
353
+
354
+ #-----------------------------------------------------------------------------
355
+ # Utilities
356
+
357
+ def self.prefix(prefix, data)
358
+ result = nil
359
+
360
+ unless prefix.is_a?(String) && ! empty?(prefix)
361
+ prefix = ''
362
+ end
363
+
364
+ case data
365
+ when String, Symbol
366
+ result = ( prefix.empty? ? data.to_s : prefix + '_' + data.to_s )
367
+
368
+ when Array
369
+ result = []
370
+ data.each do |value|
371
+ result << prefix(prefix, value)
372
+ end
373
+
374
+ when Hash
375
+ result = {}
376
+ data.each do |key, value|
377
+ result[prefix(prefix, key)] = value
378
+ end
379
+ end
380
+ return result
381
+ end
382
+
383
+ #---
384
+
385
+ def self.ensure(test, success_value = nil, failure_value = nil)
386
+ success_value = (success_value ? success_value : test)
387
+ failure_value = (failure_value ? failure_value : nil)
388
+
389
+ if empty?(test)
390
+ value = failure_value
391
+ else
392
+ value = success_value
393
+ end
394
+ return value
395
+ end
396
+
397
+ #---
398
+
399
+ def self.ensure_value(value, failure_value = nil)
400
+ return self.ensure(value, nil, failure_value)
401
+ end
402
+ end
403
+ end
404
+ end
@@ -0,0 +1,114 @@
1
+
2
+ module Nucleon
3
+ module Util
4
+ class Disk
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Properties
8
+
9
+ @@files = {}
10
+
11
+ @@separator = false
12
+ @@description = ''
13
+
14
+ #-----------------------------------------------------------------------------
15
+ # Utilities
16
+
17
+ def self.exists?(file)
18
+ return ::File.exists?(::File.expand_path(file))
19
+ end
20
+
21
+ #---
22
+
23
+ def self.filename(file_name)
24
+ return ( file_name.is_a?(Array) ? file_name.join(::File::SEPARATOR) : file_name.to_s )
25
+ end
26
+
27
+ #---
28
+
29
+ def self.open(file_name, options = {}, reset = false)
30
+ mode = options[:mode].to_s
31
+
32
+ @@separator = ( options[:separator] ? options[:separator] : false )
33
+ @@description = ( options[:description] ? options[:description] : '' )
34
+
35
+ if @@files.has_key?(file_name) && ! reset
36
+ reset = true if ! mode.empty? && mode != @@files[file_name][:mode]
37
+ end
38
+
39
+ if ! @@files.has_key?(file_name) || ! @@files[file_name][:file] || reset
40
+ @@files[file_name][:file].close if @@files[file_name] && @@files[file_name][:file]
41
+ unless mode.empty? || ( mode == 'r' && ! ::File.exists?(file_name) )
42
+ @@files[file_name] = {
43
+ :file => ::File.open(file_name, mode),
44
+ :mode => mode,
45
+ }
46
+ end
47
+ end
48
+ return nil unless @@files[file_name]
49
+ return @@files[file_name][:file]
50
+ end
51
+
52
+ #---
53
+
54
+ def self.read(file_name, options = {})
55
+ options[:mode] = ( options[:mode] ? options[:mode] : 'r' )
56
+ file = open(file_name, options)
57
+
58
+ if file
59
+ file.pos = 0 if options[:mode] == 'r'
60
+ return file.read
61
+ end
62
+ return nil
63
+ end
64
+
65
+ #---
66
+
67
+ def self.write(file_name, data, options = {})
68
+ options[:mode] = ( options[:mode] ? options[:mode] : 'w' )
69
+ file = open(file_name, options)
70
+
71
+ if file
72
+ file.pos = 0 if options[:mode] == 'w'
73
+ success = file.write(data)
74
+ file.flush
75
+ return success
76
+ end
77
+ return nil
78
+ end
79
+
80
+ #---
81
+
82
+ def self.delete(file_path)
83
+ return ::File.delete(file_path)
84
+ end
85
+
86
+ #---
87
+
88
+ def self.log(data, options = {})
89
+ reset = ( options[:file_name] || options[:mode] )
90
+ file = open(( options[:file_name] ? options[:file_name] : 'log.txt' ), options, reset)
91
+ if file
92
+ file.write("--------------------------------------\n") if @@separator
93
+ file.write("#{@@description}\n") if @@description
94
+ file.write("#{data}\n")
95
+ end
96
+ end
97
+
98
+ #---
99
+
100
+ def self.close(file_names = [])
101
+ file_names = @@files.keys unless file_names && ! file_names.empty?
102
+
103
+ unless file_names.is_a?(Array)
104
+ file_names = [ file_names ]
105
+ end
106
+
107
+ file_names.each do |file_name|
108
+ @@files[file_name][:file].close if @@files[file_name] && @@files[file_name][:file]
109
+ @@files.delete(file_name)
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,43 @@
1
+
2
+ module Nucleon
3
+ module Util
4
+ class Git < ::Grit::Repo
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Constructor / Destructor
8
+
9
+ def initialize(path, options = {})
10
+ epath = File.expand_path(path)
11
+ git_dir = File.join(epath, '.git')
12
+
13
+ @bare = (options[:is_bare] ? true : false)
14
+
15
+ Grit.debug = true if Nucleon.log_level == :debug
16
+
17
+ if File.exist?(git_dir)
18
+ self.working_dir = epath
19
+
20
+ if File.directory?(git_dir)
21
+ self.path = git_dir
22
+ else
23
+ git_dir = Util::Disk.read(git_dir)
24
+ unless git_dir.nil?
25
+ git_dir = git_dir.gsub(/^gitdir\:\s*/, '').strip
26
+ self.path = git_dir if File.directory?(git_dir)
27
+ end
28
+ end
29
+
30
+ elsif File.directory?(epath) && (options[:is_bare] || (epath =~ /\.git$/ && File.exist?(File.join(epath, 'HEAD'))))
31
+ self.path = epath
32
+ @bare = true
33
+
34
+ else
35
+ self.path = git_dir
36
+ end
37
+
38
+ self.git = ::Grit::Git.new(self.path)
39
+ self.git.work_tree = epath
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module Nucleon
3
+ module Util
4
+ class Liquid
5
+
6
+ def initialize(&code)
7
+ @code = code
8
+ end
9
+
10
+ #---
11
+
12
+ def method_missing(method, *args, &block)
13
+ @code.call(method, args, block)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,147 @@
1
+
2
+ module Nucleon
3
+ module Util
4
+ class Logger
5
+
6
+ #-----------------------------------------------------------------------------
7
+ # Properties
8
+
9
+ @@level = nil
10
+ @@loggers = {}
11
+
12
+ #---
13
+
14
+ def self.level
15
+ @@level
16
+ end
17
+
18
+ def self.level=level
19
+ @@level = set_level(level)
20
+ end
21
+
22
+ #---
23
+
24
+ def self.loggers
25
+ @@loggers
26
+ end
27
+
28
+ #---
29
+
30
+ def self.set_levels(*levels)
31
+ levels = levels.flatten.collect do |level|
32
+ level.to_s.upcase
33
+ end
34
+ Log4r::Configurator.custom_levels(*levels)
35
+ end
36
+
37
+ #---
38
+
39
+ def self.set_level(level, logger = nil)
40
+ level_sym = level.to_s.downcase.to_sym
41
+ level_id = level.to_s.upcase
42
+
43
+ if logger.nil?
44
+ loggers.each do |name, registered_logger|
45
+ @@loggers[name].level = Log4r.const_get(level_id)
46
+ end
47
+ else
48
+ if logger.levels.include?(level_id)
49
+ logger.level = Log4r.const_get(level_id)
50
+ end
51
+ end
52
+ level_sym
53
+ end
54
+
55
+ #---
56
+
57
+ def self.add_logger(name, logger)
58
+ logger.outputters = Log4r::StdoutOutputter.new('console')
59
+
60
+ level = Logger.level.nil? ? 'off' : Logger.level
61
+ set_level(level, logger)
62
+
63
+ @@loggers[name] = logger
64
+ end
65
+
66
+ # Initialize log levels
67
+
68
+ set_levels :debug, :info, :warn, :error, :hook
69
+
70
+ if ENV['NUCLEON_LOG']
71
+ Logger.level = ENV['NUCLEON_LOG']
72
+ end
73
+
74
+ #-----------------------------------------------------------------------------
75
+ # Constructor
76
+
77
+ def initialize(options = {})
78
+ if options.is_a?(String)
79
+ options = { :logger => options }
80
+ end
81
+ config = Config.ensure(options)
82
+
83
+ @resource = config.get(:resource, '')
84
+
85
+ if config.get(:logger, false)
86
+ self.logger = config[:logger]
87
+ else
88
+ self.logger = Log4r::Logger.new(@resource)
89
+ end
90
+ end
91
+
92
+ #---
93
+
94
+ def inspect
95
+ "#<#{self.class}: #{@resource}>"
96
+ end
97
+
98
+ #-----------------------------------------------------------------------------
99
+ # Accessors / Modifiers
100
+
101
+ attr_reader :resource
102
+
103
+ #---
104
+
105
+ def logger=logger
106
+ if logger.is_a?(String)
107
+ @resource = logger
108
+ @logger = Log4r::Logger.new(logger)
109
+ else
110
+ @logger = logger
111
+ end
112
+ self.class.add_logger(@resource, @logger)
113
+ end
114
+
115
+ #-----------------------------------------------------------------------------
116
+ # Log statements
117
+
118
+ def debug(message)
119
+ @logger.debug(message)
120
+ end
121
+
122
+ #---
123
+
124
+ def info(message)
125
+ @logger.info(message)
126
+ end
127
+
128
+ #---
129
+
130
+ def warn(message)
131
+ @logger.warn(message)
132
+ end
133
+
134
+ #---
135
+
136
+ def error(message)
137
+ @logger.error(message)
138
+ end
139
+
140
+ #---
141
+
142
+ def hook(message)
143
+ @logger.hook(message)
144
+ end
145
+ end
146
+ end
147
+ end