diggit 1.0.3 → 2.0.0
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 +4 -4
- data/README.md +3 -7
- data/bin/dgit +187 -2
- data/lib/dgit.rb +6 -0
- data/lib/dgit/core.rb +479 -0
- data/lib/dgit/formatador.rb +31 -0
- data/lib/dgit/plugins.rb +80 -0
- data/lib/dgit/version.rb +5 -0
- data/spec/core_spec.rb +109 -0
- data/{includes/addons/test.rb → spec/dgit/plugins/addon/test_addon.rb} +2 -8
- data/{includes/analyses/test.rb → spec/dgit/plugins/analysis/test_analysis.rb} +2 -4
- data/spec/dgit/plugins/analysis/test_analysis_with_addon.rb +20 -0
- data/spec/dgit/plugins/analysis/test_analysis_with_error.rb +10 -0
- data/spec/dgit/plugins/join/test_join.rb +15 -0
- data/spec/dgit/plugins/join/test_join_with_addon.rb +6 -0
- data/spec/spec_helper.rb +5 -29
- metadata +53 -26
- data/includes/addons/db.rb +0 -26
- data/includes/addons/output.rb +0 -37
- data/includes/addons/sources_options.rb +0 -21
- data/includes/analyses/authors.rb +0 -12
- data/includes/analyses/cloc.rb +0 -51
- data/includes/analyses/diff_stats.rb +0 -39
- data/includes/analyses/metadata.rb +0 -40
- data/includes/analyses/pom.rb +0 -16
- data/includes/joins/diff_size.rb +0 -67
- data/includes/joins/test.rb +0 -13
- data/lib/diggit_cli.rb +0 -334
- data/lib/diggit_core.rb +0 -343
- data/spec/diggit_spec.rb +0 -135
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab5b0bd0d5959100238fb8bdcd2d6471a660bc94
|
4
|
+
data.tar.gz: 41bcf9e0cea8e6110faded4f51b37caa8475adf2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
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`.
|
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
|
-
|
4
|
+
require 'gli'
|
5
|
+
require_relative '../lib/dgit'
|
5
6
|
|
6
|
-
|
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
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
|