summaryrefslogtreecommitdiffstats
path: root/nix-rust
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2019-09-17 22:26:49 +0200
committerEelco Dolstra <edolstra@gmail.com>2019-12-10 13:37:23 +0100
commit6317f0f7a0663aed9d877031f7815fa292bd6b09 (patch)
tree45a6a2e6674a3dd5504b9e8f093271954afb1884 /nix-rust
parentcce218f95050e82587f376d51e5f732d1f68eab3 (diff)
StorePath improvements
Diffstat (limited to 'nix-rust')
-rw-r--r--nix-rust/src/error.rs33
-rw-r--r--nix-rust/src/store/mod.rs4
-rw-r--r--nix-rust/src/store/path.rs100
-rw-r--r--nix-rust/src/store/path_info.rs4
-rw-r--r--nix-rust/src/store/store.rs50
5 files changed, 130 insertions, 61 deletions
diff --git a/nix-rust/src/error.rs b/nix-rust/src/error.rs
index 9d6fa4c51..5717a7a47 100644
--- a/nix-rust/src/error.rs
+++ b/nix-rust/src/error.rs
@@ -1,9 +1,13 @@
+use std::fmt;
+
#[derive(Debug)]
pub enum Error {
InvalidPath(crate::store::StorePath),
BadStorePath(std::path::PathBuf),
BadNarInfo,
BadBase32,
+ StorePathNameTooLong,
+ BadStorePathName,
IOError(std::io::Error),
HttpError(reqwest::Error),
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 {
fn from(err: Error) -> Self {
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::Misc(s) => unsafe { make_error(&s) },
+ _ => unsafe { make_error(&err.to_string()) },
}
}
}
diff --git a/nix-rust/src/store/mod.rs b/nix-rust/src/store/mod.rs
index a0d1c72ab..85355b594 100644
--- a/nix-rust/src/store/mod.rs
+++ b/nix-rust/src/store/mod.rs
@@ -1,7 +1,9 @@
mod binary_cache_store;
+mod path;
mod path_info;
mod store;
pub use binary_cache_store::BinaryCacheStore;
+pub use path::{StorePath, StorePathHash, StorePathName};
pub use path_info::PathInfo;
-pub use store::{Store, StorePath};
+pub use store::Store;
diff --git a/nix-rust/src/store/path.rs b/nix-rust/src/store/path.rs
new file mode 100644
index 000000000..4b866f9b4
--- /dev/null
+++ b/nix-rust/src/store/path.rs
@@ -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
diff --git a/nix-rust/src/store/path_info.rs b/nix-rust/src/store/path_info.rs
index 2759e03d4..c2903ed29 100644
--- a/nix-rust/src/store/path_info.rs
+++ b/nix-rust/src/store/path_info.rs
@@ -43,11 +43,11 @@ impl PathInfo {
} else if name == "References" {
if !value.is_empty() {
for r in value.split(' ') {
- references.insert(StorePath::new_short(r)?);
+ references.insert(StorePath::new_from_base_name(r)?);
}
}
} else if name == "Deriver" {
- deriver = Some(StorePath::new_short(value)?);
+ deriver = Some(StorePath::new_from_base_name(value)?);
} else if name == "URL" {
url = Some(value.into());
} else if name == "Compression" {
diff --git a/nix-rust/src/store/store.rs b/nix-rust/src/store/store.rs
index 32949a078..c33dc4a90 100644
--- a/nix-rust/src/store/store.rs
+++ b/nix-rust/src/store/store.rs
@@ -1,56 +1,8 @@
-use super::PathInfo;
+use super::{PathInfo, StorePath};
use crate::Error;
use std::collections::{BTreeMap, BTreeSet};
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 {
fn store_dir(&self) -> &str {
"/nix/store"