#!/usr/bin/env python3
import argparse
from collections import OrderedDict
import os
import re
import shutil
import subprocess
import yaml
import stat
import zlib
from datetime import datetime
import socket
try:
    import requests
except ImportError:
    print("Installing required dependencies...")
    subprocess.check_call(
        [
            "pip3",
            "install",
            "requests",
        ]
    )
    import requests
try:
    from filelock import Timeout, FileLock
except ImportError:    
    print("Installing required dependencies...")
    subprocess.check_call(
        [
            "pip3",
            "install",
            "filelock",
        ]
    )
    from filelock import Timeout, FileLock
guru_dir = os.path.expanduser("~/.guru-external")
current_dir = os.getcwd()
gurusdk_giturl = "git@git.chengdu.pundit.company:castbox/gurusdk.git"
gurumodules_giturl = "git@git.chengdu.pundit.company:castbox/guru_modules.git"
gurusdk_use_submodule = False
def get_guru_dir():
    return guru_dir
def get_guru_flutter_dir():
    return f"{get_guru_dir()}/flutter"
def get_gurusdk_root():
    return f"{get_guru_flutter_dir()}/gurusdk"
def get_gurusdk_integrated_dir(app):
    return f"{get_gurusdk_root()}/integrated/{app}"
def get_gurusdk_runtime_dir(app):
    return f"{get_gurusdk_integrated_dir(app)}/gurusdk"
def get_gurusdk_compiler_dir(app):
    return f"{get_gurusdk_integrated_dir(app)}/gurusdk_compiler"
def calculate_pubspec_crc32(pubpaths, initial_crc=0):
    crc = initial_crc  # 初始 CRC 值
    for pubspec_path in pubpaths:
        # 更新 CRC 值,注意确保数据块是字节串
        with open(pubspec_path, "r") as file:
            data = file.read()
            crc = zlib.crc32(data.encode("utf-8"), crc)
    return crc
def change_dart_files_readonly(directory):
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(".dart"):
                full_path = os.path.join(root, file)
                current_permissions = os.stat(full_path).st_mode
                readonly_permissions = current_permissions & ~stat.S_IWRITE
                os.chmod(full_path, readonly_permissions)
def search_pkg_dirs(target_root):
    results = []
    for dirpath, dirnames, filenames in os.walk(target_root):
        # Check if the file is a pubspec.yaml file
        for filename in filenames:
            if filename == "pubspec.yaml":
                dir = dirpath.removeprefix(f"{target_root}/")
                results.append(dir)
    return results
def gurusdk_crc32(version, target_dir):
    pkg_dirs = search_pkg_dirs(target_dir)
    pubpaths = []
    initial_crc = zlib.crc32(version.encode("utf-8"), 2627)
    pkg_dirs.sort()
    for dir in pkg_dirs:
        package_name = os.path.basename(dir)
        if package_name not in invalid_pkgs and package_name not in dev_pkgs:
            pubpaths.append(f"{target_dir}/{dir}/pubspec.yaml")
    return calculate_pubspec_crc32(pubpaths, initial_crc=initial_crc)
invalid_pkgs = {"example", "flutter_2048", "showcase"}
dev_pkgs = {"guru_splash_flutter"}
def gurusdk_snapshot(version, target_dir):
    os.chdir(target_dir)
    crc = gurusdk_crc32(version, target_dir)
    print(f"crc32: {crc}")
    cmdrun(f"echo '[CRC]{crc}' > .gurusdk")
    if gurusdk_use_submodule:
        cmdrun(f"git submodule >> .gurusdk")
def gurusdk_dir():
    if not os.path.exists("gurusdk.yaml"):
        gsdir = cmdrun("which gurusdk", loggable=False)[0]
        while len(gsdir) > 0:
            gsdir = os.path.dirname(gsdir)
            if is_gurusdk_dir(gsdir):
                print(gsdir)
                exit(0)
        exit(-1)
    with open("gurusdk.yaml", "r") as file:
        config = yaml.safe_load(file)
    with open("pubspec.yaml", "r") as file:
        pubspec_config = yaml.safe_load(file)
    if pubspec_config.get("gurulib", False):
        print("\033[31m" + "`update` action Not Support gurulib!" + "\033[0m")
        exit(-1)
    app = pubspec_config["name"]
    dir = get_gurusdk_integrated_dir(app)
    print(dir)
    exit(0)
