Only scan one filesystem by default (can configure 'cross_filesystems' if needed)
ci/woodpecker/push/build Pipeline was successful Details
ci/woodpecker/push/release Pipeline was successful Details

This commit is contained in:
Olivier 'reivilibre' 2022-05-31 09:39:25 +01:00
parent e8fc448ace
commit af553d1fed
8 changed files with 52 additions and 19 deletions

View File

@ -195,10 +195,10 @@ fn main() -> anyhow::Result<()> {
unimplemented!(); unimplemented!();
} }
DatmanCommand::InteractiveLabelling { source_name } => { DatmanCommand::InteractiveLabelling { source_name } => {
interactive_labelling_session(Path::new("."), source_name).unwrap(); interactive_labelling_session(Path::new("."), source_name)?;
} }
DatmanCommand::InteractiveBrowsing { source_name } => { DatmanCommand::InteractiveBrowsing { source_name } => {
datman::commands::ibrowse::session(Path::new("."), source_name).unwrap(); datman::commands::ibrowse::session(Path::new("."), source_name)?;
} }
DatmanCommand::BackupOne { DatmanCommand::BackupOne {
source_name, source_name,

View File

@ -147,10 +147,12 @@ pub fn backup_source_to_destination<PT: ProgressTracker>(
SourceDescriptor::DirectorySource { SourceDescriptor::DirectorySource {
hostname: _, hostname: _,
directory, directory,
cross_filesystems,
} => { } => {
info!("Looking to backup {} to {}", source_name, dest_name); info!("Looking to backup {} to {}", source_name, dest_name);
info!("Scanning."); info!("Scanning.");
let tree = scan(directory)?.ok_or_else(|| anyhow!("Source does not exist."))?; let tree = scan(directory, !*cross_filesystems)?
.ok_or_else(|| anyhow!("Source does not exist."))?;
let absolute_source_path = desc_path.join(directory); let absolute_source_path = desc_path.join(directory);
let absolute_dest_path = desc_path.join(&dest.path); let absolute_dest_path = desc_path.join(&dest.path);

View File

@ -68,15 +68,19 @@ pub fn session(path: &Path, source_name: String) -> anyhow::Result<()> {
.get(&source_name) .get(&source_name)
.ok_or_else(|| anyhow!("Could not find source {:?}!", source_name))?; .ok_or_else(|| anyhow!("Could not find source {:?}!", source_name))?;
let directory = match source_descriptor { let (directory, one_filesystem) = match source_descriptor {
SourceDescriptor::DirectorySource { directory, .. } => directory, SourceDescriptor::DirectorySource {
directory,
cross_filesystems,
..
} => (directory, !*cross_filesystems),
SourceDescriptor::VirtualSource { .. } => { SourceDescriptor::VirtualSource { .. } => {
bail!("Cannot browse virtual source."); bail!("Cannot browse virtual source.");
} }
}; };
println!("Scanning source; this might take a little while..."); println!("Scanning source; this might take a little while...");
let mut dir_scan: FileTree1<Option<State>> = scan(directory)? let mut dir_scan: FileTree1<Option<State>> = scan(directory, one_filesystem)?
.ok_or_else(|| anyhow!("Empty source."))? .ok_or_else(|| anyhow!("Empty source."))?
.replace_meta(&None); .replace_meta(&None);

View File

@ -186,12 +186,13 @@ pub fn interactive_labelling_session(path: &Path, source_name: String) -> anyhow
if let SourceDescriptor::DirectorySource { if let SourceDescriptor::DirectorySource {
hostname, hostname,
directory, directory,
cross_filesystems,
} = source } = source
{ {
let my_hostname = get_hostname(); let my_hostname = get_hostname();
let mut dir_scan = if &my_hostname == hostname { let mut dir_scan = if &my_hostname == hostname {
info!("Scanning source; this might take a little while..."); info!("Scanning source; this might take a little while...");
scan(directory)? scan(directory, !*cross_filesystems)?
.ok_or_else(|| anyhow!("Empty source."))? .ok_or_else(|| anyhow!("Empty source."))?
.replace_meta(&None) .replace_meta(&None)
} else { } else {
@ -206,8 +207,12 @@ pub fn interactive_labelling_session(path: &Path, source_name: String) -> anyhow
// then request to scan // then request to scan
info!("Requesting scan from remote source... (this may take some time)"); info!("Requesting scan from remote source... (this may take some time)");
let scan = let scan = backup_source_requester::scanning(
backup_source_requester::scanning(&mut read, &mut write, directory.as_ref())? &mut read,
&mut write,
directory.as_ref(),
!*cross_filesystems,
)?
.ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))? .ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?
.replace_meta(&None); .replace_meta(&None);

View File

@ -52,6 +52,8 @@ pub enum SourceDescriptor {
DirectorySource { DirectorySource {
hostname: String, hostname: String,
directory: PathBuf, directory: PathBuf,
#[serde(default)]
cross_filesystems: bool,
}, },
VirtualSource { VirtualSource {
/// The name of the helper program that will be used to do this backup. /// The name of the helper program that will be used to do this backup.

View File

@ -47,10 +47,12 @@ pub fn scanning<R: Read, W: Write>(
read: &mut R, read: &mut R,
write: &mut W, write: &mut W,
path: &Path, path: &Path,
one_filesystem: bool,
) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> { ) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
info!("Scanning."); info!("Scanning.");
write_message(write, &"scan")?; write_message(write, &"scan")?;
write_message(write, &path)?; write_message(write, &path)?;
write_message(write, &one_filesystem)?;
write.flush()?; write.flush()?;
let scan_result: Option<FileTree<(), (), (), ()>> = read_message(read)?; let scan_result: Option<FileTree<(), (), (), ()>> = read_message(read)?;
@ -177,6 +179,7 @@ pub fn backup_remote_source_to_destination<PT: ProgressTracker + Send + 'static>
SourceDescriptor::DirectorySource { SourceDescriptor::DirectorySource {
hostname, hostname,
directory, directory,
cross_filesystems,
} => { } => {
let remote_host_descriptor = descriptor let remote_host_descriptor = descriptor
.remote_hosts .remote_hosts
@ -198,7 +201,12 @@ pub fn backup_remote_source_to_destination<PT: ProgressTracker + Send + 'static>
// then request to scan // then request to scan
info!("Requesting scan... (this may take some time)"); info!("Requesting scan... (this may take some time)");
let scan_result = scanning(&mut read, &mut write, directory.as_ref())? let scan_result = scanning(
&mut read,
&mut write,
directory.as_ref(),
!*cross_filesystems,
)?
.ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?; .ok_or_else(|| anyhow!("Remote scan failed (does the directory exist?)"))?;
let mut root = let mut root =

View File

@ -42,7 +42,8 @@ pub fn introduction<R: Read, W: Write>(read: &mut R, write: &mut W) -> anyhow::R
pub fn scanning<R: Read, W: Write>(read: &mut R, write: &mut W) -> anyhow::Result<()> { pub fn scanning<R: Read, W: Write>(read: &mut R, write: &mut W) -> anyhow::Result<()> {
let path: PathBuf = read_message(read)?; let path: PathBuf = read_message(read)?;
let scan_result = scan(&path)?; let one_filesystem: bool = read_message(read)?;
let scan_result = scan(&path, one_filesystem)?;
write_message(write, &scan_result)?; write_message(write, &scan_result)?;
write.flush()?; write.flush()?;
Ok(()) Ok(())

View File

@ -24,7 +24,7 @@ use std::path::Path;
use anyhow::anyhow; use anyhow::anyhow;
use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle}; use indicatif::{ProgressBar, ProgressDrawTarget, ProgressStyle};
use log::warn; use log::{info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub use yama::definitions::FilesystemOwnership; pub use yama::definitions::FilesystemOwnership;
@ -216,12 +216,14 @@ pub fn mtime_msec(metadata: &Metadata) -> u64 {
} }
/// Scan the filesystem to produce a Tree, using a default progress bar. /// Scan the filesystem to produce a Tree, using a default progress bar.
pub fn scan(path: &Path) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> { pub fn scan(path: &Path, one_filesystem: bool) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
let pbar = ProgressBar::with_draw_target(0, ProgressDrawTarget::stdout_with_hz(2)); let pbar = ProgressBar::with_draw_target(0, ProgressDrawTarget::stdout_with_hz(2));
pbar.set_style(ProgressStyle::default_spinner().template("{spinner} {pos:7} {msg}")); pbar.set_style(ProgressStyle::default_spinner().template("{spinner} {pos:7} {msg}"));
pbar.set_message("dir scan"); pbar.set_message("dir scan");
let result = scan_with_progress_bar(path, &pbar); let one_filesystem = if one_filesystem { Some(None) } else { None };
let result = scan_with_progress_bar(path, &pbar, one_filesystem);
pbar.finish_at_current_pos(); pbar.finish_at_current_pos();
result result
} }
@ -230,6 +232,7 @@ pub fn scan(path: &Path) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
pub fn scan_with_progress_bar( pub fn scan_with_progress_bar(
path: &Path, path: &Path,
progress_bar: &ProgressBar, progress_bar: &ProgressBar,
mut one_filesystem: Option<Option<u64>>,
) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> { ) -> anyhow::Result<Option<FileTree<(), (), (), ()>>> {
let metadata_res = symlink_metadata(path); let metadata_res = symlink_metadata(path);
progress_bar.inc(1); progress_bar.inc(1);
@ -249,6 +252,14 @@ pub fn scan_with_progress_bar(
let metadata = metadata_res?; let metadata = metadata_res?;
let filetype = metadata.file_type(); let filetype = metadata.file_type();
if let Some(one_filesystem) = one_filesystem.as_mut() {
let this_fs = metadata.dev();
if *one_filesystem.get_or_insert(this_fs) != this_fs {
info!("Stopping at filesystem boundary: {:?}", path);
return Ok(None);
}
}
/*let name = path /*let name = path
.file_name() .file_name()
.ok_or(anyhow!("No filename, wat"))? .ok_or(anyhow!("No filename, wat"))?
@ -294,7 +305,7 @@ pub fn scan_with_progress_bar(
for entry in dir_read? { for entry in dir_read? {
let entry: DirEntry = entry?; let entry: DirEntry = entry?;
let scanned = scan_with_progress_bar(&entry.path(), progress_bar)?; let scanned = scan_with_progress_bar(&entry.path(), progress_bar, one_filesystem)?;
if let Some(scanned) = scanned { if let Some(scanned) = scanned {
children.insert( children.insert(
entry entry