use crate::cli::{Cli, Command, MountArgs, SubmodulesMode, UnmountArgs};
use crate::errors::{Error, Result};
use fuser::MountOption;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone)]
pub enum AppCommand {
Mount(MountConfig),
Unmount(UnmountConfig),
}
impl AppCommand {
pub fn from_cli(cli: Cli) -> Result<Self> {
match cli.command {
Command::Mount(args) => MountConfig::try_from(args).map(Self::Mount),
Command::Unmount(args) => UnmountConfig::try_from(args).map(Self::Unmount),
}
}
}
#[derive(Debug, Clone)]
pub struct MountConfig {
pub repo: PathBuf,
pub mountpoint: PathBuf,
pub foreground: bool,
pub allow_other: bool,
pub submodules: SubmodulesMode,
pub lfs: bool,
pub ref_snapshot: bool,
pub cache_size_mb: usize,
pub uid: Option<u32>,
pub gid: Option<u32>,
}
impl MountConfig {
pub fn fuse_mount_options(&self) -> Vec<MountOption> {
let mut options = vec![
MountOption::RO,
MountOption::DefaultPermissions,
MountOption::FSName(String::from("timefs")),
MountOption::Subtype(String::from("timefs")),
];
if self.allow_other {
options.push(MountOption::AllowOther);
}
options
}
}
impl TryFrom<MountArgs> for MountConfig {
type Error = Error;
fn try_from(args: MountArgs) -> Result<Self> {
let repo = validate_existing_dir(&args.repo, "repository")?;
let mountpoint = validate_existing_dir(&args.mountpoint, "mountpoint")?;
Ok(Self {
repo,
mountpoint,
foreground: args.foreground,
allow_other: args.allow_other,
submodules: args.submodules,
lfs: args.lfs,
ref_snapshot: args.ref_snapshot,
cache_size_mb: args.cache_size_mb,
uid: args.uid,
gid: args.gid,
})
}
}
#[derive(Debug, Clone)]
pub struct UnmountConfig {
pub mountpoint: PathBuf,
}
impl TryFrom<UnmountArgs> for UnmountConfig {
type Error = Error;
fn try_from(args: UnmountArgs) -> Result<Self> {
let mountpoint = validate_existing_dir(&args.mountpoint, "mountpoint")?;
Ok(Self { mountpoint })
}
}
fn validate_existing_dir(path: &Path, label: &'static str) -> Result<PathBuf> {
match path.try_exists() {
Ok(true) => {}
Ok(false) => {
return Err(Error::PathDoesNotExist {
label,
path: path.to_path_buf(),
});
}
Err(source) => {
return Err(Error::PathProbeFailed {
label,
path: path.to_path_buf(),
source,
});
}
}
let metadata = std::fs::metadata(path).map_err(|source| Error::PathProbeFailed {
label,
path: path.to_path_buf(),
source,
})?;
if !metadata.is_dir() {
return Err(Error::PathIsNotDirectory {
label,
path: path.to_path_buf(),
});
}
std::fs::canonicalize(path).map_err(|source| Error::PathCanonicalizeFailed {
label,
path: path.to_path_buf(),
source,
})
}