feat(fs): add .path(path).rename()
This commit is contained in:
parent
afee181872
commit
f825aad327
5 changed files with 86 additions and 10 deletions
|
@ -17,7 +17,7 @@ Provides injectable Filesystem and Network resources to make code more testable.
|
||||||
- [x] `std::fs::remove_dir` - `dir(path).remove()` - Removes an empty directory.
|
- [x] `std::fs::remove_dir` - `dir(path).remove()` - Removes an empty directory.
|
||||||
- [x] `std::fs::remove_dir_all` - `dir(path).remove_all()` - Removes a directory at this path, after removing all its contents. Use carefully!
|
- [x] `std::fs::remove_dir_all` - `dir(path).remove_all()` - Removes a directory at this path, after removing all its contents. Use carefully!
|
||||||
- [x] `std::fs::remove_file` - `file(path).remove()` - Removes a file from the filesystem.
|
- [x] `std::fs::remove_file` - `file(path).remove()` - Removes a file from the filesystem.
|
||||||
- [ ] `std::fs::rename` - `path(path).rename()` - Rename a file or directory to a new name, replacing the original file if to already exists.
|
- [x] `std::fs::rename` - `path(path).rename()` - Rename a file or directory to a new name, replacing the original file if to already exists.
|
||||||
- [ ] `std::fs::set_permissions` - `path(path).set_permissions()` - Changes the permissions found on a file or a directory.
|
- [ ] `std::fs::set_permissions` - `path(path).set_permissions()` - Changes the permissions found on a file or a directory.
|
||||||
- [ ] `std::fs::symlink_metadata` - `link(path).metadata()` - Query the metadata about a file without following symlinks.
|
- [ ] `std::fs::symlink_metadata` - `link(path).metadata()` - Query the metadata about a file without following symlinks.
|
||||||
- [x] `std::fs::write` - `file(path).write()` - Write a slice as the entire contents of a file.
|
- [x] `std::fs::write` - `file(path).write()` - Write a slice as the entire contents of a file.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use crate::fs::{DirItem, DirItemIterator, Result};
|
use crate::fs::{DirItem, DirItemIterator, Result};
|
||||||
|
|
||||||
use super::{DirHandle, Error, FileHandle, PathHandle};
|
use super::{DirHandle, Error, FileHandle, PathHandle, PathMarker};
|
||||||
|
|
||||||
impl<'base, 'path> DirHandle<'base, 'path> {
|
impl<'base, 'path> DirHandle<'base, 'path> {
|
||||||
/// Creates a new, empty directory at the path
|
/// Creates a new, empty directory at the path
|
||||||
|
@ -93,10 +93,12 @@ impl<'base, 'path> DirHandle<'base, 'path> {
|
||||||
std::fs::remove_dir_all(self.as_pathbuf()).map_err(Error::Io)
|
std::fs::remove_dir_all(self.as_pathbuf()).map_err(Error::Io)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'base, 'path> TryFrom<PathHandle<'base, 'path>> for FileHandle<'base, 'path> {
|
impl<'base, 'path> TryFrom<PathHandle<'base, 'path, PathMarker>> for FileHandle<'base, 'path> {
|
||||||
type Error = crate::fs::Error;
|
type Error = crate::fs::Error;
|
||||||
|
|
||||||
fn try_from(path: PathHandle<'base, 'path>) -> std::result::Result<Self, Self::Error> {
|
fn try_from(
|
||||||
|
path: PathHandle<'base, 'path, PathMarker>,
|
||||||
|
) -> std::result::Result<Self, Self::Error> {
|
||||||
match path.as_file() {
|
match path.as_file() {
|
||||||
Ok(Some(dir)) => Ok(dir.clone()),
|
Ok(Some(dir)) => Ok(dir.clone()),
|
||||||
Ok(None) => Err(crate::fs::Error::NotADirectory {
|
Ok(None) => Err(crate::fs::Error::NotADirectory {
|
||||||
|
@ -106,10 +108,12 @@ impl<'base, 'path> TryFrom<PathHandle<'base, 'path>> for FileHandle<'base, 'path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'base, 'path> TryFrom<PathHandle<'base, 'path>> for DirHandle<'base, 'path> {
|
impl<'base, 'path> TryFrom<PathHandle<'base, 'path, PathMarker>> for DirHandle<'base, 'path> {
|
||||||
type Error = crate::fs::Error;
|
type Error = crate::fs::Error;
|
||||||
|
|
||||||
fn try_from(path: PathHandle<'base, 'path>) -> std::result::Result<Self, Self::Error> {
|
fn try_from(
|
||||||
|
path: PathHandle<'base, 'path, PathMarker>,
|
||||||
|
) -> std::result::Result<Self, Self::Error> {
|
||||||
match path.as_dir() {
|
match path.as_dir() {
|
||||||
Ok(Some(dir)) => Ok(dir.clone()),
|
Ok(Some(dir)) => Ok(dir.clone()),
|
||||||
Ok(None) => Err(crate::fs::Error::NotADirectory {
|
Ok(None) => Err(crate::fs::Error::NotADirectory {
|
||||||
|
|
|
@ -203,9 +203,41 @@ impl<'base, 'path, T: PathType> PathReal<'base, 'path, T> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Renames a path.
|
||||||
|
///
|
||||||
|
/// Wrapper for [std::fs::rename]
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # use kxio::fs::Result;
|
||||||
|
/// # fn main() -> Result<()> {
|
||||||
|
/// let fs = kxio::fs::temp()?;
|
||||||
|
/// let src_path = fs.base().join("foo");
|
||||||
|
/// let src = fs.file(&src_path);
|
||||||
|
/// # src.write("bar")?;
|
||||||
|
/// let dst_path = fs.base().join("bar");
|
||||||
|
/// let dst = fs.file(&dst_path);
|
||||||
|
/// src.rename(&dst)?;
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
pub fn rename(&self, dest: &PathHandle<'base, 'path, T>) -> Result<()> {
|
||||||
|
self.check_error()?;
|
||||||
|
std::fs::rename(self.as_pathbuf(), dest.as_pathbuf()).map_err(Error::Io)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl<'base, 'path> From<PathHandle<'base, 'path>> for PathBuf {
|
impl<'base, 'path> From<PathHandle<'base, 'path, PathMarker>> for PathBuf {
|
||||||
fn from(path: PathReal<PathMarker>) -> Self {
|
fn from(path: PathReal<PathMarker>) -> Self {
|
||||||
path.base.join(path.path)
|
path.base.join(path.path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'base, 'path> From<DirHandle<'base, 'path>> for PathHandle<'base, 'path, PathMarker> {
|
||||||
|
fn from(dir: DirHandle<'base, 'path>) -> Self {
|
||||||
|
PathReal::new(dir.base, dir.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'base, 'path> From<FileHandle<'base, 'path>> for PathHandle<'base, 'path, PathMarker> {
|
||||||
|
fn from(file: FileHandle<'base, 'path>) -> Self {
|
||||||
|
PathReal::new(file.base, file.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,10 @@ use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::fs::{Error, Result};
|
use crate::fs::{Error, Result};
|
||||||
|
|
||||||
use super::path::{DirMarker, FileMarker, PathMarker, PathReal};
|
use super::{
|
||||||
|
path::{DirMarker, FileMarker, PathReal},
|
||||||
|
PathMarker,
|
||||||
|
};
|
||||||
|
|
||||||
/// Represents to base of a section of a file system.
|
/// Represents to base of a section of a file system.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -18,7 +21,7 @@ pub type DirHandle<'base, 'path> = PathReal<'base, 'path, DirMarker>;
|
||||||
pub type FileHandle<'base, 'path> = PathReal<'base, 'path, FileMarker>;
|
pub type FileHandle<'base, 'path> = PathReal<'base, 'path, FileMarker>;
|
||||||
|
|
||||||
/// Represents a path in the filesystem.
|
/// Represents a path in the filesystem.
|
||||||
pub type PathHandle<'base, 'path> = PathReal<'base, 'path, PathMarker>;
|
pub type PathHandle<'base, 'path, T> = PathReal<'base, 'path, T>;
|
||||||
|
|
||||||
impl FileSystem {
|
impl FileSystem {
|
||||||
pub const fn new(base: PathBuf) -> Self {
|
pub const fn new(base: PathBuf) -> Self {
|
||||||
|
@ -121,7 +124,10 @@ impl FileSystem {
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn path<'base, 'path>(&'base self, path: &'path Path) -> PathHandle<'base, 'path> {
|
pub fn path<'base, 'path>(
|
||||||
|
&'base self,
|
||||||
|
path: &'path Path,
|
||||||
|
) -> PathHandle<'base, 'path, PathMarker> {
|
||||||
PathReal::new(self.base(), path)
|
PathReal::new(self.base(), path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
tests/fs.rs
34
tests/fs.rs
|
@ -448,6 +448,40 @@ mod path_is_file {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mod path_rename {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn should_rename_a_file() -> TestResult {
|
||||||
|
let fs = fs::temp().expect("temp fs");
|
||||||
|
let src_path = fs.base().join("foo");
|
||||||
|
let src = fs.file(&src_path);
|
||||||
|
src.write("bar").expect("write");
|
||||||
|
let src_contents = src.reader().expect("reader").to_string();
|
||||||
|
let dst_path = fs.base().join("bar");
|
||||||
|
let dst = fs.file(&dst_path);
|
||||||
|
src.rename(&dst).expect("rename");
|
||||||
|
let dst_contents = dst.reader().expect("reader").to_string();
|
||||||
|
assert_eq!(src_contents, dst_contents);
|
||||||
|
let src_exists = src.exists().expect("exists");
|
||||||
|
assert!(!src_exists);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_fail_on_path_traversal() -> TestResult {
|
||||||
|
let fs = fs::temp().expect("temp fs");
|
||||||
|
let src_path = fs.base().join("..").join("foo");
|
||||||
|
let_assert!(
|
||||||
|
Err(fs::Error::PathTraversal {
|
||||||
|
base: _base,
|
||||||
|
path: _path
|
||||||
|
}) = fs.file(&src_path).rename(&fs.file(&src_path))
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
mod copy {
|
mod copy {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue