#![cfg_attr(not(mount), allow(dead_code, unused_imports))]
mod copy;
mod folder;
#[cfg(mount)]
mod fs;
mod git;
mod gitfile;
mod github;
mod host;
mod mcp;
#[cfg(mount)]
mod memory;
#[cfg(any(nfs, all(test, fuse)))]
mod nfs;
#[cfg(any(nfs, all(test, fuse)))]
mod nfsserve;
mod ops;
mod persist;
mod relaunch;
#[cfg(mount)]
mod server;
mod shell;
mod store;
mod update;
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
struct ReadmeExample;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use anyhow::Result;
pub use sandfs_core::ChangeKind;
pub(crate) use crate::ops::resolve_new;
#[cfg(mount)]
pub(crate) use crate::ops::{serve, served_times};
pub use crate::relaunch::handle_relaunch;
pub use crate::update::Updated;
#[derive(Debug)]
pub struct Home {
inner: store::Home,
}
impl Home {
pub fn locate() -> Result<Home> {
Ok(Home { inner: store::Home::locate()? })
}
pub fn at(root: impl AsRef<Path>) -> Result<Home> {
Ok(Home { inner: store::Home::at(std::path::absolute(root)?) })
}
pub fn root(&self) -> &Path {
self.inner.root()
}
pub fn mount(&self, source: &str, dir: &Path, options: &MountOptions) -> Result<Mounted> {
ops::mount_source(&self.inner, source, dir, options)
}
pub fn fork(&self, from: &str, dir: Option<&Path>, options: &ForkOptions) -> Result<Forked> {
ops::fork(&self.inner, from, dir, options)
}
pub fn changes(&self, workspace: &str, options: &ChangesOptions) -> Result<Changes> {
ops::changes(&self.inner, workspace, options)
}
pub fn update(&self, workspace: &str, source: Option<&str>) -> Result<Updated> {
let name = self.inner.find(workspace)?;
update::update(&self.inner, &name, source)
}
pub fn workspaces(&self) -> Result<Vec<WorkspaceInfo>> {
ops::workspaces(&self.inner)
}
pub fn find(&self, workspace: &str) -> Result<String> {
self.inner.find(workspace)
}
pub fn unmount(&self, workspace: &str) -> Result<()> {
ops::unmount_workspace(&self.inner, workspace)
}
pub fn trim(&self, workspace: Option<&str>) -> Result<Trimmed> {
ops::trim(&self.inner, workspace)
}
pub fn remove(&self, name: &str, unmount: bool) -> Result<()> {
ops::remove(&self.inner, name, unmount)
}
pub fn clean(&self) -> Result<Vec<Cleaned>> {
ops::clean(&self.inner)
}
pub fn serve_mcp(&self, workspace: &str, options: &ServeOptions) -> Result<()> {
ops::serve_mcp(&self.inner, workspace, options)
}
pub fn shell(&self, workspace: &str, network: bool, command: &[OsString]) -> Result<i32> {
ops::shell(&self.inner, workspace, network, command)
}
}
#[derive(Debug, Clone, Default)]
pub struct MountOptions {
pub name: Option<String>,
pub read_only: Vec<String>,
pub foreground: bool,
}
#[derive(Debug, Clone, Default)]
pub struct ForkOptions {
pub name: Option<String>,
pub read_only: Vec<String>,
pub branch: Option<String>,
pub foreground: bool,
pub real_folder: Option<bool>,
pub allow_copy: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CrossDevice {
pub folder: PathBuf,
pub home: PathBuf,
}
impl std::fmt::Display for CrossDevice {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} is on another disk than sandfs's home ({}), and forking a plain folder clones its files, \
which works only within one disk. `sandfs fork --allow-copy` copies them in full instead; \
`sandfs mount {} DIR` mounts the folder itself, showing its later changes too",
self.folder.display(),
self.home.display(),
self.folder.display()
)
}
}
impl std::error::Error for CrossDevice {}
#[derive(Debug, Clone, Default)]
pub struct ChangesOptions {
pub paths: Vec<String>,
pub since: Option<String>,
pub copy_to: Option<PathBuf>,
pub force: bool,
}
#[derive(Debug, Clone, Default)]
pub struct ServeOptions {
pub name: Option<String>,
pub read_only: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct Mounted {
pub name: String,
pub dir: PathBuf,
}
#[derive(Debug, Clone)]
pub struct Forked {
pub name: String,
pub from: String,
pub dir: Option<PathBuf>,
pub real_folder: bool,
}
#[derive(Debug, Clone)]
pub struct Changes {
pub changes: Vec<Change>,
pub held_back: usize,
pub git_settings: Vec<String>,
pub committed: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Change {
pub kind: ChangeKind,
pub path: String,
}
#[derive(Debug, Clone)]
pub struct WorkspaceInfo {
pub name: String,
pub source: String,
pub mounted: Option<PathBuf>,
}
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
pub struct Trimmed {
pub mounts: usize,
pub given_back: Option<u64>,
}
#[derive(Debug, Clone)]
pub struct Cleaned {
pub repository: String,
pub outcome: CleanOutcome,
}
#[derive(Debug, Clone)]
pub enum CleanOutcome {
Deleted {
freed: u64,
},
Shrunk {
freed: u64,
},
Kept {
busy: String,
},
}