fix(task-worktree): 联接列改三态点名——半联树不再被说成已联,adopt 没补齐不许报就绪
同一个谎有两处,根因是「联没联上」有两套判定:列表只取样 JUNCTION_SPECS 首项 (.venv),而 adopt 填两条。于是「有 .venv、缺 simulator/SDL2」的半联树被报成已联, adopt 遇主线缺 SDL2 走 skip、联接失败走 warn,回来照样打「现在可以跑」——宣布就绪。 改法是把判定收成一处: - 新增 junction_states() 三态(link / real 实体内容 / absent 真缺)与 junction_label(), plugin_trees() 改读三态;adopt_junctions() 也改读同一函数,消除两处逻辑分叉。 - 列表按缺的那一样分别说后果:缺 .venv 会**静默**落到机器级解释器(无 fontTools, 即 generated-fresh 假红的老根因);缺 simulator/SDL2 是模拟器当场报错(CMakeLists.txt 的 SDL2_DIR 是裸 set,没有环境变量逃生口)。实体目录单列齐(实体SDL2),不算共享。 - adopt 补完复算一次,仍缺就打「还不能算就绪」,不再打「现在可以跑」;锁归属与 锁命令照常打印。 - SKILL.md 同步四处措辞,并把「adopt 之前跑不了 Python」这条不准确的说法换成上面 两种真实失败方式(一条是静默错解释器、一条是响亮报错)。 验证:scratch 仓 16 条断言全 PASS(全联 / 只摘 SDL2 那条 → 缺 SDL2 且不得再出现已联 / 实体目录不被覆盖 / unadopt 只摘联接 / 主线缺 SDL2 时 skip + 不报就绪 / 已联的 .venv 不误报 / 两样都缺 → 缺 .venv+SDL2),同一半联态上新旧对照 = 缺 SDL2 vs 已联。 py_compile 通过;doc-links --all --sections-strict 与编号门禁绿;两文件无 BOM、无 U+FFFD、纯 LF、无行尾空格。改动只落在 .dsh/,不进体积门禁指纹面,也不需要 @build。
This commit is contained in:
@@ -442,6 +442,35 @@ def plugin_dir_for(name: str) -> Path:
|
||||
return p
|
||||
|
||||
|
||||
def junction_states(wt: Path):
|
||||
"""每个共享联接的三态:link(目录联接)/ real(实体内容)/ absent(真缺)。
|
||||
|
||||
这是「联没联上」的**唯一**判定处——列表显示与 adopt 收尾都读它。早先列表只取样
|
||||
JUNCTION_SPECS 的第一项,于是「有 .venv、缺 simulator/SDL2」的半联树被报成已联,
|
||||
而 adopt 可以只成功一条(主线缺 SDL2 走 skip、联接失败走 warn)→ 说谎的正是这一列。
|
||||
"""
|
||||
st = {}
|
||||
for rel, _desc in JUNCTION_SPECS:
|
||||
link = wt / rel
|
||||
if is_reparse(link):
|
||||
st[rel] = "link"
|
||||
elif os.path.lexists(str(link)):
|
||||
st[rel] = "real"
|
||||
else:
|
||||
st[rel] = "absent"
|
||||
return st
|
||||
|
||||
|
||||
def junction_label(st) -> str:
|
||||
"""把三态压成一列短标签:缺什么都点名,实体内容也算「齐」但不算共享。"""
|
||||
tag = {rel: rel.rsplit("/", 1)[-1] for rel in st}
|
||||
absent = [tag[r] for r, s in st.items() if s == "absent"]
|
||||
real = [tag[r] for r, s in st.items() if s == "real"]
|
||||
if absent:
|
||||
return "缺 " + "+".join(absent)
|
||||
return "齐(实体" + "+".join(real) + ")" if real else "已联"
|
||||
|
||||
|
||||
def plugin_trees():
|
||||
""".dsh-worktrees/worktree/ 下的工作树(事实源 = git worktree list,不读插件 manifest)。
|
||||
|
||||
@@ -469,7 +498,7 @@ def plugin_trees():
|
||||
"path": str(p),
|
||||
"branch": ent.get("branch") or "(detached)",
|
||||
"dirty": dirty,
|
||||
"adopted": is_reparse(p / JUNCTION_SPECS[0][0]),
|
||||
"jn": junction_states(p),
|
||||
})
|
||||
return trees
|
||||
|
||||
@@ -482,25 +511,34 @@ def print_plugin_trees() -> int:
|
||||
print()
|
||||
print("DSH 插件工作树({} 下;**不在本 skill 台账** → 不占 {} 个名额、done/abort "
|
||||
"管不到,回收走 /worktree remove|prune):".format(PLUGIN_SUBDIR, MAX_CONCURRENT))
|
||||
print("{:<26} {:<34} {:>4} {:>6}".format("名称", "分支", "脏", "联接"))
|
||||
print("{:<26} {:<34} {:>4} {:>16}".format("名称", "分支", "脏", "联接"))
|
||||
for t in trees:
|
||||
print("{:<26} {:<34} {:>4} {:>6}".format(
|
||||
print("{:<26} {:<34} {:>4} {:>16}".format(
|
||||
t["name"], t["branch"], "-" if t["dirty"] < 0 else str(t["dirty"]),
|
||||
"已联" if t["adopted"] else "未联"))
|
||||
if any(not t["adopted"] for t in trees):
|
||||
print("未联的进去跑不了 Python:「plugin adopt <name>」只建共享联接,不碰树内容")
|
||||
junction_label(t["jn"])))
|
||||
def miss(rel):
|
||||
return any(t["jn"].get(rel) == "absent" for t in trees)
|
||||
if miss(".venv"):
|
||||
print(" 缺 .venv:进去跑 @build / ci_local.py 会**静默**落到机器级解释器(无 "
|
||||
"fontTools,generated-fresh 假红的老根因)")
|
||||
if miss("simulator/SDL2"):
|
||||
print(" 缺 simulator/SDL2:模拟器 build_sim.bat 直接报错——CMakeLists.txt 的 "
|
||||
"SDL2_DIR 是裸 set,没有环境变量逃生口")
|
||||
if miss(".venv") or miss("simulator/SDL2"):
|
||||
print(" 补法:「plugin adopt <name>」——只建缺失的联接,不碰树里任何文件")
|
||||
return len(trees)
|
||||
|
||||
|
||||
def adopt_junctions(wt: Path):
|
||||
"""只补**缺失**的共享联接(已联的跳过、实体目录绝不碰),返回 (已有, 本次新建)。"""
|
||||
already, made = [], []
|
||||
st = junction_states(wt)
|
||||
for rel, desc in JUNCTION_SPECS:
|
||||
link = wt / rel
|
||||
if is_reparse(link):
|
||||
if st[rel] == "link":
|
||||
already.append(rel)
|
||||
continue
|
||||
if os.path.lexists(str(link)):
|
||||
if st[rel] == "real":
|
||||
print("[warn] {} 已是实体目录/文件(不是联接)——不动它".format(rel))
|
||||
already.append(rel)
|
||||
continue
|
||||
@@ -537,10 +575,17 @@ def cmd_plugin(a) -> int:
|
||||
print("为插件树补共享联接:{}".format(wt))
|
||||
already, made = adopt_junctions(wt)
|
||||
owner = plugin_lock_owner(a.name)
|
||||
# 复算一次:adopt 里 skip/warn/失败都不算成功,「已有 N + 新建 M」两两相加可能对不上
|
||||
# 总数——就绪判定只能按**现在的实际状态**说,否则又是把没联上的说成联上了
|
||||
still = [r for r, s in junction_states(wt).items() if s == "absent"]
|
||||
print()
|
||||
print("[ok] 联接:已有 {} 个、本次新建 {} 个".format(len(already), len(made)))
|
||||
print("该目录现在可以跑 @build / ci_local.py / @test;build 锁由 keil_build.py "
|
||||
"自持自释,持有者名就是 {}".format(owner))
|
||||
if still:
|
||||
print("[warn] 仍缺 {}:主线里该路径不存在或联接失败——先补主线再复跑 adopt"
|
||||
"(这棵树还不能算就绪)".format("、".join(still)))
|
||||
else:
|
||||
print("该目录现在可以跑 @build / ci_local.py / @test")
|
||||
print("build 锁由 keil_build.py 自持自释,持有者名就是 {}".format(owner))
|
||||
print("上台架前:$TW lock acquire bench --task {} --note <说明>".format(owner))
|
||||
print("下台架后:$TW lock release bench --task {}".format(owner))
|
||||
print("回收仍归插件:/worktree remove {}(本 skill 不删插件树)".format(a.name))
|
||||
|
||||
Reference in New Issue
Block a user