Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,5 @@ winfsp-sys = "0.2"
fn_params_excessive_bools = "warn"

[workspace.lints.rust]
missing_docs = "warn"
unsafe_op_in_unsafe_fn = "deny"
14 changes: 14 additions & 0 deletions crates/is_default_derive_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,26 @@
// SPDX-License-Identifier: Apache-2.0
// https://github.com/spkenv/spk

//! Derive macro for the [`spk_schema_foundation::IsDefault`] trait.
//!
//! This crate provides a procedural macro that automatically implements
//! the `IsDefault` trait for structs by checking if all fields are at
//! their default values.

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{Data, DeriveInput, Fields, parse_macro_input};

/// Derives the `IsDefault` trait for a struct.
///
/// The generated implementation returns `true` if all fields
/// report `is_default() == true`.
///
/// # Panics
///
/// This macro panics at compile time if applied to non-struct types.
#[proc_macro_derive(IsDefault)]
pub fn derive_is_default(input: TokenStream) -> TokenStream {
// Parse the input tokens into a syntax tree
Expand Down
7 changes: 7 additions & 0 deletions crates/parsedbuf/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
// https://github.com/spkenv/spk

//! Macro for generating validated string wrapper types.
//!
//! This crate provides the [`parsed!`] macro which generates a pair of
//! types (borrowed and owned) that wrap strings with validation logic.
//! This is useful for creating type-safe string wrappers like package
//! names, version strings, or other validated identifiers.

pub use paste;

/// Generate a pair of types to represent a parsed string type.
Expand Down
6 changes: 5 additions & 1 deletion crates/sentry-miette/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
// SPDX-License-Identifier: Apache-2.0
// https://github.com/spkenv/spk

// TODO: this might be overkill for the integration changes we make/need
//! Integration between [`sentry`] and [`miette`] error types.
//!
//! Provides utilities for capturing miette diagnostic errors
//! as Sentry events, preserving the rich formatting that miette
//! provides.

use sentry::Hub;
use sentry::protocol::Event;
Expand Down
2 changes: 1 addition & 1 deletion crates/spfs-cli/cmd-clean/src/cmd_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ impl CmdClean {
// durable upper path's workdir that have 'd---------' permissions
// from overlayfs.
std::fs::remove_dir_all(durable_path.clone())
.map_err(|err| spfs::Error::RuntimeWriteError(durable_path, err))?;
.map_err(|err| spfs::runtime::Error::RuntimeWriteError(durable_path, err))?;
}
return Ok(0);
}
Expand Down
7 changes: 4 additions & 3 deletions crates/spfs-cli/cmd-render/src/cmd_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use clap::Parser;
use clap::builder::TypedValueParser;
use miette::{Context, Result};
use spfs::prelude::*;
use spfs::runtime::Error as RuntimeError;
use spfs::storage::fallback::FallbackProxy;
use spfs::{Error, RenderResult, graph};
use spfs_cli_common::{self as cli, CommandName, HasRepositoryArgs};
Expand Down Expand Up @@ -97,15 +98,15 @@ impl CmdRender {
) -> Result<RenderResult> {
tokio::fs::create_dir_all(&target)
.await
.map_err(|err| Error::RuntimeWriteError(target.to_owned(), err))?;
.map_err(|err| RuntimeError::RuntimeWriteError(target.to_owned(), err))?;
let target_dir = tokio::task::block_in_place(|| dunce::canonicalize(target))
.map_err(|err| Error::InvalidPath(target.to_owned(), err))?;
if tokio::fs::read_dir(&target_dir)
.await
.map_err(|err| Error::RuntimeReadError(target_dir.clone(), err))?
.map_err(|err| RuntimeError::RuntimeReadError(target_dir.clone(), err))?
.next_entry()
.await
.map_err(|err| Error::RuntimeReadError(target_dir.clone(), err))?
.map_err(|err| RuntimeError::RuntimeReadError(target_dir.clone(), err))?
.is_some()
&& !self.allow_existing
{
Expand Down
13 changes: 10 additions & 3 deletions crates/spfs-cli/common/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,10 @@ macro_rules! handle_result {
tracing::error!("Out of disk space: {msg}");
Ok(1)
}
Some(spfs::Error::RuntimeWriteError(path, io_err))
Some(spfs::Error::Runtime(spfs::runtime::Error::RuntimeWriteError(
path,
io_err,
)))
| Some(spfs::Error::StorageWriteError(_, path, io_err))
if std::matches!(io_err.os_error(), Some($crate::__private::libc::ENOSPC)) =>
{
Expand All @@ -704,13 +707,17 @@ macro_rules! handle_result {
}};
}

/// Captures an error to sentry if it represents an unexpected failure.
///
/// Certain expected error types (like missing runtime, unknown objects)
/// are not reported to sentry as they represent normal operation.
pub fn capture_if_relevant(err: &Error) {
match err.root_cause().downcast_ref::<spfs::Error>() {
Some(spfs::Error::NoActiveRuntime) => (),
Some(spfs::Error::Runtime(spfs::runtime::Error::NoActiveRuntime)) => (),
Some(spfs::Error::UnknownObject(_)) => (),
Some(spfs::Error::UnknownReference(_)) => (),
Some(spfs::Error::AmbiguousReference(_)) => (),
Some(spfs::Error::NothingToCommit) => (),
Some(spfs::Error::Runtime(spfs::runtime::Error::NothingToCommit)) => (),
_ => {
#[cfg(feature = "sentry")]
sentry_miette::capture_miette(err);
Expand Down
7 changes: 5 additions & 2 deletions crates/spfs-cli/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@
// SPDX-License-Identifier: Apache-2.0
// https://github.com/spkenv/spk

//! Common macros and argument structures for the spfs command line
//! Common macros and argument structures for the spfs command line.
//!
//! This crate provides shared CLI argument structures, logging configuration,
//! and utility macros used across spfs CLI commands.

mod args;

#[doc(hidden)]
pub mod __private {
// Private re-exports for macros
pub use {libc, spfs};
}

Expand Down
2 changes: 1 addition & 1 deletion crates/spfs-cli/main/src/cmd_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ impl CmdCommit {
if let Some(path) = &self.path {
let manifest = committer.commit_dir(path).await?;
if manifest.is_empty() && !self.allow_empty {
return Err(spfs::Error::NothingToCommit);
return Err(spfs::runtime::Error::NothingToCommit.into());
}
return Ok(repo
.create_layer(&manifest.to_graph_manifest())
Expand Down
4 changes: 2 additions & 2 deletions crates/spfs-cli/main/src/cmd_edit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use clap::Args;
use miette::Result;
use spfs::Error;
use spfs::runtime::Error as RuntimeError;

/// Make the current runtime editable
#[derive(Debug, Args)]
Expand Down Expand Up @@ -38,7 +38,7 @@ impl CmdEdit {
if !self.off {
match spfs::make_active_runtime_editable().await {
Ok(_) => tracing::info!("edit mode enabled"),
Err(Error::RuntimeAlreadyEditable) => {}
Err(spfs::Error::Runtime(RuntimeError::RuntimeAlreadyEditable)) => {}
Err(err) => {
return Err(err.into());
}
Expand Down
2 changes: 1 addition & 1 deletion crates/spfs-cli/main/src/cmd_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ impl CmdInfo {
let found = match spfs::find_path::find_path_providers_in_spfs_runtime(filepath, repo).await
{
Ok(f) => f,
Err(spfs::Error::NoActiveRuntime) => {
Err(spfs::Error::Runtime(spfs::runtime::Error::NoActiveRuntime)) => {
in_a_runtime = false;
Vec::new()
}
Expand Down
6 changes: 3 additions & 3 deletions crates/spfs-cli/main/src/cmd_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use std::path::PathBuf;

use clap::Args;
use miette::Result;
use spfs::Error;
use spfs::prelude::*;
use spfs::runtime::Error as RuntimeError;
use spfs::tracking::BlobReadExt;
use spfs_cli_common as cli;

Expand Down Expand Up @@ -40,12 +40,12 @@ impl CmdWrite {
Some(file) => {
let handle = tokio::fs::File::open(&file)
.await
.map_err(|err| Error::RuntimeWriteError(file.clone(), err))?;
.map_err(|err| RuntimeError::RuntimeWriteError(file.clone(), err))?;
#[cfg(unix)]
let mode = handle
.metadata()
.await
.map_err(|err| Error::RuntimeWriteError(file.clone(), err))?
.map_err(|err| RuntimeError::RuntimeWriteError(file.clone(), err))?
.permissions()
.mode();
#[cfg(windows)]
Expand Down
7 changes: 7 additions & 0 deletions crates/spfs-proto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
// https://github.com/spkenv/spk

//! FlatBuffer protocol definitions for SPFS.
//!
//! This crate contains generated FlatBuffer code for serializing
//! and deserializing SPFS data structures, particularly [`Digest`]
//! types used for content addressing.

#![allow(missing_docs)]
#![allow(unused_imports)]
#![allow(unsafe_op_in_unsafe_fn)]
#![allow(mismatched_lifetime_syntaxes)]
Expand Down
2 changes: 1 addition & 1 deletion crates/spfs-vfs/src/winfsp/router.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl Router {
tracing::info!(%root_pid, env_spec=%env_spec.to_string(),"mounted");
let mut routes = self.routes.write().expect("lock is never poisoned");
if routes.contains_key(&root_pid) {
return Err(spfs::Error::RuntimeExists(root_pid.to_string()));
return Err(spfs::runtime::Error::RuntimeExists(root_pid.to_string()).into());
}
routes.insert(root_pid, Arc::new(mount));
Ok(())
Expand Down
9 changes: 5 additions & 4 deletions crates/spfs/src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use spfs_encoding::prelude::*;

use super::status::remount_runtime;
use crate::prelude::*;
use crate::runtime::Error as RuntimeError;
use crate::tracking::{BlobHasher, BlobRead, ManifestBuilder, PathFilter};
use crate::{Error, Result, encoding, graph, runtime, storage, tracking};

Expand Down Expand Up @@ -198,7 +199,7 @@ where
runtime: &mut runtime::Runtime,
) -> Result<graph::Layer> {
if manifest.is_empty() && !self.allow_empty {
return Err(Error::NothingToCommit);
return Err(RuntimeError::NothingToCommit.into());
}
let layer = self
.repo
Expand All @@ -208,7 +209,7 @@ where
// Don't bother putting the empty layer on the stack, the goal
// with allow_empty is to create an empty manifest.
if !runtime.push_digest(layer.digest()?) {
return Err(Error::NothingToCommit);
return Err(RuntimeError::NothingToCommit.into());
}
runtime.status.editable = false;
runtime.save_state_to_storage().await?;
Expand All @@ -220,13 +221,13 @@ where
/// Commit the full layer stack and working files to a new platform.
pub async fn commit_platform(&self, runtime: &mut runtime::Runtime) -> Result<graph::Platform> {
match self.commit_layer(runtime).await {
Ok(_) | Err(Error::NothingToCommit) => (),
Ok(_) | Err(Error::Runtime(RuntimeError::NothingToCommit)) => (),
Err(err) => return Err(err),
}

runtime.reload_state_from_storage().await?;
if runtime.status.stack.is_empty() && !self.allow_empty {
Err(Error::NothingToCommit)
Err(RuntimeError::NothingToCommit.into())
} else {
self.repo
.create_platform(runtime.status.stack.clone())
Expand Down
5 changes: 3 additions & 2 deletions crates/spfs/src/commit_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rstest::rstest;
use super::Committer;
use crate::Error;
use crate::fixtures::*;
use crate::runtime::Error as RuntimeError;

#[rstest]
#[tokio::test]
Expand All @@ -27,12 +28,12 @@ async fn test_commit_empty(tmpdir: tempfile::TempDir) {
rt.ensure_required_directories().await.unwrap();
let committer = Committer::new(&repo);
match committer.commit_layer(&mut rt).await {
Err(Error::NothingToCommit) => {}
Err(Error::Runtime(RuntimeError::NothingToCommit)) => {}
res => panic!("expected nothing to commit, got {res:?}"),
}

match committer.commit_platform(&mut rt).await {
Err(Error::NothingToCommit) => {}
Err(Error::Runtime(RuntimeError::NothingToCommit)) => {}
res => panic!("expected nothing to commit, got {res:?}"),
}
}
Loading
Loading