]> git.sev.monster Git - docker-abuild.git/log
docker-abuild.git
22 months agofix errexit on empty $1, add help sev/devel
sev [Thu, 14 Jul 2022 17:11:05 +0000 (12:11 -0500)]
fix errexit on empty $1, add help

22 months agolots of small changes
sev [Tue, 5 Jul 2022 10:55:02 +0000 (05:55 -0500)]
lots of small changes

- don't cache docker build
- add dabuild user to sudoers
- update some comments
- dabuild: error out if REPODEST can't be created
- entrypoint: always create dabuild user and assign to DABUILD_UID
- entrypoint: actually copy .ssh and .gitconfig
- entrypoint: add ability to run other commands than abuild

2 years agorun as any user + lots of small tweaks and fixes
sev [Wed, 15 Dec 2021 08:39:25 +0000 (02:39 -0600)]
run as any user + lots of small tweaks and fixes

dabuild can now run as any user/group combination, and supports root. it
will now more thoroughly and sanely check to ensure it is able to write
to its destination directories, and will take into account any
additional group memberships in addition to primary group.  this
constituted touching up and rewriting a lot of the entrypoint logic.

aside from that there are a lot of other small tweaks and fixes:
- removed extraneous commands from Dockerfile, and use better initial
  package management + unnecessary config pruning
- added dabuild tag to die() messages
- prevent additional debug vars from being sent, now that we check_debug
  multiple times; while likely not necessary, it should help provide a
  more sane docker command line and prevent edge cases in the future
- replace $* with $@ in arg()
- fix potential empty case in setup_volume, some sh complain
- clean up comments
- add DABUILD_SKIP_PERMISSION_CHECKS and
  DABUILD_IGNORE_PERMISSION_ERRORS to skip checks/ignore errors when
  checking important dir permissions, useful in environments with ACLs
  that are not checked or where the underlying filesystem may otherwise
  be reporting permissions that actually work
- set defaults for missing abuild.conf
- remove unnecessary DABUILD_DEBUG default value declaration
- set vars directly instead of using ${x:=y} where possible

2 years agocomplete code refactor
sev [Sun, 11 Jul 2021 16:46:01 +0000 (11:46 -0500)]
complete code refactor

added/improved:
 - abuild is now run with the same UID as the calling user
 - packager keys and other files are copied over more reliably
 - environent vars are now much more deeply inspected and copied
 - new vars from default abuild.conf added to copy list
 - renamed a lot of variables for readability and context
 - added helper functions in various places to help streamline
 - any repos/packages in DABUILD_REPODIR are available in the container

removed:
 - multiarch/cross-compile not implemented
 - CI and related automation not implemented
 - dabuild.conf, not rewritten for new values
 - dabuild-admin, make_images.sh, and other unnecessary scripts
 - builder user is no longer set up in container

issues compared to upstream:
 - expects Alpine userland
 - no automation
 - less command line interactivity (dabuild-admin etc)

known bugs:
 - user group memberships are not considered when calculating permission
 - currently cannot be run as root

3 years agoMerge branch 'rules-ci' into 'master'
Carlo Landmeter [Fri, 19 Jun 2020 19:06:49 +0000 (19:06 +0000)]
Merge branch 'rules-ci' into 'master'

ci: switch to using rules

See merge request alpine/docker-abuild!63

3 years agoci: switch to using rules
Carlo Landmeter [Wed, 17 Jun 2020 19:55:30 +0000 (21:55 +0200)]
ci: switch to using rules

this will not push to docker hub when project is not alpine based
and is not master.

4 years agoExplicitly depend on sudo
Carlo Landmeter [Fri, 1 May 2020 08:04:40 +0000 (08:04 +0000)]
Explicitly depend on sudo

https://gitlab.alpinelinux.org/alpine/aports/-/commit/39bd500283b46d2d5f3ad24b360e062592558110

4 years agoentrypoint: always set correct permissions of abuild conf dir
Carlo Landmeter [Mon, 3 Feb 2020 14:14:35 +0000 (15:14 +0100)]
entrypoint: always set correct permissions of abuild conf dir

4 years agoentrypoint: fix abuild config dir permission
Carlo Landmeter [Mon, 3 Feb 2020 12:03:30 +0000 (13:03 +0100)]
entrypoint: fix abuild config dir permission

4 years agoMerge branch 'multiple_fixes' into 'master'
Richard Mortier [Thu, 30 Jan 2020 21:03:29 +0000 (21:03 +0000)]
Merge branch 'multiple_fixes' into 'master'

Multiple fixes and features

See merge request alpine/docker-abuild!60

4 years agoadmin: use correct program and uppercase globals
Carlo Landmeter [Sat, 18 Jan 2020 13:47:15 +0000 (14:47 +0100)]
admin: use correct program and uppercase globals

4 years agoadmin: multiarch add enable/disable with warning
Carlo Landmeter [Sat, 18 Jan 2020 13:39:04 +0000 (14:39 +0100)]
admin: multiarch add enable/disable with warning

4 years agoadmin: set shell to -eu
Carlo Landmeter [Tue, 14 Jan 2020 09:21:45 +0000 (10:21 +0100)]
admin: set shell to -eu

4 years agoadd editorconfig support and follow alpine coding style
Carlo Landmeter [Tue, 14 Jan 2020 09:20:15 +0000 (10:20 +0100)]
add editorconfig support and follow alpine coding style

4 years agodabuild: alpine release can have more digits
Carlo Landmeter [Mon, 13 Jan 2020 23:53:11 +0000 (00:53 +0100)]
dabuild: alpine release can have more digits

4 years agodabuild: set shell to catch unset vars
Carlo Landmeter [Mon, 13 Jan 2020 23:50:31 +0000 (00:50 +0100)]
dabuild: set shell to catch unset vars

assign default values early in dabuild

4 years agouse git symbolic-ref to get branch name
Carlo Landmeter [Mon, 13 Jan 2020 22:28:13 +0000 (23:28 +0100)]
use git symbolic-ref to get branch name

4 years agoremove check for packages dir
Carlo Landmeter [Mon, 13 Jan 2020 22:23:52 +0000 (23:23 +0100)]
remove check for packages dir

Packages dir is a docker volume and the mount point will be
automatically created. Permissions will be correct from entrypoint.

4 years agoadmin: add enable multi-arch
Carlo Landmeter [Sat, 11 Jan 2020 21:17:45 +0000 (22:17 +0100)]
admin: add enable multi-arch

4 years agomake distfiles named volume/bind configuable:
Carlo Landmeter [Sat, 11 Jan 2020 16:49:45 +0000 (17:49 +0100)]
make distfiles named volume/bind configuable:

- set to true to enable named volume
- set to absolute path to enable bind mount

4 years agoadd default settings to users abuild.conf
Carlo Landmeter [Sat, 11 Jan 2020 15:38:33 +0000 (16:38 +0100)]
add default settings to users abuild.conf

4 years agodabuild: do not mount hosts /etc/abuild.conf
Carlo Landmeter [Sat, 11 Jan 2020 14:11:59 +0000 (15:11 +0100)]
dabuild: do not mount hosts /etc/abuild.conf

On Alpine (and also on other dists) its not safe to share the same
abuild.conf for multiple Alpine releases and architectures. Use the
users .abuild/abuild.conf instead.

4 years agoentrypoint: simplify abuild key generation
Carlo Landmeter [Sat, 11 Jan 2020 14:11:24 +0000 (15:11 +0100)]
entrypoint: simplify abuild key generation

4 years agoadmin: add cmd to list all volumes
Carlo Landmeter [Fri, 10 Jan 2020 09:31:36 +0000 (10:31 +0100)]
admin: add cmd to list all volumes

4 years agorename alpine based variables
Carlo Landmeter [Fri, 10 Jan 2020 09:11:28 +0000 (10:11 +0100)]
rename alpine based variables

4 years agoadd script to administer dabuild
Carlo Landmeter [Fri, 10 Jan 2020 08:28:00 +0000 (09:28 +0100)]
add script to administer dabuild

