oxidized 0.19.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|