def gurusdk_update():
    os.chdir(current_dir)
    with open("gurusdk.yaml", "r") as file:
        config = yaml.safe_load(file)
    with open("pubspec.yaml", "r") as file:
        pubspec_config = yaml.safe_load(file)
    if pubspec_config.get("gurulib", False):
        print("Not Support gurulib project")
        print("\033[31m" + "`update` action Not Support gurulib!" + "\033[0m")
        exit(0)
    app = pubspec_config["name"]
    gurusdk_runtime_dir = get_gurusdk_runtime_dir(app)
    runtime_lock = {}
    if not os.path.exists(f"{gurusdk_runtime_dir}/gurusdk.lock"):
        print(
            "\033[31m"
            + "gurusdk.lock not found! please use `gurusdk get` command first"
            + "\033[0m"
        )
        exit(0)
    with open(f"{gurusdk_runtime_dir}/gurusdk.lock", "r") as file:
        runtime_lock.update(yaml.safe_load(file))
    locked_version = runtime_lock["guru_sdk"]
    version = config["guru_sdk"]
    if locked_version != version:
        print(
            "\033[31m"
            + f"Locked version({locked_version}) != config version({version}), please use `gurusdk get` command first"
            + "\033[0m"
        )
        exit(0)
    version_dir = f"{get_gurusdk_root()}/{version}"
    if os.path.exists(f"{version_dir}/sdk_commit"):
        with open(f"{version_dir}/sdk_commit", "r") as file:
            sdk_commit = file.readline().strip()
        resolved_ref = cmdrun(
            f"git ls-remote {gurusdk_giturl} {version} | awk '{{print $1}}'"
        )[0]
        print("sdk_commit: ", sdk_commit, "resolved_ref: ", resolved_ref)
        if sdk_commit != resolved_ref:
            gurusdk_download(version, force=True)
    else:
        gurusdk_download(version, force=True)
def gurusdk_download(version, force=False):
    gurusdk_root = get_gurusdk_root()
    gurusdk_version_dir = f"{gurusdk_root}/{version}"
    if os.path.exists(gurusdk_version_dir):
        crc32 = gurusdk_crc32(version, gurusdk_version_dir)
        with open(f"{gurusdk_version_dir}/.gurusdk", "r") as file:
            filedata = file.readline().strip()
        crcStr = f"[CRC]{crc32}"
        if filedata != crcStr:
            print(
                f"{filedata} != {crcStr}! remove {gurusdk_version_dir}, re-download.."
            )
            shutil.rmtree(gurusdk_version_dir)
    version_dir_exists = os.path.exists(gurusdk_version_dir)
    if force or not version_dir_exists:
        if version_dir_exists:
            shutil.rmtree(gurusdk_version_dir)
        os.chdir(gurusdk_root)
        os.system(
            f"git clone -b {version} --single-branch --depth 1 {gurusdk_giturl} {version}"
        )
        os.chdir(gurusdk_version_dir)
        if gurusdk_use_submodule:
            os.system("git submodule init")
            os.system("git submodule update")
            os.remove(".gitmodules")
        cmdrun("git rev-parse HEAD > sdk_commit")
        shutil.rmtree(f".git")
        change_dart_files_readonly(gurusdk_version_dir)
    return gurusdk_version_dir
def guru_modules_sync():
    guru_flutter_dir = get_guru_flutter_dir()
    guru_modules_dir = f"{guru_flutter_dir}/guru_modules"
    if os.path.exists(guru_modules_dir) != True:
        os.makedirs(guru_flutter_dir, exist_ok=True)
        os.chdir(guru_flutter_dir)
        os.system(
            f"git clone {gurumodules_giturl} {guru_modules_dir}"
        )
    else:
        os.chdir(guru_modules_dir)
        cmdrun("git reset --hard HEAD")
        os.system("git pull --rebase")
    os.chdir(current_dir)
    return guru_modules_dir
