bring the repo up to repo standards (closes #1)

Adopt the standard tooling from sneak/prompts: the Makefile and script/
entrypoints, lint and test stages in one Dockerfile, the canonical lint
config, the CI workflow and the formatter settings. Change the module
path to sneak.berlin/go/dcf.

Fix the lint findings in pkg/dcf in place. DCFStore becomes Store and
DCFObject becomes Object. One behaviour changes: an error listing mount
points is now returned, where a typo used to drop it.

Replace the placeholder test with real tests. Move the README into the
required sections. make build now compiles the library; it pointed at a
command that does not exist.

Model: opus-5-5
This commit is contained in:
clawbot committed 2026-11-02 18:18:27 +00:00
1 parent f585e8fa34
commit 188d5d3da0
32 files changed
+1728 -109

No files matched your search

+120 -16
View File
@@ -1,33 +1,137 @@
# dcf
Golang reader implementation of the so-called "Design rule for Camera File
system" or DCF, aka JEITA (Japan Electronics and Information Technology
Industries Association) specification number CP-3461.
## Description
[wikipedia.org/wiki/Design_rule_for_Camera_File_system](https://en.wikipedia.org/wiki/Design_rule_for_Camera_File_system)
`dcf` is a WTFPL-licensed Go library by [@sneak](https://sneak.berlin) that
reads DCF memory cards from digital cameras.
DCF is the "Design rule for Camera File system". It is also JEITA specification
number CP-3461. JEITA is the Japan Electronics and Information Technology
Industries Association. Wikipedia describes it at
[Design rule for Camera File system](https://en.wikipedia.org/wiki/Design_rule_for_Camera_File_system).
The DCF specification is why your digital camera puts images and videos in
`DCIM` and `PRIVATE/M4ROOT` directories on the memory card.
# status
`dcf` is incomplete and under development. It does not work yet.
incomplete, under development, does not work yet
## Getting Started
# why
Add the library to your Go module:
I wanted to copy images off my memory cards for processing and like
```sh
go get sneak.berlin/go/dcf
```
Then list the DCF stores on the mounted filesystems:
```go
package main
import (
"fmt"
"log"
"sneak.berlin/go/dcf/pkg/dcf"
)
func main() {
stores, err := dcf.GetDCFStores(0)
if err != nil {
log.Fatal(err)
}
for _, store := range *stores {
fmt.Println(store.String())
}
}
```
To work on the library itself, you need docker and git:
```sh
git clone git@git.eeqj.de:sneak/dcf.git
cd dcf
script/setup
make check
```
## Entrypoints
This repo adheres to the
[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all)
standard. Each entrypoint is a POSIX sh script in `script/`. Use these instead
of running the underlying tools directly.
- `script/bootstrap` (`make bootstrap`) installs the tools the host needs. It
does not install Go or the linter.
- `script/setup` (`make setup`) runs `script/bootstrap` and then installs the
git pre-commit hook.
- `script/test` (`make test`) runs the tests by building the `test` stage of the
`Dockerfile`.
- `script/lint` (`make lint`) checks the Go code by building the `lint` stage of
the `Dockerfile`. The stage fails on Go code that `gofmt` would change.
- `script/fmt` (`make fmt`) rewrites the Markdown files with `prettier`. It does
not format Go code.
- `script/fmt-check` (`make fmt-check`) checks the Markdown formatting and
changes nothing.
- `script/check` (`make check`) runs the tests, then the linter, then the
Markdown check.
- `script/build` (`make build`) compiles every package. It needs Go on the host.
- `script/docker` (`make docker`) builds the development image, tagged `dcf`.
- `script/cibuild` runs the whole CI build. The Gitea workflow runs it on every
push.
- `script/precommit` is what the git pre-commit hook runs. It runs
`script/check`.
- `script/install-precommit` (`make hooks`) installs the git pre-commit hook.
- `script/projectname` prints the project name for the other scripts.
The development image cannot be built unless the `lint` and `test` stages pass.
Run `docker run --rm -it dcf` for a shell inside it, with Go and `make`.
## Rationale
I wanted to copy images off my memory cards for processing. I also like
overengineering and reusable code.
# bugs
## Design
does not yet handle "dcf file groups" where multiple objects share the same
index number. if you need this, send me a link to a zip or tar of a memory
card that uses it and i'll see what i can do.
All the code is in the `pkg/dcf` package. The repo has no commands.
# author
- `dcf.go` holds the public API. `GetDCFStores` finds the DCF stores and lists
the files on them.
- `helpers.go` finds the mount points that hold a DCF store.
sneak <[sneak@sneak.berlin](mailto:sneak@sneak.berlin)>
The main types are:
# license
- `Store` is one DCF store on one mounted filesystem.
- `Object` is one file in a store.
- `Image` and `Video` embed `Object`. The file extension decides which one a
file becomes.
WTFPL
A mounted filesystem is a DCF store when its root holds a `DCIM` or `M4ROOT`
directory. `dcf` never mounts a filesystem.
## TODO
- Handle DCF file groups, where multiple objects share the same index number.
`dcf` does not handle these yet. If you need this, send me a link to a zip or
tar of a memory card that uses them, and I'll see what I can do.
- Parse the DCF directory and file names, rather than listing every media file
on the filesystem.
- Look for `PRIVATE/M4ROOT` rather than `M4ROOT` when detecting a DCF store.
- Return exactly the number of stores asked for. `GetDCFStores` returns one too
few when asked for two or more.
- Read stores through `fs.FS`, with a `context.Context` to cancel a walk.
- Return a plain slice from `GetDCFStores`, not a pointer to one.
- Test the walk of a store and the detection of mount points. They only run
against real mounted media today.
- Copy files off a card, and verify each copy against its SHA256 hash.
## License
WTFPL. See [LICENSE](LICENSE).
## Author
[@sneak](https://sneak.berlin) <[sneak@sneak.berlin](mailto:sneak@sneak.berlin)>