six-updater 0.17.1-x86-mingw32

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.
@@ -0,0 +1,112 @@
1
+ # encoding: UTF-8
2
+
3
+ module Six
4
+ module Updater
5
+ class GitRepo
6
+ def initialize(repositories, path, depth = 1)
7
+ @repositories = repositories
8
+ @path = path
9
+ @depth = depth
10
+ Six::Updater.setup_git
11
+ end
12
+
13
+ def open
14
+ repository
15
+ end
16
+
17
+ def repository
18
+ @repository || Git.open(@path)
19
+ end
20
+
21
+ def log
22
+ Six::Updater.log
23
+ end
24
+
25
+ def reset(opts = {})
26
+ repository.reset(nil, opts)
27
+ end
28
+
29
+ def clone(opts = {})
30
+ repositories = @repositories.clone
31
+ done = false
32
+ opts[:depth] = @depth
33
+ while repositories.size > 0 && !done
34
+ rep = repositories.sample
35
+ repositories -= [rep]
36
+ log.info "Trying #{rep}"
37
+
38
+ begin
39
+ Git.clone(rep, @path, opts)
40
+ Git.open(@path).config("core.autocrlf", "false")
41
+ done = true
42
+ rescue
43
+ log.debug "WARNING: Failed, trying other mirrors if available"
44
+ log.debug "#{$!}"
45
+ end
46
+ end
47
+ log.warn "WARNING: Failed, was unable to clone!" unless done
48
+ done
49
+ end
50
+
51
+ def version
52
+ repository.log.first.to_s
53
+ end
54
+
55
+ def update(opts = {})
56
+ done = false
57
+ repositories = @repositories.clone
58
+ while repositories.size > 0 && !done
59
+ cfg = nil
60
+ File.open(File.join(@path, '.git/config')) { |file| cfg = file.readlines }
61
+ rep = ''
62
+ cfg.map! do |entry|
63
+ if entry[/(\t*)url \=/]
64
+ rep = repositories.sample
65
+ repositories -= [rep]
66
+ "#{$1}url = #{rep}"
67
+ else
68
+ entry
69
+ end
70
+ end
71
+ log.info "Trying #{rep}"
72
+ File.open(File.join(@path, '.git/config'), 'w') { |file| file.puts cfg }
73
+ begin
74
+ repository.config("core.autocrlf", "false")
75
+ repository.pull_legacy
76
+ done = true
77
+ rescue
78
+ log.debug "WARNING: Failed, trying other mirrors if available"
79
+ log.debug "#{$!}"
80
+ end
81
+ end
82
+ log.warn "WARNING: Failed, was unable to update!" unless done
83
+ done
84
+ end
85
+
86
+ def status(force = false)
87
+ if force || !@status
88
+ @status = status_update
89
+ end
90
+ @status
91
+ end
92
+
93
+ def check_status(type, array, msg)
94
+ str = []
95
+ if array.size > 0
96
+ str << "#{type}:"
97
+ array.each { |item| str << item[0] }
98
+ msg << str.join("\n")
99
+ end
100
+ end
101
+
102
+ def status_update
103
+ msg = []
104
+ [
105
+ ['Added', repository.status.added], ['Changed', repository.status.changed],
106
+ ['Deleted', repository.status.deleted], ['Untracked', repository.status.untracked]
107
+ ].each { |entry| check_status(entry[0], entry[1], msg) }
108
+ msg
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,348 @@
1
+ # encoding: UTF-8
2
+
3
+ module Six
4
+ module Updater
5
+ class Mod
6
+ attr_reader :changed
7
+ DEFAULT_PRIORITY = 9999
8
+ def initialize(modconfig, config)
9
+ @modconfig = modconfig
10
+ @config = config
11
+ @stat = Hash.new
12
+ @stat[:changelog] = []
13
+ @stat[:current], @stat[:previous] = "A", "B"
14
+ @path = File.join(self.apppath, @modconfig[:folder])
15
+ get_repositories
16
+
17
+ @modconfig[:folder].gsub!('\\', '/')
18
+ @folder_str = @modconfig[:folder].clone
19
+ @folder_str.gsub!('/', '-')
20
+
21
+ if @modconfig[:versionfile]
22
+ @modconfig[:versionfile] = File.join(@config[:app_modpath], @modconfig[:folder], @modconfig[:versionfile])
23
+ else
24
+ @modconfig[:versionfile] = File.join(@config[:app_modpath], @modconfig[:folder], '.version.txt')
25
+ end
26
+
27
+ unless @modconfig[:depth]
28
+ @modconfig[:depth] = @config[:depth]
29
+ end
30
+
31
+ @changed = false
32
+
33
+ @installed = if FileTest.exists?(File.join(@path, '.rsync'))
34
+ @repository = RsyncRepo.new(@modconfig[:repository], @path, :log => log)
35
+ true
36
+ else
37
+ false
38
+ end
39
+ end
40
+
41
+ # TODO: Custom paths need more consideration, especially re the -mod= line
42
+ def apppath; @modconfig[:path] ? @modconfig[:path] : @config[:app_modpath]; end
43
+ def priority; @modconfig[:priority] ? @modconfig[:priority] : DEFAULT_PRIORITY; end
44
+ def esc(val); "\"#{val}\""; end
45
+ def log; Six::Updater.log; end
46
+ def sure?; Six::Updater.sure?; end
47
+ def log_status; log.warn "Status: #{@repository.status.join("\n")}" if @repository.status.size > 0; end
48
+ def not_a_repository; log.warn "Does not seem to be a repository!"; end
49
+
50
+ def disabled?
51
+ log.info "Mod is tagged 'disabled' in the configuration file. Skipping..." if @modconfig[:disabled]
52
+ @modconfig[:disabled]
53
+ end
54
+
55
+ def installed?
56
+ not_a_repository unless @installed
57
+ @installed
58
+ end
59
+
60
+ def skip?
61
+ log.info "Mod is tagged 'skip' in the configuration file. Skipping..." if @modconfig[:skip]
62
+ @modconfig[:skip]
63
+ end
64
+
65
+ def get_repositories
66
+ cfg = File.join(@path, '.repositories.yml')
67
+ @repositories = if FileTest.exist?(cfg)
68
+ File.open(cfg) { |file| YAML::load(file) }
69
+ elsif @modconfig[:repository].class == Array
70
+ @modconfig[:repository]
71
+ else
72
+ [@modconfig[:repository]]
73
+ end
74
+ end
75
+
76
+ def write_version
77
+ @modconfig[:versionfile][/(.*)\/(.*)/]
78
+ folder = $1
79
+ FileUtils.mkdir_p folder unless FileTest.exists? folder
80
+ begin
81
+ File.open(@modconfig[:versionfile], 'w') { |file| file.puts @stat[:current] }
82
+ true
83
+ rescue
84
+ log.warn "WARNING: Unable to write version.txt file, please make sure everything arma is closed, etc"
85
+ log.debug "#{$!}"
86
+ false
87
+ end
88
+ end
89
+
90
+ def changelog
91
+ return if self.disabled?
92
+ return unless self.installed?
93
+
94
+ unless @stat[:previous] == @stat[:current]
95
+ log.info 'Playing log...'
96
+ @stat[:changelog].each do |msg|
97
+ log.debug msg # TODO: Necessary?
98
+ puts msg
99
+ end
100
+ end
101
+ end
102
+
103
+ # RESET process (incase everything FOOKED :D)
104
+ def reset
105
+ return if self.disabled?
106
+ return unless self.installed?
107
+
108
+ log.warn "###########"
109
+ log.warn "# WARNING #"
110
+ log.warn "###########"
111
+ log.warn "You are about to reset and loose all local changes in the specified repository"
112
+ log_status
113
+ sure?
114
+ log.info 'Resetting...'
115
+ @repository.repository.reset(nil, {:hard => true})
116
+ end
117
+
118
+ # UPDATE Process
119
+ def update
120
+ if self.skip?
121
+ begin
122
+ userconfig(false)
123
+ rescue
124
+ log.warn 'WARNING: Userconfig processing is unable to complete.'
125
+ log.debug "#{$!}"
126
+ end
127
+ return
128
+ else
129
+ return if self.disabled?
130
+ end
131
+
132
+ return unless self.installed?
133
+
134
+ @stat[:previous] = @repository.version
135
+ log.info "Current Version: #{@stat[:previous]}, checking for updates..."
136
+ done = @repository.update
137
+ @stat[:current] = @repository.version
138
+
139
+ begin
140
+ @repository.status(true)
141
+ rescue
142
+ log.warn 'WARNING: Update seems to have completed but there was a status error..'
143
+ log.debug "#{$!}"
144
+ log_status
145
+ end
146
+
147
+ if @stat[:previous] == @stat[:current]
148
+ log.info "No updates found"
149
+ write_version # DO this always incase previous version.txt failed for whatever reason!
150
+ else
151
+ log.info "Applied version: #{@stat[:current]}"
152
+ @changed = true
153
+ if write_version
154
+ #write_changelog
155
+ else
156
+ @repository.reset(@stat[:previous], {:hard => true})
157
+ @changed = false
158
+ @stat[:current] = @stat[:previous]
159
+ end
160
+ end
161
+
162
+ # TODO: Detect missing / out of date config files, and notify user
163
+ begin
164
+ userconfig(false)
165
+ rescue
166
+ log.warn 'WARNING: Userconfig processing is unable to complete.'
167
+ log.debug "#{$!}"
168
+ end
169
+
170
+ unless done
171
+ log.warn 'WARNING: Update was unable to complete. This could be due to a server / connection problem, or due to files in use or out of synch repositories. Please make sure ArmA is closed, retry, otherwise reset and retry'
172
+ log_status
173
+ # TODO: Add display of stats for changed files etc
174
+ end
175
+ end
176
+
177
+ # INSTALL process
178
+ def install
179
+ log.debug "Path: #{@path}"
180
+ return if self.disabled?
181
+ if self.installed?
182
+ log.info "Already installed, trying to update..."
183
+ update
184
+ else
185
+ if FileTest.exist?(@path)
186
+ log.warn "WARNING: Folder already exists but seems incompatible. Not installing."
187
+ log.info "If you want the software to install this mod, please delete the modfolder"
188
+ else
189
+ log.info "Installing... This might take a while, please wait."
190
+ folder = ''
191
+ if @modconfig[:folder][/(.*)\/(.*)/]
192
+ basepath, subfolder = $1, $2
193
+ basepath = File.join(@config[:app_modpath], basepath)
194
+ FileUtils.mkdir_p basepath unless FileTest.exist?(basepath)
195
+ end
196
+
197
+ file = File.join(DATA_PATH, "#{@folder_str}.7z")
198
+ file = File.join(BASE_PATH, "#{@folder_str}.7z") unless File.exists?(file)
199
+ if File.exists?(file)
200
+ log.info "Found #{@folder_str}.7z, using it"
201
+ #Six::Updater.zipcheck
202
+ FileUtils.mkdir_p @path
203
+ cmd = "7z x -o#{esc(@path)} #{esc(file)}"
204
+ log.debug cmd
205
+ output = %x[#{cmd}]
206
+ log.debug output
207
+
208
+ if File.exists?(File.join(@path, ".rsync", "config.yml"))
209
+ begin
210
+ @repository = RsyncRepo.new(@modconfig[:repository], @path, :log => log)
211
+ @installed = true
212
+ get_repositories
213
+ update
214
+ rescue
215
+ @installed = false
216
+ FileUtils::rm_rf(@path) if FileTest.exist?(@path)
217
+ end
218
+ else
219
+ log.warn "WARNING: Failed to open the repository, the #{@folder_str}.7z does not seem to be correct"
220
+ log.warn "Installing from rsync network instead"
221
+ log.debug "#{$!}"
222
+ FileUtils::rm_rf(@path) if FileTest.exist?(@path)
223
+ end
224
+ end
225
+
226
+ unless @installed
227
+ @repository = RsyncRepo.new(@repositories, @path)
228
+ opts = {}
229
+ opts.merge!({:log => log}) if @config[:verbose]
230
+ @installed = @repository.clone(opts)
231
+ unless @installed
232
+ log.warn "WARNING: Failed to download the repository! This could be due to a server / connection problem. Please try again later"
233
+ end
234
+ end
235
+
236
+ if @installed
237
+ @changed = true
238
+ @stat[:previous] = nil
239
+ begin
240
+ @stat[:current] = @repository.version
241
+ write_version
242
+ rescue
243
+ log.warn 'WARNING: Post installation was unable to complete. This could be due to a server / connection problem. Please try again later'
244
+ log.debug "#{$!}"
245
+ FileUtils::rm_rf(@path) if FileTest.exist?(@path)
246
+ end
247
+ begin
248
+ userconfig
249
+ rescue
250
+ log.warn 'WARNING: Userconfig processing is unable to complete.'
251
+ log.debug "#{$!}"
252
+ end
253
+ else
254
+ FileUtils::rm_rf(@path) if FileTest.exist?(@path)
255
+ end
256
+ end
257
+ end
258
+ end
259
+
260
+ def cleanup
261
+ log.warn "CLEANUP Action unimplemented atm, please pick different action"
262
+ end
263
+
264
+ # UNINSTALL process
265
+ def uninstall
266
+ return if self.disabled?
267
+
268
+ if FileTest.exist?(@path)
269
+ log.warn "###########"
270
+ log.warn "# WARNING #"
271
+ log.warn "###########"
272
+ log.warn "You are about to uninstall the specified repository"
273
+ sure?
274
+ log.warn 'Uninstalling...'
275
+ FileUtils.rm_rf @path
276
+ end
277
+ # TODO: Cleanup Userconfig ?
278
+ end
279
+
280
+ # Process keys
281
+ def keys(force = true)
282
+ return if self.disabled?
283
+ return unless self.installed?
284
+
285
+ path = File.join(@path, 'store', 'keys.tar')
286
+ path = File.join(@path, 'store', 'keys') unless File.exists?(path)
287
+ path = File.join(@path, 'keys') unless File.directory?(path)
288
+ if File.exists?(path)
289
+ log.info "Found keys, processing..."
290
+ k_path = File.join(@config[:app_path], 'keys')
291
+ if File.directory? path
292
+ Dir[File.join(path, '*.bikey')].each do |key|
293
+ key[/(.*)\/(.*)/]
294
+ path, file = $1, $2
295
+ file[/(.*)_(.*)\.bikey/]
296
+ prefix, suffix = $1, $2
297
+ if suffix && prefix
298
+ if suffix[/(\D*)\d*/]
299
+ suf = $1
300
+ Dir[File.join(k_path, "#{prefix}_#{suf}*.bikey")].each { |delkey| FileUtils.rm_f(delkey) } if suf
301
+ end
302
+ end
303
+ FileUtils.cp(key, k_path)
304
+ end
305
+ else
306
+ # TODO: Cleanup old keys, Ruby Tar library, examine content? - tarruby doesn't build on 1.9.1. mingw
307
+ cmd = "7z x #{esc(path)} -o #{esc(@config[:app_path])}"
308
+ cmd.gsub!("/", "\\")
309
+ system cmd
310
+ end
311
+ end
312
+ end
313
+
314
+ # Process userconfigs
315
+ # TODO: Add this processing to update, aka; IF userconfig has changed THEN update it
316
+ def userconfig(force = true)
317
+ return if self.disabled?
318
+ return unless self.installed?
319
+
320
+ # TODO: Process this on file level instead of folder level?
321
+ time = Time.now.to_i
322
+ f = @modconfig[:folder].clone
323
+ f.gsub!('@', '')
324
+ path = File.join(@path, 'store', 'userconfig.tar')
325
+ path = File.join(@path, 'store', 'userconfig') unless File.exists?(path)
326
+ path = File.join(@path, 'userconfig') unless File.exists?(path)
327
+ if File.exists?(path)
328
+ uconfig = File.join(@config[:app_path], 'userconfig')
329
+ uconfigpath = File.join(uconfig, f)
330
+ if !force && FileTest.exist?(uconfigpath)
331
+ log.debug "Userconfig folder already found, skipping"
332
+ return
333
+ end
334
+ log.info "Found userconfig, processing..."
335
+ FileUtils::mv(uconfigpath, "#{uconfigpath}_#{time}") if File.exists?(uconfigpath)
336
+ if File.directory? path
337
+ FileUtils::mkdir_p uconfig unless File.exists?(uconfig)
338
+ FileUtils::cp_r(path, uconfigpath)
339
+ else
340
+ cmd = "7z x #{esc(path)} -o#{esc(@config[:app_path])} -y"
341
+ cmd.gsub!("/", "\\")
342
+ system cmd
343
+ end
344
+ end
345
+ end
346
+ end
347
+ end
348
+ end