def get_git_relative_path():
    try:
        git_root = subprocess.check_output(
            ["git", "rev-parse", "--show-toplevel"], encoding="utf-8"
        ).strip()
        return os.path.relpath(current_dir, git_root)
    except subprocess.CalledProcessError:
        print("current directory is not a git repository")
def gurusdk_publish():
    if os.path.exists("gurusdk.yaml") != True:
        print("\033[31m" + "gurusdk.yaml not found" + "\033[0m")
        exit(1)
    with open("gurusdk.yaml", "r") as file:
        gurusdk = yaml.safe_load(file)
    if os.path.exists("pubspec.yaml") != True:
        print("\033[31m" + "pubspec.yaml not found" + "\033[0m")
        exit(1)
    with open("pubspec.yaml", "r") as file:
        pubspec = yaml.safe_load(file)
    libname = pubspec.get("name", None)
    if not libname:
        print("\033[31m" + "`name` is required in pubspec.yaml" + "\033[0m")
        exit(1)
    if not pubspec.get("gurulib", False):
        print(
            "\033[31m"
            + "Not a gurulib project, please set gurulib: true in pubspec.yaml"
            + "\033[0m"
        )
        exit(1)
    if not pubspec.get("dependencies", {}).get(f"{libname}_gurusdk", None):
        print(
            "\033[31m"
            + f"Please use `gurusdk get` command to add {libname}_gurusdk"
            + "\033[0m"
        )
    if not pubspec.get("dev_dependencies", {}).get(f"{libname}_gurusdk_compiler", None):
        print(
            "\033[31m"
            + f"Please use `gurusdk get` command to add {libname}_gurusdk_compiler"
            + "\033[0m"
        )
    guru_modules_dir = guru_modules_sync()
    with open(f"{guru_modules_dir}/guru_modules.yaml", "r") as file:
        gurumodules = yaml.safe_load(file)
    if libname in gurumodules:
        print("\033[31m" + f"Module({libname}) already published" + "\033[0m")
        exit(1)
    modules = gurusdk.get("modules", {})
    for module in modules.keys():
        if module not in gurumodules:
            print(
                "\033[31m"
                + f"{libname} depends on {module}, but {module} not published! please publish {module} first"
                + "\033[0m"
            )
            exit(1)
    giturl = cmdrun("git remote get-url origin")[0]
    gitpath = get_git_relative_path()
    print("giturl: ", giturl, "gitpath: ", gitpath)
    gurumodules[libname] = {"git": f"{giturl}"}
    if gitpath != ".":
        gurumodules[libname]["path"] = gitpath
    resolved_ref = cmdrun(
        f"git ls-remote origin module/{libname} | awk '{{print $1}}'"
    )[0]
    if resolved_ref != "":
        print(
            "\033[31m"
            + f"Already published {libname} module! Please contact Haoyi as soon as possible to help with the review."
            + "\033[0m"
        )
        exit(1)
    os.chdir(guru_modules_dir)
    cmdrun(f"git checkout main")
    cmdrun(f"git branch -D module/{libname}", loggable=False),
    checkout_result = checkout_result = batch_cmdrun(
        [f"git checkout -b module/{libname}"]
    )
    if not checkout_result:
        print("\033[31m" + "checkout failed" + "\033[0m")
        exit(1)
    with open(f"{guru_modules_dir}/guru_modules.yaml", "w") as file:
        yaml.dump(gurumodules, file)
    result = batch_cmdrun(
        [
            "git add guru_modules.yaml",
            f"git commit -s -m 'publish `{libname}` module!'",
            f"git push --set-upstream origin module/{libname}",
            "git checkout main",
            f"git branch -D module/{libname}",
        ]
    )
    if not result:
        print("\033[31m" + "publish failed" + "\033[0m")
        exit(1)
    user_name = cmdrun("git config user.name")[0]
    user_email = cmdrun("git config user.email")[0]
    send_module_publish_notice(libname, user_name, user_email, giturl, gitpath)
    os.chdir(current_dir)
    print(f"Publish {libname} Module Success!")
