mirror of
https://github.com/NVIDIA/OpenShell.git
synced 2026-10-02 07:34:45 +08:00
(feat) early snap support (#1238)
This commit is contained in:
@@ -212,5 +212,9 @@ rfc.md
|
||||
*.tar.xz
|
||||
*.tar.bz2
|
||||
|
||||
# Snap build artifacts
|
||||
*.snap
|
||||
*.comp
|
||||
|
||||
# Markdown/mermaid lint tooling deps
|
||||
scripts/lint-mermaid/node_modules/
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
# Building a snap package
|
||||
|
||||
OpenShell snap packages are defined by the root `snapcraft.yaml` and built with
|
||||
Snapcraft from source.
|
||||
|
||||
The helper task under `tasks/` still stages the same payload from pre-built
|
||||
binaries when you want to inspect the snap root or produce local artifacts.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Linux on `amd64` or `arm64`
|
||||
- `snap` from `snapd`
|
||||
- `snapcraft`
|
||||
- Docker from the Docker snap (`sudo snap install docker`)
|
||||
|
||||
## Build with Snapcraft
|
||||
|
||||
Build the snap from source with the root manifest:
|
||||
|
||||
```shell
|
||||
snapcraft pack
|
||||
```
|
||||
|
||||
The manifest builds the Rust binaries inside Snapcraft, installs the CLI,
|
||||
gateway, and sandbox supervisor into the snap, and keeps the same runtime
|
||||
environment as the current deployment logic.
|
||||
|
||||
## Staged helper flow
|
||||
|
||||
The helper task under `tasks/` still stages the same payload from pre-built
|
||||
binaries when you want to inspect the snap root or produce local artifacts.
|
||||
|
||||
For that flow, install `mise` and build:
|
||||
|
||||
- `openshell`
|
||||
- `openshell-gateway`
|
||||
- `openshell-sandbox`
|
||||
|
||||
## Build helper binaries
|
||||
|
||||
Build the release binaries used by the staged helper flow:
|
||||
|
||||
```shell
|
||||
mise run build:rust:snap
|
||||
```
|
||||
|
||||
This convenience target builds the CLI with `bundled-z3`, the gateway, and
|
||||
`openshell-sandbox` for the Docker driver to bind-mount into sandbox containers.
|
||||
|
||||
## Pack the snap
|
||||
|
||||
Run the packaging hook through mise:
|
||||
|
||||
```shell
|
||||
VERSION="$(uv run python tasks/scripts/release.py get-version --snap)"
|
||||
|
||||
OPENSHELL_CLI_BINARY="$PWD/target/release/openshell" \
|
||||
OPENSHELL_GATEWAY_BINARY="$PWD/target/release/openshell-gateway" \
|
||||
OPENSHELL_DOCKER_SUPERVISOR_BINARY="$PWD/target/release/openshell-sandbox" \
|
||||
OPENSHELL_SNAP_VERSION="$VERSION" \
|
||||
OPENSHELL_OUTPUT_DIR=artifacts \
|
||||
mise run package:snap
|
||||
```
|
||||
|
||||
The artifact is written to `artifacts/openshell_${VERSION}_${ARCH}.snap`. The
|
||||
packaging hook fails before `snap pack` if `openshell-sandbox` is missing or not
|
||||
executable.
|
||||
|
||||
## Stage without packing
|
||||
|
||||
To inspect the snap root without running `snap pack`:
|
||||
|
||||
```shell
|
||||
VERSION="$(uv run python tasks/scripts/release.py get-version --snap)"
|
||||
|
||||
OPENSHELL_CLI_BINARY="$PWD/target/release/openshell" \
|
||||
OPENSHELL_GATEWAY_BINARY="$PWD/target/release/openshell-gateway" \
|
||||
OPENSHELL_DOCKER_SUPERVISOR_BINARY="$PWD/target/release/openshell-sandbox" \
|
||||
OPENSHELL_SNAP_VERSION="$VERSION" \
|
||||
mise run package:snap:stage
|
||||
```
|
||||
|
||||
The staged root is written to `artifacts/snap-root`.
|
||||
|
||||
## Commands in the snap
|
||||
|
||||
The snap exposes the CLI:
|
||||
|
||||
- `openshell`
|
||||
|
||||
It also defines a system service running the gateway with the Docker driver.
|
||||
|
||||
- `openshell.gateway`
|
||||
|
||||
The gateway service uses `refresh-mode: endure` so snap refreshes do not restart
|
||||
it while sandboxes are active. Restart the service manually when you are ready
|
||||
to move the gateway to the refreshed snap revision.
|
||||
|
||||
`openshell-sandbox` is staged next to `openshell-gateway` as the Docker
|
||||
supervisor binary. The gateway app passes it to the in-process Docker driver
|
||||
through `OPENSHELL_DOCKER_SUPERVISOR_BIN=$SNAP/bin/openshell-sandbox`. The
|
||||
service stores its gateway database under `$SNAP_COMMON`.
|
||||
|
||||
## Interfaces
|
||||
|
||||
The `openshell` CLI app plugs:
|
||||
|
||||
- `home`
|
||||
- `network`
|
||||
- `ssh-keys`
|
||||
- `system-observe`
|
||||
|
||||
The `openshell.gateway` service plugs:
|
||||
|
||||
- `docker`
|
||||
- `log-observe`
|
||||
- `network`
|
||||
- `network-bind`
|
||||
- `ssh-keys`
|
||||
- `system-observe`
|
||||
|
||||
## Start a Docker gateway from the snap
|
||||
|
||||
The snapped gateway talks to Docker through the Docker snap's
|
||||
`docker:docker-daemon` slot. The snap declares `default-provider: docker` on
|
||||
its Docker plug so snapd can install the Docker snap when OpenShell is
|
||||
installed. Connect the interface before using the Docker driver:
|
||||
|
||||
```shell
|
||||
sudo snap connect openshell:docker docker:docker-daemon
|
||||
sudo snap connect openshell:log-observe
|
||||
sudo snap connect openshell:system-observe
|
||||
sudo snap connect openshell:ssh-keys
|
||||
```
|
||||
|
||||
The gateway uses Docker's default Unix socket location. The Docker snap exposes
|
||||
that socket through the connected `docker` interface, so no `DOCKER_HOST`
|
||||
override is required. The OpenShell snap still requires the Docker snap because
|
||||
it relies on the `docker:docker-daemon` slot; it does not work with Docker
|
||||
installed from a Debian package or Docker's upstream packages.
|
||||
|
||||
The service runs the gateway with the Docker driver enabled:
|
||||
|
||||
```shell
|
||||
openshell.gateway \
|
||||
--drivers docker \
|
||||
--disable-tls \
|
||||
--port 17670 \
|
||||
--db-url "sqlite:$SNAP_COMMON/gateway.db?mode=rwc" \
|
||||
--docker-supervisor-bin "$SNAP/bin/openshell-sandbox" \
|
||||
--docker-network-name openshell-snap \
|
||||
--sandbox-namespace docker-snap \
|
||||
--sandbox-image ghcr.io/nvidia/openshell-community/sandboxes/base:latest \
|
||||
--sandbox-image-pull-policy IfNotPresent \
|
||||
--grpc-endpoint http://host.openshell.internal:17670
|
||||
```
|
||||
|
||||
This stores the gateway SQLite database at
|
||||
`/var/snap/openshell/common/gateway.db`.
|
||||
|
||||
## Connect with the OpenShell CLI
|
||||
|
||||
Register the snap-run gateway as a local plaintext gateway:
|
||||
|
||||
```shell
|
||||
openshell gateway add http://127.0.0.1:17670 --local --name snap-docker
|
||||
openshell gateway select snap-docker
|
||||
openshell status
|
||||
```
|
||||
|
||||
Then use normal sandbox commands:
|
||||
|
||||
```shell
|
||||
openshell sandbox create --name demo
|
||||
openshell sandbox connect demo
|
||||
```
|
||||
|
||||
To avoid changing the default gateway, pass the gateway name per command:
|
||||
|
||||
```shell
|
||||
openshell --gateway snap-docker status
|
||||
openshell --gateway snap-docker sandbox create --name demo
|
||||
```
|
||||
@@ -0,0 +1,66 @@
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: openshell
|
||||
title: OpenShell
|
||||
version: "@VERSION@"
|
||||
summary: Safe, sandboxed runtimes for autonomous AI agents
|
||||
description: |
|
||||
OpenShell provides safe, sandboxed runtimes for autonomous AI agents.
|
||||
It offers a CLI for managing gateways, sandboxes, and providers with
|
||||
policy-enforced egress routing, credential proxying, and privacy-aware
|
||||
LLM inference routing.
|
||||
|
||||
base: "@BASE@"
|
||||
grade: "@GRADE@"
|
||||
confinement: strict
|
||||
license: Apache-2.0
|
||||
website: https://docs.nvidia.com/openshell/latest/index.html
|
||||
source-code: https://github.com/NVIDIA/OpenShell
|
||||
issues: https://github.com/NVIDIA/OpenShell/issues
|
||||
contact: https://github.com/NVIDIA/OpenShell/security/policy
|
||||
architectures:
|
||||
- "@ARCH@"
|
||||
|
||||
apps:
|
||||
openshell:
|
||||
command: bin/openshell
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
- ssh-keys
|
||||
- system-observe
|
||||
gateway:
|
||||
command: bin/openshell-gateway
|
||||
daemon: simple
|
||||
refresh-mode: endure
|
||||
environment:
|
||||
OPENSHELL_BIND_ADDRESS: 127.0.0.1
|
||||
OPENSHELL_SERVER_PORT: 17670
|
||||
OPENSHELL_DB_URL: "sqlite:$SNAP_COMMON/gateway.db?mode=rwc"
|
||||
OPENSHELL_GRPC_ENDPOINT: http://host.openshell.internal:17670
|
||||
OPENSHELL_DISABLE_TLS: true
|
||||
OPENSHELL_DRIVERS: docker
|
||||
OPENSHELL_DOCKER_SUPERVISOR_BIN: "$SNAP/bin/openshell-sandbox"
|
||||
OPENSHELL_DOCKER_NETWORK_NAME: openshell-snap
|
||||
OPENSHELL_SANDBOX_IMAGE: ghcr.io/nvidia/openshell-community/sandboxes/base:latest
|
||||
OPENSHELL_SANDBOX_IMAGE_PULL_POLICY: IfNotPresent
|
||||
OPENSHELL_SANDBOX_SSH_PORT: 2222
|
||||
OPENSHELL_SSH_GATEWAY_HOST: 127.0.0.1
|
||||
OPENSHELL_SSH_GATEWAY_PORT: 8080
|
||||
XDG_DATA_HOME: "$SNAP_COMMON"
|
||||
# Used for creating and locating certain sockets.
|
||||
XDG_RUNTIME_DIR: "$SNAP_COMMON"
|
||||
|
||||
plugs:
|
||||
- docker
|
||||
- log-observe
|
||||
- network
|
||||
- network-bind
|
||||
- ssh-keys
|
||||
- system-observe
|
||||
|
||||
plugs:
|
||||
docker:
|
||||
interface: docker
|
||||
default-provider: docker
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
name: openshell
|
||||
title: OpenShell
|
||||
adopt-info: openshell
|
||||
summary: Safe, sandboxed runtimes for autonomous AI agents
|
||||
description: |
|
||||
OpenShell provides safe, sandboxed runtimes for autonomous AI agents.
|
||||
It offers a CLI for managing gateways, sandboxes, and providers with
|
||||
policy-enforced egress routing, credential proxying, and privacy-aware
|
||||
LLM inference routing.
|
||||
|
||||
base: core24
|
||||
# TODO: this prevents publishing a snap to latest/stable.
|
||||
grade: devel
|
||||
confinement: strict
|
||||
license: Apache-2.0
|
||||
website: https://docs.nvidia.com/openshell/latest/index.html
|
||||
source-code: https://github.com/NVIDIA/OpenShell
|
||||
issues: https://github.com/NVIDIA/OpenShell/issues
|
||||
contact: https://github.com/NVIDIA/OpenShell/security/policy
|
||||
platforms:
|
||||
amd64:
|
||||
build-on: [amd64]
|
||||
build-for: [amd64]
|
||||
arm64:
|
||||
build-on: [arm64]
|
||||
build-for: [arm64]
|
||||
|
||||
apps:
|
||||
openshell:
|
||||
command: bin/openshell
|
||||
plugs:
|
||||
- home
|
||||
- network
|
||||
- ssh-keys
|
||||
- system-observe
|
||||
gateway:
|
||||
command: bin/openshell-gateway
|
||||
daemon: simple
|
||||
refresh-mode: endure
|
||||
environment:
|
||||
OPENSHELL_BIND_ADDRESS: 127.0.0.1
|
||||
OPENSHELL_SERVER_PORT: 17670
|
||||
OPENSHELL_DB_URL: "sqlite:$SNAP_COMMON/gateway.db?mode=rwc"
|
||||
OPENSHELL_GRPC_ENDPOINT: http://host.openshell.internal:17670
|
||||
OPENSHELL_DISABLE_TLS: "true"
|
||||
OPENSHELL_DRIVERS: docker
|
||||
OPENSHELL_DOCKER_SUPERVISOR_BIN: "$SNAP/bin/openshell-sandbox"
|
||||
OPENSHELL_DOCKER_NETWORK_NAME: openshell-snap
|
||||
OPENSHELL_SANDBOX_IMAGE: ghcr.io/nvidia/openshell-community/sandboxes/base:latest
|
||||
OPENSHELL_SANDBOX_IMAGE_PULL_POLICY: IfNotPresent
|
||||
OPENSHELL_SANDBOX_SSH_PORT: 2222
|
||||
OPENSHELL_SSH_GATEWAY_HOST: 127.0.0.1
|
||||
OPENSHELL_SSH_GATEWAY_PORT: 8080
|
||||
XDG_DATA_HOME: "$SNAP_COMMON"
|
||||
XDG_RUNTIME_DIR: "$SNAP_COMMON"
|
||||
plugs:
|
||||
- docker
|
||||
- log-observe
|
||||
- network
|
||||
- network-bind
|
||||
- ssh-keys
|
||||
- system-observe
|
||||
|
||||
parts:
|
||||
openshell:
|
||||
plugin: rust
|
||||
rust-channel: "1.95.0"
|
||||
source: .
|
||||
build-packages:
|
||||
- build-essential
|
||||
- ca-certificates
|
||||
- clang
|
||||
- cmake
|
||||
- git
|
||||
- libclang-dev
|
||||
- libssl-dev
|
||||
- libz3-dev
|
||||
- pkg-config
|
||||
- python3
|
||||
override-pull: |
|
||||
craftctl default
|
||||
craftctl set version="$(python3 "$CRAFT_PROJECT_DIR/tasks/scripts/release.py" get-version --snap)"
|
||||
override-build: |
|
||||
set -euo pipefail
|
||||
|
||||
cargo build --release --locked -p openshell-cli --features bundled-z3
|
||||
cargo build --release --locked -p openshell-server --bin openshell-gateway
|
||||
cargo build --release --locked -p openshell-sandbox --bin openshell-sandbox
|
||||
|
||||
install -D -m 0755 "$CRAFT_PROJECT_DIR/target/release/openshell" \
|
||||
"$CRAFT_PART_INSTALL/bin/openshell"
|
||||
install -D -m 0755 "$CRAFT_PROJECT_DIR/target/release/openshell-gateway" \
|
||||
"$CRAFT_PART_INSTALL/bin/openshell-gateway"
|
||||
install -D -m 0755 "$CRAFT_PROJECT_DIR/target/release/openshell-sandbox" \
|
||||
"$CRAFT_PART_INSTALL/bin/openshell-sandbox"
|
||||
install -D -m 0644 "$CRAFT_PROJECT_DIR/LICENSE" \
|
||||
"$CRAFT_PART_INSTALL/usr/share/doc/openshell/LICENSE"
|
||||
install -D -m 0644 "$CRAFT_PROJECT_DIR/README.md" \
|
||||
"$CRAFT_PART_INSTALL/usr/share/doc/openshell/README.md"
|
||||
@@ -27,6 +27,14 @@ description = "Build all Rust crates in release mode"
|
||||
run = "cargo build --workspace --release"
|
||||
hide = true
|
||||
|
||||
["build:rust:snap"]
|
||||
description = "Build release Rust binaries consumed by the hand-staged snap"
|
||||
run = [
|
||||
"cargo build --release -p openshell-cli --features bundled-z3",
|
||||
"cargo build --release -p openshell-server",
|
||||
"cargo build --release -p openshell-sandbox",
|
||||
]
|
||||
|
||||
[check]
|
||||
description = "Run fast compile and type checks"
|
||||
depends = ["rust:check", "python:typecheck"]
|
||||
|
||||
@@ -23,3 +23,26 @@ hide = true
|
||||
["package:deb:install"]
|
||||
description = "Build OpenShell from source and install the deb locally (requires sudo)"
|
||||
run = "tasks/scripts/package-deb-install.sh"
|
||||
|
||||
["package:snap"]
|
||||
description = "Build a snap package from supplied OpenShell binaries"
|
||||
run = "tasks/scripts/package-snap.sh"
|
||||
hide = true
|
||||
|
||||
["package:snap:amd64"]
|
||||
description = "Build an amd64 snap package from supplied OpenShell binaries"
|
||||
env = { OPENSHELL_SNAP_ARCH = "amd64" }
|
||||
run = "tasks/scripts/package-snap.sh"
|
||||
hide = true
|
||||
|
||||
["package:snap:arm64"]
|
||||
description = "Build an arm64 snap package from supplied OpenShell binaries"
|
||||
env = { OPENSHELL_SNAP_ARCH = "arm64" }
|
||||
run = "tasks/scripts/package-snap.sh"
|
||||
hide = true
|
||||
|
||||
["package:snap:stage"]
|
||||
description = "Stage a snap root from supplied OpenShell binaries without running snap pack"
|
||||
env = { OPENSHELL_SNAP_PACK = "0", OPENSHELL_SNAP_STAGE_DIR = "artifacts/snap-root" }
|
||||
run = "tasks/scripts/package-snap.sh"
|
||||
hide = true
|
||||
|
||||
Executable
+215
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Stage a hand-authored OpenShell snap payload from pre-built binaries, then
|
||||
# optionally invoke `snap pack` against the staged directory.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
APP_NAME="openshell"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Build or stage the openshell snap from supplied binaries.
|
||||
|
||||
Required environment:
|
||||
OPENSHELL_CLI_BINARY Path to openshell
|
||||
OPENSHELL_GATEWAY_BINARY Path to openshell-gateway
|
||||
OPENSHELL_DOCKER_SUPERVISOR_BINARY
|
||||
Path to the Linux openshell-sandbox supervisor
|
||||
OPENSHELL_SNAP_VERSION Snap version
|
||||
|
||||
Optional environment:
|
||||
OPENSHELL_SNAP_ARCH Snap architecture (amd64 or arm64; defaults to host arch)
|
||||
OPENSHELL_SNAP_BASE Snap base (default: core24)
|
||||
OPENSHELL_SNAP_GRADE Snap grade (default: devel)
|
||||
OPENSHELL_SNAP_PACK Set to 0 to only stage the snap root (default: 1)
|
||||
OPENSHELL_SNAP_STAGE_DIR Directory to stage into (default: temporary directory)
|
||||
OPENSHELL_OUTPUT_DIR Output directory for .snap artifacts (default: artifacts)
|
||||
EOF
|
||||
}
|
||||
|
||||
require_env() {
|
||||
local name="$1"
|
||||
if [ -z "${!name:-}" ]; then
|
||||
echo "error: ${name} is required" >&2
|
||||
usage >&2
|
||||
exit 2
|
||||
fi
|
||||
}
|
||||
|
||||
stage_binary() {
|
||||
local src="$1"
|
||||
local dst="$2"
|
||||
if [ ! -x "$src" ]; then
|
||||
echo "error: binary is missing or not executable: ${src}" >&2
|
||||
exit 1
|
||||
fi
|
||||
mkdir -p "$(dirname "$dst")"
|
||||
install -m 0755 "$src" "$dst"
|
||||
}
|
||||
|
||||
infer_snap_arch() {
|
||||
case "$(uname -m)" in
|
||||
x86_64 | amd64) echo "amd64" ;;
|
||||
aarch64 | arm64) echo "arm64" ;;
|
||||
*) uname -m ;;
|
||||
esac
|
||||
}
|
||||
|
||||
normalize_bool() {
|
||||
case "${1,,}" in
|
||||
1 | true | yes | on) echo "1" ;;
|
||||
0 | false | no | off) echo "0" ;;
|
||||
*)
|
||||
echo "error: invalid boolean value '${1}' (expected true/false, 1/0, yes/no, on/off)" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
prepare_stage_dir() {
|
||||
local dir="$1"
|
||||
|
||||
if [ -z "$dir" ]; then
|
||||
echo "error: refusing empty OPENSHELL_SNAP_STAGE_DIR" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
mkdir -p "$dir"
|
||||
|
||||
local canonical_dir
|
||||
local canonical_repo_root
|
||||
canonical_dir="$(cd "$dir" && pwd -P)"
|
||||
canonical_repo_root="$(cd "$repo_root" && pwd -P)"
|
||||
|
||||
if [[ "$canonical_dir" == "/" ||
|
||||
"$canonical_dir" == "$canonical_repo_root" ||
|
||||
"$canonical_repo_root" == "$canonical_dir/"* ]]; then
|
||||
echo "error: refusing unsafe OPENSHELL_SNAP_STAGE_DIR: '${dir}' resolved to '${canonical_dir}'" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
find "$canonical_dir" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} +
|
||||
}
|
||||
|
||||
render_snap_yaml() {
|
||||
local template="$1"
|
||||
local output="$2"
|
||||
|
||||
awk \
|
||||
-v version="$OPENSHELL_SNAP_VERSION" \
|
||||
-v base="$OPENSHELL_SNAP_BASE" \
|
||||
-v grade="$OPENSHELL_SNAP_GRADE" \
|
||||
-v arch="$OPENSHELL_SNAP_ARCH" '
|
||||
{
|
||||
gsub(/@VERSION@/, version);
|
||||
gsub(/@BASE@/, base);
|
||||
gsub(/@GRADE@/, grade);
|
||||
gsub(/@ARCH@/, arch);
|
||||
print;
|
||||
}
|
||||
' "$template" >"$output"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Inputs
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
require_env OPENSHELL_CLI_BINARY
|
||||
require_env OPENSHELL_GATEWAY_BINARY
|
||||
require_env OPENSHELL_DOCKER_SUPERVISOR_BINARY
|
||||
require_env OPENSHELL_SNAP_VERSION
|
||||
|
||||
OPENSHELL_SNAP_ARCH="${OPENSHELL_SNAP_ARCH:-$(infer_snap_arch)}"
|
||||
OPENSHELL_SNAP_BASE="${OPENSHELL_SNAP_BASE:-core24}"
|
||||
OPENSHELL_SNAP_GRADE="${OPENSHELL_SNAP_GRADE:-devel}"
|
||||
OPENSHELL_SNAP_PACK="$(normalize_bool "${OPENSHELL_SNAP_PACK:-1}")"
|
||||
|
||||
case "$OPENSHELL_SNAP_ARCH" in
|
||||
amd64 | arm64) ;;
|
||||
*)
|
||||
echo "error: OPENSHELL_SNAP_ARCH must be amd64 or arm64, got ${OPENSHELL_SNAP_ARCH}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$OPENSHELL_SNAP_GRADE" in
|
||||
devel | stable) ;;
|
||||
*)
|
||||
echo "error: OPENSHELL_SNAP_GRADE must be devel or stable, got ${OPENSHELL_SNAP_GRADE}" >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
repo_root="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
src_dir="${repo_root}/deploy/snap"
|
||||
template="${src_dir}/meta/snap.yaml.in"
|
||||
output_dir_input="${OPENSHELL_OUTPUT_DIR:-artifacts}"
|
||||
case "$output_dir_input" in
|
||||
/*) output_dir="$output_dir_input" ;;
|
||||
*) output_dir="${repo_root}/${output_dir_input}" ;;
|
||||
esac
|
||||
mkdir -p "$output_dir"
|
||||
|
||||
if [ ! -f "$template" ]; then
|
||||
echo "error: snap metadata template not found: ${template}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tmpdir="$(mktemp -d)"
|
||||
cleanup() {
|
||||
rm -rf "$tmpdir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [ -n "${OPENSHELL_SNAP_STAGE_DIR:-}" ]; then
|
||||
case "$OPENSHELL_SNAP_STAGE_DIR" in
|
||||
/*) snap_root="$OPENSHELL_SNAP_STAGE_DIR" ;;
|
||||
*) snap_root="${repo_root}/${OPENSHELL_SNAP_STAGE_DIR}" ;;
|
||||
esac
|
||||
prepare_stage_dir "$snap_root"
|
||||
else
|
||||
snap_root="${tmpdir}/snap-root"
|
||||
mkdir -p "$snap_root"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stage the snap payload
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
stage_binary "$OPENSHELL_CLI_BINARY" "$snap_root/bin/openshell"
|
||||
stage_binary "$OPENSHELL_GATEWAY_BINARY" "$snap_root/bin/openshell-gateway"
|
||||
stage_binary "$OPENSHELL_DOCKER_SUPERVISOR_BINARY" "$snap_root/bin/openshell-sandbox"
|
||||
|
||||
install -D -m 0644 "${repo_root}/LICENSE" "$snap_root/usr/share/doc/openshell/LICENSE"
|
||||
install -D -m 0644 "${repo_root}/README.md" "$snap_root/usr/share/doc/openshell/README.md"
|
||||
|
||||
mkdir -p "$snap_root/meta"
|
||||
render_snap_yaml "$template" "$snap_root/meta/snap.yaml"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Smoke tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
"$snap_root/bin/openshell" --version
|
||||
"$snap_root/bin/openshell-gateway" --version
|
||||
"$snap_root/bin/openshell-sandbox" --version
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pack
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if [ "$OPENSHELL_SNAP_PACK" = "0" ]; then
|
||||
echo "Staged snap root at ${snap_root}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v snap >/dev/null 2>&1; then
|
||||
echo "error: snap command not found; install snapd or set OPENSHELL_SNAP_PACK=0 to only stage the snap root" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
snap pack "$snap_root" "$output_dir"
|
||||
echo "Wrote ${output_dir}/${APP_NAME}_${OPENSHELL_SNAP_VERSION}_${OPENSHELL_SNAP_ARCH}.snap"
|
||||
@@ -22,6 +22,7 @@ class Versions:
|
||||
cargo: str
|
||||
docker: str
|
||||
deb: str
|
||||
snap: str
|
||||
rpm_version: str
|
||||
rpm_release: str
|
||||
git_tag: str
|
||||
@@ -108,6 +109,11 @@ def _versions_from_parts(
|
||||
# Docker tags can't contain '+'.
|
||||
docker_version = cargo_version.replace("+", "-")
|
||||
|
||||
# Snap versions cannot contain '+' and are limited to 32 characters.
|
||||
snap_version = re.sub(r"\.d\d{8}$", "", docker_version)
|
||||
if len(snap_version) > 32:
|
||||
raise ValueError(f"snap version must be at most 32 characters: {snap_version}")
|
||||
|
||||
# Debian versions use '~' so prereleases sort before the eventual release.
|
||||
deb_version = cargo_version
|
||||
deb_version = deb_version[1:] if deb_version.startswith("v") else deb_version
|
||||
@@ -119,6 +125,7 @@ def _versions_from_parts(
|
||||
cargo=cargo_version,
|
||||
docker=docker_version,
|
||||
deb=deb_version,
|
||||
snap=snap_version,
|
||||
rpm_version=rpm_version,
|
||||
rpm_release=rpm_release,
|
||||
git_tag=git_tag,
|
||||
@@ -149,6 +156,7 @@ def _print_env(versions: Versions) -> None:
|
||||
print(f"VERSION_CARGO={versions.cargo}")
|
||||
print(f"VERSION_DOCKER={versions.docker}")
|
||||
print(f"VERSION_DEB={versions.deb}")
|
||||
print(f"VERSION_SNAP={versions.snap}")
|
||||
print(f"VERSION_RPM={versions.rpm_version}")
|
||||
print(f"VERSION_RPM_RELEASE={versions.rpm_release}")
|
||||
print(f"GIT_TAG={versions.git_tag}")
|
||||
@@ -166,6 +174,8 @@ def get_version(format: str) -> None:
|
||||
print(versions.docker)
|
||||
elif format == "deb":
|
||||
print(versions.deb)
|
||||
elif format == "snap":
|
||||
print(versions.snap)
|
||||
elif format == "rpm-version":
|
||||
print(versions.rpm_version)
|
||||
elif format == "rpm-release":
|
||||
@@ -406,6 +416,9 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
get_version_parser.add_argument(
|
||||
"--deb", action="store_true", help="Print Debian package version only."
|
||||
)
|
||||
get_version_parser.add_argument(
|
||||
"--snap", action="store_true", help="Print Snap package version only."
|
||||
)
|
||||
get_version_parser.add_argument(
|
||||
"--rpm-version", action="store_true", help="Print RPM Version only."
|
||||
)
|
||||
@@ -454,6 +467,8 @@ def main() -> None:
|
||||
get_version("docker")
|
||||
elif args.deb:
|
||||
get_version("deb")
|
||||
elif args.snap:
|
||||
get_version("snap")
|
||||
elif args.rpm_version:
|
||||
get_version("rpm-version")
|
||||
elif args.rpm_release:
|
||||
|
||||
Reference in New Issue
Block a user