diggit 1.0.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bdc49eaf85ab5ea705046d562d66d05aec279b07
4
- data.tar.gz: 8046df957be6fcc9a9296256c9bee91562f8ee7e
3
+ metadata.gz: ab5b0bd0d5959100238fb8bdcd2d6471a660bc94
4
+ data.tar.gz: 41bcf9e0cea8e6110faded4f51b37caa8475adf2
5
5
  SHA512:
6
- metadata.gz: 6b42a77ecfb10bc8f95e952d58f1a8bae42395b017038fea82fd5240a2f238645ec9007172dfdc54671e945674bc90bcc96946fadae62238a2781cc9a39c7d52
7
- data.tar.gz: f2626d93e3f2e1179d10f16f5cfcb3ddfcb292f99614518925e60349e1c5814bdf721beed37cb6851822ddba08ba6e5595de7a0fd50855f62f5faa3d48cc7247
6
+ metadata.gz: 2d11da8a99ed2706e882bbdaf9a95e011f46fb3f3e1941c6728311de15b7796ab624ce62ac0220e778094f6a8f29e0b798e79efa6c5916de8cce471a8f9b0b8f
7
+ data.tar.gz: f7272bb6679af26829ee4ccbc1b013f2f6d6c1e2026b01e0501335a0cd726e82b117c42fc8f2a28fbc24bae2ef988c86b37fd54f06581f3b78520cee010850a1
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Diggit
2
2
 
3
- A ruby tool to analyse Git repositories
3
+ A ruby tool to analyze Git repositories
4
4
 
5
5
  # Installation
6
6
 
@@ -36,10 +36,6 @@ A join is performed after all analyses of all repositories have been performed.
36
36
 
37
37
  ## Running analyses
38
38
 
39
- Once diggit is configured you can perform the analyses. First, you have to clone the repositories by using `dgit perform clones`. Then you can launch the analyses by using `dgit perform analyses`. Finally, the joins are executed via the command `dgit perform joins`.
39
+ Once diggit is configured you can perform the analyses. First, you have to clone the repositories by using `dgit clones perform`. Then you can launch the analyses by using `dgit analyses perform`. Finally, the joins are executed via the command `dgit joins perform`. You can use the `mode` option to handle the cleaning of joins or analyses.
40
40
 
41
- At all time, you can check the status of your diggit folder by using `dgit status`. If you want more info on the status of a given repository, you can use the `dgit sources info https://github.com/jrfaller/diggit.git` command.
42
-
43
- ## Cleaning up
44
-
45
- If something is going wrong, you can always delete the results of the joins by using the command `dgit clean joins` and of the analysis with the command `dgit clean analyses`.
41
+ At all time, you can check the status of your diggit folder by using `dgit status`.
data/bin/dgit CHANGED
@@ -1,6 +1,191 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
 
4
- require_relative '../lib/diggit_cli.rb'
4
+ require 'gli'
5
+ require_relative '../lib/dgit'
5
6
 
