Change the errors away from using anyhow and add --all to empty
This commit is contained in:
parent
5579e5b951
commit
2d0421f041
14 changed files with 109 additions and 76 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -9,12 +9,6 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.33"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
@ -194,7 +188,6 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
|
||||||
name = "garbage"
|
name = "garbage"
|
||||||
version = "0.2.2"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"chrono",
|
"chrono",
|
||||||
"chrono-humanize",
|
"chrono-humanize",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
|
|
@ -11,7 +11,6 @@ name = "garbage"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
chrono-humanize = "0.1.1"
|
chrono-humanize = "0.1.1"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
|
|
|
@ -131,6 +131,7 @@ impl Iterator for TrashDirIter {
|
||||||
&name.as_bytes()[..name.len() - b".trashinfo".len()],
|
&name.as_bytes()[..name.len() - b".trashinfo".len()],
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
TrashInfo::from_files(entry.path(), deleted_path)
|
TrashInfo::from_files(entry.path(), deleted_path)
|
||||||
.map_err(Error::from),
|
.map_err(Error::from),
|
||||||
|
|
|
@ -1,15 +1,38 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
/// Result convenience type for the Error type
|
||||||
|
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
||||||
/// All errors that could happen
|
/// All errors that could happen
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("IO error: {0}")]
|
#[error("IO error: {0}")]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
|
||||||
#[error("Walkdir error: {0}")]
|
#[error("Walkdir error: {0}")]
|
||||||
WalkDir(#[from] walkdir::Error),
|
WalkDir(#[from] walkdir::Error),
|
||||||
#[error("Bad .trashinfo file: {0}")]
|
|
||||||
BadTrashInfo(#[from] TrashInfoError),
|
#[error("Mount error: {0}")]
|
||||||
|
Mount(#[from] libmount::mountinfo::ParseError),
|
||||||
|
|
||||||
|
#[error("Strip prefix error: {0}")]
|
||||||
|
StripPrefix(#[from] std::path::StripPrefixError),
|
||||||
|
|
||||||
|
#[error("Bad .trashinfo file at {0:?}: {1}")]
|
||||||
|
BadTrashInfo(PathBuf, TrashInfoError),
|
||||||
|
|
||||||
#[error("Date parsing error: {0}")]
|
#[error("Date parsing error: {0}")]
|
||||||
ParseDate(#[from] chrono::format::ParseError),
|
ParseDate(#[from] chrono::format::ParseError),
|
||||||
|
|
||||||
|
#[error("No trash directory exists at: {0:?}")]
|
||||||
|
TrashDirDoesntExist(PathBuf),
|
||||||
|
|
||||||
|
#[error("No files in the trash directory: {0:?}")]
|
||||||
|
NoFilesInThisDirectory(PathBuf),
|
||||||
|
|
||||||
|
#[error("Put error: {0}")]
|
||||||
|
Put(#[from] crate::ops::put::PutError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors related to .trashinfo files
|
/// Errors related to .trashinfo files
|
||||||
|
@ -18,8 +41,10 @@ pub enum Error {
|
||||||
pub enum TrashInfoError {
|
pub enum TrashInfoError {
|
||||||
#[error("Missing [TrashInfo] header")]
|
#[error("Missing [TrashInfo] header")]
|
||||||
MissingHeader,
|
MissingHeader,
|
||||||
|
|
||||||
#[error("Missing path attribute")]
|
#[error("Missing path attribute")]
|
||||||
MissingPath,
|
MissingPath,
|
||||||
|
|
||||||
#[error("Missing date attribute")]
|
#[error("Missing date attribute")]
|
||||||
MissingDate,
|
MissingDate,
|
||||||
}
|
}
|
||||||
|
|
11
src/info.rs
11
src/info.rs
|
@ -64,6 +64,7 @@ impl TrashInfo {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if line != "[Trash Info]" {
|
if line != "[Trash Info]" {
|
||||||
return Err(Error::BadTrashInfo(
|
return Err(Error::BadTrashInfo(
|
||||||
|
info_path,
|
||||||
TrashInfoError::MissingHeader,
|
TrashInfoError::MissingHeader,
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
@ -94,14 +95,20 @@ impl TrashInfo {
|
||||||
let path = match path {
|
let path = match path {
|
||||||
Some(path) => path,
|
Some(path) => path,
|
||||||
None => {
|
None => {
|
||||||
return Err(Error::BadTrashInfo(TrashInfoError::MissingPath))
|
return Err(Error::BadTrashInfo(
|
||||||
|
info_path,
|
||||||
|
TrashInfoError::MissingPath,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let deletion_date = match deletion_date {
|
let deletion_date = match deletion_date {
|
||||||
Some(deletion_date) => deletion_date,
|
Some(deletion_date) => deletion_date,
|
||||||
None => {
|
None => {
|
||||||
return Err(Error::BadTrashInfo(TrashInfoError::MissingDate))
|
return Err(Error::BadTrashInfo(
|
||||||
|
info_path,
|
||||||
|
TrashInfoError::MissingDate,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ extern crate lazy_static;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate structopt;
|
extern crate structopt;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate anyhow;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate thiserror;
|
extern crate thiserror;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -26,7 +24,7 @@ use std::path::PathBuf;
|
||||||
use xdg::BaseDirectories;
|
use xdg::BaseDirectories;
|
||||||
|
|
||||||
pub use crate::dir::TrashDir;
|
pub use crate::dir::TrashDir;
|
||||||
pub use crate::errors::Error;
|
pub use crate::errors::{Error, Result};
|
||||||
pub use crate::info::TrashInfo;
|
pub use crate::info::TrashInfo;
|
||||||
use crate::mounts::Mounts;
|
use crate::mounts::Mounts;
|
||||||
|
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -1,10 +1,8 @@
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
extern crate anyhow;
|
use garbage::{
|
||||||
|
ops::{self, EmptyOptions, ListOptions, PutOptions, RestoreOptions},
|
||||||
use anyhow::Result;
|
Result,
|
||||||
use garbage::ops::{
|
|
||||||
self, EmptyOptions, ListOptions, PutOptions, RestoreOptions,
|
|
||||||
};
|
};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
@ -46,7 +44,7 @@ fn main() {
|
||||||
match run() {
|
match run() {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("Error: {:?}", err);
|
eprintln!("Error: {}", err);
|
||||||
// for cause in err.chain() {
|
// for cause in err.chain() {
|
||||||
// eprintln!("- {:?}", cause);
|
// eprintln!("- {:?}", cause);
|
||||||
// }
|
// }
|
||||||
|
|
|
@ -4,9 +4,9 @@ use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Error;
|
|
||||||
use libmount::mountinfo::Parser;
|
use libmount::mountinfo::Parser;
|
||||||
|
|
||||||
|
use crate::errors::Error;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use chrono::{Duration, Local};
|
use chrono::{Duration, Local};
|
||||||
|
|
||||||
|
use crate::errors::Result;
|
||||||
use crate::TrashDir;
|
use crate::TrashDir;
|
||||||
|
|
||||||
/// Options to pass to empty
|
/// Options to pass to empty
|
||||||
|
@ -23,11 +24,16 @@ pub struct EmptyOptions {
|
||||||
/// By default, this is your home directory's trash ($XDG_DATA_HOME/Trash)
|
/// By default, this is your home directory's trash ($XDG_DATA_HOME/Trash)
|
||||||
#[structopt(long = "trash-dir", parse(from_os_str))]
|
#[structopt(long = "trash-dir", parse(from_os_str))]
|
||||||
trash_dir: Option<PathBuf>,
|
trash_dir: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// Delete all files in the trash (by default, only files in the current
|
||||||
|
/// directory are listed)
|
||||||
|
#[structopt(short = "a", long = "all")]
|
||||||
|
all: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Actually delete files in the trash.
|
/// Actually delete files in the trash.
|
||||||
pub fn empty(options: EmptyOptions) -> Result<()> {
|
pub fn empty(options: EmptyOptions) -> Result<()> {
|
||||||
let trash_dir = TrashDir::from_opt(options.trash_dir);
|
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
|
||||||
|
|
||||||
// cutoff date
|
// cutoff date
|
||||||
let cutoff = if let Some(days) = options.days {
|
let cutoff = if let Some(days) = options.days {
|
||||||
|
@ -36,28 +42,32 @@ pub fn empty(options: EmptyOptions) -> Result<()> {
|
||||||
Local::now()
|
Local::now()
|
||||||
};
|
};
|
||||||
|
|
||||||
for file in trash_dir.iter()? {
|
let current_dir = env::current_dir()?;
|
||||||
let file = file?;
|
trash_dir
|
||||||
|
.iter()?
|
||||||
|
.collect::<Result<Vec<_>>>()?
|
||||||
|
.into_iter()
|
||||||
// ignore files that were deleted after the cutoff (younger)
|
// ignore files that were deleted after the cutoff (younger)
|
||||||
let ignore = file.deletion_date > cutoff;
|
.filter(|info| info.deletion_date <= cutoff)
|
||||||
|
.filter(|info| options.all || info.path.starts_with(¤t_dir))
|
||||||
if !ignore {
|
.map(|info| -> Result<_> {
|
||||||
if options.dry {
|
if options.dry {
|
||||||
println!("{:?}", file.path);
|
println!("deleting {:?}", info.path);
|
||||||
} else {
|
} else {
|
||||||
fs::remove_file(file.info_path)?;
|
fs::remove_file(info.info_path)?;
|
||||||
|
|
||||||
if file.deleted_path.exists() {
|
if info.deleted_path.exists() {
|
||||||
if file.deleted_path.is_dir() {
|
if info.deleted_path.is_dir() {
|
||||||
fs::remove_dir_all(file.deleted_path)?;
|
fs::remove_dir_all(info.deleted_path)?;
|
||||||
} else {
|
} else {
|
||||||
fs::remove_file(file.deleted_path)?;
|
fs::remove_file(info.deleted_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
Ok(())
|
||||||
|
})
|
||||||
|
.collect::<Result<_>>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use crate::dir::TrashDir;
|
||||||
|
use crate::errors::Result;
|
||||||
use crate::list;
|
use crate::list;
|
||||||
use crate::TrashDir;
|
|
||||||
|
|
||||||
/// Options to pass to list
|
/// Options to pass to list
|
||||||
#[derive(StructOpt)]
|
#[derive(StructOpt)]
|
||||||
|
@ -25,19 +24,16 @@ pub fn list(options: ListOptions) -> Result<()> {
|
||||||
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
|
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
|
||||||
|
|
||||||
let current_dir = env::current_dir()?;
|
let current_dir = env::current_dir()?;
|
||||||
|
|
||||||
let mut files = trash_dir
|
let mut files = trash_dir
|
||||||
.iter()
|
.iter()?
|
||||||
.unwrap()
|
.collect::<Result<Vec<_>>>()?
|
||||||
.filter_map(|entry| match entry {
|
.into_iter()
|
||||||
Ok(info) => {
|
.filter_map(|info| {
|
||||||
if !options.all && !info.path.starts_with(¤t_dir) {
|
if !options.all && !info.path.starts_with(¤t_dir) {
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(info)
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
eprintln!("failed to get file info: {:?}", err);
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(info)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! Operations that garbage can do.
|
//! Operations that garbage can do.
|
||||||
|
|
||||||
mod empty;
|
pub(crate) mod empty;
|
||||||
mod list;
|
pub(crate) mod list;
|
||||||
mod put;
|
pub(crate) mod put;
|
||||||
mod restore;
|
pub(crate) mod restore;
|
||||||
|
|
||||||
pub use self::empty::{empty, EmptyOptions};
|
pub use self::empty::{empty, EmptyOptions};
|
||||||
pub use self::list::{list, ListOptions};
|
pub use self::list::{list, ListOptions};
|
||||||
|
|
|
@ -4,15 +4,15 @@ use std::io::{self, Write};
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
|
|
||||||
|
use crate::errors::{Error, Result};
|
||||||
use crate::utils::{self};
|
use crate::utils::{self};
|
||||||
use crate::{TrashDir, TrashInfo};
|
use crate::{TrashDir, TrashInfo};
|
||||||
use crate::{HOME_MOUNT, MOUNTS};
|
use crate::{HOME_MOUNT, MOUNTS};
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum PutError {
|
||||||
// #[error("Refusing to remove directory {0} without '-r' option")]
|
// #[error("Refusing to remove directory {0} without '-r' option")]
|
||||||
// MissingRecursiveOption(PathBuf),
|
// MissingRecursiveOption(PathBuf),
|
||||||
#[error("Refusing to remove '.' or '..', skipping...")]
|
#[error("Refusing to remove '.' or '..', skipping...")]
|
||||||
|
@ -23,6 +23,9 @@ pub enum Error {
|
||||||
|
|
||||||
#[error("Invalid filename.")]
|
#[error("Invalid filename.")]
|
||||||
InvalidFilename,
|
InvalidFilename,
|
||||||
|
|
||||||
|
#[error("Couldn't find mount point.")]
|
||||||
|
CouldntFindMountPoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Options to pass to put
|
/// Options to pass to put
|
||||||
|
@ -65,13 +68,14 @@ pub fn put(options: PutOptions) -> Result<()> {
|
||||||
for path in options.paths.iter() {
|
for path in options.paths.iter() {
|
||||||
// don't allow deleting '.' or '..'
|
// don't allow deleting '.' or '..'
|
||||||
let current_dir = env::current_dir()?;
|
let current_dir = env::current_dir()?;
|
||||||
ensure!(
|
|
||||||
!(utils::into_absolute(&path)? == current_dir.as_path()
|
if !(utils::into_absolute(&path)? == current_dir.as_path()
|
||||||
|| (current_dir.parent().is_some()
|
|| (current_dir.parent().is_some()
|
||||||
&& utils::into_absolute(&path)?
|
&& utils::into_absolute(&path)?
|
||||||
== current_dir.parent().unwrap())),
|
== current_dir.parent().unwrap()))
|
||||||
Error::CannotTrashDotDirs
|
{
|
||||||
);
|
return Err(Error::Put(PutError::CannotTrashDotDirs));
|
||||||
|
}
|
||||||
|
|
||||||
// pick the best strategy for deleting this particular file
|
// pick the best strategy for deleting this particular file
|
||||||
let strategy = if let Some(ref trash_dir) = options.trash_dir {
|
let strategy = if let Some(ref trash_dir) = options.trash_dir {
|
||||||
|
@ -112,7 +116,7 @@ impl DeletionStrategy {
|
||||||
let target = target.as_ref();
|
let target = target.as_ref();
|
||||||
let target_mount = MOUNTS
|
let target_mount = MOUNTS
|
||||||
.get_mount_point(target)
|
.get_mount_point(target)
|
||||||
.ok_or_else(|| anyhow!("couldn't get mount point"))?;
|
.ok_or_else(|| PutError::CouldntFindMountPoint)?;
|
||||||
|
|
||||||
// first, are we on the home mount?
|
// first, are we on the home mount?
|
||||||
if target_mount == *HOME_MOUNT {
|
if target_mount == *HOME_MOUNT {
|
||||||
|
@ -193,7 +197,7 @@ impl DeletionStrategy {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if !should_continue {
|
if !should_continue {
|
||||||
bail!(Error::CancelledByUser);
|
return Err(Error::Put(PutError::CancelledByUser));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,9 +208,9 @@ impl DeletionStrategy {
|
||||||
let elapsed_str = elapsed.to_string();
|
let elapsed_str = elapsed.to_string();
|
||||||
let target_file = match target.file_name() {
|
let target_file = match target.file_name() {
|
||||||
Some(file) => file.to_os_string(),
|
Some(file) => file.to_os_string(),
|
||||||
None => bail!(Error::InvalidFilename),
|
None => return Err(Error::Put(PutError::InvalidFilename)),
|
||||||
};
|
};
|
||||||
let file_name = crate::concat_os_str!(elapsed_str, ".", target_file);
|
let file_name = concat_os_str!(elapsed_str, ".", target_file);
|
||||||
// {
|
// {
|
||||||
// let buf = vec![0; elapsed_str.len() + 1 + target_file.len()];
|
// let buf = vec![0; elapsed_str.len() + 1 + target_file.len()];
|
||||||
// unimplemented!()
|
// unimplemented!()
|
||||||
|
@ -220,7 +224,7 @@ impl DeletionStrategy {
|
||||||
let trash_file_path = trash_dir.files_dir()?.join(&file_name);
|
let trash_file_path = trash_dir.files_dir()?.join(&file_name);
|
||||||
let trash_info_path = trash_dir
|
let trash_info_path = trash_dir
|
||||||
.info_dir()?
|
.info_dir()?
|
||||||
.join(crate::concat_os_str!(file_name, ".trashinfo"));
|
.join(concat_os_str!(file_name, ".trashinfo"));
|
||||||
|
|
||||||
let trash_info = TrashInfo {
|
let trash_info = TrashInfo {
|
||||||
path: utils::into_absolute(target)?,
|
path: utils::into_absolute(target)?,
|
||||||
|
|
|
@ -3,8 +3,7 @@ use std::fs;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use anyhow::Result;
|
use crate::errors::{Error, Result};
|
||||||
|
|
||||||
use crate::list;
|
use crate::list;
|
||||||
use crate::TrashDir;
|
use crate::TrashDir;
|
||||||
|
|
||||||
|
@ -27,7 +26,7 @@ pub fn restore(options: RestoreOptions) -> Result<()> {
|
||||||
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
|
let trash_dir = TrashDir::from_opt(options.trash_dir.as_ref());
|
||||||
|
|
||||||
if trash_dir.check_info_dir()?.is_none() {
|
if trash_dir.check_info_dir()?.is_none() {
|
||||||
bail!("There's no trash directory here.");
|
return Err(Error::TrashDirDoesntExist(trash_dir.path().to_path_buf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// get list of files sorted by deletion date
|
// get list of files sorted by deletion date
|
||||||
|
@ -55,7 +54,9 @@ pub fn restore(options: RestoreOptions) -> Result<()> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if files.len() == 0 {
|
if files.len() == 0 {
|
||||||
bail!("No files in this trash directory.");
|
return Err(Error::NoFilesInThisDirectory(
|
||||||
|
trash_dir.path().to_path_buf(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
list::print_files_list(files.iter(), true);
|
list::print_files_list(files.iter(), true);
|
||||||
|
|
|
@ -4,10 +4,11 @@ use std::fs;
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
|
use std::path::{Component, Path, PathBuf, MAIN_SEPARATOR};
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use percent_encoding::AsciiSet;
|
use percent_encoding::AsciiSet;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::errors::Result;
|
||||||
|
|
||||||
const MASK: &AsciiSet = percent_encoding::CONTROLS;
|
const MASK: &AsciiSet = percent_encoding::CONTROLS;
|
||||||
|
|
||||||
pub fn into_absolute(path: impl AsRef<Path>) -> Result<PathBuf> {
|
pub fn into_absolute(path: impl AsRef<Path>) -> Result<PathBuf> {
|
||||||
|
|
Loading…
Add table
Reference in a new issue