def send_module_publish_notice(module, user, email, giturl, gitpath):
    now = datetime.now()
    formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S")
    hostname = socket.gethostname()
    url = f"https://github.com/castbox/guru_modules/tree/module/{module}"
    content_text = f"""【模块提审】 {user}提交「{module}」模块审核
### 审核信息
>`仓库`: {giturl}
>`路径`: {gitpath}
### 提交信息
>`邮箱`: {email}
>`日期`: {formatted_datetime}
>`主机`: {hostname}"""
    content = {"content": content_text}
    body = {"msgtype": "markdown", "markdown": content}
    headers = {"Content-Type": "application/json"}
    requests.post(
        "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=031c61ce-b504-45ac-b955-67c7e3ed840b",
        json=body,
        headers=headers,
    )
def extract_git_name(url):
    match = re.search(r"/([^/]+)\.git$", url) or re.search(r":([^/]+)\.git$", url)
    if match:
        return match.group(1)
    raise ValueError("Invalid git url: {url}")
def import_modules(app, modules, runtime_pubspec_file, locked_modules={}, refs={}):
    guru_flutter_dir = get_guru_flutter_dir()
    gurusdk_root = get_gurusdk_root()
    gurusdk_runtime_dir = get_gurusdk_runtime_dir(app)
    os.makedirs(f"{gurusdk_root}/modules", exist_ok=True)
    os.chdir(f"{gurusdk_root}/modules")
    runtime_pkg_dir = f"{gurusdk_runtime_dir}/packages"
    os.makedirs(f"{runtime_pkg_dir}", exist_ok=True)
    if not os.path.exists(f"{guru_flutter_dir}/guru_modules/guru_modules.yaml"):
        cmdrun(
            f"git clone {gurumodules_giturl} {guru_flutter_dir}/guru_modules"
        )
    else:
        guru_modules_sync()
    with open(f"{guru_flutter_dir}/guru_modules/guru_modules.yaml", "r") as file:
        gurumodules = yaml.safe_load(file)
    runtime_modules = {}
    for module, branch in modules.items():
        if module in gurumodules:
            if os.path.isdir(branch) and os.path.exists(f"{branch}/pubspec.yaml"):
                module_path = branch
            else:
                module_info = gurumodules[module]
                runtime_module_info = locked_modules.get(module, {})
                giturl = module_info["git"]
                repo_name = extract_git_name(giturl)
                resolved_ref = ""
                if (
                    runtime_module_info.get("git", "-") == giturl
                    and runtime_module_info.get("ref", "") == branch
                ):
                    resolved_ref = runtime_module_info["resolved-ref"]
                if resolved_ref == "":
                    resolved_ref = cmdrun(
                        f"git ls-remote {giturl} {branch} | awk '{{print $1}}'"
                    )[0]
                module_path = f"{gurusdk_root}/modules/{repo_name}-{resolved_ref}"
                if not os.path.exists(module_path):
                    cmdrun(
                        f"git clone -b {branch} --single-branch --depth 1 {giturl} {module_path}"
                    )
                    os.chdir(module_path)
                    curren_resolved_ref = cmdrun(f"git rev-parse HEAD")[0]
                    shutil.rmtree(f"{module_path}/.git")
                    print(
                        "resuloved_ref: ",
                        resolved_ref,
                        "curren_resolved_ref:",
                        curren_resolved_ref,
                    )
                    if curren_resolved_ref != resolved_ref:
                        os.chdir(f"{gurusdk_root}/modules")
                        changed_module_path = (
                            f"{gurusdk_root}/modules/{repo_name}-{curren_resolved_ref}"
                        )
                        os.rename(module_path, changed_module_path)
                        resolved_ref = curren_resolved_ref
                        module_path = changed_module_path
                        print("error: resolved_ref != curren_resolved_ref: fixed!!")
                runtime_modules[module] = {
                    "git": giturl,
                    "ref": branch,
                    "resolved-ref": resolved_ref,
                }
            module_subpath = ""
            if "path" in module_info:
                module_subpath = f"/{module_info['path']}"
            module_symlink = f"{runtime_pkg_dir}/{module}"
            if os.path.islink(module_symlink):
                os.unlink(module_symlink)
            os.symlink(f"{module_path}{module_subpath}", module_symlink)
            new_refs = set(refs)
            new_refs.add(module)
            print(f"{module_path}{module_subpath}")
            gurusdk_get(
                f"{module_path}{module_subpath}",
                gurusdk_resolved_ref=resolved_ref,
                refs=new_refs,
            )
            os.chdir(gurusdk_runtime_dir)
            runtime_pubspec_file.write(f"  {module}:\n")
            runtime_pubspec_file.write(f"    path: packages/{module}\n")
            os.chdir(f"{gurusdk_root}/modules")
    return runtime_modules
