Module: Six::Updater

Defined in:
lib/six/updater.rb,
lib/six/updater-app.rb,
lib/six/updater/mod.rb,
lib/six/updater/gitrepo.rb,
lib/six/updater/options.rb,
lib/six/updater/rsyncrepo.rb

Overview

TODO: Evaluate if this module should be a class instead?

Defined Under Namespace

Classes: GitRepo, Mod, RsyncRepo

Constant Summary collapse

VERSION =
'0.22.4'
COMPONENT =
'six-updater'
LOG_LIMIT =
9999
BASE_PATH =

Fix for WinXP

if defined?(TAR2RUBYSCRIPT)
  if oldlocation
    oldlocation
  else
    Dir.pwd
  end
else
  p = Dir.pwd
  p.gsub!('\\', '/')
  p
end
DATA_PATH =
File.join(File.exists?(File.join(BASE_PATH, "legacy.txt")) ? BASE_PATH : HOME_PATH, COMPONENT)
PID_FILE =
File.join(DATA_PATH, "#{COMPONENT}.pid")
@@log =

Create loggers

Log4r::Logger.new(COMPONENT)

Class Method Summary collapse

Class Method Details

.afteractionObject



496
497
498
499
500
501
502
503
504
# File 'lib/six/updater.rb', line 496

def afteraction
  Dir.chdir(BASE_PATH)
    case RUBY_PLATFORM
      when /-mingw32$/, /-mswin32$/
        system "afteraction.bat"
      else
        system "afteraction.sh"
  end
end

.beta_msgObject



388
389
390
391
392
393
394
# File 'lib/six/updater.rb', line 388

def beta_msg
  if @beta_exe && !@beta
    log.warn "WARNING: You do not seem to be running the 'beta' modfolder, but have selected 'beta/arma2.exe'"
  elsif !@beta_exe && @beta
    log.warn "WARNING: You seem to be running the 'beta' modfolder, but have not selected 'beta/arma2.exe'"
  end
end

.createdesktopshortcutObject



577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
# File 'lib/six/updater.rb', line 577

def createdesktopshortcut
  case RUBY_PLATFORM
    when /-mingw32$/, /-mswin32$/
      begin
        desktop = Win32::Registry.open(Win32::Registry::HKEY_CURRENT_USER, DESKTOP[0])[DESKTOP[1]]
        while desktop =~ /\%(\w*)\%/ do
          desktop.sub!("%#{$1}%", ENV[$1])
        end
        shortcut desktop if File.directory? desktop
      rescue => e
        log.warn "WARNING: Problem while creating shortcut! ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
      end
    else
      log.warn "Unsupported on current Platform: #{RUBY_PLATFORM}"
  end
end

.createshortcutObject



565
566
567
# File 'lib/six/updater.rb', line 565

def createshortcut
  shortcut @config[:app_path]
end

.exitObject



482
483
484
485
# File 'lib/six/updater.rb', line 482

def exit
  FileUtils.rm_f PID_FILE if File.exist?(PID_FILE)
  Process.exit
end

.exit_appObject



400
401
402
403
# File 'lib/six/updater.rb', line 400

def exit_app
  FileUtils.rm_f PID_FILE
  exit
end

.find_process(name, path) ⇒ Object



409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
# File 'lib/six/updater.rb', line 409

def find_process(name, path)
  # TODO: Filter for process's folder.

  pids = []
  begin
    case RUBY_PLATFORM
      when /-mingw32$/, /-mswin32$/
        %x[WMIC PROCESS get Caption,ExecutablePath,ProcessId].each_line do |l| #Commandline
            line = l.clone
            line.chomp!
            line.strip!
            reg = /([0-9]*)$/
            line[reg]
            pid = $1
            next if pid.nil?
            line.sub!(reg, "")
            line.strip!
            line[/^([\w ]*\.\w*)[ ]*(.*)/]
            image, full = $1, $2
            next if image.nil?

            case image.downcase
              when name.downcase
                pid = pid.to_i
                next unless pid > 0
                unless path && !full.nil?
                  pids << pid
                  next
                end
                if File.join(path, name).gsub("/", "\\").downcase == full.downcase
                  pids << pid
                end
            end
        end
=begin
        out = %x[tasklist]
        out.split("\n").each do |line|
          if line =~ /\A#{name}[\t| ]*([0-9]*)/
            pid = $1
            if pid.size > 0
              pid = pid.to_i
              pids << pid
            end
          end
        end
