diff --git a/deb/build-deb b/deb/build-deb
index a67475a097..cf259a7859 100755
--- a/deb/build-deb
+++ b/deb/build-deb
@@ -43,8 +43,40 @@ debSource="$(awk -F ': ' '$1 == "Source" { print $2; exit }' debian/control)"
debMaintainer="$(awk -F ': ' '$1 == "Maintainer" { print $2; exit }' debian/control)"
debDate="$(date --rfc-2822)"
+versionID="$(. /etc/os-release && echo "$VERSION_ID")"
+
+# Include an extra `.0` in the version, in case we ever would have to re-build an
+# already published release with a packaging-only change.
+pkgRevision=0
+
+# Generate changelog. The version/name of the generated packages are based on this.
+#
+# Resulting packages are formatted as;
+#
+# - name of the package (e.g., "docker-ce")
+# - version (e.g., "22.10.6~beta.0")
+# - "-0" (mostly "best practice", and allows updating for specific situations)
+# - distro (e.g., "ubuntu")
+# - VERSION_ID (e.g. "22.04" or "11") this must be "sortable" to make sure that
+# packages are upgraded when upgrading to a newer distro version ("codename"
+# cannot be used for this, as they're not sorted)
+# - pkgRevision (usually "0", see above)
+# - SUITE ("codename"), e.g. "jammy" or "bullseye". This is mostly for convenience,
+# because some places refer to distro versions by codename, others by version.
+# we prefix the codename with a tilde (~), which effectively excludes it from
+# version comparison.
+#
+# Note that while the `${EPOCH}${EPOCH_SEP}` is part of the version, it is not
+# included in the package's *filename*. (And if you're wondering: we needed the
+# EPOCH because of our use of CalVer, which made version comparing not work in
+# some cases).
+#
+# Examples:
+#
+# docker-ce_22.10.6~beta.0-0~debian.11.0~bullseye_amd64.deb
+# docker-ce_22.10.6~beta.0-0~ubuntu.22.04.0~jammy_amd64.deb
cat > "debian/changelog" <<-EOF
-$debSource (${EPOCH}${EPOCH_SEP}${DEB_VERSION}-0~${DISTRO}-${SUITE}) $SUITE; urgency=low
+$debSource (${EPOCH}${EPOCH_SEP}${DEB_VERSION}-0~${DISTRO}.${versionID}.${pkgRevision}~${SUITE}) $SUITE; urgency=low
* Version: $VERSION
-- $debMaintainer $debDate
EOF
diff --git a/deb/gen-deb-ver b/deb/gen-deb-ver
index 27728b37d0..bb5aaf4717 100755
--- a/deb/gen-deb-ver
+++ b/deb/gen-deb-ver
@@ -13,48 +13,26 @@ GIT_COMMAND="git -C $REPO_DIR"
origVersion="$VERSION"
debVersion="${VERSION#v}"
-gen_deb_version() {
- # Adds an increment to the deb version to get proper order
- # 18.01.0-tp1 -> 18.01.0-0.1-tp1
- # 18.01.0-beta1 -> 18.01.0-1.1-beta1
- # 18.01.0-rc1 -> 18.01.0-2.1-rc1
- # 18.01.0 -> 18.01.0-3
- fullVersion="$1"
- pattern="$2"
- increment="$3"
- testVersion="${fullVersion#*-$pattern}"
- baseVersion="${fullVersion%-"$pattern"*}"
- echo "$baseVersion-$increment.${testVersion##.}.$pattern$testVersion"
-}
+# deb packages require a tilde (~) instead of a hyphen (-) as separator between
+# the version # and pre-release suffixes, otherwise pre-releases are sorted AFTER
+# non-pre-release versions, which would prevent users from updating from a pre-
+# release version to the "ga" version.
+#
+# For details, see this thread on the Debian mailing list:
+# https://lists.debian.org/debian-policy/1998/06/msg00099.html
+#
+# The code below replaces hyphens with tildes. Note that an intermediate $tilde
+# variable is needed to make this work on all versions of Bash. In some versions
+# of Bash, the tilde would be substituted with $HOME (even when escaped (\~) or
+# quoted ('~').
+tilde='~'
+debVersion="${debVersion//-/$tilde}"
-case "$debVersion" in
- *-dev)
- ;;
- *-tp[.0-9]*)
- debVersion="$(gen_deb_version "$debVersion" tp 0)"
- ;;
- *-beta[.0-9]*)
- debVersion="$(gen_deb_version "$debVersion" beta 1)"
- ;;
- *-rc[.0-9]*)
- debVersion="$(gen_deb_version "$debVersion" rc 2)"
- ;;
- *)
- debVersion="$debVersion-3"
- ;;
-esac
-
-tilde='~' # ouch Bash 4.2 vs 4.3, you keel me
-debVersion="${debVersion//-/$tilde}" # using \~ or '~' here works in 4.3, but not 4.2; just ~ causes $HOME to be inserted, hence the $tilde
-# if we have a "-dev" suffix or have change in Git, let's make this package version more complex so it works better
-if [[ "$VERSION" == *-dev ]]; then
+# if we have a "-dev" suffix or have change in Git, this is a nightly build, and
+# we'll create a pseudo version based on commit-date and -sha.
+if [[ "$VERSION" == *-dev ]] || [ -n "$($GIT_COMMAND status --porcelain)" ]; then
export TZ=UTC
- DATE_COMMAND="date"
- if [[ $(uname) == "Darwin" ]]; then
- DATE_COMMAND="docker run --rm alpine date"
- fi
-
# based on golang's pseudo-version: https://groups.google.com/forum/#!topic/golang-dev/a5PqQuBljF4
#
# using a "pseudo-version" of the form v0.0.0-yyyymmddhhmmss-abcdefabcdef,
@@ -65,11 +43,20 @@ if [[ "$VERSION" == *-dev ]]; then
# as a pre-release before version v0.0.0, so that the go command prefers any
# tagged release over any pseudo-version.
gitUnix="$($GIT_COMMAND log -1 --pretty='%ct')"
- gitDate="$($DATE_COMMAND --utc --date "@$gitUnix" +'%Y%m%d%H%M%S')"
+
+ if [ "$(uname)" = "Darwin" ]; then
+ # Using BSD date (macOS), which doesn't support the --date option
+ # date -jf "" "" +"