mirror of
https://github.com/NixOS/nix
synced 2025-06-28 05:21:16 +02:00
Move stuff around
This commit is contained in:
parent
ce3c41aef0
commit
a1ff43045b
10 changed files with 74 additions and 67 deletions
50
nix-rust/src/store/binary_cache_store.rs
Normal file
50
nix-rust/src/store/binary_cache_store.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
use super::{Store, StorePath, PathInfo};
|
||||
use crate::Error;
|
||||
use futures::compat::Future01CompatExt;
|
||||
|
||||
pub struct BinaryCacheStore {
|
||||
base_uri: String,
|
||||
client: reqwest::r#async::Client,
|
||||
}
|
||||
|
||||
impl BinaryCacheStore {
|
||||
pub fn new(base_uri: String) -> Self {
|
||||
Self {
|
||||
base_uri,
|
||||
client: reqwest::r#async::Client::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Store for BinaryCacheStore {
|
||||
fn query_path_info(
|
||||
&self,
|
||||
path: &StorePath,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<PathInfo, Error>> + Send>> {
|
||||
let uri = format!("{}/{}.narinfo", self.base_uri.clone(), path.hash);
|
||||
let path = path.clone();
|
||||
let client = self.client.clone();
|
||||
let store_dir = self.store_dir().to_string();
|
||||
|
||||
Box::pin(async move {
|
||||
let response = client
|
||||
.get(&uri)
|
||||
.send()
|
||||
.compat()
|
||||
.await?;
|
||||
|
||||
if response.status() == reqwest::StatusCode::NOT_FOUND || response.status() == reqwest::StatusCode::FORBIDDEN {
|
||||
return Err(Error::InvalidPath(path));
|
||||
}
|
||||
|
||||
let mut response = response.error_for_status()?;
|
||||
|
||||
let body = response
|
||||
.text()
|
||||
.compat()
|
||||
.await?;
|
||||
|
||||
PathInfo::parse_nar_info(&body, &store_dir)
|
||||
})
|
||||
}
|
||||
}
|
7
nix-rust/src/store/mod.rs
Normal file
7
nix-rust/src/store/mod.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
mod binary_cache_store;
|
||||
mod path_info;
|
||||
mod store;
|
||||
|
||||
pub use binary_cache_store::BinaryCacheStore;
|
||||
pub use path_info::PathInfo;
|
||||
pub use store::{Store, StorePath};
|
70
nix-rust/src/store/path_info.rs
Normal file
70
nix-rust/src/store/path_info.rs
Normal file
|
@ -0,0 +1,70 @@
|
|||
use crate::store::StorePath;
|
||||
use crate::Error;
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PathInfo {
|
||||
pub path: StorePath,
|
||||
pub references: BTreeSet<StorePath>,
|
||||
pub nar_size: u64,
|
||||
pub deriver: Option<StorePath>,
|
||||
|
||||
// Additional binary cache info.
|
||||
pub url: Option<String>,
|
||||
pub compression: Option<String>,
|
||||
pub file_size: Option<u64>,
|
||||
}
|
||||
|
||||
impl PathInfo {
|
||||
pub fn parse_nar_info(nar_info: &str, store_dir: &str) -> Result<Self, Error> {
|
||||
let mut path = None;
|
||||
let mut references = BTreeSet::new();
|
||||
let mut nar_size = None;
|
||||
let mut deriver = None;
|
||||
let mut url = None;
|
||||
let mut compression = None;
|
||||
let mut file_size = None;
|
||||
|
||||
for line in nar_info.lines() {
|
||||
let colon = line.find(':').ok_or(Error::BadNarInfo)?;
|
||||
|
||||
let (name, value) = line.split_at(colon);
|
||||
|
||||
if !value.starts_with(": ") {
|
||||
return Err(Error::BadNarInfo);
|
||||
}
|
||||
|
||||
let value = &value[2..];
|
||||
|
||||
if name == "StorePath" {
|
||||
path = Some(StorePath::new(std::path::Path::new(value), store_dir)?);
|
||||
} else if name == "NarSize" {
|
||||
nar_size = Some(u64::from_str_radix(value, 10).map_err(|_| Error::BadNarInfo)?);
|
||||
} else if name == "References" {
|
||||
if !value.is_empty() {
|
||||
for r in value.split(' ') {
|
||||
references.insert(StorePath::new_short(r)?);
|
||||
}
|
||||
}
|
||||
} else if name == "Deriver" {
|
||||
deriver = Some(StorePath::new_short(value)?);
|
||||
} else if name == "URL" {
|
||||
url = Some(value.into());
|
||||
} else if name == "Compression" {
|
||||
compression = Some(value.into());
|
||||
} else if name == "FileSize" {
|
||||
file_size = Some(u64::from_str_radix(value, 10).map_err(|_| Error::BadNarInfo)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(PathInfo {
|
||||
path: path.ok_or(Error::BadNarInfo)?,
|
||||
references,
|
||||
nar_size: nar_size.ok_or(Error::BadNarInfo)?,
|
||||
deriver,
|
||||
url: Some(url.ok_or(Error::BadNarInfo)?),
|
||||
compression,
|
||||
file_size,
|
||||
})
|
||||
}
|
||||
}
|
101
nix-rust/src/store/store.rs
Normal file
101
nix-rust/src/store/store.rs
Normal file
|
@ -0,0 +1,101 @@
|
|||
use super::PathInfo;
|
||||
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"
|
||||
}
|
||||
|
||||
fn query_path_info(
|
||||
&self,
|
||||
store_path: &StorePath,
|
||||
) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<PathInfo, Error>> + Send>>;
|
||||
}
|
||||
|
||||
impl dyn Store {
|
||||
pub fn parse_store_path(&self, path: &Path) -> Result<StorePath, Error> {
|
||||
StorePath::new(path, self.store_dir())
|
||||
}
|
||||
|
||||
pub async fn compute_path_closure(
|
||||
&self,
|
||||
roots: BTreeSet<StorePath>,
|
||||
) -> Result<BTreeMap<StorePath, PathInfo>, Error> {
|
||||
let mut done = BTreeSet::new();
|
||||
let mut result = BTreeMap::new();
|
||||
let mut pending = vec![];
|
||||
|
||||
for root in roots {
|
||||
pending.push(self.query_path_info(&root));
|
||||
done.insert(root);
|
||||
}
|
||||
|
||||
while !pending.is_empty() {
|
||||
let (info, _, remaining) = futures::future::select_all(pending).await;
|
||||
pending = remaining;
|
||||
|
||||
let info = info?;
|
||||
|
||||
for path in &info.references {
|
||||
if !done.contains(path) {
|
||||
pending.push(self.query_path_info(&path));
|
||||
done.insert(path.clone());
|
||||
}
|
||||
}
|
||||
|
||||
result.insert(info.path.clone(), info);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue