Odoc docs
0

Configure Feed

Select the types of activity you want to include in your feed.

Rename project to "odd" (odoc docs)

Rename the package, binary, and library from odoc-switchdocs/switchdocs to
odd: opam package `odd`, command `odd <subcommand>`, library module `Odd`.
Knock-on renames: the stale marker is now `.odd-stale`, state lives in
var/cache/odd, the SWITCHDOCS_DRIVER env var becomes ODD_DRIVER, the zsh
completion is _odd, and the opam hooks and docs refer to `odd`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

+183 -183
+22 -22
DESIGN.md
··· 1 - # odoc-switchdocs — design 1 + # odd — design 2 2 3 3 Keep per-switch HTML documentation continuously up to date by hooking into 4 4 opam's session lifecycle and rebuilding only the packages each session ··· 39 39 - `--odoc-dir`, `--odocl-dir` and `--html-dir` all default to 40 40 `<switch-prefix>/odoc`. Intermediate `.odoc`/`.odocl` files and HTML 41 41 share that tree, with each package's output directly under 42 - `odoc/<package>/` (flat layout, same as plain `odoc_driver`). This is a 43 - switchdocs-owned tree, kept separate from opam's own `<prefix>/doc`, where 42 + `odoc/<package>/` (flat layout, same as plain `odoc_driver`). This is an 43 + odd-owned tree, kept separate from opam's own `<prefix>/doc`, where 44 44 packages install their own documentation. 45 45 - Previously built dependencies are discovered by scanning `--odoc-dir` 46 46 for the `.odoc_pkg_marker` / `.odoc_lib_marker` files written on earlier ··· 58 58 ### 1. opam hooks (configured in `~/.opam/config`, shipped via opamrc) 59 59 60 60 Three wrapper fields drive everything. The two per-package hooks are plain 61 - coreutils — crucially they invoke **no switchdocs binary** — so they keep 62 - working even in a switch where switchdocs isn't installed (or is mid-upgrade, 61 + coreutils — crucially they invoke **no odd binary** — so they keep 62 + working even in a switch where odd isn't installed (or is mid-upgrade, 63 63 or where a *global* hook fires for a switch that never had it). All real work 64 64 happens once per session, in the one hook that does need the binary. 65 65 66 66 ``` 67 67 post-install-commands: [ 68 - [ "sh" "-c" "mkdir -p \"$1/odoc/$2\" && touch \"$1/odoc/$2/.switchdocs-stale\"" 68 + [ "sh" "-c" "mkdir -p \"$1/odoc/$2\" && touch \"$1/odoc/$2/.odd-stale\"" 69 69 "--" "%{prefix}%" "%{name}%" ] { error-code = 0 } 70 70 ] 71 71 post-remove-commands: [ 72 72 [ "rm" "-rf" "%{prefix}%/odoc/%{name}%" ] { error-code = 0 } 73 73 ] 74 74 post-session-commands: [ 75 - [ "%{hooks}%/switchdocs" "sync" "--prefix" "%{prefix}%" ] { success } 75 + [ "%{hooks}%/odd" "sync" "--prefix" "%{prefix}%" ] { success } 76 76 ] 77 77 ``` 78 78 79 79 - **post-install** marks the package stale by `touch`-ing 80 - `odoc/<pkg>/.switchdocs-stale` (after `mkdir -p`-ing the dir). It fires for 80 + `odoc/<pkg>/.odd-stale` (after `mkdir -p`-ing the dir). It fires for 81 81 every install action including same-version rebuilds — which matters, 82 82 because a dependency-triggered rebuild changes the `.cmti`s but is invisible 83 83 to session-level `%{new}%`/`%{removed}%`. A marker is a single empty file per ··· 88 88 - **post-remove** deletes the package's doc subtree outright. Removal needs no 89 89 marker and no deferral: the deletion *is* the action, done immediately and 90 90 binary-free. (This also clears any stale marker that lived in that subtree.) 91 - - **post-session** runs `switchdocs sync`, the one hook that needs the binary. 91 + - **post-session** runs `odd sync`, the one hook that needs the binary. 92 92 It always exits 0: doc failures are logged, never propagated, because opam 93 93 aborts the invocation with a configuration error if a session hook fails 94 - (`opamSolution.ml`, post-session handling). If switchdocs is absent, this 94 + (`opamSolution.ml`, post-session handling). If odd is absent, this 95 95 hook simply doesn't run; the markers persist and are drained by the next 96 96 session that does have it — deferred, never lost. 97 97 98 98 ### 2. State and layout (all under `$OPAM_SWITCH_PREFIX`) 99 99 100 100 ``` 101 - var/cache/switchdocs/ 101 + var/cache/odd/ 102 102 log # sync output, since hooks must stay quiet 103 103 lock # guards a manual sync against a hook-invoked one 104 104 odoc/ 105 105 <package>/ 106 - .switchdocs-stale # marker: post-install touched it, sync rebuilds 106 + .odd-stale # marker: post-install touched it, sync rebuilds 107 107 ... # per-package odoc, odocl and HTML (driver defaults) 108 108 index.html # switch-wide landing page (ours) 109 109 odoc-search/... # driver support files, search assets ··· 111 111 112 112 The driver's defaults are taken as-is: one `odoc/` tree per switch holding 113 113 both intermediates and HTML, separate from opam's own `<prefix>/doc`. The 114 - work list lives in that tree too — a `.switchdocs-stale` marker file inside 114 + work list lives in that tree too — a `.odd-stale` marker file inside 115 115 each stale package's dir — so the post-install hook can write it without 116 - switchdocs. Our only other state is the log and lock. 116 + odd. Our only other state is the log and lock. 117 117 118 118 ### 3. The `sync` step 119 119 ··· 126 126 with the lock the surrounding session holds. 127 127 128 128 1. **Collect the stale set**: the package names whose `odoc/<pkg>/` holds a 129 - `.switchdocs-stale` marker, intersected with the installed set. (A marker 129 + `.odd-stale` marker, intersected with the installed set. (A marker 130 130 for a no-longer-installed package can only survive an install+remove in the 131 131 same session — the remove hook's `rm -rf` normally clears it — so tidy it 132 132 away.) Removals need no handling here: the post-remove hook already deleted ··· 202 202 203 203 ## Tool shape 204 204 205 - One OCaml executable, `switchdocs`, with subcommands: 205 + One OCaml executable, `odd`, with subcommands: 206 206 207 - - `switchdocs sync` — the session worker described above (the post-session hook). 208 - - `switchdocs rebuild [--all | <pkg>...]` — manual escape hatch: mark 207 + - `odd sync` — the session worker described above (the post-session hook). 208 + - `odd rebuild [--all | <pkg>...]` — manual escape hatch: mark 209 209 packages (or everything installed) stale and run sync. `--all` works on 210 210 pre-existing switches because the installed-package metadata is always 211 211 present, whether or not hooks were configured at install time. 212 - - `switchdocs setup` — write the three wrapper fields into `~/.opam/config` 212 + - `odd setup` — write the three wrapper fields into `~/.opam/config` 213 213 with `opam option --global` (idempotent). 214 214 215 215 There is deliberately **no** `record` subcommand: recording a change (a 216 216 `touch`) and cleaning up a removal (an `rm -rf`) are plain coreutils in the 217 - hooks, so they never depend on switchdocs being installed. 217 + hooks, so they never depend on odd being installed. 218 218 219 219 Dependencies: `opam-format` (opam file parsing), `bos`, `fpath`, 220 220 `cmdliner`; `odoc_driver_opam` is invoked as an external binary so its ··· 223 223 via the switch `PATH`. 224 224 225 225 Distribution: an opamrc adding the three `*-commands` fields for 226 - `opam init --config`; `switchdocs setup` for retrofitting existing roots. 226 + `opam init --config`; `odd setup` for retrofitting existing roots. 227 227 228 228 ## Failure handling summary 229 229 230 230 | Failure | Behaviour | 231 231 |---|---| 232 232 | package build fails | hooks filtered on `error-code = 0` / `{ success }`; the package isn't marked stale, no sync | 233 - | switchdocs not installed in the switch | post-install/post-remove still work (coreutils); markers accumulate, drained by the next session that has switchdocs — deferred, never lost | 233 + | odd not installed in the switch | post-install/post-remove still work (coreutils); markers accumulate, drained by the next session that has odd — deferred, never lost | 234 234 | doc build fails for one package | logged; its marker is re-created; later packages still attempted (their deps' docs may be stale — accepted, fixed on retry) | 235 235 | sync interrupted | markers intact (a marker is only cleared by a successful build); next session resumes | 236 236 | `odoc_driver_opam` missing from switch | sync logs and exits 0; markers survive until the driver is installed |
+7 -7
DESIGN_COMPLETE.md
··· 1 - # odoc-switchdocs — `complete`: reference completion 1 + # odd — `complete`: reference completion 2 2 3 - > **Status: implemented** (`lib/complete.ml`, `switchdocs complete`). The shared 3 + > **Status: implemented** (`lib/complete.ml`, `odd complete`). The shared 4 4 > resolve/load substrate was extracted into `Refs` (`lib/refs.ml`) rather than 5 5 > left in `show.ml`; `Show` and `Complete` are thin layers over it. Deviations 6 6 > from the design below: names containing `__` (wrapped internal modules) are ··· 14 14 next. 15 15 16 16 ``` 17 - $ switchdocs complete /o 17 + $ odd complete /o 18 18 /ocaml-compiler 19 19 /odoc 20 20 /odoc.model 21 21 ... 22 - $ switchdocs complete List.m 22 + $ odd complete List.m 23 23 List.map 24 24 List.mapi 25 25 List.map2 26 26 List.mem 27 27 ... 28 - $ switchdocs complete module-List.type- 28 + $ odd complete module-List.type- 29 29 module-List.type-t 30 30 ``` 31 31 ··· 170 170 ## CLI shape 171 171 172 172 ``` 173 - switchdocs complete [--prefix DIR] PARTIAL 173 + odd complete [--prefix DIR] PARTIAL 174 174 ``` 175 175 176 176 - Prints candidates one per line, sorted, on stdout. Each is a complete ··· 180 180 - A `--kind`-style filter is unnecessary: the kind tag is part of `PARTIAL` 181 181 (`module-List.type-`), which is also what the user is mid-typing. 182 182 183 - Shell glue (bash/zsh `complete -C`, a zsh `_switchdocs` function) is a thin 183 + Shell glue (bash/zsh `complete -C`, a zsh `_odd` function) is a thin 184 184 wrapper over this and is left to a follow-up; the command is the engine. 185 185 186 186 ## Performance
+7 -7
DESIGN_SHOW.md
··· 1 - # odoc-switchdocs — `show`: print the docs for a reference 1 + # odd — `show`: print the docs for a reference 2 2 3 3 A CLI subcommand that takes an odoc reference and prints the docstring of the 4 4 item it names, as Markdown: 5 5 6 6 ``` 7 - $ switchdocs show Odoc_model.Paths.Identifier 7 + $ odd show Odoc_model.Paths.Identifier 8 8 ``` 9 9 10 10 The job is essentially the reference-resolution half of `odoc link`, run ··· 70 70 scanning the directories it is given for `*.odoc` files. In a switch the driver 71 71 writes these under `$OPAM_SWITCH_PREFIX/odoc/<pkg>/<lib>/<Module>.odoc` (verified 72 72 on the dev switch: e.g. `odoc/astring/astring/astring.odoc`). (This is the 73 - switchdocs-owned tree, separate from opam's own `<prefix>/doc`.) So: 73 + odd-owned tree, separate from opam's own `<prefix>/doc`.) So: 74 74 75 75 - discover the switch prefix exactly as the existing commands do 76 - (`Switchdocs.Switch.detect`, `--prefix`); 76 + (`Odd.Switch.detect`, `--prefix`); 77 77 - recursively collect every directory under `<prefix>/odoc` that contains a 78 78 `.odoc` file, and pass them all as `directories` (`Show.scan`). 79 79 ··· 209 209 backed by `lib/show.ml` (mirroring how `lib/search.ml` backs `search`): 210 210 211 211 ``` 212 - switchdocs show [--prefix DIR] REFERENCE 212 + odd show [--prefix DIR] REFERENCE 213 213 ``` 214 214 215 215 - `REFERENCE` is an odoc reference string (`Odoc_model.Paths.Identifier`, ··· 232 232 `odoc.odoc` (for `Resolver`/`Semantics`), `odoc.document`, `odoc.markdown`. 233 233 These must be the *same* odoc that produced the switch's `.odoc`/`.odocl` (the 234 234 formats are version-coupled). In this repo's dev switch odoc is pinned to the 235 - driver's source, so they match; in general `switchdocs` should be built against 235 + driver's source, so they match; in general `odd` should be built against 236 236 the switch's odoc. 237 237 238 238 ## Open questions / future work ··· 251 251 the single item) — a reasonable follow-up. 252 252 - **Cross-reference link targets.** With `Base ""` the in-comment links are not 253 253 meaningfully clickable from a terminal; a future mode could rewrite them to 254 - `switchdocs show` invocations or to the switch's HTML. 254 + `odd show` invocations or to the switch's HTML.
+16 -16
README.md
··· 1 - # odoc-switchdocs 1 + # odd 2 2 3 3 Keep an opam switch's HTML documentation continuously up to date. 4 4 5 - `switchdocs` wires opam's `post-install-commands`, `post-remove-commands` 5 + `odd` wires opam's `post-install-commands`, `post-remove-commands` 6 6 and `post-session-commands` hooks so that after every successful 7 7 `opam install` / `opam upgrade` / `opam remove`, the docs for exactly the 8 8 packages that changed are regenerated, in dependency order, by 9 9 `odoc_driver_opam`. The per-package hooks are plain coreutils (a `touch` to 10 10 mark a package stale, an `rm -rf` to drop a removed one's docs), so they keep 11 - working even when switchdocs itself isn't installed in the switch; only the 11 + working even when odd itself isn't installed in the switch; only the 12 12 once-per-session worker needs the binary. 13 13 Docs are written to `$OPAM_SWITCH_PREFIX/odoc/<package>/`, with a landing 14 - page at `$OPAM_SWITCH_PREFIX/odoc/index.html`. (This is switchdocs' own tree, 14 + page at `$OPAM_SWITCH_PREFIX/odoc/index.html`. (This is odd's own tree, 15 15 kept separate from opam's `$OPAM_SWITCH_PREFIX/doc`, where packages install 16 16 their own documentation.) 17 17 ··· 20 20 ## Setup 21 21 22 22 ``` 23 - $ switchdocs setup # show the opam configuration to be added 24 - $ switchdocs setup --apply # add it to ~/.opam/config via `opam option` 23 + $ odd setup # show the opam configuration to be added 24 + $ odd setup --apply # add it to ~/.opam/config via `opam option` 25 25 ``` 26 26 27 27 `odoc_driver_opam` must be installed in each switch you want documented ··· 29 29 30 30 ## Commands 31 31 32 - - `switchdocs sync` — session worker (the post-session hook); rebuilds every 32 + - `odd sync` — session worker (the post-session hook); rebuilds every 33 33 package marked stale, in dependency order, and regenerates the landing page. 34 34 Always exits 0; details go to 35 - `$OPAM_SWITCH_PREFIX/var/cache/switchdocs/log`. 36 - - `switchdocs rebuild [--all | PKG...]` — mark packages stale and sync. 35 + `$OPAM_SWITCH_PREFIX/var/cache/odd/log`. 36 + - `odd rebuild [--all | PKG...]` — mark packages stale and sync. 37 37 Exits non-zero on failure (user-facing, unlike the hook commands). 38 - - `switchdocs order [PKG...]` — print the dependency order that sync would 38 + - `odd order [PKG...]` — print the dependency order that sync would 39 39 use (debugging aid). 40 - - `switchdocs search [--package PKG]... [-n N] QUERY` — search the generated 40 + - `odd search [--package PKG]... [-n N] QUERY` — search the generated 41 41 documentation. Queries every package's `sherlodoc_db.marshal` together (a 42 42 single query covers the whole switch), printing each match with its owning 43 43 library and package. `--package` restricts to named packages. 44 - - `switchdocs show REFERENCE` — print an item's documentation as Markdown, 44 + - `odd show REFERENCE` — print an item's documentation as Markdown, 45 45 under a header naming the item and the library/package it comes from, 46 46 resolving an odoc reference against the whole switch. `Stdlib` is open, so 47 47 bare names work (`List`, `print_endline`); references may also be qualified 48 48 (`Astring.String`) or package-qualified (`/stdlib/Stdlib.List.map`). When a 49 49 reference is ambiguous (e.g. a bare `index`, a page in every package), it 50 50 lists the package-qualified alternatives instead of picking one. 51 - - `switchdocs complete PARTIAL` — list the references `PARTIAL` could be 51 + - `odd complete PARTIAL` — list the references `PARTIAL` could be 52 52 completed to, one per line: members of what it names so far (`List.m` → 53 53 `List.map`, …; kind tags filter, e.g. `module-List.type-` → `module-List.type-t`), 54 54 package/library names for a leading `/` (`/o` → `/odoc`, `/odoc.model`, …), or ··· 56 56 57 57 ## Shell completion (zsh) 58 58 59 - A zsh completion is shipped in `completions/zsh/_switchdocs`. It completes the 59 + A zsh completion is shipped in `completions/zsh/_odd`. It completes the 60 60 subcommands and, for `show` and `complete`, the reference argument — by calling 61 - `switchdocs complete`, so completion always matches the command's own resolver 61 + `odd complete`, so completion always matches the command's own resolver 62 62 (`Stdlib` open, package-qualified `/pkg/...` paths, kind tags like `type-`, 63 63 section labels, …). Type `.` or `/` and press TAB again to drill in. 64 64 ··· 66 66 zsh's `$fpath` by default, so add it (before `compinit`) in `~/.zshrc`: 67 67 68 68 ```zsh 69 - fpath=("$(opam var odoc-switchdocs:share)/zsh" $fpath) 69 + fpath=("$(opam var odd:share)/zsh" $fpath) 70 70 autoload -U compinit && compinit 71 71 ``` 72 72
+3 -3
bin/dune
··· 1 1 (executable 2 2 (name main) 3 - (public_name switchdocs) 4 - (package odoc-switchdocs) 5 - (libraries switchdocs cmdliner fpath bos)) 3 + (public_name odd) 4 + (package odd) 5 + (libraries odd cmdliner fpath bos))
+32 -32
bin/main.ml
··· 12 12 Arg.(value & opt (some string) None & info [ "prefix" ] ~docv:"DIR" ~doc) 13 13 in 14 14 let resolve = function 15 - | Some p -> Ok (Switchdocs.Switch.v (Fpath.v p)) 16 - | None -> Switchdocs.Switch.detect () 15 + | Some p -> Ok (Odd.Switch.v (Fpath.v p)) 16 + | None -> Odd.Switch.detect () 17 17 in 18 18 Term.(const resolve $ prefix) 19 19 ··· 29 29 value 30 30 & opt string "odoc_driver_opam" 31 31 & info [ "driver" ] ~docv:"BIN" ~doc 32 - ~env:(Cmd.Env.info "SWITCHDOCS_DRIVER")) 32 + ~env:(Cmd.Env.info "ODD_DRIVER")) 33 33 in 34 34 let resolve d = 35 35 if String.contains d '/' then ··· 47 47 Term.(const resolve $ arg) 48 48 49 49 let print_outcome sw outcome = 50 - Printf.printf "switchdocs: %s\n" (Switchdocs.Sync.summary outcome); 51 - if outcome.Switchdocs.Sync.failed <> [] then 52 - Printf.printf "switchdocs: see %s\n" 53 - (Fpath.to_string (Switchdocs.Switch.log_file sw)) 50 + Printf.printf "odd: %s\n" (Odd.Sync.summary outcome); 51 + if outcome.Odd.Sync.failed <> [] then 52 + Printf.printf "odd: see %s\n" 53 + (Fpath.to_string (Odd.Switch.log_file sw)) 54 54 55 55 (* sync — hook-facing: always exits 0. *) 56 56 let sync_cmd = 57 57 let run switch driver = 58 58 (match switch with 59 - | Error (`Msg m) -> Printf.eprintf "switchdocs sync: %s\n" m 59 + | Error (`Msg m) -> Printf.eprintf "odd sync: %s\n" m 60 60 | Ok sw -> ( 61 - match Switchdocs.Sync.sync ~driver sw with 61 + match Odd.Sync.sync ~driver sw with 62 62 | Ok { built = []; failed = [] } -> () 63 63 | Ok outcome -> print_outcome sw outcome 64 64 | Error (`Msg m) -> 65 - Switchdocs.Sync.log sw m; 66 - Printf.eprintf "switchdocs sync: %s\n" m)); 65 + Odd.Sync.log sw m; 66 + Printf.eprintf "odd sync: %s\n" m)); 67 67 0 68 68 in 69 69 let doc = "Bring the switch documentation up to date (opam hook worker)" in ··· 97 97 match switch with 98 98 | Error (`Msg m) -> `Error (false, m) 99 99 | Ok sw -> ( 100 - let installed = Switchdocs.Switch.installed sw in 100 + let installed = Odd.Switch.installed sw in 101 101 let targets = 102 102 if all then Ok installed 103 103 else if pkgs = [] then ··· 118 118 let mark_all = 119 119 List.fold_left 120 120 (fun acc (name, _version) -> 121 - Result.bind acc @@ fun () -> Switchdocs.Pending.mark sw name) 121 + Result.bind acc @@ fun () -> Odd.Pending.mark sw name) 122 122 (Ok ()) targets 123 123 in 124 124 match 125 - Result.bind mark_all @@ fun () -> Switchdocs.Sync.sync ~driver sw 125 + Result.bind mark_all @@ fun () -> Odd.Sync.sync ~driver sw 126 126 with 127 127 | Error (`Msg m) -> `Error (false, m) 128 128 | Ok outcome -> 129 129 print_outcome sw outcome; 130 - if outcome.Switchdocs.Sync.failed <> [] then 130 + if outcome.Odd.Sync.failed <> [] then 131 131 `Ok exit_doc_failure 132 132 else `Ok 0)) 133 133 in ··· 138 138 `P 139 139 "The manual escape hatch: marks the given packages (or, with \ 140 140 $(b,--all), every installed package) as stale and runs the same \ 141 - worker as $(b,switchdocs sync). Unlike the hook-facing commands this \ 141 + worker as $(b,odd sync). Unlike the hook-facing commands this \ 142 142 exits non-zero when a documentation build fails."; 143 143 ] 144 144 in ··· 161 161 | Error (`Msg m) -> `Error (false, m) 162 162 | Ok sw -> 163 163 let pkgs = 164 - if pkgs = [] then List.map fst (Switchdocs.Switch.installed sw) 164 + if pkgs = [] then List.map fst (Odd.Switch.installed sw) 165 165 else pkgs 166 166 in 167 167 let warn m = Printf.eprintf "warning: %s\n" m in 168 - List.iter print_endline (Switchdocs.Deps.order ~warn sw pkgs); 168 + List.iter print_endline (Odd.Deps.order ~warn sw pkgs); 169 169 `Ok 0 170 170 in 171 171 let doc = "Print the dependency order sync would use" in ··· 175 175 `P 176 176 "Prints the given packages in dependency order, one per line: every \ 177 177 package appears after its (transitive) dependencies among the listed \ 178 - packages. This is the order $(b,switchdocs sync) processes stale \ 178 + packages. This is the order $(b,odd sync) processes stale \ 179 179 packages in."; 180 180 ] 181 181 in ··· 211 211 | Error (`Msg m) -> `Error (false, m) 212 212 | Ok sw -> 213 213 let warn m = Printf.eprintf "warning: %s\n" m in 214 - (match Switchdocs.Search.search ~warn ~limit ~packages sw query with 214 + (match Odd.Search.search ~warn ~limit ~packages sw query with 215 215 | [] -> 216 216 Printf.printf "No results.\n"; 217 217 `Ok 0 218 218 | results -> 219 219 List.iter 220 - (fun r -> Format.printf "%a@." Switchdocs.Search.pp r) 220 + (fun r -> Format.printf "%a@." Odd.Search.pp r) 221 221 results; 222 222 `Ok 0) 223 223 in ··· 256 256 match switch with 257 257 | Error (`Msg m) -> `Error (false, m) 258 258 | Ok sw -> ( 259 - match Switchdocs.Show.show sw reference with 259 + match Odd.Show.show sw reference with 260 260 | Ok markdown -> 261 261 print_string markdown; 262 262 `Ok 0 ··· 264 264 (* A failure to resolve or find docs is a runtime outcome, not a 265 265 command-line misuse, so report it on stderr and exit non-zero 266 266 rather than with cmdliner's CLI-error code. *) 267 - Printf.eprintf "switchdocs show: %s\n" m; 267 + Printf.eprintf "odd show: %s\n" m; 268 268 `Ok exit_doc_failure) 269 269 in 270 270 let doc = "Print the documentation for a reference, as Markdown" in ··· 301 301 match switch with 302 302 | Error (`Msg m) -> `Error (false, m) 303 303 | Ok sw -> 304 - List.iter print_endline (Switchdocs.Complete.complete sw partial); 304 + List.iter print_endline (Odd.Complete.complete sw partial); 305 305 `Ok 0 306 306 in 307 307 let doc = "List the possible completions of a partial reference" in ··· 341 341 else exe 342 342 in 343 343 if not apply then ( 344 - Switchdocs.Setup.print ~exe; 344 + Odd.Setup.print ~exe; 345 345 `Ok 0) 346 346 else 347 - match Switchdocs.Setup.apply ~exe with 347 + match Odd.Setup.apply ~exe with 348 348 | Ok () -> `Ok 0 349 349 | Error (`Msg m) -> `Error (false, m) 350 350 in 351 - let doc = "Configure the opam hooks that drive switchdocs" in 351 + let doc = "Configure the opam hooks that drive odd" in 352 352 let man = 353 353 [ 354 354 `S Manpage.s_description; 355 355 `P 356 356 "Adds to the global opam configuration: a $(b,post-install-commands) \ 357 357 hook that marks a package's docs stale (a plain $(b,mkdir)+$(b,touch), \ 358 - so it works even when switchdocs isn't installed), a \ 358 + so it works even when odd isn't installed), a \ 359 359 $(b,post-remove-commands) hook that deletes a package's docs \ 360 360 ($(b,rm -rf)), and a $(b,post-session-commands) hook that runs \ 361 - $(b,switchdocs sync). Without $(b,--apply), prints the $(b,opam \ 361 + $(b,odd sync). Without $(b,--apply), prints the $(b,opam \ 362 362 option) invocations instead of running them. Fields already carrying \ 363 363 our command are skipped, so the command is idempotent."; 364 364 ] ··· 373 373 `P 374 374 "$(mname) keeps the HTML documentation of an opam switch in sync with \ 375 375 its installed packages. An opam post-install hook marks each changed \ 376 - package stale (a marker file it touches, needing no switchdocs binary) \ 376 + package stale (a marker file it touches, needing no odd binary) \ 377 377 and a post-remove hook deletes a package's docs; at the end of the \ 378 378 session the worker rebuilds exactly the stale packages, in dependency \ 379 379 order, using an odoc driver. Output goes to \ 380 380 $(b,\\$OPAM_SWITCH_PREFIX/odoc), with a landing page at \ 381 381 $(b,odoc/index.html)."; 382 - `P "Run $(b,switchdocs setup) to configure the hooks."; 382 + `P "Run $(b,odd setup) to configure the hooks."; 383 383 ] 384 384 in 385 385 Cmd.group 386 - (Cmd.info "switchdocs" ~version:"%%VERSION%%" ~doc ~man) 386 + (Cmd.info "odd" ~version:"%%VERSION%%" ~doc ~man) 387 387 [ 388 388 sync_cmd; 389 389 rebuild_cmd;
+3 -3
completions/dune
··· 1 1 ; Install the zsh completion under the package's own share dir, 2 - ; <prefix>/share/odoc-switchdocs/zsh/_switchdocs. (The switch's 2 + ; <prefix>/share/odd/zsh/_odd. (The switch's 3 3 ; share/zsh/site-functions is not on zsh's $fpath by default, so there is no 4 4 ; benefit to that layout — the user adds this dir to $fpath either way; see the 5 5 ; README.) 6 6 (install 7 7 (section share) 8 - (package odoc-switchdocs) 8 + (package odd) 9 9 (files 10 - (zsh/_switchdocs as zsh/_switchdocs))) 10 + (zsh/_odd as zsh/_odd)))
+8 -8
completions/zsh/_switchdocs completions/zsh/_odd
··· 1 - #compdef switchdocs 1 + #compdef odd 2 2 # 3 - # zsh completion for switchdocs. 3 + # zsh completion for odd. 4 4 # 5 5 # Install: put this file's directory on $fpath before compinit. After 6 6 # `opam install` it lives under the package's share dir; add to ~/.zshrc: 7 7 # 8 - # fpath=("$(opam var odoc-switchdocs:share)/zsh" $fpath) 8 + # fpath=("$(opam var odd:share)/zsh" $fpath) 9 9 # autoload -U compinit && compinit 10 10 # 11 11 # (or point $fpath at completions/zsh in a source checkout.) 12 12 # 13 13 # Reference arguments (to `show` and `complete`) are completed by calling 14 - # `switchdocs complete`, which resolves the partial reference against the whole 14 + # `odd complete`, which resolves the partial reference against the whole 15 15 # switch and returns the candidates — so completion is always in sync with the 16 16 # command's own resolver (Stdlib open, package-qualified `/pkg/...` paths, kind 17 17 # tags like `type-`, section labels, …). ··· 27 27 'setup:configure the opam hooks' 28 28 ) 29 29 30 - # Word 1 is "switchdocs"; word 2 is the subcommand. 30 + # Word 1 is "odd"; word 2 is the subcommand. 31 31 if (( CURRENT == 2 )); then 32 - _describe -t commands 'switchdocs command' cmds 32 + _describe -t commands 'odd command' cmds 33 33 return 34 34 fi 35 35 ··· 41 41 elif [[ $prev == (--prefix|-p) ]]; then 42 42 _files -/ 43 43 else 44 - # Hand the current word to `switchdocs complete`; it returns full 44 + # Hand the current word to `odd complete`; it returns full 45 45 # reference strings. Empty suffix so dotted/slashed references can be 46 46 # drilled into (type `.` and complete again). 47 47 local -a refs 48 - refs=(${(f)"$(switchdocs complete -- "$cur" 2>/dev/null)"}) 48 + refs=(${(f)"$(odd complete -- "$cur" 2>/dev/null)"}) 49 49 compadd -S '' -- $refs 50 50 fi 51 51 ;;
+4 -4
dune-project
··· 1 1 (lang dune 3.16) 2 - (name odoc-switchdocs) 2 + (name odd) 3 3 4 4 (cram enable) 5 5 6 6 (generate_opam_files true) 7 7 8 - (source (github jonludlam/odoc-switchdocs)) 8 + (source (github jonludlam/odd)) 9 9 (license ISC) 10 10 (authors "Jon Ludlam <jon@recoil.org>") 11 11 (maintainers "Jon Ludlam <jon@recoil.org>") 12 12 13 13 (package 14 - (name odoc-switchdocs) 14 + (name odd) 15 15 (synopsis "Keep an opam switch's documentation up to date via opam hooks") 16 16 (description 17 - "switchdocs wires opam's post-install, post-remove and post-session hooks \ 17 + "odd wires opam's post-install, post-remove and post-session hooks \ 18 18 to an odoc driver so that the HTML documentation of every package \ 19 19 installed in a switch is regenerated incrementally, in dependency order, \ 20 20 after each opam invocation.")
+1 -1
lib/dune
··· 1 1 (library 2 - (name switchdocs) 2 + (name odd) 3 3 (libraries 4 4 bos 5 5 fpath
+1 -1
lib/pending.ml
··· 1 - let marker_name = ".switchdocs-stale" 1 + let marker_name = ".odd-stale" 2 2 let marker sw name = Fpath.(Switch.odoc_dir sw / name / marker_name) 3 3 4 4 let read sw =
+3 -3
lib/pending.mli
··· 1 1 (** Stale markers: the set of packages whose documentation is out of date. 2 2 3 - A package is marked by the empty file [<prefix>/odoc/<name>/.switchdocs-stale]. 3 + A package is marked by the empty file [<prefix>/odoc/<name>/.odd-stale]. 4 4 The opam post-install hook creates it with a plain [mkdir -p] + [touch], so 5 - recording a change needs no switchdocs binary in the switch — only [sync] 5 + recording a change needs no odd binary in the switch — only [sync] 6 6 (and [rebuild]) do. Removals are handled directly by the post-remove hook 7 7 ([rm -rf] of the package's doc directory), which also clears any marker, so 8 8 there is no remove marker. *) 9 9 10 10 val marker : Switch.t -> string -> Fpath.t 11 - (** [<prefix>/odoc/<name>/.switchdocs-stale]. *) 11 + (** [<prefix>/odoc/<name>/.odd-stale]. *) 12 12 13 13 val read : Switch.t -> string list 14 14 (** Names of packages with a stale marker — the subdirectories of
+5 -5
lib/setup.ml
··· 2 2 3 3 (* Each entry is an opam field, the command to append to it, and a substring 4 4 that identifies our command if it is already present (for idempotency). The 5 - per-package hooks deliberately don't mention the switchdocs binary — they are 6 - plain coreutils so recording works even when switchdocs isn't installed — so 5 + per-package hooks deliberately don't mention the odd binary — they are 6 + plain coreutils so recording works even when odd isn't installed — so 7 7 the marker can't just be [exe]. *) 8 8 let fields ~exe = 9 9 [ ··· 11 11 [mkdir -p] then [touch], passing prefix/name as $1/$2 to avoid quoting 12 12 opam variables into the script. *) 13 13 ( "post-install-commands", 14 - {|["sh" "-c" "mkdir -p \"$1/odoc/$2\" && touch \"$1/odoc/$2/.switchdocs-stale\"" "--" "%{prefix}%" "%{name}%"] {error-code = 0}|}, 15 - ".switchdocs-stale" ); 14 + {|["sh" "-c" "mkdir -p \"$1/odoc/$2\" && touch \"$1/odoc/$2/.odd-stale\"" "--" "%{prefix}%" "%{name}%"] {error-code = 0}|}, 15 + ".odd-stale" ); 16 16 (* post-remove: delete the package's docs outright. Run as an argv list (no 17 17 shell), so a prefix with spaces needs no quoting. *) 18 18 ( "post-remove-commands", 19 19 {|["rm" "-rf" "%{prefix}%/odoc/%{name}%"] {error-code = 0}|}, 20 20 "/odoc/%{name}%" ); 21 - (* post-session: the one hook that needs switchdocs — rebuild stale packages 21 + (* post-session: the one hook that needs odd — rebuild stale packages 22 22 and refresh the landing page. *) 23 23 ( "post-session-commands", 24 24 Printf.sprintf {|[%s "sync" "--prefix" "%%{prefix}%%"] {success}|}
+1 -1
lib/setup.mli
··· 6 6 val fields : exe:string -> (string * string * string) list 7 7 (** The wrapper fields, the command to append to each, and a substring 8 8 identifying our command if already present. The per-package hooks are plain 9 - coreutils ([mkdir]/[touch]/[rm]) so they work without switchdocs installed; 9 + coreutils ([mkdir]/[touch]/[rm]) so they work without odd installed; 10 10 only the post-session worker invokes the binary at [exe]. *) 11 11 12 12 val print : exe:string -> unit
+1 -1
lib/switch.ml
··· 28 28 $OPAM_SWITCH_PREFIX or pass --prefix" 29 29 m))) 30 30 31 - let state_dir t = Fpath.(t.prefix / "var" / "cache" / "switchdocs") 31 + let state_dir t = Fpath.(t.prefix / "var" / "cache" / "odd") 32 32 let log_file t = Fpath.(state_dir t / "log") 33 33 let lock_file t = Fpath.(state_dir t / "lock") 34 34 let work_dir t = Fpath.(state_dir t / "work")
+2 -2
lib/switch.mli
··· 1 - (** An opam switch and the paths switchdocs uses within it. *) 1 + (** An opam switch and the paths odd uses within it. *) 2 2 3 3 type t 4 4 ··· 12 12 val prefix : t -> Fpath.t 13 13 14 14 val state_dir : t -> Fpath.t 15 - (** [<prefix>/var/cache/switchdocs], holding the log and lock. *) 15 + (** [<prefix>/var/cache/odd], holding the log and lock. *) 16 16 17 17 val log_file : t -> Fpath.t 18 18 val lock_file : t -> Fpath.t
+1 -1
lib/sync.mli
··· 3 3 type outcome = { built : string list; failed : string list } 4 4 5 5 val log : Switch.t -> string -> unit 6 - (** Append a timestamped line to the switch's switchdocs log. Best-effort; never 6 + (** Append a timestamped line to the switch's odd log. Best-effort; never 7 7 raises. *) 8 8 9 9 val sync : ?driver:Bos.Cmd.t -> Switch.t -> (outcome, [ `Msg of string ]) result
+35
odd.opam
··· 1 + # This file is generated by dune, edit dune-project instead 2 + opam-version: "2.0" 3 + synopsis: "Keep an opam switch's documentation up to date via opam hooks" 4 + description: 5 + "odd wires opam's post-install, post-remove and post-session hooks to an odoc driver so that the HTML documentation of every package installed in a switch is regenerated incrementally, in dependency order, after each opam invocation." 6 + maintainer: ["Jon Ludlam <jon@recoil.org>"] 7 + authors: ["Jon Ludlam <jon@recoil.org>"] 8 + license: "ISC" 9 + homepage: "https://github.com/jonludlam/odd" 10 + bug-reports: "https://github.com/jonludlam/odd/issues" 11 + depends: [ 12 + "dune" {>= "3.16"} 13 + "ocaml" {>= "5.2.0"} 14 + "cmdliner" {>= "1.3.0"} 15 + "bos" {>= "0.2.1"} 16 + "fpath" {>= "0.7.3"} 17 + "opam-format" {>= "2.2.0"} 18 + "sherlodoc" 19 + "odoc" {with-doc} 20 + ] 21 + build: [ 22 + ["dune" "subst"] {dev} 23 + [ 24 + "dune" 25 + "build" 26 + "-p" 27 + name 28 + "-j" 29 + jobs 30 + "@install" 31 + "@runtest" {with-test} 32 + "@doc" {with-doc} 33 + ] 34 + ] 35 + dev-repo: "git+https://github.com/jonludlam/odd.git"
-35
odoc-switchdocs.opam
··· 1 - # This file is generated by dune, edit dune-project instead 2 - opam-version: "2.0" 3 - synopsis: "Keep an opam switch's documentation up to date via opam hooks" 4 - description: 5 - "switchdocs wires opam's post-install, post-remove and post-session hooks to an odoc driver so that the HTML documentation of every package installed in a switch is regenerated incrementally, in dependency order, after each opam invocation." 6 - maintainer: ["Jon Ludlam <jon@recoil.org>"] 7 - authors: ["Jon Ludlam <jon@recoil.org>"] 8 - license: "ISC" 9 - homepage: "https://github.com/jonludlam/odoc-switchdocs" 10 - bug-reports: "https://github.com/jonludlam/odoc-switchdocs/issues" 11 - depends: [ 12 - "dune" {>= "3.16"} 13 - "ocaml" {>= "5.2.0"} 14 - "cmdliner" {>= "1.3.0"} 15 - "bos" {>= "0.2.1"} 16 - "fpath" {>= "0.7.3"} 17 - "opam-format" {>= "2.2.0"} 18 - "sherlodoc" 19 - "odoc" {with-doc} 20 - ] 21 - build: [ 22 - ["dune" "subst"] {dev} 23 - [ 24 - "dune" 25 - "build" 26 - "-p" 27 - name 28 - "-j" 29 - jobs 30 - "@install" 31 - "@runtest" {with-test} 32 - "@doc" {with-doc} 33 - ] 34 - ] 35 - dev-repo: "git+https://github.com/jonludlam/odoc-switchdocs.git"
+1 -1
test/dune
··· 1 1 (cram 2 - (deps %{bin:switchdocs})) 2 + (deps %{bin:odd}))
+7 -7
test/order.t
··· 16 16 17 17 Dependencies come before dependents, whatever order the names are given in: 18 18 19 - $ switchdocs order --prefix prefix c b a 19 + $ odd order --prefix prefix c b a 20 20 a 21 21 b 22 22 c 23 - $ switchdocs order --prefix prefix a c 23 + $ odd order --prefix prefix a c 24 24 a 25 25 c 26 26 27 27 With no arguments, every installed package is ordered: 28 28 29 - $ switchdocs order --prefix prefix 29 + $ odd order --prefix prefix 30 30 a 31 31 b 32 32 c ··· 34 34 Names that are not installed are ignored, as sync ignores them (they are 35 35 removals, not builds): 36 36 37 - $ switchdocs order --prefix prefix c nosuchpkg a 37 + $ odd order --prefix prefix c nosuchpkg a 38 38 a 39 39 c 40 40 ··· 50 50 > opam-version: "2.0" 51 51 > depends: [ "x" {post} ] 52 52 > EOF 53 - $ switchdocs order --prefix prefix x y 53 + $ odd order --prefix prefix x y 54 54 y 55 55 x 56 56 ··· 61 61 > opam-version: "2.0" 62 62 > depopts: [ "c" ] 63 63 > EOF 64 - $ switchdocs order --prefix prefix z c b 64 + $ odd order --prefix prefix z c b 65 65 b 66 66 c 67 67 z ··· 76 76 > opam-version: "2.0" 77 77 > depends: [ "p" ] 78 78 > EOF 79 - $ switchdocs order --prefix prefix p q 79 + $ odd order --prefix prefix p q 80 80 q 81 81 p 82 82 warning: dependency cycle through p; breaking it
+23 -23
test/sync.t
··· 23 23 The post-install hook marks a package stale by touching a marker file; the 24 24 post-remove hook just deletes the package's doc directory. Stand in for them: 25 25 26 - $ stale() { mkdir -p "prefix/odoc/$1"; touch "prefix/odoc/$1/.switchdocs-stale"; } 26 + $ stale() { mkdir -p "prefix/odoc/$1"; touch "prefix/odoc/$1/.odd-stale"; } 27 27 $ removed() { rm -rf "prefix/odoc/$1"; } 28 28 29 29 No stale markers is a no-op with no output: 30 30 31 - $ switchdocs sync --prefix prefix --driver ./driver.sh 31 + $ odd sync --prefix prefix --driver ./driver.sh 32 32 33 33 Marked packages are rebuilt in dependency order, regardless of the order they 34 34 were marked in (b was marked first but depends on a): 35 35 36 36 $ stale b 37 37 $ stale a 38 - $ switchdocs sync --prefix prefix --driver ./driver.sh 39 - switchdocs: 2 built, 0 failed 38 + $ odd sync --prefix prefix --driver ./driver.sh 39 + odd: 2 built, 0 failed 40 40 $ cat prefix/build-order 41 41 a 42 42 b ··· 44 44 A successful build clears the marker, and a landing page lists the documented 45 45 packages: 46 46 47 - $ test -e prefix/odoc/a/.switchdocs-stale || echo consumed 47 + $ test -e prefix/odoc/a/.odd-stale || echo consumed 48 48 consumed 49 49 $ grep -o '<li>.*</li>' prefix/odoc/index.html | sed 's/<[^>]*>//g' 50 50 a 1 ··· 57 57 > EOF 58 58 $ stale bad 59 59 $ stale a 60 - $ switchdocs sync --prefix prefix --driver ./driver.sh 61 - switchdocs: 1 built, 1 failed 62 - switchdocs: see $TESTCASE_ROOT/prefix/var/cache/switchdocs/log 63 - $ test -e prefix/odoc/bad/.switchdocs-stale && echo still-marked 60 + $ odd sync --prefix prefix --driver ./driver.sh 61 + odd: 1 built, 1 failed 62 + odd: see $TESTCASE_ROOT/prefix/var/cache/odd/log 63 + $ test -e prefix/odoc/bad/.odd-stale && echo still-marked 64 64 still-marked 65 65 66 66 A removal deletes the package's docs (post-remove hook); the landing page ··· 71 71 present 72 72 $ rm -r prefix/.opam-switch/packages/b.1 73 73 $ removed b 74 - $ switchdocs sync --prefix prefix --driver ./driver.sh 75 - switchdocs: 0 built, 1 failed 76 - switchdocs: see $TESTCASE_ROOT/prefix/var/cache/switchdocs/log 74 + $ odd sync --prefix prefix --driver ./driver.sh 75 + odd: 0 built, 1 failed 76 + odd: see $TESTCASE_ROOT/prefix/var/cache/odd/log 77 77 $ test -d prefix/odoc/b || echo gone 78 78 gone 79 79 $ grep -o '<li>.*</li>' prefix/odoc/index.html | sed 's/<[^>]*>//g' ··· 83 83 (sync still exits 0 — it is hook-facing): 84 84 85 85 $ stale a 86 - $ switchdocs sync --prefix prefix --driver ./no-such-driver 87 - switchdocs: 0 built, 2 failed 88 - switchdocs: see $TESTCASE_ROOT/prefix/var/cache/switchdocs/log 89 - $ ls prefix/odoc/a/.switchdocs-stale prefix/odoc/bad/.switchdocs-stale 90 - prefix/odoc/a/.switchdocs-stale 91 - prefix/odoc/bad/.switchdocs-stale 86 + $ odd sync --prefix prefix --driver ./no-such-driver 87 + odd: 0 built, 2 failed 88 + odd: see $TESTCASE_ROOT/prefix/var/cache/odd/log 89 + $ ls prefix/odoc/a/.odd-stale prefix/odoc/bad/.odd-stale 90 + prefix/odoc/a/.odd-stale 91 + prefix/odoc/bad/.odd-stale 92 92 93 93 rebuild is the user-facing equivalent: it marks packages stale itself and 94 94 fails loudly: 95 95 96 - $ switchdocs rebuild --prefix prefix --driver ./driver.sh a bad 97 - switchdocs: 1 built, 1 failed 98 - switchdocs: see $TESTCASE_ROOT/prefix/var/cache/switchdocs/log 96 + $ odd rebuild --prefix prefix --driver ./driver.sh a bad 97 + odd: 1 built, 1 failed 98 + odd: see $TESTCASE_ROOT/prefix/var/cache/odd/log 99 99 [1] 100 - $ switchdocs rebuild --prefix prefix --driver ./driver.sh nosuchpkg 101 - switchdocs: not installed in this switch: nosuchpkg 100 + $ odd rebuild --prefix prefix --driver ./driver.sh nosuchpkg 101 + odd: not installed in this switch: nosuchpkg 102 102 [124]