|
| 1 | +#!/usr/bin/env python3 |
| 2 | +"""Generate an asciinema v2 cast of the current devbox experience. |
| 3 | +
|
| 4 | +Used to produce the animated terminal demo in the README. The output strings |
| 5 | +mirror what the devbox CLI actually prints today, so refresh this script when |
| 6 | +those messages change. |
| 7 | +
|
| 8 | +To regenerate docs/app/static/img/devbox_demo.svg: |
| 9 | +
|
| 10 | + python3 scripts/gen_cast.py /tmp/devbox.cast |
| 11 | + npx svg-term-cli --in /tmp/devbox.cast \\ |
| 12 | + --out docs/app/static/img/devbox_demo.svg \\ |
| 13 | + --window --width 84 --height 26 |
| 14 | +""" |
| 15 | +import json |
| 16 | +import sys |
| 17 | + |
| 18 | +# ANSI styles |
| 19 | +CYAN = "\x1b[36m" |
| 20 | +BLUE = "\x1b[94m" |
| 21 | +GREEN = "\x1b[32m" |
| 22 | +DIM = "\x1b[90m" |
| 23 | +YELLOW = "\x1b[33m" |
| 24 | +BGREEN = "\x1b[92m" |
| 25 | +RESET = "\x1b[0m" |
| 26 | + |
| 27 | +events = [] |
| 28 | +t = 0.4 # start a touch after the window opens |
| 29 | + |
| 30 | + |
| 31 | +def out(s): |
| 32 | + events.append([round(t, 3), "o", s]) |
| 33 | + |
| 34 | + |
| 35 | +def emit(s, dt=0.0): |
| 36 | + global t |
| 37 | + t += dt |
| 38 | + out(s) |
| 39 | + |
| 40 | + |
| 41 | +def prompt(in_shell=False): |
| 42 | + """Print the starship-style two-line prompt.""" |
| 43 | + if in_shell: |
| 44 | + emit(f"{CYAN}~{RESET} {DIM}in{RESET} \U0001F4E6 {BLUE}devbox{RESET}\r\n", 0.5) |
| 45 | + else: |
| 46 | + emit(f"{CYAN}~{RESET}\r\n", 0.5) |
| 47 | + emit(f"{GREEN}❯{RESET} ", 0.15) |
| 48 | + |
| 49 | + |
| 50 | +def type_cmd(cmd): |
| 51 | + """Type a command character by character, first word highlighted.""" |
| 52 | + global t |
| 53 | + first, _, rest = cmd.partition(" ") |
| 54 | + emit(f"{GREEN}{first[0]}{RESET}", 0.12) |
| 55 | + for ch in first[1:]: |
| 56 | + emit(f"{GREEN}{ch}{RESET}", 0.05) |
| 57 | + if rest: |
| 58 | + emit(" ", 0.05) |
| 59 | + for ch in rest: |
| 60 | + emit(ch, 0.045) |
| 61 | + emit("\r\n", 0.25) # press enter |
| 62 | + |
| 63 | + |
| 64 | +def output(lines, dt_first=0.25, dt=0.12): |
| 65 | + first = True |
| 66 | + for line in lines: |
| 67 | + emit(line + "\r\n", dt_first if first else dt) |
| 68 | + first = False |
| 69 | + |
| 70 | + |
| 71 | +# 1. go is not available on the host |
| 72 | +prompt() |
| 73 | +type_cmd("go version") |
| 74 | +output([f"{DIM}zsh: command not found: go{RESET}"]) |
| 75 | + |
| 76 | +# 2. init a project |
| 77 | +prompt() |
| 78 | +type_cmd("devbox init") |
| 79 | +output([ |
| 80 | + "Created devbox.json in .", |
| 81 | + "Run `devbox add <package>` to add packages, or `devbox shell` to start a dev shell.", |
| 82 | +]) |
| 83 | + |
| 84 | +# 3. add packages with the modern @version syntax |
| 85 | +prompt() |
| 86 | +type_cmd("devbox add python@3.10 go@1.18") |
| 87 | +output([ |
| 88 | + f"{YELLOW}Info:{RESET} Adding package 'python@3.10' to devbox.json", |
| 89 | + f"{YELLOW}Info:{RESET} Adding package 'go@1.18' to devbox.json", |
| 90 | + f"{YELLOW}Info:{RESET} Ensuring packages are installed.", |
| 91 | + f"{YELLOW}Info:{RESET} Installing the following packages to the nix store: python@3.10, go@1.18", |
| 92 | +], dt_first=0.4, dt=0.5) |
| 93 | +emit(f"{BGREEN}✓{RESET} Computed the Devbox environment.\r\n", 1.2) |
| 94 | + |
| 95 | +# 4. run a single command in the environment |
| 96 | +prompt() |
| 97 | +type_cmd("devbox run python --version") |
| 98 | +output(["Python 3.10.14"], dt_first=0.8) |
| 99 | + |
| 100 | +# 5. drop into an interactive shell |
| 101 | +prompt() |
| 102 | +type_cmd("devbox shell") |
| 103 | +output([f"{DIM}Starting a devbox shell...{RESET}"]) |
| 104 | +emit(f"{BGREEN}✓{RESET} Computed the Devbox environment.\r\n", 1.0) |
| 105 | + |
| 106 | +# 6. tools are now on PATH inside the shell |
| 107 | +prompt(in_shell=True) |
| 108 | +type_cmd("python --version") |
| 109 | +output(["Python 3.10.14"], dt_first=0.5) |
| 110 | + |
| 111 | +prompt(in_shell=True) |
| 112 | +type_cmd("go version") |
| 113 | +output(["go version go1.18 linux/amd64"], dt_first=0.5) |
| 114 | + |
| 115 | +# settle on a final prompt |
| 116 | +prompt(in_shell=True) |
| 117 | +emit("", 1.5) |
| 118 | + |
| 119 | +header = { |
| 120 | + "version": 2, |
| 121 | + "width": 84, |
| 122 | + "height": 26, |
| 123 | + "timestamp": 0, |
| 124 | + "env": {"SHELL": "/bin/zsh", "TERM": "xterm-256color"}, |
| 125 | +} |
| 126 | + |
| 127 | +with open(sys.argv[1], "w") as f: |
| 128 | + f.write(json.dumps(header) + "\n") |
| 129 | + for ev in events: |
| 130 | + f.write(json.dumps(ev) + "\n") |
0 commit comments