softwares

ubuntu-24.04.3-wsl-amd64.gz
https://softwares-b243.obs.cn-north-4.myhuaweicloud.com/ubuntu-24.04.3-wsl-amd64.gz

mac-soft

#!/usr/bin/env python3
import os
import sys
import shutil
import subprocess
import re
import plistlib  # <--- 新增这个库,用于修改 Info.plist
from pathlib import Path

# ==============================================================================
#  配置区
# ==============================================================================
SCRIPT_DIR = Path(__file__).resolve().parent

def get_version():
    init_path = SCRIPT_DIR / "mind_tree/__init__.py"
    try:
        with open(init_path, "r", encoding="utf-8") as f:
            content = f.read()
        match = re.search(r'__version__\s*=\s*["\']([^"\']+)["\']', content)
        if match:
            return match.group(1)
        return "1.0.0"
    except:
        return "1.0.0"

VERSION = get_version()

class Config:
    APP_NAME = "Mind Tree"
    APP_SLUG = "mind-tree"
    VERSION = VERSION
    
    SCRIPT_DIR = SCRIPT_DIR
    PYINSTALLER_ENTRY_POINT = SCRIPT_DIR / "mind_tree/main.py"
    
    DIST_DIR = SCRIPT_DIR / "dist"
    WORK_DIR = SCRIPT_DIR / "build"
    
    ICON_PATH = SCRIPT_DIR / "mind_tree/libs/mind-tree-logo-3.ico"
    ASSETS_SOURCE = SCRIPT_DIR / "mind_tree/libs"
    ASSETS_DEST = "libs"

# ==============================================================================
#  工具函数
# ==============================================================================
def log(msg):
    print(f"\033[0;32m[MacBuild] {msg}\033[0m")

def run_cmd(cmd):
    print(f"Running: {' '.join([str(c) for c in cmd])}")
    subprocess.check_call([str(c) for c in cmd])

def get_snownlp_path():
    import snownlp
    return Path(snownlp.__file__).parent

def modify_info_plist(app_path):
    """
    修改生成的 Info.plist,设置 LSUIElement=True (隐藏 Dock 图标)
    """
    plist_path = app_path / "Contents" / "Info.plist"
    if not plist_path.exists():
        print(f"Error: Info.plist not found at {plist_path}")
        sys.exit(1)
        
    log(f"Modifying Info.plist at: {plist_path}")
    
    try:
        # 读取 Plist
        with open(plist_path, 'rb') as f:
            plist_data = plistlib.load(f)
        
        # 修改:设置为后台应用
        plist_data['LSUIElement'] = True
        # 也可以顺便加上 Bundle Identifier,防止系统混淆
        plist_data['CFBundleIdentifier'] = "com.mindtree.app"
        
        # 写回 Plist
        with open(plist_path, 'wb') as f:
            plistlib.dump(plist_data, f)
            
        log("Info.plist modified successfully (LSUIElement=True).")
        
    except Exception as e:
        print(f"Failed to modify Info.plist: {e}")
        sys.exit(1)

# ==============================================================================
#  主逻辑
# ==============================================================================
def main():
    log("=== Starting macOS Build Process (Plan B) ===")

    # 1. PyInstaller 打包
    snownlp_path = get_snownlp_path()
    
    cmd = [
        "pyinstaller",
        "--clean", "--noconfirm", 
        "--onedir",
        "--windowed",
        "--name", Config.APP_NAME,
        "--workpath", str(Config.WORK_DIR),
        "--distpath", str(Config.DIST_DIR),
        "--specpath", str(Config.WORK_DIR),
        "--add-data", f"{Config.ASSETS_SOURCE}:{Config.ASSETS_DEST}",
        "--icon", str(Config.ICON_PATH),
        "-p", str(Config.SCRIPT_DIR),
        "--hidden-import", "sip",
        # 注意:这里去掉了 --runtime-hook 和 --plist-items
        # 我们改用 post-build 修改的方式
    ]

    # SnowNLP 数据
    for sub in ["normal", "tag", "seg", "sentiment"]:
        src = snownlp_path / sub
        if src.exists():
            cmd.extend(["--add-data", f"{src}:snownlp/{sub}"])

    cmd.append(str(Config.PYINSTALLER_ENTRY_POINT))
    run_cmd(cmd)

    app_path = Config.DIST_DIR / f"{Config.APP_NAME}.app"
    if not app_path.exists():
        print("Error: .app bundle not found!")
        sys.exit(1)

    log(f"App bundle created at: {app_path}")

    # 2. 【关键步骤】修改 Info.plist 使其默认为后台应用
    modify_info_plist(app_path)

    # 3. 重新签名 (因为修改了 plist,必须重签,否则 M1 上会崩溃)
    log("Applying Ad-hoc signature (Required for Apple Silicon)...")
    try:
        run_cmd(["codesign", "--force", "--deep", "--sign", "-", str(app_path)])
        log("Ad-hoc signing complete.")
    except Exception as e:
        print(f"Warning: Signing failed. Error: {e}")

    # 4. 创建 .dmg
    dmg_name = f"{Config.APP_SLUG}-{Config.VERSION}-macos.dmg"
    dmg_path = Config.DIST_DIR / dmg_name
    
    if dmg_path.exists():
        dmg_path.unlink()

    log("Creating .dmg disk image...")
    run_cmd([
        "hdiutil", "create",
        "-volname", Config.APP_NAME,
        "-srcfolder", str(app_path),
        "-ov",
        "-format", "UDZO",
        str(dmg_path)
    ])

    log("✅ macOS Build Complete!")
    log(f"DMG File: {dmg_path}")

