Just store one string in StorePath

This commit is contained in:
Artemis Tosini 2024-07-14 00:07:10 +00:00
parent 72580f5e65
commit 0652538579
Signed by: artemist
GPG key ID: EE5227935FE3FF18

View file

@ -9,6 +9,7 @@ use base64::Engine;
use bytes::Buf;
use ed25519_dalek::VerifyingKey;
use reqwest::Url;
use serde::{Deserialize, Serialize};
use sha2::Digest;
use tokio::io::AsyncWriteExt;
use tracing::{span, Span};
@ -104,8 +105,7 @@ impl FetchAndUnpackNixSubstituter {
) -> Result<NarInfo, ActionError> {
for substituter in &self.substituters {
let narinfo_url = substituter
.join(&format!("{}.narinfo", &output.digest))
// TODO: Give more useful error message here
.join(&format!("{}.narinfo", &output.digest()))
.map_err(|err| UrlOrPathError::Url("".to_string(), err))
.map_err(ActionErrorKind::UrlOrPathError)
.map_err(Self::error)?;
@ -137,7 +137,7 @@ impl FetchAndUnpackNixSubstituter {
}
Err(Self::error(SubstitutionError::NonexistantNarInfo(
output.full_path.clone(),
output.full_path().clone(),
)))
}
}
@ -153,7 +153,7 @@ impl Action for FetchAndUnpackNixSubstituter {
"Fetch {} from substituters to `{}`",
self.targets
.iter()
.map(|t| format!("`{}`", t.full_path))
.map(|t| format!("`{}`", t.full_path()))
.collect::<Vec<String>>()
.join(", "),
self.dest.display()
@ -281,9 +281,7 @@ impl Action for FetchAndUnpackNixSubstituter {
return Err(Self::error(SubstitutionError::BadNar(narinfo.url.clone())));
}
// TODO: Figure out a better way to make relative
// Maybe simplify StorePath?
let out_dir = self.dest.join("nix-/store").join(output.full_name);
let out_dir = self.dest.join("nix-/store").join(output.full_name());
let decoder = nix_nar::Decoder::new(decompressed_nar.reader())
.map_err(|e| SubstitutionError::Unpack(narinfo.url.clone(), e))
@ -297,14 +295,14 @@ impl Action for FetchAndUnpackNixSubstituter {
// File format isn't documented anywhere but implementation is simple:
// https://git.lix.systems/lix-project/lix/src/commit/d461cc1d7b2f489c3886f147166ba5b5e0e37541/src/libstore/store-api.cc#L846
// Unwrapping because string can't fail methods in std::fmt::Write
write!(reginfo, "{}\n", output.full_path).unwrap();
write!(reginfo, "{}\n", output.full_path()).unwrap();
write!(reginfo, "sha256:{}\n", narinfo.nar_hash).unwrap();
write!(reginfo, "{}\n", narinfo.nar_size).unwrap();
// Leave deriver empty, same as lix binary tarballs
reginfo.push('\n');
write!(reginfo, "{}\n", narinfo.references.len()).unwrap();
for reference in &narinfo.references {
write!(reginfo, "{}\n", reference.full_path).unwrap();
write!(reginfo, "{}\n", reference.full_path()).unwrap();
}
}
@ -355,21 +353,30 @@ fn parse_key(key: &str) -> Result<(String, VerifyingKey), SubstitutionError> {
}
/// Utility struct representing a store path
#[derive(Clone, Eq, Debug)]
struct StorePath {
#[derive(Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)]
#[serde(transparent)]
struct StorePath(String);
impl StorePath {
/// The full name of a path, not including STORE_DIR,
/// e.g. `n50jk09x9hshwx1lh6k3qaiygc7yxbv9-lix-2.90.0-rc1`
pub fn full_name(&self) -> &str {
&self.0
}
/// The base32 hash part of a store path,
/// e.g. `n50jk09x9hshwx1lh6k3qaiygc7yxbv9`
pub fn digest(&self) -> &str {
&self.0.split_once('-').unwrap().0
}
/// Full path of the output including STORE_DIR,
/// as seen in StorePath in narinfo
/// e.g. `/nix/store/n50jk09x9hshwx1lh6k3qaiygc7yxbv9-lix-2.90.0-rc1`
pub full_path: String,
/// The base32 hash part of a store path,
/// e.g. `n50jk09x9hshwx1lh6k3qaiygc7yxbv9`
pub digest: String,
/// The full name of a path, not including STORE_DIR,
/// e.g. `n50jk09x9hshwx1lh6k3qaiygc7yxbv9-lix-2.90.0-rc1`
pub full_name: String,
}
pub fn full_path(&self) -> String {
format!("{}{}", STORE_DIR, &self.0)
}
impl StorePath {
pub fn from_full_path(full_path: &str) -> Option<Self> {
if !full_path.starts_with(STORE_DIR) {
return None;
@ -377,6 +384,18 @@ impl StorePath {
let (_, full_name) = full_path.split_at(STORE_DIR.len());
Self::from_full_name(full_name)
}
pub fn from_path(path: &Path) -> Result<Self, SubstitutionError> {
let path_str = path
.to_str()
.ok_or_else(|| SubstitutionError::InvalidStorePath(path.to_owned()))?;
Self::from_full_path(path_str)
.ok_or_else(|| SubstitutionError::InvalidStorePath(path.to_owned()))
}
pub fn from_full_name(full_name: &str) -> Option<Self> {
let (digest, name) = full_name.split_once('-')?;
if digest.len() != 32
@ -397,75 +416,7 @@ impl StorePath {
return None;
}
Some(Self {
full_path: full_path.to_string(),
digest: digest.to_string(),
full_name: full_name.to_string(),
})
}
pub fn from_path(path: &Path) -> Result<Self, SubstitutionError> {
let path_str = path
.to_str()
.ok_or_else(|| SubstitutionError::InvalidStorePath(path.to_owned()))?;
Self::from_full_path(path_str)
.ok_or_else(|| SubstitutionError::InvalidStorePath(path.to_owned()))
}
pub fn from_full_name(full_name: &str) -> Option<Self> {
Self::from_full_path(
&Path::new(STORE_DIR)
.join(&full_name)
.into_os_string()
.into_string()
.ok()?,
)
}
}
impl std::hash::Hash for StorePath {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.full_path.hash(state);
}
}
impl PartialEq for StorePath {
fn eq(&self, other: &Self) -> bool {
self.full_path == other.full_path
}
}
impl serde::Serialize for StorePath {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.full_path.serialize(serializer)
}
}
impl<'de> serde::Deserialize<'de> for StorePath {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
deserializer.deserialize_string(StorePathVisitor)
}
}
struct StorePathVisitor;
impl serde::de::Visitor<'_> for StorePathVisitor {
type Value = StorePath;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid nix store path starting with /nix/store")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
StorePath::from_full_path(value).ok_or_else(|| E::custom("invalid store path"))
Some(Self(full_name.to_string()))
}
}
@ -592,13 +543,13 @@ impl NarInfo {
// https://git.lix.systems/lix-project/lix/src/commit/d461cc1d7b2f489c3886f147166ba5b5e0e37541/src/libstore/path-info.cc#L25
let fingerprint = format!(
"1;{};sha256:{};{};{}",
self.store_path.full_path,
self.store_path.full_path(),
self.nar_hash,
self.nar_size,
self.references
.iter()
.map(|reference| reference.full_path.as_ref())
.collect::<Vec<&str>>()
.map(|reference| reference.full_path())
.collect::<Vec<String>>()
.join(",")
);