oxidized 0.30.1 → 0.31.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/.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
|