GitHub - clayrisser/mkpm: makefile package manager

GitHub

5 min read Original article ↗

makefile package manager

mkpm shares makefile code across projects as versioned packages. A package is a tarball of makefile code stored in a git repo (via git-lfs) and tagged <package>/<version>. Installing a package unpacks it under .mkpm/ in your project, where it can be included from a Mkpmfile.

Status

mkpm is in maintenance mode. It is kept clean and working for the projects that still use it, but new projects at BitSpur use plain Makefile conventions instead. Bug fixes are welcome; new features are unlikely.

Requirements

  • POSIX shell and coreutils
  • GNU Make >= 4.1 (on macOS install remake or gmake, since apple ships make 3.81)
  • Git and Git LFS
  • jq
  • curl or wget
  • on macOS additionally gawk, gnu-sed and gnu-tar

mkpm checks for its requirements on first run and offers to install anything missing through the system package manager.

Install

$(curl --version >/dev/null 2>&1 && echo "curl -L" || echo "wget -O-") \
    https://gitlab.com/api/v4/projects/48207162/packages/generic/mkpm/1.1.0/install.sh 2>/dev/null | sh

This installs mkpm to /usr/local/bin (override with PREFIX). A debian package and the raw scripts are attached to each release.

The global mkpm binary is optional. Projects initialized with a committed ./mkpm proxy binary and a committed .mkpm/cache.tar.gz bootstrap themselves, so make works on a fresh clone without installing anything.

Quickstart

  1. Initialize mkpm at the root of a git project.

    This creates mkpm.json and offers to add the ./mkpm proxy binary, a Mkpmfile, a proxy Makefile, and editor/git configuration.

  2. Install a package.

    the - tells mkpm the argument is a command instead of a make target (in a directory that is not yet an mkpm project, like during init, the - can be omitted)

  3. Include the package in your Mkpmfile.

    include $(MKPM)/mkpm
    include $(MKPM)/hello
    
    .PHONY: greet
    greet: hello
    	@$(ECHO) done greeting

    include $(MKPM)/mkpm loads the mkpm runtime and must come first. Each installed package is included the same way by name.

  4. Run targets through mkpm.

    mkpm greet          # or ./mkpm greet
    make greet          # via the generated proxy Makefile

Commands

mkpm [options] <TARGET> [...ARGS]
mkpm [options] - <COMMAND> [...ARGS]

options:
    -h, --help                            show brief help
    -s, --silent                          silent output
    -d, --debug                           debug output
    -e, --dotenv                          dotenv file

commands:
    u|upgrade                             upgrade all packages from default git repo
    u|upgrade <REPO>                      upgrade all packages from git repo
    u|upgrade <REPO> <PACKAGE>            upgrade a package from git repo
    v|version                             mkpm version
    i|install                             install all packages
    i|install <PACKAGE>                   install a package from default git repo
    i|install <REPO> <PACKAGE>            install a package from git repo
    rm|remove <PACKAGE>                   remove a package
    ra|repo-add <REPO_NAME> <REPO_URI>    add repo
    rr|repo-remove <REPO_NAME>            remove repo
    reset                                 reset mkpm
    init                                  initialize mkpm
    pack                                  pack mkpm module
    publish                               pack and publish mkpm module

mkpm.json

All project configuration lives in mkpm.json at the project root. It is managed by the mkpm commands, but safe to edit by hand.

{
  "packages": {
    "default": {
      "gnu": "0.1.0"
    }
  },
  "repos": {
    "default": "https://gitlab.com/bitspur/mkpm/packages.git"
  },
  "binaries": {
    "docker": {
      "debian": "sudo apt-get install -y docker.io"
    }
  }
}
  • repos maps repo names to git uris. Packages under packages.<repo> are installed from that repo.
  • binaries (optional) declares system binaries the project needs. When a binary is missing, mkpm prints the matching install command (looked up by distro flavor or platform) and offers to run it.

Repos

The default package repo is https://gitlab.com/bitspur/mkpm/packages.git.

You can point the default repo at your own package repo, or add extra repos under a new name.

mkpm - repo-add howdy https://gitlab.com/example/howdy-packages.git
mkpm - install howdy texas

Authoring packages

A package is a project with a main.mk entrypoint and package metadata in mkpm.json.

{
  "name": "hello",
  "version": "0.1.0",
  "description": "example mkpm package",
  "author": "Clay Risser <email@clayrisser.com>",
  "repo": "git@gitlab.com:bitspur/mkpm/packages.git",
  "source": "https://gitlab.com/bitspur/mkpm/hello.git",
  "files": ["extra.mk"]
}
  • mkpm - pack builds <name>.tar.gz containing main.mk, mkpm.json, LICENSE and anything listed in files.
  • mkpm - publish packs and pushes the tarball to the package repo (repo), tagging it <name>/<version>. Publishing requires write access to the package repo plus python3 and pandoc (used to update the package table in the repo readme).

How it works

  • The committed ./mkpm proxy binary downloads the real mkpm.sh (pinned by version) into .mkpm/mkpm/.bin/mkpm and executes it.
  • Installed packages live under .mkpm/mkpm/, which is gitignored.
  • .mkpm/cache.tar.gz is a deterministic tarball of the bootstrap state and installed packages. Committing it (the default) makes fresh clones and CI work offline without hitting the package registry.
  • Useful environment variables: MKPM_DEBUG=1 for verbose output, DEFAULT_REPO to change the repo init starts with, and MKPM_SH_URL, MKPM_MK_URL, MKPM_PROXY_SH_URL to override where the bootstrap scripts are downloaded from.

Development

This repo self-hosts: ./mkpm <target> (or make <target>) runs the targets in Mkpmfile using the local sources, bootstrapping from the committed cache.

make test     # bats test suite (offline, sandboxed)
make lint     # shfmt formatting check
make format   # shfmt formatting fix

Tool versions are pinned in .tool-versions (asdf format). Releases are cut by pushing a git tag, which builds the debian package and uploads the scripts to the GitLab generic package registry.

License

Apache-2.0