diff --git a/build/image-recipe/build.sh b/build/image-recipe/build.sh index 2e4458587..641f16c7c 100755 --- a/build/image-recipe/build.sh +++ b/build/image-recipe/build.sh @@ -202,7 +202,7 @@ cat > config/hooks/normal/9000-install-startos.hook.chroot << EOF set -e -if [ "${NON_FREE}" = "1" ]; then +if [ "${NON_FREE}" = "1" ] && [ "${IB_TARGET_PLATFORM}" != "raspberrypi" ]; then # install a specific NVIDIA driver version # ---------------- configuration ---------------- diff --git a/build/raspberrypi/make-image.sh b/build/raspberrypi/make-image.sh deleted file mode 100755 index ec5ea4297..000000000 --- a/build/raspberrypi/make-image.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/bash - -set -e - -function partition_for () { - if [[ "$1" =~ [0-9]+$ ]]; then - echo "$1p$2" - else - echo "$1$2" - fi -} - -VERSION=$(cat VERSION.txt) -ENVIRONMENT=$(cat ENVIRONMENT.txt) -GIT_HASH=$(cat GIT_HASH.txt | head -c 7) -DATE=$(date +%Y%m%d) - -ROOT_PART_END=7217792 - -VERSION_FULL="$VERSION-$GIT_HASH" - -if [ -n "$ENVIRONMENT" ]; then - VERSION_FULL="$VERSION_FULL~$ENVIRONMENT" -fi - -TARGET_NAME=startos-${VERSION_FULL}-${DATE}_raspberrypi.img -TARGET_SIZE=$[($ROOT_PART_END+1)*512] - -rm -f $TARGET_NAME -truncate -s $TARGET_SIZE $TARGET_NAME -( - echo o - echo x - echo i - echo "0xcb15ae4d" - echo r - echo n - echo p - echo 1 - echo 2048 - echo 526335 - echo t - echo c - echo n - echo p - echo 2 - echo 526336 - echo $ROOT_PART_END - echo a - echo 1 - echo w -) | fdisk $TARGET_NAME -OUTPUT_DEVICE=$(sudo losetup --show -fP $TARGET_NAME) -sudo mkfs.ext4 `partition_for ${OUTPUT_DEVICE} 2` -sudo mkfs.vfat `partition_for ${OUTPUT_DEVICE} 1` - -TMPDIR=$(mktemp -d) - -sudo mount `partition_for ${OUTPUT_DEVICE} 2` $TMPDIR -sudo mkdir $TMPDIR/boot -sudo mount `partition_for ${OUTPUT_DEVICE} 1` $TMPDIR/boot -sudo unsquashfs -f -d $TMPDIR startos.raspberrypi.squashfs -REAL_GIT_HASH=$(cat $TMPDIR/usr/lib/startos/GIT_HASH.txt) -REAL_VERSION=$(cat $TMPDIR/usr/lib/startos/VERSION.txt) -REAL_ENVIRONMENT=$(cat $TMPDIR/usr/lib/startos/ENVIRONMENT.txt) -sudo sed -i 's| boot=startos| init=/usr/lib/startos/scripts/init_resize\.sh|' $TMPDIR/boot/cmdline.txt -sudo cp ./build/raspberrypi/fstab $TMPDIR/etc/ -sudo cp ./build/raspberrypi/init_resize.sh $TMPDIR/usr/lib/startos/scripts/init_resize.sh -sudo umount $TMPDIR/boot -sudo umount $TMPDIR -sudo losetup -d $OUTPUT_DEVICE - -if [ "$ALLOW_VERSION_MISMATCH" != 1 ]; then - if [ "$(cat GIT_HASH.txt)" != "$REAL_GIT_HASH" ]; then - >&2 echo "startos.raspberrypi.squashfs GIT_HASH.txt mismatch" - >&2 echo "expected $REAL_GIT_HASH (dpkg) found $(cat GIT_HASH.txt) (repo)" - exit 1 - fi - if [ "$(cat VERSION.txt)" != "$REAL_VERSION" ]; then - >&2 echo "startos.raspberrypi.squashfs VERSION.txt mismatch" - exit 1 - fi - if [ "$(cat ENVIRONMENT.txt)" != "$REAL_ENVIRONMENT" ]; then - >&2 echo "startos.raspberrypi.squashfs ENVIRONMENT.txt mismatch" - exit 1 - fi -fi \ No newline at end of file diff --git a/build/upload-ota.sh b/build/upload-ota.sh index 164ca8878..be36e52f6 100755 --- a/build/upload-ota.sh +++ b/build/upload-ota.sh @@ -15,10 +15,10 @@ if [ "$SKIP_DL" != "1" ]; then fi if [ -n "$RUN_ID" ]; then - for arch in aarch64 aarch64-nonfree riscv64 x86_64 x86_64-nonfree raspberrypi; do + for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree raspberrypi; do while ! gh run download -R Start9Labs/start-os $RUN_ID -n $arch.squashfs -D $(pwd); do sleep 1; done done - for arch in aarch64 aarch64-nonfree riscv64 x86_64 x86_64-nonfree; do + for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree; do while ! gh run download -R Start9Labs/start-os $RUN_ID -n $arch.iso -D $(pwd); do sleep 1; done done while ! gh run download -R Start9Labs/start-os $RUN_ID -n raspberrypi.img -D $(pwd); do sleep 1; done @@ -69,7 +69,7 @@ elif [ "$SKIP_UL" != "1" ]; then fi if [ "$SKIP_INDEX" != "1" ]; then - for arch in aarch64 aarch64-nonfree x86_64 x86_64-nonfree; do + for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree; do for file in *_$arch.squashfs *_$arch.iso; do start-cli --registry=https://alpha-registry-x.start9.com registry os asset add --platform=$arch --version=$VERSION $file https://github.com/Start9Labs/start-os/releases/download/v$VERSION/$(echo -n "$file" | sed 's/~/./g') done diff --git a/core/src/bins/mod.rs b/core/src/bins/mod.rs index 7f4e7da7f..de809e093 100644 --- a/core/src/bins/mod.rs +++ b/core/src/bins/mod.rs @@ -11,67 +11,89 @@ pub mod startd; pub mod tunnel; #[derive(Default)] -pub struct MultiExecutable(BTreeMap<&'static str, fn(VecDeque)>); +pub struct MultiExecutable { + default: Option<&'static str>, + bins: BTreeMap<&'static str, fn(VecDeque)>, +} impl MultiExecutable { pub fn enable_startd(&mut self) -> &mut Self { - self.0.insert("startd", startd::main); - self.0 + self.bins.insert("startd", startd::main); + self.bins .insert("embassyd", |_| deprecated::renamed("embassyd", "startd")); - self.0 + self.bins .insert("embassy-init", |_| deprecated::removed("embassy-init")); self } pub fn enable_start_cli(&mut self) -> &mut Self { - self.0.insert("start-cli", start_cli::main); - self.0.insert("embassy-cli", |_| { + self.bins.insert("start-cli", start_cli::main); + self.bins.insert("embassy-cli", |_| { deprecated::renamed("embassy-cli", "start-cli") }); - self.0 + self.bins .insert("embassy-sdk", |_| deprecated::removed("embassy-sdk")); self } pub fn enable_start_container(&mut self) -> &mut Self { - self.0.insert("start-container", container_cli::main); + self.bins.insert("start-container", container_cli::main); self } pub fn enable_start_registryd(&mut self) -> &mut Self { - self.0.insert("start-registryd", registry::main); + self.bins.insert("start-registryd", registry::main); self } pub fn enable_start_registry(&mut self) -> &mut Self { - self.0.insert("start-registry", registry::cli); + self.bins.insert("start-registry", registry::cli); self } pub fn enable_start_tunneld(&mut self) -> &mut Self { - self.0.insert("start-tunneld", tunnel::main); + self.bins.insert("start-tunneld", tunnel::main); self } pub fn enable_start_tunnel(&mut self) -> &mut Self { - self.0.insert("start-tunnel", tunnel::cli); + self.bins.insert("start-tunnel", tunnel::cli); + self + } + + pub fn set_default(&mut self, name: &str) -> &mut Self { + if let Some((name, _)) = self.bins.get_key_value(name) { + self.default = Some(*name); + } else { + panic!("{name} does not exist in MultiExecutable"); + } self } fn select_executable(&self, name: &str) -> Option)> { - self.0.get(&name).copied() + self.bins.get(&name).copied() } pub fn execute(&self) { + let mut popped = Vec::with_capacity(2); let mut args = std::env::args_os().collect::>(); + for _ in 0..2 { if let Some(s) = args.pop_front() { if let Some(name) = Path::new(&*s).file_name().and_then(|s| s.to_str()) { if name == "--contents" { - for name in self.0.keys() { + for name in self.bins.keys() { println!("{name}"); } + return; } if let Some(x) = self.select_executable(&name) { args.push_front(s); return x(args); } } + popped.push(s); } } + if let Some(default) = self.default { + while let Some(arg) = popped.pop() { + args.push_front(arg); + } + return self.bins[default](args); + } let args = std::env::args().collect::>(); eprintln!( "unknown executable: {}", diff --git a/core/src/main/start-cli.rs b/core/src/main/start-cli.rs index d1c5741ab..72b88147c 100644 --- a/core/src/main/start-cli.rs +++ b/core/src/main/start-cli.rs @@ -15,5 +15,8 @@ fn main() { }) { PREFER_DOCKER.set(true).ok(); } - MultiExecutable::default().enable_start_cli().execute() + MultiExecutable::default() + .enable_start_cli() + .set_default("start-cli") + .execute() } diff --git a/core/src/main/start-container.rs b/core/src/main/start-container.rs index 5d812980e..e8f26a343 100644 --- a/core/src/main/start-container.rs +++ b/core/src/main/start-container.rs @@ -3,5 +3,6 @@ use startos::bins::MultiExecutable; fn main() { MultiExecutable::default() .enable_start_container() + .set_default("start-container") .execute() } diff --git a/core/src/registry/migrations/m_00_package_signer_scope.rs b/core/src/registry/migrations/m_00_package_signer_scope.rs index d1db9f7b4..a688eb352 100644 --- a/core/src/registry/migrations/m_00_package_signer_scope.rs +++ b/core/src/registry/migrations/m_00_package_signer_scope.rs @@ -5,9 +5,6 @@ use crate::prelude::*; pub struct PackageSignerScopeMigration; impl RegistryMigration for PackageSignerScopeMigration { - fn name(&self) -> &'static str { - "PackageSignerScopeMigration" - } fn action(&self, db: &mut Value) -> Result<(), Error> { for (_, info) in db["index"]["package"]["packages"] .as_object_mut() diff --git a/core/src/registry/migrations/m_01_package_s9pk_array.rs b/core/src/registry/migrations/m_01_registry_asset_array.rs similarity index 59% rename from core/src/registry/migrations/m_01_package_s9pk_array.rs rename to core/src/registry/migrations/m_01_registry_asset_array.rs index 42a3d3e1c..779a3c86f 100644 --- a/core/src/registry/migrations/m_01_package_s9pk_array.rs +++ b/core/src/registry/migrations/m_01_registry_asset_array.rs @@ -1,14 +1,10 @@ use imbl::vector; -use imbl_value::json; use super::RegistryMigration; use crate::prelude::*; -pub struct PackageS9pkArray; -impl RegistryMigration for PackageS9pkArray { - fn name(&self) -> &'static str { - "PackageS9pkArray" - } +pub struct RegistryAssetArray; +impl RegistryMigration for RegistryAssetArray { fn action(&self, db: &mut Value) -> Result<(), Error> { for (_, info) in db["index"]["package"]["packages"] .as_object_mut() @@ -22,6 +18,17 @@ impl RegistryMigration for PackageS9pkArray { info["s9pks"] = Value::Array(vector![Value::Array(vector![hw_req, s9pk])]); } } + for (_, info) in db["index"]["os"]["versions"] + .as_object_mut() + .unwrap() + .iter_mut() + { + for asset_ty in ["iso", "squashfs", "img"] { + for (_, info) in info[asset_ty].as_object_mut().unwrap().iter_mut() { + info["urls"] = Value::Array(vector![info["url"].take()]); + } + } + } Ok(()) } diff --git a/core/src/registry/migrations/mod.rs b/core/src/registry/migrations/mod.rs index 4620baa3e..4cabcdf47 100644 --- a/core/src/registry/migrations/mod.rs +++ b/core/src/registry/migrations/mod.rs @@ -4,25 +4,29 @@ use crate::prelude::*; use crate::registry::RegistryDatabase; mod m_00_package_signer_scope; -mod m_01_package_s9pk_array; +mod m_01_registry_asset_array; pub trait RegistryMigration { - fn name(&self) -> &'static str; + fn name(&self) -> &'static str { + let val = std::any::type_name_of_val(self); + val.rsplit_once("::").map_or(val, |v| v.1) + } fn action(&self, db: &mut Value) -> Result<(), Error>; } pub const MIGRATIONS: &[&dyn RegistryMigration] = &[ &m_00_package_signer_scope::PackageSignerScopeMigration, - &m_01_package_s9pk_array::PackageS9pkArray, + &m_01_registry_asset_array::RegistryAssetArray, ]; #[instrument(skip_all)] pub fn run_migrations(db: &mut Model) -> Result<(), Error> { let mut migrations = db.as_migrations().de().unwrap_or_default(); for migration in MIGRATIONS { - if !migrations.contains(migration.name()) { + let name = migration.name(); + if !migrations.contains(name) { migration.action(ModelExt::as_value_mut(db))?; - migrations.insert(migration.name().into()); + migrations.insert(name.into()); } } let mut db_deser = db.de()?; diff --git a/core/src/registry/os/version/mod.rs b/core/src/registry/os/version/mod.rs index d6b68652f..292be863c 100644 --- a/core/src/registry/os/version/mod.rs +++ b/core/src/registry/os/version/mod.rs @@ -187,7 +187,8 @@ pub async fn get_version( platform, device_info, }: GetOsVersionParams, -) -> Result, Error> { +) -> Result // BTreeMap +{ let source = source.or_else(|| device_info.as_ref().map(|d| d.os.version.clone())); let platform = platform.or_else(|| device_info.as_ref().map(|d| d.os.platform.clone())); if let (Some(pool), Some(server_id), Some(arch)) = (&ctx.pool, server_id, &platform) { @@ -202,33 +203,63 @@ pub async fn get_version( .with_kind(ErrorKind::Database)?; } let target = target.unwrap_or(VersionRange::Any); - ctx.db - .peek() - .await - .into_index() - .into_os() - .into_versions() - .into_entries()? - .into_iter() - .map(|(v, i)| i.de().map(|i| (v, i))) - .filter_ok(|(version, info)| { - platform - .as_ref() - .map_or(true, |p| info.squashfs.contains_key(p)) - && version.satisfies(&target) - && source + let mut res = to_value::>( + &ctx.db + .peek() + .await + .into_index() + .into_os() + .into_versions() + .into_entries()? + .into_iter() + .map(|(v, i)| i.de().map(|i| (v, i))) + .filter_ok(|(version, info)| { + platform .as_ref() - .map_or(true, |s| s.satisfies(&info.source_version)) - }) - .collect() + .map_or(true, |p| info.squashfs.contains_key(p)) + && version.satisfies(&target) + && source + .as_ref() + .map_or(true, |s| s.satisfies(&info.source_version)) + }) + .collect::>()?, + )?; + + // TODO: remove + if device_info.map_or(false, |d| { + "0.4.0-alpha.17" + .parse::() + .map_or(false, |v| d.os.version <= v) + }) { + for (_, v) in res + .as_object_mut() + .into_iter() + .map(|v| v.iter_mut()) + .flatten() + { + for asset_ty in ["iso", "squashfs", "img"] { + for (_, v) in v[asset_ty] + .as_object_mut() + .into_iter() + .map(|v| v.iter_mut()) + .flatten() + { + v["url"] = v["urls"][0].clone(); + } + } + } + } + Ok(res) } pub fn display_version_info( params: WithIoFormat, - info: BTreeMap, + info: Value, // BTreeMap, ) -> Result<(), Error> { use prettytable::*; + let info = from_value::>(info)?; + if let Some(format) = params.format { return display_serializable(format, info); } diff --git a/core/src/registry/package/get.rs b/core/src/registry/package/get.rs index 5c6db4a8e..6b099a063 100644 --- a/core/src/registry/package/get.rs +++ b/core/src/registry/package/get.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::path::{Path, PathBuf}; use clap::{Parser, ValueEnum}; -use exver::{ExtendedVersion, VersionRange}; +use exver::{ExtendedVersion, Version, VersionRange}; use imbl_value::{InternedString, json}; use itertools::Itertools; use serde::{Deserialize, Serialize}; @@ -247,17 +247,17 @@ pub async fn get_package(ctx: RegistryContext, params: GetPackageParams) -> Resu package_other.insert(version.into(), (info, assets)); } } - if let Some(id) = params.id { + let mut res = if let Some(id) = ¶ms.id { let categories = peek .as_index() .as_package() .as_packages() - .as_idx(&id) + .as_idx(id) .map(|p| p.as_categories().de()) .transpose()? .unwrap_or_default(); let best = best - .remove(&id) + .remove(id) .unwrap_or_default() .into_iter() .map(|(k, (i, a))| { @@ -271,7 +271,7 @@ pub async fn get_package(ctx: RegistryContext, params: GetPackageParams) -> Resu )) }) .try_collect()?; - let other = other.remove(&id).unwrap_or_default(); + let other = other.remove(id).unwrap_or_default(); match params.other_versions { PackageDetailLevel::None => to_value(&GetPackageResponse { categories, @@ -431,7 +431,47 @@ pub async fn get_package(ctx: RegistryContext, params: GetPackageParams) -> Resu .try_collect::<_, GetPackagesResponseFull, _>()?, ), } + }?; + + // TODO: remove + if true + || params.device_info.map_or(false, |d| { + "0.4.0-alpha.17" + .parse::() + .map_or(false, |v| d.os.version <= v) + }) + { + let patch = |v: &mut Value| { + for kind in ["best", "otherVersions"] { + for (_, v) in v[kind] + .as_object_mut() + .into_iter() + .map(|v| v.iter_mut()) + .flatten() + { + let Some(mut tup) = v["s9pks"].get(0).cloned() else { + continue; + }; + v["s9pk"] = tup[1].take(); + v["hardwareRequirements"] = tup[0].take(); + v["s9pk"]["url"] = v["s9pk"]["urls"][0].clone(); + } + } + }; + if params.id.is_some() { + patch(&mut res); + } else { + for (_, v) in res + .as_object_mut() + .into_iter() + .map(|v| v.iter_mut()) + .flatten() + { + patch(v); + } + } } + Ok(res) } pub fn display_package_info( diff --git a/patch-db b/patch-db index bdb5a1011..05c93290c 160000 --- a/patch-db +++ b/patch-db @@ -1 +1 @@ -Subproject commit bdb5a10114a085e86b52ab72e9691ec0db63c4dd +Subproject commit 05c93290c759bdf5e7308a24cf0d4a440ed287a0