feat(installer): install full trapos by default

This commit is contained in:
Guillaume ARM 2026-06-15 00:57:10 +02:00
parent f8e15d2267
commit e10a1d5976
16 changed files with 247 additions and 177 deletions

View File

@ -37,13 +37,13 @@ Use [`docs/README.md`](docs/README.md) as the entrypoint for CC:Tweaked, CraftOS
- Preserve `periphemu` guards used for CraftOS-PC emulation; see [`docs/craftos_pc_glossary.md`](docs/craftos_pc_glossary.md) for upstream emulator references.
- Global CraftOS-PC save data lives in `~/Library/Application Support/CraftOS-PC` on macOS and `~/.local/share/craftos-pc` on Linux. Repo launchers use local state instead: `.craftos/` for TrapOS and `.craftos-vanilla/` for vanilla CraftOS-PC. See [`docs/install-craftos-pc.md`](docs/install-craftos-pc.md).
- TrapOS ships as packages, each described by `packages/<name>/ccpm.json` (`name`, `version`, `dependencies`, `files`, `autostart`); `packages/index.json` lists them. Source files stay in place — descriptors only reference them. To ship a new file, add it to the right package's `files` (and `autostart` if it is a server). `packages/trapos/ccpm.json` is the full OS meta-package. See [ADR-0010](docs/adrs/adr-0010-ccpm-package-manager.md).
- `install-ccpm.lua` is the one-time wget bootstrap. It installs only `trapos-core`/`ccpm`, seeds the default `guillaumearm/cc-libs` registry as a `gitea` registry on `git.trapcloud.fr` tracking `master` (or `next` with `--beta`), and tells users to run `ccpm update` then `ccpm install trapos`. The legacy `github` registry type still resolves but is deprecated.
- `install-trapos.lua` is the one-time wget bootstrap (public entry point `https://trapos.trapcloud.fr/install`). It installs `trapos-core`/`ccpm`, seeds the default `guillaumearm/cc-libs` registry as a `gitea` registry on `git.trapcloud.fr` tracking `master` (the only channel), then runs `ccpm update` + `ccpm install trapos` and `trapos-postinstall`. Pass `--cpm-only` to stop after the ccpm bootstrap. The legacy `github` registry type still resolves but is deprecated.
- `ccpm` (in `trapos-core`) is the package manager: `apis/libccpm.lua` is the testable core (factory with injectable `http`/`stateDir`/`installRoot`), `programs/ccpm.lua` the CLI. State: `/trapos/ccpm.json` (registries), `/trapos/ccpm.lock.json` (installed packages), and `/trapos/ccpm.cache.json` (available packages from `ccpm update`). Never use the word "manifest" in ccpm — it is reserved for the OS manifest.
- Add new servers to `startup/servers.lua` as needed.
## Conventions
- Bump the owning `packages/<name>/ccpm.json` version (and mirror it in `packages/index.json`) when changing module behavior; programs report it at runtime via `require('/apis/libversion')().forSelf()`. `install-ccpm.lua` is the only file that still carries its own `_VERSION` because it is the wget bootstrap and lives outside the package system.
- Bump the owning `packages/<name>/ccpm.json` version (and mirror it in `packages/index.json`) when changing module behavior; programs report it at runtime via `require('/apis/libversion')().forSelf()`. `install-trapos.lua` is the only file that still carries its own `_VERSION` because it is the wget bootstrap and lives outside the package system.
- Programs support `-version`/`--version` and `-help`/`--help`; router also supports `-silent`/`--silent`.
- French or English comments are fine; match surrounding code.
- Commit messages use lightweight conventional style: `topic(scope): description` or `topic: description`.

View File