if __name__ == "__main__":
    main()
# mind_tree/main.py
import sys
import multiprocessing
# ... 其他 import ...

def promote_to_foreground():
    """
    [macOS] 将当前进程从后台(LSUIElement)升级为前台应用。
    效果:图标会出现在 Dock 栏,且窗口可以获取焦点。
    """
    if sys.platform != 'darwin':
        return

    try:
        from ctypes import cdll, util, c_int, c_void_p, Structure, POINTER, byref

        # 加载系统库
        app_services = cdll.LoadLibrary(util.find_library('ApplicationServices'))
        
        # 1. 获取当前进程 PSN (Process Serial Number)
        class ProcessSerialNumber(Structure):
            _fields_ = [("highLongOfPSN", c_int), ("lowLongOfPSN", c_int)]
            
        psn = ProcessSerialNumber()
        # GetCurrentProcess(ProcessSerialNumber *PSN)
        app_services.GetCurrentProcess.argtypes = [POINTER(ProcessSerialNumber)]
        app_services.GetCurrentProcess(byref(psn))

        # 2. 变形!(TransformProcessType)
        # kProcessTransformToForegroundApplication = 1
        # 这会让图标优雅地滑入 Dock 栏
        app_services.TransformProcessType.argtypes = [POINTER(ProcessSerialNumber), c_int]
        app_services.TransformProcessType(byref(psn), 1)

        # 3. (可选) 强制让应用置顶并获取焦点
        # 如果发现图标出来了但窗口在后面,可以加这段逻辑
        # 为了不引入 pyobjc 依赖,这里简化处理,通常 GUI 框架(PyQt/Tkinter)的 show() 会处理好焦点
        
    except Exception as e:
        print(f"设置 Dock 图标失败: {e}")

# rthook_hide_dock.py
import sys
import os
from ctypes import cdll, util, c_int, c_uint, Structure, byref, POINTER

# 定义 macOS 的 ProcessSerialNumber 结构体
class ProcessSerialNumber(Structure):
    _fields_ = [("highLongOfPSN", c_uint),
                ("lowLongOfPSN", c_uint)]

def _log(msg):
    try:
        with open("/tmp/mit_debug.txt", "a") as f:
            pid = os.getpid()
            f.write(f"[PID {pid}] {msg}\n")
    except:
        pass

if sys.platform == 'darwin':
    try:
        args = sys.argv
        should_hide = False

        # 1. 检测逻辑 (保持你之前的逻辑,因为检测是成功的)
        if '-c' in args:
            for arg in args:
                if 'resource_tracker' in arg:
                    should_hide = True
                    break
        
        for arg in args:
            if 'multiprocessing' in arg and 'fork' in arg:
                should_hide = True
                break

        if should_hide:
            # 加载 ApplicationServices
            core_services_lib = util.find_library('ApplicationServices')
            if core_services_lib:
                core_services = cdll.LoadLibrary(core_services_lib)

                # === 修正部分开始 ===
                
                # 1. 定义 GetCurrentProcess 函数
                # OSErr GetCurrentProcess(ProcessSerialNumber *PSN);
                core_services.GetCurrentProcess.argtypes = [POINTER(ProcessSerialNumber)]
                core_services.GetCurrentProcess.restype = c_int

                # 2. 定义 TransformProcessType 函数
                # OSStatus TransformProcessType(const ProcessSerialNumber *psn, ProcessApplicationTransformState transformState);
                core_services.TransformProcessType.argtypes = [POINTER(ProcessSerialNumber), c_int]
                core_services.TransformProcessType.restype = c_int

                # 3. 获取当前进程的 PSN
                psn = ProcessSerialNumber()
                err_get = core_services.GetCurrentProcess(byref(psn))
                
                if err_get == 0:
                    # 4. 使用获取到的 PSN 进行转换
                    # kProcessTransformToBackgroundApplication = 2
                    err_transform = core_services.TransformProcessType(byref(psn), 2)
                    _log(f"隐藏尝试完成。GetPSN: {err_get}, Transform: {err_transform}")
                else:
                    _log(f"获取进程PSN失败: {err_get}")
                
                # === 修正部分结束 ===

            else:
                _log("错误:无法加载 ApplicationServices")

    except Exception as e:
        _log(f"发生异常: {e}")
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew update
brew install python@3.12


echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc
echo 'eval "$(pyenv init -)"' >> ~/.zshrc


import sys

def make_process_background():
    """
    将当前进程转为后台进程(隐藏 Dock 图标)。
    仅在 macOS 下打包后的环境有效。
    """
    if sys.platform != 'darwin':
        return

    try:
        from ctypes import cdll, util, c_int, c_void_p
        
        # 1. 加载 ApplicationServices 框架
        core_services_path = util.find_library('ApplicationServices')
        if not core_services_path:
            return
        core_services = cdll.LoadLibrary(core_services_path)
        
        # 2. 调用 TransformProcessType
        # kProcessTransformToBackgroundApplication = 2
        # 这会让系统把当前进程标记为后台进程,从而移除 Dock 图标
        core_services.TransformProcessType.argtypes = [c_void_p, c_int]
        core_services.TransformProcessType(None, 2) 
        
    except Exception:
        # 如果失败了也不要让程序崩溃,只是图标去不掉而已
        pass