nucleon 0.1.0 → 0.1.1

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.
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,594 @@
1
+
2
+ module Nucleon
3
+ class Manager
4
+
5
+ include Celluloid
6
+
7
+ #-----------------------------------------------------------------------------
8
+
9
+ @@supervisors = {}
10
+
11
+ #-----------------------------------------------------------------------------
12
+ # Plugin manager interface
13
+
14
+ def self.init_manager(name)
15
+ name = name.to_sym
16
+
17
+ Manager.supervise_as name
18
+ @@supervisors[name] = Celluloid::Actor[name]
19
+ end
20
+
21
+ #---
22
+
23
+ def self.connection(name = :core)
24
+ name = name.to_sym
25
+
26
+ init_manager(name) unless @@supervisors.has_key?(name)
27
+
28
+ begin
29
+ @@supervisors[name].test_connection
30
+ rescue Celluloid::DeadActorError
31
+ retry
32
+ end
33
+ @@supervisors[name]
34
+ end
35
+
36
+ #---
37
+
38
+ def initialize
39
+ @logger = Nucleon.logger
40
+
41
+ @namespaces = {}
42
+ @types = {}
43
+ @load_info = {}
44
+ @plugins = {}
45
+ end
46
+
47
+ #-----------------------------------------------------------------------------
48
+ # Property accessor / modifiers
49
+
50
+ attr_reader :logger
51
+
52
+ #---
53
+
54
+ def namespaces
55
+ @namespaces.keys
56
+ end
57
+
58
+ def define_namespace(*namespaces)
59
+ namespaces.each do |namespace|
60
+ @namespaces[namespace.to_sym] = true
61
+ end
62
+ end
63
+
64
+ #---
65
+
66
+ def types
67
+ @types.keys
68
+ end
69
+
70
+ #---
71
+
72
+ def type_default(type)
73
+ @types[type.to_sym]
74
+ end
75
+
76
+ #---
77
+
78
+ def loaded_plugins(type = nil, provider = nil)
79
+ results = {}
80
+ type = type.to_sym if type
81
+ provider = provider.to_sym if provider
82
+
83
+ if type && @load_info.has_key?(type)
84
+ if provider && @load_info.has_key?(provider)
85
+ results = @load_info[type][provider]
86
+ else
87
+ results = @load_info[type]
88
+ end
89
+ elsif ! type
90
+ results = @load_info
91
+ end
92
+ results
93
+ end
94
+
95
+ #---
96
+
97
+ def plugins(type = nil, provider = nil)
98
+ results = {}
99
+ type = type.to_sym if type
100
+ provider = provider.to_sym if provider
101
+
102
+ if type && @plugins.has_key?(type)
103
+ if provider && ! @plugins[type].keys.empty?
104
+ @plugins[type].each do |instance_name, plugin|
105
+ plugin = @plugins[type][instance_name]
106
+ results[instance_name] = plugin if plugin.plugin_provider == provider
107
+ end
108
+ else
109
+ results = @plugins[type]
110
+ end
111
+ elsif ! type
112
+ results = @plugins
113
+ end
114
+ results
115
+ end
116
+
117
+ #-----------------------------------------------------------------------------
118
+ # Operations
119
+
120
+ def test_connection
121
+ true
122
+ end
123
+
124
+ #---
125
+
126
+ def reload
127
+ current_time = Time.now
128
+ Celluloid.logger = logger
129
+
130
+ logger.info("Initializing the Nucleon plugin system at #{current_time}")
131
+
132
+ define_namespace :nucleon
133
+
134
+ define_type :extension => nil, # Core
135
+ :action => :update, # Core
136
+ :project => :git, # Core
137
+ :command => :bash, # Core
138
+ :event => :regex, # Utility
139
+ :template => :json, # Utility
140
+ :translator => :json # Utility
141
+
142
+ load_plugins(true)
143
+ logger.info("Finished initializing Nucleon plugin system at #{Time.now}")
144
+ end
145
+
146
+ #---
147
+
148
+ def define_type(type_info)
149
+ if type_info.is_a?(Hash)
150
+ logger.info("Defining plugin types at #{Time.now}")
151
+
152
+ type_info.each do |type, default_provider|
153
+ logger.debug("Mapping plugin type #{type} to default provider #{default_provider}")
154
+ @types[type.to_sym] = default_provider
155
+ end
156
+ else
157
+ logger.warn("Defined types must be specified as a hash to be registered properly")
158
+ end
159
+ end
160
+
161
+ #---
162
+
163
+ def load_plugins(reset_gems = false)
164
+ # Register core plugins
165
+ logger.info("Initializing core plugins at #{Time.now}")
166
+ register(File.join(File.dirname(__FILE__), '..'))
167
+
168
+ # Register external Gem defined plugins
169
+ Gems.register(reset_gems)
170
+
171
+ # Register any other extension plugins
172
+ exec(:register_plugins)
173
+
174
+ # Autoload all registered plugins
175
+ autoload
176
+ end
177
+
178
+ #---
179
+
180
+ def register(base_path, &code)
181
+ namespaces.each do |namespace|
182
+ namespace_path = File.join(base_path, namespace.to_s)
183
+
184
+ if File.directory?(namespace_path)
185
+ register_namespace(namespace, namespace_path, &code)
186
+ end
187
+ end
188
+ end
189
+
190
+ #---
191
+
192
+ def register_namespace(namespace, base_path, &code)
193
+ if File.directory?(base_path)
194
+ logger.info("Loading files from #{base_path} at #{Time.now}")
195
+
196
+ Dir.glob(File.join(base_path, '*.rb')).each do |file|
197
+ logger.debug("Loading file: #{file}")
198
+ require file
199
+ end
200
+
201
+ logger.info("Loading directories from #{base_path} at #{Time.now}")
202
+ Dir.entries(base_path).each do |path|
203
+ unless path.match(/^\.\.?$/)
204
+ register_type(namespace, base_path, path, &code) if types.include?(path.to_sym)
205
+ end
206
+ end
207
+ end
208
+ end
209
+ protected :register_namespace
210
+
211
+ #---
212
+
213
+ def register_type(namespace, base_path, plugin_type, &code)
214
+ base_directory = File.join(base_path, plugin_type.to_s)
215
+
216
+ if File.directory?(base_directory)
217
+ logger.info("Registering #{base_directory} at #{Time.now}")
218
+
219
+ Dir.glob(File.join(base_directory, '*.rb')).each do |file|
220
+ add_build_info(namespace, plugin_type, file)
221
+ end
222
+ end
223
+ end
224
+ protected :register_type
225
+
226
+ #---
227
+
228
+ def add_build_info(namespace, type, file, &code)
229
+ type = type.to_sym
230
+
231
+ @load_info[type] = {} unless @load_info.has_key?(type)
232
+
233
+ components = file.split(File::SEPARATOR)
234
+ provider = components.pop.sub(/\.rb/, '').to_sym
235
+ directory = components.join(File::SEPARATOR)
236
+
237
+ logger.info("Loading nucleon #{type} plugin #{provider} at #{Time.now}")
238
+
239
+ unless @load_info[type].has_key?(provider)
240
+ data = {
241
+ :namespace => namespace,
242
+ :type => type,
243
+ :provider => provider,
244
+ :directory => directory,
245
+ :file => file
246
+ }
247
+ code.call(data) if code
248
+
249
+ logger.debug("Plugin #{type} loaded: #{data.inspect}")
250
+ @load_info[type][provider] = data
251
+ end
252
+ end
253
+ protected :add_build_info
254
+
255
+ #---
256
+
257
+ def autoload
258
+ logger.info("Autoloading registered plugins at #{Time.now}")
259
+
260
+ @load_info.keys.each do |type|
261
+ logger.debug("Autoloading type: #{type}")
262
+
263
+ @load_info[type].each do |provider, plugin|
264
+ logger.debug("Autoloading provider #{provider} at #{plugin[:directory]}")
265
+
266
+ nucleon_require(plugin[:directory], provider)
267
+
268
+ @load_info[type][provider][:class] = provider_class(plugin[:namespace], type, provider)
269
+ logger.debug("Updated #{type} #{provider} load info: #{@load_info[type][provider].inspect}")
270
+
271
+ # Make sure extensions are listening from the time they are loaded
272
+ load(:extension, provider, { :name => provider }) if type == :extension # Create a persistent instance
273
+ end
274
+ end
275
+ end
276
+
277
+ #---
278
+
279
+ def load(type, provider = nil, options = {})
280
+ config = Config.ensure(options)
281
+ name = config.get(:name, nil)
282
+
283
+ logger.info("Fetching plugin #{type} provider #{provider} at #{Time.now}")
284
+ logger.debug("Plugin options: #{config.export.inspect}")
285
+
286
+ default_provider = type_default(type)
287
+
288
+ if options.is_a?(Hash) || options.is_a?(Nucleon::Config)
289
+ config = Config.ensure(translate_type(type, options))
290
+ provider = config.get(:provider, provider)
291
+ options = config.export
292
+ end
293
+ provider = default_provider unless provider
294
+
295
+ if name
296
+ logger.debug("Looking up existing instance of #{name}")
297
+
298
+ existing_instance = get(type, name)
299
+ logger.info("Using existing instance of #{type}, #{name}") if existing_instance
300
+ end
301
+
302
+ return existing_instance if existing_instance
303
+ create(type, provider, config.export)
304
+ end
305
+
306
+ #---
307
+
308
+ def load_multiple(type, data, build_hash = false, keep_array = false)
309
+ logger.info("Fetching multiple plugins of #{type} at #{Time.now}")
310
+
311
+ group = ( build_hash ? {} : [] )
312
+ klass = base_plugin_class(type)
313
+ data = klass.build_info(type, data) if klass.respond_to?(:build_info)
314
+
315
+ logger.debug("Translated plugin data: #{data.inspect}")
316
+
317
+ data.each do |options|
318
+ if plugin = load(type, options[:provider], options)
319
+ if build_hash
320
+ group[plugin.plugin_name] = plugin
321
+ else
322
+ group << plugin
323
+ end
324
+ end
325
+ end
326
+ return group.shift if ! build_hash && group.length == 1 && ! keep_array
327
+ group
328
+ end
329
+
330
+ #---
331
+
332
+ def create(type, provider, options = {})
333
+ type = type.to_sym
334
+ provider = provider.to_sym
335
+
336
+ unless @types.has_key?(type)
337
+ logger.warn("Plugin type #{type} creation requested but it has not been registered yet")
338
+ return nil
339
+ end
340
+
341
+ info = @load_info[type][provider] if Util::Data.exists?(@load_info, [ type, provider ])
342
+
343
+ if info
344
+ logger.debug("Plugin information for #{provider} #{type} found. Data: #{info.inspect}")
345
+
346
+ instance_name = "#{provider}_" + Nucleon.sha1(options)
347
+ options = translate(info[:namespace], type, provider, options)
348
+
349
+ @plugins[type] = {} unless @plugins.has_key?(type)
350
+
351
+ unless instance_name && @plugins[type].has_key?(instance_name)
352
+ info[:instance_name] = instance_name
353
+ options[:meta] = Config.new(info).import(Util::Data.hash(options[:meta]))
354
+
355
+ logger.info("Creating new plugin #{provider} #{type} with #{options.inspect}")
356
+
357
+ plugin = info[:class].new(type, provider, options)
358
+
359
+ @plugins[type][instance_name] = plugin
360
+ end
361
+ return @plugins[type][instance_name]
362
+ end
363
+
364
+ logger.warn("Plugin information cannot be found for plugin #{type} #{provider}")
365
+ nil
366
+ end
367
+
368
+ #---
369
+
370
+ def get(type, name)
371
+ logger.info("Fetching plugin #{type} #{name}")
372
+
373
+ if @plugins.has_key?(type)
374
+ @plugins[type].each do |instance_name, plugin|
375
+ if plugin.plugin_name.to_s == name.to_s
376
+ logger.debug("Plugin #{type} #{name} found")
377
+ return plugin
378
+ end
379
+ end
380
+ end
381
+ logger.debug("Plugin #{type} #{name} not found")
382
+ nil
383
+ end
384
+
385
+ #---
386
+
387
+ def remove(plugin)
388
+ if plugin && plugin.respond_to?(:plugin_type) && @plugins.has_key?(plugin.plugin_type)
389
+ logger.debug("Removing #{plugin.plugin_type} #{plugin.plugin_name}")
390
+ @plugins[plugin.plugin_type].delete(plugin.plugin_instance_name)
391
+ plugin.terminate if plugin.respond_to?(:terminate)
392
+ else
393
+ logger.warn("Cannot remove plugin: #{plugin.inspect}")
394
+ end
395
+ end
396
+
397
+ #-----------------------------------------------------------------------------
398
+ # Extension hook execution
399
+
400
+ def exec(method, options = {})
401
+ results = nil
402
+
403
+ if Nucleon.log_level == :hook # To save processing on rendering
404
+ logger.hook("Executing extension hook { #{method} } at #{Time.now} with:\n#{PP.pp(options, '')}\n")
405
+ end
406
+
407
+ extensions = plugins(:extension)
408
+
409
+ extensions.each do |name, plugin|
410
+ provider = plugin.plugin_provider
411
+ result = nil
412
+
413
+ logger.debug("Checking extension #{provider}")
414
+
415
+ if plugin.respond_to?(method)
416
+ results = {} if results.nil?
417
+
418
+ result = plugin.send(method, options)
419
+ logger.info("Completed hook #{method} at #{Time.now} with: #{result.inspect}")
420
+
421
+ if block_given?
422
+ results[provider] = yield(:process, result)
423
+ logger.debug("Processed extension result into: #{results[provider].inspect}")
424
+ end
425
+
426
+ if results[provider].nil?
427
+ logger.debug("Setting extension result to: #{result.inspect}")
428
+ results[provider] = result
429
+ end
430
+ end
431
+ end
432
+
433
+ if ! results.nil? && block_given?
434
+ results = yield(:reduce, results)
435
+ logger.debug("Reducing extension results to: #{results.inspect}")
436
+ else
437
+ logger.debug("Final extension results: #{results.inspect}")
438
+ end
439
+ results
440
+ end
441
+
442
+ #---
443
+
444
+ def config(type, options = {})
445
+ config = Config.ensure(options)
446
+
447
+ logger.debug("Generating #{type} extended configuration from: #{config.export.inspect}")
448
+
449
+ exec("#{type}_config", Config.new(config.export)) do |op, data|
450
+ if op == :reduce
451
+ data.each do |provider, result|
452
+ config.defaults(result)
453
+ end
454
+ nil
455
+ else
456
+ hash(data)
457
+ end
458
+ end
459
+ config.delete(:extension_type)
460
+
461
+ logger.debug("Final extended configuration: #{config.export.inspect}")
462
+ config
463
+ end
464
+
465
+ #---
466
+
467
+ def check(method, options = {})
468
+ config = Config.ensure(options)
469
+
470
+ logger.debug("Checking extension #{method} given: #{config.export.inspect}")
471
+
472
+ success = exec(method, config.import({ :extension_type => :check })) do |op, data|
473
+ if op == :reduce
474
+ ! data.values.include?(false)
475
+ else
476
+ data ? true : false
477
+ end
478
+ end
479
+
480
+ success = success.nil? || success ? true : false
481
+
482
+ logger.debug("Extension #{method} check result: #{success.inspect}")
483
+ success
484
+ end
485
+
486
+ #---
487
+
488
+ def value(method, value, options = {})
489
+ config = Config.ensure(options)
490
+
491
+ logger.debug("Setting extension #{method} value given: #{value.inspect}")
492
+
493
+ exec(method, config.import({ :value => value, :extension_type => :value })) do |op, data|
494
+ if op == :process
495
+ value = data unless data.nil?
496
+ end
497
+ end
498
+
499
+ logger.debug("Extension #{method} retrieved value: #{value.inspect}")
500
+ value
501
+ end
502
+
503
+ #---
504
+
505
+ def collect(method, options = {})
506
+ config = Config.ensure(options)
507
+ values = []
508
+
509
+ logger.debug("Collecting extension #{method} values")
510
+
511
+ exec(method, config.import({ :extension_type => :collect })) do |op, data|
512
+ if op == :process
513
+ values << data unless data.nil?
514
+ end
515
+ end
516
+
517
+ logger.debug("Extension #{method} collected values: #{values.inspect}")
518
+ values
519
+ end
520
+
521
+ #-----------------------------------------------------------------------------
522
+ # Utilities
523
+
524
+ def translate_type(type, options)
525
+ klass = base_plugin_class(type)
526
+ logger.debug("Executing option translation for: #{klass.inspect}")
527
+
528
+ options = klass.send(:translate, options) if klass.respond_to?(method)
529
+ options
530
+ end
531
+
532
+ #---
533
+
534
+ def translate(namespace, type, provider, options)
535
+ klass = provider_class(namespace, type, provider)
536
+ logger.debug("Executing option translation for: #{klass.inspect}")
537
+
538
+ options = klass.send(:translate, options) if klass.respond_to?(method)
539
+ options
540
+ end
541
+
542
+ #---
543
+
544
+ def class_name(name, separator = '::', want_array = FALSE)
545
+ components = []
546
+
547
+ case name
548
+ when String, Symbol
549
+ components = name.to_s.split(separator)
550
+ when Array
551
+ components = name
552
+ end
553
+
554
+ components.collect! do |value|
555
+ value = value.to_s.strip
556
+ value[0] = value.capitalize[0] if value =~ /^[a-z]/
557
+ value
558
+ end
559
+
560
+ if want_array
561
+ return components
562
+ end
563
+ components.join(separator)
564
+ end
565
+
566
+ #---
567
+
568
+ def class_const(name, separator = '::')
569
+ components = class_name(name, separator, TRUE)
570
+ constant = Object
571
+
572
+ components.each do |component|
573
+ constant = constant.const_defined?(component) ?
574
+ constant.const_get(component) :
575
+ constant.const_missing(component)
576
+ end
577
+ constant
578
+ end
579
+
580
+ #---
581
+
582
+ def base_plugin_class(type)
583
+ class_const([ :nucleon, :plugin, type ])
584
+ end
585
+ protected :base_plugin_class
586
+
587
+ #---
588
+
589
+ def provider_class(namespace, type, provider)
590
+ class_const([ namespace, type, provider ])
591
+ end
592
+ protected :provider_class
593
+ end
594
+ end
@@ -0,0 +1,58 @@
1
+
2
+ module Nucleon
3
+ module Mixin
4
+ module Action
5
+ module Commit
6
+
7
+ #-----------------------------------------------------------------------------
8
+ # Options
9
+
10
+ def commit_options(parser, optional = true)
11
+ if optional
12
+ parser.option_bool(:commit, false,
13
+ '--commit',
14
+ 'nucleon.core.mixins.commit.options.commit'
15
+ )
16
+ else
17
+ parser.options[:commit] = true
18
+ end
19
+
20
+ parser.option_bool(:allow_empty, false,
21
+ '--empty',
22
+ 'nucleon.core.mixins.commit.options.empty'
23
+ )
24
+ parser.option_bool(:propogate, false,
25
+ '--propogate',
26
+ 'nucleon.core.mixins.commit.options.propogate'
27
+ )
28
+ parser.option_str(:message, '',
29
+ '--message COMMIT_MESSAGE',
30
+ 'nucleon.core.mixins.commit.options.message'
31
+ )
32
+ parser.option_str(:author, nil,
33
+ '--author COMMIT_AUTHOR',
34
+ 'nucleon.core.mixins.commit.options.author'
35
+ )
36
+ end
37
+
38
+ #-----------------------------------------------------------------------------
39
+ # Operations
40
+
41
+ def commit(project, files = '.')
42
+ success = true
43
+
44
+ if project && settings[:commit]
45
+ success = project.commit(files, extended_config(:commit, {
46
+ :allow_empty => settings[:allow_empty],
47
+ :message => settings[:message],
48
+ :author => settings[:author],
49
+ :propogate => settings[:propogate]
50
+ }))
51
+ end
52
+ success
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,53 @@
1
+
2
+ module Nucleon
3
+ module Mixin
4
+ module Action
5
+ module Project
6
+
7
+ #-----------------------------------------------------------------------------
8
+ # Options
9
+
10
+ def project_options(parser, ref_override = false, rev_override = false)
11
+ parser.option_str(:project_provider, 'git',
12
+ '--proj-provider PROVIDER',
13
+ 'nucleon.core.mixins.project.options.provider'
14
+ )
15
+ if ref_override
16
+ parser.option_str(:reference, nil,
17
+ '--reference PROJECT_REF',
18
+ 'nucleon.core.mixins.project.options.reference'
19
+ )
20
+ end
21
+ if rev_override
22
+ parser.option_str(:revision, nil,
23
+ '--revision PROJECT_REV',
24
+ 'nucleon.core.mixins.project.options.revision'
25
+ )
26
+ end
27
+ end
28
+
29
+ #-----------------------------------------------------------------------------
30
+ # Operations
31
+
32
+ def project_load(root_dir, update = false)
33
+
34
+ # 1. Set a default project provider (reference can override)
35
+ # 2. Get project from root directory
36
+ # 3. Initialize project if not yet initialized
37
+ # 4. Set remote if needed
38
+ # 5. Checkout revision if needed
39
+ # 6. Pull down updates if requested
40
+
41
+ return Nucleon.project(extended_config(:project, {
42
+ :provider => settings[:project_provider],
43
+ :directory => root_dir,
44
+ :url => settings[:reference],
45
+ :revision => settings[:revision],
46
+ :pull => update
47
+ }))
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+