use std::path::PathBuf;
use std::result;
use glob::{glob, Paths};
use ignore::gitignore::{Gitignore, GitignoreBuilder};
use num_cpus;
use structopt::StructOpt;
use unbytify::unbytify;
use walkdir::{DirEntry};
use crate::errors::Result;
use crate::drivers::Drivers;
#[derive(Clone, Debug, StructOpt)]
#[structopt(
name = "xcp",
about = "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.",
setting = structopt::clap::AppSettings::ColoredHelp
)]
pub struct Opts {
#[structopt(short = "v", long = "verbose", parse(from_occurrences))]
pub verbose: u64,
#[structopt(short = "r", long = "recursive")]
pub recursive: bool,
#[structopt(short = "w", long = "workers", default_value = "4")]
pub workers: i64,
#[structopt(long = "block-size", default_value = "1MB", parse(try_from_str = unbytify))]
pub block_size: u64,
#[structopt(short = "n", long = "no-clobber")]
pub noclobber: bool,
#[structopt(long = "gitignore")]
pub gitignore: bool,
#[structopt(short = "g", long = "glob")]
pub glob: bool,
#[structopt(long = "no-progress")]
pub noprogress: bool,
#[structopt(long = "no-perms")]
pub no_perms: bool,
#[structopt(long = "driver")]
pub driver: Option<Drivers>,
#[structopt(short = "T", long = "no-target-directory" )]
pub no_target_directory: bool,
#[structopt(required = true, min_values = 2 )]
pub paths: Vec<String>,
}
pub fn num_workers(opts: &Opts) -> u64 {
if opts.workers <= 0 {
num_cpus::get() as u64
} else {
opts.workers as u64
}
}
pub fn expand_globs(patterns: &[String]) -> Result<Vec<PathBuf>> {
let mut globs = patterns
.iter()
.map(|s| glob(&*s.as_str())) .collect::<result::Result<Vec<Paths>, _>>()?; let path_vecs = globs
.iter_mut()
.map::<result::Result<Vec<PathBuf>, _>, _>(|p| p.collect())
.collect::<result::Result<Vec<Vec<PathBuf>>, _>>()?;
let paths = path_vecs
.iter()
.flat_map(|p| p.to_owned())
.collect::<Vec<PathBuf>>();
Ok(paths)
}
pub fn to_pathbufs(paths: &[String]) -> Vec<PathBuf> {
paths
.iter()
.map(PathBuf::from)
.collect::<Vec<PathBuf>>()
}
pub fn expand_sources(source_list: &[String], opts: &Opts) -> Result<Vec<PathBuf>> {
if opts.glob {
expand_globs(&source_list)
} else {
Ok(to_pathbufs(source_list))
}
}
pub fn parse_ignore(source: &PathBuf, opts: &Opts) -> Result<Option<Gitignore>> {
let gitignore = if opts.gitignore {
let mut builder = GitignoreBuilder::new(&source);
builder.add(&source.join(".gitignore"));
let ignore = builder.build()?;
Some(ignore)
} else {
None
};
Ok(gitignore)
}
pub fn ignore_filter(entry: &DirEntry, ignore: &Option<Gitignore>) -> bool {
match ignore {
None => true,
Some(gi) => {
let path = entry.path();
let m = gi.matched(&path, path.is_dir());
!m.is_ignore()
}
}
}