Private OPAM Repository#
A private OPAM repository with tooling for publishing OCaml packages.
Repository Structure#
├── bin/opam-publish # CLI tool for publishing packages
├── packages/ # Published package metadata
│ └── <pkg>/
│ └── <pkg>.<version>/
│ └── opam
└── repo # OPAM repository marker
Architecture#
┌──────────────┐ opam-publish ┌─────────────┐
│ Your Package │ ────────────────▶│ S3 Storage │◀── tarballs
└──────────────┘ └─────────────┘
│
▼
┌─────────────┐
│ Cloudflare │◀── public reads
└─────────────┘
┌──────────────┐ opam-publish ┌─────────────┐
│ Your Package │ ────────────────▶│ This Repo │◀── metadata only
└──────────────┘ └─────────────┘
Setup#
Requirements#
mc(MinIO client, for S3-compatible uploads)git(for pushing to this repo)tar,sha256sum(standard Unix tools)opam(optional, for linting validation)- SSH access to this repository
Configuration#
1. Configure mc alias (stores credentials securely in ~/.mc/):
mc alias set mys3 https://your-s3-endpoint ACCESS_KEY SECRET_KEY
2. Create opam-publish config (~/.config/opam-publish/config):
mkdir -p ~/.config/opam-publish
chmod 700 ~/.config/opam-publish
cat > ~/.config/opam-publish/config << 'EOF'
MC_ALIAS=mys3
S3_BUCKET=your-bucket
PUBLIC_URL_BASE=https://packages.yourdomain.com
OPAM_REPO_URL=git@your-git-host:path/to/this/repo
EOF
chmod 600 ~/.config/opam-publish/config
Add to PATH#
export PATH="$PATH:/path/to/this/repo/bin"
Or symlink:
ln -s /path/to/this/repo/bin/opam-publish ~/.local/bin/
Publishing a Package#
Prerequisites#
Your OCaml project must have:
- A
<package>.opamfile (or generate viadune build) - A
versionfield in the.opamfile ordune-project
Publish#
From your project root:
opam-publish
If multiple .opam files exist, specify which one:
opam-publish mypackage
What Happens#
- Validates
.opamfile (required fields, runsopam lintif available) - Builds a source tarball (excludes
.git,_build,_opam) - Computes SHA256 checksum
- Uploads tarball to S3
- Clones this repo, adds package metadata with URL + checksum
- Pushes commit to this repo
Example Output#
==> Validating mylib.opam...
ok
==> Building mylib.1.0.0.tbz...
42K
==> Uploading to S3...
https://packages.example.com/mylib/mylib.1.0.0.tbz
==> Cloning opam repository...
==> Pushing to opam repository...
==> Published mylib 1.0.0
Done. Users can install with:
opam install mylib
Using This Repository#
Add to OPAM#
opam repository add private git+ssh://git@your-git-host/path/to/repo.git
Or via HTTPS:
opam repository add private git+https://your-git-host/path/to/repo.git
Install Packages#
opam update
opam install <package>
Remove Repository#
opam repository remove private
Releasing a New Version#
-
Update version in
dune-project:(version 1.2.0) -
Regenerate opam file:
dune build -
Commit changes:
git add -A git commit -m "Release 1.2.0" git tag v1.2.0 git push origin main --tags -
Publish:
opam-publish
Troubleshooting#
"version not found"#
Ensure your .opam file has a version field:
version: "1.0.0"
Or in dune-project:
(version 1.0.0)
"version already published"#
Each version can only be published once. Bump the version number.
S3 upload fails#
Check mc alias and bucket access:
mc alias list
mc ls mys3/your-bucket
Git push fails#
Ensure you have SSH access to this repository:
ssh -T git@your-git-host
"opam lint failed"#
Fix the issues reported by opam lint. Common problems:
opam lint mylib.opam
Missing fields can be added to dune-project:
(generate_opam_files true)
(name mylib)
(synopsis "Short description")
(authors "Your Name")
(maintainers "your@email.com")
(license MIT)
Then regenerate with dune build.