puts_debug "read " + __FILE__.foreground(:green) require 'tmpdir' require 'open3' require 'systemu' require 'sqlite3' module Dev class SystemCall attr_accessor :output,:error,:status,:command,:start_time,:end_time,:timeout,:timed_out,:dir,:cache, :capture_output, :capture_error, :throw_on_error def initialize(cmd) @throw_on_error=true if(cmd.kind_of?(Hash)) set_hash(cmd) else hash=Dev::Environment.s_to_hash(cmd) set_hash(hash) unless hash.nil? @command=cmd if hash.nil? end execute(@command); end def elapsed; @end_time-@start_time; end def cache_name name = @dir+"/" + @command.gsub(" ","_").gsub("\\","-").gsub("/","-") unless @dir.nil? name = @command.gsub(" ","_").gsub("\\","-").gsub("/","-") if @dir.nil? return name end def has_cache File.exist?(cache_name) end def get_hash hash = Hash.new() hash[:cmd]=@command hash[:dir]=@dir hash[:output]=@output hash[:error]=@error hash[:status]=@status hash[:start_time]=@start_time hash[:end_time]=@end_time hash[:elapsed]=elapsed.to_s hash[:time_out]=@time_out hash[:timeout]=@timeout hash[:cache]=@cache hash[:capture_output]=@capture_output hash[:capture_error]=@capture_error hash[:throw_on_error]=@throw_on_error return hash end def set_hash(hash) @command=hash[:cmd] unless hash[:cmd].nil? @dir=hash[:dir] unless hash[:dir].nil? @output=hash[:output] unless hash[:output].nil? @error=hash[:error] unless hash[:error].nil? @status=hash[:status] unless hash[:status].nil? @start_time=hash[:start_time] unless hash[:start_time].nil? @end_time=hash[:end_time] unless hash[:end_time].nil? @time_out=hash[:timeout] unless hash[:timeout].nil? @timed_out=hash[:timed_out] unless hash[:timed_out].nil? @cache=hash[:cache] unless hash[:cache].nil? @capture_output=hash[:capture_output] unless hash[:capture_output].nil? @capture_error=hash[:capture_error] unless hash[:capture_error].nil? @throw_on_error=hash[:throw_on_error] unless hash[:throw_on_error].nil? end def write_cache marshal_dump = Marshal.dump(get_hash) file=File.new(cache_name,'wb') file.write marshal_dump file.close end def load_cache file=File.open(cache_name,'rb') hash = Marshal.load file.read file.close set_hash hash end def execute(cmd) if !@cache.nil? && has_cache load_cache return end pwd=Dir.pwd @start_time=Time.now begin capture_output=true if capture_output.nil? capture_output=false if capture_output == "false" capture_error=true if capture_error.nil? capture_error=false unless capture_output capture_error=false if capture_error == "false" #puts_debug "system2('#{@dir}','#{@command}',#{@capture_output.to_s},#{@capture_error.to_s}) (in SystemCall.execute)" @status,@output,@error=system2(@dir,@command,@capture_output,@capture_error) @end_time=Time.now log rescue Exception=>e puts "error executing ruby code: #{@command}" warn "exception:" warn e.to_s @status="1" @end_time=Time.now ensure Dir.chdir(pwd) if Dir.pwd != pwd write_cache if !@cache.nil? end end def system2(working_dir,command,capture_output,capture_error) capture_output=true if capture_output.nil? capture_output=false if capture_output == "false" capture_error=true if capture_error.nil? capture_error=false unless capture_output capture_error=false if capture_error == "false" filename=Dir.tmpdir + "/" + (0...2).map{65.+(rand(25)).chr}.join filename=Dir.tmpdir + "/" + (0...2).map{65.+(rand(25)).chr}.join if File.exist? "#{filename}.out" working_dir = Dir.pwd if working_dir.nil? || working_dir.empty? status=0 output="" error="" FileUtils.rm("#{filename}.out") if File.exist? "#{filename}.out" FileUtils.rm("#{filename}.err") if File.exist? "#{filename}.err" Dir.chdir(working_dir) do if(capture_output) if(capture_error) system("#{@command} >#{filename}.out 2>#{filename}.err") else system("#{@command} >#{filename}.out") end else if(capture_error) system("#{@command} 2>#{filename}.err") else system(@command) end end end if(File.exist?("#{filename}.out")) File.open("#{filename}.out",'r') {|f| output = f.read f.close } begin FileUtils.rm("#{filename}.out") rescue warn "unable to remove file #{filename}.out" end end if(File.exist?("#{filename}.err")) File.open("#{filename}.err",'r') {|f| error = f.read f.close } begin FileUtils.rm("#{filename}.err") rescue warn "unable to remove file #{filename}.err" end end status=$?.exitstatus return status,output,error end def puts_summary puts_summary2(@throw_on_error) end def puts_summary2(throw_on_error) if(@status != 0) summary = " [".foreground(:cyan) + "X".foreground(:red).bright + "]".foreground(:cyan) + " " + @command.foreground(:green) + " has exit status of " + @status.to_s summary += " dir: " + @dir unless @dir.nil? summary += " cache: true" unless @cache.nil? summary += " capture_output: false" unless @capture_output.nil? || @capture_output puts summary puts @output if !@output.nil? warn @error if !@error.nil? throw "exit status was " + @status.to_s if throw_on_error else elapsed_str="[" + "%.0f" %(elapsed) + "s]" summary = " [".foreground(:cyan) + "+".foreground(:green) + "]".foreground(:cyan) + " " + @command.foreground(:green) + " " + elapsed_str.foreground(:cyan) summary += " dir: " + @dir unless @dir.nil? summary += " cache: true" unless @cache.nil? summary += " capture_output: false" unless @capture_output.nil? || @capture_output puts summary end end def self.puts_hash_summary(h) if(h[:status] != 0 && h[:status] != "0") summary = " [".foreground(:cyan) + "X".foreground(:red).bright + "]".foreground(:cyan) + " " + h[:cmd].foreground(:green) + " has exit status of " + h[:status].to_s summary += " dir: " + h[:dir] unless h[:dir].nil? puts summary puts h[:output] if !h[:output].nil? warn h[:error] if !h[:error].nil? throw "exit status was " + h[:status].to_s else elapsed_str="[" + "%.0f" %(h[:elapsed]) + "s]" summary = " [".foreground(:cyan) + "+".foreground(:green) + "]".foreground(:cyan) + " " + h[:cmd].foreground(:green) + " " + elapsed_str.foreground(:cyan) summary += " dir: " + h[:dir] unless h[:dir].nil? puts summary end end def user_profile ["USERPROFILE","HOME"].each {|v| return ENV[v].gsub('\\','/') unless ENV[v].nil? } dir="~" end def log filename = user_profile + "/CommandHistory.sql" sql="" if(File.exists?(filename)) begin db = SQLite3::Database.new filename @timeout=0 if @timeout.nil? @dir=Rake.original_dir() if(@dir.nil?) values = "VALUES('" + @start_time.strftime('%Y-%m-%dT%H:%M:%S') + "','" + @end_time.strftime('%Y-%m-%dT%H:%M:%S') + "','" + Time.at(elapsed).gmtime.strftime('%H:%M:%S') + "'," + @status.to_s + ",'" + @command.gsub("'","''") + "','" + @dir.to_s + "','" + @output.gsub("'", "''") + "','" + @error.gsub("'", "''") + "'," + @timeout.to_s + ")" sql="insert into Commands #{values};" db.execute(sql) db.close db=nil rescue puts "failed to execute '#{sql}'" end end end end # class SystemCall end # module Dev