4 years agoadd apk cache and simplify named volumes
Carlo Landmeter [Fri, 10 Jan 2020 08:16:18 +0000 (09:16 +0100)]
add apk cache and simplify named volumes

- apk supports caching of packages for reuse on next run. This is the
  prefered way and should be relativly fast compared to other package
  magenagers. This also removed the need for other named volumes which
  need to be setup and maintained on each run.
- correcly set perm of volume mount points

4 years agoMerge branch 'use-dabuild_docker' into 'master'
Richard Mortier [Sat, 4 Jan 2020 09:40:36 +0000 (09:40 +0000)]
Merge branch 'use-dabuild_docker' into 'master'

dabuild: doh! actually use the indicated `$DABUILD_DOCKER` command

See merge request alpine/docker-abuild!58

4 years agodabuild: doh! actually use the indicated `$DABUILD_DOCKER` command
Richard Mortier [Mon, 30 Dec 2019 12:51:42 +0000 (13:51 +0100)]
dabuild: doh! actually use the indicated `$DABUILD_DOCKER` command

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoMerge branch 'github/fork/clandmeter/dabuild-conf' into 'master'
Richard Mortier [Fri, 3 Jan 2020 21:58:53 +0000 (21:58 +0000)]
Merge branch 'github/fork/clandmeter/dabuild-conf' into 'master'

add dabuild.conf support

See merge request alpine/docker-abuild!57

4 years agoonly build images when needed
Carlo Landmeter [Thu, 2 Jan 2020 23:23:11 +0000 (00:23 +0100)]
only build images when needed

4 years agoupdate readme arch support
Carlo Landmeter [Thu, 2 Jan 2020 22:55:53 +0000 (23:55 +0100)]
update readme arch support

4 years agofix project and release name
Carlo Landmeter [Thu, 2 Jan 2020 22:25:40 +0000 (23:25 +0100)]
fix project and release name

4 years agoadd gitlab ci
Carlo Landmeter [Thu, 2 Jan 2020 20:29:26 +0000 (21:29 +0100)]
add gitlab ci

4 years agodabuild: mount gitconfig in container
Carlo Landmeter [Sat, 28 Dec 2019 14:09:07 +0000 (15:09 +0100)]
dabuild: mount gitconfig in container

abuild-keygen will look for gitconfig to fetch user and email address
and set proper PACKAGER variable in abuild.conf

4 years agoadd dabuild.conf support
Carlo Landmeter [Tue, 31 Dec 2019 01:31:49 +0000 (02:31 +0100)]
add dabuild.conf support

4 years agoreadme: fix instructions for multiarch support
Richard Mortier [Sun, 29 Dec 2019 18:25:47 +0000 (19:25 +0100)]
readme: fix instructions for multiarch support

closes #51

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoadd alpine v3.11
Carlo Landmeter [Sat, 28 Dec 2019 14:39:03 +0000 (15:39 +0100)]
add alpine v3.11

4 years agoreadme: add instructions to install multiarch support on Linux
Richard Mortier [Sun, 29 Dec 2019 15:59:22 +0000 (16:59 +0100)]
readme: add instructions to install multiarch support on Linux

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agodabuild: put `.ccache` into a named volume, to support multiarch
Richard Mortier [Sun, 29 Dec 2019 14:04:43 +0000 (15:04 +0100)]
dabuild: put `.ccache` into a named volume, to support multiarch

closes #48

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoreadme: document `sudo` issue and fix
Richard Mortier [Sun, 29 Dec 2019 13:44:40 +0000 (14:44 +0100)]
readme: document `sudo` issue and fix

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoreadme: document supported environment variables
Richard Mortier [Fri, 27 Dec 2019 16:45:28 +0000 (17:45 +0100)]
readme: document supported environment variables

Closes #46
Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agofeat: add support for ccache-enabled abuild
Joseph Benden [Sat, 20 Jul 2019 01:43:04 +0000 (01:43 +0000)]
feat: add support for ccache-enabled abuild

This introduces support for ccache, when enabled in `abuild`.

Signed-off-by: Joseph Benden <joe@benden.us>
4 years agodabuild: add support for `DABUILD_DOCKER` env var
Richard Mortier [Fri, 29 Nov 2019 17:30:11 +0000 (17:30 +0000)]
dabuild: add support for `DABUILD_DOCKER` env var