def is_gurusdk_dir(target_dir):
    return (
        os.path.isdir(target_dir)
        and os.path.isdir(f"{target_dir}/guru_app")
        and os.path.isdir(f"{target_dir}/guru_ui")
        and os.path.isdir(f"{target_dir}/guru_activity")
        and os.path.isdir(f"{target_dir}/showcase")
    )
def gurusdk_get(target_dir, force=False, gurusdk_resolved_ref="", refs={}):
    print("gurusdk_get: ", target_dir)
    os.chdir(target_dir)
    with open("gurusdk.yaml", "r") as file:
        config = yaml.safe_load(file)
    with open("pubspec.yaml", "r") as file:
        pubspec_config = yaml.safe_load(file)
    pubname = pubspec_config["name"]
    app = pubname
    is_guru_lib = pubspec_config.get("gurulib", False)
    if is_guru_lib:
        runtime_ref_name = f"{pubname}_gurusdk"
        compiler_ref_name = f"{pubname}_gurusdk_compiler"
    else:
        runtime_ref_name = "gurusdk"
        compiler_ref_name = "gurusdk_compiler"
    if gurusdk_resolved_ref != "":
        app = f"{pubname}-{gurusdk_resolved_ref}"
    gurusdk_root = get_gurusdk_root()
    gurusdk_integrated_root = get_gurusdk_integrated_dir(app)
    if not os.path.exists(gurusdk_integrated_root):
        os.makedirs(gurusdk_integrated_root)
    if local is not None and is_gurusdk_dir(local):
        print(f"use local gurusdk:{local}")
        version = "local"
        gurusdk_version_dir = local
    else:
        version = config["guru_sdk"]
        gurusdk_version_dir = gurusdk_download(version, force=force)
    gurusdk_runtime_dir = get_gurusdk_runtime_dir(app)
    gurusdk_compiler_dir = get_gurusdk_compiler_dir(app)
    runtime_lock = {}
    if os.path.exists(f"{gurusdk_runtime_dir}/gurusdk.lock"):
        with open(f"{gurusdk_runtime_dir}/gurusdk.lock", "r") as file:
            runtime_lock.update(yaml.safe_load(file))
    force = force or (runtime_lock.get("guru_sdk", version) != version)
    runtime_lock = {"guru_sdk": version}
    print(f"gurusdk_get {force}")
    if force or not os.path.exists(f"{gurusdk_runtime_dir}/pubspec.yaml"):
        os.chdir(gurusdk_integrated_root)
        if os.path.exists(gurusdk_runtime_dir):
            shutil.rmtree(gurusdk_runtime_dir)
        cmdrun("flutter create --template=package gurusdk")
    os.chdir(gurusdk_runtime_dir)
    if os.path.islink(version):
        os.unlink(version)
    if version == "local":
        os.symlink(local, version)
    else:
        os.symlink(f"{gurusdk_root}/{version}", version)
    os.chdir(target_dir)
    if force or not os.path.exists(f"{gurusdk_compiler_dir}/pubspec.yaml"):
        os.chdir(gurusdk_integrated_root)
        if os.path.exists(gurusdk_compiler_dir):
            shutil.rmtree(gurusdk_compiler_dir)
        cmdrun("flutter create --template=package gurusdk_compiler")
    os.chdir(gurusdk_compiler_dir)
    if os.path.islink(version):
        os.unlink(version)
    if version == "local":
        os.symlink(local, version)
    else:
        os.symlink(f"{gurusdk_root}/{version}", version)
    os.chdir(target_dir)
    compiler_bin_dir = f"{gurusdk_compiler_dir}/bin"
    if not os.path.exists(compiler_bin_dir):
        os.makedirs(compiler_bin_dir)
    if os.path.exists(f"{gurusdk_runtime_dir}/pubspec.yaml"):
        os.remove(f"{gurusdk_runtime_dir}/pubspec.yaml")
    if os.path.exists(f"{gurusdk_compiler_dir}/pubspec.yaml"):
        os.remove(f"{gurusdk_compiler_dir}/pubspec.yaml")
    cmdrun(
        f"cp {gurusdk_version_dir}/pubspec_compiler.yaml {gurusdk_compiler_dir}/pubspec.yaml"
    )
    if os.path.exists(f"{gurusdk_runtime_dir}/build.yaml"):
        os.remove(f"{gurusdk_runtime_dir}/build.yaml")
    cmdrun(f"cp {gurusdk_version_dir}/build.yaml {gurusdk_compiler_dir}/build.yaml")
    supported_packages = {}
    pkg_dirs = search_pkg_dirs(gurusdk_version_dir)
    for dir in pkg_dirs:
        package_name = os.path.basename(dir)
        if package_name not in invalid_pkgs and package_name not in dev_pkgs:
            supported_packages[package_name] = f"{version}/{dir}"
    if version == "local":
        origin_version = "0.0.0-local"
    else:
        origin_version = version.removeprefix("v")
    integrate_packages = config["integrated"]
    with open(f"{gurusdk_compiler_dir}/pubspec.yaml", "r") as file:
        compiler_filedata = file.read()
    if compiler_ref_name != "gurusdk_compiler":
        compiler_filedata = re.sub(
            "name: gurusdk_compiler", f"name: {compiler_ref_name}", compiler_filedata
        )
    compiler_filedata = re.sub(
        "version: ", f"version: {origin_version}", compiler_filedata
    )
    compiler_filedata = re.sub("", f"{version}", compiler_filedata)
    for pkg in integrate_packages:
        if pkg not in dev_pkgs:
            continue
        print(f"[compiler integrated] pkg: {pkg}")
        compiler_filedata = re.sub(rf"#(.*{pkg}:\n)", rf" \1", compiler_filedata)
        compiler_filedata = re.sub(
            rf"#(.*path: {version}.*/{pkg}\n)", rf" \1", compiler_filedata
        )
        if pkg == "guru_splash_flutter":
            if os.path.islink(f"{compiler_bin_dir}/create_splash.dart"):
                os.unlink(f"{compiler_bin_dir}/create_splash.dart")
            os.symlink(
                f"{gurusdk_root}/{version}/guru_splash_flutter/bin/create.dart",
                f"{compiler_bin_dir}/create_splash.dart",
            )
        else:
            os.remove(f"{compiler_bin_dir}/create_splash.dart")
    with open(f"{gurusdk_compiler_dir}/pubspec.yaml", "w") as file:
        file.write(compiler_filedata)
    os.chdir(gurusdk_runtime_dir)
    with open(f"{gurusdk_version_dir}/pubspec_runtime.yaml", "r") as file:
        lines = file.readlines()
    with open(f"{gurusdk_runtime_dir}/pubspec.yaml", "w") as runtime_pubspec_file:
        for line in lines:
            if line == "name: gurusdk\n":
                runtime_pubspec_file.write(f"name: {runtime_ref_name}\n")
            elif line == "version: \n":
                runtime_pubspec_file.write(f"version: {origin_version}\n")
            elif line == "######## GURU SDK DEPENDENCIES BEGIN ########\n":
                runtime_pubspec_file.write(f"{line}\n")
                for dir in pkg_dirs:
                    package_name = os.path.basename(dir)
                    if (
                        package_name in integrate_packages
                        and package_name not in invalid_pkgs
                        and package_name not in dev_pkgs
                    ):
                        runtime_pubspec_file.write(f"  {package_name}:\n")
                        runtime_pubspec_file.write(f"    path: {version}/{dir}\n")
                if "modules" in config:
                    runtime_lock["modules"] = import_modules(
                        app,
                        config["modules"],
                        runtime_pubspec_file,
                        runtime_lock.get("modules", {}),
                        refs,
                    )
            else:
                runtime_pubspec_file.write(line)
    with open(f"{gurusdk_runtime_dir}/gurusdk.lock", "w") as file:
        yaml.dump(runtime_lock, file)
    print(target_dir)
    os.chdir(target_dir)
    if os.path.islink(f".gurusdk"):
        os.unlink(f".gurusdk")
    if os.path.islink(f".gurusdk_compiler"):
        os.unlink(f".gurusdk_compiler")
    os.symlink(f"{gurusdk_runtime_dir}", f".gurusdk")
    os.symlink(f"{gurusdk_compiler_dir}", f".gurusdk_compiler")
    runtime_cmd = f'dart pub add \'{runtime_ref_name}:{{"path":"./.gurusdk"}}\''
    if runtime_ref_name not in pubspec_config["dependencies"]:
        os.system(runtime_cmd)
    compiler_cmd = (
        f'dart pub add \'dev:{compiler_ref_name}:{{"path":"./.gurusdk_compiler"}}\''
    )
    if compiler_ref_name not in pubspec_config["dev_dependencies"]:
        os.system(compiler_cmd)
