Re-shoot the guide's screenshots and add one for migrate

shots.py gains a pseudo-terminal runner so it can answer migrate's
overwrite question, and the guide shows the resulting screenshot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andy Dixon
2026-09-28 16:36:12 +01:00
co-authored by Claude Opus 5.5
parent eb138b5524
commit e40a803367
13 changed files with 39 additions and 0 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 KiB

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 89 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 88 KiB

+37
View File
@@ -16,6 +16,7 @@ import glob
import grp
import html
import os
import pty
import shutil
import subprocess
import sys
@@ -94,6 +95,28 @@ class Sandbox:
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
return self.tidy(p.stdout)
def run_tty(self, command, passphrase, answer):
"""Run on a pseudo-terminal, typing answer at vault's [y/N] question."""
env = self.env({"VAULT_PASSPHRASE": passphrase})
pid, fd = pty.fork()
if pid == 0:
os.chdir(self.home)
os.execve("/bin/bash", ["bash", "-c", command], env)
out = b""
while b"[y/N]" not in out:
out += os.read(fd, 1024)
os.write(fd, answer.encode() + b"\n")
try:
while True:
chunk = os.read(fd, 1024)
if not chunk:
break
out += chunk
except OSError:
pass
os.waitpid(pid, 0)
return self.tidy(out.decode().replace("\r\n", "\n"))
def tidy(self, text):
owner = " %s %s " % (getpass.getuser(), grp.getgrgid(os.getgid()).gr_name)
return text.replace(self.home, SHOWN_HOME).replace(owner, " sam sam ").rstrip("\n")
@@ -278,6 +301,20 @@ def main():
t.cmd("find ~/.vault/store/records -type f | wc -l")
shoot("decoy-hidden", t)
# migrate: one file is already in the vault, so it asks first
box.write("Scans/receipts/march.pdf", os.urandom(48_113))
box.write("Scans/receipts/april.pdf", os.urandom(51_870))
box.run("vault add Scans/receipts/march.pdf receipts", P)
t = Term(box)
t.lines.append(prompt() + '<span class="c">vault migrate Scans/receipts</span>')
for line in box.run_tty("vault migrate Scans/receipts", P, "y").split("\n"):
esc = html.escape(line)
if "[y/N]" in line:
esc = '<span class="hl">%s</span>' % esc
t.lines.append(esc)
t.cmd("ls Scans")
shoot("migrate", t)
# errors
t = Term(box)
t.cmd("vault list", "hunter2", highlight=("incorrect",))
+2
View File
@@ -572,6 +572,8 @@ before touching anything. Answer anything but \texttt{y} and nothing changes.
With no terminal to ask on, the answer is no. For scripts, \texttt{--yes}
answers yes up front.
\shot{migrate}{Moving a folder in. One file was already there, so vault asked first.}
\subsection{What gets skipped}
When adding a folder, anything that isn't a plain file, such as symbolic
links, sockets or devices, is skipped with a note. So are the vault and key