Closes #45

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoWorkaround for ARCH detection
macmpi [Sun, 27 Oct 2019 16:55:24 +0000 (17:55 +0100)]
Workaround for ARCH detection

Restored alpine docker genuinely supported architectures (as other ones are definitely not).
Just give a clue to set wanted DABUILD_ARCH variable at invocation, when uname does not provide adequate info on some platforms like Pi.

4 years agodabuild: more helpful error message, list possible `$ARCH` in `README`
Richard Mortier [Fri, 25 Oct 2019 14:21:00 +0000 (15:21 +0100)]
dabuild: more helpful error message, list possible `$ARCH` in `README`

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agodabuild: fix interpretation of `uname -m` on RPi; closes #41
Richard Mortier [Fri, 25 Oct 2019 13:32:54 +0000 (14:32 +0100)]
dabuild: fix interpretation of `uname -m` on RPi; closes #41

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agodabuild: rm image after run by default; control via `$DABUILD_RM`
Richard Mortier [Fri, 18 Oct 2019 16:05:47 +0000 (17:05 +0100)]
dabuild: rm image after run by default; control via `$DABUILD_RM`

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agodabuild: unabstractify `docker` invocation
Richard Mortier [Fri, 18 Oct 2019 16:05:27 +0000 (17:05 +0100)]
dabuild: unabstractify `docker` invocation

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoentrypoint: test if `~/.abuild` writable, fail if not
Richard Mortier [Fri, 13 Sep 2019 13:19:10 +0000 (14:19 +0100)]
entrypoint: test if `~/.abuild` writable, fail if not

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoreadme: add note about bash-5.0 issue
Richard Mortier [Fri, 13 Sep 2019 13:10:09 +0000 (14:10 +0100)]
readme: add note about bash-5.0 issue

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agowhitespace
Richard Mortier [Sat, 7 Sep 2019 22:04:55 +0000 (23:04 +0100)]
whitespace

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agodabuild: require `aports` tree is exactly in `.../aports/` on host
Richard Mortier [Sat, 7 Sep 2019 22:04:24 +0000 (23:04 +0100)]
dabuild: require `aports` tree is exactly in `.../aports/` on host

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agodabuild: fix `die`
Richard Mortier [Sat, 7 Sep 2019 22:03:32 +0000 (23:03 +0100)]
dabuild: fix `die`

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoreadme: move badge to the top
Richard Mortier [Fri, 12 Jul 2019 08:58:21 +0000 (09:58 +0100)]
readme: move badge to the top

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoreadme: add ipv6 issue
Richard Mortier [Fri, 21 Jun 2019 15:27:22 +0000 (16:27 +0100)]
readme: add ipv6 issue

4 years agoMakefile: whitespace
Richard Mortier [Fri, 12 Jul 2019 08:45:54 +0000 (09:45 +0100)]
Makefile: whitespace

Signed-off-by: Richard Mortier <mort@cantab.net>
4 years agoMakefile: .drone.yml target
tcely [Sat, 22 Jun 2019 14:02:29 +0000 (10:02 -0400)]
Makefile: .drone.yml target

4 years agoMakefile: add v3.10
tcely [Sat, 22 Jun 2019 17:54:13 +0000 (13:54 -0400)]
Makefile: add v3.10

4 years agodockerfiles: add alpine v3.10
Carlo Landmeter [Sat, 22 Jun 2019 09:53:32 +0000 (09:53 +0000)]
dockerfiles: add alpine v3.10

4 years agodrone: add alpine v3.10
Carlo Landmeter [Sat, 22 Jun 2019 09:50:27 +0000 (09:50 +0000)]
drone: add alpine v3.10

4 years agoMerge pull request #26 from tcely/patch-2
Richard Mortier [Fri, 21 Jun 2019 15:00:20 +0000 (16:00 +0100)]
Merge pull request #26 from tcely/patch-2

drone: do not publish for pull requests