=end
      else
        # TODO: Include exe/cmdnline check;
        # /proc/PID/exe
        # /proc/PID/cmdline
        %x[ps -A | grep #{name}].split("\n").each do |line|
          unless line[/grep/]
            line[/^\s*([0-9]*)/]
            pids << $1
          end
        end
    end
  rescue => e
    log.warn "Failed checking tasklist for #{name}"
    log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
  end
  pids
end

.folder_case(folder) ⇒ Object



182
183
184
185
186
187
188
189
# File 'lib/six/updater.rb', line 182

def folder_case(folder)
  case RUBY_PLATFORM
    when /-mingw32$/, /-mswin32$/
      nil
    else
      folder.downcase!
  end
end

.full_pathObject



383
384
385
# File 'lib/six/updater.rb', line 383

def full_path
  File.dirname(File.join(@config[:app_path], @config[:app_exe])).gsub("\\", "/")
end

.initializeObject



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
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
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
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
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# File 'lib/six/updater.rb', line 191

def initialize
  # Banner
  log.info "Updater (v#{VERSION}) by Sickboy <sb_at_dev-heaven.net>"
  log.info 'Run with --help for help'
  log.warn "WARNING: Please make sure anything ArmA related has been closed / shutdown, incl explorer windows, etc"
  log.debug "BASE_PATH: #{BASE_PATH}"
  log.debug "@config #{@config}"

  unless @zip7_installed ||= begin; %x[7z]; $? == 0; rescue; false; end
    puts "7z command not found"
    raise StandardError
  end

  # Process the config file
  config = "#{COMPONENT}.yml"
  config = File.join(DATA_PATH, config)
  if ARGV[0]
    # FIXME: This is not a very good catch..
    if ARGV[0][/.*\..*/]
      if File.exists?(ARGV[0])
        config = ARGV[0]
      else
        log.warn "#{ARGV[0]} not found, trying #{config}"
      end
    end
  end

  unless File.exists?(config)
    log.error "ERROR: #{config} config missing!"
    wait if @config[:wait]
    exit
  end

  cfg = YAML::load_file(config)
  unless cfg
    log.error "ERROR: #{config} seems to be invalid!"
    wait if @config[:wait]
    exit
  end

  @config.merge!(cfg)
  @config[:folders] = [] unless @config[:folders]
  @config[:server][:folders] = [] unless @config[:server][:folders]

  # Parses CLI Parameters, merges configuration and gets todo list
  parse_options

  # Determine arma distribution and location
  case RUBY_PLATFORM
    when /-mingw32$/, /-mswin32$/
      rpath = nil
      distro = "UNKNOWN"
      ex = "arma2oa.exe"
      unless @config[:app_path]
        begin
          rpath = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, ARMA2_STEAM[0] + " OA")[ARMA2_STEAM[1]]
          distro = "OA STEAM"
        rescue
          begin
            rpath = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, ARMA2_ALT[0] + " OA")[ARMA2_ALT[1]]
            distro = "OA ALT"
          rescue
            begin
              rpath = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, ARMA2[0] + " OA")[ARMA2[1]]
              distro = "OA STANDARD"
            rescue
              begin
                rpath = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, ARMA2_STEAM[0])[ARMA2_STEAM[1]]
                distro = "A2 STEAM"
                ex = "arma2.exe"
              rescue
                begin
                  rpath = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, ARMA2_ALT[0])[ARMA2_ALT[1]]
                  distro = "A2 ALT"
                  ex = "arma2.exe"
                rescue
                  begin
                    rpath = Win32::Registry.open(Win32::Registry::HKEY_LOCAL_MACHINE, ARMA2[0])[ARMA2[1]]
                    distro = "A2 STANDARD"
                    ex = "arma2.exe"
                  rescue
                  end
                end
              end
            end
          end
        end
        @config[:app_path] = rpath if rpath
        log.info "#{distro} Distribution detected"
      end
      @config[:app_exe] = ex unless @config[:app_exe]
    else
      @config[:app_exe] = "arma2oa.exe" unless @config[:app_exe]
  end

  # Verify installation folder
  if @config[:app_path]
    log.info "ArmA Path: #{@config[:app_path]}"
    if File.exists?(@config[:app_path])
      @config[:app_path].gsub!('\\', '/')
    else
      log.error "No valid ArmA installation folder found, please abort!"
      wait if @config[:wait]
      exit
    end
  else
    log.error "No valid ArmA installation folder found, please abort!"
    wait if @config[:wait]
    exit
  end
  log.info "ArmA exe: #{@config[:app_exe]}"

  if @config[:app_modpath]
    log.info "Installation Path: #{@config[:app_modpath]}"
    if File.exists?(@config[:app_modpath])
      @config[:app_modpath].gsub!('\\', '/')
    else
      log.error "No valid Mod installation folder found, please abort!"
      wait if @config[:wait]
      exit
    end
  else
    @config[:app_modpath] = @config[:app_path]
  end

  @config[:folders].uniq!
  @config[:folders].sort! do |a, b|
    a_prio = a[:priority] ? a[:priority] : 9999
    b_prio = b[:priority] ? b[:priority] : 9999
    a_prio <=> b_prio
  end                                                
  log.debug "@config #{@config}"

  @procs = find_process(process_name, full_path)
  unless @procs.empty?
    log.warn "WARNING: Found open arma processes! #{@config[:app_exe]}, PIDs: #{@procs}, you might want to abort and close them!"
  end

  # PreProcess the config data
  @mods = []
  @mods << @config[:mods] if @config[:mods]

  @beta = false
  @beta_exe = false
  @beta_exe = true if @config[:app_exe][/beta[\/|\\]arma2.*/i]

  @config[:folders].each do |folder|
    folder_case(folder[:folder])
    folder[:folder].gsub!('\\', '/')
    unless folder[:disabled]
      if folder[:mods]
        @mods << folder[:mods]
      else
        @mods << folder[:folder]
      end
    end
  end
  @mods = @mods.join(';')

  mar = @mods.split(";").map! do |e|
    case RUBY_PLATFORM
      when /-mingw32$/, /-mswin32$/
        e.sub("/", "\\")
      else
        e
    end
  end
  mar.uniq!
  @mods = mar.join(';')

  mar.each do |m|
    case m
      when "beta", /[\/|\\]beta$/i
        @beta = true
        break
    end
  end

  # Output processed config data
  log.info "Manager for: #{@mods}"
  beta_msg

  # Prepare stats
  @stats = []
  @config[:folders].each do |folder|
    stat = Hash.new
    @stats << stat
    path = File.join(@config[:app_modpath], folder[:folder])
    stat[:changelog] = []
  end
