Skip to content

Commit

Permalink
Merge pull request #1702 from cachix/fix-empty-env
Browse files Browse the repository at this point in the history
  • Loading branch information
sandydoo authored Feb 5, 2025
2 parents 3f49b4a + dd8b24a commit c1e6c8e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 41 deletions.
53 changes: 35 additions & 18 deletions devenv-eval-cache/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,17 +248,17 @@ pub enum Input {
}

impl Input {
pub fn content_hash(&self) -> &str {
pub fn content_hash(&self) -> Option<&str> {
match self {
Self::File(desc) => &desc.content_hash,
Self::Env(desc) => &desc.content_hash,
Self::File(desc) => desc.content_hash.as_deref(),
Self::Env(desc) => desc.content_hash.as_deref(),
}
}

pub fn compute_input_hash(inputs: &[Self]) -> String {
inputs
.iter()
.map(|input| input.content_hash())
.filter_map(Input::content_hash)
.collect::<String>()
}

Expand All @@ -281,7 +281,7 @@ impl Input {
pub struct FileInputDesc {
pub path: PathBuf,
pub is_directory: bool,
pub content_hash: String,
pub content_hash: Option<String>,
pub modified_at: SystemTime,
}

Expand All @@ -305,9 +305,9 @@ impl FileInputDesc {
.filter_map(Result::ok)
.map(|entry| entry.path().to_string_lossy().to_string())
.collect::<String>();
hash::digest(&paths)
Some(hash::digest(&paths))
} else {
hash::compute_file_hash(&path)?
hash::compute_file_hash(&path).ok()
};
let modified_at = path.metadata()?.modified()?;
Ok(Self {
Expand All @@ -322,7 +322,7 @@ impl FileInputDesc {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EnvInputDesc {
pub name: String,
pub content_hash: String,
pub content_hash: Option<String>,
}

impl Ord for EnvInputDesc {
Expand All @@ -339,8 +339,8 @@ impl PartialOrd for EnvInputDesc {

impl EnvInputDesc {
pub fn new(name: String) -> Result<Self, io::Error> {
let value = std::env::var(&name).unwrap_or_default();
let content_hash = hash::digest(&value);
let value = std::env::var(&name).ok();
let content_hash = value.map(hash::digest);
Ok(Self { name, content_hash })
}
}
Expand Down Expand Up @@ -381,7 +381,11 @@ impl From<db::FileInputRow> for FileInputDesc {
Self {
path: row.path,
is_directory: row.is_directory,
content_hash: row.content_hash,
content_hash: if row.content_hash.is_empty() {
None
} else {
Some(row.content_hash)
},
modified_at: row.modified_at,
}
}
Expand All @@ -391,7 +395,11 @@ impl From<db::EnvInputRow> for EnvInputDesc {
fn from(row: db::EnvInputRow) -> Self {
Self {
name: row.name,
content_hash: row.content_hash,
content_hash: if row.content_hash.is_empty() {
None
} else {
Some(row.content_hash)
},
}
}
}
Expand Down Expand Up @@ -545,8 +553,13 @@ enum FileState {
fn check_file_state(file: &FileInputDesc) -> io::Result<FileState> {
let metadata = match std::fs::metadata(&file.path) {
Ok(metadata) => metadata,
// Fix
Err(_) => return Ok(FileState::Removed),
Err(_) => {
if file.content_hash.is_some() {
return Ok(FileState::Removed);
} else {
return Ok(FileState::Unchanged);
}
}
};

let modified_at = metadata.modified().and_then(truncate_to_seconds)?;
Expand All @@ -570,7 +583,7 @@ fn check_file_state(file: &FileInputDesc) -> io::Result<FileState> {
hash::compute_file_hash(&file.path)?
};

if new_hash == file.content_hash {
if Some(&new_hash) == file.content_hash.as_ref() {
// File touched but hash unchanged
Ok(FileState::MetadataModified { modified_at })
} else {
Expand All @@ -586,12 +599,16 @@ fn check_env_state(env: &EnvInputDesc) -> io::Result<FileState> {
let value = std::env::var(&env.name);

if let Err(std::env::VarError::NotPresent) = value {
return Ok(FileState::Removed);
if env.content_hash.is_none() {
return Ok(FileState::Unchanged);
} else {
return Ok(FileState::Removed);
}
}

let new_hash = hash::digest(&value.unwrap_or("".into()));
let new_hash = hash::digest(value.unwrap_or("".into()));

if new_hash != env.content_hash {
if Some(&new_hash) != env.content_hash.as_ref() {
Ok(FileState::Modified {
new_hash,
modified_at: SystemTime::now(),
Expand Down
58 changes: 37 additions & 21 deletions devenv-eval-cache/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ where
let id: i64 = sqlx::query(insert_file_input)
.bind(path.to_path_buf().into_os_string().as_bytes())
.bind(is_directory)
.bind(content_hash)
.bind(content_hash.as_ref().unwrap_or(&"".to_string()))
.bind(modified_at)
.fetch_one(&mut *conn)
.await?
Expand Down Expand Up @@ -268,7 +268,7 @@ where
let id: i64 = sqlx::query(insert_env_input)
.bind(command_id)
.bind(name)
.bind(content_hash)
.bind(content_hash.as_ref().unwrap_or(&"".to_string()))
.fetch_one(&mut *conn)
.await?
.get(0);
Expand Down Expand Up @@ -456,20 +456,20 @@ mod tests {
Input::File(FileInputDesc {
path: "/path/to/file1".into(),
is_directory: false,
content_hash: "hash1".to_string(),
content_hash: Some("hash1".to_string()),
modified_at,
}),
Input::File(FileInputDesc {
path: "/path/to/file2".into(),
is_directory: false,
content_hash: "hash2".to_string(),
content_hash: Some("hash2".to_string()),
modified_at,
}),
];
let input_hash = hash::digest(
&inputs
.iter()
.map(|fp| fp.content_hash())
.filter_map(Input::content_hash)
.collect::<String>(),
);

Expand Down Expand Up @@ -507,18 +507,22 @@ mod tests {
Input::File(FileInputDesc {
path: "/path/to/file1".into(),
is_directory: false,
content_hash: "hash1".to_string(),
content_hash: Some("hash1".to_string()),
modified_at,
}),
Input::File(FileInputDesc {
path: "/path/to/file2".into(),
is_directory: false,
content_hash: "hash2".to_string(),
content_hash: Some("hash2".to_string()),
modified_at,
}),
];
let input_hash1 =
hash::digest(&inputs1.iter().map(|p| p.content_hash()).collect::<String>());
let input_hash1 = hash::digest(
&inputs1
.iter()
.filter_map(Input::content_hash)
.collect::<String>(),
);

let (command_id1, file_ids1, _) = insert_command_with_inputs(
&pool,
Expand All @@ -540,18 +544,22 @@ mod tests {
Input::File(FileInputDesc {
path: "/path/to/file2".into(),
is_directory: false,
content_hash: "hash2".to_string(),
content_hash: Some("hash2".to_string()),
modified_at,
}),
Input::File(FileInputDesc {
path: "/path/to/file3".into(),
is_directory: false,
content_hash: "hash3".to_string(),
content_hash: Some("hash3".to_string()),
modified_at,
}),
];
let input_hash2 =
hash::digest(&inputs2.iter().map(|p| p.content_hash()).collect::<String>());
let input_hash2 = hash::digest(
&inputs2
.iter()
.filter_map(Input::content_hash)
.collect::<String>(),
);

let (command_id2, file_ids2, _) = insert_command_with_inputs(
&pool,
Expand Down Expand Up @@ -606,18 +614,22 @@ mod tests {
Input::File(FileInputDesc {
path: "/path/to/file1".into(),
is_directory: false,
content_hash: "hash1".to_string(),
content_hash: Some("hash1".to_string()),
modified_at,
}),
Input::File(FileInputDesc {
path: "/path/to/file2".into(),
is_directory: false,
content_hash: "hash2".to_string(),
content_hash: Some("hash2".to_string()),
modified_at,
}),
];
let input_hash =
hash::digest(&inputs1.iter().map(|p| p.content_hash()).collect::<String>());
let input_hash = hash::digest(
&inputs1
.iter()
.filter_map(Input::content_hash)
.collect::<String>(),
);

let (_command_id1, file_ids1, _) =
insert_command_with_inputs(&pool, raw_cmd, &cmd_hash, &input_hash, output, &inputs1)
Expand All @@ -629,18 +641,22 @@ mod tests {
Input::File(FileInputDesc {
path: "/path/to/file2".into(),
is_directory: false,
content_hash: "hash2".to_string(),
content_hash: Some("hash2".to_string()),
modified_at,
}),
Input::File(FileInputDesc {
path: "/path/to/file3".into(),
is_directory: false,
content_hash: "hash3".to_string(),
content_hash: Some("hash3".to_string()),
modified_at,
}),
];
let input_hash2 =
hash::digest(&inputs2.iter().map(|p| p.content_hash()).collect::<String>());
let input_hash2 = hash::digest(
&inputs2
.iter()
.filter_map(Input::content_hash)
.collect::<String>(),
);

let (command_id2, file_ids2, _) =
insert_command_with_inputs(&pool, raw_cmd, &cmd_hash, &input_hash2, output, &inputs2)
Expand Down
4 changes: 2 additions & 2 deletions devenv-eval-cache/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use std::path::Path;
use std::{fs, io};

pub(crate) fn digest(input: &str) -> String {
let hash = blake3::hash(input.as_bytes());
pub(crate) fn digest<T: AsRef<str>>(input: T) -> String {
let hash = blake3::hash(input.as_ref().as_bytes());
hash.to_hex().as_str().to_string()
}

Expand Down

0 comments on commit c1e6c8e

Please sign in to comment.