refactor: switch to own quirks_path
This commit is contained in:
parent
b996be0702
commit
8c460dfdc0
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -3584,6 +3584,7 @@ dependencies = [
|
|||||||
"maplit",
|
"maplit",
|
||||||
"opendal",
|
"opendal",
|
||||||
"qbit-rs",
|
"qbit-rs",
|
||||||
|
"quirks_path",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"rss",
|
"rss",
|
||||||
@ -3600,7 +3601,6 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"uni-path",
|
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
"validator",
|
"validator",
|
||||||
@ -5592,12 +5592,6 @@ version = "0.1.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "uni-path"
|
|
||||||
version = "1.51.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25e328d505b1f855c20e7358711b7ec6398524181664f016dd15cfb36c3a6275"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unic-char-property"
|
name = "unic-char-property"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
|
@ -10,6 +10,7 @@ use std::{
|
|||||||
collections::TryReserveError,
|
collections::TryReserveError,
|
||||||
error::Error,
|
error::Error,
|
||||||
fmt,
|
fmt,
|
||||||
|
fmt::Formatter,
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
io,
|
io,
|
||||||
iter::FusedIterator,
|
iter::FusedIterator,
|
||||||
@ -20,7 +21,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use ::url::Url;
|
use ::url::Url;
|
||||||
pub use url::PathToUrlError;
|
pub use url::{path_equals_as_file_url, PathToUrlError};
|
||||||
use windows::is_windows_sep;
|
use windows::is_windows_sep;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -707,7 +708,7 @@ impl PathBuf {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push<P: AsRef<Path>>(&mut self, path: P) {
|
pub fn push<P: AsRef<Path>>(&mut self, path: P) {
|
||||||
self._push(path.as_ref())
|
self._push(path.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,6 +992,12 @@ impl fmt::Debug for PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PathBuf {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&**self, formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Deref for PathBuf {
|
impl Deref for PathBuf {
|
||||||
type Target = Path;
|
type Target = Path;
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -1364,6 +1371,12 @@ impl fmt::Debug for Path {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Path {
|
||||||
|
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
fmt::Display::fmt(&self.inner, formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Path {
|
impl PartialEq for Path {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Path) -> bool {
|
fn eq(&self, other: &Path) -> bool {
|
||||||
|
@ -95,3 +95,13 @@ pub(crate) fn path_to_file_url_segments(
|
|||||||
|
|
||||||
Ok((host_end, host_internal))
|
Ok((host_end, host_internal))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn path_equals_as_file_url<A: AsRef<Path>, B: AsRef<Path>>(
|
||||||
|
a: A,
|
||||||
|
b: B,
|
||||||
|
) -> Result<bool, PathToUrlError> {
|
||||||
|
let u1 = a.as_ref().to_file_url()?;
|
||||||
|
let u2 = b.as_ref().to_file_url()?;
|
||||||
|
|
||||||
|
Ok(u1.as_str() == u2.as_str())
|
||||||
|
}
|
||||||
|
@ -53,12 +53,12 @@ fancy-regex = "0.13.0"
|
|||||||
regex = "1.10.3"
|
regex = "1.10.3"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
uni-path = "1.51.1"
|
|
||||||
tl = { version = "0.7.8", features = ["simd"] }
|
tl = { version = "0.7.8", features = ["simd"] }
|
||||||
lightningcss = "1.0.0-alpha.54"
|
lightningcss = "1.0.0-alpha.54"
|
||||||
html-escape = "0.2.13"
|
html-escape = "0.2.13"
|
||||||
opendal = "0.45.0"
|
opendal = "0.45.0"
|
||||||
librqbit-core = "3.5.0"
|
librqbit-core = "3.5.0"
|
||||||
|
quirks_path = { path = "../quirks_path" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
serial_test = "2.0.0"
|
serial_test = "2.0.0"
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use axum::Router;
|
|
||||||
use loco_rs::{
|
use loco_rs::{
|
||||||
app::{AppContext, Hooks},
|
app::{AppContext, Hooks},
|
||||||
boot::{create_app, BootResult, StartMode},
|
boot::{create_app, BootResult, StartMode},
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use opendal::{layers::LoggingLayer, services, Operator};
|
use opendal::{layers::LoggingLayer, services, Operator};
|
||||||
|
use quirks_path::{Path, PathBuf};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{
|
use crate::config::AppDalConf;
|
||||||
config::AppDalConf,
|
|
||||||
path::{VFSSubPath, VFSSubPathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
@ -50,8 +48,8 @@ impl AppDalContext {
|
|||||||
let basename = format!("{}{}", Uuid::new_v4(), extname);
|
let basename = format!("{}{}", Uuid::new_v4(), extname);
|
||||||
let mut dirname = [subscriber_pid, content_category.as_ref()]
|
let mut dirname = [subscriber_pid, content_category.as_ref()]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(VFSSubPath::new)
|
.map(Path::new)
|
||||||
.collect::<VFSSubPathBuf>();
|
.collect::<PathBuf>();
|
||||||
|
|
||||||
let mut fs_builder = services::Fs::default();
|
let mut fs_builder = services::Fs::default();
|
||||||
fs_builder.root(self.config.fs_root.as_str());
|
fs_builder.root(self.config.fs_root.as_str());
|
||||||
|
@ -13,6 +13,7 @@ use qbit_rs::{
|
|||||||
model::{AddTorrentArg, Credential, GetTorrentListArg, NonEmptyStr, SyncData},
|
model::{AddTorrentArg, Credential, GetTorrentListArg, NonEmptyStr, SyncData},
|
||||||
Qbit,
|
Qbit,
|
||||||
};
|
};
|
||||||
|
use quirks_path::{path_equals_as_file_url, Path, PathBuf};
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -24,7 +25,6 @@ use super::{
|
|||||||
use crate::{
|
use crate::{
|
||||||
downloaders::defs::{QbitTorrent, QbitTorrentContent, TorrentContent},
|
downloaders::defs::{QbitTorrent, QbitTorrentContent, TorrentContent},
|
||||||
models::{entities::downloaders, prelude::DownloaderCategory},
|
models::{entities::downloaders, prelude::DownloaderCategory},
|
||||||
path::{path_str_equals, VFSPathBuf, VFSSubPath},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SyncDataCache {
|
pub struct SyncDataCache {
|
||||||
@ -35,7 +35,7 @@ pub struct QBittorrentDownloader {
|
|||||||
pub subscriber_id: i32,
|
pub subscriber_id: i32,
|
||||||
pub endpoint_url: Url,
|
pub endpoint_url: Url,
|
||||||
pub client: Arc<Qbit>,
|
pub client: Arc<Qbit>,
|
||||||
pub save_path: String,
|
pub save_path: PathBuf,
|
||||||
pub wait_sync_timeout: Duration,
|
pub wait_sync_timeout: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ impl QBittorrentDownloader {
|
|||||||
client: Arc::new(client),
|
client: Arc::new(client),
|
||||||
endpoint_url,
|
endpoint_url,
|
||||||
subscriber_id: model.subscriber_id,
|
subscriber_id: model.subscriber_id,
|
||||||
save_path: model.save_path,
|
save_path: model.save_path.into(),
|
||||||
wait_sync_timeout: Duration::from_millis(10000),
|
wait_sync_timeout: Duration::from_millis(10000),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -268,12 +268,15 @@ impl TorrentDownloader for QBittorrentDownloader {
|
|||||||
new_path: &str,
|
new_path: &str,
|
||||||
) -> eyre::Result<()> {
|
) -> eyre::Result<()> {
|
||||||
self.client.rename_file(hash, old_path, new_path).await?;
|
self.client.rename_file(hash, old_path, new_path).await?;
|
||||||
|
let new_path = self.save_path.join(new_path);
|
||||||
|
let save_path = self.save_path.as_path();
|
||||||
self.wait_torrent_contents_until(
|
self.wait_torrent_contents_until(
|
||||||
hash,
|
hash,
|
||||||
|contents| -> bool {
|
|contents| -> bool {
|
||||||
contents
|
contents.iter().any(|c| {
|
||||||
.iter()
|
path_equals_as_file_url(save_path.join(c.get_name()), &new_path)
|
||||||
.any(|c| path_str_equals(c.get_name(), new_path).unwrap_or(false))
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
@ -291,9 +294,9 @@ impl TorrentDownloader for QBittorrentDownloader {
|
|||||||
.build(),
|
.build(),
|
||||||
|torrents| -> bool {
|
|torrents| -> bool {
|
||||||
torrents.iter().all(|t| {
|
torrents.iter().all(|t| {
|
||||||
t.save_path
|
t.save_path.as_ref().map_or(false, |p| {
|
||||||
.as_ref()
|
path_equals_as_file_url(p, new_path).unwrap_or(false)
|
||||||
.map_or(false, |p| path_str_equals(p, new_path).unwrap_or(false))
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
None,
|
None,
|
||||||
@ -396,8 +399,8 @@ impl TorrentDownloader for QBittorrentDownloader {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_save_path(&self, sub_path: &VFSSubPath) -> VFSPathBuf {
|
fn get_save_path(&self, sub_path: &Path) -> PathBuf {
|
||||||
VFSPathBuf::new(self.save_path.clone(), sub_path.to_path_buf())
|
self.save_path.join(sub_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,7 +466,7 @@ pub mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn test_qbittorrent_downloader_impl() {
|
async fn test_qbittorrent_downloader_impl() {
|
||||||
let base_save_path = VFSSubPath::new(get_tmp_qbit_test_folder());
|
let base_save_path = Path::new(get_tmp_qbit_test_folder());
|
||||||
|
|
||||||
let downloader = QBittorrentDownloader::from_downloader_model(downloaders::Model {
|
let downloader = QBittorrentDownloader::from_downloader_model(downloaders::Model {
|
||||||
created_at: Default::default(),
|
created_at: Default::default(),
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use downloaders::DownloaderCategory;
|
use downloaders::DownloaderCategory;
|
||||||
|
use quirks_path::{Path, PathBuf};
|
||||||
use sea_orm::{ActiveModelTrait, ActiveValue, DatabaseConnection, IntoActiveModel};
|
use sea_orm::{ActiveModelTrait, ActiveValue, DatabaseConnection, IntoActiveModel};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -8,7 +9,7 @@ use super::{
|
|||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{bangumi, downloaders, downloads},
|
models::{bangumi, downloaders, downloads},
|
||||||
path::{torrent_path::gen_bangumi_sub_path, VFSPathBuf, VFSSubPath},
|
path::torrent_path::gen_bangumi_sub_path,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
@ -48,7 +49,7 @@ pub trait TorrentDownloader {
|
|||||||
|
|
||||||
async fn add_category(&self, category: &str) -> eyre::Result<()>;
|
async fn add_category(&self, category: &str) -> eyre::Result<()>;
|
||||||
|
|
||||||
fn get_save_path(&self, sub_path: &VFSSubPath) -> VFSPathBuf;
|
fn get_save_path(&self, sub_path: &Path) -> PathBuf;
|
||||||
|
|
||||||
async fn add_downloads_for_bangumi<'a, 'b>(
|
async fn add_downloads_for_bangumi<'a, 'b>(
|
||||||
&self,
|
&self,
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
use quirks_path::Path;
|
||||||
|
|
||||||
use super::defs::{
|
use super::defs::{
|
||||||
BRACKETS_REG, DIGIT_1PLUS_REG, SEASON_REGEX, SUBTITLE_LANG, TORRENT_PRASE_RULE_REGS,
|
BRACKETS_REG, DIGIT_1PLUS_REG, SEASON_REGEX, SUBTITLE_LANG, TORRENT_PRASE_RULE_REGS,
|
||||||
};
|
};
|
||||||
use crate::path::VFSPath;
|
|
||||||
|
|
||||||
pub fn get_path_basename<'a>(path: &'a VFSPath) -> &'a str {
|
pub fn get_path_basename(path: &Path) -> &str {
|
||||||
path.basename()
|
path.parent().map_or("", |s| s.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_fansub(group_and_title: &str) -> (Option<&str>, &str) {
|
pub fn get_fansub(group_and_title: &str) -> (Option<&str>, &str) {
|
||||||
@ -53,8 +54,8 @@ pub fn get_subtitle_lang(subtitle_name: &str) -> Option<&'static str> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_torrent<'a>(
|
pub fn parse_torrent(
|
||||||
torrent_path: &'a VFSPath<'a>,
|
torrent_path: &Path,
|
||||||
torrent_name: Option<&str>,
|
torrent_name: Option<&str>,
|
||||||
season: Option<i32>,
|
season: Option<i32>,
|
||||||
file_type: Option<&str>,
|
file_type: Option<&str>,
|
||||||
|
@ -1,7 +1 @@
|
|||||||
pub mod torrent_path;
|
pub mod torrent_path;
|
||||||
pub mod vfs_path;
|
|
||||||
|
|
||||||
pub use vfs_path::{
|
|
||||||
path_str_equals, path_str_to_file_url, VFSComponent, VFSComponents, VFSPath, VFSPathBuf,
|
|
||||||
VFSSubPath, VFSSubPathBuf,
|
|
||||||
};
|
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use quirks_path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
downloaders::defs::Torrent,
|
downloaders::defs::Torrent,
|
||||||
models::{bangumi, subscribers},
|
models::{bangumi, subscribers},
|
||||||
parsers::defs::SEASON_REGEX,
|
parsers::defs::SEASON_REGEX,
|
||||||
path::{VFSPath, VFSSubPathBuf},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn check_files(info: &Torrent) -> (Vec<VFSSubPathBuf>, Vec<VFSSubPathBuf>) {
|
pub fn check_files(info: &Torrent) -> (Vec<PathBuf>, Vec<PathBuf>) {
|
||||||
let mut media_list = vec![];
|
let mut media_list = vec![];
|
||||||
let mut subtitle_list = vec![];
|
let mut subtitle_list = vec![];
|
||||||
for f in info.iter_files() {
|
for f in info.iter_files() {
|
||||||
let file_name = VFSSubPathBuf::from(f.get_name());
|
let file_name = PathBuf::from(f.get_name());
|
||||||
let extension = file_name.extension().unwrap_or_default().to_lowercase();
|
let extension = file_name.extension().unwrap_or_default().to_lowercase();
|
||||||
|
|
||||||
match extension.as_str() {
|
match extension.as_str() {
|
||||||
@ -27,8 +28,8 @@ pub fn check_files(info: &Torrent) -> (Vec<VFSSubPathBuf>, Vec<VFSSubPathBuf>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_to_bangumi<'a>(
|
pub fn path_to_bangumi<'a>(
|
||||||
save_path: VFSPath<'a>,
|
save_path: &'a Path,
|
||||||
downloader_path: VFSPath<'a>,
|
downloader_path: &'a Path,
|
||||||
) -> Option<(&'a str, i32)> {
|
) -> Option<(&'a str, i32)> {
|
||||||
let downloader_parts = downloader_path
|
let downloader_parts = downloader_path
|
||||||
.components()
|
.components()
|
||||||
@ -57,16 +58,16 @@ pub fn path_to_bangumi<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_depth(path: &VFSPath<'_>) -> usize {
|
pub fn file_depth(path: &Path) -> usize {
|
||||||
path.components().count()
|
path.components().count()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ep(path: &VFSPath<'_>) -> bool {
|
pub fn is_ep(path: &Path) -> bool {
|
||||||
file_depth(path) <= 2
|
file_depth(path) <= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_bangumi_sub_path(data: &bangumi::Model) -> VFSSubPathBuf {
|
pub fn gen_bangumi_sub_path(data: &bangumi::Model) -> PathBuf {
|
||||||
VFSSubPathBuf::from(data.official_title.to_string()).join(format!("Season {}", data.season))
|
PathBuf::from(data.official_title.to_string()).join(format!("Season {}", data.season))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rule_name(bgm: &bangumi::Model, conf: &subscribers::SubscriberBangumiConfig) -> String {
|
pub fn rule_name(bgm: &bangumi::Model, conf: &subscribers::SubscriberBangumiConfig) -> String {
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
use std::{borrow::Cow, collections::VecDeque, path::PathBuf};
|
|
||||||
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
pub use uni_path::{Path as VFSSubPath, PathBuf as VFSSubPathBuf};
|
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::parsers::errors::ParseError;
|
|
||||||
|
|
||||||
pub fn path_str_to_file_url(path: &str) -> eyre::Result<Url> {
|
|
||||||
Url::parse(&format!("file:///{path}")).map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn path_str_equals(p1: &str, p2: &str) -> eyre::Result<bool> {
|
|
||||||
let p1 = path_str_to_file_url(p1)?;
|
|
||||||
let p2 = path_str_to_file_url(p2)?;
|
|
||||||
Ok(p1.as_str() == p2.as_str())
|
|
||||||
}
|
|
||||||
|
|
||||||
const VFS_EMPTY_STR: &str = "";
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
pub static ref VFS_SUB_ROOT_BUF: VFSSubPathBuf = VFSSubPathBuf::from("/");
|
|
||||||
pub static ref VFS_SUB_ROOT: &'static VFSSubPath = &VFS_SUB_ROOT_BUF.as_path();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type VFSComponents<'a> = uni_path::Components<'a>;
|
|
||||||
pub type VFSComponent<'a> = uni_path::Component<'a>;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct VFSPath<'a> {
|
|
||||||
pub root: &'a str,
|
|
||||||
pub sub: &'a VFSSubPath,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> VFSPath<'a> {
|
|
||||||
pub fn new(root: &'a str, sub: &'a VFSSubPath) -> VFSPath<'a> {
|
|
||||||
Self { root, sub }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn file_name(&self) -> Option<&str> {
|
|
||||||
self.sub.file_name()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parent(&self) -> Option<VFSPath> {
|
|
||||||
self.sub.parent().map(|p| Self::new(self.root, p))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dirname(&'a self) -> VFSPath<'a> {
|
|
||||||
self.parent()
|
|
||||||
.unwrap_or_else(|| Self::new(self.root, &VFS_SUB_ROOT))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn basename(&self) -> &str {
|
|
||||||
self.file_name().unwrap_or(VFS_EMPTY_STR)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn components(&self) -> VFSComponents<'a> {
|
|
||||||
self.sub.components()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn join<P: AsRef<VFSSubPath>>(&self, path: P) -> VFSPathBuf {
|
|
||||||
VFSPathBuf::new(self.root, self.sub.join(path))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extension(&self) -> Option<&str> {
|
|
||||||
self.sub.extension()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn extname(&self) -> &str {
|
|
||||||
self.extension().unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_std_path_buf(&self) -> PathBuf {
|
|
||||||
PathBuf::from(self.root).join(self.sub.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct VFSPathBuf {
|
|
||||||
root: String,
|
|
||||||
sub: VFSSubPathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VFSPathBuf {
|
|
||||||
pub fn new<R: Into<String>, S: Into<VFSSubPathBuf>>(root: R, sub: S) -> Self {
|
|
||||||
Self {
|
|
||||||
root: root.into(),
|
|
||||||
sub: sub.into(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_root(root: &str) -> Result<Self, ParseError> {
|
|
||||||
Ok(Self {
|
|
||||||
root: root.to_string(),
|
|
||||||
sub: VFS_SUB_ROOT_BUF.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_path(&self) -> VFSPath {
|
|
||||||
VFSPath::new(&self.root as &str, self.sub.as_path())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push<P: AsRef<VFSSubPath>>(&mut self, path: P) {
|
|
||||||
self.sub.push(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pop(&mut self) -> bool {
|
|
||||||
self.sub.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_extension<S: AsRef<str>>(&mut self, ext: S) {
|
|
||||||
self.sub.set_extension(ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_file_name<S: AsRef<str>>(&mut self, file_name: S) {
|
|
||||||
self.sub.set_file_name(file_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Into<PathBuf> for VFSPathBuf {
|
|
||||||
fn into(self) -> PathBuf {
|
|
||||||
let root = self.root;
|
|
||||||
PathBuf::from(root).join(self.sub.as_str())
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user