编译辅助工具
1.脚本介绍
这个脚本的主要目的如下:
命令行自动编译程序 |
---|
杀掉程序 |
启动程序 |
更新代码 |
支持命令行字体颜色高亮 |
可以帮我节省几分钟的时间。剩下的这几分钟时间,可以让我思考刚才修改的代码有没有问题。
还有一些配置通过脚本config.json
配置
PS D:\code>.\compile.py -h
usage: compile.py [-h] [-u] [-pre] [-k] [-s] [-c] [-a COMPILEARGS] [-p CONFIGPATH]
Tools for auto update code and compile project
optional arguments:
-h, --help show this help message and exit
-u, --update update code by svn or git
-pre, --precompileaction
build code previous action,for example Qt qrc file.
-k, --kill kill target process
-s, --start start target process
-c, --compile compile project
-a COMPILEARGS, --compileargs COMPILEARGS
compile project with args, for example:"Debug|Win32" or "Release|Win32". default value: "Debug|Win32"
-p CONFIGPATH, --configpath CONFIGPATH
load config json path
**config.json **配置文件路径可以在命令行指定,默认就是当前的路径下。
这些配置属性都是命令行结合用的。
比如:
.\compile.y -u -k -pre -c -s
上面的命令是我经常使用的,表示:更新代码,杀掉进程,执行编译之前动作,编译代码,启动进程。
最后面你也可以指定config.json路径,这样compile.y文件就只有一份,配置文件可以有多份。
config.json配置属性 |
---|
1.配置进程名 |
2.配置更新的命令 |
3.配置编译之前操作,比如:我的项目之前需要编译一些资源文件,我就放到bat文件去处理 |
4.需要编译的解决方案路径 |
5.IDE的路径 |
6.启动进程的路径 |
7.进程启动的参数 |
带参数的详细解释:
{
# 进程的名称
"process_name":"demo.exe",
# 更新代码的命令,比如: git pull origin master
"update_code_command":"svn up",
# 编译之前的动作,因为使用的是Qt,所以需要先编译资源,可以放到bat文件执行
"pre_compile_command":"E:\xxx.bat",
# 解决方案的名称
"compile_file":"D:/code/Demo.sln",
# IDE的路径,这样就不用修改系统环境变量
"compile_tool_dir":"C:/Program Files (x86)/Microsoft Visual Studio 12.0/Common7/IDE",
# 启动进程的路径
"start_process_path":"D:/code/bin/Debug/Demo.exe",
# 启动进程的参数
"start_process_args":["-enable", "-start"]
}
{
"process_name":"demo.exe",
"update_code_command":"svn up",
"pre_compile_command":"E:\xxx.bat",
"compile_file":"D:/code/Demo.sln",
"compile_tool_dir":"C:/Program Files (x86)/Microsoft Visual Studio 12.0/Common7/IDE",
"start_process_path":"D:/code/bin/Debug/Demo.exe",
"start_process_args":["-enable", "-start"]
}
2.原理介绍
其实没什么高大上的原理,都是稀松平常的东西。但是有几个小点和大家分享下。
- 环境变量的配置,大家要注意看下我的代码。这样做的好处就是影响范围很小,只影响本进程。
def _pre_env(self):
strewn = os.getenv("path")
os.putenv("path", strewn + ";" + self.compile_tool_dir)
return
- 编译解决方案用的devenv.com而不是devenv.exe。
你用where命令看的话会有两个
D:\>where devenv
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.com
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe
我把主要代码分享下:
class App:
def __init__(self):
self._clear()
def _clear(self):
self.pre_compile_command = ""
self.start_process_args = ""
self.process_name = ""
self.start_process_path = ""
self.update_code_command = ""
self.compile_args = ""
self.compile_file = ""
self.compile_tool_dir = ""
self.update = False
self.resource = False
self.is_kill = False
self.is_start = False
self.is_compile = False
self.compile_args = ""
self.config_path = ""
def _search_process(self):
list_process_id = []
for proc in psutil.process_iter(['name', 'pid']):
if proc.info['name'] == self.process_name:
find_flag = 1
list_process_id.append(proc.info['pid'])
break
if len(list_process_id) == 0:
print(colorama.Fore.GREEN + "Not find target process")
return list_process_id
def _kill_process(self, list_process_id):
for process_id in list_process_id:
target_process = psutil.Process(process_id)
try:
target_process.kill()
print(colorama.Fore.GREEN + "kill target process successful.")
except psutil.ZombieProcess:
print(colorama.Fore.RED + "Error: this is zombie process")
return 1
except psutil.AccessDenied:
print(colorama.Fore.RED + "Error: Access denied")
return 1
except psutil.TimeoutExpired:
print(colorama.Fore.RED + "Error: Time out expired")
return 1
return 0
def _pre_compile_code(self):
if len(self.pre_compile_command) == 0:
print(colorama.Fore.GREEN + "Not build any resource.")
return
os.system(self.pre_compile_command)
print(colorama.Fore.GREEN + "build resource finished.")
return
def _compile_code(self):
compile_tool = 'devenv'
compile_parameter = '/build "' + self.compile_args + '"'
os.system('devenv ' + self.compile_file + ' ' + compile_parameter)
def _pre_env(self):
strewn = os.getenv("path")
os.putenv("path", strewn + ";" + self.compile_tool_dir)
return
def _start_process(self):
try:
list_process_args = [self.start_process_path]
for args in self.start_process_args:
list_process_args.append(args)
subprocess.Popen(list_process_args, shell=False)
print(colorama.Fore.GREEN + "start target process successful.")
except Exception as error:
print(colorama.Fore.GREEN + str(error))
else:
pass
return
def _update_code(self):
os.system(self.update_code_command)
return
def _parse_args(self, args):
parser = argparse.ArgumentParser(description='Tools for auto update code and compile project')
parser.add_argument('-u', '--update', action='store_true', help='update code by svn or git')
parser.add_argument('-pre', '--precompileaction', action='store_true', help='build code previous action,for '
'example Qt qrc file.')
parser.add_argument('-k', '--kill', action='store_true', help='kill target process')
parser.add_argument('-s', '--start', action='store_true', help='start target process')
parser.add_argument('-c', '--compile', action='store_true', help='compile project')
parser.add_argument('-a', '--compileargs', default='Debug|Win32', type=str,
help='compile project with args, for example:"Debug|Win32" or "Release|Win32". default '
'value: "Debug|Win32"')
parser.add_argument('-p', '--configpath', default='./config.json', type=str, help='load config json path')
args = parser.parse_args(args)
self.update = args.update
self.pre_compileaction = args.precompileaction
self.is_kill = args.kill
self.is_start = args.start
self.is_compile = args.compile
self.compile_args = args.compileargs
self.config_path = args.configpath
def _parse_config(self, config_path):
with open(config_path) as f:
data = json.load(f)
self.process_name = data['process_name']
self.update_code_command = data['update_code_command']
self.pre_compile_command = data['pre_compile_command']
self.compile_file = data['compile_file']
self.compile_tool_dir = data['compile_tool_dir']
self.start_process_path = data['start_process_path']
self.start_process_args = data['start_process_args']
def run(self, args):
self._parse_args(args)
self._parse_config(self.config_path)
if self.update:
print('------------------------start update code----------------------------')
self._update_code()
print('------------------------end update code------------------------------')
if self.pre_compileaction:
print('-------------------start previous action--------------------------')
self._pre_compile_code()
print('--------------------end previous action---------------------------')
kill_flag = 0
if self.is_kill:
print('--------------------start search process--------------------------')
list_process_id = self._search_process()
if len(list_process_id) != 0:
kill_flag = self._kill_process(list_process_id)
print('---------------------end search process---------------------------')
if kill_flag != 0:
print('--------------------stop compile project--------------------------')
else:
if self.is_compile:
print('--------------------start compile project--------------------------')
print('--------------start init previous environment--------------------')
self._pre_env()
print('---------------end init previous environment---------------------')
self._compile_code()
print(colorama.Fore.GREEN + 'compile project finished')
print('--------------------end compile project----------------------------')
if self.is_start:
print('--------------------start call application-------------------------')
self._start_process()
print('--------------------end call application---------------------------')
if __name__ == '__main__':
colorama.init(autoreset=True)
app = App()
if not app.run(sys.argv[1:]):
sys.exit(-1)
sys.exit(0)
这个脚本还有些未完善的地方,后期我会再找时间继续完善。
TODO list:
- 未能识别编译错误,给出提示