Class: Six::Updater::Mod

Inherits:
Object
  • Object
show all
Defined in:
lib/six/updater/mod.rb

Constant Summary collapse

DEFAULT_PRIORITY =
9999

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(modconfig, config) ⇒ Mod

Returns a new instance of Mod.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/six/updater/mod.rb', line 8

def initialize(modconfig, config)
  @modconfig = modconfig
  @config = config
  @stat = Hash.new
  @stat[:changelog] = []
  @stat[:current], @stat[:previous] = "A", "B"
  @path = File.join(self.apppath, @modconfig[:folder])
  get_repositories

  #@modconfig[:folder].gsub!('\\', '/') # handled in updater atm..
  @folder_str = @modconfig[:folder].clone
  @folder_str.gsub!('/', '-')

  if @modconfig[:versionfile]
    @modconfig[:versionfile] = File.join(@config[:app_modpath], @modconfig[:folder], @modconfig[:versionfile])
  else
    @modconfig[:versionfile] = File.join(@config[:app_modpath], @modconfig[:folder], '.version.txt')
  end

  unless @modconfig[:depth]
    @modconfig[:depth] = @config[:depth]
  end

  @changed = false

  @installed = if FileTest.exists?(File.join(@path, '.rsync'))
    @repository = RsyncRepo.new(@modconfig[:repository], @path, :log => log)
    true
  else
    false
  end
end

Instance Attribute Details

#changedObject (readonly)

Returns the value of attribute changed.



6
7
8
# File 'lib/six/updater/mod.rb', line 6

def changed
  @changed
end

Instance Method Details

#apppathObject

TODO: Custom paths need more consideration, especially re the -mod= line



42
# File 'lib/six/updater/mod.rb', line 42

def apppath; @modconfig[:path] ? @modconfig[:path] : @config[:app_modpath]; end

#changelogObject



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/six/updater/mod.rb', line 87

def changelog
  return if self.disabled?
  return unless self.installed?

  unless @stat[:previous] == @stat[:current]
    log.info 'Playing log...'
    @stat[:changelog].each do |msg|
      log.debug msg # TODO: Necessary?
      puts msg
    end
  end
end

#cleanupObject



313
314
315
# File 'lib/six/updater/mod.rb', line 313

def cleanup
  log.warn "CLEANUP Action unimplemented atm, please pick different action"
end

#convertObject

Convert process



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/six/updater/mod.rb', line 116

def convert
  return if self.disabled?
  return if self.skip?
  if @installed
    log.warn "Already a six-updater repository, not converting."
  else
    unless File.directory?(@path)
      log.warn "Modfolder doesn't exist"
      return
    end
    opts = {}
    opts.merge!({:log => log}) if @config[:verbose]
    @repository = RsyncRepo.new(@modconfig[:repository], @path, :log => log)
    begin
      @repository.convert(opts)
    rescue => e
      log.warn 'WARNING: Error during conversion..'
      log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"            
    end
  end
end

#disabled?Boolean

Returns:

  • (Boolean)


50
51
52
53
# File 'lib/six/updater/mod.rb', line 50

def disabled?
  log.info "Mod is tagged 'disabled' in the configuration file. Skipping..." if @modconfig[:disabled]
  @modconfig[:disabled]
end

#esc(val) ⇒ Object



44
# File 'lib/six/updater/mod.rb', line 44

def esc(val); "\"#{val}\""; end

#force?Boolean

Returns:

  • (Boolean)


55
56
57
58
# File 'lib/six/updater/mod.rb', line 55

def force?
  log.info "Yet force is enabled, overriding disabled..." if @modconfig[:force]
  @modconfig[:force]
end

#get_repositoriesObject



70
71
72
# File 'lib/six/updater/mod.rb', line 70

def get_repositories
  @repositories ||= @modconfig[:repository].is_a?(Array) ? @modconfig[:repository] : [@modconfig[:repository]]
end

#handle_cludes(opts) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/six/updater/mod.rb', line 138

def handle_cludes(opts)
  if @modconfig.keys.include?(:include) || @modconfig.keys.include?(:exclude)
    if @modconfig.keys.include?(:include)
      opts[:include] = @modconfig[:include]
      log.info "Includes: #{@modconfig[:include].join(", ")}"
    end
    if @modconfig.keys.include?(:exclude)
      opts[:exclude] = @modconfig[:exclude]
      log.info "Excludes: #{@modconfig[:exclude].join(", ")}"
    end
  end
end

#installObject

INSTALL process



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/six/updater/mod.rb', line 214

