oxidized 0.30.1 → 0.31.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +2 -2
- data/.github/workflows/stale.yml +4 -2
- data/.rubocop.yml +18 -2
- data/.rubocop_todo.yml +5 -12
- data/CHANGELOG.md +61 -1
- data/CONTRIBUTING.md +5 -0
- data/Dockerfile +82 -21
- data/README.md +5 -21
- data/Rakefile +3 -2
- data/docs/Configuration.md +36 -12
- data/docs/Creating-Models.md +45 -4
- data/docs/Hooks.md +34 -0
- data/docs/Issues.md +91 -0
- data/docs/Model-Notes/Cumulus.md +5 -0
- data/docs/Model-Notes/FSOS.md +5 -0
- data/docs/Model-Notes/FortiOS.md +21 -5
- data/docs/Model-Notes/HPEAruba.md +31 -0
- data/docs/Model-Notes/OS6.md +10 -0
- data/docs/Model-Notes/RouterOS.md +15 -0
- data/docs/Model-Notes/SikluMHTG.md +7 -0
- data/docs/Outputs.md +2 -0
- data/docs/Release.md +18 -15
- data/docs/Sources.md +21 -0
- data/docs/Supported-OS-Types.md +11 -5
- data/docs/Troubleshooting.md +35 -0
- data/examples/device-simulation/README.md +173 -0
- data/examples/device-simulation/cmdsets/aoscx +9 -0
- data/examples/device-simulation/cmdsets/arubainstant +5 -0
- data/examples/device-simulation/cmdsets/asa +7 -0
- data/examples/device-simulation/cmdsets/ios +7 -0
- data/examples/device-simulation/cmdsets/nxos +5 -0
- data/examples/device-simulation/cmdsets/routeros +5 -0
- data/examples/device-simulation/cmdsets/srosmd +11 -0
- data/examples/device-simulation/device2yaml.rb +225 -0
- data/examples/device-simulation/yaml/aoscx_R0X25A-6410_FL.10.10.1100.yaml +2281 -0
- data/examples/device-simulation/yaml/aoscx_R8N85A-C6000-48G-CL4_PL.10.08.1010.yaml +451 -0
- data/examples/device-simulation/yaml/arubainstant_IAP515_8.10.0.6_VWLC.yaml +213 -0
- data/examples/device-simulation/yaml/asa_5512_9.12-4-67_single-context.yaml +531 -0
- data/examples/device-simulation/yaml/asr920_16.8.1b.yaml +1122 -0
- data/examples/device-simulation/yaml/garderos_R7709_003_006_068.yaml +101 -0
- data/examples/device-simulation/yaml/iosxe_C9200L-24P-4G_17.09.04a.yaml +514 -0
- data/examples/device-simulation/yaml/iosxe_C9800-L-F-K9_17.06.05.yaml +417 -0
- data/examples/device-simulation/yaml/riverbed_915.yaml +123 -0
- data/examples/device-simulation/yaml/routeros_CHR_7.10.1.yaml +145 -0
- data/examples/device-simulation/yaml/routeros_CHR_7.16.yaml +79 -0
- data/examples/device-simulation/yaml/routeros_L009UiGS_7.15.2.yaml +353 -0
- data/examples/podman-compose/Makefile +60 -17
- data/examples/podman-compose/README.md +63 -27
- data/examples/podman-compose/docker-compose.yml +11 -2
- data/examples/podman-compose/gitserver/.gitignore +1 -0
- data/examples/podman-compose/gitserver/Dockerfile +14 -0
- data/examples/podman-compose/model-simulation/Dockerfile-model +1 -1
- data/examples/podman-compose/model-simulation/asternos.sh +2 -0
- data/examples/podman-compose/oxidized-config/.gitignore +2 -0
- data/examples/podman-compose/oxidized-config/config +1 -1
- data/examples/podman-compose/oxidized-config/config_csv-file +46 -0
- data/examples/podman-compose/oxidized-config/config_csv-gitserver +56 -0
- data/examples/podman-compose/oxidized-ssh/.gitignore +1 -0
- data/lib/oxidized/config.rb +7 -1
- data/lib/oxidized/hook/githubrepo.rb +37 -7
- data/lib/oxidized/hook/slackdiff.rb +29 -7
- data/lib/oxidized/input/http.rb +1 -0
- data/lib/oxidized/input/telnet.rb +1 -1
- data/lib/oxidized/manager.rb +17 -16
- data/lib/oxidized/model/aoscx.rb +16 -2
- data/lib/oxidized/model/aosw.rb +7 -1
- data/lib/oxidized/model/arubainstant.rb +90 -0
- data/lib/oxidized/model/audiocodes.rb +2 -2
- data/lib/oxidized/model/cnos.rb +13 -10
- data/lib/oxidized/model/cumulus.rb +3 -0
- data/lib/oxidized/model/dlink.rb +1 -0
- data/lib/oxidized/model/dlinknextgen.rb +3 -0
- data/lib/oxidized/model/edgecos.rb +2 -1
- data/lib/oxidized/model/eos.rb +2 -0
- data/lib/oxidized/model/f5os.rb +17 -0
- data/lib/oxidized/model/firewareos.rb +10 -1
- data/lib/oxidized/model/fortios.rb +24 -1
- data/lib/oxidized/model/garderos.rb +43 -0
- data/lib/oxidized/model/h3c.rb +1 -1
- data/lib/oxidized/model/ibos.rb +1 -0
- data/lib/oxidized/model/ios.rb +20 -12
- data/lib/oxidized/model/iosxr.rb +1 -1
- data/lib/oxidized/model/lenovonos.rb +2 -0
- data/lib/oxidized/model/linuxgeneric.rb +1 -1
- data/lib/oxidized/model/netgear.rb +1 -1
- data/lib/oxidized/model/nodegrid.rb +1 -1
- data/lib/oxidized/model/nsxdfw.rb +30 -0
- data/lib/oxidized/model/nxos.rb +2 -1
- data/lib/oxidized/model/os6.rb +48 -0
- data/lib/oxidized/model/rgos.rb +1 -1
- data/lib/oxidized/model/riverbed.rb +104 -0
- data/lib/oxidized/model/routeros.rb +2 -2
- data/lib/oxidized/model/saos.rb +18 -1
- data/lib/oxidized/model/siklumhtg.rb +22 -0
- data/lib/oxidized/model/uplinkolt.rb +46 -0
- data/lib/oxidized/model/vyatta.rb +2 -2
- data/lib/oxidized/model/xos.rb +7 -0
- data/lib/oxidized/node.rb +30 -18
- data/lib/oxidized/nodes.rb +13 -5
- data/lib/oxidized/output/file.rb +45 -42
- data/lib/oxidized/output/git.rb +185 -160
- data/lib/oxidized/output/gitcrypt.rb +188 -186
- data/lib/oxidized/output/http.rb +53 -51
- data/lib/oxidized/output/output.rb +6 -4
- data/lib/oxidized/source/csv.rb +44 -49
- data/lib/oxidized/source/http.rb +63 -81
- data/lib/oxidized/source/jsonfile.rb +63 -0
- data/lib/oxidized/source/source.rb +43 -18
- data/lib/oxidized/source/sql.rb +66 -59
- data/lib/oxidized/version.rb +2 -2
- data/oxidized.gemspec +22 -16
- metadata +111 -15
data/lib/oxidized/node.rb
CHANGED
@@ -80,6 +80,8 @@ module Oxidized
|
|
80
80
|
@err_reason = err.message.to_s
|
81
81
|
false
|
82
82
|
rescue StandardError => e
|
83
|
+
# Send a message in debug mode in case we are not able to create a crashfile
|
84
|
+
Oxidized.logger.send(:debug, '%s raised %s with msg "%s", creating crashfile' % [ip, e.class, e.message])
|
83
85
|
crashdir = Oxidized.config.crash.directory
|
84
86
|
crashfile = Oxidized.config.crash.hostnames? ? name : ip.to_s
|
85
87
|
FileUtils.mkdir_p(crashdir) unless File.directory?(crashdir)
|
@@ -198,33 +200,43 @@ module Oxidized
|
|
198
200
|
end
|
199
201
|
|
200
202
|
def resolve_key(key, opt, global = nil)
|
201
|
-
# resolve key
|
203
|
+
# resolve key: the priority is as follows: node -> group specific model -> group -> model -> global passed -> global
|
204
|
+
# where node has the highest priority (= if defined, overwrites other values)
|
202
205
|
key_sym = key.to_sym
|
203
206
|
key_str = key.to_s
|
204
|
-
|
205
|
-
Oxidized.logger.debug "node.rb: resolving node key '#{key}', with passed global value of '#{
|
207
|
+
model_name = @model.class.name.to_s.downcase
|
208
|
+
Oxidized.logger.debug "node.rb: resolving node key '#{key}', with passed global value of '#{global}' and node value '#{opt[key_sym]}'"
|
206
209
|
|
207
|
-
#
|
208
|
-
if
|
209
|
-
value =
|
210
|
-
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from
|
211
|
-
end
|
210
|
+
# Node
|
211
|
+
if opt[key_sym]
|
212
|
+
value = opt[key_sym]
|
213
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from node"
|
212
214
|
|
213
|
-
#
|
214
|
-
|
215
|
+
# Group specific model
|
216
|
+
elsif Oxidized.config.groups.has_key?(@group) && Oxidized.config.groups[@group].models.has_key?(model_name) && Oxidized.config.groups[@group].models[model_name].has_key?(key_str)
|
217
|
+
value = Oxidized.config.groups[@group].models[model_name][key_str]
|
218
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from model in group"
|
219
|
+
|
220
|
+
# Group
|
221
|
+
elsif Oxidized.config.groups.has_key?(@group) && Oxidized.config.groups[@group].has_key?(key_str)
|
215
222
|
value = Oxidized.config.groups[@group][key_str]
|
216
223
|
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from group"
|
217
|
-
end
|
218
224
|
|
219
|
-
#
|
220
|
-
|
221
|
-
value = Oxidized.config.models[
|
225
|
+
# Model
|
226
|
+
elsif Oxidized.config.models.has_key?(model_name) && Oxidized.config.models[model_name].has_key?(key_str)
|
227
|
+
value = Oxidized.config.models[model_name][key_str]
|
222
228
|
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from model"
|
223
|
-
end
|
224
229
|
|
225
|
-
#
|
226
|
-
|
227
|
-
|
230
|
+
# Global passed
|
231
|
+
elsif global
|
232
|
+
value = global
|
233
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from passed global value"
|
234
|
+
|
235
|
+
# Global
|
236
|
+
elsif Oxidized.config.has_key?(key_str)
|
237
|
+
value = Oxidized.config[key_str]
|
238
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from global"
|
239
|
+
end
|
228
240
|
value
|
229
241
|
end
|
230
242
|
|
data/lib/oxidized/nodes.rb
CHANGED
@@ -61,6 +61,9 @@ module Oxidized
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
# Returns the configuration of group/node_name
|
65
|
+
#
|
66
|
+
# #fetch is called by oxidzed-web
|
64
67
|
def fetch(node_name, group)
|
65
68
|
yield_node_output(node_name) do |node, output|
|
66
69
|
output.fetch node, group
|
@@ -69,7 +72,7 @@ module Oxidized
|
|
69
72
|
|
70
73
|
# @param node [String] name of the node moved into the head of array
|
71
74
|
def next(node, opt = {})
|
72
|
-
return
|
75
|
+
return if running.find_index(node)
|
73
76
|
|
74
77
|
with_lock do
|
75
78
|
n = del node
|
@@ -98,6 +101,9 @@ module Oxidized
|
|
98
101
|
find_index(node) || raise(NodeNotFound, "unable to find '#{node}'")
|
99
102
|
end
|
100
103
|
|
104
|
+
# Returns all stored versions of group/node_name
|
105
|
+
#
|
106
|
+
# Called by oxidized-web
|
101
107
|
def version(node_name, group)
|
102
108
|
yield_node_output(node_name) do |node, output|
|
103
109
|
output.version node, group
|
@@ -116,6 +122,10 @@ module Oxidized
|
|
116
122
|
end
|
117
123
|
end
|
118
124
|
|
125
|
+
def find_index(node)
|
126
|
+
index { |e| [e.name, e.ip].include? node }
|
127
|
+
end
|
128
|
+
|
119
129
|
private
|
120
130
|
|
121
131
|
def initialize(opts = {})
|
@@ -133,10 +143,6 @@ module Oxidized
|
|
133
143
|
@mutex.synchronize(...)
|
134
144
|
end
|
135
145
|
|
136
|
-
def find_index(node)
|
137
|
-
index { |e| [e.name, e.ip].include? node }
|
138
|
-
end
|
139
|
-
|
140
146
|
# @param node node which is removed from nodes list
|
141
147
|
# @return [Node] deleted node
|
142
148
|
def del(node)
|
@@ -179,6 +185,8 @@ module Oxidized
|
|
179
185
|
def yield_node_output(node_name)
|
180
186
|
with_lock do
|
181
187
|
node = find { |n| n.name == node_name }
|
188
|
+
raise(NodeNotFound, "unable to find '#{node_name}'") if node.nil?
|
189
|
+
|
182
190
|
output = node.output.new
|
183
191
|
raise NotSupported unless output.respond_to? :fetch
|
184
192
|
|
data/lib/oxidized/output/file.rb
CHANGED
@@ -1,55 +1,58 @@
|
|
1
1
|
module Oxidized
|
2
|
-
|
3
|
-
|
2
|
+
module Output
|
3
|
+
# ruby's File class must be accessed with ::File to avoid name conflicts
|
4
|
+
class File < Output
|
5
|
+
require 'fileutils'
|
4
6
|
|
5
|
-
|
7
|
+
attr_reader :commitref
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
def initialize
|
10
|
+
super
|
11
|
+
@cfg = Oxidized.config.output.file
|
12
|
+
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
+
def setup
|
15
|
+
return unless @cfg.empty?
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
Oxidized.asetus.user.output.file.directory = ::File.join(Config::ROOT, 'configs')
|
18
|
+
Oxidized.asetus.save :user
|
19
|
+
raise NoConfig, "no output file config, edit #{Oxidized::Config.configfile}"
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
22
|
+
def store(node, outputs, opt = {})
|
23
|
+
file = ::File.expand_path @cfg.directory
|
24
|
+
file = ::File.join ::File.dirname(file), opt[:group] if opt[:group]
|
25
|
+
FileUtils.mkdir_p file
|
26
|
+
file = ::File.join file, node
|
27
|
+
::File.write(file, outputs.to_cfg)
|
28
|
+
@commitref = file
|
29
|
+
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
31
|
+
def fetch(node, group)
|
32
|
+
cfg_dir = ::File.expand_path @cfg.directory
|
33
|
+
node_name = node.name
|
34
|
+
|
35
|
+
if group # group is explicitly defined by user
|
36
|
+
cfg_dir = ::File.join ::File.dirname(cfg_dir), group
|
37
|
+
::File.read ::File.join(cfg_dir, node_name)
|
38
|
+
elsif ::File.exist? ::File.join(cfg_dir, node_name) # node configuration file is stored on base directory
|
39
|
+
::File.read ::File.join(cfg_dir, node_name)
|
40
|
+
else
|
41
|
+
path = Dir.glob(::File.join(::File.dirname(cfg_dir), '**', node_name)).first # fetch node in all groups
|
42
|
+
::File.read path
|
43
|
+
end
|
44
|
+
rescue Errno::ENOENT
|
45
|
+
nil
|
41
46
|
end
|
42
|
-
rescue Errno::ENOENT
|
43
|
-
nil
|
44
|
-
end
|
45
47
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
def version(_node, _group)
|
49
|
+
# not supported
|
50
|
+
[]
|
51
|
+
end
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
+
def get_version(_node, _group, _oid)
|
54
|
+
'not supported'
|
55
|
+
end
|
53
56
|
end
|
54
57
|
end
|
55
58
|
end
|
data/lib/oxidized/output/git.rb
CHANGED
@@ -1,195 +1,220 @@
|
|
1
1
|
module Oxidized
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
class GitError < OxidizedError; end
|
6
|
-
begin
|
7
|
-
require 'rugged'
|
8
|
-
rescue LoadError
|
9
|
-
raise OxidizedError, 'rugged not found: sudo gem install rugged'
|
10
|
-
end
|
2
|
+
module Output
|
3
|
+
class Git < Output
|
4
|
+
using Refinements
|
11
5
|
|
12
|
-
|
6
|
+
class GitError < OxidizedError; end
|
7
|
+
begin
|
8
|
+
require 'rugged'
|
9
|
+
rescue LoadError
|
10
|
+
raise OxidizedError, 'rugged not found: sudo gem install rugged'
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
super
|
16
|
-
@cfg = Oxidized.config.output.git
|
17
|
-
end
|
13
|
+
attr_reader :commitref
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
Oxidized.
|
22
|
-
Oxidized.asetus.user.output.git.email = 'o@example.com'
|
23
|
-
Oxidized.asetus.user.output.git.repo = File.join(Config::ROOT, 'oxidized.git')
|
24
|
-
Oxidized.asetus.save :user
|
25
|
-
raise NoConfig, 'no output git config, edit ~/.config/oxidized/config'
|
15
|
+
def initialize
|
16
|
+
super
|
17
|
+
@cfg = Oxidized.config.output.git
|
26
18
|
end
|
27
19
|
|
28
|
-
|
29
|
-
@cfg.
|
30
|
-
|
20
|
+
def setup
|
21
|
+
if @cfg.empty?
|
22
|
+
Oxidized.asetus.user.output.git.user = 'Oxidized'
|
23
|
+
Oxidized.asetus.user.output.git.email = 'o@example.com'
|
24
|
+
Oxidized.asetus.user.output.git.repo = File.join(Config::ROOT, 'oxidized.git')
|
25
|
+
Oxidized.asetus.save :user
|
26
|
+
raise NoConfig, "no output git config, edit #{Oxidized::Config.configfile}"
|
31
27
|
end
|
32
|
-
else
|
33
|
-
@cfg.repo = File.expand_path @cfg.repo
|
34
|
-
end
|
35
|
-
end
|
36
28
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@email = opt[:email] || @cfg.email
|
41
|
-
@opt = opt
|
42
|
-
@commitref = nil
|
43
|
-
repo = @cfg.repo
|
44
|
-
|
45
|
-
outputs.types.each do |type|
|
46
|
-
type_cfg = ''
|
47
|
-
type_repo = File.join(File.dirname(repo), type + '.git')
|
48
|
-
outputs.type(type).each do |output|
|
49
|
-
(type_cfg << output; next) unless output.name # rubocop:disable Style/Semicolon
|
50
|
-
type_file = file + '--' + output.name
|
51
|
-
if @cfg.type_as_directory?
|
52
|
-
type_file = type + '/' + type_file
|
53
|
-
type_repo = repo
|
29
|
+
if @cfg.repo.respond_to?(:each)
|
30
|
+
@cfg.repo.each do |group, repo|
|
31
|
+
@cfg.repo["#{group}="] = File.expand_path repo
|
54
32
|
end
|
55
|
-
|
33
|
+
else
|
34
|
+
@cfg.repo = File.expand_path @cfg.repo
|
56
35
|
end
|
57
|
-
update type_repo, file, type_cfg
|
58
36
|
end
|
59
37
|
|
60
|
-
|
61
|
-
|
38
|
+
def store(file, outputs, opt = {})
|
39
|
+
@msg = opt[:msg]
|
40
|
+
@user = opt[:user] || @cfg.user
|
41
|
+
@email = opt[:email] || @cfg.email
|
42
|
+
@opt = opt
|
43
|
+
@commitref = nil
|
44
|
+
repo = @cfg.repo
|
45
|
+
|
46
|
+
outputs.types.each do |type|
|
47
|
+
type_cfg = ''
|
48
|
+
type_repo = File.join(File.dirname(repo), type + '.git')
|
49
|
+
outputs.type(type).each do |output|
|
50
|
+
(type_cfg << output; next) unless output.name # rubocop:disable Style/Semicolon
|
51
|
+
type_file = file + '--' + output.name
|
52
|
+
if @cfg.type_as_directory?
|
53
|
+
type_file = type + '/' + type_file
|
54
|
+
type_repo = repo
|
55
|
+
end
|
56
|
+
update type_repo, type_file, output
|
57
|
+
end
|
58
|
+
update type_repo, file, type_cfg
|
59
|
+
end
|
62
60
|
|
63
|
-
|
64
|
-
|
65
|
-
repo = Rugged::Repository.new repo
|
66
|
-
index = repo.index
|
67
|
-
index.read_tree repo.head.target.tree unless repo.empty?
|
68
|
-
repo.read(index.get(path)[:oid]).data
|
69
|
-
rescue StandardError
|
70
|
-
'node not found'
|
71
|
-
end
|
61
|
+
update repo, file, outputs.to_cfg
|
62
|
+
end
|
72
63
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
repo
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
hash[:oid] = commit.oid
|
90
|
-
hash[:author] = commit.author
|
91
|
-
hash[:message] = commit.message
|
92
|
-
tab[i += 1] = hash
|
64
|
+
# Returns the configuration of group/node_name
|
65
|
+
#
|
66
|
+
# #fetch is called by Nodes#fetch
|
67
|
+
# Nodes#fetch creates a new Output object each time, so we cannot
|
68
|
+
# store the repo index in memory. But as we keep the repo index up
|
69
|
+
# to date on disk in #update_repo, we can read it from disk instead of
|
70
|
+
# rebuilding it each time.
|
71
|
+
def fetch(node, group)
|
72
|
+
repo, path = yield_repo_and_path(node, group)
|
73
|
+
repo = Rugged::Repository.new repo
|
74
|
+
# Read the index from disk
|
75
|
+
index = repo.index
|
76
|
+
|
77
|
+
repo.read(index.get(path)[:oid]).data
|
78
|
+
rescue StandardError
|
79
|
+
'node not found'
|
93
80
|
end
|
94
|
-
walker.reset
|
95
|
-
tab
|
96
|
-
rescue StandardError
|
97
|
-
'node not found'
|
98
|
-
end
|
99
81
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
repo = Rugged::Repository.new repo
|
104
|
-
repo.blob_at(oid, path).content
|
105
|
-
rescue StandardError
|
106
|
-
'version not found'
|
107
|
-
end
|
82
|
+
# give a hash of all oid revision for the given node, and the date of the commit
|
83
|
+
def version(node, group)
|
84
|
+
repo, path = yield_repo_and_path(node, group)
|
108
85
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
86
|
+
repo = Rugged::Repository.new repo
|
87
|
+
walker = Rugged::Walker.new(repo)
|
88
|
+
walker.sorting(Rugged::SORT_DATE)
|
89
|
+
walker.push(repo.head.target.oid)
|
90
|
+
i = -1
|
91
|
+
tab = []
|
92
|
+
walker.each do |commit|
|
93
|
+
# Diabled rubocop because the suggested .empty? does not work here.
|
94
|
+
next if commit.diff(paths: [path]).size.zero? # rubocop:disable Style/ZeroLengthPredicate
|
95
|
+
|
96
|
+
hash = {}
|
97
|
+
hash[:date] = commit.time.to_s
|
98
|
+
hash[:oid] = commit.oid
|
99
|
+
hash[:author] = commit.author
|
100
|
+
hash[:message] = commit.message
|
101
|
+
tab[i += 1] = hash
|
124
102
|
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
diff_commits = { patch: patch, stat: stat }
|
103
|
+
walker.reset
|
104
|
+
tab
|
105
|
+
rescue StandardError
|
106
|
+
'node not found'
|
130
107
|
end
|
131
108
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
109
|
+
# give the blob of a specific revision
|
110
|
+
def get_version(node, group, oid)
|
111
|
+
repo, path = yield_repo_and_path(node, group)
|
112
|
+
repo = Rugged::Repository.new repo
|
113
|
+
repo.blob_at(oid, path).content
|
114
|
+
rescue StandardError
|
115
|
+
'version not found'
|
116
|
+
end
|
136
117
|
|
137
|
-
|
118
|
+
# give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines)
|
119
|
+
def get_diff(node, group, oid1, oid2)
|
120
|
+
diff_commits = nil
|
121
|
+
repo, = yield_repo_and_path(node, group)
|
122
|
+
repo = Rugged::Repository.new repo
|
123
|
+
commit = repo.lookup(oid1)
|
124
|
+
|
125
|
+
if oid2
|
126
|
+
commit_old = repo.lookup(oid2)
|
127
|
+
diff = repo.diff(commit_old, commit)
|
128
|
+
diff.each do |patch|
|
129
|
+
if /#{node.name}\s+/ =~ patch.to_s.lines.first
|
130
|
+
diff_commits = { patch: patch.to_s, stat: patch.stat }
|
131
|
+
break
|
132
|
+
end
|
133
|
+
end
|
134
|
+
else
|
135
|
+
stat = commit.parents[0].diff(commit).stat
|
136
|
+
stat = [stat[1], stat[2]]
|
137
|
+
patch = commit.parents[0].diff(commit).patch
|
138
|
+
diff_commits = { patch: patch, stat: stat }
|
139
|
+
end
|
138
140
|
|
139
|
-
|
140
|
-
|
141
|
+
diff_commits
|
142
|
+
rescue StandardError
|
143
|
+
'no diffs'
|
144
|
+
end
|
141
145
|
|
142
|
-
|
146
|
+
private
|
143
147
|
|
144
|
-
|
145
|
-
|
148
|
+
def yield_repo_and_path(node, group)
|
149
|
+
repo, path = node.repo, node.name
|
146
150
|
|
147
|
-
|
148
|
-
return if data.empty?
|
151
|
+
path = "#{group}/#{node.name}" if group && !group.empty? && @cfg.single_repo?
|
149
152
|
|
150
|
-
|
151
|
-
if @cfg.single_repo?
|
152
|
-
file = File.join @opt[:group], file
|
153
|
-
else
|
154
|
-
repo = if repo.is_a?(::String)
|
155
|
-
File.join File.dirname(repo), @opt[:group] + '.git'
|
156
|
-
else
|
157
|
-
repo[@opt[:group]]
|
158
|
-
end
|
159
|
-
end
|
153
|
+
[repo, path]
|
160
154
|
end
|
161
155
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
156
|
+
def update(repo, file, data)
|
157
|
+
return if data.empty?
|
158
|
+
|
159
|
+
if @opt[:group]
|
160
|
+
if @cfg.single_repo?
|
161
|
+
file = File.join @opt[:group], file
|
162
|
+
else
|
163
|
+
repo = if repo.is_a?(::String)
|
164
|
+
File.join File.dirname(repo), @opt[:group] + '.git'
|
165
|
+
else
|
166
|
+
repo[@opt[:group]]
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
166
171
|
begin
|
167
|
-
Rugged::Repository.
|
168
|
-
|
169
|
-
|
172
|
+
repo = Rugged::Repository.new repo
|
173
|
+
update_repo repo, file, data
|
174
|
+
rescue Rugged::OSError, Rugged::RepositoryError => e
|
175
|
+
begin
|
176
|
+
Rugged::Repository.init_at repo, :bare
|
177
|
+
rescue StandardError => create_error
|
178
|
+
raise GitError, "first '#{e.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
|
179
|
+
end
|
180
|
+
retry
|
170
181
|
end
|
171
|
-
retry
|
172
182
|
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def update_repo(repo, file, data)
|
176
|
-
oid_old = repo.blob_at(repo.head.target_id, file) rescue nil
|
177
|
-
return false if oid_old && (oid_old.content.b == data.b)
|
178
|
-
|
179
|
-
oid = repo.write data, :blob
|
180
|
-
index = repo.index
|
181
|
-
index.add path: file, oid: oid, mode: 0o100644
|
182
183
|
|
183
|
-
repo
|
184
|
-
|
185
|
-
@
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
184
|
+
# Uploads data into file in the repo
|
185
|
+
#
|
186
|
+
# @param [String] file: the file to save the configuration to
|
187
|
+
# @param [String] data: the configuration to save
|
188
|
+
# @param [Rugged::Repository] repo: the git repository to use
|
189
|
+
#
|
190
|
+
# If Oxidized.config.output.git.single_repo = false (which is the default),
|
191
|
+
# there will one repository for each group.
|
192
|
+
#
|
193
|
+
# update_repo caches the index on disk. An index is usually used in a
|
194
|
+
# working directory and not in a bare repository, which confuses users.
|
195
|
+
# The alternative would be to rebuild the index each time, which a little
|
196
|
+
# time consuming. Caching the index in memory is difficult because a new
|
197
|
+
# Output object is created each time #store is called.
|
198
|
+
def update_repo(repo, file, data)
|
199
|
+
oid_old = repo.blob_at(repo.head.target_id, file) rescue nil
|
200
|
+
return false if oid_old && (oid_old.content.b == data.b)
|
201
|
+
|
202
|
+
oid = repo.write data, :blob
|
203
|
+
# Read the index from disk
|
204
|
+
index = repo.index
|
205
|
+
index.add path: file, oid: oid, mode: 0o100644
|
206
|
+
|
207
|
+
repo.config['user.name'] = @user
|
208
|
+
repo.config['user.email'] = @email
|
209
|
+
@commitref = Rugged::Commit.create(repo,
|
210
|
+
tree: index.write_tree(repo),
|
211
|
+
message: @msg,
|
212
|
+
parents: repo.empty? ? [] : [repo.head.target].compact,
|
213
|
+
update_ref: 'HEAD')
|
214
|
+
|
215
|
+
index.write
|
216
|
+
true
|
217
|
+
end
|
193
218
|
end
|
194
219
|
end
|
195
220
|
end
|