radicle-lfs-transfer/README.md

114 lines
5.8 KiB
Markdown

# radicle-lfs-transfer
A [Git LFS custom transfer agent][custom-transfer] that backs large file storage with
[IPFS](https://ipfs.tech), for use with [Radicle](https://radicle.xyz) repositories.
This is the companion binary for the `rad lfs` support added in
[**radicle-heartwood-lfs**](https://git.hswro.org/mab122/radicle-heartwood-lfs) (a fork of
Radicle's core node/CLI, `heartwood`). **Most people want to start there, not here** — that
repo has the full zero-to-usable setup guide. This repo is what you're reading if you want to
build/understand the transfer agent on its own, or you're following a link back from there.
`rad-lfs-transfer` is not meant to be invoked directly — `git lfs` spawns it automatically,
once a repository has been set up with `rad lfs init` (from the fork above).
[custom-transfer]: https://github.com/git-lfs/git-lfs/blob/main/docs/custom-transfers.md
## How it works
Every peer uses their own local IPFS node — there's no shared server. All of the actual
IPFS add/pin work and git-notes bookkeeping lives in the `rad lfs store`/`rad lfs fetch`/
`rad lfs precommit` subcommands, implemented in the companion
[**radicle-heartwood-lfs**](https://git.hswro.org/mab122/radicle-heartwood-lfs) fork — that's
also where content gets encrypted for private repositories before it ever reaches IPFS. This
crate deliberately has no dependency on Radicle's identity/crypto stack; it just shells out:
- On `git add`/`git commit`, a pre-commit hook (installed by `rad lfs init`) collects every
staged LFS-tracked file's oid/size and passes them all to a single `rad lfs precommit` call,
which adds each one to your local IPFS daemon, pins it, encrypts it first if the repo is
private, and records the resulting CID as a git note (batched into one call, rather than one
per file, so a private repo's passphrase is only prompted for once per commit). Note that
committing the note locally and pushing it are separate steps in Radicle — pushing your
commit (`git push rad <branch>`) does **not** also push the notes ref; that needs a separate
bare `git push rad` (see radicle-heartwood-lfs's `LFS-IPFS.md` for the full explanation).
- `rad-lfs-transfer` implements the other half: when `git lfs push`/`pull` runs, it's invoked
per-object over stdin/stdout JSON (the standard Git LFS custom-transfer-agent protocol) and:
- **upload**: shells out to `rad lfs store --oid <oid> --size <size> <path>`, which is
authoritative and idempotent — it always ends up added, pinned, and noted correctly,
whether or not the pre-commit hook already did it (e.g. if it was bypassed with
`--no-verify`).
- **download**: shells out to `rad lfs fetch --oid <oid> --size <size> --out <path>`, which
looks up the note, fetches from IPFS (pulling from the wider network if not local yet),
decrypts if needed, and writes the plaintext to `<path>`.
There is no central server anywhere in this design — see
[radicle-heartwood-lfs's `LFS-IPFS.md`](https://git.hswro.org/mab122/radicle-heartwood-lfs/src/branch/rad-lfs-ipfs/LFS-IPFS.md)
for the full rationale and how `rad seed`/`rad unseed` tie IPFS pinning to Radicle's existing
seeding lifecycle.
## Dependencies
On Arch Linux:
```sh
# To build and install
sudo pacman -S --needed rust
# To actually use it (not needed to build/install — see "Requirements" below)
sudo pacman -S --needed kubo
```
On other distributions, install a Rust toolchain (e.g. via [rustup](https://rustup.rs)) —
and, only when you want to use LFS, not to build this — [Kubo](https://docs.ipfs.tech/install/).
## Requirements
None of these are needed to build or install this binary — only at runtime, when `git lfs
push`/`pull` actually invokes it:
- The `rad` binary (built from
[**radicle-heartwood-lfs**](https://git.hswro.org/mab122/radicle-heartwood-lfs)) on your
`PATH`, with the repository already set up via `rad lfs init`. `rad-lfs-transfer` shells out
to `rad lfs store`/`rad lfs fetch` for every object — it does not talk to git notes or IPFS
directly itself anymore (that's all inside those subcommands now), and it has no dependency
on `git` either.
- A local IPFS (Kubo) daemon reachable at `http://127.0.0.1:5001` (or wherever `KUBO_API_URL`
points) — used both by `rad lfs store`/`fetch` themselves and by this binary's own startup
healthcheck on the `init` event, so a daemon-not-running failure is reported clearly up
front (`ipfs daemon`) rather than confusingly mid-transfer.
- [Git LFS](https://git-lfs.com) installed (`git-lfs` on your `PATH`) — `git-lfs` package on
Arch (`sudo pacman -S --needed git-lfs`).
## Build & install
```sh
git clone ssh://git@git.hswro.org:9022/mab122/radicle-lfs-transfer.git
cd radicle-lfs-transfer
cargo install --path .
```
This installs the `rad-lfs-transfer` binary to `~/.cargo/bin` by default — make sure that's on
your `PATH`. If you're installing it alongside `radicle-heartwood-lfs` (the usual case), install
it to that project's shared root instead so everything ends up in one place:
```sh
cargo install --path . --force --locked --root ~/.radicle
```
(You normally don't need to clone this repo separately at all for that — `radicle-heartwood-lfs`
includes it as a git submodule and its own setup instructions cover installing both together.)
## Configuration
| Environment variable | Default | Purpose |
|-----------------------|----------------------------|-------------------------------------------|
| `KUBO_API_URL` | `http://127.0.0.1:5001` | Base URL of your local Kubo HTTP RPC API |
You normally don't need to set this yourself — `rad lfs init` wires up everything else
(the transfer-agent config, the pre-commit hook, and the notes-ref refspecs) automatically.
## License
Licensed under either of [Apache License, Version 2.0](LICENSE-APACHE) or
[MIT license](LICENSE-MIT) at your option.