Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d90bef8580 | ||
|
|
6de3f1d714 |
@@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[Makefile]
|
||||||
|
indent_style = tab
|
||||||
+21
-2
@@ -10,5 +10,24 @@ modcache.tzst
|
|||||||
# Generated manifest files
|
# Generated manifest files
|
||||||
.index.mf
|
.index.mf
|
||||||
|
|
||||||
# Stale files
|
# Secrets
|
||||||
.drone.yml
|
.env
|
||||||
|
.env.*
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editor files
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Go build artifacts
|
||||||
|
*.log
|
||||||
|
*.out
|
||||||
|
*.test
|
||||||
|
|||||||
-12
@@ -11,10 +11,6 @@ COPY . .
|
|||||||
# Touch .pb.go so make does not try to regenerate via protoc (file is committed)
|
# Touch .pb.go so make does not try to regenerate via protoc (file is committed)
|
||||||
RUN touch mfer/mf.pb.go
|
RUN touch mfer/mf.pb.go
|
||||||
|
|
||||||
# Changing value from script/cibuild; forces the check steps below to
|
|
||||||
# re-run instead of being served from a stale layer cache.
|
|
||||||
ARG CHECK_EPOCH
|
|
||||||
|
|
||||||
# Go half of fmt-check only: this image has no node, so no prettier. The
|
# Go half of fmt-check only: this image has no node, so no prettier. The
|
||||||
# markdown half runs in the mdfmt stage below.
|
# markdown half runs in the mdfmt stage below.
|
||||||
RUN make fmt-check-go
|
RUN make fmt-check-go
|
||||||
@@ -31,10 +27,6 @@ RUN yarn install --frozen-lockfile
|
|||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Changing value from script/cibuild; forces the check step below to
|
|
||||||
# re-run instead of being served from a stale layer cache.
|
|
||||||
ARG CHECK_EPOCH
|
|
||||||
|
|
||||||
# No make in this image; call the script entrypoint directly.
|
# No make in this image; call the script entrypoint directly.
|
||||||
RUN script/prettier --check
|
RUN script/prettier --check
|
||||||
|
|
||||||
@@ -55,10 +47,6 @@ COPY . .
|
|||||||
# Touch .pb.go so make does not try to regenerate via protoc (file is committed)
|
# Touch .pb.go so make does not try to regenerate via protoc (file is committed)
|
||||||
RUN touch mfer/mf.pb.go
|
RUN touch mfer/mf.pb.go
|
||||||
|
|
||||||
# Changing value from script/cibuild; forces the check steps below to
|
|
||||||
# re-run instead of being served from a stale layer cache.
|
|
||||||
ARG CHECK_EPOCH
|
|
||||||
|
|
||||||
RUN make test
|
RUN make test
|
||||||
RUN cd cmd/mfer && go build -tags urfave_cli_no_docs -o /mfer .
|
RUN cd cmd/mfer && go build -tags urfave_cli_no_docs -o /mfer .
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# mfer
|
# mfer
|
||||||
|
|
||||||
[mfer](https://git.eeqj.de/sneak/mfer) is a reference implementation library and
|
[mfer](https://git.eeqj.de/sneak/mfer) is a [WTFPL](https://wtfpl.net)-licensed
|
||||||
thin wrapper command-line utility written in [Go](https://golang.org) and first
|
(public domain) [Go](https://golang.org) library and command-line tool by
|
||||||
published in 2022 under the [WTFPL](https://wtfpl.net) (public domain) license.
|
[@sneak](https://sneak.berlin) that specifies and generates `.mf` manifest files
|
||||||
It specifies and generates `.mf` manifest files over a directory tree of files
|
over a directory tree to encapsulate metadata about the files — such as
|
||||||
to encapsulate metadata about them (such as cryptographic checksums or
|
cryptographic checksums and signatures over same — to aid in archiving,
|
||||||
signatures over same) to aid in archiving, downloading, and streaming, or
|
downloading, streaming, and mirroring. It was first published in 2022. The
|
||||||
mirroring. The manifest files' data is serialized with Google's
|
manifest files' data is serialized with Google's
|
||||||
[protobuf serialization format](https://developers.google.com/protocol-buffers).
|
[protobuf serialization format](https://developers.google.com/protocol-buffers).
|
||||||
The structure of these files can be found
|
The structure of these files can be found
|
||||||
[in the format specification](https://git.eeqj.de/sneak/mfer/src/branch/main/mfer/mf.proto)
|
[in the format specification](https://git.eeqj.de/sneak/mfer/src/branch/main/mfer/mf.proto)
|
||||||
@@ -21,6 +21,36 @@ This project was started by [@sneak](https://sneak.berlin) to scratch an itch in
|
|||||||
as a de-facto standard and be incorporated into other software. A compatible
|
as a de-facto standard and be incorporated into other software. A compatible
|
||||||
javascript library is planned.
|
javascript library is planned.
|
||||||
|
|
||||||
|
# Getting Started
|
||||||
|
|
||||||
|
`mfer` builds from source with a Go 1.23+ toolchain. The generated protobuf code
|
||||||
|
is committed, so no `protoc` toolchain is required:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://git.eeqj.de/sneak/mfer.git
|
||||||
|
cd mfer
|
||||||
|
go build -o bin/mfer ./cmd/mfer
|
||||||
|
```
|
||||||
|
|
||||||
|
Generate a manifest for a directory tree, verify it later, and fetch a published
|
||||||
|
tree by URL:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Write .index.mf describing every file under the current directory.
|
||||||
|
bin/mfer gen .
|
||||||
|
|
||||||
|
# Verify the files on disk against the manifest. Exits nonzero if any file
|
||||||
|
# is missing or corrupted.
|
||||||
|
bin/mfer check .index.mf
|
||||||
|
|
||||||
|
# Download and cryptographically verify a tree published over HTTP: mfer
|
||||||
|
# fetches <url>/index.mf, then downloads every file it lists.
|
||||||
|
bin/mfer fetch https://example.com/tree/
|
||||||
|
```
|
||||||
|
|
||||||
|
Run `bin/mfer help` for the full command list, or `bin/mfer <command> --help`
|
||||||
|
for a single command's options.
|
||||||
|
|
||||||
# Build Status
|
# Build Status
|
||||||
|
|
||||||
CI runs via `script/cibuild` (`docker build .`), which executes `make check`
|
CI runs via `script/cibuild` (`docker build .`), which executes `make check`
|
||||||
@@ -81,7 +111,9 @@ Any changes submitted to this project must also be
|
|||||||
See [`REPO_POLICIES.md`](REPO_POLICIES.md) for detailed coding standards,
|
See [`REPO_POLICIES.md`](REPO_POLICIES.md) for detailed coding standards,
|
||||||
tooling requirements, and workflow conventions.
|
tooling requirements, and workflow conventions.
|
||||||
|
|
||||||
# Problem Statement
|
# Rationale
|
||||||
|
|
||||||
|
## The problem
|
||||||
|
|
||||||
Given a plain URL, there is no standard way to safely and programmatically
|
Given a plain URL, there is no standard way to safely and programmatically
|
||||||
download everything "under" that URL path. `wget -r` can traverse directory
|
download everything "under" that URL path. `wget -r` can traverse directory
|
||||||
@@ -105,7 +137,7 @@ Real issues I face:
|
|||||||
- when I download a large file via HTTP, I have no way of knowing if the file
|
- when I download a large file via HTTP, I have no way of knowing if the file
|
||||||
content is what it's supposed to be
|
content is what it's supposed to be
|
||||||
|
|
||||||
# Proposed Solution
|
## The solution
|
||||||
|
|
||||||
A standard, a manifest file format, and a tool for generating same.
|
A standard, a manifest file format, and a tool for generating same.
|
||||||
|
|
||||||
@@ -137,6 +169,27 @@ The manifest file would do several important things:
|
|||||||
- maybe a bittorrent chunklist for torrent client compatibility? perhaps a
|
- maybe a bittorrent chunklist for torrent client compatibility? perhaps a
|
||||||
top-level infohash for the whole manifest?
|
top-level infohash for the whole manifest?
|
||||||
|
|
||||||
|
# Design
|
||||||
|
|
||||||
|
The repository is split into a reusable library and a thin command-line wrapper
|
||||||
|
around it.
|
||||||
|
|
||||||
|
- `mfer/` is the reusable library and the heart of the project: it defines the
|
||||||
|
manifest format and implements building, scanning, checking, serialization,
|
||||||
|
and signing. The protobuf schema is `mfer/mf.proto`, and the generated code it
|
||||||
|
produces (`mfer/mf.pb.go`) is committed alongside it so the library builds
|
||||||
|
with `go get` and needs no `protoc` toolchain.
|
||||||
|
- `internal/cli/` holds the command implementations — `gen`, `check`, `freshen`,
|
||||||
|
`export`, `list`, and `fetch` — that wire the library to the command-line
|
||||||
|
interface.
|
||||||
|
- `internal/log/` provides the logging used across the commands.
|
||||||
|
- `internal/bork/` provides error-handling support.
|
||||||
|
- `cmd/mfer/` is the entrypoint: its `main` package assembles the pieces above
|
||||||
|
into the `mfer` binary.
|
||||||
|
|
||||||
|
Everything under `internal/` is private to this repository; only the `mfer/`
|
||||||
|
package is intended for import by other software.
|
||||||
|
|
||||||
# Design Goals
|
# Design Goals
|
||||||
|
|
||||||
- Replace SHASUMS/SHASUMS.asc files
|
- Replace SHASUMS/SHASUMS.asc files
|
||||||
@@ -462,9 +515,9 @@ proto `go_package` option. Which is canonical?
|
|||||||
- Issues:
|
- Issues:
|
||||||
[https://git.eeqj.de/sneak/mfer/issues](https://git.eeqj.de/sneak/mfer/issues)
|
[https://git.eeqj.de/sneak/mfer/issues](https://git.eeqj.de/sneak/mfer/issues)
|
||||||
|
|
||||||
# Authors
|
# Author
|
||||||
|
|
||||||
- [@sneak <sneak@sneak.berlin>](mailto:sneak@sneak.berlin)
|
- [@sneak](https://sneak.berlin)
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,14 @@ only thing left of the `chore/align-repo-policies` branch is the list below.
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
- 2026-09-21: made `script/cibuild` re-run the checks on an unchanged tree via a
|
- 2026-09-21: added the required README sections — named author, license, and
|
||||||
changing `CHECK_EPOCH` build arg in each Dockerfile check stage (#89)
|
category in the Description first line; added Getting Started (verified
|
||||||
|
install/usage block), Rationale (folding in Problem Statement and Proposed
|
||||||
|
Solution), and a Design section for the package layout; renamed Authors to
|
||||||
|
Author (#75)
|
||||||
|
- 2026-09-21: added the canonical `.editorconfig`, made `.gitignore` cover
|
||||||
|
secrets, OS, editor, and Go artifacts, and removed the dead Drone CI
|
||||||
|
references from `.gitignore` and `bin/gitrev.sh` (#72)
|
||||||
- 2026-08-09: added `.prettierrc`/`.prettierignore`, gave `script/fmt` and
|
- 2026-08-09: added `.prettierrc`/`.prettierignore`, gave `script/fmt` and
|
||||||
`script/fmt-check` one shared prettier file set via `script/prettier`, dropped
|
`script/fmt-check` one shared prettier file set via `script/prettier`, dropped
|
||||||
the `|| true` that hid prettier failures, and added a node-based Dockerfile
|
the `|| true` that hid prettier failures, and added a node-based Dockerfile
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
#
|
#
|
||||||
if [[ ! -z "$DRONE_COMMIT_SHA" ]]; then
|
|
||||||
echo "${DRONE_COMMIT_SHA:0:7}"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -z "$GITREV" ]]; then
|
if [[ ! -z "$GITREV" ]]; then
|
||||||
echo $GITREV
|
echo $GITREV
|
||||||
else
|
else
|
||||||
|
|||||||
+4
-9
@@ -1,19 +1,14 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# script/cibuild: run the CI build. The Dockerfile runs make fmt-check-go,
|
# script/cibuild: run the CI build. The Dockerfile runs script/check
|
||||||
# make lint, the prettier check, and make test as build steps. A bare
|
# (via make check), so a successful build implies all checks pass.
|
||||||
# `docker build .` would serve those steps from Docker's layer cache on an
|
# Generic: needs no adaptation. The Gitea workflow runs this on push.
|
||||||
# unchanged tree, exiting 0 without running them. CHECK_EPOCH is a build
|
|
||||||
# arg placed above the check steps in every check stage; passing a fresh
|
|
||||||
# value each run busts the cache for those steps (and nothing above them),
|
|
||||||
# so a green build means the checks actually ran. Dependency layers above
|
|
||||||
# the arg stay cached. The Gitea workflow runs this on push.
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
docker build --build-arg CHECK_EPOCH="$(date +%s)" .
|
docker build .
|
||||||
}
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user