4 years agoMerge pull request #24 from tcely/patch-1
Richard Mortier [Fri, 21 Jun 2019 14:58:58 +0000 (15:58 +0100)]
Merge pull request #24 from tcely/patch-1

Dockerfile: upgrade the installed packages

4 years agodrone: do not publish for pull requests
tcely [Sat, 1 Jun 2019 16:13:13 +0000 (12:13 -0400)]
drone: do not publish for pull requests

4 years agoDockerfile: upgrade the installed packages
tcely [Fri, 31 May 2019 14:53:33 +0000 (10:53 -0400)]
Dockerfile: upgrade the installed packages

This is done before the cache is setup to keep the layer clean.

Resolves #23

4 years agoreadme: add drone build status
Carlo Landmeter [Tue, 21 May 2019 21:41:24 +0000 (21:41 +0000)]
readme: add drone build status

4 years agochange image namespace to alpinelinux
Carlo Landmeter [Tue, 21 May 2019 20:22:50 +0000 (20:22 +0000)]
change image namespace to alpinelinux

ref: GH-20

4 years agomakefile: add support for arch based images
Carlo Landmeter [Sun, 19 May 2019 20:33:33 +0000 (20:33 +0000)]
makefile: add support for arch based images

4 years agoupdate dockerfiles cleanup and gitignore
Carlo Landmeter [Sun, 19 May 2019 08:33:31 +0000 (08:33 +0000)]
update dockerfiles cleanup and gitignore

4 years agoentrypoint: update indexes and world
Carlo Landmeter [Sat, 18 May 2019 10:53:48 +0000 (10:53 +0000)]
entrypoint: update indexes and world

4 years agodabuild: mount abuild.conf readonly
Carlo Landmeter [Sat, 18 May 2019 10:50:38 +0000 (10:50 +0000)]
dabuild: mount abuild.conf readonly

4 years agodrone: add depends_on dockerfiles
Carlo Landmeter [Sat, 18 May 2019 10:40:03 +0000 (10:40 +0000)]
drone: add depends_on dockerfiles

this should run steps in parallel

4 years agodrone: generate dockerfiles
Carlo Landmeter [Fri, 17 May 2019 10:45:55 +0000 (10:45 +0000)]
drone: generate dockerfiles

4 years agodabuild: refactor volumes
Carlo Landmeter [Fri, 17 May 2019 08:00:13 +0000 (08:00 +0000)]
dabuild: refactor volumes

- printf -v is not posix
- check for abuild.conf instead of alpine-release
- check if distfiles is writable
- do not mount /var/cache/apk as this will break apkindex
- do not create volumes from makefile

4 years agodabuild: add support for multiple architectures
Carlo Landmeter [Fri, 17 May 2019 07:47:29 +0000 (07:47 +0000)]
dabuild: add support for multiple architectures

4 years agoadd drone image building support
Carlo Landmeter [Fri, 17 May 2019 06:49:12 +0000 (06:49 +0000)]
add drone image building support

5 years agodabuild: per @tcely, `mkdir -p` then test for success
Richard Mortier [Sun, 19 May 2019 20:25:42 +0000 (21:25 +0100)]
dabuild: per @tcely, `mkdir -p` then test for success

5 years agoentrypoint: do not install with abuild-keygen
tcely [Fri, 17 May 2019 23:45:10 +0000 (19:45 -0400)]
entrypoint: do not install with abuild-keygen

The copy with sudo is going to be done in any case.
Having abuild-keygen do this work also is not needed.

5 years agoentrypoint: ensure PACKAGER_PRIVKEY has content
tcely [Fri, 17 May 2019 23:37:24 +0000 (19:37 -0400)]
entrypoint: ensure PACKAGER_PRIVKEY has content

5 years ago!fixup entrypoint: copy public keys to /etc/apk/keys directory
tcely [Fri, 17 May 2019 19:32:45 +0000 (15:32 -0400)]
!fixup entrypoint: copy public keys to /etc/apk/keys directory

Oops. I forgot this runs as builder.

5 years agoentrypoint: copy public keys to /etc/apk/keys directory
tcely [Wed, 15 May 2019 13:48:01 +0000 (09:48 -0400)]
entrypoint: copy public keys to /etc/apk/keys directory

