feat: manage Dokku system dependencies in a single file

This will allow us to more quickly update a dependency by adding support so that downstream repos can auto-push updates to the main repo when there is a release.
This commit is contained in:
Jose Diaz-Gonzalez
2023-10-08 22:17:04 -04:00
parent aaf4c1d7d1
commit 934a6b5cd5
9 changed files with 170 additions and 36 deletions

View File

@@ -11,5 +11,7 @@ tests
!docs/_build/requirements.txt
!tests/dhparam.pem
!contrib/bash-completion
!contrib/dependencies.json
!contrib/docker
!contrib/update-deb-dependencies
vendor

View File

@@ -2,23 +2,14 @@ DOKKU_VERSION ?= master
TARGETARCH ?= amd64
DOCKER_IMAGE_LABELER_VERSION ?= 0.6.1
DOCKER_CONTAINER_HEALTHCHECKER_VERSION ?= 0.6.4
HEROKUISH_VERSION ?= 0.7.1
LAMBDA_BUILDER_VERSION ?= 0.5.0
NETRC_VERSION ?= 0.7.1
PLUGN_VERSION ?= 0.12.0
PROCFILE_VERSION ?= 0.16.0
SIGIL_VERSION ?= 0.10.1
SSHCOMMAND_VERSION ?= 0.17.1
DOCKER_IMAGE_LABELER_URL ?= https://github.com/dokku/docker-image-labeler/releases/download/v${DOCKER_IMAGE_LABELER_VERSION}/docker-image-labeler_${DOCKER_IMAGE_LABELER_VERSION}_linux_${TARGETARCH}.tgz
DOCKER_CONTAINER_HEALTHCHECKER_URL ?= https://github.com/dokku/docker-container-healthchecker/releases/download/v${DOCKER_CONTAINER_HEALTHCHECKER_VERSION}/docker-container-healthchecker_${DOCKER_CONTAINER_HEALTHCHECKER_VERSION}_linux_${TARGETARCH}.tgz
LAMBDA_BUILDER_URL ?= https://github.com/dokku/lambda-builder/releases/download/v${LAMBDA_BUILDER_VERSION}/lambda-builder_${LAMBDA_BUILDER_VERSION}_linux_${TARGETARCH}.tgz
NETRC_URL ?= https://github.com/dokku/netrc/releases/download/v${NETRC_VERSION}/netrc_${NETRC_VERSION}_linux_${TARGETARCH}.tgz
PLUGN_URL ?= https://github.com/dokku/plugn/releases/download/v${PLUGN_VERSION}/plugn_${PLUGN_VERSION}_linux_${TARGETARCH}.tgz
PROCFILE_UTIL_URL ?= https://github.com/josegonzalez/go-procfile-util/releases/download/v${PROCFILE_VERSION}/procfile-util_${PROCFILE_VERSION}_linux_${TARGETARCH}.tgz
SIGIL_URL ?= https://github.com/gliderlabs/sigil/releases/download/v${SIGIL_VERSION}/gliderlabs-sigil_${SIGIL_VERSION}_linux_${TARGETARCH}.tgz
SSHCOMMAND_URL ?= https://github.com/dokku/sshcommand/releases/download/v${SSHCOMMAND_VERSION}/sshcommand_${SSHCOMMAND_VERSION}_linux_x86_64.tgz
DOCKER_IMAGE_LABELER_URL ?= $(shell jq -r --arg name docker-image-labeler --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
DOCKER_CONTAINER_HEALTHCHECKER_URL ?= $(shell jq -r --arg name docker-container-healthchecker --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
LAMBDA_BUILDER_URL ?= $(shell jq -r --arg name lambda-builder --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
NETRC_URL ?= $(shell jq -r --arg name netrc --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
PLUGN_URL ?= $(shell jq -r --arg name plugn --arg arch $(TARGETARCH) '.predependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
PROCFILE_UTIL_URL ?= $(shell jq -r --arg name procfile-util --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
SIGIL_URL ?= $(shell jq -r --arg name gliderlabs-sigil --arg arch $(TARGETARCH) '.predependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
SSHCOMMAND_URL ?= $(shell jq -r --arg name sshcommand --arg arch $(TARGETARCH) '.dependencies[] | select(.name == $$name) | .urls[$$arch]' contrib/dependencies.json)
STACK_URL ?= https://github.com/gliderlabs/herokuish.git
PREBUILT_STACK_URL ?= gliderlabs/herokuish:latest-22
DOKKU_LIB_ROOT ?= /var/lib/dokku

View File

@@ -2,7 +2,7 @@ FROM ubuntu:20.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -qq && apt-get -qq -y --no-install-recommends install ca-certificates curl gcc git build-essential wget ruby-dev lintian rpm help2man man-db sudo
RUN apt-get update -qq && apt-get -qq -y --no-install-recommends install ca-certificates curl gcc git jq build-essential wget ruby-dev lintian python3 rpm help2man man-db sudo
RUN curl -sL -o /usr/local/share/ca-certificates/GlobalSignRootCA_R3.crt https://raw.githubusercontent.com/rubygems/rubygems/master/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem
RUN update-ca-certificates
RUN command -v fpm || gem install fpm

View File

@@ -1,19 +1,20 @@
FROM dokku/build-base:0.0.1 AS builder
FROM dokku/build-base:0.1.2 AS builder
ENV DEBIAN_FRONTEND=noninteractive
ARG GOLANG_VERSION
RUN wget -qO /tmp/go${GOLANG_VERSION}.linux.tar.gz "https://storage.googleapis.com/golang/go${GOLANG_VERSION}.linux-$(dpkg --print-architecture).tar.gz" \
&& tar -C /usr/local -xzf /tmp/go${GOLANG_VERSION}.linux.tar.gz \
&& cp /usr/local/go/bin/* /usr/local/bin
ARG WORKDIR=/go/src/github.com/dokku/dokku
WORKDIR ${WORKDIR}
RUN wget -qO /tmp/go${GOLANG_VERSION}.linux.tar.gz "https://storage.googleapis.com/golang/go${GOLANG_VERSION}.linux-$(dpkg --print-architecture).tar.gz" \
&& tar -C /usr/local -xzf /tmp/go${GOLANG_VERSION}.linux.tar.gz \
&& cp /usr/local/go/bin/* /usr/local/bin \
&& mkdir -p ${WORKDIR}/contrib
COPY Makefile ${WORKDIR}/
COPY *.mk ${WORKDIR}/
COPY contrib/dependencies.json ${WORKDIR}/contrib/dependencies.json
RUN make deb-setup sshcommand plugn

107
contrib/dependencies.json Normal file
View File

@@ -0,0 +1,107 @@
{
"dependencies": [
{
"name": "docker-image-labeler",
"version": "0.6.1",
"urls": {
"amd64": "https://github.com/dokku/docker-image-labeler/releases/download/v0.6.1/docker-image-labeler_0.6.1_linux_amd64.tgz",
"arm64": "https://github.com/dokku/docker-image-labeler/releases/download/v0.6.1/docker-image-labeler_0.6.1_linux_arm64.tgz",
"arm": "https://github.com/dokku/docker-image-labeler/releases/download/v0.6.1/docker-image-labeler_0.6.1_linux_armhf.tgz"
}
},
{
"name": "docker-container-healthchecker",
"version": "0.6.4",
"urls": {
"amd64": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.6.4/docker-container-healthchecker_0.6.4_linux_amd64.tgz",
"arm4": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.6.4/docker-container-healthchecker_0.6.4_linux_arm64.tgz",
"arm": "https://github.com/dokku/docker-container-healthchecker/releases/download/v0.6.4/docker-container-healthchecker_0.6.4_linux_armhf.tgz"
}
},
{
"name": "lambda-builder",
"version": "0.5.0",
"urls": {
"amd64": "https://github.com/dokku/lambda-builder/releases/download/v0.5.0/lambda-builder_0.5.0_linux_amd64.tgz",
"arm64": "https://github.com/dokku/lambda-builder/releases/download/v0.5.0/lambda-builder_0.5.0_linux_arm64.tgz",
"arm": "https://github.com/dokku/lambda-builder/releases/download/v0.5.0/lambda-builder_0.5.0_linux_armhf.tgz"
}
},
{
"name": "netrc",
"version": "0.7.1",
"urls": {
"amd64": "https://github.com/dokku/netrc/releases/download/v0.7.1/netrc_0.7.1_linux_amd64.tgz",
"arm64": "https://github.com/dokku/netrc/releases/download/v0.7.1/netrc_0.7.1_linux_arm64.tgz",
"arm": "https://github.com/dokku/netrc/releases/download/v0.7.1/netrc_0.7.1_linux_armhf.tgz"
}
},
{
"name": "procfile-util",
"version": "0.16.0",
"urls": {
"amd64": "https://github.com/dokku/procfile-util/releases/download/v0.16.0/procfile-util_0.16.0_linux_amd64.tgz",
"arm64": "https://github.com/dokku/procfile-util/releases/download/v0.16.0/procfile-util_0.16.0_linux_arm64.tgz",
"arm": "https://github.com/dokku/procfile-util/releases/download/v0.16.0/procfile-util_0.16.0_linux_armhf.tgz"
}
},
{
"name": "sshcommand",
"version": "0.17.1",
"urls": {
"amd64": "https://github.com/dokku/sshcommand/releases/download/v0.17.1/sshcommand_0.17.1_linux_x86_64.tgz",
"arm64": "https://github.com/dokku/sshcommand/releases/download/v0.17.1/sshcommand_0.17.1_linux_x86_64.tgz",
"arm": "https://github.com/dokku/sshcommand/releases/download/v0.17.1/sshcommand_0.17.1_linux_x86_64.tgz"
}
}
],
"predependencies": [
{
"name": "gliderlabs-sigil",
"version": "0.10.1",
"urls": {
"amd64": "https://github.com/gliderlabs/sigil/releases/download/v0.10.1/gliderlabs-sigil_0.10.1_linux_amd64.tgz",
"arm64": "https://github.com/gliderlabs/sigil/releases/download/v0.10.1/gliderlabs-sigil_0.10.1_linux_arm64.tgz",
"arm": "https://github.com/gliderlabs/sigil/releases/download/v0.10.1/gliderlabs-sigil_0.10.1_linux_armhf.tgz"
}
},
{
"name": "plugn",
"version": "0.12.0",
"urls": {
"amd64": "https://github.com/dokku/plugn/releases/download/v0.12.0/plugn_0.12.0_linux_amd64.tgz",
"arm64": "https://github.com/dokku/plugn/releases/download/v0.12.0/plugn_0.12.0_linux_arm64.tgz",
"arm": "https://github.com/dokku/plugn/releases/download/v0.12.0/plugn_0.12.0_linux_armhf.tgz"
}
}
],
"recommendations": [
{
"name": "dokku-event-listener",
"version": "0.15.0",
"urls": {
"amd64": "https://github.com/dokku/dokku-event-listener/releases/download/v0.15.0/dokku-event-listener_0.15.0_linux_amd64.tgz",
"arm64": "https://github.com/dokku/dokku-event-listener/releases/download/v0.15.0/dokku-event-listener_0.15.0_linux_arm64.tgz",
"arm": "https://github.com/dokku/dokku-event-listener/releases/download/v0.15.0/dokku-event-listener_0.15.0_linux_armhf.tgz"
}
},
{
"name": "dokku-update",
"version": "0.7.2",
"urls": {
"amd64": "https://github.com/dokku/dokku-update/releases/download/v0.7.2/dokku-update_0.7.2_linux_x86_64.tgz",
"arm64": "https://github.com/dokku/dokku-update/releases/download/v0.7.2/dokku-update_0.7.2_linux_x86_64.tgz",
"arm": "https://github.com/dokku/dokku-update/releases/download/v0.7.2/dokku-update_0.7.2_linux_x86_64.tgz"
}
},
{
"name": "herokuish",
"version": "0.7.1",
"urls": {
"amd64": "https://github.com/gliderlabs/herokuish/releases/download/v0.7.1/herokuish_0.7.1_linux_x86_64.tgz",
"arm64": "https://github.com/gliderlabs/herokuish/releases/download/v0.7.1/herokuish_0.7.1_linux_x86_64.tgz",
"arm": "https://github.com/gliderlabs/herokuish/releases/download/v0.7.1/herokuish_0.7.1_linux_x86_64.tgz"
}
}
]
}

32
contrib/update-deb-dependencies Executable file
View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python3
import json
def main():
"""
updates the control file with the tested debian dependencies
"""
deps = {}
with open("contrib/dependencies.json", encoding="utf-8") as handle:
deps = json.load(handle)
control_lines = []
with open("debian/control", encoding="utf-8") as handle:
control_lines = [line for line in handle.readlines()]
for key in ["dependencies", "predependencies", "recommendations"]:
for dependency in deps[key]:
name = dependency["name"]
version = dependency["version"]
for i, line in enumerate(control_lines):
if name in line:
control_lines[i] = control_lines[i].replace(
name, f"{name} (>= {version})"
)
with open("debian/control", mode="w", encoding="utf-8") as handle:
handle.writelines(control_lines)
if __name__ == "__main__":
main()

1
deb.mk
View File

@@ -43,6 +43,7 @@ ifneq (,$(findstring false,$(IS_RELEASE)))
sed -i.bak -e "s/^/`date +%s`:/" /tmp/build-dokku/var/lib/dokku/STABLE_VERSION && rm /tmp/build-dokku/var/lib/dokku/STABLE_VERSION.bak
endif
contrib/update-deb-dependencies
cp -r debian /tmp/build-dokku/DEBIAN
sed -i.bak "s/^Architecture: .*/Architecture: $(DOKKU_ARCHITECTURE)/g" /tmp/build-dokku/DEBIAN/control && rm /tmp/build-dokku/DEBIAN/control.bak
rm -f /tmp/build-dokku/DEBIAN/lintian-overrides

6
debian/control vendored
View File

@@ -3,9 +3,9 @@ Version: 0.31.4
Section: web
Priority: optional
Architecture: amd64
Depends: apache2-utils, locales, git, cpio, curl, man-db, netcat, sshcommand (>= 0.17.1), docker-engine-cs (>= 17.05.0) | docker-engine (>= 17.05.0) | docker-io (>= 17.05.0) | docker.io (>= 17.05.0) | docker-ce (>= 17.05.0) | docker-ee (>= 17.05.0) | moby-engine, docker-compose-plugin | moby-compose, docker-buildx-plugin | moby-buildx, docker-container-healthchecker (>= 0.6.4), docker-image-labeler (>= 0.6.1), lambda-builder (>= 0.5.0), net-tools, netrc (>= 0.7.1), software-properties-common, parallel, procfile-util (>= 0.16.0), python-software-properties | python3-software-properties, rsync, rsyslog, dos2unix, jq, unzip
Recommends: herokuish (>= 0.7.1), bash-completion, dokku-update, dokku-event-listener
Pre-Depends: gliderlabs-sigil (>= 0.10.1), nginx (>= 1.8.0) | openresty, dnsutils, cgroupfs-mount | cgroup-lite, plugn (>= 0.3.0), sudo, python3, debconf
Depends: apache2-utils, locales, git, cpio, curl, man-db, netcat, sshcommand, docker-engine-cs (>= 17.05.0) | docker-engine (>= 17.05.0) | docker-io (>= 17.05.0) | docker.io (>= 17.05.0) | docker-ce (>= 17.05.0) | docker-ee (>= 17.05.0) | moby-engine, docker-compose-plugin | moby-compose, docker-buildx-plugin | moby-buildx, docker-container-healthchecker, docker-image-labeler, lambda-builder, net-tools, netrc, software-properties-common, parallel, procfile-util, python-software-properties | python3-software-properties, rsync, rsyslog, dos2unix, jq, unzip
Recommends: herokuish, bash-completion, dokku-update, dokku-event-listener
Pre-Depends: gliderlabs-sigil, nginx (>= 1.8.0) | openresty, dnsutils, cgroupfs-mount | cgroup-lite, plugn, sudo, python3, debconf
Maintainer: Jose Diaz-Gonzalez <dokku@josediazgonzalez.com>
Description: Docker-powered PaaS that helps build and manage the lifecycle of applications
Dokku is an extensible, open source Platform as a Service

View File

@@ -8,55 +8,55 @@ install_dependencies() {
mkdir -p "$ROOT_DIR/build/"
DOCKER_IMAGE_LABELER_VERSION=$(grep DOCKER_IMAGE_LABELER_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
DOCKER_IMAGE_LABELER_VERSION=$(jq -r --arg name docker-image-labeler '.dependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
DOCKER_IMAGE_LABELER_PACKAGE_NAME="docker-image-labeler_${DOCKER_IMAGE_LABELER_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${DOCKER_IMAGE_LABELER_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/docker-image-labeler_${DOCKER_IMAGE_LABELER_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${DOCKER_IMAGE_LABELER_PACKAGE_NAME}"
fi
DOCKER_CONTAINER_HEALTHCHECKER_VERSION=$(grep DOCKER_CONTAINER_HEALTHCHECKER_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
DOCKER_CONTAINER_HEALTHCHECKER_VERSION=$(jq -r --arg name docker-container-healthchecker '.dependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
DOCKER_CONTAINER_HEALTHCHECKER_PACKAGE_NAME="docker-container-healthchecker_${DOCKER_CONTAINER_HEALTHCHECKER_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${DOCKER_CONTAINER_HEALTHCHECKER_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/docker-container-healthchecker_${DOCKER_CONTAINER_HEALTHCHECKER_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${DOCKER_CONTAINER_HEALTHCHECKER_PACKAGE_NAME}"
fi
HEROKUISH_VERSION=$(grep HEROKUISH_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
HEROKUISH_VERSION=$(jq -r --arg name herokuish '.recommendations[] | select(.name == $name) | .version' contrib/dependencies.json)
HEROKUISH_PACKAGE_NAME="herokuish_${HEROKUISH_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${HEROKUISH_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/herokuish_${HEROKUISH_VERSION}_all.deb/download.deb" -o "$ROOT_DIR/build/${HEROKUISH_PACKAGE_NAME}"
fi
LAMBDA_BUILDER_VERSION=$(grep LAMBDA_BUILDER_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
LAMBDA_BUILDER_VERSION=$(jq -r --arg name lambda-builder '.dependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
LAMBDA_BUILDER_PACKAGE_NAME="lambda-builder_${LAMBDA_BUILDER_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${LAMBDA_BUILDER_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/lambda-builder_${LAMBDA_BUILDER_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${LAMBDA_BUILDER_PACKAGE_NAME}"
fi
NETRC_VERSION=$(grep NETRC_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
NETRC_VERSION=$(jq -r --arg name netrc '.dependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
NETRC_PACKAGE_NAME="netrc_${NETRC_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${NETRC_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/netrc_${NETRC_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${NETRC_PACKAGE_NAME}"
fi
PLUGN_VERSION=$(grep PLUGN_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
PLUGN_VERSION=$(jq -r --arg name plugn '.predependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
PLUGN_PACKAGE_NAME="plugn_${PLUGN_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${PLUGN_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/plugn_${PLUGN_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${PLUGN_PACKAGE_NAME}"
fi
SSHCOMMAND_VERSION=$(grep SSHCOMMAND_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
SSHCOMMAND_VERSION=$(jq -r --arg name sshcommand '.dependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
SSHCOMMAND_PACKAGE_NAME="sshcommand_${SSHCOMMAND_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${SSHCOMMAND_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/sshcommand_${SSHCOMMAND_VERSION}_all.deb/download.deb" -o "$ROOT_DIR/build/${SSHCOMMAND_PACKAGE_NAME}"
fi
SIGIL_VERSION=$(grep SIGIL_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
SIGIL_VERSION=$(jq -r --arg name gliderlabs-sigil '.predependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
SIGIL_PACKAGE_NAME="gliderlabs-sigil_${SIGIL_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${SIGIL_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/gliderlabs-sigil_${SIGIL_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${SIGIL_PACKAGE_NAME}"
fi
PROCFILE_VERSION=$(grep PROCFILE_VERSION "${ROOT_DIR}/Makefile" | head -n1 | cut -d' ' -f3)
PROCFILE_VERSION=$(jq -r --arg name procfile-util '.dependencies[] | select(.name == $name) | .version' contrib/dependencies.json)
PROCFILE_UTIL_PACKAGE_NAME="procfile-util_${PROCFILE_VERSION}_amd64.deb"
if [[ ! -f "$ROOT_DIR/build/${PROCFILE_UTIL_PACKAGE_NAME}" ]]; then
curl -L "https://packagecloud.io/dokku/dokku/packages/ubuntu/focal/procfile-util_${PROCFILE_VERSION}_amd64.deb/download.deb" -o "$ROOT_DIR/build/${PROCFILE_UTIL_PACKAGE_NAME}"