1 Star 1 Fork 0

skyfire/smake

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
smake.py 14.02 KB
一键复制 编辑 原始数据 按行查看 历史
skyfire 提交于 2018-09-04 14:21 . 添加第三方库支持
# coding: utf-8
from jinja2 import Template
import sys
import os
import platform
import json
import errno
import subprocess
import uuid
import argparse
import traceback
import shutil
import stat
global_config = {}
project_config = {}
version_info = """
smake Dependency Configuration Tool
version: 1.0.1
author:By SkyFire
"""
def error_output(*args):
msg = list(map(lambda x: str(x), args))
print("ERROR-->" + " ".join(msg))
traceback.print_exc()
def msg_output(*args):
msg = list(map(lambda x: str(x), args))
print("MSG -->" + " ".join(msg))
def warn_output(*args):
msg = list(map(lambda x: str(x), args))
print("WARN -->" + " ".join(msg))
def succ_output(*args):
msg = list(map(lambda x: str(x), args))
print("SUCC -->" + " ".join(msg))
def del_dir_tree(path):
if os.path.isfile(path):
try:
os.chmod( path, stat.S_IWRITE | stat.S_IREAD )
os.remove(path)
msg_output("Delete -->", path)
except Exception as e:
error_output("Delete file error", path, e)
elif os.path.isdir(path):
for item in os.listdir(path):
itempath = os.path.join(path, item)
del_dir_tree(itempath)
try:
os.chmod( path, stat.S_IWRITE | stat.S_IREAD )
os.rmdir(path)
msg_output("Delete dir -->", path)
except Exception as e:
error_output("Delete dir error", path, e)
def ask_abort(error_question="A critical error has occurred, whether to continue?"):
while True:
answer = input(error_question + " (Y/n) ")
if answer == "y" or answer == "Y":
return
elif answer == "n" or answer == "N":
exit(-1)
def ask(error_question:str):
while True:
answer = input(error_question + " (Y/n) ")
if answer == "y" or answer == "Y":
return True
elif answer == "n" or answer == "N":
return False
def load_default_config():
global project_config
global global_config
if platform.system() == "Windows":
shell = "cmd /c"
home_dir = os.path.join(os.environ["HOMEDRIVE"], os.environ["HOMEPATH"])
else:
shell = "/bin/bash"
home_dir = os.path.expanduser("~")
global_config = {
"shell": shell,
"home_dir": home_dir,
"download_path": home_dir,
"git_bin": "git",
"svn_bin": "svn",
"work_dir": os.path.abspath(os.curdir),
"curr_script": os.path.abspath(sys.argv[0]),
"old_env": os.environ,
"system_type": platform.system(),
"path_stack": [os.path.abspath(os.curdir)],
"package_install_mark_dir": os.path.join(home_dir, "smake", "smakeInstalledPackage"),
"pkg_list_config": os.path.join(home_dir,"smake","pkgListConfig"),
"pkg_source":[],
"env": {
}
}
try:
global_config_path = os.path.join(home_dir, ".smake.config.json")
with open(global_config_path, "r") as fp:
config = json.loads(fp.read())
global_config.update(config)
os.environ.update(global_config["env"])
except OSError as err:
if err.errno == errno.ENOENT:
warn_output(global_config_path, "not found, will use default configuration")
def make_dirs(dirs: str):
try:
os.makedirs(dirs)
except OSError as err:
if err.errno == errno.EEXIST and os.path.isdir(dirs):
pass
else:
error_output(err)
exit(-1)
def make_install_mark_dir():
global project_config
global global_config
make_dirs(global_config["package_install_mark_dir"])
def to_json_encode_str(value):
if isinstance(value, str):
return value.replace("\\", "\\\\").replace("\"", "\\\"") \
.replace("\/", "\\/").replace("\b", "\\b").replace("\f", "\\f").replace(
"\n", "\\n").replace("\r", "\\r").replace("\t", "\\t")
return value
def load_project_config(config_file = "smake.json"):
global project_config
global global_config
with open(config_file, "r") as fp:
project_config_content = fp.read()
tmp_render_obj = {}
for key in os.environ.keys():
tmp_render_obj[key] = to_json_encode_str(os.environ[key])
for key in project_config.keys():
tmp_render_obj[key] = to_json_encode_str(project_config[key])
rendered_config = Template(project_config_content).render(**tmp_render_obj)
project_config_obj = json.loads(rendered_config)
project_config.update(project_config_obj)
if "env" in project_config:
os.environ.update(project_config["env"])
def run_cmd(cmd: str):
global project_config
global global_config
msg_output("Run cmd:",cmd)
while True:
try:
subprocess.check_call(cmd, shell=True)
return
except Exception as err:
error_output(err)
ask_abort(cmd + " Failure to execute, Retry?")
def change_dir(dir_path: str):
global project_config
global global_config
global_config["path_stack"].append(os.path.abspath(os.curdir))
msg_output("Change to", dir_path)
os.chdir(os.path.abspath(dir_path))
def change_back_dir():
global project_config
global global_config
new_path = global_config["path_stack"].pop()
msg_output("Change to", new_path)
os.chdir(new_path)
def load_pkg_export_env(mark_path: str):
global project_config
global global_config
with open(mark_path) as fp:
pkg_obj = json.loads(fp.read())
if "install" in pkg_obj:
if "export" in pkg_obj["install"]:
os.environ.update(pkg_obj["install"]["export"])
project_config["install"]["export"].update(pkg_obj["install"]["export"])
system_type = global_config["system_type"]
if system_type in pkg_obj["install"]:
if "export" in pkg_obj["install"][system_type]:
os.environ.update(pkg_obj["install"][system_type]["export"])
if system_type not in project_config["install"]:
project_config["install"][system_type] = {}
if "export" not in project_config["install"][system_type]:
project_config["install"][system_type]["export"]= {}
project_config["install"][system_type]["export"].update(pkg_obj["install"][system_type]["export"])
def find_support_pkg(name:str,version:str):
global global_config
global project_config
for pkg in global_config["pkg_source"]:
if pkg["name"] == name and pkg["version"] == version:
return pkg
return None
def download_install_depend_item(dep):
global project_config
global global_config
pkg_name = dep["name"] + dep["version"]
mark_path = os.path.join(global_config["package_install_mark_dir"], pkg_name)
if os.path.exists(mark_path):
succ_output(pkg_name, "has already installed")
load_pkg_export_env(mark_path)
return
src_path = os.path.join(global_config["download_path"], pkg_name)
if os.path.exists(src_path):
msg_output("Remove path",src_path)
#shutil.rmtree(src_path, ignore_errors=True)
del_dir_tree(src_path)
get_src_cmd = None
script_path = None
if "git" in dep:
get_src_cmd = global_config["git_bin"] + " clone " + dep["git"] + " \"" + src_path + "\""
elif "svn" in dep:
get_src_cmd = global_config["svn_bin"] + " checkout " + dep["svn"] + " \"" + src_path + "\""
else:
result = find_support_pkg(dep["name"] ,dep["version"])
if result is None:
ask_abort(pkg_name + " -> Git path or SVN path is not specified, Continue?")
return
else:
if "git" in result:
get_src_cmd = global_config["git_bin"] + " clone " + result["git"] + " \"" + src_path + "\""
elif "svn" in result:
get_src_cmd = global_config["svn_bin"] + " checkout " + dep["svn"] + " \"" + src_path + "\""
else:
ask_abort(pkg_name + " -> Git path or SVN path is not specified, Continue?")
return
if "script" in result:
script_path = os.path.join(global_config["pkg_list_config"], "script", result["script"])
else:
ask_abort(pkg_name + " -> Third-party library configuration scripts not specified, Continue?")
run_cmd(get_src_cmd)
change_dir(src_path)
config_file = os.path.join(src_path, "smake.json")
if not os.path.exists(config_file):
if script_path is not None:
shutil.copy(script_path,config_file)
run_cmd("python \"" + global_config["curr_script"] + "\"")
change_back_dir()
load_pkg_export_env(mark_path)
def download_and_build_depend():
global project_config
global global_config
if "install" not in project_config:
project_config["install"] = {}
if "export" not in project_config["install"]:
project_config["install"]["export"] = {}
if "build" not in project_config:
return
if "depend" in project_config["build"]:
for dep in project_config["build"]["depend"]:
download_install_depend_item(dep)
system_type = global_config["system_type"]
if system_type in project_config["build"]:
if "depend" in project_config["build"][system_type]:
for dep in project_config["build"][system_type]["depend"]:
download_install_depend_item(dep)
load_project_config()
def run_cmd_list(cmd_list: list):
global project_config
global global_config
file_content = "\n".join(cmd_list)
if global_config["system_type"] == "Windows":
file_content = "@echo off\n" + file_content
tmp_file = str(uuid.uuid1()) + ".bat"
with open(tmp_file, "w") as fp:
fp.write(file_content)
msg_output("Prepare run script:\n", file_content)
run_cmd(global_config["shell"] + " \"" + tmp_file + "\"")
os.remove(tmp_file)
def build_project():
global project_config
global global_config
pkg_name = project_config["name"] + project_config["version"]
if "build" in project_config:
if "command" in project_config["build"]:
run_cmd_list(project_config["build"]["command"])
system_type = global_config["system_type"]
if system_type in project_config["build"]:
if "command" in project_config["build"][system_type]:
run_cmd_list(project_config["build"][system_type]["command"])
succ_output(pkg_name, "build success")
def install_pkg():
global project_config
global global_config
if "install" in project_config:
if "command" in project_config["install"]:
run_cmd_list(project_config["install"]["command"])
system_type = global_config["system_type"]
if system_type in project_config["install"]:
if "command" in project_config["install"][system_type]:
run_cmd_list(project_config["install"][system_type]["command"])
pkg_name = project_config["name"] + project_config["version"]
mark_path = os.path.join(global_config["package_install_mark_dir"], pkg_name)
with open(mark_path, "w") as fp:
fp.write(json.dumps(project_config))
succ_output(pkg_name, "install success")
def list_package():
global project_config
global global_config
pkg_list = os.listdir(global_config["package_install_mark_dir"])
for pkg in pkg_list:
with open(os.path.join(global_config["package_install_mark_dir"], pkg), "r") as fp:
pkg_obj = json.loads(fp.read())
print("Package:",pkg)
print("Name:",pkg_obj["name"])
print("Version:",pkg_obj["version"])
print("Source:",pkg_obj["project_dir"])
print("--------------------")
print("Package count:", len(pkg_list))
def remove_package(pkg:str):
global project_config
global global_config
pkg_mark_path = os.path.join(global_config["package_install_mark_dir"], pkg)
if not os.path.exists(pkg_mark_path):
print("Package", pkg, "not installed")
return
with open(pkg_mark_path, "r") as fp:
pkg_obj = json.loads(fp.read())
if "uninstall" in pkg_obj:
if "command" in pkg_obj["uninstall"]:
run_cmd_list(pkg_obj["uninstall"]["command"])
system_type = global_config["system_type"]
if system_type in pkg_obj["uninstall"]:
if "command" in pkg_obj["uninstall"][system_type]:
run_cmd_list(pkg_obj["uninstall"][system_type]["command"])
if ask("Delete source (" + pkg_obj["project_dir"] + ")"):
#shutil.rmtree(pkg_obj["project_dir"],ignore_errors=True)
del_dir_tree(pkg_obj["project_dir"])
os.remove(pkg_mark_path)
print(pkg,"Removed")
def load_pkg_list_config():
global global_config
global project_config
source_file = os.path.join(global_config["pkg_list_config"],"source.json")
try:
with open(source_file) as fp:
global_config["pkg_source"] = json.loads(fp.read())
except Exception:
warn_output("Failed to load package configuration file, third-party libraries are not supported, please check the file", source_file)
def main():
global global_config
global project_config
try:
load_default_config()
make_install_mark_dir()
load_pkg_list_config()
parser = argparse.ArgumentParser(description=version_info)
parser.add_argument("--list","-l",action="store_true", help="List packages installed")
parser.add_argument("--remove","-r",type=str,help="Remove a package")
args = parser.parse_args()
if args.list:
list_package()
return
if args.remove:
remove_package(args.remove)
return
project_config = {
"project_dir": global_config["work_dir"],
}
load_project_config()
download_and_build_depend()
build_project()
install_pkg()
except Exception as err:
error_output(err)
ask_abort()
if __name__ == "__main__":
exit(main())
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/skyfireitdiy/smake.git
git@gitee.com:skyfireitdiy/smake.git
skyfireitdiy
smake
smake
master

搜索帮助