110 lines
3.7 KiB
Python
Executable File
110 lines
3.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Start a project again: close its pages, remove its worktrees, keep its work.
|
|
|
|
bin/project-reset <folder> --dry-run
|
|
bin/project-reset <folder> --yes
|
|
bin/project-reset <folder> --yes --delete-folder
|
|
|
|
What it removes, and nothing else:
|
|
|
|
- the project's screen panes in its TUIOS session (the shell pane stays, so
|
|
the session survives)
|
|
- the git worktrees Paperclip made for the project's tasks, and the branches
|
|
those tasks were on
|
|
|
|
What it leaves alone: the folder, its `.harness`, its git history, and every
|
|
Paperclip record — tasks, comments, runs, cost. Paperclip owns those, so a reset
|
|
here cannot erase the history of what happened; it only clears the machinery.
|
|
|
|
`--delete-folder` is the only destructive option and it asks for the folder name
|
|
to be typed. Without it, nothing outside git and TUIOS is touched.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, os.path.join(HERE, "lib"))
|
|
import harness as h # noqa: E402
|
|
import tuios # noqa: E402
|
|
import project as pj # noqa: E402
|
|
|
|
PAGES = ["tree", "reply", "log", "new"]
|
|
|
|
|
|
def main():
|
|
argv = sys.argv[1:]
|
|
args = [a for a in argv if not a.startswith("--")]
|
|
if not args:
|
|
h.say("usage: bin/project-reset <folder> [--dry-run] [--yes] [--delete-folder]")
|
|
return 2
|
|
folder = os.path.abspath(os.path.expanduser(args[0]))
|
|
dry = "--dry-run" in argv
|
|
yes = "--yes" in argv
|
|
delete_folder = "--delete-folder" in argv
|
|
|
|
cfg = pj.load(folder)
|
|
pj.check_machine(cfg)
|
|
session = cfg["session"]
|
|
project_id = cfg["paperclip"]["project"]
|
|
|
|
tasks = pj.active_tasks(project_id)
|
|
worktrees = []
|
|
for t in tasks:
|
|
full = h.api("GET", "/api/issues/%s" % t["id"])
|
|
ws = full.get("currentExecutionWorkspace") or {}
|
|
if ws.get("cwd"):
|
|
worktrees.append((t["identifier"], ws["cwd"], ws.get("branchName") or ""))
|
|
|
|
h.say("project: %s" % project_id)
|
|
h.say("folder: %s" % folder)
|
|
h.say("session: %s" % session)
|
|
h.say("")
|
|
h.say("would remove:")
|
|
h.say(" panes: %s in %s" % (", ".join(PAGES), session))
|
|
for ref, cwd, branch in worktrees:
|
|
h.say(" worktree: %s (%s, branch %s)" % (cwd, ref, branch or "none"))
|
|
if delete_folder:
|
|
h.say(" the folder: %s (including .harness and git history)" % folder)
|
|
h.say("kept: the Paperclip project, its tasks, comments, runs and cost")
|
|
|
|
if dry:
|
|
h.say("")
|
|
h.say("dry run: nothing was removed")
|
|
return 0
|
|
|
|
if not yes:
|
|
h.say("")
|
|
h.say("Type the folder name to continue: %s" % os.path.basename(folder))
|
|
typed = input("> ").strip()
|
|
if typed != os.path.basename(folder):
|
|
h.say("nothing was removed")
|
|
return 1
|
|
|
|
for name in PAGES:
|
|
if tuios.close_pane(name, session):
|
|
h.say("closed pane %s" % name)
|
|
|
|
repo = folder
|
|
for ref, cwd, branch in worktrees:
|
|
code, out = h.run(["git", "-C", repo, "worktree", "remove", "--force", cwd])
|
|
h.say("worktree %s: %s" % (ref, "removed" if code == 0 else out.strip()[:120]))
|
|
if branch:
|
|
code, out = h.run(["git", "-C", repo, "branch", "-D", branch])
|
|
h.say("branch %s: %s" % (branch, "deleted" if code == 0 else out.strip()[:120]))
|
|
|
|
if delete_folder:
|
|
h.say("")
|
|
h.say("Type the folder name again to delete %s: " % folder)
|
|
typed = input("> ").strip()
|
|
if typed != os.path.basename(folder):
|
|
h.say("folder kept")
|
|
return 0
|
|
code, out = h.run(["rm", "-rf", folder])
|
|
h.say("folder %s" % ("deleted" if code == 0 else "not deleted: " + out.strip()))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
h.main_guard(main)
|