初次创建仓库提交代码
1. 已经构建好了架子了。 2. 添加了示例的插件
This commit is contained in:
104
utils/shell.py
Normal file
104
utils/shell.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import time
|
||||
import os, sys
|
||||
import signal
|
||||
import subprocess
|
||||
import threading
|
||||
import queue
|
||||
import select
|
||||
from functools import wraps
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
||||
import core.logger as logger
|
||||
log = logger.get_logger()
|
||||
|
||||
def timeit(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
start_time = time.time()
|
||||
result = func(*args, **kwargs)
|
||||
end_time = time.time()
|
||||
execution_time = end_time - start_time
|
||||
cmd = args[0]
|
||||
log.trace(f"Spent [{execution_time:.4f}s] Run: [ {cmd} ]")
|
||||
return result
|
||||
return wrapper
|
||||
|
||||
@timeit
|
||||
def shell(cmd, *kwargs, timeout:float=10, checkret:bool=True, async_handle=None, handle_param=None):
|
||||
executer = ShellExecute(cmd, timeout, async_handle, handle_param)
|
||||
ret, output, error = executer.execute()
|
||||
if checkret and ret!= 0:
|
||||
log.error(f"Execute [\n{cmd}\n] failed Ret:{ret}")
|
||||
log.debug(f"Stdout:{output}")
|
||||
log.error(f"Stderr:{error}")
|
||||
raise Exception("error execute shell command")
|
||||
return ret, output, error
|
||||
|
||||
class ShellExecute(threading.Thread):
|
||||
def __init__(self, cmd_line, timeout:int, async_handle, handle_param):
|
||||
super().__init__(target=self.monitor)
|
||||
self.cmd_line = cmd_line
|
||||
self.timeout = timeout
|
||||
self.async_handle = async_handle
|
||||
self.handle_param = handle_param
|
||||
|
||||
def monitor(self):
|
||||
if self.timeout is None:
|
||||
log.debug("Block to execute [{}] ".format(self.cmd_line))
|
||||
return
|
||||
cnt = self.timeout / 0.1
|
||||
while self.process.poll() is None and cnt > 0:
|
||||
time.sleep(0.1)
|
||||
cnt -= 1
|
||||
if self.process.poll() is not None: # 进程已经结束
|
||||
return
|
||||
os.kill(self.process.pid, signal.SIGSEGV)
|
||||
log.error("execute [{}] timeout, Force kill it(pid:{})...".format(self.cmd_line, self.process.pid))
|
||||
raise TimeoutError("Execute cmd timeout")
|
||||
|
||||
def execute(self):
|
||||
if self.async_handle is not None:
|
||||
return self.async_execute()
|
||||
else:
|
||||
return self.sync_execute()
|
||||
def sync_execute(self):
|
||||
process = subprocess.Popen(self.cmd_line, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
self.process = process
|
||||
self.start() #启动监控线程
|
||||
stdout, stderr = process.communicate()
|
||||
output = stdout.decode('utf-8')
|
||||
error = stderr.decode('utf-8')
|
||||
return_code = process.returncode
|
||||
return return_code, output, error
|
||||
|
||||
def async_execute(self):
|
||||
output_queue = queue.Queue()
|
||||
# read_fd, write_fd = os.pipe()
|
||||
thread = threading.Thread(target=self.async_handle, args=(output_queue,self.handle_param), daemon=True)
|
||||
thread.start()
|
||||
process = subprocess.Popen(self.cmd_line, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True)
|
||||
self.process = process
|
||||
self.start() #启动监控线程
|
||||
try:
|
||||
epoll = select.epoll()
|
||||
epoll.register(process.stdout.fileno(), select.EPOLLIN)
|
||||
while process.poll() is None:
|
||||
events = epoll.poll()
|
||||
for fileno, _ in events:
|
||||
if fileno != process.stdout.fileno():
|
||||
continue
|
||||
while True:
|
||||
std_out = process.stdout.readline()
|
||||
if not std_out:
|
||||
break
|
||||
output_queue.put(std_out) # 将输出放入队列
|
||||
except KeyboardInterrupt:
|
||||
log.warning("Interrupted Process")
|
||||
os.kill(self.process.pid, signal.SIGSEGV)
|
||||
log.trace("Process finished.")
|
||||
output_queue.put(None) # 结束队列
|
||||
thread.join() # 等待线程结束
|
||||
stdout, stderr = process.communicate()
|
||||
output = stdout#.decode('utf-8')
|
||||
error = stderr#.decode('utf-8')
|
||||
return_code = process.returncode
|
||||
return return_code, output, error
|
||||
Reference in New Issue
Block a user