end

.joingameObject

General Tasks



488
489
490
491
492
493
494
# File 'lib/six/updater.rb', line 488

def joingame
  cmd = ""
  cmd << " -connect=#{@config[:server][:address]}" if @config[:server][:address]
  cmd << " -port=#{@config[:server][:port]}" if @config[:server][:port]
  cmd << " -password=#{@config[:server][:password]}" if @config[:server][:password]
  startgame(cmd)
end

.killObject



569
570
571
572
573
574
575
# File 'lib/six/updater.rb', line 569

def kill
  @procs.each do |p|
    Process.kill(9, p).each do |kill| #.ProcessId
      log.debug "Killed: #{kill}"
    end        
  end
end

.logObject



396
397
398
# File 'lib/six/updater.rb', line 396

def log
  @@log
end

.parse_optionsObject



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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/six/updater/options.rb', line 9

def parse_options
  todo, general_todo, second_todo, pre_todo = [], [], [], []

  options = Hash.new
  OptionParser.new do |opts|
    $0[/.*\/(.*)/]
    opts.banner = "Usage: #{$1} [config.yml] [options]"

    opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
      options[:verbose] = v
    end

    opts.on("-i", "--install", "Installs the mods, unless already installed") do |bool|
      todo << :install if bool
    end

    opts.on("-d", "--uninstall", "Uninstalls the mods, unless not installed") do |bool|
      todo << :uninstall if bool
    end

    opts.on("-u", "--update", "Updates each mod to latest version") do |bool|
      todo << :update if bool
    end

    opts.on("-n", "--convert", "Convert each mod available on the updater network to updater") do |bool|
      todo << :convert if bool
    end

    opts.on("-r", "--reset", "Resets the modfolders to latest commit status. All modifications lost") do |bool|
      todo << :reset if bool
    end

    opts.on("-z", "--userconfig", "Processes the userconfigs of each mod. Makes backups of previous files") do |bool|
      todo << :userconfig if bool
    end

    opts.on("-k", "--keys", "Processes the keys of each mod. Removes old keys automatically") do |bool|
      todo << :keys if bool
    end

    opts.on("-l", "--changelog", "Display Changelog after update") do |bool|
      second_todo << :changelog if bool
    end

    opts.on("-c", "--cleanup", "Cleans up the modfolders git repositories") do |bool|
      second_todo << :cleanup if bool
    end

    opts.on("-a", "--afteraction", "Runs user-configurable after-action script") do |bool|
      general_todo << :afteraction if bool
    end

    opts.on("-s", "--createshortcut", "Creates shortcut to run the game with the mods, in installation folder") do |bool|
      general_todo << :createshortcut if bool
    end

    opts.on("-t", "--createdesktopshortcut", "Creates shortcut to run the game with the mods, on the desktop") do |bool|
      general_todo << :createdesktopshortcut if bool
    end

    opts.on("-j", "--join", "Starts the game with #{@config[:app_params]} -mod=#{@mods} -connect=#{@config[:server][:address]} -port=#{@config[:server][:port]}") do |bool|
      general_todo << :joingame if bool
    end

    opts.on("-g", "--startgame", "Starts the game with #{@config[:app_params]} -mod=#{@mods}") do |bool|
      general_todo << :startgame if bool
    end

    opts.on("-w", "--wait", "Waits at the end for user pressing ENTER") do |bool|
      options[:wait] = bool
    end

    opts.on("-f", "--force", "Forces to run tasks even though no changes were detected") do |bool|
      options[:force] = bool
    end

    opts.on("-q", "--kill", "Kills the open processes") do |bool|
      pre_todo << :kill if bool
    end

    opts.on("--mods S", String, "Additional Mods") do |s|
      options[:mods] = s
    end

    opts.on("--apppath S", String, "Destination folder") do |s|
      options[:app_path] = s
    end
  end.parse!

  default = if (todo + second_todo + general_todo + pre_todo).size > 0
    false
  else
    true
  end

  # TODO: Move this to Updater ?
  @todo = if todo.size > 0
    todo
  else
    log.info "No parameters given, running the default"
    #options[:wait] = true
    if default
      @config[:defaultactions]
    else
      []
    end
  end

  @pre_todo = pre_todo
  @general_todo = if general_todo.size > 0
    general_todo
  else
    if default
      @config[:defaultgeneralactions]
    else
      []
    end
  end

  @second_todo = if second_todo.size > 0
    second_todo
  else
    if default
      @config[:defaultsecondactions]
    else
      []
    end
  end
  @config = @config.merge(options)
