From d2ceebe5f6223f2d44ad976fb0f9cf8897bb5cef Mon Sep 17 00:00:00 2001 From: Nick Ninov Date: Thu, 24 Sep 2026 08:32:59 +0300 Subject: [PATCH 1/2] docker: Launch existing build --- docs/account.md | 2 +- docs/utils.md | 26 +++++++++++++++++--------- pyproject.toml | 2 +- status_sdk/utils/external.py | 21 ++++++++++++++++----- 4 files changed, 35 insertions(+), 16 deletions(-) diff --git a/docs/account.md b/docs/account.md index 7783a16..74e66fa 100644 --- a/docs/account.md +++ b/docs/account.md @@ -1821,7 +1821,7 @@ The exact shape depends on how the backend was launched: | Launched with | Reported version | `status_go_commit_sha` | |--------|--------|-------------| -| [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue) / [`download_build_and_launch`](./utils.md#download_build_and_launchfile_namenone-repo_namestatus-imstatus-go-tagnone-tokennone-addresslocalhost8080-wait_seconds30) | `v10.35.0-48-g9f09f9027` | `9f09f9027` - the short SHA, taken out of the `git describe` version | +| [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue) / [`download_build_and_launch`](./utils.md#download_build_and_launchlaunchernone-repo_namestatus-imstatus-go-tagnone-tokennone-addresslocalhost8080-wait_seconds30) | `v10.35.0-48-g9f09f9027` | `9f09f9027` - the short SHA, taken out of the `git describe` version | | [`launch_docker_container`](./utils.md#launch_docker_containercommitnone-wait_seconds5-platformlinuxamd64-data_foldernone) | `9f09f902762292fbe8264dd75a68e739ecd17444` | the same value, unchanged | The two differ because a native build is compiled inside a git clone, so `status-go` embeds a `git describe` version that the SDK extracts the SHA from. The Docker image is built from a git **context** that carries no `.git` folder, so `docker-compose.yaml` injects the ref it was told to build instead - meaning the full SHA comes back as-is. diff --git a/docs/utils.md b/docs/utils.md index 1bc48d4..30caaf0 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -156,20 +156,20 @@ build_and_launch(address="localhost:9500", wait_seconds=60) account = Account(backend_port=9500) ``` -### `download_build_and_launch(file_name=None, repo_name="status-im/status-go", tag=None, token=None, address="localhost:8080", wait_seconds=30)` +### `download_build_and_launch(launcher=None, repo_name="status-im/status-go", tag=None, token=None, address="localhost:8080", wait_seconds=30)` -Download a prebuilt `status-backend` bundle from a GitHub release and launch it. This is an **alternative to [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue)** for setups that do not want to build [`status-im/status-go`](https://github.com/status-im/status-go) from source. +Download a prebuilt `status-backend` bundle from a GitHub release, extract it and launch it. This is an **alternative to [`build_and_launch`](./utils.md#build_and_launchcommitnone-repo_dirnone-addresslocalhost8080-wait_seconds30-install_depstrue)** for setups that do not want to build [`status-im/status-go`](https://github.com/status-im/status-go) from source - no Nix or Go toolchain is needed. | Name | Type | Required | Description | |-----|-----|-----|-------------| -| `file_name` | `str` | No | The release asset to download, exactly as it appears on the release page. When omitted, the asset matching this machine is picked using the pattern `status-backend_{platform}_{arch}_{version}`, e.g. `status-backend_linux_x86_64_2.34.0`. | +| `launcher` | `str` | No | Path to a `status-backend` binary that is **already on disk**. When given, **nothing is downloaded**. Use it to re-launch a bundle you already have, or a binary from somewhere else entirely. | | `repo_name` | `str` | No | The `owner/name` of the repository to pull the release from. Defaults to `status-im/status-go`. | | `tag` | `str` | No | A release tag. When omitted, the latest release is used. | | `token` | `str` | No | A GitHub token. Required for private repositories. | | `address` | `str` | No | The `host:port` to run `status-backend` on. Defaults to `localhost:8080`, which matches the defaults of [`Account`](./account.md#accountdomainlocalhost-backend_port8080-media_port9000-is_securefalse-backup_foldernone-volume_foldernone). If you change it, pass the matching `domain` and `backend_port` when creating the `Account`. | -| `wait_seconds` | `int` | No | How long to poll the backend's `/health` endpoint before giving up, in seconds. Defaults to `30`. **Downloading itself is not subject to this timeout** - only the startup that follows it. | +| `wait_seconds` | `int` | No | How long to poll the backend's `/health` endpoint before giving up, in seconds. Defaults to `30`. **Downloading and extracting are not subject to this timeout** - only the startup that follows them. | -The bundle is extracted into a `status-backend-bundle` folder in the current working directory, and reused on later calls instead of downloading again. +Returns `str` - the path of the file that was launched. A custom exception is raised when the release has no asset for this machine, when the extracted bundle contains nothing runnable, or when the backend does not answer on `/health` in time. ```python from status_sdk import download_build_and_launch, Account @@ -185,9 +185,6 @@ params = { account.login(**params) print(account.info["public_key"]) - -# Stop the backend when you are done -process.terminate() ``` Download a specific release tag from a private repository: @@ -195,13 +192,24 @@ Download a specific release tag from a private repository: ```python from status_sdk import download_build_and_launch -download_build_and_launch( +launcher = download_build_and_launch( repo_name="status-im/status-go", tag="v2.34.0", token="ghp_xxxxxxxxxxxxxxxxxxxx" ) +print(f"Launched {launcher}") +``` + +Re-launch a bundle that is already on disk, with no network access at all: + +```python +from status_sdk import download_build_and_launch + +download_build_and_launch("./status-backend-bundle/run.sh") ``` +**Note**: if something already answers on `address`, the backend is **not** launched a second time and the function returns straight away. That makes repeated calls safe, but it also means a backend left running from an earlier session is reused - stop it first if you want a different build. + ## Properties ### `__version__` diff --git a/pyproject.toml b/pyproject.toml index 960ad90..c9b5045 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "status-sdk" -version = "1.2.0" +version = "1.2.1" description = "Private chat. Communities. Multi-chain wallet. Browser. dApps all in one app, powered by SNT." readme = "README.md" requires-python = ">=3.11" diff --git a/status_sdk/utils/external.py b/status_sdk/utils/external.py index 45e1bc9..f4ec6f6 100644 --- a/status_sdk/utils/external.py +++ b/status_sdk/utils/external.py @@ -198,21 +198,29 @@ def run(cmd: list[str], cwd: Optional[str] = None) -> subprocess.CompletedProces builds.launch_build(binary_path, repo_dir, address, wait_seconds) -def download_build_and_launch(file_name: Optional[str] = None, repo_name: str = "status-im/status-go", tag: Optional[str] = None, token: Optional[str] = None, address: str = "localhost:8080", wait_seconds: int = 30): +def download_build_and_launch(launcher: Optional[str] = None, repo_name: str = "status-im/status-go", tag: Optional[str] = None, token: Optional[str] = None, address: str = "localhost:8080", wait_seconds: int = 30): """ Download a prebuilt `status-backend` bundle from a GitHub release, extract it and launch it. This is an alternative to `build_and_launch` for setups that do not want to build `status-im/status-go` from source - no Nix or Go toolchain is needed. Parameters: - - `file_name` - the release asset to download, exactly as it appears on the release page. If not provided, the asset matching this machine is picked + - `launcher` - the `status-backend` binary to launch - `repo_name` - the `owner/name` of the repository - `tag` - a release tag. If not provided, the latest release is used - `token` - a GitHub token. Required for private repositories - `address` - the `host:port` to launch `status-backend` on. Defaults to `localhost:8080`. - `wait_seconds` - number of seconds to wait, polling the health endpoint, before giving up on the backend starting. Downloading itself is not subject to this timeout. + + Output: + - the `status-backend` binary to launch """ logger = logging.getLogger(__name__) + destination = os.getcwd() + if launcher: + builds.launch_build(launcher, destination, address, wait_seconds) + return launcher + headers = {"Accept": "application/vnd.github+json"} if token: headers["Authorization"] = f"Bearer {token}" @@ -231,7 +239,6 @@ def download_build_and_launch(file_name: Optional[str] = None, repo_name: str = selected = assets[0] file_name = selected["name"] - destination = os.getcwd() archive_path = os.path.join(destination, file_name) bundle_dir = os.path.join(destination, "status-backend-bundle") if not os.path.exists(bundle_dir): @@ -250,12 +257,16 @@ def download_build_and_launch(file_name: Optional[str] = None, repo_name: str = if not os.path.basename(member.name).startswith("._") ] + common_prefix = os.path.commonpath([member.name for member in members]) + for member in members: + member.name = os.path.relpath(member.name, common_prefix) + # A bundle from a previous release must not mix with the new one shutil.rmtree(bundle_dir, ignore_errors=True) logger.info(f"Extracting '{file_name}' into {bundle_dir}...") # The `data` filter blocks paths escaping `destination`. Only available from Python 3.11.4 extract_options = {"filter": "data"} if hasattr(tarfile, "data_filter") else {} - archive.extractall(destination, members=members, **extract_options) + archive.extractall(bundle_dir, members=members, **extract_options) os.remove(archive_path) else: @@ -279,4 +290,4 @@ def download_build_and_launch(file_name: Optional[str] = None, repo_name: str = logger.warning(f"Failed to clear quarantine attribute on {bundle_dir}: {result.stderr.strip()}") builds.launch_build(launcher, destination, address, wait_seconds) - + return launcher From 6a75993cf343680fa78ea8bb5bdb6d99e43b8340 Mon Sep 17 00:00:00 2001 From: Nick Ninov Date: Fri, 25 Sep 2026 08:01:29 +0300 Subject: [PATCH 2/2] docs: CHANGELOG 1.2.1 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9769a09..a56c7e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to `status-python-sdk` will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.1] - 2026-09-25 + +### Changed + +- `def download_build_and_launch` + - A `launcher` can be passed to launch a [status-go] build that is already on disk, skipping the release download and extraction + - The path of the launched build is now returned + ## [1.2.0] - 2026-09-22 ### Added @@ -201,6 +209,7 @@ will try to log in without a hashed password - Launch [status-go] Docker container with Python instead of manual `docker compose up -d` setup. - Custom library errors +[1.2.1]: https://github.com/status-im/status-python-sdk/releases/tag/1.2.1 [1.2.0]: https://github.com/status-im/status-python-sdk/releases/tag/1.2.0 [1.1.6]: https://github.com/status-im/status-python-sdk/releases/tag/1.1.6 [1.1.5]: https://github.com/status-im/status-python-sdk/releases/tag/1.1.5