class Sixconfig < ActiveRecord::Base has_and_belongs_to_many :mods belongs_to :queryserver belongs_to :server belongs_to :appsetting belongs_to :action six_guid def from_updater_yml(yml) yml.each_pair do |key, value| end end def all_mods(srv = self.get_server, setting = Appsetting.new) m = [] m += srv.mods if srv self.mods.each { |mod| m << mod unless m.include?(mod) } if setting.beta t = setting.found_type if t t::DEFAULT_BETA_MODS.each do |mf| mod = Mod.find_by_name(mf) next unless mod m << mod unless m.include?(mod) end end end m.each {|mod| if (mod.new_record? && !mod.exists?(self.appsetting)); mod.disabled = true; end } ms = [] m.each {|mod| ms += mod.all_dependentmods; ms << mod } ms.uniq end def exec "" end def execute(action, setting, server, autoskip, inweb) #self.auto_skip_status(setting, server, false) if autoskip h = self.output_yml(setting, server) cl = "" if action action.tasks.each do |task| cl += " --#{task}" unless task == "Default" end end if inweb Sixconfig.start_updater_inweb(cl) return h end case RUBY_PLATFORM when /-mingw32$/, /-mswin32$/ cl += " --wait" end Sixconfig.start_updater(cl) h end def clear_skip_status(server_override = nil) self.all_mods(server_override).each do |mod| mod.skip = false mod.save end end def get_server if self.queryserver.nil? if self.server.nil? return nil else begin self.server rescue end end else begin self.queryserver rescue end end end def auto_skip_status(setting_override = false, server_override = nil, force = false) setting = if setting_override setting_override else self.appsetting end srv = if server_override server_override else self.get_server end setting = Appsetting.new unless setting self.all_mods(srv, setting).each do |mod| if force mod.skip = false else mod.update_version(setting.real_modpath) mod.update_skip end mod.save end end def output_yml(setting = nil, server = nil) yml = self.to_updater_yml(setting, server) File.open(File.join(SixUpdaterWeb::DATA_PATH, 'six-updater.yml'), 'w') do |file| file.puts yml.to_yaml end yml end def to_updater_yml(setting_override = nil, server_override = nil) setting = if setting_override setting_override else self.appsetting end srv = if server_override server_override else self.get_server end setting = Appsetting.new unless setting hash = setting.to_updater_yml hash[:folders] = [] self.all_mods(srv, setting).each do |mod| y = mod.to_updater_yml hash[:folders] << y unless hash[:folders].include?(y) end hash[:server] = srv.to_updater_yml if srv hash end def self.backtrace(e, log) log.info "ERROR!!! #{e.class}: #{e.message} #{e.backtrace.join("\n")}" end def self.exec # Dirty workaround for Windows six-updater.rb inside BASE_PATH will take precedence over ruby\bin\six-updater(.bat) case RUBY_PLATFORM when /-mingw32$/, /-mswin32$/ "six-updater.bat" else "six-updater" end end def imp(setting = Appsetting.new) Mod.find(:all).each do |mod| mod.update_version(setting.real_path) mod.save if mod.changed? next unless mod.installed? self.mods << mod unless self.mods.include?(mod) end end def self.start_updater(cl) SixUpdaterWeb.run_program(self.exec, SixUpdaterWeb::BASE_PATH, cl) end def self.process_msg(msg, messages, ses, previous_r = nil) # Create new logentry when no previous_r is found entry = previous_r ? previous_r : Log.new(:logsession_id => ses) entry.content = msg #p [msg, entry] # Set new previous_r unless last message had return previous_r = msg[/\n$/] ? nil : entry #&& ! msg[/.+\r\n$/] messages << entry unless messages.include?(entry) previous_r end # TODO: On Windows, use the wrapper, and SIX-SHEBANG # While on linux we could simply use normal IO.popen as the exitstatus is fine there? # TODO: FIXME, Can't run this in development atm! def self.start_updater_inweb(cli) logger.info "Starting #{exec} with #{cli} from #{SixUpdaterWeb::BASE_PATH}" ActiveRecord::Base.connection_pool.clear_stale_cached_connections! Thread.new(cli, logger) do |cl, log| Dir.chdir SixUpdaterWeb::BASE_PATH do |dir| # Setup session ses = Logsession.new ses.save ses = ses.id # Workaround for some issue with throwing around this record, in development mode. messages, buff = [], [] shebang = nil found_r, previous_r = nil, nil status = nil cmd = case RUBY_PLATFORM when /-mingw32$/, /-mswin32$/ "ruby \"#{File.join(RAILS_ROOT, "lib", "wrapper.rb")}\" #{exec} #{cl}" else "#{exec} #{cl}" end begin status = IO.popen(cmd) do |io_out| #Open3.popen3("#{exec} #{cl}") do |io_in, io_out, io_err, waitth| previous = Time.now #io_in.close io_out.sync = true io_out.each_byte do |b| begin char = b.chr case RUBY_PLATFORM when /-mingw32$/, /-mswin32$/ if found_r # Found \r found_r = false if ["\n"].include?(char) # Line ending: Add to buffer, then process it buff << char msg = buff.join("") buff = [] if msg =~ /^SIX-SHEBANG: / shebang = msg else previous_r = process_msg(msg, messages, ses, previous_r) end else # Other char; Process buffer, then add it to a new buffer msg = buff.join("") buff = [] if msg =~ /^SIX-SHEBANG: / shebang = msg else previous_r = process_msg(msg, messages, ses, previous_r) end found_r = true if ["\r"].include?(char) buff << char end else # Default processing buff << char case char when "\r" found_r = true when "\n" msg = buff.join("") buff = [] if msg =~ /^SIX-SHEBANG: / shebang = msg else previous_r = process_msg(msg, messages, ses, previous_r) end end end else # Default processing buff << char if ["\r","\n"].include?(char) msg = buff.join("") buff = [] #if msg =~ /^SIX-SHEBANG: / # shebang = msg #else previous_r = process_msg(msg, messages, ses, previous_r) #end end end rescue => e backtrace(e, log) end unless messages.empty? # Write the messages buffer to database # only check every 2 seconds if Time.now - previous > 2 previous = Time.now done = [] messages.uniq! begin messages.each {|msg| msg.save; done << msg} rescue => e backtrace(e, log) end messages -= done end end end #status = waitth.value end rescue => e backtrace(e, log) end pid, status = nil, 1 case RUBY_PLATFORM when /-mingw32$/, /-mswin32$/ # Handle last bits in the buffer unless buff.empty? msg = buff.join("") if msg =~ /^SIX-SHEBANG: / shebang = msg else previous_r = process_msg(msg, messages, ses, previous_r) end end # Handle status and pid if shebang if shebang[/^SIX-SHEBANG: (-?.*), (-?.*)/] pid = $1.to_i if $1 status = $2.to_i if $2 end end else # Handle last bits in the buffer unless buff.empty? msg = buff.join("") previous_r = process_msg(msg, messages, ses, previous_r) end # Handle status and pid pid, status = $?.pid, $?.exitstatus end if status > 0 messages << Log.new(:logsession_id => ses, :content => "Abnormal program termination. #{pid}: #{status}") else messages << Log.new(:logsession_id => ses, :content => "Normal program termination. #{pid}: #{status}") end unless messages.empty? i = 0; done = false until done || i > 3 i += 1 begin messages.each {|msg| msg.save} done = true rescue => e backtrace(e, log) sleep 2 end end end end ActiveRecord::Base.connection_pool.clear_stale_cached_connections! end sleep 2 end end