Add SConsUI tool.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2494 bbd45198-f89e-11dd-88c7-29a3b14d5316
This commit is contained in:
parent
eef72f68de
commit
be73747fc4
|
@ -0,0 +1,409 @@
|
||||||
|
#! /usr/bin/env python
|
||||||
|
#coding=utf-8
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
py2 = py30 = py31 = False
|
||||||
|
version = sys.hexversion
|
||||||
|
if version >= 0x020600F0 and version < 0x03000000 :
|
||||||
|
py2 = True # Python 2.6 or 2.7
|
||||||
|
from Tkinter import *
|
||||||
|
import ttk
|
||||||
|
elif version >= 0x03000000 and version < 0x03010000 :
|
||||||
|
py30 = True
|
||||||
|
from tkinter import *
|
||||||
|
import ttk
|
||||||
|
elif version >= 0x03010000:
|
||||||
|
py31 = True
|
||||||
|
from tkinter import *
|
||||||
|
import tkinter.ttk as ttk
|
||||||
|
else:
|
||||||
|
print ("""
|
||||||
|
You do not have a version of python supporting ttk widgets..
|
||||||
|
You need a version >= 2.6 to execute PAGE modules.
|
||||||
|
""")
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
import ScrolledText
|
||||||
|
import tkFileDialog
|
||||||
|
import tkMessageBox
|
||||||
|
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import platform
|
||||||
|
|
||||||
|
builder = None
|
||||||
|
executor = None
|
||||||
|
lock = None
|
||||||
|
|
||||||
|
class CmdExecutor(threading.Thread):
|
||||||
|
def __init__(self, cmd, output):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.cmd = cmd
|
||||||
|
self.child = None
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
global executor
|
||||||
|
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
from win32spawn import Win32Spawn
|
||||||
|
|
||||||
|
subprocess = Win32Spawn(self.cmd)
|
||||||
|
subprocess.start_pipe()
|
||||||
|
|
||||||
|
builder.progressbar.start()
|
||||||
|
while not subprocess.is_terminated or subprocess.qsize() > 0:
|
||||||
|
try:
|
||||||
|
line = subprocess.get(timeout=1)
|
||||||
|
line = line.replace('\r', '')
|
||||||
|
if line:
|
||||||
|
lock.acquire()
|
||||||
|
builder.output.see(END)
|
||||||
|
builder.output.insert(END, line)
|
||||||
|
lock.release()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
builder.progressbar.stop()
|
||||||
|
|
||||||
|
executor = None
|
||||||
|
|
||||||
|
def ExecCmd(cmd):
|
||||||
|
global executor
|
||||||
|
if executor:
|
||||||
|
print 'cmd not exit, return'
|
||||||
|
return
|
||||||
|
|
||||||
|
executor = CmdExecutor(cmd, builder)
|
||||||
|
executor.start()
|
||||||
|
|
||||||
|
class DirSelectBox(ttk.Frame):
|
||||||
|
def __init__(self, master=None, **kw):
|
||||||
|
ttk.Frame.__init__(self, master, **kw)
|
||||||
|
self.dir_var = StringVar()
|
||||||
|
self.entry = ttk.Entry(self, textvariable = self.dir_var)
|
||||||
|
self.entry.pack(fill=BOTH, expand=1,side=LEFT)
|
||||||
|
self.entry.configure(width = 50)
|
||||||
|
|
||||||
|
self.browser_button = ttk.Button(self, text="Browser", command=self.browser)
|
||||||
|
self.browser_button.pack(side=RIGHT)
|
||||||
|
|
||||||
|
def browser(self):
|
||||||
|
dir = tkFileDialog.askdirectory(parent=self, title='Open directory', initialdir=self.dir_var.get())
|
||||||
|
if dir != '':
|
||||||
|
self.dir_var.set(dir)
|
||||||
|
|
||||||
|
def set_path(self, path):
|
||||||
|
path = path.replace('\\', '/')
|
||||||
|
self.dir_var.set(path)
|
||||||
|
|
||||||
|
def get_path(self):
|
||||||
|
return self.dir_var.get()
|
||||||
|
|
||||||
|
COMPILER = [
|
||||||
|
("GNU GCC", "GCC"),
|
||||||
|
("Keil ARMCC", "ARMCC"),
|
||||||
|
("IAR Compiler", "IAR"),
|
||||||
|
]
|
||||||
|
|
||||||
|
IDE = [
|
||||||
|
('Keil MDK4', 'mdk4'),
|
||||||
|
('Keil MDK', 'mdk'),
|
||||||
|
('IAR Compiler', 'iar')
|
||||||
|
]
|
||||||
|
|
||||||
|
class SconsUI():
|
||||||
|
def __init__(self, master=None):
|
||||||
|
style = ttk.Style()
|
||||||
|
theme = style.theme_use()
|
||||||
|
default = style.lookup(theme, 'background')
|
||||||
|
master.configure(background=default)
|
||||||
|
|
||||||
|
notebook = ttk.Notebook(master)
|
||||||
|
notebook.pack(fill=BOTH, padx=5, pady=5)
|
||||||
|
|
||||||
|
# building page
|
||||||
|
page_building = ttk.Frame(notebook)
|
||||||
|
notebook.add(page_building, padding=3)
|
||||||
|
notebook.tab(0, text='Build', underline="-1")
|
||||||
|
self.setup_building_ui(page_building)
|
||||||
|
|
||||||
|
# make project page
|
||||||
|
page_project = ttk.Frame(notebook)
|
||||||
|
notebook.add(page_project, padding = 3)
|
||||||
|
notebook.tab(1, text = 'Project', underline = '-1')
|
||||||
|
self.setup_project_ui(page_project)
|
||||||
|
|
||||||
|
# setting page
|
||||||
|
page_setting = ttk.Frame(notebook)
|
||||||
|
notebook.add(page_setting, padding = 3)
|
||||||
|
notebook.tab(2, text = 'Setting', underline = '-1')
|
||||||
|
self.setup_setting_ui(page_setting)
|
||||||
|
|
||||||
|
padding = ttk.Frame(master)
|
||||||
|
padding.pack(fill=X)
|
||||||
|
quit = ttk.Button(padding, text='Quit', command = self.quit)
|
||||||
|
quit.pack(side=RIGHT)
|
||||||
|
|
||||||
|
# read setting
|
||||||
|
self.read_setting()
|
||||||
|
|
||||||
|
def read_setting(self):
|
||||||
|
import platform
|
||||||
|
import os
|
||||||
|
|
||||||
|
home = ''
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
driver = os.environ['HOMEDRIVE']
|
||||||
|
home = os.environ['HOMEPATH']
|
||||||
|
home = os.path.join(driver, home)
|
||||||
|
else:
|
||||||
|
home = os.environ['HOME']
|
||||||
|
|
||||||
|
setting_path = os.path.join(home, '.rtt_scons')
|
||||||
|
if os.path.exists(setting_path):
|
||||||
|
setting = file(os.path.join(home, '.rtt_scons'))
|
||||||
|
for line in setting:
|
||||||
|
line = line.replace('\n', '')
|
||||||
|
line = line.replace('\r', '')
|
||||||
|
if line.find('=') != -1:
|
||||||
|
items = line.split('=')
|
||||||
|
if items[0] == 'RTTRoot':
|
||||||
|
self.RTTRoot.set_path(items[1])
|
||||||
|
elif items[0] == 'BSPRoot':
|
||||||
|
self.BSPRoot.set_path(items[1])
|
||||||
|
elif items[0] == 'compiler':
|
||||||
|
compiler = items[1]
|
||||||
|
else:
|
||||||
|
self.CompilersPath[items[0]].set_path(items[1])
|
||||||
|
setting.close()
|
||||||
|
|
||||||
|
# set RT-Thread Root Directory according environ
|
||||||
|
if os.environ.has_key('RTT_ROOT'):
|
||||||
|
self.RTTRoot.set_path(os.environ['RTT_ROOT'])
|
||||||
|
|
||||||
|
# detect compiler path
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
# Keil MDK
|
||||||
|
if not self.CompilersPath['ARMCC'].get_path():
|
||||||
|
if os.path.exists('C:\\Keil'):
|
||||||
|
self.CompilersPath['ARMCC'].set_path('C:\\Keil')
|
||||||
|
elif os.path.exists('D:\\Keil'):
|
||||||
|
self.CompilersPath['ARMCC'].set_path('D:\\Keil')
|
||||||
|
elif os.path.exists('E:\\Keil'):
|
||||||
|
self.CompilersPath['ARMCC'].set_path('E:\\Keil')
|
||||||
|
elif os.path.exists('F:\\Keil'):
|
||||||
|
self.CompilersPath['ARMCC'].set_path('F:\\Keil')
|
||||||
|
elif os.path.exists('G:\\Keil'):
|
||||||
|
self.CompilersPath['ARMCC'].set_path('G:\\Keil')
|
||||||
|
|
||||||
|
# GNU GCC
|
||||||
|
if not self.CompilersPath['GCC'].get_path():
|
||||||
|
paths = os.environ['PATH']
|
||||||
|
paths = paths.split(';')
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
if path.find('CodeSourcery') != -1:
|
||||||
|
self.CompilersPath['GCC'].set_path(path)
|
||||||
|
break
|
||||||
|
elif path.find('GNU Tools ARM Embedded') != -1:
|
||||||
|
self.CompilersPath['GCC'].set_path(path)
|
||||||
|
break
|
||||||
|
|
||||||
|
def save_setting(self):
|
||||||
|
import platform
|
||||||
|
import os
|
||||||
|
|
||||||
|
home = ''
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
driver = os.environ['HOMEDRIVE']
|
||||||
|
home = os.environ['HOMEPATH']
|
||||||
|
home = os.path.join(driver, home)
|
||||||
|
else:
|
||||||
|
home = os.environ['HOME']
|
||||||
|
|
||||||
|
setting = file(os.path.join(home, '.rtt_scons'), 'wb+')
|
||||||
|
# current comiler
|
||||||
|
# line = '%s=%s\n' % ('compiler', self.compilers.get()))
|
||||||
|
line = '%s=%s\n' % ('compiler', 'iar')
|
||||||
|
setting.write(line)
|
||||||
|
|
||||||
|
# RTT Root Folder
|
||||||
|
if self.RTTRoot.get_path():
|
||||||
|
line = '%s=%s\n' % ('RTTRoot', self.RTTRoot.get_path())
|
||||||
|
setting.write(line)
|
||||||
|
|
||||||
|
# BSP Root Folder
|
||||||
|
if self.BSPRoot.get_path():
|
||||||
|
line = '%s=%s\n' % ('BSPRoot', self.BSPRoot.get_path())
|
||||||
|
setting.write(line)
|
||||||
|
|
||||||
|
for (compiler, path) in self.CompilersPath.iteritems():
|
||||||
|
if path.get_path():
|
||||||
|
line = '%s=%s\n' % (compiler, path.get_path())
|
||||||
|
setting.write(line)
|
||||||
|
|
||||||
|
setting.close()
|
||||||
|
tkMessageBox.showinfo("RT-Thread SCons UI",
|
||||||
|
"Save setting sucessfully")
|
||||||
|
|
||||||
|
def setup_building_ui(self, frame):
|
||||||
|
padding = ttk.Frame(frame)
|
||||||
|
padding.pack(fill=X)
|
||||||
|
|
||||||
|
button = ttk.Button(padding, text='Clean', command=self.do_clean)
|
||||||
|
button.pack(side=RIGHT)
|
||||||
|
button = ttk.Button(padding, text='Build', command=self.do_build)
|
||||||
|
button.pack(side=RIGHT)
|
||||||
|
label = ttk.Label(padding, relief = 'flat', text = 'Click Build or Clean to build or clean system -->')
|
||||||
|
label.pack(side=RIGHT, ipady = 5)
|
||||||
|
|
||||||
|
self.progressbar = ttk.Progressbar(frame)
|
||||||
|
self.progressbar.pack(fill=X)
|
||||||
|
|
||||||
|
separator = ttk.Separator(frame)
|
||||||
|
separator.pack(fill=X)
|
||||||
|
|
||||||
|
self.output = ScrolledText.ScrolledText(frame)
|
||||||
|
self.output.pack(fill=X)
|
||||||
|
|
||||||
|
def setup_project_ui(self, frame):
|
||||||
|
label = ttk.Label(frame, relief = 'flat', text = 'Choose Integrated Development Environment:')
|
||||||
|
label.pack(fill=X, pady = 5)
|
||||||
|
|
||||||
|
separator = ttk.Separator(frame)
|
||||||
|
separator.pack(fill=X)
|
||||||
|
|
||||||
|
self.ide = StringVar()
|
||||||
|
self.ide.set("mdk4") # initialize
|
||||||
|
|
||||||
|
for text,mode in IDE:
|
||||||
|
radiobutton = ttk.Radiobutton(frame, text=text, variable = self.ide, value = mode)
|
||||||
|
radiobutton.pack(fill=X, padx=10)
|
||||||
|
|
||||||
|
bottom = ttk.Frame(frame)
|
||||||
|
bottom.pack(side=BOTTOM, fill=X)
|
||||||
|
button = ttk.Button(bottom, text="Make Project", command = self.do_make_project)
|
||||||
|
button.pack(side=RIGHT, padx = 10, pady = 10)
|
||||||
|
|
||||||
|
def setup_setting_ui(self, frame):
|
||||||
|
row = 0
|
||||||
|
label = ttk.Label (frame, relief = 'flat', text='RT-Thread Root Folder:')
|
||||||
|
label.grid(row=row, column=0,ipadx=5, ipady=5, padx = 5)
|
||||||
|
|
||||||
|
self.RTTRoot = DirSelectBox(frame)
|
||||||
|
self.RTTRoot.grid(row=row, column=1, sticky=E+W)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
label = ttk.Label (frame, relief = 'flat', text='Board Support Folder:')
|
||||||
|
label.grid(row=row, column=0,ipadx=5, ipady=5, padx = 5)
|
||||||
|
|
||||||
|
self.BSPRoot = DirSelectBox(frame)
|
||||||
|
self.BSPRoot.grid(row=row, column=1, sticky=E+W)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
label = ttk.Label (frame, relief='flat', text='Toolchain:')
|
||||||
|
label.grid(row=row, column=0,ipadx=5, ipady=5, sticky=E+W)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
separator = ttk.Separator(frame)
|
||||||
|
separator.grid(row = row, column = 0, columnspan = 2, sticky = E+W)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
self.compilers = StringVar()
|
||||||
|
self.compilers.set("GCC") # initialize
|
||||||
|
|
||||||
|
self.CompilersPath = {}
|
||||||
|
|
||||||
|
for text,compiler in COMPILER:
|
||||||
|
radiobutton = ttk.Radiobutton(frame, text=text, variable = self.compilers, value = compiler)
|
||||||
|
radiobutton.grid(row=row, column = 0, sticky = W, ipadx = 5, ipady = 5, padx = 20)
|
||||||
|
|
||||||
|
self.CompilersPath[compiler] = DirSelectBox(frame)
|
||||||
|
self.CompilersPath[compiler].grid(row=row, column=1, sticky=E+W)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
button = ttk.Button(frame, text='Save Setting', command = self.save_setting)
|
||||||
|
button.grid(row = row, column = 1, sticky = E)
|
||||||
|
row = row + 1
|
||||||
|
|
||||||
|
def prepare_build(self):
|
||||||
|
# get compiler
|
||||||
|
compiler = self.compilers.get()
|
||||||
|
if compiler == 'GCC':
|
||||||
|
compiler = 'gcc'
|
||||||
|
elif compiler == 'ARMCC':
|
||||||
|
compiler = 'keil'
|
||||||
|
elif compiler == 'IAR':
|
||||||
|
compiler = 'iar'
|
||||||
|
|
||||||
|
# get RTT Root
|
||||||
|
rtt_root = self.RTTRoot.get_path()
|
||||||
|
# get Compiler path
|
||||||
|
exec_path = self.CompilersPath[self.compilers.get()].get_path()
|
||||||
|
|
||||||
|
command = ''
|
||||||
|
|
||||||
|
os.environ['RTT_ROOT'] = rtt_root
|
||||||
|
os.environ['RTT_CC'] = compiler
|
||||||
|
os.environ['RTT_EXEC_PATH'] = exec_path
|
||||||
|
|
||||||
|
return command
|
||||||
|
|
||||||
|
def do_build(self):
|
||||||
|
self.prepare_build()
|
||||||
|
command = 'scons'
|
||||||
|
|
||||||
|
bsp = self.BSPRoot.get_path()
|
||||||
|
os.chdir(bsp)
|
||||||
|
|
||||||
|
self.output.delete(1.0, END)
|
||||||
|
self.output.insert(END, 'building project...\n')
|
||||||
|
ExecCmd(command)
|
||||||
|
|
||||||
|
def do_clean(self):
|
||||||
|
self.prepare_build()
|
||||||
|
command = 'scons -c'
|
||||||
|
|
||||||
|
bsp = self.BSPRoot.get_path()
|
||||||
|
os.chdir(bsp)
|
||||||
|
|
||||||
|
self.output.delete(1.0, END)
|
||||||
|
self.output.insert(END, 'clean project...\n')
|
||||||
|
ExecCmd(command)
|
||||||
|
|
||||||
|
def do_make_project(self):
|
||||||
|
ide = self.ide.get()
|
||||||
|
self.prepare_build()
|
||||||
|
command = 'scons --target=%s -s' % ide
|
||||||
|
|
||||||
|
bsp = self.BSPRoot.get_path()
|
||||||
|
os.chdir(bsp)
|
||||||
|
|
||||||
|
self.output.delete(1.0, END)
|
||||||
|
self.output.insert(END, 'make project ...\n')
|
||||||
|
ExecCmd(command)
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
def StartSConsUI(path=None):
|
||||||
|
global val, root
|
||||||
|
root = Tk()
|
||||||
|
root.title('RT-Thread SCons UI')
|
||||||
|
root.geometrygeometry('590x510+50+50')
|
||||||
|
lock = threading.RLock()
|
||||||
|
builder = SconsUI(root)
|
||||||
|
if path:
|
||||||
|
builder.BSPRoot.set_path(path)
|
||||||
|
root.mainloop
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
global val, root
|
||||||
|
root = Tk()
|
||||||
|
root.title('scons_builder')
|
||||||
|
root.geometry('590x510+50+50')
|
||||||
|
lock = threading.RLock()
|
||||||
|
scons_ui = SconsUI(root)
|
||||||
|
builder = scons_ui
|
||||||
|
root.mainloop()
|
|
@ -0,0 +1,154 @@
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import Queue
|
||||||
|
|
||||||
|
# Windows import
|
||||||
|
import win32file
|
||||||
|
import win32pipe
|
||||||
|
import win32api
|
||||||
|
import win32con
|
||||||
|
import win32security
|
||||||
|
import win32process
|
||||||
|
import win32event
|
||||||
|
|
||||||
|
class Win32Spawn(object):
|
||||||
|
def __init__(self, cmd, shell=False):
|
||||||
|
self.queue = Queue.Queue()
|
||||||
|
self.is_terminated = False
|
||||||
|
self.wake_up_event = win32event.CreateEvent(None, 0, 0, None)
|
||||||
|
|
||||||
|
exec_dir = os.getcwd()
|
||||||
|
comspec = os.environ.get("COMSPEC", "cmd.exe")
|
||||||
|
cmd = comspec + ' /c ' + cmd
|
||||||
|
|
||||||
|
win32event.ResetEvent(self.wake_up_event)
|
||||||
|
|
||||||
|
currproc = win32api.GetCurrentProcess()
|
||||||
|
|
||||||
|
sa = win32security.SECURITY_ATTRIBUTES()
|
||||||
|
sa.bInheritHandle = 1
|
||||||
|
|
||||||
|
child_stdout_rd, child_stdout_wr = win32pipe.CreatePipe(sa, 0)
|
||||||
|
child_stdout_rd_dup = win32api.DuplicateHandle(currproc, child_stdout_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
|
||||||
|
win32file.CloseHandle(child_stdout_rd)
|
||||||
|
|
||||||
|
child_stderr_rd, child_stderr_wr = win32pipe.CreatePipe(sa, 0)
|
||||||
|
child_stderr_rd_dup = win32api.DuplicateHandle(currproc, child_stderr_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
|
||||||
|
win32file.CloseHandle(child_stderr_rd)
|
||||||
|
|
||||||
|
child_stdin_rd, child_stdin_wr = win32pipe.CreatePipe(sa, 0)
|
||||||
|
child_stdin_wr_dup = win32api.DuplicateHandle(currproc, child_stdin_wr, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
|
||||||
|
win32file.CloseHandle(child_stdin_wr)
|
||||||
|
|
||||||
|
startup_info = win32process.STARTUPINFO()
|
||||||
|
startup_info.hStdInput = child_stdin_rd
|
||||||
|
startup_info.hStdOutput = child_stdout_wr
|
||||||
|
startup_info.hStdError = child_stderr_wr
|
||||||
|
startup_info.dwFlags = win32process.STARTF_USESTDHANDLES
|
||||||
|
|
||||||
|
cr_flags = 0
|
||||||
|
cr_flags = win32process.CREATE_NEW_PROCESS_GROUP
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
self.h_process, h_thread, dw_pid, dw_tid = win32process.CreateProcess(None, cmd, None, None, 1,
|
||||||
|
cr_flags, env, os.path.abspath(exec_dir),
|
||||||
|
startup_info)
|
||||||
|
|
||||||
|
win32api.CloseHandle(h_thread)
|
||||||
|
|
||||||
|
win32file.CloseHandle(child_stdin_rd)
|
||||||
|
win32file.CloseHandle(child_stdout_wr)
|
||||||
|
win32file.CloseHandle(child_stderr_wr)
|
||||||
|
|
||||||
|
self.__child_stdout = child_stdout_rd_dup
|
||||||
|
self.__child_stderr = child_stderr_rd_dup
|
||||||
|
self.__child_stdin = child_stdin_wr_dup
|
||||||
|
|
||||||
|
self.exit_code = -1
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
win32file.CloseHandle(self.__child_stdout)
|
||||||
|
win32file.CloseHandle(self.__child_stderr)
|
||||||
|
win32file.CloseHandle(self.__child_stdin)
|
||||||
|
win32api.CloseHandle(self.h_process)
|
||||||
|
win32api.CloseHandle(self.wake_up_event)
|
||||||
|
|
||||||
|
def kill_subprocess():
|
||||||
|
win32event.SetEvent(self.wake_up_event)
|
||||||
|
|
||||||
|
def sleep(secs):
|
||||||
|
win32event.ResetEvent(self.wake_up_event)
|
||||||
|
timeout = int(1000 * secs)
|
||||||
|
val = win32event.WaitForSingleObject(self.wake_up_event, timeout)
|
||||||
|
if val == win32event.WAIT_TIMEOUT:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# The wake_up_event must have been signalled
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get(self, block=True, timeout=None):
|
||||||
|
return self.queue.get(block=block, timeout=timeout)
|
||||||
|
|
||||||
|
def qsize(self):
|
||||||
|
return self.queue.qsize()
|
||||||
|
|
||||||
|
def __wait_for_child(self):
|
||||||
|
# kick off threads to read from stdout and stderr of the child process
|
||||||
|
threading.Thread(target=self.__do_read, args=(self.__child_stdout, )).start()
|
||||||
|
threading.Thread(target=self.__do_read, args=(self.__child_stderr, )).start()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
# block waiting for the process to finish or the interrupt to happen
|
||||||
|
handles = (self.wake_up_event, self.h_process)
|
||||||
|
val = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)
|
||||||
|
|
||||||
|
if val >= win32event.WAIT_OBJECT_0 and val < win32event.WAIT_OBJECT_0 + len(handles):
|
||||||
|
handle = handles[val - win32event.WAIT_OBJECT_0]
|
||||||
|
if handle == self.wake_up_event:
|
||||||
|
win32api.TerminateProcess(self.h_process, 1)
|
||||||
|
win32event.ResetEvent(self.wake_up_event)
|
||||||
|
return False
|
||||||
|
elif handle == self.h_process:
|
||||||
|
# the process has ended naturally
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
assert False, "Unknown handle fired"
|
||||||
|
else:
|
||||||
|
assert False, "Unexpected return from WaitForMultipleObjects"
|
||||||
|
|
||||||
|
# Wait for job to finish. Since this method blocks, it can to be called from another thread.
|
||||||
|
# If the application wants to kill the process, it should call kill_subprocess().
|
||||||
|
def wait(self):
|
||||||
|
if not self.__wait_for_child():
|
||||||
|
# it's been killed
|
||||||
|
result = False
|
||||||
|
else:
|
||||||
|
# normal termination
|
||||||
|
self.exit_code = win32process.GetExitCodeProcess(self.h_process)
|
||||||
|
result = self.exit_code == 0
|
||||||
|
self.close()
|
||||||
|
self.is_terminated = True
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
# This method gets called on a worker thread to read from either a stderr
|
||||||
|
# or stdout thread from the child process.
|
||||||
|
def __do_read(self, handle):
|
||||||
|
bytesToRead = 1024
|
||||||
|
while 1:
|
||||||
|
try:
|
||||||
|
finished = 0
|
||||||
|
hr, data = win32file.ReadFile(handle, bytesToRead, None)
|
||||||
|
self.queue.put_nowait(data)
|
||||||
|
except win32api.error:
|
||||||
|
finished = 1
|
||||||
|
|
||||||
|
if finished:
|
||||||
|
return
|
||||||
|
|
||||||
|
def start_pipe(self):
|
||||||
|
def worker(pipe):
|
||||||
|
return pipe.wait()
|
||||||
|
|
||||||
|
thrd = threading.Thread(target=worker, args=(self, ))
|
||||||
|
thrd.start()
|
Loading…
Reference in New Issue