Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
4444dd0
Refactor FsRepository's renders
jrray Dec 7, 2024
7d385c6
Integration test for render directory creation
jrray Dec 11, 2024
75b6b30
Fix clean silently ignoring MaybeRenders type
jrray Dec 11, 2024
dd214c5
Make clean not create renders
jrray Dec 11, 2024
49c2d81
Stop shadowing `RenderStore` type name in generic parameter
jrray Mar 6, 2026
b05ad01
Implement FallbackProxy::render_store_for_user
jrray Mar 6, 2026
9ec01d0
Rework FromConfig trait
jrray Mar 6, 2026
b4aca4b
spfs: honor create_renders policy and avoid maybe-render poisoning
jrray Mar 6, 2026
22b66b6
spfs: limit clean_manifest_renders test to render-capable repos
jrray Mar 6, 2026
8539321
spfs: test render store creation policy behavior
jrray Mar 7, 2026
845eef9
spfs: test maybe-render to render conversion paths
jrray Mar 7, 2026
3b9f821
spfs: test fallback proxy render-store variant behavior
jrray Mar 7, 2026
b467146
spfs: test resolve stack across repository handle variants
jrray Mar 7, 2026
a2f84ac
spfs: test renderer behavior without render store
jrray Mar 7, 2026
693ad96
spfs: pass username segment in renders_for_all_users and test it
jrray Mar 7, 2026
9674335
spfs: only create render proxy dir when metadata is missing
jrray Mar 7, 2026
39d4c28
spfs: skip unavailable per-user render stores in renders_for_all_users
jrray Mar 7, 2026
0e922b4
spfs: pre-validate proxy directory in renders_for_all_users
jrray Mar 7, 2026
66d457d
Return Error::NoRenderStorage instead of generic string error in rend…
jrray Mar 7, 2026
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.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions crates/spfs-cli/cmd-render/src/cmd_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

