#!/usr/bin/env bash
export DS_GRIDDESIGN_CHANNEL=stable
#!/usr/bin/env bash
# Public bootstrap for the small manager; Core owns component installation.
set -euo pipefail
die(){ printf 'ERROR: %s\n' "$*" >&2;exit 1; }
channel=${DS_GRIDDESIGN_CHANNEL:-stable}
[[ "$channel" == stable || "$channel" == canary ]] || die manager_lane_invalid
component=${DS_INSTALLATION_MANAGER_COMPONENT:-desktop}
[[ "$component" == desktop || "$component" == core ]] || die manager_component_invalid
[[ $(uname -s):$(uname -m) == Linux:x86_64 ]] || die manager_platform_unavailable
for tool in curl python3 bash;do command -v "$tool" >/dev/null || die "$tool is required";done
origin=https://datasolutions.rw
[[ "$channel" != canary ]] || origin=https://electrification-rural.web.app
work=$(mktemp -d "${TMPDIR:-/var/tmp}/ds-manager-bootstrap.XXXXXXXX")
chmod 700 "$work"
trap '[[ "$work" == */ds-manager-bootstrap.* ]] && rm -rf -- "$work"' EXIT
fetch(){ curl --proto '=https' --max-time 60 --max-filesize "$3" -fsS "$origin$1" -o "$2" || die manager_download_failed; }
fetch "/installation-manager/$channel.json" "$work/publication.json" 65536
python3 - "$work/publication.json" "$channel" > "$work/assets.tsv" <<'PY_PUBLICATION' || die manager_publication_invalid
import datetime,json,re,sys
from pathlib import Path
p=Path(sys.argv[1]);assert 0<p.stat().st_size<=65536
m=json.loads(p.read_bytes());lane=sys.argv[2]
assert set(m)=={'schema','channel','product_id','published_at','platforms'}
assert m['schema']=='ds.installation-manager-publication/v1' and m['channel']==lane
assert m['product_id']=='rw.datasolutions.installation-manager'+('.canary' if lane=='canary' else '')
assert datetime.datetime.fromisoformat(m['published_at'].replace('Z','+00:00')).tzinfo
assert set(m['platforms'])=={'windows','linux'}
unit=m['platforms']['linux'];assert set(unit)=={'arch','package_receipt_sha256','source_revisions','assets','bootstrap'} and unit['arch']=='x86_64'
sha=unit['package_receipt_sha256'];assert re.fullmatch('[a-f0-9]{64}',sha)
bootstrap=unit['bootstrap'];assert set(bootstrap)=={'filename','path','size_bytes','sha256'}
assert bootstrap['filename']=='install-manager.sh' and re.fullmatch('[a-f0-9]{64}',bootstrap['sha256'])
assert type(bootstrap['size_bytes']) is int and 0<bootstrap['size_bytes']<=131072
assert bootstrap['path']=='/installation-manager/'+bootstrap['sha256']+'/install-manager.sh'
assert set(unit['source_revisions'])=={'ds-cli','ds-web'} and all(re.fullmatch('[a-f0-9]{40}',v) for v in unit['source_revisions'].values())
names={'package.receipt.json','ds-install-manager.sh','install-core.sh','install-desktop.sh'};assets=unit['assets']
assert len(assets)==len(names) and {a['filename'] for a in assets}==names
for a in assets:
 assert set(a)=={'filename','size_bytes','sha256','path'}
 assert type(a['size_bytes']) is int and 0<a['size_bytes']<=131072 and re.fullmatch('[a-f0-9]{64}',a['sha256'])
 assert a['path']=='/installation-manager/'+sha+'/'+a['filename']
 if a['filename']=='package.receipt.json':assert a['sha256']==sha and a['size_bytes']<=65536
 print(a['filename'],a['size_bytes'],a['path'],sep='\t')
PY_PUBLICATION
while IFS=$'\t' read -r name size path;do fetch "$path" "$work/$name" "$size";done < "$work/assets.tsv"
python3 - "$work" <<'PY_PACKAGE' || die manager_package_invalid
import hashlib,json,pathlib,sys
p=pathlib.Path(sys.argv[1]);m=json.loads((p/'publication.json').read_bytes());unit=m['platforms']['linux']
for a in unit['assets']:
 f=p/a['filename'];assert f.is_file() and not f.is_symlink()
 b=f.read_bytes();assert len(b)==a['size_bytes'] and hashlib.sha256(b).hexdigest()==a['sha256']
r=json.loads((p/'package.receipt.json').read_bytes())
assert set(r)=={'schema','platform','arch','source_sha','web_source_sha','files'}
assert r['schema']=='ds.installation-manager-package/v1' and r['platform']=='linux' and r['arch']=='x86_64'
assert r['source_sha']==unit['source_revisions']['ds-cli'] and r['web_source_sha']==unit['source_revisions']['ds-web']
expected=[{k:a[k] for k in ['filename','size_bytes','sha256']} for a in unit['assets'] if a['filename']!='package.receipt.json']
assert sorted(r['files'],key=lambda a:a['filename'])==sorted(expected,key=lambda a:a['filename'])
PY_PACKAGE
bash "$work/ds-install-manager.sh" setup core "$channel" --yes
installed="${XDG_DATA_HOME:-$HOME/.local/share}/ds-installation-manager/$channel/ds-install-manager.sh"
bash "$installed" install "$component" "$channel" --yes