@ -4,52 +4,47 @@ A small in-game operating system for ComputerCraft / CC:Tweaked, built around a
## Installation
Install `ccpm` first. This is the only step that needs `wget` with a URL:
One command installs everything — it bootstraps `ccpm`, syncs the default
registry (`guillaumearm/cc-libs`), and installs the full TrapOS:
```
wget run https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/master/install-ccpm.lua
wget run https://trapos.trapcloud.fr/install
```
Then sync the default registry (`guillaumearm/cc-libs`) and install TrapOS:
When it finishes, run `sandbox --help` to get started, or `trapos-upgrade` to
update later.
Install only the package manager (no full OS) with `--cpm-only`, then
cherry-pick packages yourself:
```
wget run https://trapos.trapcloud.fr/install --cpm-only
ccpm update
ccpm install trapos
ccpm install trapos-net
ccpm install trapos-ui
```
Install individual packages instead if you want to cherry-pick:
```
> ccpm install trapos-net
> ccpm install trapos-ui
```
Install `ccpm` from the beta branch (one-time opt-in, asks for confirmation):
```
wget run https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/next/install-ccpm.lua --beta
```
Once `ccpm` is installed from beta, the default registry tracks `next`; `ccpm update` and `ccpm upgrade` keep using that branch.
After install, every boot shows a colored MOTD with the installed version and branch (lime for stable, orange + `[BETA]` for beta).
After install, every boot shows a colored MOTD with the installed version.
## Packages
TrapOS is split into packages, each described by a `packages/<name>/ccpm.json`:
- `trapos-core`: the package manager (`ccpm`), event loop, `upgrade`, `events`.
- `trapos-core`: the package manager (`ccpm`), event loop, `trapos-upgrade`, `trapos-postinstall`, `events`.
- `trapos-test`: the test framework (`libtest`) and suite runner (`runtest`).
- `trapos-boot`: the startup MOTD and autostart server launcher.
- `trapos-net`: routed modem networking (`net`, `router`, `ping`, `ping-server`).
- `trapos-ui`: the terminal UI toolkit (`libtui`, `tuidemo`).
- `trapos-ai`: the AI client for `opencode serve`.
- `trapos`: full TrapOS meta-package (`trapos-boot`, `trapos-net`, `trapos-ui`, `trapos-test`, and `trapos-ai` during beta).
- `trapos`: full TrapOS meta-package (`trapos-boot`, `trapos-net`, `trapos-ui`, `trapos-test`, `trapos-ai`, `trapos-sandbox`).
The `trapos` meta-package is the user-facing full install. Package descriptors list
files and autostart servers; installed state is tracked under `/trapos`.
## ccpm
`ccpm` is the TrapOS package manager. `install-ccpm.lua` installs it by installing
`ccpm` is the TrapOS package manager. `install-trapos.lua` installs it by installing
the required `trapos-core` package and configures the default registry
(`guillaumearm/cc-libs`).
(`guillaumearm/cc-libs`), then (unless `--cpm-only`) installs the full `trapos`
meta-package.
```
ccpm install <package> ccpm reinstall <package> ccpm uninstall <package>
@ -82,7 +77,8 @@ Servers listed in `manifest.autostart` are launched at boot by `startup/servers.
- `router`: routes messages. You need to set up a router to use all `apis/net`-based programs and libraries.
- `ping`: pings machines using `apis/net`.
- `events`: emits and logs computer events.
- `upgrade`: alias for `ccpm upgrade`.
- `trapos-upgrade`: runs `ccpm update` then `ccpm upgrade`; pass `--reboot`/`-r` to reboot after upgrading.
- `trapos-postinstall`: prints the post-install welcome and next steps (run automatically by the installer).
## Development
See [DEVELOPMENT.md](./DEVELOPMENT.md) for local development installation.

View File

