Updates to hello world.
This commit is contained in:
1 parent
6a02494ac8
commit
785569abdd
7 files changed
+177
-20
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
/hello-world/bin/
|
/hello-world/bin/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
|
/dist/
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
GOCACHE ?= /tmp/cthulhu-go-cache
|
GOCACHE ?= /tmp/cthulhu-go-cache
|
||||||
export GOCACHE
|
export GOCACHE
|
||||||
|
|
||||||
.PHONY: build check
|
.PHONY: build check package
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -buildvcs=false -mod=readonly -o hello-world/bin/hello-world ./hello-world/src
|
go build -buildvcs=false -mod=readonly -o hello-world/bin/hello-world ./hello-world/src
|
||||||
@@ -10,3 +10,6 @@ check: build
|
|||||||
go vet ./...
|
go vet ./...
|
||||||
python3 -B tools/check.py
|
python3 -B tools/check.py
|
||||||
|
|
||||||
|
package:
|
||||||
|
python3 -B tools/package.py
|
||||||
|
|
||||||
@@ -7,10 +7,10 @@ Repository material and Hello World are licensed under GPL-3.0-or-later; see
|
|||||||
|
|
||||||
`repository.toml` identifies this source. `catalog.toml` explicitly lists its
|
`repository.toml` identifies this source. `catalog.toml` explicitly lists its
|
||||||
Tentacles, each in a direct top-level folder with its own `tentacle.toml`.
|
Tentacles, each in a direct top-level folder with its own `tentacle.toml`.
|
||||||
The catalog currently contains discovery metadata, with no release artifacts.
|
The catalog lists verified native packages for Linux amd64 and arm64. Prepared
|
||||||
The proposed source URL is
|
release artifacts live in `dist/`; they become downloadable only after publication.
|
||||||
`https://git.stormux.org/storm/cthulhu-tentacles`; it becomes usable after the
|
The discovery source URL is
|
||||||
maintainer creates and publishes the Git repository.
|
`https://git.stormux.org/storm/cthulhu-tentacles`.
|
||||||
|
|
||||||
## Build and check
|
## Build and check
|
||||||
|
|
||||||
@@ -29,20 +29,63 @@ Checks validate the TOML metadata, registration and suggested bindings, and
|
|||||||
invoke Hello World through the actual Cthulhu-Go host. They produce no speech
|
invoke Hello World through the actual Cthulhu-Go host. They produce no speech
|
||||||
or Braille and leave the running reader alone.
|
or Braille and leave the running reader alone.
|
||||||
|
|
||||||
## Discovery and the upcoming installation workflow
|
## Repository installation
|
||||||
|
|
||||||
After publishing this repository, open global Cthulhu Preferences → Tentacles
|
With the updated reader, open global Cthulhu Preferences → Tentacles → Add
|
||||||
→ Add repository and enter its HTTPS Git URL. Its tab should list Hello World,
|
repository and enter the HTTPS Git URL above. Refresh an already added source.
|
||||||
version 0.1.0, with the description from its manifest.
|
Select Hello World and press Space to review its source/version and requested
|
||||||
|
speech/Braille access, then **Install and enable**. **Install** instead downloads
|
||||||
|
and saves the package disabled. The reader verifies the catalog's SHA-256 digest,
|
||||||
|
package identity and native architecture before saving a launch entry. Catalogs
|
||||||
|
without a published compatible release show a clear message and remain unchecked.
|
||||||
|
No source builds or install scripts run during this workflow. Resource limits
|
||||||
|
do not make untrusted same-user programs safe.
|
||||||
|
|
||||||
The current reader validates and displays repository catalogs. It does not
|
After installation, refresh status until Active and use Cthulhu+Alt+Shift+H.
|
||||||
yet install or build a Tentacle from a catalog. Manifest launch/runtime/API
|
Disable retains the package; re-enabling and reader startup use installed files
|
||||||
fields document this package for the next installation slice; the current
|
without network access. Removing the source retains installed Tentacles. Removing
|
||||||
discovery parser does not interpret them. There is no invented download URL,
|
a managed Tentacle stops it and deletes its package files after shutdown.
|
||||||
release digest, or automatic installation step here.
|
Package updates are not implemented in this slice. See the
|
||||||
|
[Hello World live checks](hello-world/README.md#live-verification).
|
||||||
|
|
||||||
For local execution before installation is implemented, see the explicit
|
## Prepare and publish packages
|
||||||
[Hello World launch procedure](hello-world/README.md). Future publishing should
|
|
||||||
add immutable artifacts and verified digests only once the reader has a defined
|
|
||||||
installation contract.
|
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make check
|
||||||
|
make package
|
||||||
|
```
|
||||||
|
|
||||||
|
`tools/package.py` cross-builds statically linked native binaries for Linux amd64
|
||||||
|
and arm64 from the matching adjacent SDK. It creates deterministic archives
|
||||||
|
containing `tentacle.toml`, `bin/hello-world`, `README.md` and `LICENSE`, plus
|
||||||
|
`dist/SHA256SUMS` and a generated `dist/catalog.toml`. Go builds use readonly
|
||||||
|
module metadata, trim paths and omit VCS stamping. To build one architecture:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python3 -B tools/package.py --architecture amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
Validate the actual host-architecture package through Cthulhu-Go's installer
|
||||||
|
and command host, without changing the running reader:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd ../cthulhu-go
|
||||||
|
CTHULHU_TENTACLE_RELEASE_ROOT=../cthulhu-tentacles GOCACHE=/tmp/cthulhu-go-cache go test ./internal/tentacle -run '^TestBuiltHelloWorldPackageThroughHost$' -count=1 -v
|
||||||
|
```
|
||||||
|
|
||||||
|
Before publication, review both repositories' changes and contributing guides.
|
||||||
|
Commit the reviewed source with the matching SDK available; select that source
|
||||||
|
revision for the `hello-world-v0.1.0` release. In the Git hosting release page,
|
||||||
|
upload `dist/hello-world-0.1.0-linux-amd64.tar.gz`,
|
||||||
|
`dist/hello-world-0.1.0-linux-arm64.tar.gz` and `dist/SHA256SUMS`. Publish and verify
|
||||||
|
the download URLs and digests **before** publishing the matching catalog change.
|
||||||
|
Copy the reviewed `dist/catalog.toml` to `catalog.toml`, review the diff, and
|
||||||
|
submit/push it explicitly. A release filename/version must never be reused for
|
||||||
|
changed content; bump the version before preparing a later release.
|
||||||
|
|
||||||
|
The package command creates local artifacts only. It does not create commits,
|
||||||
|
releases, tags, uploads or pushes. Prepared catalog changes are not evidence that
|
||||||
|
the corresponding release is already available. Live shortcut, speech, Braille,
|
||||||
|
lock/handoff and interruption checks remain necessary after publication and an
|
||||||
|
explicit reader restart. For source-only local testing, the development launch
|
||||||
|
procedure remains in [Hello World](hello-world/README.md#local-launch).
|
||||||
@@ -4,3 +4,14 @@ format-version = 1
|
|||||||
id = "hello-world"
|
id = "hello-world"
|
||||||
manifest = "hello-world/tentacle.toml"
|
manifest = "hello-world/tentacle.toml"
|
||||||
|
|
||||||
|
[[tentacles.releases]]
|
||||||
|
platform = "linux"
|
||||||
|
architecture = "amd64"
|
||||||
|
url = "https://git.stormux.org/storm/cthulhu-tentacles/releases/download/hello-world-v0.1.0/hello-world-0.1.0-linux-amd64.tar.gz"
|
||||||
|
sha256 = "2bad533bc217a5b1bd374115f6151da2a1f6e4ccdbdc93528a5a783f0518f8cd"
|
||||||
|
|
||||||
|
[[tentacles.releases]]
|
||||||
|
platform = "linux"
|
||||||
|
architecture = "arm64"
|
||||||
|
url = "https://git.stormux.org/storm/cthulhu-tentacles/releases/download/hello-world-v0.1.0/hello-world-0.1.0-linux-arm64.tar.gz"
|
||||||
|
sha256 = "9ef956a04fb1fa98ac01b04fadc122f92b77d708440e0438a7451da62078a9d4"
|
||||||
@@ -20,6 +20,14 @@ Hello World requests presentation access only. It receives no focused text,
|
|||||||
uses no network services, and stores no settings. Source and distribution are
|
uses no network services, and stores no settings. Source and distribution are
|
||||||
licensed under GPL-3.0-or-later; see [LICENSE](LICENSE).
|
licensed under GPL-3.0-or-later; see [LICENSE](LICENSE).
|
||||||
|
|
||||||
|
## Repository installation
|
||||||
|
|
||||||
|
Refresh the source in global Preferences → Tentacles. Space on Hello World
|
||||||
|
opens first-use review and installs/enables the package after acceptance.
|
||||||
|
**Install** saves it disabled instead. The release must be published at the
|
||||||
|
catalog URL; building locally alone does not make it downloadable. Refresh
|
||||||
|
status until Active before trying the shortcut.
|
||||||
|
|
||||||
## Local launch
|
## Local launch
|
||||||
|
|
||||||
Run `make build` from the repository root. Rebuild Cthulhu-Go with the matching
|
Run `make build` from the repository root. Rebuild Cthulhu-Go with the matching
|
||||||
@@ -72,7 +80,7 @@ Resource limits do not make untrusted same-user programs safe.
|
|||||||
5. Check speech off/beeps and disabled Braille settings. Hello World must respect
|
5. Check speech off/beeps and disabled Braille settings. Hello World must respect
|
||||||
them. Remap or occupy the suggested binding and check core/user precedence.
|
them. Remap or occupy the suggested binding and check core/user precedence.
|
||||||
|
|
||||||
Audible speech, physical shortcuts, actual display output and the eventual
|
Audible speech, physical shortcuts, actual display output and the
|
||||||
repository-installation workflow require these live checks; protocol tests do
|
repository-installation workflow require these live checks; protocol tests do
|
||||||
not establish them.
|
not establish them.
|
||||||
|
|
||||||
+21
-1
@@ -3,11 +3,13 @@
|
|||||||
"""Check the repository and the built Tentacle without running a reader."""
|
"""Check the repository and the built Tentacle without running a reader."""
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import hashlib
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import select
|
import select
|
||||||
import subprocess
|
import subprocess
|
||||||
import tomllib
|
import tomllib
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
def require(condition, message):
|
def require(condition, message):
|
||||||
@@ -27,7 +29,8 @@ def check_metadata(repoRoot):
|
|||||||
"Unsupported metadata format")
|
"Unsupported metadata format")
|
||||||
require(repository["id"] == "storm.cthulhu-tentacles" and repository["name"],
|
require(repository["id"] == "storm.cthulhu-tentacles" and repository["name"],
|
||||||
"Repository identity is missing")
|
"Repository identity is missing")
|
||||||
require(catalog["tentacles"] == [{"id": "hello-world", "manifest": "hello-world/tentacle.toml"}],
|
require(len(catalog["tentacles"]) == 1 and catalog["tentacles"][0]["id"] == "hello-world"
|
||||||
|
and catalog["tentacles"][0]["manifest"] == "hello-world/tentacle.toml",
|
||||||
"Catalog must list exactly Hello World")
|
"Catalog must list exactly Hello World")
|
||||||
manifest = read_toml(repoRoot / catalog["tentacles"][0]["manifest"])
|
manifest = read_toml(repoRoot / catalog["tentacles"][0]["manifest"])
|
||||||
require(manifest["format-version"] == 1 and manifest["id"] == "hello-world"
|
require(manifest["format-version"] == 1 and manifest["id"] == "hello-world"
|
||||||
@@ -38,6 +41,23 @@ def check_metadata(repoRoot):
|
|||||||
require((repoRoot / "LICENSE").is_file() and (repoRoot / "hello-world/LICENSE").is_file(),
|
require((repoRoot / "LICENSE").is_file() and (repoRoot / "hello-world/LICENSE").is_file(),
|
||||||
"Repository and Tentacle licenses are required")
|
"Repository and Tentacle licenses are required")
|
||||||
|
|
||||||
|
seen = set()
|
||||||
|
for release in catalog["tentacles"][0].get("releases", []):
|
||||||
|
key = (release["platform"], release["architecture"])
|
||||||
|
require(key not in seen and key[0] == "linux" and key[1] in ("amd64", "arm64"),
|
||||||
|
"Invalid or duplicate release target")
|
||||||
|
seen.add(key)
|
||||||
|
parsed = urlparse(release["url"])
|
||||||
|
require(parsed.scheme == "https" and parsed.hostname and not parsed.username
|
||||||
|
and not parsed.fragment, "Release URL must be HTTPS without credentials")
|
||||||
|
digest = release["sha256"]
|
||||||
|
require(len(digest) == 64 and all(character in "0123456789abcdef" for character in digest),
|
||||||
|
"Invalid SHA-256 digest")
|
||||||
|
artifactPath = repoRoot / "dist" / parsed.path.rsplit("/", 1)[-1]
|
||||||
|
if artifactPath.exists():
|
||||||
|
require(hashlib.sha256(artifactPath.read_bytes()).hexdigest() == digest,
|
||||||
|
"Prepared package does not match its catalog digest")
|
||||||
|
|
||||||
|
|
||||||
def check_registration(programPath):
|
def check_registration(programPath):
|
||||||
with subprocess.Popen([str(programPath)], stdin=subprocess.PIPE,
|
with subprocess.Popen([str(programPath)], stdin=subprocess.PIPE,
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# Copyright (c) 2026 Storm Dragon
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
"""Build reproducible Hello World release artifacts and a catalog for review."""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import gzip
|
||||||
|
import hashlib
|
||||||
|
import io
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import subprocess
|
||||||
|
import tarfile
|
||||||
|
import tomllib
|
||||||
|
|
||||||
|
|
||||||
|
def build_package(repoRoot, architecture, version):
|
||||||
|
distRoot = repoRoot / "dist"
|
||||||
|
distRoot.mkdir(exist_ok=True)
|
||||||
|
programPath = distRoot / f"hello-world-linux-{architecture}"
|
||||||
|
environment = dict(os.environ, CGO_ENABLED="0", GOOS="linux", GOARCH=architecture)
|
||||||
|
environment.setdefault("GOCACHE", "/tmp/cthulhu-go-cache")
|
||||||
|
subprocess.run(["go", "build", "-buildvcs=false", "-mod=readonly", "-trimpath",
|
||||||
|
"-ldflags=-s -w", "-o", str(programPath), "./hello-world/src"],
|
||||||
|
cwd=repoRoot, env=environment, check=True)
|
||||||
|
artifactPath = distRoot / f"hello-world-{version}-linux-{architecture}.tar.gz"
|
||||||
|
with artifactPath.open("wb") as output:
|
||||||
|
with gzip.GzipFile(filename="", mode="wb", fileobj=output, mtime=0) as compressed:
|
||||||
|
with tarfile.open(fileobj=compressed, mode="w", format=tarfile.USTAR_FORMAT) as archive:
|
||||||
|
for name, data, mode in [
|
||||||
|
("tentacle.toml", (repoRoot / "hello-world/tentacle.toml").read_bytes(), 0o644),
|
||||||
|
("README.md", (repoRoot / "hello-world/README.md").read_bytes(), 0o644),
|
||||||
|
("LICENSE", (repoRoot / "hello-world/LICENSE").read_bytes(), 0o644),
|
||||||
|
("bin/hello-world", programPath.read_bytes(), 0o755),
|
||||||
|
]:
|
||||||
|
member = tarfile.TarInfo(name)
|
||||||
|
member.size, member.mode, member.mtime = len(data), mode, 0
|
||||||
|
archive.addfile(member, io.BytesIO(data))
|
||||||
|
digest = hashlib.sha256(artifactPath.read_bytes()).hexdigest()
|
||||||
|
return artifactPath, digest
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument("--architecture", nargs="+", choices=["amd64", "arm64"], default=["amd64", "arm64"])
|
||||||
|
args = parser.parse_args()
|
||||||
|
if len(set(args.architecture)) != len(args.architecture):
|
||||||
|
parser.error("Architectures must not be repeated")
|
||||||
|
repoRoot = Path(__file__).resolve().parents[1]
|
||||||
|
manifest = tomllib.loads((repoRoot / "hello-world/tentacle.toml").read_text())
|
||||||
|
version = manifest["version"]
|
||||||
|
if not version or any(character not in "0123456789abcdefghijklmnopqrstuvwxyz.-" for character in version):
|
||||||
|
raise ValueError("Version must be safe for release filenames")
|
||||||
|
lines = ["format-version = 1", "", "[[tentacles]]", 'id = "hello-world"',
|
||||||
|
'manifest = "hello-world/tentacle.toml"']
|
||||||
|
checksums = []
|
||||||
|
for architecture in args.architecture:
|
||||||
|
artifactPath, digest = build_package(repoRoot, architecture, version)
|
||||||
|
releaseURL = f"https://git.stormux.org/storm/cthulhu-tentacles/releases/download/hello-world-v{version}/{artifactPath.name}"
|
||||||
|
lines += ["", "[[tentacles.releases]]", 'platform = "linux"',
|
||||||
|
f"architecture = {json.dumps(architecture)}", f"url = {json.dumps(releaseURL)}",
|
||||||
|
f"sha256 = {json.dumps(digest)}"]
|
||||||
|
checksums.append(f"{digest} {artifactPath.name}")
|
||||||
|
print(f"Prepared {artifactPath.name}: {digest}")
|
||||||
|
(repoRoot / "dist/catalog.toml").write_text("\n".join(lines) + "\n")
|
||||||
|
(repoRoot / "dist/SHA256SUMS").write_text("\n".join(checksums) + "\n")
|
||||||
|
print("Prepared dist/catalog.toml and dist/SHA256SUMS for review. Nothing was published.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in new issue
Block a user