office: full --help, and --host copies the commands to the other machine and works from any folder on it
This commit is contained in:
127
bin/office
127
bin/office
@@ -169,6 +169,9 @@ exit 0
|
||||
|
||||
|
||||
|
||||
# Where the commands live on a machine that is driven over ssh.
|
||||
REMOTE_BIN = "~/.local/share/paperclip-harness/bin"
|
||||
|
||||
HOSTS = {
|
||||
"nixos-desktop": "192.168.20.13", ".13": "192.168.20.13", "13": "192.168.20.13",
|
||||
"sam-4screen-desktop": "192.168.20.27", "sam-4screen-desktop-1": "192.168.20.27",
|
||||
@@ -204,6 +207,16 @@ def is_this_machine(name):
|
||||
return addr in local_addresses()
|
||||
|
||||
|
||||
def install_wrapper(addr, remote_bin):
|
||||
"""Leave a short `office` on the other machine's PATH, pointing at the copy."""
|
||||
script = ("#!/bin/sh\n"
|
||||
"# Written by office on another machine. Runs the copy it keeps here.\n"
|
||||
'exec "$HOME/.local/share/paperclip-harness/bin/office" "$@"\n')
|
||||
subprocess.run(["ssh", "-o", "BatchMode=yes", addr,
|
||||
"mkdir -p \"$HOME/.local/bin\" && cat > \"$HOME/.local/bin/office\" && chmod +x \"$HOME/.local/bin/office\""],
|
||||
input=script, text=True, capture_output=True, timeout=60)
|
||||
|
||||
|
||||
def run_on_remote(host, folder, opts):
|
||||
"""Adopt a folder that lives on another machine, from where you are sitting.
|
||||
|
||||
@@ -218,14 +231,34 @@ def run_on_remote(host, folder, opts):
|
||||
if probe.returncode != 0:
|
||||
raise h.Refused(3, "cannot log in to %s (%s). Set up a key first: ssh-copy-id %s"
|
||||
% (host, addr, addr))
|
||||
# The other machine needs the commands. They are copied to one fixed place
|
||||
# there rather than assumed to be in the same folder: a machine that has
|
||||
# never seen this repository still gets a working `office`. Copying every
|
||||
# time is what keeps the two in step, and it is one small folder.
|
||||
here = os.path.dirname(os.path.realpath(__file__))
|
||||
inner = [os.path.join(here, "office"), folder, "--no-switch"]
|
||||
remote_bin = REMOTE_BIN
|
||||
# rsync will not make two levels of directory, so make the parent first.
|
||||
subprocess.run(["ssh", "-o", "BatchMode=yes", addr,
|
||||
"mkdir -p \"$HOME/.local/share/paperclip-harness\""],
|
||||
capture_output=True, text=True, timeout=60)
|
||||
copy = subprocess.run(
|
||||
["rsync", "-a", "--delete", "--exclude", "__pycache__", "--exclude", "*.pyc",
|
||||
here + "/", "%s:%s/" % (addr, remote_bin)],
|
||||
capture_output=True, text=True, timeout=300)
|
||||
if copy.returncode != 0:
|
||||
raise h.Refused(3, "could not copy the commands to %s: %s"
|
||||
% (host, (copy.stderr or copy.stdout).strip()[:300]))
|
||||
install_wrapper(addr, remote_bin)
|
||||
inner = [folder, "--no-switch"]
|
||||
for flag, value in (("--project", opts["project"]), ("--session", opts["session"]), ("--new", opts["new"])):
|
||||
if value:
|
||||
inner += [flag, value]
|
||||
if opts["dry"]:
|
||||
inner.append("--dry")
|
||||
cmd = " ".join(shlex.quote(a) for a in inner)
|
||||
# "$HOME" must stay unquoted so the other machine's shell expands it; every
|
||||
# argument after it is quoted, so a folder with a space still arrives whole.
|
||||
cmd = 'exec "$HOME/.local/share/paperclip-harness/bin/office" ' + \
|
||||
" ".join(shlex.quote(a) for a in inner)
|
||||
h.say("on %s: %s" % (host, cmd))
|
||||
out = subprocess.run(["ssh", "-o", "StrictHostKeyChecking=accept-new", addr, cmd],
|
||||
capture_output=True, text=True, timeout=600)
|
||||
@@ -237,15 +270,85 @@ def run_on_remote(host, folder, opts):
|
||||
return 0
|
||||
|
||||
|
||||
USAGE = """office — open a folder as a project
|
||||
USAGE = """office — open a folder as a project, and say what else can be run
|
||||
|
||||
office <folder> --project "<Name>" adopt a project Paperclip already has
|
||||
office <folder> --new "<Name>" create the Paperclip project too
|
||||
office <folder> --project "<Name>" --host nixos-desktop the folder is on that machine
|
||||
office <folder> --dry say what would happen, write nothing
|
||||
THE RULE
|
||||
The folder and the session live on the same machine. If you are typing inside
|
||||
the session, on the machine that owns the folder, it is just: office <folder>
|
||||
Use --host only when the folder is on a different machine from your shell.
|
||||
|
||||
The folder and the session live on the same machine. If you are typing inside the
|
||||
session, on the machine that owns the folder, it is just: office <folder>.
|
||||
WHAT IT DOES
|
||||
1. reads the folder
|
||||
2. if a machine is named, checks whether that is this machine, and runs locally if so
|
||||
3. if it really is another machine, checks the login and runs the same command there
|
||||
4. adopts the Paperclip project, or creates it with --new
|
||||
5. writes what is missing in <folder>/.harness/ and never overwrites
|
||||
6. records the project in ~/.config/paperclip-harness/projects.toml
|
||||
7. creates the session on that machine's daemon, then builds eight panes
|
||||
|
||||
COMMANDS
|
||||
|
||||
office <folder> --project "<Name>" adopt a project Paperclip already has
|
||||
office <folder> --new "<Name>" create the Paperclip project as well
|
||||
office . adopt the folder you are standing in
|
||||
office <folder> --session <name> name the session instead of the folder
|
||||
office <folder> --project "<Name>" --host <machine> the folder is on that machine
|
||||
office <folder> --new "<Name>" --dry say what would happen, write nothing
|
||||
|
||||
board create any missing pane in this project's session
|
||||
board --folder <folder> the same, for another project
|
||||
board --replace close this project's panes, then build all eight again
|
||||
board --reset close every pane in the session, then build
|
||||
project-reset <folder> forget the session and start this project again
|
||||
merge <task> rebase, check, review and merge one task (asks first)
|
||||
review <task> [--post] run ocr over one task's diff, and record the verdict
|
||||
triage <task> [--ask next|failure] ask Mouse-1 one question about a task
|
||||
|
||||
MACHINES (name, or the address ssh reaches)
|
||||
nixos-desktop .13 192.168.20.13 hosts Paperclip, the daemon, the main session
|
||||
sam-4screen-desktop .27 192.168.20.27 your working desktop
|
||||
sam-thinkpad .51 192.168.20.51 the laptop
|
||||
|
||||
EVERY MACHINE, FROM THE TERMINAL
|
||||
|
||||
On .13, a folder that is on .13:
|
||||
office ~/paseo/projects/test-alpha --project "test-alpha"
|
||||
|
||||
On .27, adopting a folder that lives on .13:
|
||||
office /home/sam/paseo/projects/email_agent --project "Email Agent" --host nixos-desktop
|
||||
|
||||
On .27, a folder that is on .27 (stays local, no --host):
|
||||
office ~/src/thing --new "thing"
|
||||
|
||||
On .51, the same folder on .51:
|
||||
office ~/src/thing --project "thing" --host sam-thinkpad
|
||||
|
||||
Then attach. Nothing may move your client from inside a pane, so the last step is yours:
|
||||
tuios attach <session> on this machine
|
||||
tuios attach --host nixos-desktop <session> to a session on another machine
|
||||
|
||||
ON ANOTHER MACHINE
|
||||
--host copies this folder of commands to the other machine, at
|
||||
~/.local/share/paperclip-harness/bin/
|
||||
and leaves a short ~/.local/bin/office there, so it can be run from that
|
||||
machine too. Nothing has to be installed by hand. On .27 and .51 ~/.local/bin
|
||||
is not on PATH yet, so there you call it by its full path:
|
||||
~/.local/share/paperclip-harness/bin/office <folder>
|
||||
|
||||
AFTER A REBOOT
|
||||
TUIOS restores a session with a fresh shell in every pane and keeps the pane
|
||||
names. Run board once for that project: it checks what each pane is actually
|
||||
running and replaces any pane that is only a prompt.
|
||||
|
||||
KEYS INSIDE THE PANES
|
||||
( ) change tab tab change panel enter open / choose
|
||||
r re-read Paperclip R rebuild all panes ? list the keys
|
||||
h j k l z n and digits belong to TUIOS and never reach the program.
|
||||
|
||||
MORE
|
||||
docs/STARTUP.md these commands, the rule, and the three rebuild levels
|
||||
docs/WORKSPACES.md what each of the eight panes is for
|
||||
docs/CLEAN-TESTS.md the two end-to-end tests and what they measured
|
||||
"""
|
||||
|
||||
|
||||
@@ -260,7 +363,11 @@ def main():
|
||||
# are standing in. Only a missing argument is an error.
|
||||
raise h.Refused(2, "give the folder: office <folder> --project \"<Name>\" (office --help)")
|
||||
folder = os.path.abspath(os.path.expanduser(opts["folder"]))
|
||||
if not os.path.isdir(folder):
|
||||
# The folder is only checked here when it is this machine's folder. A folder
|
||||
# on another machine is checked there: asking this machine about it says "no
|
||||
# folder", which is true and useless.
|
||||
wanted = opts["host"] or opts["remote"]
|
||||
if not (wanted and not is_this_machine(wanted)) and not os.path.isdir(folder):
|
||||
raise h.Refused(2, "no folder at %s" % folder)
|
||||
|
||||
host = opts["host"] or pj.this_machine()
|
||||
|
||||
Reference in New Issue
Block a user