update ota script, rbind for dependency mounts, cli list-ingredients fix, and formatting

This commit is contained in:
Aiden McClelland
2026-01-28 16:09:37 -07:00
parent c65db31fd9
commit d232b91d31
45 changed files with 446 additions and 157 deletions

View File

@@ -15,13 +15,12 @@ if [ "$SKIP_DL" != "1" ]; then
fi
if [ -n "$RUN_ID" ]; then
for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree raspberrypi; do
for arch in aarch64 aarch64-nonfree riscv64 x86_64 x86_64-nonfree; 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 riscv64-nonfree x86_64 x86_64-nonfree; do
for arch in aarch64 aarch64-nonfree riscv64 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
fi
if [ -n "$ST_RUN_ID" ]; then
@@ -57,31 +56,23 @@ start-cli --registry=https://alpha-registry-x.start9.com registry os version add
if [ "$SKIP_UL" = "2" ]; then
exit 2
elif [ "$SKIP_UL" != "1" ]; then
for file in *.squashfs *.iso *.deb start-cli_*; do
for file in *.deb start-cli_*; do
gh release upload -R Start9Labs/start-os v$VERSION $file
done
for file in *.img; do
if ! [ -f $file.gz ]; then
cat $file | pigz > $file.gz
fi
gh release upload -R Start9Labs/start-os v$VERSION $file.gz
for file in *.iso *.squashfs; do
s3cmd put -P $file s3://startos-images/v$VERSION/$file
done
fi
if [ "$SKIP_INDEX" != "1" ]; then
for arch in aarch64 aarch64-nonfree riscv64 riscv64-nonfree x86_64 x86_64-nonfree; do
for arch in aarch64 aarch64-nonfree riscv64 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
done
for arch in raspberrypi; do
for file in *_$arch.squashfs; 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')
start-cli --registry=https://alpha-registry-x.start9.com registry os asset add --platform=$arch --version=$VERSION $file https://startos-images.nyc3.cdn.digitaloceanspaces.com/v$VERSION/$file
done
done
fi
for file in *.iso *.img *.img.gz *.squashfs *.deb start-cli_*; do
for file in *.iso *.squashfs *.deb start-cli_*; do
gpg -u 7CFFDA41CA66056A --detach-sign --armor -o "${file}.asc" "$file"
done
@@ -90,20 +81,30 @@ tar -czvf signatures.tar.gz *.asc
gh release upload -R Start9Labs/start-os v$VERSION signatures.tar.gz
cat << EOF
# ISO Downloads
- [x86_64/AMD64](https://startos-images.nyc3.cdn.digitaloceanspaces.com/v$VERSION/$(ls *_x86_64-nonfree.iso))
- [x86_64/AMD64 (Slim/FOSS-Only)](https://startos-images.nyc3.cdn.digitaloceanspaces.com/v$VERSION/$(ls *_x86_64.iso) "Without proprietary software or drivers")
- [aarch64/ARM64](https://startos-images.nyc3.cdn.digitaloceanspaces.com/v$VERSION/$(ls *_aarch64-nonfree.iso))
- [aarch64/ARM64 (Slim/FOSS-Only)](https://startos-images.nyc3.cdn.digitaloceanspaces.com/v$VERSION/$(ls *_aarch64.iso) "Without proprietary software or drivers")
- [RISCV64 (RVA23)](https://startos-images.nyc3.cdn.digitaloceanspaces.com/v$VERSION/$(ls *_riscv64.iso))
EOF
cat << 'EOF'
# StartOS Checksums
## SHA-256
```
EOF
sha256sum *.iso *.img *img.gz *.squashfs
sha256sum *.iso *.squashfs
cat << 'EOF'
```
## BLAKE-3
```
EOF
b3sum *.iso *.img *.img.gz *.squashfs
b3sum *.iso *.squashfs
cat << 'EOF'
```
@@ -138,5 +139,4 @@ EOF
b3sum start-cli_*
cat << 'EOF'
```
EOF
EOF

View File

@@ -180,7 +180,13 @@ pub async fn update(
.as_idx_mut(&id)
.ok_or_else(|| {
Error::new(
eyre!("{}", t!("backup.target.cifs.target-not-found", id = BackupTargetId::Cifs { id })),
eyre!(
"{}",
t!(
"backup.target.cifs.target-not-found",
id = BackupTargetId::Cifs { id }
)
),
ErrorKind::NotFound,
)
})?

View File

@@ -1,10 +1,7 @@
use rust_i18n::t;
pub fn renamed(old: &str, new: &str) -> ! {
eprintln!(
"{}",
t!("bins.deprecated.renamed", old = old, new = new)
);
eprintln!("{}", t!("bins.deprecated.renamed", old = old, new = new));
std::process::exit(1)
}

View File

@@ -4,8 +4,8 @@ use std::time::Duration;
use clap::Parser;
use color_eyre::eyre::eyre;
use rust_i18n::t;
use futures::{FutureExt, TryFutureExt};
use rust_i18n::t;
use tokio::signal::unix::signal;
use tracing::instrument;

View File

@@ -160,21 +160,23 @@ impl CliContext {
if !path.exists() {
continue;
}
let pair = <ed25519::KeypairBytes as ed25519::pkcs8::DecodePrivateKey>::from_pkcs8_pem(
&std::fs::read_to_string(path)?,
)
.with_kind(crate::ErrorKind::Pem)?;
let secret = ed25519_dalek::SecretKey::try_from(&pair.secret_key[..]).map_err(|_| {
Error::new(
eyre!("{}", t!("context.cli.pkcs8-key-incorrect-length")),
ErrorKind::OpenSsl,
let pair =
<ed25519::KeypairBytes as ed25519::pkcs8::DecodePrivateKey>::from_pkcs8_pem(
&std::fs::read_to_string(path)?,
)
})?;
return Ok(secret.into())
.with_kind(crate::ErrorKind::Pem)?;
let secret =
ed25519_dalek::SecretKey::try_from(&pair.secret_key[..]).map_err(|_| {
Error::new(
eyre!("{}", t!("context.cli.pkcs8-key-incorrect-length")),
ErrorKind::OpenSsl,
)
})?;
return Ok(secret.into());
}
Err(Error::new(
eyre!("{}", t!("context.cli.developer-key-does-not-exist")),
crate::ErrorKind::Uninitialized
crate::ErrorKind::Uninitialized,
))
})
}
@@ -195,8 +197,12 @@ impl CliContext {
.into());
}
};
url.set_scheme(ws_scheme)
.map_err(|_| Error::new(eyre!("{}", t!("context.cli.cannot-set-url-scheme")), crate::ErrorKind::ParseUrl))?;
url.set_scheme(ws_scheme).map_err(|_| {
Error::new(
eyre!("{}", t!("context.cli.cannot-set-url-scheme")),
crate::ErrorKind::ParseUrl,
)
})?;
url.path_segments_mut()
.map_err(|_| eyre!("Url cannot be base"))
.with_kind(crate::ErrorKind::ParseUrl)?

View File

@@ -27,7 +27,10 @@ impl DiagnosticContext {
disk_guid: Option<InternedString>,
error: Error,
) -> Result<Self, Error> {
tracing::error!("{}", t!("context.diagnostic.starting-diagnostic-ui", error = error));
tracing::error!(
"{}",
t!("context.diagnostic.starting-diagnostic-ui", error = error)
);
tracing::debug!("{:?}", error);
let (shutdown, _) = tokio::sync::broadcast::channel(1);

View File

@@ -463,7 +463,10 @@ impl RpcContext {
.await
.result
{
tracing::error!("{}", t!("context.rpc.error-in-session-cleanup-cron", error = e));
tracing::error!(
"{}",
t!("context.rpc.error-in-session-cleanup-cron", error = e)
);
tracing::debug!("{e:?}");
}
}

View File

@@ -87,7 +87,11 @@ pub enum RevisionsRes {
#[serde(rename_all = "camelCase")]
#[command(rename_all = "kebab-case")]
pub struct CliDumpParams {
#[arg(long = "include-private", short = 'p', help = "help.arg.include-private-data")]
#[arg(
long = "include-private",
short = 'p',
help = "help.arg.include-private-data"
)]
#[serde(default)]
include_private: bool,
#[arg(help = "help.arg.db-path")]

View File

@@ -70,12 +70,20 @@ async fn e2fsck_runner(
if code & 4 != 0 {
tracing::error!(
"{}",
t!("disk.fsck.errors-not-corrected", device = logicalname.as_ref().display(), stderr = e2fsck_stderr),
t!(
"disk.fsck.errors-not-corrected",
device = logicalname.as_ref().display(),
stderr = e2fsck_stderr
),
);
} else if code & 1 != 0 {
tracing::warn!(
"{}",
t!("disk.fsck.errors-corrected", device = logicalname.as_ref().display(), stderr = e2fsck_stderr),
t!(
"disk.fsck.errors-corrected",
device = logicalname.as_ref().display(),
stderr = e2fsck_stderr
),
);
}
if code < 8 {

View File

@@ -29,25 +29,31 @@ impl Default for FileType {
pub struct Bind<Src: AsRef<Path>> {
src: Src,
filetype: FileType,
recursive: bool,
}
impl<Src: AsRef<Path>> Bind<Src> {
pub fn new(src: Src) -> Self {
Self {
src,
filetype: FileType::Directory,
recursive: false,
}
}
pub fn with_type(mut self, filetype: FileType) -> Self {
self.filetype = filetype;
self
}
pub fn recursive(mut self, recursive: bool) -> Self {
self.recursive = recursive;
self
}
}
impl<Src: AsRef<Path> + Send + Sync> FileSystem for Bind<Src> {
async fn source(&self) -> Result<Option<impl AsRef<Path>>, Error> {
Ok(Some(&self.src))
}
fn extra_args(&self) -> impl IntoIterator<Item = impl AsRef<std::ffi::OsStr>> {
["--bind"]
[if self.recursive { "--rbind" } else { "--bind" }]
}
async fn pre_mount(&self, mountpoint: &Path, mount_type: MountType) -> Result<(), Error> {
let from_meta = tokio::fs::metadata(&self.src).await.ok();

View File

@@ -24,7 +24,11 @@ pub async fn bind<P0: AsRef<Path>, P1: AsRef<Path>>(
) -> Result<(), Error> {
tracing::info!(
"{}",
t!("disk.mount.binding", src = src.as_ref().display(), dst = dst.as_ref().display())
t!(
"disk.mount.binding",
src = src.as_ref().display(),
dst = dst.as_ref().display()
)
);
if is_mountpoint(&dst).await? {
unmount(dst.as_ref(), true).await?;

View File

@@ -183,7 +183,8 @@ impl ErrorKind {
UpdateFailed => t!("error.update-failed"),
Smtp => t!("error.smtp"),
SetSysInfo => t!("error.set-sys-info"),
}.to_string()
}
.to_string()
}
}
impl Display for ErrorKind {

View File

@@ -6,7 +6,6 @@ use std::str::FromStr;
use std::time::{Duration, UNIX_EPOCH};
use axum::extract::ws;
use crate::util::net::WebSocket;
use chrono::{DateTime, Utc};
use clap::builder::ValueParserFactory;
use clap::{Args, FromArgMatches, Parser};
@@ -31,6 +30,7 @@ use crate::context::{CliContext, RpcContext};
use crate::error::ResultExt;
use crate::prelude::*;
use crate::rpc_continuations::{Guid, RpcContinuation, RpcContinuations};
use crate::util::net::WebSocket;
use crate::util::serde::Reversible;
use crate::util::{FromStrParser, Invoke};
@@ -330,12 +330,22 @@ pub struct LogsParams<Extra: FromArgMatches + Args = Empty> {
extra: Extra,
#[arg(short = 'l', long = "limit", help = "help.arg.log-limit")]
limit: Option<usize>,
#[arg(short = 'c', long = "cursor", conflicts_with = "follow", help = "help.arg.log-cursor")]
#[arg(
short = 'c',
long = "cursor",
conflicts_with = "follow",
help = "help.arg.log-cursor"
)]
cursor: Option<String>,
#[arg(short = 'b', long = "boot", help = "help.arg.log-boot")]
#[serde(default)]
boot: Option<BootIdentifier>,
#[arg(short = 'B', long = "before", conflicts_with = "follow", help = "help.arg.log-before")]
#[arg(
short = 'B',
long = "before",
conflicts_with = "follow",
help = "help.arg.log-before"
)]
#[serde(default)]
before: bool,
}
@@ -553,10 +563,12 @@ pub async fn journalctl(
follow_cmd.arg("--lines=0");
}
let mut child = follow_cmd.stdout(Stdio::piped()).spawn()?;
let out =
BufReader::new(child.stdout.take().ok_or_else(|| {
Error::new(eyre!("{}", t!("logs.no-stdout-available")), crate::ErrorKind::Journald)
})?);
let out = BufReader::new(child.stdout.take().ok_or_else(|| {
Error::new(
eyre!("{}", t!("logs.no-stdout-available")),
crate::ErrorKind::Journald,
)
})?);
let journalctl_entries = LinesStream::new(out.lines());
@@ -701,7 +713,10 @@ pub async fn follow_logs<Context: AsRef<RpcContinuations>>(
RpcContinuation::ws(
move |socket| async move {
if let Err(e) = ws_handler(first_entry, stream, socket).await {
tracing::error!("{}", t!("logs.error-in-log-stream", error = e.to_string()));
tracing::error!(
"{}",
t!("logs.error-in-log-stream", error = e.to_string())
);
}
},
Duration::from_secs(30),

View File

@@ -40,7 +40,10 @@ impl LocalAuthContext for RpcContext {
}
fn unauthorized() -> Error {
Error::new(eyre!("{}", t!("middleware.auth.unauthorized")), crate::ErrorKind::Authorization)
Error::new(
eyre!("{}", t!("middleware.auth.unauthorized")),
crate::ErrorKind::Authorization,
)
}
async fn check_from_header<C: LocalAuthContext>(header: Option<&HeaderValue>) -> Result<(), Error> {

View File

@@ -244,7 +244,10 @@ impl ValidSessionToken {
C::access_sessions(db)
.as_idx_mut(session_hash)
.ok_or_else(|| {
Error::new(eyre!("{}", t!("middleware.auth.unauthorized")), crate::ErrorKind::Authorization)
Error::new(
eyre!("{}", t!("middleware.auth.unauthorized")),
crate::ErrorKind::Authorization,
)
})?
.mutate(|s| {
s.last_active = Utc::now();

View File

@@ -347,6 +347,10 @@ pub async fn call_remote<Ctx: SigningContext + AsRef<Client>>(
.with_kind(ErrorKind::Deserialization)?
.result
}
_ => Err(Error::new(eyre!("{}", t!("middleware.auth.unknown-content-type")), ErrorKind::Network).into()),
_ => Err(Error::new(
eyre!("{}", t!("middleware.auth.unknown-content-type")),
ErrorKind::Network,
)
.into()),
}
}

View File

@@ -47,7 +47,13 @@ impl Middleware<RpcContext> for SyncDb {
}
.await
{
tracing::error!("{}", t!("middleware.db.error-writing-patch-sequence-header", error = e));
tracing::error!(
"{}",
t!(
"middleware.db.error-writing-patch-sequence-header",
error = e
)
);
tracing::debug!("{e:?}");
}
}

View File

@@ -240,7 +240,13 @@ impl PortForwardController {
}
.await
{
tracing::error!("{}", t!("net.forward.error-initializing-controller", error = format!("{e:#}")));
tracing::error!(
"{}",
t!(
"net.forward.error-initializing-controller",
error = format!("{e:#}")
)
);
tracing::debug!("{e:?}");
tokio::time::sleep(Duration::from_secs(5)).await;
}

View File

@@ -171,16 +171,13 @@ where
let mut tls_handler = self.tls_handler.clone();
let mut fut = async move {
let res = async {
let mut acceptor = LazyConfigAcceptor::new(
Acceptor::default(),
BackTrackingIO::new(stream),
);
let mut acceptor =
LazyConfigAcceptor::new(Acceptor::default(), BackTrackingIO::new(stream));
let mut mid: tokio_rustls::StartHandshake<BackTrackingIO<AcceptStream>> =
match (&mut acceptor).await {
Ok(a) => a,
Err(e) => {
let mut stream =
acceptor.take_io().or_not_found("acceptor io")?;
let mut stream = acceptor.take_io().or_not_found("acceptor io")?;
let (_, buf) = stream.rewind();
if std::str::from_utf8(buf)
.ok()

View File

@@ -324,7 +324,12 @@ pub async fn list_keys(ctx: RpcContext) -> Result<BTreeSet<OnionAddress>, Error>
#[serde(rename_all = "camelCase")]
#[command(rename_all = "kebab-case")]
pub struct ResetParams {
#[arg(name = "wipe-state", short = 'w', long = "wipe-state", help = "help.arg.wipe-tor-state")]
#[arg(
name = "wipe-state",
short = 'w',
long = "wipe-state",
help = "help.arg.wipe-tor-state"
)]
wipe_state: bool,
}

View File

@@ -351,7 +351,12 @@ pub async fn list_keys(ctx: RpcContext) -> Result<BTreeSet<OnionAddress>, Error>
#[serde(rename_all = "camelCase")]
#[command(rename_all = "kebab-case")]
pub struct ResetParams {
#[arg(name = "wipe-state", short = 'w', long = "wipe-state", help = "help.arg.wipe-tor-state")]
#[arg(
name = "wipe-state",
short = 'w',
long = "wipe-state",
help = "help.arg.wipe-tor-state"
)]
wipe_state: bool,
#[arg(help = "help.arg.reset-reason")]
reason: String,

View File

@@ -94,7 +94,12 @@ impl Model<BTreeMap<Guid, SignerInfo>> {
.next()
.transpose()?
.map(|(a, _)| a)
.ok_or_else(|| Error::new(eyre!("{}", t!("registry.admin.unknown-signer")), ErrorKind::Authorization))
.ok_or_else(|| {
Error::new(
eyre!("{}", t!("registry.admin.unknown-signer")),
ErrorKind::Authorization,
)
})
}
pub fn get_signer_info(&self, key: &AnyVerifyingKey) -> Result<(Guid, SignerInfo), Error> {
@@ -104,7 +109,12 @@ impl Model<BTreeMap<Guid, SignerInfo>> {
.filter_ok(|(_, s)| s.keys.contains(key))
.next()
.transpose()?
.ok_or_else(|| Error::new(eyre!("{}", t!("registry.admin.unknown-signer")), ErrorKind::Authorization))
.ok_or_else(|| {
Error::new(
eyre!("{}", t!("registry.admin.unknown-signer")),
ErrorKind::Authorization,
)
})
}
pub fn add_signer(&mut self, signer: &SignerInfo) -> Result<Guid, Error> {
@@ -119,7 +129,11 @@ impl Model<BTreeMap<Guid, SignerInfo>> {
return Err(Error::new(
eyre!(
"{}",
t!("registry.admin.signer-already-exists", guid = guid, name = s.name)
t!(
"registry.admin.signer-already-exists",
guid = guid,
name = s.name
)
),
ErrorKind::InvalidRequest,
));

View File

@@ -44,7 +44,11 @@ const DEFAULT_REGISTRY_LISTEN: SocketAddr =
pub struct RegistryConfig {
#[arg(short = 'c', long = "config", help = "help.arg.config-file-path")]
pub config: Option<PathBuf>,
#[arg(short = 'l', long = "listen", help = "help.arg.registry-listen-address")]
#[arg(
short = 'l',
long = "listen",
help = "help.arg.registry-listen-address"
)]
pub registry_listen: Option<SocketAddr>,
#[arg(short = 'H', long = "hostname", help = "help.arg.registry-hostname")]
pub registry_hostname: Vec<InternedString>,
@@ -52,7 +56,11 @@ pub struct RegistryConfig {
pub tor_proxy: Option<Url>,
#[arg(short = 'd', long = "datadir", help = "help.arg.data-directory")]
pub datadir: Option<PathBuf>,
#[arg(short = 'u', long = "pg-connection-url", help = "help.arg.postgres-connection-url")]
#[arg(
short = 'u',
long = "pg-connection-url",
help = "help.arg.postgres-connection-url"
)]
pub pg_connection_url: Option<String>,
}
impl ContextConfig for RegistryConfig {
@@ -195,9 +203,11 @@ impl CallRemote<RegistryContext> for CliContext {
.push("v0");
url
} else {
return Err(
Error::new(eyre!("{}", t!("registry.context.registry-required")), ErrorKind::InvalidRequest).into(),
);
return Err(Error::new(
eyre!("{}", t!("registry.context.registry-required")),
ErrorKind::InvalidRequest,
)
.into());
};
if let Ok(local) = cookie {
@@ -331,7 +341,10 @@ impl SignatureAuthContext for RegistryContext {
}
}
Err(Error::new(eyre!("{}", t!("registry.context.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.context.unauthorized")),
ErrorKind::Authorization,
))
}
async fn post_auth_hook(
&self,

View File

@@ -154,7 +154,10 @@ async fn add_asset(
})?;
Ok(())
} else {
Err(Error::new(eyre!("{}", t!("registry.os.asset.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.os.asset.unauthorized")),
ErrorKind::Authorization,
))
}
})
.await
@@ -231,10 +234,12 @@ pub async fn cli_add_asset(
sign_phase.start();
let blake3 = file.blake3_mmap().await?;
let size = file
.size()
.await
.ok_or_else(|| Error::new(eyre!("{}", t!("registry.os.asset.failed-read-metadata")), ErrorKind::Filesystem))?;
let size = file.size().await.ok_or_else(|| {
Error::new(
eyre!("{}", t!("registry.os.asset.failed-read-metadata")),
ErrorKind::Filesystem,
)
})?;
let commitment = Blake3Commitment {
hash: Base64(*blake3.as_bytes()),
size,
@@ -336,7 +341,10 @@ async fn remove_asset(
.remove(&platform)?;
Ok(())
} else {
Err(Error::new(eyre!("{}", t!("registry.os.asset.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.os.asset.unauthorized")),
ErrorKind::Authorization,
))
}
})
.await

View File

@@ -125,17 +125,9 @@ pub struct CliGetOsAssetParams {
pub version: Version,
#[arg(help = "help.arg.platform")]
pub platform: InternedString,
#[arg(
long = "download",
short = 'd',
help = "help.arg.download-directory"
)]
#[arg(long = "download", short = 'd', help = "help.arg.download-directory")]
pub download: Option<PathBuf>,
#[arg(
long = "reverify",
short = 'r',
help = "help.arg.reverify-hash"
)]
#[arg(long = "reverify", short = 'r', help = "help.arg.reverify-hash")]
pub reverify: bool,
}

View File

@@ -89,7 +89,10 @@ async fn sign_asset(
.contains(&guid)
{
return Err(Error::new(
eyre!("{}", t!("registry.os.asset.signer-not-authorized", guid = guid)),
eyre!(
"{}",
t!("registry.os.asset.signer-not-authorized", guid = guid)
),
ErrorKind::Authorization,
));
}
@@ -184,10 +187,12 @@ pub async fn cli_sign_asset(
sign_phase.start();
let blake3 = file.blake3_mmap().await?;
let size = file
.size()
.await
.ok_or_else(|| Error::new(eyre!("{}", t!("registry.os.asset.failed-read-metadata")), ErrorKind::Filesystem))?;
let size = file.size().await.ok_or_else(|| {
Error::new(
eyre!("{}", t!("registry.os.asset.failed-read-metadata")),
ErrorKind::Filesystem,
)
})?;
let commitment = Blake3Commitment {
hash: Base64(*blake3.as_bytes()),
size,

View File

@@ -26,7 +26,6 @@ pub fn os_api<C: Context>() -> ParentHandler<C> {
)
.subcommand(
"version",
version::version_api::<C>()
.with_about("about.commands-add-remove-list-versions"),
version::version_api::<C>().with_about("about.commands-add-remove-list-versions"),
)
}

View File

@@ -95,7 +95,14 @@ pub async fn remove_version_signer(
.mutate(|s| Ok(s.remove(&signer)))?
{
return Err(Error::new(
eyre!("{}", t!("registry.os.version.signer-not-authorized", signer = signer, version = version)),
eyre!(
"{}",
t!(
"registry.os.version.signer-not-authorized",
signer = signer,
version = version
)
),
ErrorKind::NotFound,
));
}

View File

@@ -112,7 +112,10 @@ pub async fn add_package(
Ok(())
} else {
Err(Error::new(eyre!("{}", t!("registry.package.add.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.package.add.unauthorized")),
ErrorKind::Authorization,
))
}
})
.await
@@ -228,8 +231,12 @@ pub async fn remove_package(
}: RemovePackageParams,
) -> Result<bool, Error> {
let peek = ctx.db.peek().await;
let signer =
signer.ok_or_else(|| Error::new(eyre!("{}", t!("registry.package.missing-signer")), ErrorKind::InvalidRequest))?;
let signer = signer.ok_or_else(|| {
Error::new(
eyre!("{}", t!("registry.package.missing-signer")),
ErrorKind::InvalidRequest,
)
})?;
let signer_guid = peek.as_index().as_signers().get_signer(&signer)?;
let rev = ctx
@@ -270,7 +277,10 @@ pub async fn remove_package(
}
Ok(())
} else {
Err(Error::new(eyre!("{}", t!("registry.package.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.package.unauthorized")),
ErrorKind::Authorization,
))
}
})
.await;
@@ -345,7 +355,10 @@ pub async fn add_mirror(
Ok(())
} else {
Err(Error::new(eyre!("{}", t!("registry.package.add-mirror.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.package.add-mirror.unauthorized")),
ErrorKind::Authorization,
))
}
})
.await
@@ -461,8 +474,12 @@ pub async fn remove_mirror(
}: RemoveMirrorParams,
) -> Result<(), Error> {
let peek = ctx.db.peek().await;
let signer =
signer.ok_or_else(|| Error::new(eyre!("{}", t!("registry.package.missing-signer")), ErrorKind::InvalidRequest))?;
let signer = signer.ok_or_else(|| {
Error::new(
eyre!("{}", t!("registry.package.missing-signer")),
ErrorKind::InvalidRequest,
)
})?;
let signer_guid = peek.as_index().as_signers().get_signer(&signer)?;
ctx.db
@@ -501,7 +518,10 @@ pub async fn remove_mirror(
}
Ok(())
} else {
Err(Error::new(eyre!("{}", t!("registry.package.remove-mirror.unauthorized")), ErrorKind::Authorization))
Err(Error::new(
eyre!("{}", t!("registry.package.remove-mirror.unauthorized")),
ErrorKind::Authorization,
))
}
})
.await

View File

@@ -52,10 +52,14 @@ pub fn package_api<C: Context>() -> ParentHandler<C> {
if !changed {
tracing::warn!(
"{}",
t!("registry.package.remove-not-exist",
t!(
"registry.package.remove-not-exist",
id = args.params.id,
version = args.params.version,
sighash = args.params.sighash.map_or(String::new(), |h| format!("#{h}"))
sighash = args
.params
.sighash
.map_or(String::new(), |h| format!("#{h}"))
)
);
}
@@ -96,7 +100,6 @@ pub fn package_api<C: Context>() -> ParentHandler<C> {
)
.subcommand(
"category",
category::category_api::<C>()
.with_about("about.update-categories-registry"),
category::category_api::<C>().with_about("about.update-categories-registry"),
)
}

View File

@@ -118,7 +118,14 @@ pub async fn remove_package_signer(
.is_some()
{
return Err(Error::new(
eyre!("{}", t!("registry.package.signer.not-authorized", signer = signer, id = id)),
eyre!(
"{}",
t!(
"registry.package.signer.not-authorized",
signer = signer,
id = id
)
),
ErrorKind::NotFound,
));
}

View File

@@ -385,13 +385,17 @@ impl ImageSource {
pub fn ingredients(&self) -> Vec<PathBuf> {
match self {
Self::Packed => Vec::new(),
Self::DockerBuild { dockerfile, .. } => {
vec![
dockerfile
Self::DockerBuild {
dockerfile,
workdir,
..
} => {
vec![dockerfile.clone().unwrap_or_else(|| {
workdir
.as_deref()
.unwrap_or(Path::new("Dockerfile"))
.to_owned(),
]
.unwrap_or(Path::new("."))
.join("Dockerfile")
})]
}
Self::DockerTag(_) => Vec::new(),
}

View File

@@ -102,7 +102,13 @@ pub fn update_tasks(
}
}
None => {
tracing::error!("{}", t!("service.action.action-request-invalid-state", task = format!("{:?}", v.task)));
tracing::error!(
"{}",
t!(
"service.action.action-request-invalid-state",
task = format!("{:?}", v.task)
)
);
}
},
}
@@ -151,7 +157,10 @@ impl Handler<RunAction> for ServiceActor {
.de()?;
if matches!(&action.visibility, ActionVisibility::Disabled(_)) {
return Err(Error::new(
eyre!("{}", t!("service.action.action-is-disabled", action_id = action_id)),
eyre!(
"{}",
t!("service.action.action-is-disabled", action_id = action_id)
),
ErrorKind::Action,
));
}
@@ -162,7 +171,13 @@ impl Handler<RunAction> for ServiceActor {
_ => false,
} {
return Err(Error::new(
eyre!("{}", t!("service.action.service-not-in-allowed-status", action_id = action_id)),
eyre!(
"{}",
t!(
"service.action.service-not-in-allowed-status",
action_id = action_id
)
),
ErrorKind::Action,
));
}

View File

@@ -181,7 +181,10 @@ async fn run_action(
if package_id != &context.seed.id {
return Err(Error::new(
eyre!("{}", t!("service.effects.action.calling-actions-on-other-packages-unsupported")),
eyre!(
"{}",
t!("service.effects.action.calling-actions-on-other-packages-unsupported")
),
ErrorKind::InvalidRequest,
));
context
@@ -226,7 +229,10 @@ async fn create_task(
TaskCondition::InputNotMatches => {
let Some(input) = task.input.as_ref() else {
return Err(Error::new(
eyre!("{}", t!("service.effects.action.input-not-matches-requires-input")),
eyre!(
"{}",
t!("service.effects.action.input-not-matches-requires-input")
),
ErrorKind::InvalidRequest,
));
};
@@ -244,7 +250,12 @@ async fn create_task(
else {
return Err(Error::new(
eyre!(
"{}", t!("service.effects.action.action-has-no-input", action_id = task.action_id, package_id = task.package_id)
"{}",
t!(
"service.effects.action.action-has-no-input",
action_id = task.action_id,
package_id = task.package_id
)
),
ErrorKind::InvalidRequest,
));

View File

@@ -79,7 +79,7 @@ pub async fn mount(
}
IdMapped::new(
Bind::new(source).with_type(filetype),
Bind::new(source).with_type(filetype).recursive(true),
IdMap::stack(
vec![IdMap {
from_id: 0,

View File

@@ -28,7 +28,6 @@ use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode;
use ts_rs::TS;
use url::Url;
use crate::context::{CliContext, RpcContext};
use crate::db::model::package::{
InstalledState, ManifestPreference, PackageState, PackageStateMatchModelRef, TaskSeverity,
@@ -184,7 +183,10 @@ impl ServiceRef {
Arc::try_unwrap(service.seed)
.map_err(|_| {
Error::new(
eyre!("{}", t!("service.mod.service-actor-seed-held-after-shutdown")),
eyre!(
"{}",
t!("service.mod.service-actor-seed-held-after-shutdown")
),
ErrorKind::Unknown,
)
})?
@@ -376,12 +378,16 @@ impl Service {
{
Ok(PackageState::Installed(InstalledState { manifest }))
} else {
Err(Error::new(eyre!("{}", t!("service.mod.race-condition-detected")), ErrorKind::Database))
Err(Error::new(
eyre!("{}", t!("service.mod.race-condition-detected")),
ErrorKind::Database,
))
}
})
}
})
.await.result?;
.await
.result?;
handle_installed(s9pk).await
}
PackageStateMatchModelRef::Removing(_) | PackageStateMatchModelRef::Restoring(_) => {
@@ -447,7 +453,13 @@ impl Service {
handle_installed(S9pk::open(s9pk_path, Some(id)).await?).await
}
PackageStateMatchModelRef::Error(e) => Err(Error::new(
eyre!("{}", t!("service.mod.failed-to-parse-package-data-entry", error = format!("{e:?}"))),
eyre!(
"{}",
t!(
"service.mod.failed-to-parse-package-data-entry",
error = format!("{e:?}")
)
),
ErrorKind::Deserialization,
)),
}
@@ -553,7 +565,11 @@ impl Service {
true
} else {
tracing::warn!(
"{}", t!("service.mod.deleting-task-action-no-longer-exists", id = id)
"{}",
t!(
"service.mod.deleting-task-action-no-longer-exists",
id = id
)
);
false
}
@@ -791,7 +807,12 @@ pub async fn attach(
.join("\n");
return Err(Error::new(
eyre!(
"{}", t!("service.mod.no-matching-subcontainers", id = id, subcontainers = subcontainers)
"{}",
t!(
"service.mod.no-matching-subcontainers",
id = id,
subcontainers = subcontainers
)
),
ErrorKind::NotFound,
));
@@ -830,7 +851,14 @@ pub async fn attach(
.map(format_subcontainer_pair)
.join("\n");
return Err(Error::new(
eyre!("{}", t!("service.mod.multiple-subcontainers-found", id = id, subcontainer_ids = subcontainer_ids)),
eyre!(
"{}",
t!(
"service.mod.multiple-subcontainers-found",
id = id,
subcontainer_ids = subcontainer_ids
)
),
ErrorKind::InvalidRequest,
));
}
@@ -1120,7 +1148,13 @@ async fn get_passwd_command(etc_passwd_path: PathBuf, user: &str) -> RootCommand
}
}
Err(Error::new(
eyre!("{}", t!("service.mod.could-not-parse-etc-passwd", contents = contents)),
eyre!(
"{}",
t!(
"service.mod.could-not-parse-etc-passwd",
contents = contents
)
),
ErrorKind::Filesystem,
))
}

View File

@@ -364,7 +364,14 @@ impl PersistentContainer {
let handle = NonDetachingJoinHandle::from(tokio::spawn(async move {
let chown_status = async {
let res = server.run_unix(&path, |err| {
tracing::error!("{}", t!("service.persistent-container.error-on-unix-socket", path = path.display(), error = err))
tracing::error!(
"{}",
t!(
"service.persistent-container.error-on-unix-socket",
path = path.display(),
error = err
)
)
})?;
Command::new("chown")
.arg("100000:100000")
@@ -386,7 +393,10 @@ impl PersistentContainer {
}));
let shutdown = recv.await.map_err(|_| {
Error::new(
eyre!("{}", t!("service.persistent-container.unix-socket-server-panicked")),
eyre!(
"{}",
t!("service.persistent-container.unix-socket-server-panicked")
),
ErrorKind::Unknown,
)
})??;
@@ -473,7 +483,13 @@ impl PersistentContainer {
if let Some(destroy) = self.destroy(uninit) {
destroy.await?;
}
tracing::info!("{}", t!("service.persistent-container.service-exited", id = self.s9pk.as_manifest().id));
tracing::info!(
"{}",
t!(
"service.persistent-container.service-exited",
id = self.s9pk.as_manifest().id
)
);
Ok(())
}

View File

@@ -47,9 +47,18 @@ impl Actor for ServiceActor {
}
.await
{
tracing::error!("{}", t!("service.service-actor.error-synchronizing-state", error = e));
tracing::error!(
"{}",
t!("service.service-actor.error-synchronizing-state", error = e)
);
tracing::debug!("{e:?}");
tracing::error!("{}", t!("service.service-actor.retrying-in-seconds", seconds = SYNC_RETRY_COOLDOWN_SECONDS));
tracing::error!(
"{}",
t!(
"service.service-actor.retrying-in-seconds",
seconds = SYNC_RETRY_COOLDOWN_SECONDS
)
);
tokio::time::timeout(
Duration::from_secs(SYNC_RETRY_COOLDOWN_SECONDS),
async {

View File

@@ -62,7 +62,13 @@ pub async fn cleanup(ctx: &RpcContext, id: &PackageId, soft: bool) -> Result<(),
| PackageState::Removing(InstalledState { manifest }) => manifest,
s => {
return Err(Error::new(
eyre!("{}", t!("service.uninstall.invalid-package-state-for-cleanup", state = format!("{s:?}"))),
eyre!(
"{}",
t!(
"service.uninstall.invalid-package-state-for-cleanup",
state = format!("{s:?}")
)
),
ErrorKind::InvalidRequest,
));
}

View File

@@ -1,4 +1,3 @@
use crate::PLATFORM;
use crate::context::RpcContext;
use crate::disk::main::export;
@@ -36,18 +35,33 @@ impl Shutdown {
.invoke(crate::ErrorKind::Journald)
.await
{
tracing::error!("{}", t!("shutdown.error-stopping-journald", error = e.to_string()));
tracing::error!(
"{}",
t!("shutdown.error-stopping-journald", error = e.to_string())
);
tracing::debug!("{:?}", e);
}
if let Some(guid) = &self.disk_guid {
if let Err(e) = export(guid, crate::DATA_DIR).await {
tracing::error!("{}", t!("shutdown.error-exporting-volume-group", error = e.to_string()));
tracing::error!(
"{}",
t!(
"shutdown.error-exporting-volume-group",
error = e.to_string()
)
);
tracing::debug!("{:?}", e);
}
}
if &*PLATFORM != "raspberrypi" || self.restart {
if let Err(e) = SHUTDOWN.play().await {
tracing::error!("{}", t!("shutdown.error-playing-shutdown-song", error = e.to_string()));
tracing::error!(
"{}",
t!(
"shutdown.error-playing-shutdown-song",
error = e.to_string()
)
);
tracing::debug!("{:?}", e);
}
}

View File

@@ -19,8 +19,7 @@ pub fn tunnel_api<C: Context>() -> ParentHandler<C> {
.subcommand("web", super::web::web_api::<C>())
.subcommand(
"db",
super::db::db_api::<C>()
.with_about("about.commands-interact-with-db-dump-apply"),
super::db::db_api::<C>().with_about("about.commands-interact-with-db-dump-apply"),
)
.subcommand(
"auth",

View File

@@ -179,7 +179,10 @@ pub async fn cli_update_system(
Some(v) => {
if let Some(progress) = res.progress {
let mut ws = context.ws_continuation(progress).await?;
let mut progress = PhasedProgressBar::new(&t!("update.updating-to-version", version = v.to_string()));
let mut progress = PhasedProgressBar::new(&t!(
"update.updating-to-version",
version = v.to_string()
));
let mut prev = None;
while let Some(msg) = ws.try_next().await.with_kind(ErrorKind::Network)? {
if let tokio_tungstenite::tungstenite::Message::Text(msg) = msg {
@@ -202,7 +205,10 @@ pub async fn cli_update_system(
}
println!("{}", t!("update.complete-restart-to-apply"))
} else {
println!("{}", t!("update.updating-to-version", version = v.to_string()))
println!(
"{}",
t!("update.updating-to-version", version = v.to_string())
)
}
}
}

View File

@@ -97,7 +97,11 @@ impl WebSocket {
if self.ping_state.is_some() {
self.fused = true;
break Poll::Ready(Some(Err(axum::Error::new(eyre!(
"{}", t!("util.net.websocket-ping-timeout", timeout = format!("{PING_TIMEOUT:?}"))
"{}",
t!(
"util.net.websocket-ping-timeout",
timeout = format!("{PING_TIMEOUT:?}")
)
)))));
}
self.ping_state = Some((false, rand::random()));

View File

@@ -1151,7 +1151,13 @@ pub fn apply_expr(input: jaq_core::Val, expr: &str) -> Result<jaq_core::Val, Err
let Some(expr) = expr else {
return Err(Error::new(
eyre!("{}", t!("util.serde.failed-to-parse-expression", errors = format!("{:?}", errs))),
eyre!(
"{}",
t!(
"util.serde.failed-to-parse-expression",
errors = format!("{:?}", errs)
)
),
crate::ErrorKind::InvalidRequest,
));
};
@@ -1167,7 +1173,13 @@ pub fn apply_expr(input: jaq_core::Val, expr: &str) -> Result<jaq_core::Val, Err
if !errs.is_empty() {
return Err(Error::new(
eyre!("{}", t!("util.serde.failed-to-compile-expression", errors = format!("{:?}", errs))),
eyre!(
"{}",
t!(
"util.serde.failed-to-compile-expression",
errors = format!("{:?}", errs)
)
),
crate::ErrorKind::InvalidRequest,
));
};

View File

@@ -50,7 +50,10 @@ pub async fn prompt<T, E: std::fmt::Display, Parse: FnMut(&str) -> Result<T, E>>
}
}
ReadlineEvent::Eof | ReadlineEvent::Interrupted => {
return Err(Error::new(eyre!("{}", t!("util.tui.aborted")), ErrorKind::Cancelled));
return Err(Error::new(
eyre!("{}", t!("util.tui.aborted")),
ErrorKind::Cancelled,
));
}
_ => (),
}
@@ -83,7 +86,10 @@ pub async fn prompt_multiline<
Err(e) => writeln!(&mut rl_ctx.shared_writer, "{e}")?,
},
ReadlineEvent::Eof | ReadlineEvent::Interrupted => {
return Err(Error::new(eyre!("{}", t!("util.tui.aborted")), ErrorKind::Cancelled));
return Err(Error::new(
eyre!("{}", t!("util.tui.aborted")),
ErrorKind::Cancelled,
));
}
_ => (),
}
@@ -119,7 +125,10 @@ pub async fn choose_custom_display<'t, T>(
.await
.map_err(map_miette)?;
if choice.len() < 1 {
return Err(Error::new(eyre!("{}", t!("util.tui.aborted")), ErrorKind::Cancelled));
return Err(Error::new(
eyre!("{}", t!("util.tui.aborted")),
ErrorKind::Cancelled,
));
}
let (idx, choice_str) = string_choices
.iter()