mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
* bugfixes * update fe types * implement new registry types in marketplace and ui * fix marketplace types to have default params * add alt implementation toggle * merge cleanup * more cleanup and notes * fix build * cleanup sync with next/minor * add exver JS parser * parse ValidExVer to string * update types to interface * add VersionRange and comparative functions * Parse ExtendedVersion from string * add conjunction, disjunction, and inversion logic * consider flavor in satisfiedBy fn * consider prerelease for ordering * add compare fn for sorting * rename fns for consistency * refactoring * update compare fn to return null if flavors don't match * begin simplifying dependencies * under construction * wip * add dependency metadata to CurrentDependencyInfo * ditch inheritance for recursive VersionRange constructor. Recursive 'satisfiedBy' fn wip * preprocess manifest * misc fixes * use sdk version as osVersion in manifest * chore: Change the type to just validate and not generate all solutions. * add publishedAt * fix pegjs exports * integrate exver into sdk * misc fixes * complete satisfiedBy fn * refactor - use greaterThanOrEqual and lessThanOrEqual fns * fix tests * update dependency details * update types * remove interim types * rename alt implementation to flavor * cleanup os update * format exver.ts * add s9pk parsing endpoints * fix build * update to exver * exver and bug fixes * update static endpoints + cleanup * cleanup * update static proxy verification * make mocks more robust; fix dep icon fallback; cleanup * refactor alert versions and update fixtures * registry bugfixes * misc fixes * cleanup unused * convert patchdb ui seed to camelCase * update otherVersions type * change otherVersions: null to 'none' * refactor and complete feature * improve static endpoints * fix install params * mask systemd-networkd-wait-online * fix static file fetching * include non-matching versions in otherVersions * convert release notes to modal and clean up displayExver * alert for no other versions * Fix ack-instructions casing * fix indeterminate loader on service install --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: Shadowy Super Coder <musashidisciple@proton.me> Co-authored-by: Aiden McClelland <3732071+dr-bonez@users.noreply.github.com> Co-authored-by: J H <dragondef@gmail.com> Co-authored-by: Matt Hill <mattnine@protonmail.com>
232 lines
6.8 KiB
Rust
232 lines
6.8 KiB
Rust
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use clap::Parser;
|
|
use models::ImageId;
|
|
use rpc_toolkit::{from_fn_async, Empty, HandlerExt, ParentHandler};
|
|
use serde::{Deserialize, Serialize};
|
|
use ts_rs::TS;
|
|
|
|
use crate::context::CliContext;
|
|
use crate::prelude::*;
|
|
use crate::s9pk::manifest::Manifest;
|
|
use crate::s9pk::merkle_archive::source::multi_cursor_file::MultiCursorFile;
|
|
use crate::s9pk::v2::pack::ImageConfig;
|
|
use crate::s9pk::v2::SIG_CONTEXT;
|
|
use crate::util::io::{create_file, open_file, TmpDir};
|
|
use crate::util::serde::{apply_expr, HandlerExtSerde};
|
|
use crate::util::Apply;
|
|
|
|
pub const SKIP_ENV: &[&str] = &["TERM", "container", "HOME", "HOSTNAME"];
|
|
|
|
pub fn s9pk() -> ParentHandler<CliContext> {
|
|
ParentHandler::new()
|
|
.subcommand("pack", from_fn_async(super::v2::pack::pack).no_display())
|
|
.subcommand(
|
|
"list-ingredients",
|
|
from_fn_async(super::v2::pack::list_ingredients).with_custom_display_fn(
|
|
|_, ingredients| {
|
|
ingredients
|
|
.into_iter()
|
|
.map(Some)
|
|
.apply(|i| itertools::intersperse(i, None))
|
|
.for_each(|i| {
|
|
if let Some(p) = i {
|
|
print!("{}", p.display())
|
|
} else {
|
|
print!(" ")
|
|
}
|
|
});
|
|
println!();
|
|
Ok(())
|
|
},
|
|
),
|
|
)
|
|
.subcommand("edit", edit())
|
|
.subcommand("inspect", inspect())
|
|
.subcommand("convert", from_fn_async(convert).no_display())
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Parser)]
|
|
struct S9pkPath {
|
|
s9pk: PathBuf,
|
|
}
|
|
|
|
fn edit() -> ParentHandler<CliContext, S9pkPath> {
|
|
let only_parent = |a, _| a;
|
|
ParentHandler::new()
|
|
.subcommand(
|
|
"add-image",
|
|
from_fn_async(add_image)
|
|
.with_inherited(only_parent)
|
|
.no_display(),
|
|
)
|
|
.subcommand(
|
|
"manifest",
|
|
from_fn_async(edit_manifest)
|
|
.with_inherited(only_parent)
|
|
.with_display_serializable(),
|
|
)
|
|
}
|
|
|
|
fn inspect() -> ParentHandler<CliContext, S9pkPath> {
|
|
let only_parent = |a, _| a;
|
|
ParentHandler::new()
|
|
.subcommand(
|
|
"file-tree",
|
|
from_fn_async(file_tree)
|
|
.with_inherited(only_parent)
|
|
.with_display_serializable(),
|
|
)
|
|
.subcommand(
|
|
"cat",
|
|
from_fn_async(cat).with_inherited(only_parent).no_display(),
|
|
)
|
|
.subcommand(
|
|
"manifest",
|
|
from_fn_async(inspect_manifest)
|
|
.with_inherited(only_parent)
|
|
.with_display_serializable(),
|
|
)
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Parser, TS)]
|
|
struct AddImageParams {
|
|
id: ImageId,
|
|
#[command(flatten)]
|
|
config: ImageConfig,
|
|
}
|
|
async fn add_image(
|
|
ctx: CliContext,
|
|
AddImageParams { id, config }: AddImageParams,
|
|
S9pkPath { s9pk: s9pk_path }: S9pkPath,
|
|
) -> Result<(), Error> {
|
|
let mut s9pk = super::load(
|
|
MultiCursorFile::from(open_file(&s9pk_path).await?),
|
|
|| ctx.developer_key().cloned(),
|
|
None,
|
|
)
|
|
.await?;
|
|
s9pk.as_manifest_mut().images.insert(id, config);
|
|
let tmp_dir = Arc::new(TmpDir::new().await?);
|
|
s9pk.load_images(tmp_dir.clone()).await?;
|
|
s9pk.validate_and_filter(None)?;
|
|
let tmp_path = s9pk_path.with_extension("s9pk.tmp");
|
|
let mut tmp_file = create_file(&tmp_path).await?;
|
|
s9pk.serialize(&mut tmp_file, true).await?;
|
|
drop(s9pk);
|
|
tmp_file.sync_all().await?;
|
|
tokio::fs::rename(&tmp_path, &s9pk_path).await?;
|
|
|
|
tmp_dir.gc().await?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Parser, TS)]
|
|
struct EditManifestParams {
|
|
expression: String,
|
|
}
|
|
async fn edit_manifest(
|
|
ctx: CliContext,
|
|
EditManifestParams { expression }: EditManifestParams,
|
|
S9pkPath { s9pk: s9pk_path }: S9pkPath,
|
|
) -> Result<Manifest, Error> {
|
|
let mut s9pk = super::load(
|
|
MultiCursorFile::from(open_file(&s9pk_path).await?),
|
|
|| ctx.developer_key().cloned(),
|
|
None,
|
|
)
|
|
.await?;
|
|
let old = serde_json::to_value(s9pk.as_manifest()).with_kind(ErrorKind::Serialization)?;
|
|
*s9pk.as_manifest_mut() = serde_json::from_value(apply_expr(old.into(), &expression)?.into())
|
|
.with_kind(ErrorKind::Serialization)?;
|
|
let manifest = s9pk.as_manifest().clone();
|
|
let tmp_path = s9pk_path.with_extension("s9pk.tmp");
|
|
let mut tmp_file = create_file(&tmp_path).await?;
|
|
s9pk.as_archive_mut()
|
|
.set_signer(ctx.developer_key()?.clone(), SIG_CONTEXT);
|
|
s9pk.serialize(&mut tmp_file, true).await?;
|
|
tmp_file.sync_all().await?;
|
|
tokio::fs::rename(&tmp_path, &s9pk_path).await?;
|
|
|
|
Ok(manifest)
|
|
}
|
|
|
|
async fn file_tree(
|
|
ctx: CliContext,
|
|
_: Empty,
|
|
S9pkPath { s9pk: s9pk_path }: S9pkPath,
|
|
) -> Result<Vec<PathBuf>, Error> {
|
|
let s9pk = super::load(
|
|
MultiCursorFile::from(open_file(&s9pk_path).await?),
|
|
|| ctx.developer_key().cloned(),
|
|
None,
|
|
)
|
|
.await?;
|
|
Ok(s9pk.as_archive().contents().file_paths(""))
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Parser, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[command(rename_all = "kebab-case")]
|
|
struct CatParams {
|
|
file_path: PathBuf,
|
|
}
|
|
async fn cat(
|
|
ctx: CliContext,
|
|
CatParams { file_path }: CatParams,
|
|
S9pkPath { s9pk: s9pk_path }: S9pkPath,
|
|
) -> Result<(), Error> {
|
|
use crate::s9pk::merkle_archive::source::FileSource;
|
|
|
|
let s9pk = super::load(
|
|
MultiCursorFile::from(open_file(&s9pk_path).await?),
|
|
|| ctx.developer_key().cloned(),
|
|
None,
|
|
)
|
|
.await?;
|
|
tokio::io::copy(
|
|
&mut s9pk
|
|
.as_archive()
|
|
.contents()
|
|
.get_path(&file_path)
|
|
.or_not_found(&file_path.display())?
|
|
.as_file()
|
|
.or_not_found(&file_path.display())?
|
|
.reader()
|
|
.await?,
|
|
&mut tokio::io::stdout(),
|
|
)
|
|
.await?;
|
|
Ok(())
|
|
}
|
|
|
|
async fn inspect_manifest(
|
|
ctx: CliContext,
|
|
_: Empty,
|
|
S9pkPath { s9pk: s9pk_path }: S9pkPath,
|
|
) -> Result<Manifest, Error> {
|
|
let s9pk = super::load(
|
|
MultiCursorFile::from(open_file(&s9pk_path).await?),
|
|
|| ctx.developer_key().cloned(),
|
|
None,
|
|
)
|
|
.await?;
|
|
Ok(s9pk.as_manifest().clone())
|
|
}
|
|
|
|
async fn convert(ctx: CliContext, S9pkPath { s9pk: s9pk_path }: S9pkPath) -> Result<(), Error> {
|
|
let mut s9pk = super::load(
|
|
MultiCursorFile::from(open_file(&s9pk_path).await?),
|
|
|| ctx.developer_key().cloned(),
|
|
None,
|
|
)
|
|
.await?;
|
|
let tmp_path = s9pk_path.with_extension("s9pk.tmp");
|
|
s9pk.serialize(&mut create_file(&tmp_path).await?, true)
|
|
.await?;
|
|
tokio::fs::rename(tmp_path, s9pk_path).await?;
|
|
Ok(())
|
|
}
|