6
- Diggit::Cli::DiggitCli.start(ARGV)
7
+ include GLI::App
8
+
9
+ program_desc 'A git repository analysis tool.'
10
+
11
+ version Diggit::VERSION
12
+
13
+ subcommand_option_handling :normal
14
+ arguments :strict
15
+
16
+ desc 'Init a diggit folder.'
17
+ skips_pre
18
+ command :init do |c|
19
+ c.action do |_global_options, _options, _args|
20
+ Diggit::Dig.init_dir
21
+ Log.ok "Diggit folder initialized."
22
+ end
23
+ end
24
+
25
+ desc 'Display the status of the diggit folder.'
26
+ command :status do |c|
27
+ c.action do |_global_options, _options, _args|
28
+ Log.info "Config"
29
+ Log.info "======"
30
+ Log.info "- Analyses: #{Diggit::Dig.it.config.get_analyses.join(', ')}"
31
+ Log.info "- Joins: #{Diggit::Dig.it.config.get_joins.join(', ')}"
32
+ Log.info ""
33
+ Log.info "Journal"
34
+ Log.info "======="
35
+ Log.info "- New sources:"
36
+ Log.indent do
37
+ Log.ok "* Ok: #{Diggit::Dig.it.journal.sources_by_state(:new).size}"
38
+ Log.error "* Error: #{Diggit::Dig.it.journal.sources_by_state(:new, true).size}"
39
+ end
40
+ Log.info "- Cloned sources:"
41
+ Log.indent do
42
+ Log.ok "* Ok: #{Diggit::Dig.it.journal.sources_by_state(:cloned).size}"
43
+ Log.error "* Error: #{Diggit::Dig.it.journal.sources_by_state(:cloned, true).size}"
44
+ end
45
+ end
46
+ end
47
+
48
+ desc 'Manage the sources of the diggit folder.'
49
+ command :sources do |c|
50
+ c.desc 'List the sources.'
51
+ c.command :list do |list|
52
+ list.action do |_global_options, _options, _args|
53
+ sources = Diggit::Dig.it.journal.sources
54
+ sources.each_index do |idx|
55
+ msg = "#{idx} #{sources[idx].url} (#{sources[idx].state})"
56
+ sources[idx].error? ? Log.error(msg) : Log.ok(msg)
57
+ end
58
+ end
59
+ end
60
+ c.desc 'Add a source.'
61
+ c.arg_name 'url'
62
+ c.command :add do |add|
63
+ add.action do |_global_options, _options, args|
64
+ Diggit::Dig.it.journal.add_source args[0]
65
+ end
66
+ end
67
+ c.desc 'Import sources from a file.'
68
+ c.arg_name 'file'
69
+ c.command :import do |import|
70
+ import.action do |_global_options, _options, args|
71
+ File.open(args[0]).each { |line| Diggit::Dig.it.journal.add_source(line) }
72
+ end
73
+ end
74
+ c.default_command :list
75
+ end
76
+
77
+ desc 'Manage the joins of the diggit folder.'
78
+ command :joins do |c|
79
+ c.desc 'List the joins'
80
+ c.command :list do |list|
81
+ list.action do |_global_options, _options, _args|
82
+ Diggit::Dig.it.config.get_joins.each { |a| Log.info a.name }
83
+ end
84
+ end
85
+ c.desc 'Add add join.'
86
+ c.arg_name 'name'
87
+ c.command :add do |add|
88
+ add.action do |_global_options, _options, args|
89
+ Diggit::Dig.it.config.add_join args[0]
90
+ end
91
+ end
92
+ c.desc 'Perform joins.'
93
+ c.command :perform do |perform|
94
+ perform.flag [:s, :sources], desc: "list of sources", type: Array, default_value: []
95
+ perform.flag [:a, :analyses], desc: "list of analyses", type: Array, default_value: []
96
+ perform.flag [:m, :mode], desc: "running mode",
97
+ must_match: { "run" => :run, "clean" => :clean, "rerun" => :rerun }, default_value: :run
98
+ perform.action do |_global_options, options, _args|
99
+ Diggit::Dig.it.join(options[:s], options[:a], options[:m])
100
+ end
101
+ end
102
+ c.default_command :list
103
+ end
104
+
105
+ desc 'Manage the analyses of the diggit folder.'
106
+ command :analyses do |c|
107
+ c.desc 'List the analyses'
108
+ c.command :list do |list|
109
+ list.action do |_global_options, _options, _args|
110
+ Diggit::Dig.it.config.get_analyses.each { |a| Log.info a.name }
111
+ end
112
+ end
113
+ c.desc 'Add an analysis.'
114
+ c.arg_name 'name'
115
+ c.command :add do |add|
116
+ add.action do |_global_options, _options, args|
117
+ Diggit::Dig.it.config.add_analysis args[0]
118
+ end
119
+ end
120
+ c.desc 'Perform analyses.'
121
+ c.command :perform do |perform|
122
+ perform.flag [:s, :sources], desc: "list of sources", type: Array, default_value: []
123
+ perform.flag [:a, :analyses], desc: "list of analyses", type: Array, default_value: []
124
+ perform.flag [:m, :mode], desc: "running mode",
125
+ must_match: { "run" => :run, "clean" => :clean, "rerun" => :rerun }, default_value: :run
126
+ perform.action do |_global_options, options, _args|
127
+ Diggit::Dig.it.analyze(options[:s], options[:a], options[:m])
128
+ end
129
+ end
130
+ c.default_command :list
131
+ end
132
+
133
+ desc 'Manage clone actions.'
134
+ command :clone do |c|
135
+ c.desc 'Perform the clones.'
136
+ c.command :perform do |perform|
137
+ perform.flag [:s, :sources], desc: "list of sources", type: Array, default_value: []
138
+ perform.action do |_global_options, options, _args|
139
+ Diggit::Dig.it.clone(*options[:s])
140
+ end
141
+ end
142
+ c.default_command :perform
143
+ end
144
+
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|
177
+ Diggit::Dig.init
178
+ end
179
+
180
+ post do |_global, _command, _options, _args|
181
+ # Post logic here, skips_post to skip commands
182
+ end
183
+
184
+ on_error do |exception|
185
+ Log.error "Error running diggit."
186
+ Log.error exception.message
187
+ Log.info exception.backtrace.join("\n")
188
+ false
189
+ end
190
+
191
+ exit run(ARGV)
data/lib/dgit.rb ADDED
@@ -0,0 +1,6 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative "dgit/core"
4
+ require_relative "dgit/plugins"
5
+ require_relative "dgit/version"
6
+ require_relative "dgit/formatador"
data/lib/dgit/core.rb ADDED
@@ -0,0 +1,479 @@
1
+ # encoding: utf-8
2
+
3
+ require 'oj'
4
+ require 'rugged'
5
+ require 'singleton'
6
+ require_relative 'formatador'
7
+
8
+ class String
9
+ def underscore
10
+ gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
11
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2'). tr("-", "_").downcase
12
+ end
13
+
14
+ def camel_case
15
+ return self if self !~ /_/ && self =~ /[A-Z]+.*/
16
+ split('_').map(&:capitalize).join
17
+ end
18
+
19
+ def id
20
+ gsub(/[^[\w-]]+/, "_")
21
+ end
22
+ end
23
+
24
+ module Diggit
25
+ class Source
26
+ attr_reader :url, :repository
27
+ attr_accessor :entry
28
+
29
+ def initialize(url)
30
+ @url = url
31
+ @entry = Journal.new_source_entry
32
+ @repository = nil
33
+ end
34
+
35
+ def id
36
+ @url.id
37
+ end
38
+
39
+ def folder
40
+ Dig.it.file_path("sources/#{id}")
41
+ end
42
+
43
+ def error?
44
+ !(@entry[:last_error].nil? || @entry[:last_error].empty?)
45
+ end
46
+
47
+ def error
48
+ @entry[:last_error]
49
+ end
50
+
51
+ def error=(error)
52
+ @entry[:last_error] = error
53
+ end
54
+
55
+ def state
56
+ @entry[:state]
57
+ end
58
+
59
+ def state=(state)
60
+ @entry[:state] = state
61
+ end
62
+
63
+ def new?
64
+ @entry[:state] == :new
65
+ end
66
+
67
+ def cloned?
68
+ @entry[:state] == :cloned
69
+ end
70
+
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)
77
+ end
78
+
79
+ def analyses_performed?(*names)
80
+ (names - @entry[:performed_analyses]).empty?
81
+ end
82
+
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)
110
+ end
111
+
112
+ def clone
113
+ if File.exist?(folder)
114
+ Rugged::Repository.new(folder)
115
+ else
116
+ Rugged::Repository.clone_at(url, folder)
117
+ end
118
+ self.state = :cloned
119
+ rescue => e
120
+ Log.error "Error cloning #{url}."
121
+ self.error = Journal.dump_error(e)
122
+ end
123
+
124
+ def load_repository
125
+ fail "Source not cloned #{url}." if new?
126
+ @repository = Rugged::Repository.new(folder)
127
+ end
128
+ end
129
+
130
+ class Journal
131
+ def initialize(hash)
132
+ @sources = {}
133
+ @workspace = {}
134
+ hash[:urls].each do |u|
135
+ s = Source.new(u)
136
+ s.entry = hash[:sources][u] if !hash[:sources].nil? && hash[:sources].key?(u)
137
+ @sources[u] = s
138
+ end
139
+ @workspace = hash[:workspace]
140
+ @workspace = Journal.new_workspace_entry if hash[:workspace].nil? || hash[:workspace].empty?
141
+ end
142
+
143
+ def sources
144
+ @sources.values
145
+ end
146
+
147
+ def sources_by_state(state, error = false)
148
+ @sources.select { |_u, s| s.state == state && s.error? == error }.values
149
+ end
150
+
151
+ def sources_by_ids(*ids)
152
+ return sources if ids.empty?
153
+ source_array = sources
154
+ result = []
155
+ ids.each do |id|
156
+ fail "No such source index #{id}." if id >= source_array.length
157
+ result << source_array[id]
158
+ end
159
+ result
160
+ end
161
+
162
+ def update_source(source)
163
+ fail "No such source #{source}." unless @sources.key?(source.url)
164
+ @sources[source.url] = source
165
+ Dig.it.save_journal
166
+ end
167
+
168
+ def add_source(url)
169
+ @sources[url] = Source.new(url) unless @sources.key?(url)
170
+ Dig.it.save_journal
171
+ end
172
+
173
+ def join?(name)
174
+ @workspace[:performed_joins].include?(name)
175
+ end
176
+
177
+ def add_join(name)
178
+ @workspace[:performed_joins] << name
179
+ Dig.it.save_journal
180
+ end
181
+
182
+ def join_error?
183
+ !@workspace[:last_error].nil?
184
+ end
185
+
186
+ def join_error
187
+ @workspace[:last_error]
188
+ end
189
+
190
+ def join_error=(error)
191
+ @workspace[:last_error] = Journal.dump_error(error)
192
+ Dig.it.save_journal
193
+ end
194
+
195
+ def to_hash
196
+ entry_hash = {}
197
+ @sources.each { |entry| entry_hash[entry[0]] = entry[1].entry }
198
+ { urls: @sources.keys, sources: entry_hash, workspace: @workspace }
199
+ end
200
+
201
+ def self.new_source_entry
202
+ { state: :new, performed_analyses: [], error_analyses: [], ongoing_analyses: [], last_error: {} }
203
+ end
204
+
205
+ def self.new_workspace_entry
206
+ { performed_joins: [], last_error: {} }
207
+ end
208
+
209
+ def self.dump_error(error)
210
+ { name: error.class.name, message: error.to_s, backtrace: error.backtrace }
211
+ end
212
+ end
213
+
214
+ class Config
215
+ attr_reader :analyses, :joins
216
+
217
+ def initialize(hash)
218
+ @analyses = []
219
+ @joins = []
220
+ hash[:analyses].each { |a| load_analysis(a) }
221
+ hash[:joins].each { |j| load_join(j) }
222
+ end
223
+
224
+ def to_hash
225
+ { analyses: @analyses.map(&:name), joins: @joins.map(&:name) }
226
+ end
227
+
228
+ def add_analysis(name)
229
+ load_analysis(name) unless @analyses.map(&:name).include?(name)
230
+ Dig.it.save_config
231
+ end
232
+
233
+ def load_analysis(name)
234
+ @analyses << Dig.it.plugin_loader.load_plugin(name, :analysis)
235
+ end
236
+
237
+ def del_analysis(name)
238
+ @analyses.delete_if { |a| a.name == name }
239
+ Dig.it.save_config
240
+ end
241
+
242
+ def get_analyses(*names)
243
+ return analyses if names.empty?
244
+ analyses.select { |a| names.include?(a.name) }
245
+ end
246
+
247
+ def add_join(name)
248
+ load_join(name) unless @joins.map(&:name).include?(name)
249
+ Dig.it.save_config
250
+ end
251
+
252
+ def load_join(name)
253
+ @joins << Dig.it.plugin_loader.load_plugin(name, :join)
254
+ end
255
+
256
+ def del_join(name)
257
+ @joins.delete_if { |j| j.name == name }
258
+ Dig.it.save_config
259
+ end
260
+
261
+ def get_joins(*names)
262
+ return joins if names.empty?
263
+ joins.select { |j| joins.include?(j.name) }
264
+ end
265
+
266
+ def self.empty_config
267
+ { analyses: [], joins: [] }
268
+ end
269
+ end
270
+
271
+ class PluginLoader
272
+ include Singleton
273
+
274
+ PLUGINS_TYPES = [:addon, :analysis, :join]
275
+
276
+ def load_plugin(name, type, instance = false)
277
+ plugin = search_plugin(name, type)
278
+ if plugin
279
+ if instance
280
+ return plugin.new(Dig.it.options)
281
+ else
282
+ return plugin
283
+ end
284
+ else
285
+ fail "Plugin #{name} not found."
286
+ end
287
+ end
288
+
289
+ 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
306
+ end
307
+
308
+ 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)
312
+ 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
319
+ else
320
+ found = false
321
+ end
322
+ found
323
+ 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
+ end
333
+
334
+ class Dig
335
+ DGIT_FOLDER = ".dgit"
336
+ DGIT_SOURCES = "sources"
337
+ DGIT_CONFIG = "config"
338
+ DGIT_OPTIONS = "options"
339
+ DGIT_JOURNAL = "journal"
340
+
341
+ attr_reader :config, :options, :journal, :plugin_loader, :folder
342
+
343
+ @diggit = nil
344
+
345
+ def self.it
346
+ fail "Diggit has not been initialized." if @diggit.nil?
347
+ @diggit
348
+ end
349
+
350
+ def self.init(folder = '.')
351
+ @diggit = Dig.new(folder)
352
+ @diggit.load_options
353
+ @diggit.load_config
354
+ @diggit.load_journal
355
+ @diggit
356
+ end
357
+
358
+ def self.init_dir(folder = '.')
359
+ 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))
366
+ end
367
+
368
+ def initialize(folder)
369
+ fail "Folder #{folder} is not a diggit folder." unless File.exist?(File.expand_path(DGIT_FOLDER, folder))
370
+ @plugin_loader = PluginLoader.instance
371
+ @folder = folder
372
+ end
373
+
374
+ def load_journal
375
+ url_array = []
376
+ IO.readlines(config_path(DGIT_SOURCES)).each { |l| url_array << l.strip }
377
+ saved_hash = Oj.load_file(config_path(DGIT_JOURNAL))
378
+ hash = { urls: url_array, sources: saved_hash[:sources], workspace: saved_hash[:workspace] }
379
+ @journal = Journal.new(hash)
380
+ end
381
+
382
+ def save_journal
383
+ hash = @journal.to_hash
384
+ File.open(config_path(DGIT_SOURCES), "w") { |f| hash[:urls].each { |u| f.puts(u) } }
385
+ Oj.to_file(config_path(DGIT_JOURNAL), { sources: hash[:sources], workspace: hash[:workspace] })
386
+ end
387
+
388
+ def load_options
389
+ @options = Oj.load_file(config_path(DGIT_OPTIONS))
390
+ end
391
+
392
+ def save_options
393
+ Oj.to_file(config_path(DGIT_OPTIONS), options)
394
+ end
395
+
396
+ def load_config
397
+ @config = Config.new(Oj.load_file(config_path(DGIT_CONFIG)))
398
+ end
399
+
400
+ def save_config
401
+ config_hash = @config.to_hash
402
+ Oj.to_file(config_path(DGIT_CONFIG), config_hash)
403
+ end
404
+
405
+ def clone(*source_ids)
406
+ @journal.sources_by_ids(*source_ids).select(&:new?).each(&:clone)
407
+ ensure
408
+ save_journal
409
+ end
410
+
411
+ def analyze(source_ids = [], analyses = [], mode = :run)
412
+ @journal.sources_by_ids(*source_ids).select(&:cloned?).each do |s|
413
+ @config.get_analyses(*analyses).each do |klass|
414
+ a = klass.new(@options)
415
+ s.load_repository
416
+ 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)
419
+ end
420
+ end
421
+ end
422
+
423
+ def clean_mode?(mode)
424
+ mode == :rerun || mode == :clean
425
+ end
426
+
427
+ def run_mode?(mode)
428
+ mode == :rerun || mode == :run
429
+ end
430
+
431
+ def clean_analysis(s, a)
432
+ a.clean
433
+ s.del_analysis(a.name)
434
+ ensure
435
+ save_journal
436
+ end
437
+
438
+ def run_analysis(s, a)
439
+ s.add_ongoing_analysis(a.name)
440
+ a.run
441
+ s.del_ongoing_analysis(a.name)
442
+ s.add_performed_analysis(a.name)
443
+ rescue => e
444
+ Log.error "Error applying analysis #{a.name} on #{s.url}"
445
+ s.error = Journal.dump_error(e)
446
+ ensure
447
+ save_journal
448
+ end
449
+
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
+ def run_join(j, source_array)
461
+ j.sources = source_array
462
+ j.run
463
+ @journal.add_join(j.name)
464
+ rescue => e
465
+ Log.error "Error applying join #{j.name}"
466
+ @journal.join_error = e
467
+ ensure
468
+ save_journal
469
+ 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
+ end
479
+ end