@ -56,7 +56,7 @@ Two safe-exec recipes wrap raw `--headless --exec` with `xpcall`, call `os.shutd
- `just craftos-exec '<lua>'` — probe against **vanilla CraftOS-PC**. No mounts, no startup scripts. Use this when the question is purely about CC:Tweaked behavior and TrapOS files would be a distraction, or to confirm a behavior is upstream rather than something the dev env layered on.
- `just trapos-install` — drive the full real install (`install-ccpm.lua` → `ccpm update``ccpm install trapos`) on a fresh ephemeral state. This is the probe to run when changing anything in the install path itself.
- `just trapos-install` — drive the full real install (`install-trapos.lua`, which bootstraps ccpm then runs `ccpm update` + `ccpm install trapos` itself) on a fresh ephemeral state. This is the probe to run when changing anything in the install path itself.
Conventions:
@ -73,7 +73,7 @@ Conventions:
- `just repl` is a human-only interactive wrapper around `just trapos --cli`; automation and LLM agents must use `just trapos-exec '<lua>'` or `just craftos-exec '<lua>'` instead.
- `craftos` (GUI) now opens a single unlabelled `Computer 0` window with a top modem attached. Cross-machine testing requires an explicit `periphemu create` call from the shell rather than being implicit on boot — one extra command when you need a peer, no surprise windows or persisted ghost VMs.
- `.craftos-vanilla/` is in `.gitignore` alongside `.craftos/`.
- `just trapos-install` is *not* part of `just ci`: it is network-dependent and slower than `just test`. Run it manually when touching `install-ccpm.lua` or ccpm package descriptors.
- `just trapos-install` is *not* part of `just ci`: it is network-dependent and slower than `just test`. Run it manually when touching `install-trapos.lua` or ccpm package descriptors.
- Higher CraftOS-PC invocation traffic during agent sessions; cheap enough that this is a good trade.
- The harness version becomes a project-level concern. When CC:Tweaked ships breaking changes that require a newer CraftOS-PC build, we bump the minimum version in [`docs/install-craftos-pc.md`](../install-craftos-pc.md) and `check-craftos` keeps contributors honest.
- No CI integration yet. Running CraftOS-PC headless in GitHub Actions is feasible (the AppImage works on Ubuntu runners) but is out of scope; the contract is local-only for now.

View File

@ -8,6 +8,19 @@ Accepted
2026-06-08
## Update (2026-06-15)
The beta/stable two-channel model has been retired now that `next` is merged into
`master`: `master` is the only channel. The `wget` bootstrap is renamed
`install-ccpm.lua``install-trapos.lua` (public entry point
`https://trapos.trapcloud.fr/install`) and now installs the **full OS** in one shot —
it bootstraps `ccpm`, then runs `ccpm update` + `ccpm install trapos` and a
`trapos-postinstall` welcome. Pass `--cpm-only` to stop after the ccpm bootstrap. The
persisted `branch` field is always `master`; the `--beta` opt-in and its confirmation
prompt are gone. The `upgrade` program is replaced by `trapos-upgrade` (`ccpm update` +
`ccpm upgrade`, with `--reboot`/`-r`). References to `--beta`/`install-ccpm.lua` below
are retained as historical context.
## Context
The previous install flow (a `LIST_FILES` table inside `install.lua` and a single flat

View File

@ -7,9 +7,7 @@ Follow this order while playing.
On the ComputerCraft computer:
```sh
wget run https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/next/install-ccpm.lua --beta
ccpm update
ccpm install trapos
wget run https://trapos.trapcloud.fr/install
```
If the computer asks to reboot, reboot it.

View File

@ -90,7 +90,7 @@ On macOS, use the `--rom` form shown above if the command fails with `Could not
`just craftos` launches a vanilla CraftOS-PC with no mounts, persistent under `.craftos-vanilla/` (also gitignored). Use it when a probe should not see TrapOS files — for example, to confirm a behavior is upstream rather than TrapOS-specific.
`just trapos-install` exercises the real ccpm bootstrap (`install-ccpm.lua` → `ccpm update` `ccpm install trapos`) end-to-end on a fresh, ephemeral CraftOS-PC state. Network-dependent and slower than `just test`, so not part of `just ci`. Override the watchdog with `TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS` (default `60`).
`just trapos-install` exercises the real one-shot installer (`install-trapos.lua`, which bootstraps ccpm then runs `ccpm update` + `ccpm install trapos`) end-to-end on a fresh, ephemeral CraftOS-PC state. Network-dependent and slower than `just test`, so not part of `just ci`. Override the watchdog with `TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS` (default `60`).
For automated probes, use the safe wrappers. They mount the right environment,
shut down the machine after completion or Lua errors, and kill the host process

View File

@ -14,12 +14,10 @@ CC Computer
## 0. Install TrapOS and the AI package
On a fresh CC computer (beta branch):
On a fresh CC computer:
```
wget run https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/next/install-ccpm.lua --beta
ccpm update
ccpm install trapos
wget run https://trapos.trapcloud.fr/install
```
## 1. Start `opencode serve`

View File

@ -1,18 +1,18 @@
local _VERSION = '5.1.0';
local _VERSION = '6.0.0';
local REPO_BASE = 'https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/';
local REPO_BASE = 'https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/master/';
local LOCAL_STATE_DIR = '/trapos';
local LOCAL_MANIFEST_PATH = '/trapos/manifest.json';
local LOCAL_CONFIG_PATH = '/trapos/ccpm.json';
local LOCAL_LOCK_PATH = '/trapos/ccpm.lock.json';
local DEFAULT_REGISTRY_NAME = 'guillaumearm/cc-libs';
local INSTALL_BRANCH = 'master';
local function printUsage()
print('install-ccpm usage:');
print('install-trapos usage:');
print();
print('\t\twget run <install-url>');
print('\t\twget run <install-url> --beta');
print('\t\twget run <install-url> --stable');
print('\t\twget run <install-url> --cpm-only');
end
local function readJsonFile(path)
@ -34,17 +34,6 @@ local function writeJsonFile(path, value)
return true;
end
local function confirmBeta()
print();
print('You are about to install the BETA branch (next).');
print('Beta builds may be unstable. Continue? (y/N)');
write('> ');
local answer = read();
if not answer then return false; end
answer = answer:lower();
return answer == 'y' or answer == 'yes';
end
local function fetchJson(url)
local response = http.get(url);
if not response then return nil end
@ -54,12 +43,12 @@ local function fetchJson(url)
return textutils.unserializeJSON(body);
end
local function fetchManifest(branch)
return fetchJson(REPO_BASE .. branch .. '/manifest.json');
local function fetchManifest()
return fetchJson(REPO_BASE .. 'manifest.json');
end
local function fetchDescriptor(branch, pkg)
return fetchJson(REPO_BASE .. branch .. '/packages/' .. pkg .. '/ccpm.json');
local function fetchDescriptor(pkg)
return fetchJson(REPO_BASE .. 'packages/' .. pkg .. '/ccpm.json');
end
local function ensureProgramsPath()
@ -76,7 +65,7 @@ end
-- Resolve a list of package names + their dependencies into install order
-- (deps first). Returns an ordered list of descriptors or nil, err.
local function resolvePackages(branch, names)
local function resolvePackages(names)
local ordered = {};
local state = {}; -- name -> 'visiting' | 'done'
@ -86,7 +75,7 @@ local function resolvePackages(branch, names)
return false, 'dependency cycle detected at ' .. name;
end
state[name] = 'visiting';
local desc = fetchDescriptor(branch, name);
local desc = fetchDescriptor(name);
if not desc then
return false, 'package not found: ' .. name;
end
@ -107,79 +96,57 @@ local function resolvePackages(branch, names)
end
-- Seed/refresh the default ccpm registry so it tracks the install branch.
local function seedCcpmConfig(branch)
local function seedCcpmConfig()
local cfg = readJsonFile(LOCAL_CONFIG_PATH) or { registries = {} };
cfg.registries = cfg.registries or {};
local found = false;
for _, r in ipairs(cfg.registries) do
if r.name == DEFAULT_REGISTRY_NAME then
r.type = 'gitea';
r.branch = branch;
r.branch = INSTALL_BRANCH;
found = true;
end
end
if not found then
table.insert(cfg.registries, 1, { name = DEFAULT_REGISTRY_NAME, type = 'gitea', branch = branch });
table.insert(cfg.registries, 1, { name = DEFAULT_REGISTRY_NAME, type = 'gitea', branch = INSTALL_BRANCH });
end
writeJsonFile(LOCAL_CONFIG_PATH, cfg);
end
local rawArgs = table.pack(...);
local forceBeta, forceStable = false, false;
local cpmOnly = false;
for i = 1, rawArgs.n do
local a = rawArgs[i];
if a == 'version' or a == '-version' or a == '--version' then
print('install-ccpm v' .. _VERSION);
print('install-trapos v' .. _VERSION);
return;
elseif a == 'help' or a == '-help' or a == '--help' then
printUsage();
return;
elseif a == '--beta' or a == '-beta' then
forceBeta = true;
elseif a == '--stable' or a == '-stable' then
forceStable = true;
elseif a == '--cpm-only' or a == '-cpm-only' then
cpmOnly = true;
elseif a ~= nil and a ~= '' then
printUsage();
return;
end
end
local localManifest = readJsonFile(LOCAL_MANIFEST_PATH);
local localBranch = localManifest and localManifest.branch or nil;
local branch;
if forceBeta then
branch = 'next';
if localBranch ~= 'next' then
if not confirmBeta() then
print('Aborted.');
return;
end
end
elseif forceStable then
branch = 'master';
else
branch = localBranch or 'master';
end
print('Fetching manifest from branch: ' .. branch);
local manifest = fetchManifest(branch);
print('Fetching manifest from branch: ' .. INSTALL_BRANCH);
local manifest = fetchManifest();
if not manifest then
print('Failed to fetch or parse manifest.json from ' .. branch);
print('Failed to fetch or parse manifest.json from ' .. INSTALL_BRANCH);
return;
end
local requested = { 'trapos-core' };
local resolved, resolveErr = resolvePackages(branch, requested);
local resolved, resolveErr = resolvePackages(requested);
if not resolved then
print('Failed to resolve packages: ' .. resolveErr);
return;
end
local REPO_PREFIX = REPO_BASE .. branch .. '/';
-- Legacy file cleanup (pre-manifest installs).
fs.delete('ping-server.lua');
fs.delete('ping.lua');
@ -212,7 +179,7 @@ for _, desc in ipairs(resolved) do
seenFile[filePath] = true;
allFiles[#allFiles + 1] = filePath;
fs.delete(filePath);
shell.execute('wget', REPO_PREFIX .. filePath, filePath);
shell.execute('wget', REPO_BASE .. filePath, filePath);
end
end
for _, srv in ipairs(desc.autostart or {}) do
@ -234,22 +201,34 @@ end
writeJsonFile(LOCAL_MANIFEST_PATH, {
name = manifest.name or 'TrapOS',
version = manifest.version or '?',
branch = branch,
branch = INSTALL_BRANCH,
files = allFiles,
autostart = autostart,
});
writeJsonFile(LOCAL_LOCK_PATH, { packages = lockPackages });
seedCcpmConfig(branch);
seedCcpmConfig();
ensureProgramsPath();
print();
print('=> ccpm installed (branch: ' .. branch .. ')');
print('=> ccpm installed (branch: ' .. INSTALL_BRANCH .. ')');
print('=> Default registry: ' .. DEFAULT_REGISTRY_NAME);
if cpmOnly then
print('=> Run: ccpm update');
print('=> Run: ccpm install trapos');
shell.setDir(previousDir);
return;
end
-- Full install: sync the registry and install the TrapOS meta-package.
shell.execute('ccpm', 'update');
shell.execute('ccpm', 'install', 'trapos');
if fs.exists('/startup/servers.lua') then
shell.execute('/startup/servers.lua');
end
shell.execute('trapos-postinstall');
shell.setDir(previousDir);

View File

@ -177,11 +177,10 @@ craftos-exec code:
exit 1
fi
# End-to-end install probe: drive the real ccpm bootstrap
# (install-ccpm.lua -> `ccpm update` -> `ccpm install trapos`) on a fresh,
# ephemeral CraftOS-PC state. Reflects the currently checked-out git branch:
# `master` -> --stable, `next` -> --beta (confirmation stubbed). Other
# branches are rejected because install-ccpm only knows master/next.
# End-to-end install probe: drive the real one-shot installer
# (install-trapos.lua, which bootstraps ccpm then runs `ccpm update` +
# `ccpm install trapos` itself) on a fresh, ephemeral CraftOS-PC state.
# Always installs from the published `master` branch (the only channel).
# Network-dependent and slower than `just test`, so not part of `just ci`.
# Override timeout with TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS (default 60).
# See ADR-0005.
@ -191,31 +190,15 @@ trapos-install: check-install
repo='{{justfile_directory()}}'
timeout_seconds="${TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS:-60}"
case "$timeout_seconds" in ''|*[!0-9]*) printf '%s\n' 'TRAP_CCLIBS_INSTALL_TIMEOUT_SECONDS must be a positive integer' >&2; exit 1 ;; esac
branch="$(git -C "$repo" rev-parse --abbrev-ref HEAD 2>/dev/null || echo '')"
case "$branch" in
master)
install_flag='--stable'
stub_read=''
;;
next)
install_flag='--beta'
stub_read="_G.read = function() return 'y' end; "
;;
*)
printf '%s\n' "trapos-install only supports the master or next branch (current: ${branch:-unknown}). install-ccpm.lua does not accept other branches." >&2
exit 1
;;
esac
printf '%s\n' "trapos-install: branch=$branch flag=$install_flag"
rom_arg=()
if [ "$(uname -s)" = "Darwin" ]; then
rom_arg=(--rom /Applications/CraftOS-PC.app/Contents/Resources)
fi
data_dir="$(mktemp -d)"
stage_dir="$(mktemp -d)"
cp "$repo/install-ccpm.lua" "$stage_dir/install-ccpm.lua"
cp "$repo/install-trapos.lua" "$stage_dir/install-trapos.lua"
tmp="$(mktemp)"
exec_code="${stub_read}shell.run('/staging/install-ccpm', '$install_flag'); shell.run('/programs/ccpm', 'update'); local ok = shell.run('/programs/ccpm', 'install', 'trapos'); if ok then print('__TRAPOS_INSTALL_OK__') end; os.shutdown()"
exec_code="shell.run('/staging/install-trapos'); if fs.exists('/trapos/manifest.json') and fs.exists('/trapos/ccpm.lock.json') then print('__TRAPOS_INSTALL_OK__') end; os.shutdown()"
craftos --directory "$data_dir" --headless "${rom_arg[@]}" --mount-ro "/staging=$stage_dir" --exec "$exec_code" >"$tmp" 2>&1 &
pid="$!"
( sleep "$timeout_seconds"; kill -TERM "$pid" >/dev/null 2>&1 ) &

View File

@ -1,7 +1,7 @@
{
"name": "TrapOS",
"version": "0.9.3",
"branch": "next",
"branch": "master",
"packages": [
"trapos"
]

View File

@ -1,6 +1,6 @@
{
"packages": {
"trapos-core": "0.5.1",
"trapos-core": "0.6.0",
"trapos-test": "0.2.1",
"trapos-boot": "0.3.3",
"trapos-net": "0.3.0",

View File

@ -1,6 +1,6 @@
{
"name": "trapos-core",
"version": "0.5.1",
"version": "0.6.0",
"description": "TrapOS base: package manager, event loop, upgrade and event tools",
"dependencies": [],
"files": [
@ -8,7 +8,8 @@
"apis/libccpm.lua",
"apis/libversion.lua",
"programs/ccpm.lua",
"programs/upgrade.lua",
"programs/trapos-upgrade.lua",
"programs/trapos-postinstall.lua",
"programs/events.lua"
],
"autostart": []

View File

@ -0,0 +1,50 @@
local createVersion = require('/apis/libversion');
local function printUsage()
print('trapos-postinstall usage:');
print();
print('\t\ttrapos-postinstall');
print('\t\ttrapos-postinstall version');
print('\t\ttrapos-postinstall help');
end
local command = ...;
if command == 'version' or command == '-version' or command == '--version' then
print('v' .. createVersion().forSelf());
return;
end
if command == 'help' or command == '-help' or command == '--help' then
printUsage();
return;
end
if command ~= nil and command ~= '' then
printUsage();
return;
end
local function readManifestVersion()
if not fs.exists('/trapos/manifest.json') then return nil; end
local f = fs.open('/trapos/manifest.json', 'r');
if not f then return nil; end
local data = f.readAll();
f.close();
local manifest = data and textutils.unserializeJSON(data);
return manifest and manifest.version or nil;
end
local version = readManifestVersion();
print();
if version then
print('=> TrapOS v' .. version .. ' installed.');
else
print('=> TrapOS installed.');
end
print();
print('Get started:');
print(' sandbox --help -- open the sandbox help');
print(' trapos-upgrade -- update and upgrade TrapOS');
print();

View File

@ -0,0 +1,38 @@
local createVersion = require('/apis/libversion');
local function printUsage()
print('trapos-upgrade usage:');
print();
print('\t\ttrapos-upgrade');
print('\t\ttrapos-upgrade --reboot');
print('\t\ttrapos-upgrade version');
print('\t\ttrapos-upgrade help');
end
local rawArgs = table.pack(...);
local reboot = false;
for i = 1, rawArgs.n do
local a = rawArgs[i];
if a == 'version' or a == '-version' or a == '--version' then
print('v' .. createVersion().forSelf());
return;
elseif a == 'help' or a == '-help' or a == '--help' then
printUsage();
return;
elseif a == '--reboot' or a == '-reboot' or a == '-r' then
reboot = true;
elseif a ~= nil and a ~= '' then
printUsage();
return;
end
end
shell.execute('ccpm', 'update');
shell.execute('ccpm', 'upgrade');
if reboot then
print();
print('=> Rebooting...');
os.reboot();
end

View File

@ -1,28 +0,0 @@
local createVersion = require('/apis/libversion');
local function printUsage()
print('upgrade usage:');
print();
print('\t\tupgrade');
print('\t\tupgrade version');
print('\t\tupgrade help');
end
local command = ...;
if command == 'version' or command == '-version' or command == '--version' then
print('v' .. createVersion().forSelf());
return;
end
if command == 'help' or command == '-help' or command == '--help' then
printUsage();
return;
end
if command ~= nil and command ~= '' then
printUsage();
return;
end
shell.execute('ccpm', 'upgrade');

View File

@ -43,31 +43,29 @@ local function fakeHttp(routes)
};
end
testlib.test('programs path resolves the ccpm command', function()
local previous = shell.path();
shell.setPath('/rom/programs:/programs');
local resolved = shell.resolveProgram('ccpm');
shell.setPath(previous);
testlib.assertEquals(resolved, 'programs/ccpm.lua');
end);
local INSTALL_BASE = 'https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/master/';
testlib.test('fresh beta bootstrap leaves ccpm runnable without trapos-boot', function()
local root = '/install-ccpm-test/fresh-beta';
fs.delete(root);
fs.makeDir(root);
local base = 'https://git.trapcloud.fr/guillaumearm/cc-libs/raw/branch/next/';
local routes = {
[base .. 'manifest.json'] = textutils.serializeJSON({ name = 'TrapOS', version = 'test' }),
[base .. 'packages/trapos-core/ccpm.json'] = textutils.serializeJSON({
local function installRoutes()
return {
[INSTALL_BASE .. 'manifest.json'] = textutils.serializeJSON({ name = 'TrapOS', version = 'test' }),
[INSTALL_BASE .. 'packages/trapos-core/ccpm.json'] = textutils.serializeJSON({
name = 'trapos-core',
version = '1',
dependencies = {},
files = { 'apis/libccpm.lua', 'programs/ccpm.lua' },
}),
[base .. 'apis/libccpm.lua'] = 'libccpm-body',
[base .. 'programs/ccpm.lua'] = 'ccpm-body',
[INSTALL_BASE .. 'apis/libccpm.lua'] = 'libccpm-body',
[INSTALL_BASE .. 'programs/ccpm.lua'] = 'ccpm-body',
};
end
-- Run install-trapos.lua inside a sandboxed env. `args` is a list of CLI args.
-- Returns { calls, root } for assertions.
local function runInstall(root, args)
fs.delete(root);
fs.makeDir(root);
local routes = installRoutes();
local calls = {
executes = {},
path = '/rom/programs',
@ -85,9 +83,11 @@ testlib.test('fresh beta bootstrap leaves ccpm runnable without trapos-boot', fu
setDir = function(path) calls.dir = path; end,
path = function() return calls.path; end,
setPath = function(path) calls.path = path; end,
execute = function(program, url, target)
calls.executes[#calls.executes + 1] = { program = program, url = url, target = target };
execute = function(program, ...)
local rest = { ... };
calls.executes[#calls.executes + 1] = { program = program, args = rest };
if program ~= 'wget' then return true; end
local url, target = rest[1], rest[2];
local body = routes[url];
if not body then return false; end
local dir = parentDir(target);
@ -100,22 +100,64 @@ testlib.test('fresh beta bootstrap leaves ccpm runnable without trapos-boot', fu
},
}, { __index = _G });
local chunk, loadErr = loadfile('/trapos/install-ccpm.lua', 't', env);
local chunk, loadErr = loadfile('/trapos/install-trapos.lua', 't', env);
if not chunk then error(loadErr, 0); end
local ok, err = pcall(chunk, '--beta');
local ok, err = pcall(chunk, table.unpack(args));
if not ok then error(err, 0); end
return calls;
end
local function findExecute(calls, program, firstArg)
for _, call in ipairs(calls.executes) do
if call.program == program then
if firstArg == nil or call.args[1] == firstArg then
return true;
end
end
end
return false;
end
testlib.test('programs path resolves the ccpm command', function()
local previous = shell.path();
shell.setPath('/rom/programs:/programs');
local resolved = shell.resolveProgram('ccpm');
shell.setPath(previous);
testlib.assertEquals(resolved, 'programs/ccpm.lua');
end);
testlib.test('fresh bootstrap seeds a gitea master registry and runs ccpm', function()
local root = '/install-trapos-test/full';
local calls = runInstall(root, {});
testlib.assertTrue(fs.exists(root .. '/programs/ccpm.lua'));
testlib.assertTrue(string.find(calls.path, '/programs', 1, true));
for _, call in ipairs(calls.executes) do
testlib.assertTrue(call.program ~= '/startup/servers.lua');
end
local f = fs.open(root .. '/trapos/ccpm.json', 'r');
local config = textutils.unserializeJSON(f.readAll());
f.close();
testlib.assertEquals(config.registries[1].branch, 'next');
testlib.assertEquals(config.registries[1].branch, 'master');
testlib.assertEquals(config.registries[1].type, 'gitea');
end);
testlib.test('default install runs update, install trapos and postinstall', function()
local root = '/install-trapos-test/default';
local calls = runInstall(root, {});
testlib.assertTrue(findExecute(calls, 'ccpm', 'update'));
testlib.assertTrue(findExecute(calls, 'ccpm', 'install'));
testlib.assertTrue(findExecute(calls, 'trapos-postinstall'));
end);
testlib.test('--cpm-only stops after the ccpm bootstrap', function()
local root = '/install-trapos-test/cpm-only';
local calls = runInstall(root, { '--cpm-only' });
testlib.assertTrue(fs.exists(root .. '/programs/ccpm.lua'));
testlib.assertTrue(not findExecute(calls, 'ccpm', 'update'));
testlib.assertTrue(not findExecute(calls, 'ccpm', 'install'));
testlib.assertTrue(not findExecute(calls, 'trapos-postinstall'));
end);
testlib.run();