8000 GitHub - dhoard/repoman · GitHub
[go: up one dir, main page]

Skip to content
dhoardPublic

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Repoman

Publish built artifacts into a Maven repository layout — driven entirely by a configuration file.

Repoman reads a .conf file that lists the modules to publish (their Maven coordinates and where the built artifacts live), copies them into a Maven repository layout, generates a POM and checksums, and updates maven-metadata.xml. Publishing is immutable: an existing version is never overwritten.

The repository target can be a local directory or a remote rsync destination (rsync:// daemon URL or scp-style [user@]host:path).

Features

  • Config-driven — one .conf file per publish run; no build-system detection, no guessing. Coordinates and artifact locations are declared explicitly.
  • Indentation-tolerant conf format — ----delimited key : value blocks; lines are trimmed, empty lines and # comments are ignored.
  • Quoting — values/keys may be quoted ("...", '...') with \" escaping, or use Rust-style raw strings (r"...", r#"..."#).
  • Immutable publishing — existing versions are skipped, never overwritten; cleanup is the user's responsibility.
  • Complete Maven layout — groupPath/artifact/version/, generated POM, .sha256 checksums, and maven-metadata.xml.
  • Local or remote — publish into a local directory, or into a remote repository over rsync (daemon or ssh; never --delete): the remote's directory layout and maven-metadata.xml files are pulled into ./staging/ (binaries stay on the remote), the new artifacts are patched in, and the combined tree is sy B6B6 nced back.
  • Clean output — concise standard output, or detailed step-by-step output with --verbose.

Requirements

  • Go 1.25+ to build.
  • rsync on PATH when publishing to a remote target.
  • upx (optional) to compress the binary during build.sh.

Install / Build

./build.sh

This produces ./repoman. Set VERSION to inject a version string (defaults to dev):

VERSION=0.3.0 ./build.sh

Or build manually:

go build -trimpath -ldflags="-s -w -X main.version=0.3.0" -o repoman .

Usage

repoman [--verbose] <conf-file> <target>
Argument Description
conf-file Required conf file listing the modules to publish
target Required local directory, or a remote rsync destination: an rsync:// daemon URL or [user@]host:path
Option Description
--verbose, -v Print detailed step-by-step output
-h, --help Show help

Exit codes:

Code Meaning
0 Success (possibly with skipped modules)
1 A module failed, or a fatal error occurred
2 Usage / argument error

Configuration

A conf file is a flat list of modules. Each module is a ----delimited block of key : value lines. Lines are trimmed; empty lines and lines starting with # are ignored, so indentation is harmless. Leading, trailing, and doubled --- separators are tolerated.

Each module requires:

  • group-id — Maven group ID
  • artifact-id — Maven artifact ID
  • version — version to publish
  • exactly one of:
    • jar — a pinned artifact file to publish
    • output-dir — a directory to scan for artifacts (picks up pom, sources, javadoc, executables, etc.)

Relative jar / output-dir paths are resolved against the conf file's directory.

Example:

# org.example.core.conf

---

group-id    : org.example
artifact-id : core
version     : 1.2.3
jar         : ../core/target/core-1.2.3.jar

---

group-id    : org.example
artifact-id : api
version     : 1.2.3
output-dir  : ../api/target

---

Quoting

Keys and values may be quoted with " or ' to include spaces or special characters:

jar: "path with spaces.jar"

Inside a quoted value, \" escapes a double quote and \\ escapes a backslash. Rust-style raw strings are also accepted and skip escaping altogether:

jar: r#"path with "quotes".jar"#

How Publishing Works

For each module, repoman:

  1. Checks that the version does not already exist in the target repository. An existing version is skipped (never overwritten) and repoman prints a SKIPPED notice with the directory to remove to republish.
  2. Copies the artifact(s) into <target>/<group-path>/<artifact>/<version>/. Pinned jars are copied as <artifact>-<version>.jar; output directories are scanned for matching artifacts, executables (which get a platform tag), and supporting files.
  3. Generates a POM (<artifact>-<version>.pom) if one is not already present.
  4. Generates a SHA-256 checksum file (<artifact>-<version>.sha256).
  5. Updates maven-metadata.xml with the new version.

For a local target, maven-metadata.xml is updated in place: the metadata directory is scanned for existing version directories and the new version is merged in (deduplicated, sorted, <release>/<latest> updated), so already-published versions are preserved. For a remote target, the remote's directory layout and maven-metadata.xml files are first pulled into ./staging/, then the same in-place merge runs against that staged tree, and the combined result is synced back — see Remote Publishing.

Output

Standard output (default):

Repoman 0.3.0

Configuration: altcontainers.conf
Repository:    /tmp/repo
Modules:       2
Options:       none

[1/2] org.altcontainers:core:0.3.0-POST
  ✓ Published
  • jar: core-0.3.0-POST.jar
  • repo: /tmp/repo/org/altcontainers/core/0.3.0-POST
  • metadata: updated

[2/2] org.altcontainers:reaper:0.3.0-POST
  ✓ Published
  • jar: reaper-0.3.0-POST.jar
  • repo: /tmp/repo/org/altcontainers/reaper/0.3.0-POST
  • metadata: updated

Summary

  Published:  2
  Skipped:    0
  Failed:     0

Published artifacts
  • org.altcontainers:core:0.3.0-POST
    -> /tmp/repo/org/altcontainers/core/0.3.0-POST
  • org.altcontainers:reaper:0.3.0-POST
    -> /tmp/repo/org/altcontainers/reaper/0.3.0-POST

Repository: /tmp/repo

A version that already exists is skipped, with the directory to remove to republish:

[1/1] org.altcontainers:core:0.3.0-POST
      SKIPPED  Version already exists
               Remove REPOSITORY/org/altcontainers/core/0.3.0-POST to republish

Summary

  Published:  0
  Skipped:    1
  Failed:     0

Repository: ./REPOSITORY

Verbose output (--verbose):

Repoman 0.3.0

Configuration: altcontainers.conf
Repository:    /tmp/repo
Modules:       2
Options:       --verbose

[1/2] org.altcontainers:core:0.3.0-POST
  • source jar: ../../altcontainers/altcontainers/core/target/core-0.3.0-POST.jar
  • target dir: /tmp/repo/org/altcontainers/core/0.3.0-POST
  ✓ Repository directory ready
  ✓ Version is unique
  ✓ Copied artifact: core-0.3.0-POST.jar
  ✓ Generated POM: core-0.3.0-POST.pom
  ✓ Updated metadata: /tmp/repo/org/altcontainers/core/maven-metadata.xml
  ✓ Verified repository integrity

[2/2] org.altcontainers:reaper:0.3.0-POST
  • source jar: ../../altcontainers/altcontainers/reaper/target/reaper-0.3.0-POST.jar
  • target dir: /tmp/repo/org/altcontainers/reaper/0.3.0-POST
  ✓ Version is unique
  ✓ Copied artifact: reaper-0.3.0-POST.jar
  ✓ Generated POM: reaper-0.3.0-POST.pom
  ✓ Updated metadata: /tmp/repo/org/altcontainers/reaper/maven-metadata.xml
  ✓ Verified repository integrity

Summary

  Published:  2
  Skipped:    0
  Failed:     0

Repository: /tmp/repo

Remote Publishing

Passing a remote URL as the target publishes in three phases: the remote's directory layout and maven-metadata.xml files are first pulled into ./staging/ — binaries and other artifact files stay on the remote, so the pull stays cheap even for large repositories — the new artifacts and the regenerated maven-metadata.xml are patched on top of it, then the combined tree is synced back to the remote. Pulling first matters: existing remote versions are preserved and their metadata is merged instead of being replaced by a fresh local file, so maven-metadata.xml keeps listing every published version. A remote that does not exist yet (or is empty) is treated as a fresh repository and the first publish creates it; a missing source is not an error.

The staging directory is created if missing and emptied at the start of each run before the pull, but it is never deleted, so it can be inspected between runs.

Local targets do not use the pull/patch/push flow: repoDir is the target directory itself, so existing versions are seen and maven-metadata.xml is merged in place.

Two transports are supported:

  • rsync daemon — rsync://[user@]host/module syncs to a module defined in the remote rsyncd.conf. Requires an rsync daemon on the remote.
  • ssh — scp-style [user@]host:path syncs to a real directory over ssh. Uses your normal ssh authentication (keys, agent, ~/.ssh/config); no daemon needed.
repoman altcontainers.conf rsync://repo.example.com/maven
repoman altcontainers.conf user@repo.example.com:/var/maven

Remote targets never delete files (no --delete): the remote is cumulative, and cleanup is the user's responsibility. If an rsync:// daemon cannot be reached at all (no rsyncd running, firewall, ...), repoman retries the same URL path over ssh — for both the pull and the push — so rsync://host/path works on hosts without a daemon by syncing to host:/path instead.

Authentication uses environment variables:

Variable Purpose
REPOMAN_USERNAME Added to the URL (rsync://user@host/..., user@host:...) when the URL has none
REPOMAN_PASSWORD Mapped to rsync's RSYNC_PASSWORD for rsync:// daemon syncs (not used for ssh)

Example Configs

  • example.conf — annotated template
  • altcontainers.conf — real-world example (single module, pinned jar)

Development

go build .        # build
go vet ./...      # static checks
gofmt -l .        # formatting check (should print nothing)
./build.sh        # full build with optional UPX compression

License

Apache License 2.0. See LICENSE.


Copyright (c) 2026-present Douglas Hoard

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0