def install
  log.debug "Path: #{@path}"
  return if self.disabled? && !self.force?
  if self.installed?
    log.info "Already installed, trying to update..."
    update
    return
  end
  if File.exists?(@path)
    log.warn "WARNING: Folder already exists but seems incompatible. Not installing."
    log.info "If you want the software to install this mod, please remove the modfolder or convert it"
    return
  end
  log.info "Installing... This might take a while, please wait."
  unless File.dirname(@modconfig[:folder]) == "."
    basepath, subfolder = File.dirname(@modconfig[:folder]), File.basename(@modconfig[:folder])
    basepath = File.join(@config[:app_modpath], basepath)
    FileUtils.mkdir_p basepath unless File.exists?(basepath)
  end

  file = File.join(DATA_PATH, "#{@folder_str}.7z")
  file = File.join(BASE_PATH, "#{@folder_str}.7z") unless File.exists?(file)
  if File.exists?(file)
    log.info "Found #{@folder_str}.7z, using it"
    #Six::Updater.zipcheck
    FileUtils.mkdir_p @path
    log.debug unpack(file, @path)

    if File.exists?(File.join(@path, ".rsync", "config.yml"))
      begin
        @repository = RsyncRepo.new(@modconfig[:repository], @path, :log => log)
        @installed = true
        get_repositories
        update
      rescue => e
        @installed = false
        #FileUtils::rm_rf(@path) if File.exists?(@path)
      end
    else
      log.warn "WARNING: Failed to open the repository, the #{@folder_str}.7z does not seem to be correct"
      log.warn "Installing from rsync network instead"
      log.debug "#{$!}"
      FileUtils::rm_rf(@path) if File.exists?(@path)
    end
  end

  unless @installed
    @repository = RsyncRepo.new(@repositories, @path)
    opts = {}
    opts.merge!({:log => log}) if @config[:verbose]
    handle_cludes(opts)
    begin
      @repository.clone(opts)
      @installed = true
    rescue => e
      log.warn "WARNING: Failed to download the repository! This could be due to a server / connection problem. Please try again later"
      log.debug "#{e.class}: #{e.message} #{e.backtrace.join("\n")}"
    end
  end

  if @installed
    @changed = true
    @stat[:previous] = nil
    begin
      @stat[:current] = @repository.version
      log.info "Current version: #{@stat[:current]}"
      write_version
    rescue => e
      log.warn 'WARNING: Post installation was unable to complete. This could be due to a server / connection problem. Please try again later'
      log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
      #FileUtils::rm_rf(@path) if File.exists?(@path)
    end
    begin
      userconfig
    rescue => e
      log.warn 'WARNING: Userconfig processing is unable to complete.'
      log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
    end
  else
    # FileUtils::rm_rf(@path) if File.exists?(@path)
  end
end

#installed?Boolean

Returns:

  • (Boolean)


60
61
62
63
# File 'lib/six/updater/mod.rb', line 60

def installed?
  not_a_repository unless @installed
  @installed
end

#keys(force = true) ⇒ Object

Process keys



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
# File 'lib/six/updater/mod.rb', line 334

def keys(force = true)
  return if self.disabled? && !self.force?
  return unless self.installed?

  path = File.join(@path, 'store', 'keys.tar')
  path = File.join(@path, 'store', 'keys') unless File.exists?(path)
  path = File.join(@path, 'keys') unless File.directory?(path)
  if File.exists?(path)
    log.info "Found keys, processing..."
    k_path = File.join(@config[:app_path], 'keys')
    FileUtils.mkdir_p(k_path) unless File.exists?(k_path)
    unless File.directory?(k_path)
      log.warn "WARNING: Keys folder not existing (or is file), aborting"
      return
    end
    if File.directory? path
      Dir[File.join(path, '*.bikey')].each do |key|
        path, file = File.dirname(key), File.basename(key)
        file[/(.*)_(.*)\.bikey/]
        prefix, suffix = $1, $2
        if suffix && prefix
          if suffix[/(\D*)\d*/]
            suf = $1
            Dir[File.join(k_path, "#{prefix}_#{suf}*.bikey")].each { |delkey| FileUtils.rm_f(delkey) } if suf
          end
        end
        FileUtils.cp(key, k_path)
      end
    else
      # TODO: Cleanup old keys, Ruby Tar library, examine content? - tarruby doesn't build on 1.9.1. mingw
      unpack(path, @config[:app_path])
    end
  end
end

#logObject



45
# File 'lib/six/updater/mod.rb', line 45

def log; Six::Updater.log; end

#log_statusObject



47
# File 'lib/six/updater/mod.rb', line 47

def log_status; log.warn "Status: #{@repository.status.join("\n")}" if @repository.status.size > 0; end

#not_a_repositoryObject



48
# File 'lib/six/updater/mod.rb', line 48

def not_a_repository; log.warn "Does not seem to be a repository!"; end

#priorityObject



43
# File 'lib/six/updater/mod.rb', line 43

def priority; @modconfig[:priority] ? @modconfig[:priority] : DEFAULT_PRIORITY; end

#resetObject

RESET process (incase everything FOOKED :D)



101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/six/updater/mod.rb', line 101

def reset
  return if self.disabled?
  return unless self.installed?

  log.warn "###########"
  log.warn "# WARNING #"
  log.warn "###########"
  log.warn "You are about to reset and loose all local changes in the specified repository"
  log_status
  sure?
  log.info 'Resetting...'
  @repository.repository.reset(nil, {:hard => true})