end

.process_nameObject



473
474
475
# File 'lib/six/updater.rb', line 473

def process_name
  @process_name ||= File.basename(@config[:app_exe])
end

.shortcut(path) ⇒ Object



534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
# File 'lib/six/updater.rb', line 534

def shortcut(path)
  case RUBY_PLATFORM
    when /-mingw32$/, /-mswin32$/
      cwd = Dir.pwd
      Dir.chdir path
      mods = @mods.clone
      mods.gsub!(/\//, '-')
      mods.gsub!(/\\/, '-')
      mods2 = @mods.clone
      case RUBY_PLATFORM
        when /-mingw32$/, /-mswin32$/
          mods2.gsub!('/', '\\')
      end
      name = "Play ArmA2 with #{mods}.lnk"
      begin
        Win32::Shortcut.new(name) do |shortcut|
          shortcut.description = "Start Arma2 with #{mods2}"
          shortcut.path = File.join(@config[:app_path], @config[:app_exe])
          shortcut.working_directory = @config[:app_path]
          shortcut.arguments = "#{@config[:app_params]} \"-mod=#{mods2}\""
        end
        log.info "Created shortcut (in #{path}): #{name}"
      rescue => e
        log.warn "WARNING: Problem while creating shortcut! ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
      end
      Dir.chdir cwd
    else
      log.warn "Unsupported on current Platform: #{RUBY_PLATFORM}"
  end
end

.startgame(cmd = nil) ⇒ Object



506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
# File 'lib/six/updater.rb', line 506

def startgame(cmd = nil)
  log.info "Starting the game #{@config[:app_exe]} from #{@config[:app_path]}"
  log.info "#{@config[:app_params]} -mod=#{@mods}#{cmd}"

  case RUBY_PLATFORM
    when /-mingw32$/, /-mswin32$/
      begin
        struct = Process.create(
          :app_name         => File.join(@config[:app_path], @config[:app_exe]),
          :command_line     => " #{@config[:app_params]} \"-mod=#{@mods}#{cmd}\"",
          :creation_flags   => Process::DETACHED_PROCESS,
          :process_inherit  => false,
          :thread_inherit   => false,
          :cwd              => @config[:app_path],
          :inherit          => false
          #:environment      => ""
        )
      rescue => e
        log.warn "WARNING: Something went wrong starting the app: #{@config[:app_exe]}"
        log.debug "ERROR: #{e.class} #{e.message} #{e.backtrace.join("\n")}"
      end
    else
      Dir.chdir(@config[:app_path]) do
        system "#{@config[:app_exe]} #{@config[:app_params]} \"-mod=#{@mods}#{cmd}\""
      end
  end
end

.sure?Boolean

Returns:

  • (Boolean)


477
478
479
480
# File 'lib/six/updater.rb', line 477

def sure?
  log.info "Are you really sure? Please press Enter to continue, or close the application to abort."
  wait
end

.uninstallObject



594
595
596
597
598
599
600
601
602
603
# File 'lib/six/updater.rb', line 594

def uninstall
  log.warn "Uninstall feature temporary disabled. Please delete the modfolder manually for uninstall"
=begin
    @config[:folders].each do |config|
      log.info "= #{config[:folder]}"
      mod = Mod.new(config, @config)
      mod.uninstall
    end
=end
end

.waitObject



405
406
407
# File 'lib/six/updater.rb', line 405

def wait
  STDIN.gets
end