use clap::Parser;
use clap::builder::TypedValueParser;
use miette::{Context, Result};
use miette::{Context, IntoDiagnostic, Result};
use spfs::prelude::*;
use spfs::storage::fallback::FallbackProxy;
use spfs::storage::fs::{MaybeRenderStore, RenderStore};
use spfs::{Error, RenderResult, graph};
use spfs_cli_common::{self as cli, CommandName, HasRepositoryArgs};
use strum::VariantNames;
Expand Down Expand Up @@ -80,7 +81,11 @@ impl CmdRender {

let rendered = match &self.target {
Some(target) => self.render_to_dir(fallback, env_spec, target).await?,
None => self.render_to_repo(fallback, env_spec).await?,
None => {
// This path requires a repository that supports renders.
let fallback: FallbackProxy<RenderStore> = fallback.try_into().into_diagnostic()?;
self.render_to_repo(fallback, env_spec).await?
}
};

tracing::debug!("render(s) completed successfully");
Expand All @@ -91,7 +96,7 @@ impl CmdRender {

async fn render_to_dir(
&self,
repo: FallbackProxy,
repo: FallbackProxy<MaybeRenderStore>,
env_spec: spfs::tracking::EnvSpec,
target: &std::path::Path,
) -> Result<RenderResult> {
Expand Down Expand Up @@ -140,7 +145,7 @@ impl CmdRender {

async fn render_to_repo(
&self,
repo: FallbackProxy,
repo: FallbackProxy<RenderStore>,
env_spec: spfs::tracking::EnvSpec,
) -> Result<RenderResult> {
let mut stack = graph::Stack::default();
Expand Down
4 changes: 2 additions & 2 deletions crates/spfs-cli/common/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use miette::{Error, IntoDiagnostic, Result, WrapErr};
#[cfg(feature = "sentry")]
use once_cell::sync::OnceCell;
use spfs::io::Pluralize;
use spfs::storage::LocalRepository;
use spfs::storage::LocalPayloads;
use tracing_subscriber::prelude::*;

const SPFS_LOG: &str = "SPFS_LOG";
Expand Down Expand Up @@ -140,7 +140,7 @@ impl Render {
reporter: Reporter,
) -> spfs::storage::fs::Renderer<'repo, Repo, Reporter>
where
Repo: spfs::storage::Repository + LocalRepository,
Repo: spfs::storage::Repository + LocalPayloads,
Reporter: spfs::storage::fs::RenderReporter,
{
spfs::storage::fs::Renderer::new(repo)
Expand Down
3 changes: 2 additions & 1 deletion crates/spfs-cli/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ mod args;

pub mod __private {
// Private re-exports for macros
pub use {libc, spfs};
pub use libc;
pub use spfs;
}

pub use args::{
Expand Down
3 changes: 2 additions & 1 deletion crates/spfs-cli/main/src/cmd_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::path::PathBuf;

use clap::{Args, Subcommand};
use miette::Result;
use spfs::storage::fs::NoRenderStore;

/// Create an empty filesystem repository
#[derive(Debug, Args)]
Expand Down Expand Up @@ -36,7 +37,7 @@ impl InitSubcommand {
pub async fn run(&self, _config: &spfs::Config) -> Result<i32> {
match self {
Self::Repo { path } => {
spfs::storage::fs::MaybeOpenFsRepository::create(&path).await?;
spfs::storage::fs::MaybeOpenFsRepository::<NoRenderStore>::create(&path).await?;
Ok(0)
}
}
Expand Down
6 changes: 5 additions & 1 deletion crates/spfs-cli/main/src/cmd_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use clap::Args;
use miette::Result;
use spfs::prelude::*;
use spfs::storage::fs::NoRenderStore;
use spfs_cli_common as cli;
use tokio_stream::StreamExt;

Expand Down Expand Up @@ -33,7 +34,10 @@ impl CmdSearch {
};
repos.push(remote);
}
repos.insert(0, config.get_local_repository().await?.into());
repos.insert(
0,
config.get_local_repository::<NoRenderStore>().await?.into(),
);
for repo in repos.into_iter() {
let mut tag_streams = repo.iter_tags();
while let Some(tag) = tag_streams.next().await {
Expand Down
26 changes: 20 additions & 6 deletions crates/spfs-vfs/src/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use fuser::{
};
use spfs::OsError;
use spfs::prelude::*;
use spfs::storage::LocalRepository;
use spfs::storage::LocalPayloads;
#[cfg(feature = "fuse-backend-abi-7-31")]
use spfs::tracking::BlobRead;
use spfs::tracking::{Entry, EntryKind, EnvSpec, Manifest};
Expand Down Expand Up @@ -379,9 +379,13 @@ impl Filesystem {
#[allow(unused_mut)]
let mut flags = FOPEN_KEEP_CACHE;
for repo in self.repos.iter() {
match &**repo {
spfs::storage::RepositoryHandle::FS(fs_repo) => {
let Ok(fs_repo) = fs_repo.opened().await else {
// XXX: Using a macro here for an easy fix but it would be nicer
// if there was a way to borrow the RepositoryHandle as a
// `&MaybeOpenFsRepository<NoRenderStore>` since this code
// doesn't need to access renders.
macro_rules! read_fs {
($fs_repo:ident) => {
let Ok(fs_repo) = $fs_repo.opened().await else {
reply.error(libc::ENOENT);
return;
};
Expand All @@ -396,6 +400,17 @@ impl Filesystem {
}
Err(err) => err!(reply, err),
}
};
}
match &**repo {
spfs::storage::RepositoryHandle::FSWithMaybeRenders(fs_repo) => {
read_fs!(fs_repo);
}
spfs::storage::RepositoryHandle::FSWithRenders(fs_repo) => {
read_fs!(fs_repo);
}
spfs::storage::RepositoryHandle::FSWithoutRenders(fs_repo) => {
read_fs!(fs_repo);
}
#[cfg(feature = "fuse-backend-abi-7-31")]
repo => match repo.open_payload(*digest).await {
Expand Down Expand Up @@ -747,8 +762,7 @@ impl SessionInner {
.map_err(|source| spfs::Error::FailedToOpenRepository {
repository: "<FUSE Repository Stack>".into(),
source,
})?
.into();
})?;

tracing::debug!("Computing environment manifest...");
let manifest = spfs::compute_environment_manifest(&self.reference, &repo).await?;
Expand Down
8 changes: 7 additions & 1 deletion crates/spfs-vfs/src/winfsp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ impl Service {
repository: "<WinFSP Repository Stack>".into(),
source,
})?;
let repos = repo.into_stack().into_iter().map(Arc::new).collect();
let repos = match repo {
spfs::storage::RepositoryHandle::Proxy(proxy) => proxy.into_stack(),
repo => vec![repo],
}
.into_iter()
.map(Arc::new)
.collect();

// as of writing, the descriptor mode is the only one that works in
// winfsp-rs without causing crashes
Expand Down
23 changes: 19 additions & 4 deletions crates/spfs-vfs/src/winfsp/mount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use dashmap::DashMap;
use libc::c_void;
use spfs::OsError;
use spfs::prelude::*;
use spfs::storage::LocalRepository;
use spfs::storage::LocalPayloads;
use spfs::tracking::{Entry, EntryKind};
use tokio::io::AsyncReadExt;
use windows::Win32::Foundation::{ERROR_SEEK_ON_DEVICE, STATUS_NOT_A_DIRECTORY};
Expand Down Expand Up @@ -281,9 +281,13 @@ impl winfsp::filesystem::FileSystemContext for Mount {
let digest = entry.object;
self.rt.spawn(async move {
for repo in repos.into_iter() {
match &*repo {
spfs::storage::RepositoryHandle::FS(fs_repo) => {
let Ok(fs_repo) = fs_repo.opened().await else {
// XXX: Using a macro here for an easy fix but it would be nicer
// if there was a way to borrow the RepositoryHandle as a
// `&MaybeOpenFsRepository<NoRenderStore>` since this code
// doesn't need to access renders.
macro_rules! read_fs {
($fs_repo:ident) => {
let Ok(fs_repo) = $fs_repo.opened().await else {
let _ =
send.send(Err(winfsp::FspError::IO(std::io::ErrorKind::NotFound)));
return;
Expand All @@ -299,6 +303,17 @@ impl winfsp::filesystem::FileSystemContext for Mount {
}
Err(err) => err!(send, err),
}
};
}
match &*repo {
spfs::storage::RepositoryHandle::FSWithMaybeRenders(fs_repo) => {
read_fs!(fs_repo);
}
spfs::storage::RepositoryHandle::FSWithRenders(fs_repo) => {
read_fs!(fs_repo);
}
spfs::storage::RepositoryHandle::FSWithoutRenders(fs_repo) => {
read_fs!(fs_repo);
}
repo => match repo.open_payload(digest).await {
Ok((stream, _)) => {
Expand Down
1 change: 1 addition & 0 deletions crates/spfs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ ulid = { workspace = true }
unix_mode = "0.1.3"
url = { version = "2.2", features = ["serde"] }
uuid = { version = "1.1", features = ["v4"] }
variantly = { workspace = true }
walkdir = "2.3"
whoami = { workspace = true }

Expand Down
9 changes: 6 additions & 3 deletions crates/spfs/benches/spfs_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::time::Duration;

use criterion::{Criterion, Throughput, criterion_group, criterion_main};
use spfs::prelude::*;
use spfs::storage::fs::NoRenderStore;

pub fn commit_benchmark(c: &mut Criterion) {
const NUM_FILES: usize = 1024;
Expand Down Expand Up @@ -44,9 +45,11 @@ pub fn commit_benchmark(c: &mut Criterion) {
.expect("create a temp directory for spfs repo");
let repo: Arc<RepositoryHandle> = Arc::new(
tokio_runtime
.block_on(spfs::storage::fs::MaybeOpenFsRepository::create(
repo_path.path().join("repo"),
))
.block_on(
spfs::storage::fs::MaybeOpenFsRepository::<NoRenderStore>::create(
repo_path.path().join("repo"),
),
)
.expect("create spfs repo")
.into(),
);
Expand Down
5 changes: 3 additions & 2 deletions crates/spfs/src/bootstrap_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use super::build_shell_initialized_command;
use crate::fixtures::*;
use crate::resolve::which;
use crate::runtime;
use crate::storage::fs::RenderStore;

#[rstest]
#[case::bash("bash", "test.sh", "echo hi; export TEST_VALUE='spfs-test-value'")]
Expand All @@ -33,7 +34,7 @@ async fn test_shell_initialization_startup_scripts(
};
let root = tmpdir.path().to_string_lossy().to_string();
let repo = crate::storage::RepositoryHandle::from(
crate::storage::fs::MaybeOpenFsRepository::create(&root)
crate::storage::fs::MaybeOpenFsRepository::<RenderStore>::create(&root)
.await
.unwrap(),
);
Expand Down Expand Up @@ -118,7 +119,7 @@ async fn test_shell_initialization_no_startup_scripts(
};
let root = tmpdir.path().to_string_lossy().to_string();
let repo = crate::storage::RepositoryHandle::from(
crate::storage::fs::MaybeOpenFsRepository::create(&root)
crate::storage::fs::MaybeOpenFsRepository::<RenderStore>::create(&root)
.await
.unwrap(),
);
Expand Down
Loading
Loading