end

#skip?Boolean

Returns:

  • (Boolean)


65
66
67
68
# File 'lib/six/updater/mod.rb', line 65

def skip?
  log.info "Mod is tagged 'skip' in the configuration file. Skipping..." if @modconfig[:skip]
  @modconfig[:skip]
end

#sure?Boolean

Returns:

  • (Boolean)


46
# File 'lib/six/updater/mod.rb', line 46

def sure?; Six::Updater.sure?; end

#uninstallObject

UNINSTALL process



318
319
320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/six/updater/mod.rb', line 318

def uninstall
  return if self.disabled?

  if File.exists?(@path)
    log.warn "###########"
    log.warn "# WARNING #"
    log.warn "###########"
    log.warn "You are about to uninstall the specified repository"
    sure?
    log.warn 'Uninstalling...'
    FileUtils.rm_rf @path
  end
  # TODO: Cleanup Userconfig ?
end

#unpack(file, path = nil) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/six/updater/mod.rb', line 297

def unpack(file, path = nil)
  cmd = "7z x -y"
  cmd << " -o#{esc(path)}" if path
  cmd << " #{esc(file)}"
  case RUBY_PLATFORM
    when /-mingw32$/, /-mswin32$/
      cmd.gsub!("/", "\\")
  end

  log.debug cmd
  out = %x[#{cmd}]
  log.warn "WARNING: Error unpacking #{path}: #{out}" if $? != 0
  log.debug out
  out
end

#updateObject

UPDATE Process



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/six/updater/mod.rb', line 152

def update
  if self.skip?
    begin
      userconfig(false)
    rescue => e
      log.warn 'WARNING: Userconfig processing is unable to complete.'
      log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
    end
    return
  else
    return if self.disabled? && !self.force?
  end

  return unless self.installed?

  @stat[:previous] = @repository.version
  log.info "Current Version: #{@stat[:previous]}, checking for updates..."
  opts = {}
  handle_cludes(opts)
  done = begin; @repository.update(opts); rescue => e; log.debug "#{e.class} #{e.message}: #{e.backtrace.join("\n")}"; nil; end

  begin
    @stat[:current] = @repository.version
    @repository.status(true)
  rescue => e
    log.warn 'WARNING: Update seems to have completed but there was a status error..'
    log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
    log_status
  end

  if @stat[:previous] == @stat[:current]
    log.info "No updates found (Current version: #{@stat[:current]})"
    write_version # DO this always incase previous version.txt failed for whatever reason!
  else
    log.info "Applied version: #{@stat[:current]}"
    @changed = true
    if write_version
      #write_changelog
    else
      @repository.reset(@stat[:previous], {:hard => true})
      @changed = false
      @stat[:current] = @stat[:previous]
    end
  end

  # TODO: Detect missing / out of date config files, and notify user
  begin
    userconfig(false)
  rescue => e
    log.warn 'WARNING: Userconfig processing is unable to complete.'
    log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
  end

  unless done
    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'
    log_status
    true
    # TODO: Add display of stats for changed files etc
  end
end

#userconfig(force = true) ⇒ Object

Process userconfigs TODO: Add this processing to update, aka; IF userconfig has changed THEN update it



371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
# File 'lib/six/updater/mod.rb', line 371

def userconfig(force = true)
  return if self.disabled?
  return unless self.installed?

  # TODO: Process this on file level instead of folder level?
  time = Time.now.to_i
  f = @modconfig[:folder].clone
  f.gsub!('@', '')
  path = File.join(@path, 'store', 'userconfig.tar')
  path = File.join(@path, 'store', 'userconfig') unless File.exists?(path)
  path = File.join(@path, 'userconfig') unless File.exists?(path)
  if File.exists?(path)
    uconfig = File.join(@config[:app_path], 'userconfig')
    uconfigpath = File.join(uconfig, f)
    if !force && File.exists?(uconfigpath)
      log.debug "Userconfig folder already found, skipping"
      return
    end
    log.info "Found userconfig, processing..."
    FileUtils::mv(uconfigpath, "#{uconfigpath}_#{time}") if File.exists?(uconfigpath)
    if File.directory? path
      FileUtils::mkdir_p uconfig unless File.exists?(uconfig)
      unless File.directory?(uconfig)
        log.warn "WARNING: Userconfig folder not existing (or is file), aborting"
        return
      end
      FileUtils::cp_r(path, uconfigpath)
    else
      unpack(path, @config[:app_path])
    end
  end
end

#write_versionObject



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/six/updater/mod.rb', line 74

def write_version
  folder = File.dirname(@modconfig[:versionfile])
  FileUtils.mkdir_p folder unless File.exists? folder
  begin
    File.open(@modconfig[:versionfile], 'w') { |file| file.puts @stat[:current] }
    true
  rescue => e
    log.warn "WARNING: Unable to write version.txt file, please make sure everything arma is closed, etc"
    log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
    false
  end
end