diff --git a/README.md b/README.md index b5a56fb..99b4a4d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A python lib came from [Difficult Rocket](https://github.com/shenjackyuanjie/Dif ## Information/信息 -- Version / 版本: 0.2.0-beta.0 +- Version / 版本: 0.2.0-beta.3 - Author / 作者: shenjackyuanjie <3695888@qq.com> > [shenjackyuanjie](https://github.com/shenjackyuanjie) @@ -61,7 +61,14 @@ logger.trace('so this message will be in the same line', tag='same line!') [tool.lndl.nuitka] main = "main.py" # --main=main.py +standalone = true +onefile = false +``` +```bash +lndl-nuitka . +lndl-nuitka . -- --onefile +# add --onefile to nuitka ``` ### Nuitka Compiler Helper diff --git a/docs/change_log.md b/docs/change_log.md index eef3894..692caef 100644 --- a/docs/change_log.md +++ b/docs/change_log.md @@ -1,5 +1,13 @@ # Change log / 更新日志 +## 0.2.0-beta.2 + +### lndl-nuitka + +- 可以使用 `--` 单独添加参数了 + - 例如 `lndl-nuitka -- --onefile` + - 会将 `--onefile` 添加到 `nuitka` 的参数中 + ## 0.2.0-beta.0/1 ### 重构 diff --git a/pyproject.toml b/pyproject.toml index 787456c..44cfc13 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,3 +65,9 @@ line-length = 150 src = [ "src", ] + +[tool.lndl.nuitka] +main = "test-only.py" +onefile = false +standalone = true + diff --git a/src/lib_not_dr/__init__.py b/src/lib_not_dr/__init__.py index eb356ef..221d775 100644 --- a/src/lib_not_dr/__init__.py +++ b/src/lib_not_dr/__init__.py @@ -4,7 +4,17 @@ # All rights reserved # ------------------------------- -__version__ = '0.2.0-beta.2' +__version__ = '0.2.0-beta.3' + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from lib_not_dr import ( + logger, + nuitka, + types, + command + ) __all__ = [ '__version__', diff --git a/src/lib_not_dr/nuitka/parse.py b/src/lib_not_dr/nuitka/reader/__init__.py similarity index 52% rename from src/lib_not_dr/nuitka/parse.py rename to src/lib_not_dr/nuitka/reader/__init__.py index 1544cbf..53b684c 100644 --- a/src/lib_not_dr/nuitka/parse.py +++ b/src/lib_not_dr/nuitka/reader/__init__.py @@ -8,7 +8,11 @@ import time import subprocess from pathlib import Path -from typing import Iterable +from typing import Dict, Union, List + +from lib_not_dr.nuitka.reader.arg_parser import pyproject_toml, toml_path_cli, gen_subprocess_args + +support_config_dict = Dict[str, Union[str, bool, List[Union[str, tuple]]]] USEAGE = """ usage: @@ -60,8 +64,8 @@ TOML_READERS = ( def get_toml_reader(): for module_name in TOML_READERS: try: - toml_loads = __import__(module_name).loads - return toml_loads + loaded = __import__(module_name).loads + return loaded except ImportError: continue error_msg = """No toml reader found, please install any below by pip: @@ -75,91 +79,54 @@ def get_toml_reader(): toml_loads = get_toml_reader() -def validate_toml(toml_data: dict, file_name: Path) -> dict: - if "tool" not in toml_data: - raise ValueError(f"No tool section in {file_name}") - - if "lndl" not in toml_data["tool"]: - raise ValueError(f"No lib-not-dr(lndl) section in {file_name}") - - if "nuitka" not in toml_data["tool"]["lndl"]: - raise ValueError(f"No lib-not-dr(lndl).nuitka section in {file_name}") - - nuitka_config = toml_data["tool"]["lndl"]["nuitka"] - - if "main" not in nuitka_config: - raise ValueError( - "'main' not define in lib-not-dr(lndl).nuitka section\ndefine it with 'main = []'" - ) - - return nuitka_config +def display_config(subprocess_command: list) -> None: + print(f"The config is:\n\033[34m{subprocess_command} \033[0m") + print("shell command is:\n\033[34m", end="") + print(" ".join(subprocess_command), '\033[0m') + print(f"Working Dir: \033[32m {Path().cwd().absolute()} \033[0m") -def gen_subprocess_args(nuitka_config: dict) -> list: - cmd_list = [sys.executable, "-m", "nuitka"] - - for name, value in nuitka_config.items(): - if value is True: - # -- - cmd_list.append(f"--{name}") - continue - elif isinstance(value, str): - # --= - cmd_list.append(f"--{name}={value}") - continue - elif isinstance(value, Iterable): - # --=,,... - cmd_list.append(f"--{name}={','.join(value)}") - continue - - return cmd_list - - -def get_toml() -> Path: - if len(sys.argv) < 2: - raw_path = Path().cwd() - else: - raw_path = Path(sys.argv[1]) - if raw_path.is_file(): - return raw_path - - elif raw_path.is_dir(): - if (raw_path / "pyproject.toml").exists(): - return raw_path / "pyproject.toml" - else: - raise FileNotFoundError(f"pyproject.toml not found in {raw_path}") - else: - raise FileNotFoundError(f"{raw_path} not found") - - -def main(): - toml_file = get_toml() - - with open(toml_file, "r", encoding="utf-8") as f: - toml = toml_loads(f.read()) - - nuitka_config = validate_toml(toml, toml_file) - - subprocess_command = gen_subprocess_args(nuitka_config) - - # printed in blue text - # \033[34m is the escape code for blue text - print(f"\033[34mRunning: {subprocess_command}\033[0m") - print(f"Working Dir: {Path().cwd()}") - +def run_nuitka(subprocess_command: list) -> None: start_time = time.time() subprocess.run(subprocess_command, shell=True) end_time = time.time() - print(f"Time Elapsed: {end_time - start_time} seconds") -if __name__ == "__main__": +def main(config: support_config_dict) -> None: + """ + enter point for python direct call + :param config: nuitka config dict + :return: None + """ + subprocess_command = gen_subprocess_args(config) + display_config(subprocess_command) + run_nuitka(subprocess_command) + + +def cli_main() -> None: + """ + entering point of cli + :return: None + """ if "--help" in sys.argv or "-h" in sys.argv: print(USEAGE) sys.exit(0) + if len(sys.argv) < 2: print(USEAGE) if input("are you sure to run? (y/n)") not in ["y", "Y", "yes", "Yes"]: sys.exit(0) - main() + + toml_file = toml_path_cli() + + with open(toml_file, "r", encoding="utf-8") as f: + toml = toml_loads(f.read()) + + nuitka_config = pyproject_toml(toml) + + subprocess_command = gen_subprocess_args(nuitka_config) + display_config(subprocess_command) + if input("are you sure to run? (y/n)") not in ["y", "Y", "yes", "Yes"]: + sys.exit(0) + run_nuitka(subprocess_command) diff --git a/src/lib_not_dr/nuitka/reader/arg_parser.py b/src/lib_not_dr/nuitka/reader/arg_parser.py new file mode 100644 index 0000000..aa5fc82 --- /dev/null +++ b/src/lib_not_dr/nuitka/reader/arg_parser.py @@ -0,0 +1,168 @@ +# ------------------------------- +# Difficult Rocket +# Copyright © 2020-2023 by shenjackyuanjie 3695888@qq.com +# All rights reserved +# ------------------------------- + +import sys + +from pathlib import Path +from warnings import warn +from typing import Iterable, Dict, Union, List + + +def pyproject_toml(toml_data: dict) -> dict: + """ + :param toml_data: dict (from pyproject/ raw dict) + :return: dict + """ + if "tool" not in toml_data: + raise ValueError(f"No tool section in config file/dict") + + if "lndl" not in toml_data["tool"]: + raise ValueError(f"No lib-not-dr(lndl) section in config file/dict") + + if "nuitka" not in toml_data["tool"]["lndl"]: + raise ValueError(f"No lib-not-dr(lndl).nuitka section in config file/dict") + + nuitka_config = toml_data["tool"]["lndl"]["nuitka"] + + if "main" not in nuitka_config: + raise ValueError( + "'main' not define in lib-not-dr(lndl).nuitka section\ndefine it with 'main = []'" + ) + + return nuitka_config + + +def toml_path_cli() -> Path: + """ + get toml path from cli args + :return: Path + """ + if len(sys.argv) < 2: + raw_path = Path().cwd() + else: + raw_path = Path(sys.argv[1]) + if raw_path.is_file(): + return raw_path + + elif raw_path.is_dir(): + if (raw_path / "pyproject.toml").exists(): + return raw_path / "pyproject.toml" + else: + raise FileNotFoundError(f"pyproject.toml not found in {raw_path}") + else: + raise FileNotFoundError(f"{raw_path} not found") + + +def get_cli_nuitka_args() -> dict: + """ + get -- from sys.argv + :return: list + """ + # no -- in sys.argv + if len(sys.argv) < 2: + return {} + if '--' not in sys.argv: + print(f"invalid args: {sys.argv}") + return {} + + # start from -- + index = sys.argv.index('--') + new_args = sys.argv[index + 1:] + arg_dict = {} + for arg in new_args: + if not arg.startswith('--'): + warn(f"invalid arg: {arg}") + else: + arg = arg[2:] # remove -- + # arg_name: --= + arg_name = arg.split('=')[0] + if '=' in arg: + arg_value = arg.split('=')[1] + else: + arg_value = True + arg_dict[arg_name] = arg_value + + print(f"cli config: {arg_dict}") + return arg_dict + + +def merge_cli_config(toml_config: dict, cli_config: dict) -> dict: + """ + merge toml config and cli config + :param toml_config: + :param cli_config: + :return: + """ + for name, value in cli_config.items(): + if name in toml_config: + warn(f"\033[33mcli config will overwrite toml config\n{name}:{toml_config[name]} -> {value}\033[0m") + if isinstance(toml_config[name], bool): + if not isinstance(value, bool): + warn(f"cli config {name} is bool but toml config is not\n{value} -> {value}") + continue + toml_config[name] = value + elif isinstance(toml_config[name], str): + if not isinstance(value, str): + warn(f"cli config {name} is str but toml config is not\n{value} -> {value}") + continue + toml_config[name] = value + elif isinstance(toml_config[name], Iterable): + if not isinstance(value, str): + warn(f"cli config {name} is Iterable but toml config is not\n{value} -> {value}") + continue + toml_config[name].append(value) + else: + toml_config[name] = value + return toml_config + + +def gen_subprocess_args(nuitka_config: + Dict[str, Union[str, bool, List[Union[str, tuple]]]]) -> list: + cmd_list = [sys.executable, "-m", "nuitka"] + + nuitka_config = merge_cli_config(nuitka_config, get_cli_nuitka_args()) + + def parse_value(arg_name, arg_value) -> list: + if isinstance(value, bool): + warn(f"bool value is not supported in list config {arg_name}") + return [] + elif isinstance(value, str): + return [f"--{arg_name}={arg_value}"] + else: + return [f"--{arg_name}={arg_value[0]}={arg_value[1]}"] + + for name, value in nuitka_config.items(): + if value is True: + # -- + cmd_list.append(f"--{name}") + continue + elif isinstance(value, str): + # --= + cmd_list.append(f"--{name}={value}") + continue + elif isinstance(value, Iterable): + if '__spilt__' in value: + # --= --= ... + for item in value: + if item == '__spilt__': + continue + cmd_list += parse_value(name, item) + continue + if all(isinstance(item, str) for item in value): + # --=,,... + cmd_list.append(f"--{name}={','.join(value)}") + elif all(isinstance(item, (tuple, list)) for item in value): + # --== + # --==,... + for item in value: + cmd_list.append(f"--{name}={item[0]}={item[1]}") + else: + # 处理混杂的情况 + for item in value: + cmd_list += parse_value(name, item) + continue + + return cmd_list diff --git a/src/lndl_nuitka/__init__.py b/src/lndl_nuitka/__init__.py index 25eec6f..eba8341 100644 --- a/src/lndl_nuitka/__init__.py +++ b/src/lndl_nuitka/__init__.py @@ -4,9 +4,9 @@ # All rights reserved # ------------------------------- -from lib_not_dr.nuitka.parse import main +from lib_not_dr.nuitka.reader import cli_main if __name__ == '__main__': - main() + cli_main() -main = main \ No newline at end of file +main = cli_main