diggit 2.0.0 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab5b0bd0d5959100238fb8bdcd2d6471a660bc94
4
- data.tar.gz: 41bcf9e0cea8e6110faded4f51b37caa8475adf2
3
+ metadata.gz: 9fbc5e12f3c7806df481b5627dc5f904f89428c5
4
+ data.tar.gz: 6600fc64a91b44b386795d16a792caa11f12d932
5
5
  SHA512:
6
- metadata.gz: 2d11da8a99ed2706e882bbdaf9a95e011f46fb3f3e1941c6728311de15b7796ab624ce62ac0220e778094f6a8f29e0b798e79efa6c5916de8cce471a8f9b0b8f
7
- data.tar.gz: f7272bb6679af26829ee4ccbc1b013f2f6d6c1e2026b01e0501335a0cd726e82b117c42fc8f2a28fbc24bae2ef988c86b37fd54f06581f3b78520cee010850a1
6
+ metadata.gz: 5defc137d1d9cd066c730c4c2d01b2da01bd7f848866cd01888caf6b97fea24377e293ddfc66ade5f03f9b6742ca3bc177b611762a30deb697b9fe6ff894f326
7
+ data.tar.gz: 535718d8f71f8f088f08c08bab2edb33e8e270db0e928a208d26c273c4a71b445863060ec2157175adb33fc33292e8120ba4d0df94931f96a1589db783a800ed
@@ -0,0 +1,20 @@
1
+ # Changelog of Diggit
2
+
3
+ ### Version 2.0.1
4
+ * Removed `errors`command, merged with subcommands of `sources`
5
+ * Added a lot of documentation
6
+ * Now the `init` command creates the directory for plugins and skips creating already existing folders
7
+ * Fixed plugins not shipped with the gem
8
+ * Removed useless dependency on `mongo`
9
+
10
+ ## Version 2.0.0 (Beardfish)
11
+ * huge refactoring of the code
12
+ * now addons are lazy loaded
13
+ * `require_addons` to include addons in analyses and joins
14
+ * addons are now accessible using a method with the name of the addon inside an analysis or a join
15
+ * improved command line: now uses the GLI library
16
+ * addition of run modes: `:run`, `:rerun` and `:clean`
17
+ * more detailed journaling
18
+
19
+ ## Version 1.0.0 (Anchovy)
20
+ * initial version
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Diggit
1
+ # Diggit [![Build Status](https://travis-ci.org/jrfaller/diggit.svg?branch=master)](https://travis-ci.org/jrfaller/diggit) [![Coverage Status](https://coveralls.io/repos/jrfaller/diggit/badge.svg?branch=master)](https://coveralls.io/r/jrfaller/diggit?branch=master) [![Inline docs](http://inch-ci.org/github/jrfaller/diggit.svg?branch=master)](http://inch-ci.org/github/jrfaller/diggit) [![Dependency Status](https://gemnasium.com/jrfaller/diggit.svg)](https://gemnasium.com/jrfaller/diggit)
2
2
 
3
3
  A ruby tool to analyze Git repositories
4
4
 