def gurusdk_dumprefs():
    os.chdir(current_dir)
    with open("gurusdk.yaml", "r") as file:
        config = yaml.safe_load(file)
    with open("pubspec.yaml", "r") as file:
        pubspec_config = yaml.safe_load(file)
    pubname = pubspec_config["name"]
    app = pubname
    version = config["guru_sdk"]
    gurusdk_root = get_gurusdk_root()
    gurusdk_runtime_dir = get_gurusdk_runtime_dir(app)
    gurusdk_version_dir = f"{gurusdk_root}/{version}"
    os.system("echo '\n============== gurusdk.lock =============='")
    os.system(f"cat {gurusdk_runtime_dir}/gurusdk.lock")
    os.system(f"echo '\n============== sdk_commit({version}) =============='")
    os.system(f"cat {gurusdk_version_dir}/sdk_commit")
    os.system("echo '\n============== .gurusdk =============='")
    os.system(f"cat {gurusdk_version_dir}/.gurusdk")
def cmdrun(command, loggable=True):
    try:
        if loggable:
            print(f"run: {command}")
        result = subprocess.run(
            command, shell=True, check=True, text=True, capture_output=True
        )
        return result.stdout.strip().split("\n")
    except subprocess.CalledProcessError as e:
        if loggable:
            print(f"Error: {e}")
        return []
