70 lines
3.0 KiB
Python
70 lines
3.0 KiB
Python
# actions/tier/link.py
|
|
"""Port of tier/link — @tier symlink structure for the node + each composition project."""
|
|
import os
|
|
from engine.descriptor import Meta, Arg
|
|
|
|
METADATA = Meta(summary="Create @tier symlink structure for the node + each composition project.",
|
|
args=[Arg("tier1_path", "Path to tier 1 storage root"),
|
|
Arg("tier2_path", "Path to tier 2 storage root"),
|
|
Arg("tier3_path", "Path to tier 3 storage root")])
|
|
|
|
def run(ctx, args):
|
|
log, s = ctx.log, ctx.sys
|
|
comp = ctx.paths.compositions
|
|
tiers = [os.path.realpath(args.tier1_path),
|
|
os.path.realpath(args.tier2_path),
|
|
os.path.realpath(args.tier3_path)]
|
|
|
|
def confirm(msg):
|
|
try:
|
|
return input(f"{msg} [y/N]: ").strip().lower() in ("y", "yes")
|
|
except EOFError: # non-interactive stdin = decline, like bash `read` at EOF
|
|
return False
|
|
|
|
def safe_remove(link, desc):
|
|
if os.path.islink(link):
|
|
s.sudo(["rm", link]); return True
|
|
if os.path.exists(link):
|
|
log.warn(f"Path exists but is not a symlink: {link}")
|
|
if confirm(f"Remove existing {desc} (NOT a symlink)?"):
|
|
s.sudo(["rm", "-rf", link]); return True
|
|
return False
|
|
return True
|
|
|
|
def mklink(target, link, desc):
|
|
s.sudo(["ln", "-snf", target, link])
|
|
log.success(f"Created {desc} symlink: {link} -> {target}")
|
|
|
|
log.info("Starting @tier setup...")
|
|
for t in tiers:
|
|
s.sudo(["mkdir", "-p", t])
|
|
# node-level @tierN -> tier roots
|
|
for i, n in enumerate((1, 2, 3)):
|
|
link = os.path.join(comp, f"@tier{n}")
|
|
if safe_remove(link, f"node-@tier{n}"):
|
|
mklink(tiers[i], link, f"node-@tier{n}")
|
|
# per-project (every composition subdir except dot/@)
|
|
for proj in sorted(os.listdir(comp)):
|
|
full = os.path.join(comp, proj)
|
|
if not os.path.isdir(full) or proj.startswith(".") or proj.startswith("@"):
|
|
continue
|
|
log.info(f"Processing project: {proj}")
|
|
for i, n in enumerate((1, 2, 3)):
|
|
base = tiers[i]
|
|
s.sudo(["mkdir", "-p", os.path.join(base, "shared")])
|
|
s.sudo(["mkdir", "-p", os.path.join(base, "shared", proj)])
|
|
s.sudo(["mkdir", "-p", os.path.join(base, proj)])
|
|
shared_link = os.path.join(base, proj, "shared")
|
|
if safe_remove(shared_link, "shared-internal"):
|
|
s.sudo(["ln", "-snf", "../shared", shared_link])
|
|
link = os.path.join(full, f"@tier{n}")
|
|
if safe_remove(link, f"@tier{n}"):
|
|
mklink(os.path.join(base, proj), link, f"@tier{n}")
|
|
env_link = os.path.join(full, ".env")
|
|
env_target = os.path.join(tiers[0], proj, ".env")
|
|
if safe_remove(env_link, ".env"):
|
|
if not os.path.isfile(env_target):
|
|
s.sudo(["touch", env_target])
|
|
mklink(env_target, env_link, ".env")
|
|
log.success("@tier setup completed.")
|