Skip to content

Source Code Map en

Won-Kyu Park edited this page Aug 4, 2026 · 3 revisions

Source Code Map

Package layout

simple_rcs/
  simple_rcs.py          the core class (1,848 lines) — basically the library
  codec.py                format primitives (binary encoding, hashing, escaping)
  pydifflib.py             the production diff engine (StreamSequenceMatcher)
  pybsdiff.py              binary deltas (BSDIFF40-compatible)
  myersdiff.py             pure-Python Myers algorithm (reference/benchmark)
  myersdiff_ses.py          Myers SES variant
  myersdiff_dmp.py          Myers, diff-match-patch-style offset variant
  _myersdiff_ses.pyx       Cython port of the SES variant above
  _myersdiff_dmp.pyx        Cython port of the DMP variant above
  simple_rcs_gpg.py         GPG signing/verification callbacks
  adapters.py               stream adapter for psycopg2 large objects

tools/
  srcs_commit.py     CLI to commit a file
  srcs_log.py         print history / signature listing
  srcs_diff.py        unified diff between versions, or between engines
  srcs_blame.py       per-line author/version attribution
  srcs_verify.py      verify the hash chain and GPG signatures
  srcs_sign_head.py    add a GPG signature to the current HEAD
  bench_diff.py        diff-engine benchmark (time + memory)
  compare_memory_usage.py  memory-usage comparison utility

tests/unit_tests/    pytest suite (61 tests)
docs/                 design/benchmark notes
scripts/              one-off experimental benchmark scripts (e.g. wiki backend)

simple_rcs.py — the core

One class, SimpleRCS, does essentially all the work. Its public surface looks like this:

Method What it does
commit(content, author, log, ...) store a new version (text or binary, optional snapshot)
checkout(ver_num=None) restore a specific version (defaults to HEAD)
log(limit=None, reverse=False) list history metadata
diff(ver_a, ver_b) unified diff between two versions
blame(depth=None) which version/author each line of HEAD came from
sign_head(signer_callbacks) add a GPG signature to HEAD
verify(verifier_callbacks=None) verify the whole hash chain plus signatures
verify_block_signature(...) verify a single block's signature
get_content() return the raw stream content as bytes/text

Internally, the part that matters most is the backward scan from the end of the stream (_load_head, _get_prev_block). It never loads the whole file into memory — it only reads the blocks it needs — so memory usage doesn't grow with history length.

codec.py — stateless format primitives

Pure functions that don't depend on a SimpleRCS instance, so they can be tested in isolation. Binary payload encoding/decoding (encode_binary/decode_binary, supports base64/base85/raw), escaping @ inside @...@ values, and computing the v2 block hash all live here. SimpleRCS passes its own config (hash_algo, encoding) into these as arguments.

The diff modules — why so many

  • StreamSequenceMatcher in pydifflib.py — the only engine actually used on the commit path. A hybrid: greedy hash-based matching, then standard difflib refinement on the replace blocks. Doesn't guarantee the shortest edit distance, but it's fast.
  • myersdiff*.py — pure-Python implementations of the classic Myers O(ND) algorithm. Two variants: an SES (shortest edit script) version and a diff-match-patch-style offset-based version. Both guarantee minimal edit distance, but their performance diverges depending on the input characteristics.
  • _myersdiff_{ses,dmp}.pyx — straight Cython ports of the two above. 15–26x faster than the pure-Python versions, but not wired into the commit path today — they're exercised through tools/bench_diff.py only.

Why there are this many, and what you'd actually reach for, is covered in more depth in Diff Engines.

pybsdiff.py — binary deltas

Used whenever you commit non-text content (bytes). Built to be compatible with the BSDIFF40 format, so patches can also be created and applied with the native bsdiff/bspatch tools if you have them installed.

simple_rcs_gpg.py — signing and verification

Shells out to the gpg binary to create and verify signatures. The SRCS_GPGSIGN_PATH environment variable lets you point at a different gpg executable. SimpleRCS.sign_head()/verify() take these functions in as callbacks, so if you wanted a different signing scheme entirely, you could plug in a replacement with the same callback signature.

adapters.py — plugging directly into a database

SimpleRCS expects a BinaryIO, and something like psycopg2's large object — which doesn't inherit from BinaryIO — can't be handed over directly. PsycopgLargeObjectAdapter bridges that gap, so a PostgreSQL large object can stand in for a .srcs file as the backing store. Why this particular adapter is a good fit is discussed in Wiki Backend Design (Korean only).

tools/ — command-line helpers

Each script is a thin CLI wrapper around the SimpleRCS library. Run them from the repo root with uv run tools/<name>.py. Library code is supposed to log through logging and never print, but the tools/ scripts are the exception — printing to stdout is their whole job. See CLI Tools for what each one does.

Build

[build-system] in pyproject.toml uses setuptools + Cython, and ext-modules registers the two Cython extensions (_myersdiff_ses/_myersdiff_dmp). They get built as part of uv sync. If you edit a .pyx file, you need to rebuild before it takes effect.

Clone this wiki locally