Skip to content
Merged
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 crates/vfs-cli/src/cmd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod pack;
pub mod profiling;
pub mod ps;
pub mod safety;
pub mod seed;
mod session_lock;
pub mod sync;
pub mod timeline;
Expand Down
8 changes: 4 additions & 4 deletions crates/vfs-cli/src/cmd/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ fn validate_output_target(output: Option<&Path>, live_db: &Path) -> Result<()> {
Ok(())
}

fn copy_database_family(source: &Path, target: &Path) -> Result<()> {
pub(crate) fn copy_database_family(source: &Path, target: &Path) -> Result<()> {
copy_file_exclusive(source, target)?;
for suffix in ["-wal", "-shm"] {
let source_sidecar = sidecar_path(source, suffix);
Expand Down Expand Up @@ -500,7 +500,7 @@ fn rollback_live_database(live: &Path, backup: &Path) -> Result<()> {
.context("Failed to roll back the live session database after output publication failed")
}

fn rename_database_family(source: &Path, target: &Path) -> Result<()> {
pub(crate) fn rename_database_family(source: &Path, target: &Path) -> Result<()> {
let mut renamed = Vec::new();
for suffix in ["", "-wal", "-shm"] {
let source_path = if suffix.is_empty() {
Expand Down Expand Up @@ -546,7 +546,7 @@ fn cleanup_backup_family(backup: &Path) {
}
}

fn remove_database_family(path: &Path) {
pub(crate) fn remove_database_family(path: &Path) {
for path in database_family(path) {
let _ = fs::remove_file(path);
}
Expand All @@ -560,7 +560,7 @@ fn database_family(path: &Path) -> [PathBuf; 3] {
]
}

fn sync_file_and_parent(path: &Path) -> Result<()> {
pub(crate) fn sync_file_and_parent(path: &Path) -> Result<()> {
fs::OpenOptions::new()
.read(true)
.write(true)
Expand Down
36 changes: 32 additions & 4 deletions crates/vfs-cli/src/cmd/run/darwin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,13 +301,33 @@ pub async fn run(options: RunOptions) -> Result<()> {
system: _,
encryption,
partial_origin_policy,
seed_pin,
command,
args,
} = options;
let cwd = std::env::current_dir().context("Failed to get current directory")?;
let home = dirs::home_dir().context("Failed to get home directory")?;

let session = setup_run_directory(session, allow, no_default_allows, &cwd, &home)?;
let mut session = setup_run_directory(
session,
allow,
no_default_allows,
&cwd,
&home,
seed_pin.is_none(),
)?;
if let Some(pin) = seed_pin {
let seeded = crate::cmd::seed::seed_session(
&home,
&session.session_id,
&pin,
encryption.clone(),
true,
Some(&cwd),
)
.await?;
session._session_lock = Some(seeded.into_shared_lock()?);
}

// Check if we're joining an existing session
if is_mountpoint(&session.mountpoint) {
Expand Down Expand Up @@ -473,7 +493,7 @@ fn print_welcome_banner(session: &RunSession, encrypted: bool) {
/// Configuration for a sandbox run session.
struct RunSession {
/// Shared advisory lock preventing pack from publishing over this run.
_session_lock: crate::cmd::session_lock::SessionLock,
_session_lock: Option<crate::cmd::session_lock::SessionLock>,
/// Directory containing session artifacts.
run_dir: PathBuf,
/// Path to the delta database.
Expand All @@ -498,12 +518,20 @@ fn setup_run_directory(
no_default_allows: bool,
cwd: &Path,
home: &Path,
acquire_lock: bool,
) -> Result<RunSession> {
let run_id = session_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
let run_dir = home.join(".vfs").join("run").join(&run_id);
std::fs::create_dir_all(&run_dir).context("Failed to create run directory")?;
let session_lock = crate::cmd::session_lock::SessionLock::try_shared(&run_dir)
.with_context(|| format!("session {run_id} is being packed; retry after it finishes"))?;
let session_lock = if acquire_lock {
Some(
crate::cmd::session_lock::SessionLock::try_shared(&run_dir).with_context(|| {
format!("session {run_id} is being packed or seeded; retry after it finishes")
})?,
)
} else {
None
};

let db_path = run_dir.join("delta.db");
let mountpoint = run_dir.join("mnt");
Expand Down
35 changes: 30 additions & 5 deletions crates/vfs-cli/src/cmd/run/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ pub fn run(options: RunOptions) -> Result<()> {
system,
encryption,
partial_origin_policy,
seed_pin,
command,
args,
} = options;
Expand All @@ -85,7 +86,24 @@ pub fn run(options: RunOptions) -> Result<()> {
let allowed_paths = build_allowed_paths(&allow, no_default_allows)?;

// Check if we're joining an existing session
let session = setup_run_directory(session)?;
let mut session = setup_run_directory(session, seed_pin.is_none())?;
if let Some(pin) = seed_pin {
let home = dirs::home_dir().context("Failed to get home directory")?;
let seed_runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.context("Failed to create seed runtime")?;
let seeded = seed_runtime.block_on(crate::cmd::seed::seed_session(
&home,
&session.run_id,
&pin,
encryption.clone(),
true,
Some(&cwd),
))?;
drop(seed_runtime);
session._session_lock = Some(seeded.into_shared_lock()?);
}

// If the FUSE mountpoint is already mounted, join the existing session
if is_mountpoint(&session.fuse_mountpoint) {
Expand Down Expand Up @@ -489,7 +507,7 @@ fn print_welcome_banner(cwd: &Path, allowed_paths: &[PathBuf], session_id: &str,
/// Configuration for a sandbox run session.
struct RunSession {
/// Shared advisory lock preventing pack from publishing over this run.
_session_lock: crate::cmd::session_lock::SessionLock,
_session_lock: Option<crate::cmd::session_lock::SessionLock>,
/// Unique identifier for this run.
run_id: String,
/// Path to the delta database.
Expand All @@ -504,13 +522,20 @@ struct RunSession {
///
/// If `session_id` is provided, uses that as the run ID (allowing multiple
/// runs to share the same delta layer). Otherwise generates a unique UUID.
fn setup_run_directory(session_id: Option<String>) -> Result<RunSession> {
fn setup_run_directory(session_id: Option<String>, acquire_lock: bool) -> Result<RunSession> {
let run_id = session_id.unwrap_or_else(|| uuid::Uuid::new_v4().to_string());
let home_dir = dirs::home_dir().context("Failed to get home directory")?;
let run_dir = home_dir.join(".vfs").join("run").join(&run_id);
std::fs::create_dir_all(&run_dir).context("Failed to create run directory")?;
let session_lock = crate::cmd::session_lock::SessionLock::try_shared(&run_dir)
.with_context(|| format!("session {run_id} is being packed; retry after it finishes"))?;
let session_lock = if acquire_lock {
Some(
crate::cmd::session_lock::SessionLock::try_shared(&run_dir).with_context(|| {
format!("session {run_id} is being packed or seeded; retry after it finishes")
})?,
)
} else {
None
};

let db_path = run_dir.join("delta.db");
let fuse_mountpoint = run_dir.join("mnt");
Expand Down
Loading
Loading