forked from lix-project/lix
StorePath improvements
This commit is contained in:
parent
cce218f950
commit
6317f0f7a0
|
@ -1,9 +1,13 @@
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
InvalidPath(crate::store::StorePath),
|
InvalidPath(crate::store::StorePath),
|
||||||
BadStorePath(std::path::PathBuf),
|
BadStorePath(std::path::PathBuf),
|
||||||
BadNarInfo,
|
BadNarInfo,
|
||||||
BadBase32,
|
BadBase32,
|
||||||
|
StorePathNameTooLong,
|
||||||
|
BadStorePathName,
|
||||||
IOError(std::io::Error),
|
IOError(std::io::Error),
|
||||||
HttpError(reqwest::Error),
|
HttpError(reqwest::Error),
|
||||||
Misc(String),
|
Misc(String),
|
||||||
|
@ -22,19 +26,30 @@ impl From<reqwest::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Error::InvalidPath(_) => write!(f, "invalid path"),
|
||||||
|
Error::BadNarInfo => write!(f, ".narinfo file is corrupt"),
|
||||||
|
Error::BadStorePath(path) => write!(f, "path '{}' is not a store path", path.display()),
|
||||||
|
Error::BadBase32 => write!(f, "invalid base32 string"),
|
||||||
|
Error::StorePathNameTooLong => {
|
||||||
|
write!(f, "store path name is longer than 211 characters")
|
||||||
|
}
|
||||||
|
Error::BadStorePathName => write!(f, "store path name contains forbidden character"),
|
||||||
|
Error::IOError(err) => write!(f, "I/O error: {}", err),
|
||||||
|
Error::HttpError(err) => write!(f, "HTTP error: {}", err),
|
||||||
|
Error::Foreign(_) => write!(f, "<C++ exception>"), // FIXME
|
||||||
|
Error::Misc(s) => write!(f, "{}", s),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Error> for CppException {
|
impl From<Error> for CppException {
|
||||||
fn from(err: Error) -> Self {
|
fn from(err: Error) -> Self {
|
||||||
match err {
|
match err {
|
||||||
Error::InvalidPath(_) => unsafe { make_error("invalid path") }, // FIXME
|
|
||||||
Error::BadNarInfo => unsafe { make_error(".narinfo file is corrupt") }, // FIXME
|
|
||||||
Error::BadStorePath(path) => unsafe {
|
|
||||||
make_error(&format!("path '{}' is not a store path", path.display()))
|
|
||||||
}, // FIXME
|
|
||||||
Error::BadBase32 => unsafe { make_error("invalid base32 string") }, // FIXME
|
|
||||||
Error::IOError(err) => unsafe { make_error(&err.to_string()) },
|
|
||||||
Error::HttpError(err) => unsafe { make_error(&err.to_string()) },
|
|
||||||
Error::Foreign(ex) => ex,
|
Error::Foreign(ex) => ex,
|
||||||
Error::Misc(s) => unsafe { make_error(&s) },
|
_ => unsafe { make_error(&err.to_string()) },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
mod binary_cache_store;
|
mod binary_cache_store;
|
||||||
|
mod path;
|
||||||
mod path_info;
|
mod path_info;
|
||||||
mod store;
|
mod store;
|
||||||
|
|
||||||
pub use binary_cache_store::BinaryCacheStore;
|
pub use binary_cache_store::BinaryCacheStore;
|
||||||
|
pub use path::{StorePath, StorePathHash, StorePathName};
|
||||||
pub use path_info::PathInfo;
|
pub use path_info::PathInfo;
|
||||||
pub use store::{Store, StorePath};
|
pub use store::Store;
|
||||||
|
|
100
nix-rust/src/store/path.rs
Normal file
100
nix-rust/src/store/path.rs
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::util::base32;
|
||||||
|
use std::fmt;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
pub struct StorePath {
|
||||||
|
pub hash: StorePathHash,
|
||||||
|
pub name: StorePathName,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const STORE_PATH_HASH_BYTES: usize = 20;
|
||||||
|
pub const STORE_PATH_HASH_CHARS: usize = 32;
|
||||||
|
|
||||||
|
impl StorePath {
|
||||||
|
pub fn new(path: &Path, _store_dir: &str) -> Result<Self, Error> {
|
||||||
|
// FIXME: check store_dir
|
||||||
|
Self::new_from_base_name(
|
||||||
|
path.file_name()
|
||||||
|
.ok_or(Error::BadStorePath(path.into()))?
|
||||||
|
.to_str()
|
||||||
|
.ok_or(Error::BadStorePath(path.into()))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_from_base_name(base_name: &str) -> Result<Self, Error> {
|
||||||
|
if base_name.len() < STORE_PATH_HASH_CHARS + 2
|
||||||
|
|| base_name.as_bytes()[STORE_PATH_HASH_CHARS] != '-' as u8
|
||||||
|
{
|
||||||
|
return Err(Error::BadStorePath(base_name.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(StorePath {
|
||||||
|
hash: StorePathHash::new(&base_name[0..STORE_PATH_HASH_CHARS])?,
|
||||||
|
name: StorePathName::new(&base_name[STORE_PATH_HASH_CHARS + 1..])?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StorePath {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}-{}", self.hash, self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
pub struct StorePathHash([u8; STORE_PATH_HASH_BYTES]);
|
||||||
|
|
||||||
|
impl StorePathHash {
|
||||||
|
pub fn new(s: &str) -> Result<Self, Error> {
|
||||||
|
assert_eq!(s.len(), STORE_PATH_HASH_CHARS);
|
||||||
|
let v = base32::decode(s)?;
|
||||||
|
assert_eq!(v.len(), STORE_PATH_HASH_BYTES);
|
||||||
|
let mut bytes: [u8; 20] = Default::default();
|
||||||
|
bytes.copy_from_slice(&v[0..STORE_PATH_HASH_BYTES]);
|
||||||
|
Ok(Self(bytes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StorePathHash {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(&base32::encode(&self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
pub struct StorePathName(String);
|
||||||
|
|
||||||
|
impl StorePathName {
|
||||||
|
pub fn new(s: &str) -> Result<Self, Error> {
|
||||||
|
if s.len() > 211 {
|
||||||
|
return Err(Error::StorePathNameTooLong);
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.starts_with('.')
|
||||||
|
|| !s.chars().all(|c| {
|
||||||
|
c.is_ascii_alphabetic()
|
||||||
|
|| c.is_ascii_digit()
|
||||||
|
|| c == '+'
|
||||||
|
|| c == '-'
|
||||||
|
|| c == '.'
|
||||||
|
|| c == '_'
|
||||||
|
|| c == '?'
|
||||||
|
|| c == '='
|
||||||
|
})
|
||||||
|
{
|
||||||
|
return Err(Error::BadStorePathName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self(s.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for StorePathName {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.write_str(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: add tests
|
|
@ -43,11 +43,11 @@ impl PathInfo {
|
||||||
} else if name == "References" {
|
} else if name == "References" {
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
for r in value.split(' ') {
|
for r in value.split(' ') {
|
||||||
references.insert(StorePath::new_short(r)?);
|
references.insert(StorePath::new_from_base_name(r)?);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if name == "Deriver" {
|
} else if name == "Deriver" {
|
||||||
deriver = Some(StorePath::new_short(value)?);
|
deriver = Some(StorePath::new_from_base_name(value)?);
|
||||||
} else if name == "URL" {
|
} else if name == "URL" {
|
||||||
url = Some(value.into());
|
url = Some(value.into());
|
||||||
} else if name == "Compression" {
|
} else if name == "Compression" {
|
||||||
|
|
|
@ -1,56 +1,8 @@
|
||||||
use super::PathInfo;
|
use super::{PathInfo, StorePath};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
||||||
pub struct StorePath {
|
|
||||||
pub hash: String,
|
|
||||||
pub name: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const STORE_PATH_HASH_CHARS: usize = 32;
|
|
||||||
|
|
||||||
impl StorePath {
|
|
||||||
pub fn new(path: &Path, _store_dir: &str) -> Result<Self, Error> {
|
|
||||||
// FIXME: check store_dir
|
|
||||||
Self::new_short(
|
|
||||||
path.file_name()
|
|
||||||
.ok_or(Error::BadStorePath(path.into()))?
|
|
||||||
.to_str()
|
|
||||||
.ok_or(Error::BadStorePath(path.into()))?,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_short(base_name: &str) -> Result<Self, Error> {
|
|
||||||
if base_name.len() < STORE_PATH_HASH_CHARS + 2
|
|
||||||
|| base_name.as_bytes()[STORE_PATH_HASH_CHARS] != '-' as u8
|
|
||||||
{
|
|
||||||
return Err(Error::BadStorePath(base_name.into()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: validate name
|
|
||||||
|
|
||||||
Ok(StorePath {
|
|
||||||
hash: base_name[0..STORE_PATH_HASH_CHARS].to_string(),
|
|
||||||
name: base_name[STORE_PATH_HASH_CHARS + 1..].to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
|
||||||
pub struct StorePathHash {
|
|
||||||
bytes: [u8; 20],
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
impl StorePathHash {
|
|
||||||
pub fn to_base32(&self) -> String {
|
|
||||||
"7h7qgvs4kgzsn8a6rb273saxyqh4jxlz".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub trait Store: Send + Sync {
|
pub trait Store: Send + Sync {
|
||||||
fn store_dir(&self) -> &str {
|
fn store_dir(&self) -> &str {
|
||||||
"/nix/store"
|
"/nix/store"
|
||||||
|
|
Loading…
Reference in a new issue