Skip to content

Commit 339a389

Browse files
authored
[scripts]: add update-container script for upgrade/downgrades (#1173)
- Closes #1171
1 parent 899081d commit 339a389

File tree

3 files changed

+168
-5
lines changed

3 files changed

+168
-5
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ $(STAGING_DIR):
111111
@install "$(BUILD_BIN_DIR)/container-core-images" "$(join $(STAGING_DIR), libexec/container/plugins/container-core-images/bin/container-core-images)"
112112
@install config/container-core-images-config.json "$(join $(STAGING_DIR), libexec/container/plugins/container-core-images/config.json)"
113113

114+
@echo Install update script
115+
@install scripts/update-container.sh "$(join $(STAGING_DIR), bin/update-container.sh)"
114116
@echo Install uninstaller script
115117
@install scripts/uninstall-container.sh "$(join $(STAGING_DIR), bin/uninstall-container.sh)"
116118

README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,40 @@ You need a Mac with Apple silicon to run `container`. To build it, see the [BUIL
1616

1717
`container` is supported on macOS 26, since it takes advantage of new features and enhancements to virtualization and networking in this release. We do not support older versions of macOS and the `container` maintainers typically will not address issues that cannot be reproduced on the macOS 26.
1818

19-
### Install or upgrade
19+
### Initial install
2020

21-
If you're upgrading, first stop and uninstall your existing `container` (the `-k` flag keeps your user data, while `-d` removes it):
21+
Download the latest signed installer package for `container` from the [GitHub release page](https://github.com/apple/container/releases).
22+
23+
To install the tool, double-click the package file and follow the instructions. Enter your administrator password when prompted, to give the installer permission to place the installed files under `/usr/local`.
24+
25+
Start the system service with:
26+
27+
```bash
28+
container system start
29+
```
30+
31+
### Upgrade or downgrade
32+
33+
For both upgrading and downgrading, you can manually download and install the signed installer package by following the steps from [initial install](#initial-install) or use the `update-container.sh` script (installed to `/usr/local/bin`).
34+
35+
If you're upgrading and downgrading, you must stop your existing `container`:
2236

2337
```bash
2438
container system stop
25-
/usr/local/bin/uninstall-container.sh -k
2639
```
2740

28-
Download the latest signed installer package for `container` from the [GitHub release page](https://github.com/apple/container/releases).
41+
For upgrading to the latest release version, simply run the command below:
2942

30-
To install the tool, double-click the package file and follow the instructions. Enter your administrator password when prompted, to give the installer permission to place the installed files under `/usr/local`.
43+
```bash
44+
/usr/local/bin/update-container.sh
45+
```
46+
47+
If you're downgrading, you must uninstall your existing `container` (the `-k` flag keeps your user data, while `-d` removes it):
48+
49+
```bash
50+
/usr/local/bin/uninstall-container.sh -k
51+
/usr/local/bin/update-container.sh -v 0.3.0
52+
```
3153

3254
Start the system service with:
3355

scripts/update-container.sh

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
#!/bin/bash
2+
# Copyright © 2026 Apple Inc. and the container project authors.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# https://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
set -uo pipefail
17+
18+
INSTALL_DIR="/usr/local"
19+
OPTS=0
20+
LATEST=false
21+
VERSION=
22+
TMP_DIR=
23+
24+
# Release Info
25+
RELEASE_URL=
26+
RELEASE_JSON=
27+
RELEASE_VERSION=
28+
29+
# Package Info
30+
PKG_URL=
31+
PKG_FILE=
32+
PRIMARY_PKG=
33+
FALLBACK_PKG=
34+
35+
check_installed_version() {
36+
local target_version="$1"
37+
if command -v container &>/dev/null; then
38+
local installed_version
39+
installed_version=$(container --version | awk '{print $4}')
40+
installed_version=${installed_version%\)}
41+
if [[ "$installed_version" == "$target_version" ]]; then
42+
return 0
43+
fi
44+
fi
45+
return 1
46+
}
47+
48+
usage() {
49+
echo "Usage: $0 {-v <version>}"
50+
echo "Update container"
51+
echo
52+
echo "Options:"
53+
echo "v <version> Install a specific release version"
54+
echo "No argument Defaults to latest release version"
55+
exit 1
56+
}
57+
58+
while getopts ":v:" arg; do
59+
case "$arg" in
60+
v)
61+
VERSION="$OPTARG"
62+
((OPTS+=1))
63+
;;
64+
*)
65+
echo "Invalid option: -${OPTARG}"
66+
usage
67+
;;
68+
esac
69+
done
70+
71+
# Default to install the latest release version
72+
if [ "$OPTS" -eq 0 ]; then
73+
LATEST=true
74+
fi
75+
76+
# Check if container is still running
77+
CONTAINER_RUNNING=$(launchctl list | grep -e 'com\.apple\.container\W')
78+
if [ -n "$CONTAINER_RUNNING" ]; then
79+
echo '`container` is still running. Please ensure the service is stopped by running `container system stop`'
80+
exit 1
81+
fi
82+
83+
if [ "$EUID" -ne 0 ]; then
84+
echo "This script requires admin privileges to update files under $INSTALL_DIR"
85+
fi
86+
87+
# Temporary directory creation for install/download
88+
TMP_DIR=$(mktemp -d)
89+
trap 'rm -rf "$TMP_DIR"' EXIT
90+
error() { echo "Error: $*" >&2; exit 1; }
91+
92+
# Determine the release URL and version
93+
if [[ "$LATEST" == true ]]; then
94+
RELEASE_URL="https://api.github.com/repos/apple/container/releases/latest"
95+
RELEASE_VERSION=$(curl -fsSL "$RELEASE_URL" | jq -r '.tag_name')
96+
if check_installed_version "$RELEASE_VERSION"; then
97+
echo "Container is already on latest version $RELEASE_VERSION"
98+
exit 0
99+
else
100+
echo "Updating to latest version $RELEASE_VERSION"
101+
fi
102+
elif [[ -n "$VERSION" ]]; then
103+
RELEASE_URL="https://api.github.com/repos/apple/container/releases/tags/$VERSION"
104+
RELEASE_VERSION="$VERSION"
105+
if check_installed_version "$RELEASE_VERSION"; then
106+
echo "Container is already on version $RELEASE_VERSION"
107+
exit 0
108+
else
109+
echo "Updating to release version $RELEASE_VERSION"
110+
fi
111+
fi
112+
113+
# Fetch the release json
114+
RELEASE_JSON=$(curl -fsSL "$RELEASE_URL") || {
115+
error $([[ "$LATEST" == true ]] && echo "Failed fetching latest release" || echo "Release '$VERSION' not found")
116+
}
117+
118+
# Possible package names
119+
PRIMARY_PKG="container-installer-signed.pkg"
120+
FALLBACK_PKG="container-$RELEASE_VERSION-installer-signed.pkg"
121+
122+
# Find the package URL
123+
PKG_URL=$(echo "$RELEASE_JSON" | jq -r \
124+
--arg primary "$PRIMARY_PKG" \
125+
--arg fallback "$FALLBACK_PKG" \
126+
'.assets[] | select(.name == $primary or .name == $fallback) | .browser_download_url' | head -n1)
127+
[[ -n "$PKG_URL" ]] || error "Neither $PRIMARY_PKG nor $FALLBACK_PKG found"
128+
129+
PKG_FILE="$TMP_DIR/$(basename "$PKG_URL")"
130+
131+
echo "Downloading package from: $PKG_URL..."
132+
curl -fSL "$PKG_URL" -o "$PKG_FILE"
133+
[[ -s "$PKG_FILE" ]] || error "Downloaded package is empty"
134+
135+
echo "Installing package to $INSTALL_DIR..."
136+
sudo installer -pkg "$PKG_FILE" -target / >/dev/null 2>&1 || error "Installer failed"
137+
138+
echo "Installed successfully"
139+
container --version || error "'container' command not found"

0 commit comments

Comments
 (0)