@@ -14,6 +14,8 @@ Clone diggit using the following command: `git clone https://github.com/jrfaller
14
14
 
15
15
  # Usage
16
16
 
17
+ Don't forget that dgit binary has an associated help that can be consulted using `dgit help`.
18
+
17
19
  ## Configuration
18
20
 
19
21
  The diggit tool is designed to help you analyze software repositories. Firstly you have to create a new folder in which you launch the `dgit init` command. This way, the folder becomes a diggit folder in which you can configure repositories and analyses.
data/bin/dgit CHANGED
@@ -1,5 +1,23 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
+ #
4
+ # This file is part of Diggit.
5
+ #
6
+ # Diggit is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU Lesser General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # Diggit is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU Lesser General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU Lesser General Public License
17
+ # along with Diggit. If not, see <http://www.gnu.org/licenses/>.
18
+ #
19
+ # Copyright 2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
20
+ #
3
21
 
4
22
  require 'gli'
5
23
  require_relative '../lib/dgit'
@@ -8,6 +26,8 @@ include GLI::App
8
26
 
9
27
  program_desc 'A git repository analysis tool.'
10
28
 
29
+ switch [:v, :verbose], default_value: false, negatable: false, desc: "Indicates if the debug information are visible."
30
+
11
31
  version Diggit::VERSION
12
32
 
13
33
  subcommand_option_handling :normal
@@ -71,6 +91,35 @@ command :sources do |c|
71
91
  File.open(args[0]).each { |line| Diggit::Dig.it.journal.add_source(line) }
72
92
  end
73
93
  end
94
+ c.desc 'Display all sources in error.'
95
+ c.command :errors do |errors|
96
+ errors.action do |_global_options, _options, _args|
97
+ sources = Diggit::Dig.it.journal.sources
98
+ sources.each_index do |idx|
99
+ msg = "#{idx} #{sources[idx].url} (#{sources[idx].state})"
100
+ Log.error msg if sources[idx].error?
101
+ end
102
+ end
103
+ end
104
+ c.desc 'Display information on a source'
105
+ c.arg_name 'id'
106
+ c.command :info do |info|
107
+ info.action do |_global_options, _options, args|
108
+ src = Diggit::Dig.it.journal.sources_by_ids(args.to_i)
109
+ url = "URL: #{src.url}"
110
+ src.error? ? Log.error(url) : Log.info(url)
111
+ Log.info "State: #{src.state}"
112
+ Log.info "Performed analyses: #{src.performed_analyses.join(', ')}" unless src.performed_analyses.empty?
113
+ Log.error "Ongoing analyses: #{src.ongoing_analyses.join(', ')}" unless src.ongoing_analyses.emtpy?
114
+ if src.error?
115
+ error = src.error
116
+ Log.indent do
117
+ Log.error error[:message]
118
+ Log.info error[:backtrace].join("\n")
119
+ end
120
+ end
121
+ end
122
+ end
74
123
  c.default_command :list
75
124
  end
76
125
 
@@ -117,6 +166,13 @@ command :analyses do |c|
117
166
  Diggit::Dig.it.config.add_analysis args[0]
118
167
  end
119
168
  end
169
+ c.desc 'Delete an analysis.'
170
+ c.arg_name 'name'
171
+ c.command :del do |add|
172
+ add.action do |_global_options, _options, args|
173
+ Diggit::Dig.it.config.del_analysis args[0]
174
+ end
175
+ end
120
176
  c.desc 'Perform analyses.'
121
177
  c.command :perform do |perform|
122
178
  perform.flag [:s, :sources], desc: "list of sources", type: Array, default_value: []
@@ -142,39 +198,10 @@ command :clone do |c|
142
198
  c.default_command :perform
143
199
  end
144
200
 
145
- desc 'Display errors.'
146
- command :errors do |c|
147
- c.desc 'Display the list of errors.'
148
- c.command :list do |list|
149
- list.action do |_global_options, _options, _args|
150
- sources = Diggit::Dig.it.journal.sources
151
- sources.each_index do |idx|
152
- msg = "#{idx} #{sources[idx].url} (#{sources[idx].state})"
153
- Log.error msg if sources[idx].error?
154
- end
155
- end
156
- end
157
- c.desc 'Display a source error.'
158
- c.arg_name 'id'
159
- c.command :show do |show|
160
- show.action do |_global_options, _options, args|
161
- source = Diggit::Dig.it.journal.sources_by_ids(args[0].to_i)[0]
162
- Log.ok "Error summary for source #{args[0]}"
163
- error = source.error
164
- Log.info "URL: #{source.url}"
165
- Log.info "State: #{source.state}"
166
- Log.info "Error:"
167
- Log.indent do
168
- Log.error error[:message]
169
- Log.info error[:backtrace].join("\n")
170
- end
171
- end
172
- end
173
- c.default_command :list
174
- end
175
-
176
- pre do |_global, _command, _options, _args|
201
+ pre do |global, _command, _options, _args|
177
202
  Diggit::Dig.init
203
+ Log.level = :fine if global[:v]
204
+ true
178
205
  end
179
206
 
180
207
  post do |_global, _command, _options, _args|
@@ -1,6 +1,24 @@
1
1
  # encoding: utf-8
2
+ #
3
+ # This file is part of Diggit.
4
+ #
5
+ # Diggit is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Diggit is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Diggit. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ # Copyright 2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
19
+ #
2
20
 
3
21
  require_relative "dgit/core"
4
22
  require_relative "dgit/plugins"
5
23
  require_relative "dgit/version"
6
- require_relative "dgit/formatador"
24
+ require_relative "dgit/log"
@@ -1,26 +1,59 @@
1
1
  # encoding: utf-8
2
+ #
3
+ # This file is part of Diggit.
4
+ #
5
+ # Diggit is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Diggit is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Diggit. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ # Copyright 2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
19
+ #
2
20
 
3
21
  require 'oj'
4
22
  require 'rugged'
5
23
  require 'singleton'
6
- require_relative 'formatador'
24
+ require_relative 'log'
7
25
 
8
26
  class String
27
+ # Returns a underscore cased version of the string.
28
+ # @return [String]
9
29
  def underscore
10
30
  gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
11
31
  .gsub(/([a-z\d])([A-Z])/, '\1_\2'). tr("-", "_").downcase
12
32
  end
13
33
 
34
+ # Returns a camel cased version of the string.
35
+ # @return [String]
14
36
  def camel_case
15
37
  return self if self !~ /_/ && self =~ /[A-Z]+.*/
16
38
  split('_').map(&:capitalize).join
17
39
  end
18
40
 
41
+ # Returns a version of the string that can be safely used as a folder name.
42
+ # @return [string]
19
43
  def id
20
44
  gsub(/[^[\w-]]+/, "_")
21
45
  end
22
46
  end
23
47
 
48
+ class Module
49
+ # Return the simple name of a module.
50
+ # The simple name is the underscore cased name of the module without namespaces.
51
+ # FIXME: name returns module/class instead of module::class.
52
+ def simple_name
53
+ to_s.gsub(/^.*::/, '').underscore
54
+ end
55
+ end
56
+
24
57
  module Diggit
25
58
  class Source
26
59
  attr_reader :url, :repository
@@ -68,45 +101,16 @@ module Diggit
68
101
  @entry[:state] == :cloned
69
102
  end
70
103
 
71
- def add_performed_analysis(name)
72
- @entry[:performed_analyses] << name
73
- end
74
-
75
- def analysis_performed?(name)
76
- @entry[:performed_analyses].include?(name)
104
+ def all_analyses
105
+ performed_analyses + ongoing_analyses
77
106
  end
78
107
 
79
- def analyses_performed?(*names)
80
- (names - @entry[:performed_analyses]).empty?
108
+ def performed_analyses
109
+ @entry[:performed_analyses]
81
110
  end
82
111
 
83
- def del_performed_analysis(name)
84
- @entry[:performed_analyses].delete_if { |a| a == name }
85
- end
86
-
87
- def add_ongoing_analysis(name)
88
- @entry[:ongoing_analyses].include?(name)
89
- end
90
-
91
- def del_ongoing_analysis(name)
92
- @entry[:ongoing_analyses].delete_if { |a| a == name }
93
- end
94
-
95
- def analysis_ongoing?(name)
96
- @entry[:ongoing_analyses].include?(name)
97
- end
98
-
99
- def analyses_ongoing?(*names)
100
- (names - @entry[:ongoing_analyses]).empty?
101
- end
102
-
103
- def analysis?(name)
104
- analysis_ongoing?(name) || analysis_performed?(name)
105
- end
106
-
107
- def del_analysis(name)
108
- del_ongoing_analysis(name)
109
- del_performed_analysis(name)
112
+ def ongoing_analyses
113
+ @entry[:ongoing_analyses]
110
114
  end
111
115
 
112
116
  def clone
@@ -268,11 +272,23 @@ module Diggit
268
272
  end
269
273
  end
270
274
 
275
+ # Class to handle loading of diggit plugins.
276
+ # Diggit plugins are defined in camel cased classes derived from Plugin.
277
+ # Their name is the underscore cased version of the class name (example +MyPlugin+ becomes +my_plugin+).
278
+ # It uses a singleton pattern, so you have to create an instance like that:
279
+ # @example
280
+ # PluginLoader.instance
281
+ # @see Plugin
271
282
  class PluginLoader
272
283
  include Singleton
273
284
 
274
285
  PLUGINS_TYPES = [:addon, :analysis, :join]
275
286
 
287
+ # Load the plugin with the given name and type.
288
+ # @param name [String] the name of the plugin
289
+ # @param type [Symbol] the type of the plugin: +:addon+, +:analysis+ or +:join+.
290
+ # @param instance [Boolean] +true+ for retrieving an instance or +false+ for retrieving the class.
291
+ # @return [Plugin, Class] the instance or class of the plugin.
276
292
  def load_plugin(name, type, instance = false)
277
293
  plugin = search_plugin(name, type)
278
294
  if plugin
@@ -286,51 +302,69 @@ module Diggit
286
302
  end
287
303
  end
288
304
 
305
+ def self.plugin_paths(name, type, root)
306
+ Dir.glob(File.join(root, 'plugins', type.to_s, '**', "#{name}.rb"))
307
+ end
308
+
309
+ # Constructor. Should not be called directly. Use {.instance} instead.
310
+ # @return [PluginLoader]
311
+ def initialize
312
+ @plugins = {}
313
+ end
314
+
315
+ private
316
+
289
317
  def search_plugin(name, type)
290
- plugin = nil
291
- if @plugins.key?(name)
292
- plugin = @plugins[name]
293
- else
294
- fail "Unknown plugin type #{type}." unless PLUGINS_TYPES.include?(type)
295
- if load_file(name, type)
296
- plugin = Object.const_get(name.camel_case)
297
- base_class = Object.const_get("Diggit::#{type.to_s.camel_case}")
298
- if plugin < base_class
299
- @plugins[name] = plugin
300
- else
301
- fail "Plugin #{name} not of kind #{type}."
302
- end
303
- end
304
- end
305
- plugin
318
+ return @plugins[name] if @plugins.key?(name)
319
+ fail "Unknown plugin type #{type}." unless PLUGINS_TYPES.include?(type)
320
+ fail "File #{name}.rb in #{type} directories not found." unless load_file(name, type)
321
+
322
+ base_class = Object.const_get("Diggit::#{type.to_s.camel_case}")
323
+ plugins = ObjectSpace.each_object(Class).select { |c| c < base_class && c.simple_name == name }
324
+
325
+ fail "No plugin #{name} of kind #{type} found." if plugins.empty?
326
+ warn "Ambiguous plugin name: several plugins of kind #{type} named #{name} were found." if plugins.size > 1
327
+
328
+ @plugins[name] = plugins[0]
329
+ plugins[0]
306
330
  end
307
331
 
308
332
  def load_file(name, type)
309
- f_glob = PluginLoader.plugin_path(name, type, File.expand_path('../..', File.dirname(File.realpath(__FILE__))))
310
- f_home = PluginLoader.plugin_path(name, type, File.expand_path(Dig::DGIT_FOLDER, Dir.home))
311
- f_local = PluginLoader.plugin_path(name, type, Dig.it.folder)
333
+ f_glob = PluginLoader.plugin_paths(name, type, File.expand_path('../..', File.dirname(File.realpath(__FILE__))))
334
+ f_home = PluginLoader.plugin_paths(name, type, File.join(Dir.home, Dig::DGIT_FOLDER))
335
+ f_local = PluginLoader.plugin_paths(name, type, Dig.it.folder)
336
+ Log.debug "Plugin files in global: #{f_glob}."
337
+ Log.debug "Plugin files in home: #{f_home}."
338
+ Log.debug "Plugin files in local directory: #{f_local}."
312
339
  found = true
313
- if File.exist?(f_local)
314
- require f_local
315
- elsif File.exist?(f_home)
316
- require f_home
317
- elsif File.exist?(f_glob)
318
- require f_glob
340
+ if !f_local.empty?
341
+ f_local.each { |f| require File.expand_path(f) }
342
+ elsif !f_home.empty?
343
+ f_home.each { |f| require File.expand_path(f) }
344
+ elsif !f_glob.empty?
345
+ f_glob.each { |f| require File.expand_path(f) }
319
346
  else
320
347
  found = false
321
348
  end
322
349
  found
323
350
  end
324
-
325
- def self.plugin_path(name, type, root)
326
- File.expand_path("#{name}.rb", File.expand_path(type.to_s, File.expand_path('plugins', root)))
327
- end
328
-
329
- def initialize
330
- @plugins = {}
331
- end
332
351
  end
333
352
 
353
+ # Main diggit class.
354
+ # It must be runned in a folder containing a +.dgit+ folder with a proper configuration.
355
+ # Access configuration, options, sources and journal from this object.
356
+ # It implements the singleton pattern.
357
+ # You can initialize it via {.init} and retrieve the instance via {.it}.
358
+ # @!attribute [r] config
359
+ # @return [Config] the config.
360
+ # @!attribute [r] options
361
+ # @return [Hash<String,Object>] the options.
362
+ # @!attribute [r] journal
363
+ # @return [Journal] the journal.
364
+ # @!attribute [r] folder
365
+ # @return [String] the folder in which diggit is running.
366
+ # @!attribute [r] plugin_loader
367
+ # @return [PluginLoader] utility classes to load plugins.
334
368
  class Dig
335
369
  DGIT_FOLDER = ".dgit"
336
370
  DGIT_SOURCES = "sources"
@@ -338,15 +372,22 @@ module Diggit
338
372
  DGIT_OPTIONS = "options"
339
373
  DGIT_JOURNAL = "journal"
340
374
 
375
+ private_constant :DGIT_SOURCES, :DGIT_CONFIG, :DGIT_OPTIONS, :DGIT_JOURNAL
376
+
341
377
  attr_reader :config, :options, :journal, :plugin_loader, :folder
342
378
 
343
379
  @diggit = nil
344
380
 
381
+ # Returns the diggit instance.
382
+ # @return [Dig] the instance.
345
383
  def self.it
346
384
  fail "Diggit has not been initialized." if @diggit.nil?
347
385
  @diggit
348
386
  end
349
387
 
388
+ # Initialize and return the diggit instance into the given folder.
389
+ # @param folder the path to the folder.
390
+ # @return [Dig] the instance.
350
391
  def self.init(folder = '.')
351
392
  @diggit = Dig.new(folder)
352
393
  @diggit.load_options
@@ -355,22 +396,56 @@ module Diggit
355
396
  @diggit
356
397
  end
357
398
 
399
+ # Initialize a folder to be a diggit folder by creating an empty configuration.
400
+ # It creates a +.dgit+ folder containing a +journal+, +config+, +options+ files.
401
+ # It creates a +sources+ folder.
402
+ # It creates a +plugins+ folder.
403
+ # Directory creation is skipped if folder already exist.
404
+ # @param folder the path to the folder.
405
+ # @return [void]
358
406
  def self.init_dir(folder = '.')
359
407
  dgit_folder = File.expand_path(DGIT_FOLDER, folder)
360
- FileUtils.mkdir(dgit_folder)
361
- Oj.to_file(File.expand_path(DGIT_CONFIG, dgit_folder), Config.empty_config)
362
- Oj.to_file(File.expand_path(DGIT_OPTIONS, dgit_folder), {})
363
- FileUtils.touch(File.expand_path(DGIT_SOURCES, dgit_folder))
364
- Oj.to_file(File.expand_path(DGIT_JOURNAL, dgit_folder), {})
365
- FileUtils.mkdir(File.expand_path('sources', folder))
408
+ unless File.exist?(dgit_folder)
409
+ FileUtils.mkdir(dgit_folder)
410
+ Oj.to_file(File.expand_path(DGIT_CONFIG, dgit_folder), Config.empty_config)
411
+ Oj.to_file(File.expand_path(DGIT_OPTIONS, dgit_folder), {})
412
+ FileUtils.touch(File.expand_path(DGIT_SOURCES, dgit_folder))
413
+ Oj.to_file(File.expand_path(DGIT_JOURNAL, dgit_folder), {})
414
+ end
415
+ FileUtils.mkdir(File.expand_path('sources', folder)) unless File.exist?(File.expand_path('sources', folder))
416
+ unless File.exist?(File.expand_path("plugins", folder))
417
+ FileUtils.mkdir_p(File.expand_path("plugins", folder))
418
+ FileUtils.mkdir_p(File.expand_path("plugins/analysis", folder))
419
+ FileUtils.mkdir_p(File.expand_path("plugins/addon", folder))
420
+ FileUtils.mkdir_p(File.expand_path("plugins/join", folder))
421
+ end
422
+ end
423
+
424
+ # Return the path of the given config file
425
+ # @param name [String] name of the file
426
+ # @return [String] the path to the file.
427
+ def config_path(name)
428
+ File.expand_path(name, File.expand_path(DGIT_FOLDER, @folder))
366
429
  end
367
430
 
431
+ # Return the path of the given file in the diggit folder
432
+ # @param name [String] name of the file
433
+ # @return [String] the path to the file.
434
+ def file_path(name)
435
+ File.expand_path(name, @folder)
436
+ end
437
+
438
+ # Constructor. Should not be called directly.
439
+ # Use {.init} and {.it} instead.
440
+ # @return [Dig] a diggit object.
368
441
  def initialize(folder)
369
442
  fail "Folder #{folder} is not a diggit folder." unless File.exist?(File.expand_path(DGIT_FOLDER, folder))
370
443
  @plugin_loader = PluginLoader.instance
371
444
  @folder = folder
372
445
  end
373
446
 
447
+ # Load the journal from +.dgit/journal+
448
+ # @return [void]
374
449
  def load_journal
375
450
  url_array = []
376
451
  IO.readlines(config_path(DGIT_SOURCES)).each { |l| url_array << l.strip }
@@ -379,47 +454,83 @@ module Diggit
379
454
  @journal = Journal.new(hash)
380
455
  end
381
456
 
457
+ # Save the journal to +.dgit/journal+
458
+ # @return [void]
382
459
  def save_journal
383
460
  hash = @journal.to_hash
384
461
  File.open(config_path(DGIT_SOURCES), "w") { |f| hash[:urls].each { |u| f.puts(u) } }
385
462
  Oj.to_file(config_path(DGIT_JOURNAL), { sources: hash[:sources], workspace: hash[:workspace] })
386
463
  end
387
464
 
465
+ # Load the options from +.dgit/options+
466
+ # @return [void]
388
467
  def load_options
389
468
  @options = Oj.load_file(config_path(DGIT_OPTIONS))
390
469
  end
391
470
 
471
+ # Save the options to +.dgit/options+
472
+ # @return [void]
392
473
  def save_options
393
474
  Oj.to_file(config_path(DGIT_OPTIONS), options)
394
475
  end
395
476
 
477
+ # Load the config from +.dgit/config+
478
+ # @return [void]
396
479
  def load_config
397
480
  @config = Config.new(Oj.load_file(config_path(DGIT_CONFIG)))
398
481
  end
399
482
 
483
+ # Save the config to +.dgit/config+
484
+ # @return [void]
400
485
  def save_config
401
486
  config_hash = @config.to_hash
402
487
  Oj.to_file(config_path(DGIT_CONFIG), config_hash)
403
488
  end
404
489
 
490
+ # Clone the repository of all sources with the given source ids.
491
+ # @param source_ids [Array<Integer>] the ids of the sources.
492
+ # @return [void]
405
493
  def clone(*source_ids)
406
494
  @journal.sources_by_ids(*source_ids).select(&:new?).each(&:clone)
407
495
  ensure
408
496
  save_journal
409
497
  end
410
498
 
499
+ # Perform the given analyses on sources with the given ids using the given mode.
500
+ # @param source_ids [Array<Integer>] the ids of the sources.
501
+ # @param analyses [Array<String>] the names of the analyses.
502
+ # @param mode [Symbol] the mode: +:run+, +:rerun+ or +:clean+.
503
+ # @return [void]
411
504
  def analyze(source_ids = [], analyses = [], mode = :run)
412
505
  @journal.sources_by_ids(*source_ids).select(&:cloned?).each do |s|
413
506
  @config.get_analyses(*analyses).each do |klass|
414
507
  a = klass.new(@options)
415
508
  s.load_repository
416
509
  a.source = s
417
- clean_analysis(s, a) if clean_mode?(mode) && s.analysis?(a.name)
418
- run_analysis(s, a) if run_mode?(mode) && !s.analysis_performed?(a.name)
510
+ clean_analysis(s, a) if clean_mode?(mode) && s.all_analyses.include?(a.name)
511
+ run_analysis(s, a) if run_mode?(mode) && !s.performed_analyses.include?(a.name)
419
512
  end
420
513
  end
421
514
  end
422
515
 
516
+ # Perform the given joins on sources with the given ids using the given mode.
517
+ # @param source_ids [Array<Integer>] the ids of the sources.
518
+ # @param joins [Array<String>] the names of the analyses.
519
+ # @param mode [Symbol] the mode: +:run+, +:rerun+ or +:clean+.
520
+ # @return [void]
521
+ def join(source_ids = [], joins = [], mode = :run)
522
+ @config.get_joins(*joins).each do |klass|
523
+ j = klass.new(@options)
524
+ j.clean if clean_mode?(mode)
525
+ source_array = @journal.sources_by_ids(*source_ids).select do |s|
526
+ s.cloned? && (klass.required_analyses - s.performed_analyses).empty?
527
+ end
528
+ run_join(j, source_array) if run_mode?(mode) && !source_array.empty?
529
+ end
530
+ end
531
+
532
+ private
533
+
423
534
  def clean_mode?(mode)
424
535
  mode == :rerun || mode == :clean
425
536
  end
@@ -436,10 +547,10 @@ module Diggit
436
547
  end
437
548
 
438
549
  def run_analysis(s, a)
439
- s.add_ongoing_analysis(a.name)
550
+ s.ongoing_analyses << a.name
440
551
  a.run
441
- s.del_ongoing_analysis(a.name)
442
- s.add_performed_analysis(a.name)
552
+ s.ongoing_analyses.pop
553
+ s.performed_analyses << a.name
443
554
  rescue => e
444
555
  Log.error "Error applying analysis #{a.name} on #{s.url}"
445
556
  s.error = Journal.dump_error(e)
@@ -447,16 +558,6 @@ module Diggit
447
558
  save_journal
448
559
  end
449
560
 
450
- def join(source_ids = [], joins = [], mode = :run)
451
- @config.get_joins(*joins).each do |klass|
452
- j = klass.new(@options)
453
- j.clean if clean_mode?(mode)
454
- source_array = @journal.sources_by_ids(*source_ids)
455
- .select { |s| s.cloned? && s.analyses_performed?(*klass.required_analyses) }
456
- run_join(j, source_array) if run_mode?(mode) && !source_array.empty?
457
- end
458
- end
459
-
460
561
  def run_join(j, source_array)
461
562
  j.sources = source_array
462
563
  j.run
@@ -467,13 +568,5 @@ module Diggit
467
568
  ensure
468
569
  save_journal
469
570
  end
470
-
471
- def config_path(name)
472
- File.expand_path(name, File.expand_path(DGIT_FOLDER, @folder))
473
- end
474
-
475
- def file_path(name)
476
- File.expand_path(name, @folder)
477
- end
478
571
  end
479
572
  end