5 years agodabuild: segregate `packages/` by version on the host
Richard Mortier [Wed, 15 May 2019 09:09:55 +0000 (10:09 +0100)]
dabuild: segregate `packages/` by version on the host

5 years agomake: don't always push images after building them
Richard Mortier [Tue, 14 May 2019 23:39:33 +0000 (00:39 +0100)]
make: don't always push images after building them

5 years agoDockefile: /etc/apk/repositories
tcely [Sat, 11 May 2019 20:29:48 +0000 (16:29 -0400)]
Dockefile: /etc/apk/repositories

- only pull testing from edge
- correct edge tag first, once per line
- remove tag from locally built repos

5 years agodabuild: better handling of volumes when not built from source
Richard Mortier [Sat, 11 May 2019 17:22:58 +0000 (18:22 +0100)]
dabuild: better handling of volumes when not built from source

5 years agodocker: fix the `/etc/apk/repositories` properly
Richard Mortier [Fri, 10 May 2019 21:22:05 +0000 (22:22 +0100)]
docker: fix the `/etc/apk/repositories` properly

5 years agoreadme: fix some `make` targets
Richard Mortier [Fri, 10 May 2019 21:21:15 +0000 (22:21 +0100)]
readme: fix some `make` targets

5 years agodockerfile: attempt to clean up `/etc/apk/repositories`
Richard Mortier [Fri, 10 May 2019 14:57:35 +0000 (15:57 +0100)]
dockerfile: attempt to clean up `/etc/apk/repositories`

5 years agomake: allow `TAGS` to come in from environment
Richard Mortier [Fri, 10 May 2019 14:56:26 +0000 (15:56 +0100)]
make: allow `TAGS` to come in from environment

5 years agodabuild: because I like my lines to not be too long
Richard Mortier [Fri, 10 May 2019 14:56:12 +0000 (15:56 +0100)]
dabuild: because I like my lines to not be too long

5 years agodabuild: more care building volume args, mount extra dirs on alpine
Richard Mortier [Fri, 3 May 2019 14:17:15 +0000 (15:17 +0100)]
dabuild: more care building volume args, mount extra dirs on alpine

Closes: GH-6
5 years agodabuild: tweak naming of `DABUILD_PACKAGES`
Richard Mortier [Fri, 3 May 2019 14:16:59 +0000 (15:16 +0100)]
dabuild: tweak naming of `DABUILD_PACKAGES`

5 years agomake: set default target correctly, add license info
Richard Mortier [Fri, 3 May 2019 14:16:11 +0000 (15:16 +0100)]
make: set default target correctly, add license info

5 years agodabuild: fix script to handle `DABUILD_PACKAGES` correctly
Richard Mortier [Fri, 3 May 2019 13:41:09 +0000 (14:41 +0100)]
dabuild: fix script to handle `DABUILD_PACKAGES` correctly

5 years agomake: push built images for others to use
Richard Mortier [Fri, 3 May 2019 13:40:57 +0000 (14:40 +0100)]
make: push built images for others to use

5 years agodocker: remove spurious `\`
Richard Mortier [Fri, 3 May 2019 12:59:03 +0000 (13:59 +0100)]
docker: remove spurious `\`

5 years agoMerge pull request #5 from OTLabs/repos
Richard Mortier [Fri, 3 May 2019 12:57:05 +0000 (13:57 +0100)]
Merge pull request #5 from OTLabs/repos

Add support for setup-apkrepos

5 years agodocker: ignore more irrelevant files
Richard Mortier [Wed, 1 May 2019 09:55:31 +0000 (10:55 +0100)]
docker: ignore more irrelevant files

5 years agomake: decouple building images from script
Richard Mortier [Wed, 1 May 2019 09:48:49 +0000 (10:48 +0100)]
make: decouple building images from script

5 years agodabuild: provide for user-specified `.../packages` directory
Richard Mortier [Wed, 1 May 2019 09:39:08 +0000 (10:39 +0100)]
dabuild: provide for user-specified `.../packages` directory

This page took 0.082318 seconds and 4 git commands to generate.