def batch_cmdrun(commands, loggable=True):
    try:
        for cmd in commands:
            if loggable:
                print(f"run: {cmd}")
            subprocess.run(cmd, shell=True, check=True, text=True, capture_output=True)
        return True
    except subprocess.CalledProcessError as e:
        if loggable:
            print(f"Error: {e}")
        return False
def gurusdk_locked_get(target_dir, force=False):
    lock_path = get_guru_dir() + "/.gurusdk_lock"
    lock = FileLock(lock_path, timeout=300) 
    try:
        with lock.acquire():
            gurusdk_get(target_dir, force=force)
    except Timeout:
        print("lock acquire timeout")
    except Exception as e:
        print(f"lock acquire error: {e}")
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Process some integers.")
    parser.add_argument("action", type=str, help="action")
    parser.add_argument("version", nargs="?", type=str, help="checksum version")
    parser.add_argument("--sdk", type=str, help="flutter sdk path")
    parser.add_argument("--local", type=str, help="local path")
    parser.add_argument("--force", action="store_true", help="force")
    args = parser.parse_args()
    flutter_sdk = args.sdk
    force = args.force
    local = args.local
    if flutter_sdk:
        print(f"flutter sdk: {flutter_sdk}")
        os.environ["PATH"] = f"{flutter_sdk}:{os.environ['PATH']}"
    if args.action == "get":
        gurusdk_locked_get(current_dir, force=force)
    elif args.action == "snapshot" and args.version is not None:
        gurusdk_snapshot(args.version, current_dir)
    elif args.action == "update":
        gurusdk_update()
    elif args.action == "download":
        gurusdk_download(args.version, force=True)
    elif args.action == "publish":
        gurusdk_publish()
    elif args.action == "dir":
        gurusdk_dir()
    elif args.action == "dumprefs":
        gurusdk_dumprefs()