覆盖文生 3D、图生 3D、多视图、批量生成,以及重拓扑、绑定、动画、智能分割、 纹理、PBR、智能 UV、部件补全、格式导出与下载。 代码组织:一个功能一个模块(tripo/features/),入口薄壳 tripocli.py。
129 lines
4.1 KiB
Python
129 lines
4.1 KiB
Python
"""Self-update: refresh the installed CLI from the project source tree.
|
||
|
||
The project is distributed as a source directory (no PyPI release yet), so
|
||
"updating" means: find the source tree, re-install it with the *same*
|
||
interpreter that is running us, and rehash pyenv shims if pyenv is in use.
|
||
|
||
The source directory is remembered in ``~/.tripo/config.json`` (``install_source``)
|
||
the first time it is discovered, so later runs only need ``tripocli update``.
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import shutil
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from . import __version__
|
||
|
||
INSTALL_SOURCE_KEY = "install_source"
|
||
|
||
|
||
def _running_package_dir():
|
||
"""Directory of the ``tripo`` package that is currently imported."""
|
||
return Path(__file__).resolve().parent
|
||
|
||
|
||
def _is_site_packages(path):
|
||
parts = {p.lower() for p in Path(path).parts}
|
||
return bool(parts & {"site-packages", "dist-packages"})
|
||
|
||
|
||
def detect_source(explicit=None, config=None):
|
||
"""Locate the source tree to install from.
|
||
|
||
Order: ``--from`` > remembered ``install_source`` > the tree we were imported
|
||
from (only when that is not site-packages).
|
||
"""
|
||
if explicit:
|
||
candidate = Path(explicit).expanduser().resolve()
|
||
if not (candidate / "pyproject.toml").exists():
|
||
raise ValueError(f"{candidate} 看起来不是项目目录(缺少 pyproject.toml)")
|
||
return candidate
|
||
|
||
if config:
|
||
remembered = config.data.get(INSTALL_SOURCE_KEY)
|
||
if remembered and (Path(remembered) / "pyproject.toml").exists():
|
||
return Path(remembered)
|
||
|
||
package_dir = _running_package_dir()
|
||
if not _is_site_packages(package_dir):
|
||
root = package_dir.parent
|
||
if (root / "pyproject.toml").exists():
|
||
return root
|
||
|
||
return None
|
||
|
||
|
||
def installed_version():
|
||
"""Version of the copy in site-packages (what other directories will run)."""
|
||
try:
|
||
out = subprocess.run(
|
||
[sys.executable, "-m", "pip", "show", "tripocli"],
|
||
capture_output=True, text=True, timeout=60,
|
||
)
|
||
except (OSError, subprocess.SubprocessError):
|
||
return None
|
||
for line in out.stdout.splitlines():
|
||
if line.lower().startswith("version:"):
|
||
return line.split(":", 1)[1].strip()
|
||
return None
|
||
|
||
|
||
def _has_pyenv():
|
||
return bool(shutil.which("pyenv") or os.environ.get("PYENV_ROOT"))
|
||
|
||
|
||
def update(source, rehash=True, dry_run=False):
|
||
"""Re-install ``source`` with the running interpreter. Returns a report dict."""
|
||
source = Path(source)
|
||
steps = []
|
||
command = [
|
||
sys.executable, "-m", "pip", "install",
|
||
"--no-build-isolation", "--no-deps", "--upgrade", "--force-reinstall", str(source),
|
||
]
|
||
|
||
if dry_run:
|
||
planned = [" ".join(command)]
|
||
if rehash and _has_pyenv():
|
||
planned.append("pyenv rehash")
|
||
return {"source": str(source), "command": command, "steps": planned,
|
||
"rehash": False, "dry_run": True, "version": __version__}
|
||
|
||
proc = subprocess.run(command, capture_output=True, text=True)
|
||
steps.append(" ".join(command))
|
||
tail = "\n".join((proc.stdout or "").strip().splitlines()[-6:])
|
||
if proc.returncode != 0:
|
||
raise RuntimeError(
|
||
f"pip 安装失败(退出码 {proc.returncode}):\n{(proc.stderr or proc.stdout or '')[-800:]}"
|
||
)
|
||
steps.append(tail)
|
||
|
||
rehashed = False
|
||
if rehash and _has_pyenv():
|
||
subprocess.run(["pyenv", "rehash"], capture_output=True, text=True)
|
||
steps.append("pyenv rehash")
|
||
rehashed = True
|
||
|
||
return {
|
||
"source": str(source),
|
||
"command": command,
|
||
"steps": steps,
|
||
"rehash": rehashed,
|
||
"version": __version__,
|
||
"installed_version": installed_version(),
|
||
}
|
||
|
||
|
||
def report_lines(report):
|
||
prefix = "将执行" if report.get("dry_run") else "已执行"
|
||
lines = [
|
||
f"源码目录 : {report['source']}",
|
||
f"版本 : {report.get('installed_version') or report['version']}",
|
||
f"{prefix} : {'; '.join(report['steps'])}",
|
||
]
|
||
if report.get("rehash"):
|
||
lines.append("已执行 : pyenv rehash")
|
||
return lines
|