oxidized 0.19.0 → 0.20.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/CHANGELOG.md +17 -0
- data/Dockerfile +17 -2
- data/Gemfile +0 -1
- data/Gemfile.lock +10 -9
- data/README.md +205 -10
- data/extra/auto-reload-config.runit +1 -1
- data/extra/oxidized.init +3 -3
- data/extra/update-ca-certificates.runit +7 -0
- data/lib/oxidized/config.rb +4 -2
- data/lib/oxidized/config/vars.rb +5 -1
- data/lib/oxidized/hook/exec.rb +1 -0
- data/lib/oxidized/hook/slackdiff.rb +34 -0
- data/lib/oxidized/input/ssh.rb +4 -1
- data/lib/oxidized/model/aireos.rb +1 -1
- data/lib/oxidized/model/airos.rb +9 -4
- data/lib/oxidized/model/alvarion.rb +3 -1
- data/lib/oxidized/model/aosw.rb +22 -6
- data/lib/oxidized/model/asa.rb +3 -2
- data/lib/oxidized/model/cisconga.rb +19 -0
- data/lib/oxidized/model/comware.rb +6 -0
- data/lib/oxidized/model/cumulus.rb +15 -3
- data/lib/oxidized/model/fabricos.rb +2 -1
- data/lib/oxidized/model/fiberdriver.rb +4 -0
- data/lib/oxidized/model/firewareos.rb +7 -1
- data/lib/oxidized/model/fortios.rb +15 -4
- data/lib/oxidized/model/ios.rb +83 -8
- data/lib/oxidized/model/ironware.rb +5 -6
- data/lib/oxidized/model/junos.rb +3 -0
- data/lib/oxidized/model/mlnxos.rb +5 -1
- data/lib/oxidized/model/netgear.rb +32 -0
- data/lib/oxidized/model/nxos.rb +14 -1
- data/lib/oxidized/model/oneos.rb +58 -0
- data/lib/oxidized/model/opengear.rb +2 -0
- data/lib/oxidized/model/pfsense.rb +3 -2
- data/lib/oxidized/model/powerconnect.rb +1 -0
- data/lib/oxidized/model/procurve.rb +8 -3
- data/lib/oxidized/model/quantaos.rb +1 -1
- data/lib/oxidized/model/routeros.rb +8 -0
- data/lib/oxidized/model/saos.rb +3 -1
- data/lib/oxidized/model/siklu.rb +19 -0
- data/lib/oxidized/model/timos.rb +16 -0
- data/lib/oxidized/model/tplink.rb +65 -0
- data/lib/oxidized/model/voltaire.rb +56 -0
- data/lib/oxidized/model/voss.rb +33 -0
- data/lib/oxidized/model/zhoneolt.rb +52 -0
- data/lib/oxidized/node.rb +39 -10
- data/lib/oxidized/nodes.rb +2 -1
- data/lib/oxidized/output/gitcrypt.rb +244 -0
- data/lib/oxidized/source/csv.rb +10 -1
- data/lib/oxidized/source/http.rb +24 -7
- data/lib/oxidized/version.rb +1 -1
- data/lib/oxidized/worker.rb +3 -2
- data/oxidized.gemspec +2 -1
- metadata +29 -4
@@ -0,0 +1,56 @@
|
|
1
|
+
class VOLTAIRE < Oxidized::Model
|
2
|
+
|
3
|
+
prompt /([\w.@()-\[:\s\]]+[#>]\s|(One or more tests have failed.*))$/
|
4
|
+
comment '## '
|
5
|
+
|
6
|
+
# Pager Handling
|
7
|
+
expect /.+lines\s\d+\-\d+([\s]|\/\d+\s\(END\)\s).+$/ do |data, re|
|
8
|
+
send ' '
|
9
|
+
data.sub re, ''
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
cmd :all do |cfg|
|
14
|
+
cfg.gsub! /\[\?1h=\r/, '' # Pager Handling
|
15
|
+
cfg.gsub! /\r\[K/,'' # Pager Handling
|
16
|
+
cfg.gsub! /\s/, '' # Linebreak Handling
|
17
|
+
cfg.gsub! /^CPU\ load\ averages\:\s.+/, '' # Omit constantly changing CPU info
|
18
|
+
cfg.gsub! /^System\ memory\:\s.+/, '' # Omit constantly changing memory info
|
19
|
+
cfg.gsub! /^Uptime\:\s.+/, '' # Omit constantly changing uptime info
|
20
|
+
cfg.gsub! /.+Generated\ at\s\d+.+/, '' # Omit constantly changing generation time info
|
21
|
+
cfg = cfg.lines.to_a[2..-3].join
|
22
|
+
end
|
23
|
+
|
24
|
+
cmd :secret do |cfg|
|
25
|
+
cfg.gsub! /(snmp-server community).*/, ' <snmp-server community configuration removed>'
|
26
|
+
cfg.gsub! /username (\S+) password (\d+) (\S+).*/, '<secret hidden>'
|
27
|
+
cfg
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
cmd 'version show' do |cfg|
|
32
|
+
comment cfg
|
33
|
+
end
|
34
|
+
|
35
|
+
cmd 'firmware-version show' do |cfg|
|
36
|
+
comment cfg
|
37
|
+
end
|
38
|
+
|
39
|
+
cmd 'remote show' do |cfg|
|
40
|
+
cfg
|
41
|
+
end
|
42
|
+
|
43
|
+
cmd 'sm-info show' do |cfg|
|
44
|
+
cfg
|
45
|
+
end
|
46
|
+
|
47
|
+
cmd ' show' do |cfg|
|
48
|
+
cfg
|
49
|
+
end
|
50
|
+
|
51
|
+
cfg :ssh do
|
52
|
+
post_login "no\n"
|
53
|
+
password /^Password:\s*/
|
54
|
+
pre_logout 'exit'
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Voss < Oxidized::Model
|
2
|
+
# Avaya VSP Operating System Software(VOSS)
|
3
|
+
# Created by danielcoxman@gmail.com
|
4
|
+
# May 9, 2017
|
5
|
+
# This was tested on vsp4k and vsp8k
|
6
|
+
|
7
|
+
comment '# '
|
8
|
+
|
9
|
+
prompt /^[^\s#>]+[#>]$/
|
10
|
+
|
11
|
+
cmd 'show sys-info' do |cfg|
|
12
|
+
comment cfg
|
13
|
+
end
|
14
|
+
|
15
|
+
# more the config rather than doing a show run
|
16
|
+
cmd 'more config.cfg' do |cfg|
|
17
|
+
cfg
|
18
|
+
cfg.gsub! /^[^\s#>]+[#>]$/, ''
|
19
|
+
cfg.gsub! /^more config.cfg/, ''
|
20
|
+
end
|
21
|
+
|
22
|
+
cfg :telnet do
|
23
|
+
username /Login: $/
|
24
|
+
password /Password: $/
|
25
|
+
end
|
26
|
+
|
27
|
+
cfg :telnet, :ssh do
|
28
|
+
pre_logout 'exit'
|
29
|
+
post_login 'enable'
|
30
|
+
post_login 'terminal more disable'
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class ZhoneOLT < Oxidized::Model
|
2
|
+
# Zhone OLT/MetroE/DSL devices (ONT uses a completely different CLI)
|
3
|
+
|
4
|
+
# the prompt can be anything on zhone, but it defaults to 'zXX>' and we
|
5
|
+
# always use hostname>
|
6
|
+
prompt /^(\r*[\w.@():-]+[>]\s?)$/
|
7
|
+
comment '# '
|
8
|
+
|
9
|
+
cmd :secret do |cfg|
|
10
|
+
cfg.gsub! /^(set configsyncpasswd = ) \S+/, '\\1 <removed>'
|
11
|
+
cfg.gsub! /^(set user-pass = ) \S+/, '\\1 <removed>'
|
12
|
+
cfg.gsub! /^(set auth-key = ) \S+/, '\\1 <removed>'
|
13
|
+
cfg.gsub! /^(set priv-key = ) \S+/, '\\1 <removed>'
|
14
|
+
cfg.gsub! /^(set ftp-password = ) \S+/, '\\1 <removed>'
|
15
|
+
cfg.gsub! /^(set community-name = ) \S+/, '\\1 <removed>'
|
16
|
+
cfg.gsub! /^(set communityname = ) \S+/, '\\1 <removed>'
|
17
|
+
cfg
|
18
|
+
end
|
19
|
+
|
20
|
+
cmd :all do |cfg|
|
21
|
+
cfg.each_line.to_a[1..-2].map{|line|line.delete("\r").rstrip}.join("\n") + "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
cmd 'swversion' do |cfg|
|
25
|
+
comment cfg
|
26
|
+
end
|
27
|
+
|
28
|
+
cmd 'slots' do |cfg|
|
29
|
+
comment cfg
|
30
|
+
end
|
31
|
+
|
32
|
+
cmd 'eeshow card' do |cfg|
|
33
|
+
comment cfg
|
34
|
+
end
|
35
|
+
|
36
|
+
cmd 'ethrpshow' do |cfg|
|
37
|
+
cfg = cfg.each_line.select { |line| line.match /Vendor (Name|OUI|Part|Revision)|Serial Number|Manufacturing Date/ }.join
|
38
|
+
comment cfg
|
39
|
+
end
|
40
|
+
|
41
|
+
cmd 'dump console' do |cfg|
|
42
|
+
cfg = cfg.each_line.select { |line| not line.match /To Abort the operation enter Ctrl-C/ }.join
|
43
|
+
end
|
44
|
+
|
45
|
+
# zhone technically supports ssh, but it locks up a ton. Especially when
|
46
|
+
# showing large amounts of output, like "dump console"
|
47
|
+
cfg :telnet do
|
48
|
+
username /\r*login:/
|
49
|
+
password /\r*password:/
|
50
|
+
pre_logout 'logout'
|
51
|
+
end
|
52
|
+
end
|
data/lib/oxidized/node.rb
CHANGED
@@ -10,8 +10,11 @@ module Oxidized
|
|
10
10
|
alias :running? :running
|
11
11
|
def initialize opt
|
12
12
|
Oxidized.logger.debug 'resolving DNS for %s...' % opt[:name]
|
13
|
+
# remove the prefix if an IP Address is provided with one as IPAddr converts it to a network address.
|
14
|
+
ip_addr, _ = opt[:ip].to_s.split("/")
|
15
|
+
Oxidized.logger.debug 'IPADDR %s' % ip_addr.to_s
|
13
16
|
@name = opt[:name]
|
14
|
-
@ip = IPAddr.new(
|
17
|
+
@ip = IPAddr.new(ip_addr).to_s rescue nil
|
15
18
|
@ip ||= Resolv.new.getaddress @name
|
16
19
|
@group = opt[:group]
|
17
20
|
@input = resolve_input opt
|
@@ -163,18 +166,32 @@ module Oxidized
|
|
163
166
|
end
|
164
167
|
|
165
168
|
def resolve_repo opt
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
169
|
+
if is_git? opt
|
170
|
+
remote_repo = Oxidized.config.output.git.repo
|
171
|
+
|
172
|
+
if remote_repo.is_a?(::String)
|
173
|
+
if Oxidized.config.output.git.single_repo? || @group.nil?
|
174
|
+
remote_repo
|
175
|
+
else
|
176
|
+
File.join(File.dirname(remote_repo), @group + '.git')
|
177
|
+
end
|
178
|
+
else
|
179
|
+
remote_repo[@group]
|
180
|
+
end
|
181
|
+
elsif is_gitcrypt? opt
|
182
|
+
remote_repo = Oxidized.config.output.gitcrypt.repo
|
183
|
+
|
184
|
+
if remote_repo.is_a?(::String)
|
185
|
+
if Oxidized.config.output.gitcrypt.single_repo? || @group.nil?
|
186
|
+
remote_repo
|
187
|
+
else
|
188
|
+
File.join(File.dirname(remote_repo), @group + '.git')
|
189
|
+
end
|
173
190
|
else
|
174
|
-
|
191
|
+
remote_repo[@group]
|
175
192
|
end
|
176
193
|
else
|
177
|
-
|
194
|
+
return
|
178
195
|
end
|
179
196
|
end
|
180
197
|
|
@@ -199,6 +216,14 @@ module Oxidized
|
|
199
216
|
end
|
200
217
|
end
|
201
218
|
|
219
|
+
#model
|
220
|
+
if Oxidized.config.models.has_key?(@model.class.name.to_s.downcase)
|
221
|
+
if Oxidized.config.models[@model.class.name.to_s.downcase].has_key?(key_str)
|
222
|
+
value = Oxidized.config.models[@model.class.name.to_s.downcase][key_str]
|
223
|
+
Oxidized.logger.debug "node.rb: setting node key '#{key}' to value '#{value}' from model"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
202
227
|
#node
|
203
228
|
value = opt[key_sym] || value
|
204
229
|
Oxidized.logger.debug "node.rb: returning node key '#{key}' with value '#{value}'"
|
@@ -209,5 +234,9 @@ module Oxidized
|
|
209
234
|
(opt[:output] || Oxidized.config.output.default) == 'git'
|
210
235
|
end
|
211
236
|
|
237
|
+
def is_gitcrypt? opt
|
238
|
+
(opt[:output] || Oxidized.config.output.default) == 'gitcrypt'
|
239
|
+
end
|
240
|
+
|
212
241
|
end
|
213
242
|
end
|
data/lib/oxidized/nodes.rb
CHANGED
@@ -4,7 +4,7 @@ module Oxidized
|
|
4
4
|
class Oxidized::NotSupported < OxidizedError; end
|
5
5
|
class Oxidized::NodeNotFound < OxidizedError; end
|
6
6
|
class Nodes < Array
|
7
|
-
attr_accessor :source
|
7
|
+
attr_accessor :source, :jobs
|
8
8
|
alias :put :unshift
|
9
9
|
def load node_want=nil
|
10
10
|
with_lock do
|
@@ -73,6 +73,7 @@ module Oxidized
|
|
73
73
|
# set last job to nil so that the node is picked for immediate update
|
74
74
|
n.last = nil
|
75
75
|
put n
|
76
|
+
jobs.want += 1 if Oxidized.config.next_adds_job?
|
76
77
|
end
|
77
78
|
end
|
78
79
|
end
|
@@ -0,0 +1,244 @@
|
|
1
|
+
module Oxidized
|
2
|
+
class GitCrypt < Output
|
3
|
+
class GitCryptError < OxidizedError; end
|
4
|
+
begin
|
5
|
+
require 'git'
|
6
|
+
rescue LoadError
|
7
|
+
raise OxidizedError, 'git not found: sudo gem install ruby-git'
|
8
|
+
end
|
9
|
+
|
10
|
+
attr_reader :commitref
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@cfg = Oxidized.config.output.gitcrypt
|
14
|
+
@gitcrypt_cmd = "/usr/bin/git-crypt"
|
15
|
+
@gitcrypt_init = @gitcrypt_cmd + " init"
|
16
|
+
@gitcrypt_unlock = @gitcrypt_cmd + " unlock"
|
17
|
+
@gitcrypt_lock = @gitcrypt_cmd + " lock"
|
18
|
+
@gitcrypt_adduser = @gitcrypt_cmd + " add-gpg-user --trusted "
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup
|
22
|
+
if @cfg.empty?
|
23
|
+
Oxidized.asetus.user.output.gitcrypt.user = 'Oxidized'
|
24
|
+
Oxidized.asetus.user.output.gitcrypt.email = 'o@example.com'
|
25
|
+
Oxidized.asetus.user.output.gitcrypt.repo = File.join(Config::Root, 'oxidized.git')
|
26
|
+
Oxidized.asetus.save :user
|
27
|
+
raise NoConfig, 'no output git config, edit ~/.config/oxidized/config'
|
28
|
+
end
|
29
|
+
|
30
|
+
if @cfg.repo.respond_to?(:each)
|
31
|
+
@cfg.repo.each do |group, repo|
|
32
|
+
@cfg.repo["#{group}="] = File.expand_path repo
|
33
|
+
end
|
34
|
+
else
|
35
|
+
@cfg.repo = File.expand_path @cfg.repo
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def crypt_init repo
|
40
|
+
repo.chdir do
|
41
|
+
system(@gitcrypt_init)
|
42
|
+
@cfg.users.each do |user|
|
43
|
+
system("#{@gitcrypt_adduser} #{user}")
|
44
|
+
end
|
45
|
+
File.write(".gitattributes", "* filter=git-crypt diff=git-crypt\n.gitattributes !filter !diff")
|
46
|
+
repo.add(".gitattributes")
|
47
|
+
repo.commit("Initial commit: crypt all config files")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def lock repo
|
52
|
+
repo.chdir do
|
53
|
+
system(@gitcrypt_lock)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def unlock repo
|
58
|
+
repo.chdir do
|
59
|
+
system(@gitcrypt_unlock)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def store file, outputs, opt={}
|
64
|
+
@msg = opt[:msg]
|
65
|
+
@user = (opt[:user] or @cfg.user)
|
66
|
+
@email = (opt[:email] or @cfg.email)
|
67
|
+
@opt = opt
|
68
|
+
@commitref = nil
|
69
|
+
repo = @cfg.repo
|
70
|
+
|
71
|
+
outputs.types.each do |type|
|
72
|
+
type_cfg = ''
|
73
|
+
type_repo = File.join(File.dirname(repo), type + '.git')
|
74
|
+
outputs.type(type).each do |output|
|
75
|
+
(type_cfg << output; next) if not output.name
|
76
|
+
type_file = file + '--' + output.name
|
77
|
+
if @cfg.type_as_directory?
|
78
|
+
type_file = type + '/' + type_file
|
79
|
+
type_repo = repo
|
80
|
+
end
|
81
|
+
update type_repo, type_file, output
|
82
|
+
end
|
83
|
+
update type_repo, file, type_cfg
|
84
|
+
end
|
85
|
+
|
86
|
+
update repo, file, outputs.to_cfg
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def fetch node, group
|
91
|
+
begin
|
92
|
+
repo, path = yield_repo_and_path(node, group)
|
93
|
+
repo = Git.open repo
|
94
|
+
unlock repo
|
95
|
+
index = repo.index
|
96
|
+
# Empty repo ?
|
97
|
+
empty = File.exists? index.path
|
98
|
+
if empty
|
99
|
+
raise 'Empty git repo'
|
100
|
+
else
|
101
|
+
File.read path
|
102
|
+
end
|
103
|
+
lock repo
|
104
|
+
rescue
|
105
|
+
'node not found'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# give a hash of all oid revision for the given node, and the date of the commit
|
110
|
+
def version node, group
|
111
|
+
begin
|
112
|
+
repo, path = yield_repo_and_path(node, group)
|
113
|
+
|
114
|
+
repo = Git.open repo
|
115
|
+
unlock repo
|
116
|
+
walker = repo.log.path(path)
|
117
|
+
i = -1
|
118
|
+
tab = []
|
119
|
+
walker.each do |commit|
|
120
|
+
hash = {}
|
121
|
+
hash[:date] = commit.date.to_s
|
122
|
+
hash[:oid] = commit.objectish
|
123
|
+
hash[:author] = commit.author
|
124
|
+
hash[:message] = commit.message
|
125
|
+
tab[i += 1] = hash
|
126
|
+
end
|
127
|
+
walker.reset
|
128
|
+
tab
|
129
|
+
rescue
|
130
|
+
'node not found'
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
#give the blob of a specific revision
|
135
|
+
def get_version node, group, oid
|
136
|
+
begin
|
137
|
+
repo, path = yield_repo_and_path(node, group)
|
138
|
+
repo = Git.open repo
|
139
|
+
unlock repo
|
140
|
+
repo.gtree(oid).files[path].contents
|
141
|
+
rescue
|
142
|
+
'version not found'
|
143
|
+
ensure
|
144
|
+
lock repo
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
#give a hash with the patch of a diff between 2 revision and the stats (added and deleted lines)
|
149
|
+
def get_diff node, group, oid1, oid2
|
150
|
+
begin
|
151
|
+
diff_commits = nil
|
152
|
+
repo, path = yield_repo_and_path(node, group)
|
153
|
+
repo = Git.open repo
|
154
|
+
unlock repo
|
155
|
+
commit = repo.gcommit(oid1)
|
156
|
+
|
157
|
+
if oid2
|
158
|
+
commit_old = repo.gcommit(oid2)
|
159
|
+
diff = repo.diff(commit_old, commit)
|
160
|
+
stats = [diff.stats[:files][node.name][:insertions], diff.stats[:files][node.name][:deletions]]
|
161
|
+
diff.each do |patch|
|
162
|
+
if /#{node.name}\s+/.match(patch.patch.to_s.lines.first)
|
163
|
+
diff_commits = {:patch => patch.patch.to_s, :stat => stats}
|
164
|
+
break
|
165
|
+
end
|
166
|
+
end
|
167
|
+
else
|
168
|
+
stat = commit.parents[0].diff(commit).stats
|
169
|
+
stat = [stat[:files][node.name][:insertions],stat[:files][node.name][:deletions]]
|
170
|
+
patch = commit.parents[0].diff(commit).patch
|
171
|
+
diff_commits = {:patch => patch, :stat => stat}
|
172
|
+
end
|
173
|
+
lock repo
|
174
|
+
diff_commits
|
175
|
+
rescue
|
176
|
+
'no diffs'
|
177
|
+
ensure
|
178
|
+
lock repo
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
private
|
183
|
+
|
184
|
+
def yield_repo_and_path(node, group)
|
185
|
+
repo, path = node.repo, node.name
|
186
|
+
|
187
|
+
if group and @cfg.single_repo?
|
188
|
+
path = "#{group}/#{node.name}"
|
189
|
+
end
|
190
|
+
|
191
|
+
[repo, path]
|
192
|
+
end
|
193
|
+
|
194
|
+
def update repo, file, data
|
195
|
+
return if data.empty?
|
196
|
+
|
197
|
+
if @opt[:group]
|
198
|
+
if @cfg.single_repo?
|
199
|
+
file = File.join @opt[:group], file
|
200
|
+
else
|
201
|
+
repo = if repo.is_a?(::String)
|
202
|
+
File.join File.dirname(repo), @opt[:group] + '.git'
|
203
|
+
else
|
204
|
+
repo[@opt[:group]]
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
begin
|
210
|
+
update_repo repo, file, data, @msg, @user, @email
|
211
|
+
rescue Git::GitExecuteError, ArgumentError => open_error
|
212
|
+
Oxidized.logger.debug "open_error #{open_error} #{file}"
|
213
|
+
begin
|
214
|
+
grepo = Git.init repo
|
215
|
+
crypt_init grepo
|
216
|
+
rescue => create_error
|
217
|
+
raise GitCryptError, "first '#{open_error.message}' was raised while opening git repo, then '#{create_error.message}' was while trying to create git repo"
|
218
|
+
end
|
219
|
+
retry
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def update_repo repo, file, data, msg, user, email
|
224
|
+
grepo = Git.open repo
|
225
|
+
grepo.config('user.name', user)
|
226
|
+
grepo.config('user.email', email)
|
227
|
+
grepo.chdir do
|
228
|
+
unlock grepo
|
229
|
+
File.write(file, data)
|
230
|
+
grepo.add(file)
|
231
|
+
if grepo.status[file].nil?
|
232
|
+
grepo.commit(msg)
|
233
|
+
@commitref = grepo.log(1).first.objectish
|
234
|
+
true
|
235
|
+
elsif !grepo.status[file].type.nil?
|
236
|
+
grepo.commit(msg)
|
237
|
+
@commitref = grepo.log(1).first.objectish
|
238
|
+
true
|
239
|
+
end
|
240
|
+
lock grepo
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|