Skip to content

Commit

Permalink
Merge pull request #1660 from cachix/cachix-enable
Browse files Browse the repository at this point in the history
cachix: use `cachix.enable` to disable cache setup logic
  • Loading branch information
domenkozar authored Jan 7, 2025
2 parents 07219f0 + a7218fe commit d52ca36
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 49 deletions.
174 changes: 131 additions & 43 deletions devenv/src/cnix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -607,17 +607,23 @@ impl<'a> Nix<'a> {
..self.options
};
let caches_raw = self.eval(&["devenv.cachix"]).await?;
let cachix = serde_json::from_str(&caches_raw).expect("Failed to parse JSON");
let known_keys = if let Ok(known_keys) =
std::fs::read_to_string(self.cachix_trusted_keys.as_path())
{
serde_json::from_str(&known_keys).expect("Failed to parse JSON")
} else {
HashMap::new()
};
let cachix_config: CachixConfig =
serde_json::from_str(&caches_raw).expect("Failed to parse JSON");

// Return empty caches if the Cachix integration is disabled
if !cachix_config.enable {
*self.cachix_caches.borrow_mut() = Some(CachixCaches::default());
return Ok(Ref::map(self.cachix_caches.borrow(), |option| {
option.as_ref().unwrap()
}));
}

let known_keys = std::fs::read_to_string(self.cachix_trusted_keys.as_path())
.map(|known_keys| serde_json::from_str(&known_keys).expect("Failed to parse JSON"))
.unwrap_or_default();

let mut caches = CachixCaches {
caches: cachix,
caches: cachix_config.caches,
known_keys,
};

Expand All @@ -626,7 +632,7 @@ impl<'a> Nix<'a> {
for name in caches.caches.pull.iter() {
if !caches.known_keys.contains_key(name) {
let mut request =
client.get(&format!("https://cachix.org/api/v1/cache/{}", name));
client.get(format!("https://cachix.org/api/v1/cache/{}", name));
if let Ok(ret) = env::var("CACHIX_AUTH_TOKEN") {
request = request.bearer_auth(ret);
}
Expand Down Expand Up @@ -691,35 +697,11 @@ impl<'a> Nix<'a> {
// Check if all of the requested caches and their public keys are in the substituters and trusted-public-keys lists.
// If not, suggest actions to remedy the issue.
if trusted == Some(0) {
let mut missing_caches = Vec::new();
let mut missing_public_keys = Vec::new();

if let Ok(nix_conf) = self.get_nix_config().await {
let substituters = nix_conf
.get("substituters")
.map(|s| s.split_whitespace().collect::<Vec<_>>());

if let Some(substituters) = substituters {
for cache in caches.caches.pull.iter() {
let cache_url = format!("https://{}.cachix.org", cache);
if !substituters.iter().any(|s| s == &cache_url) {
missing_caches.push(cache_url);
}
}
}

let trusted_public_keys = nix_conf
.get("trusted-public-keys")
.map(|s| s.split_whitespace().collect::<Vec<_>>());

if let Some(trusted_public_keys) = trusted_public_keys {
for (_name, key) in caches.known_keys.iter() {
if !trusted_public_keys.iter().any(|p| p == key) {
missing_public_keys.push(key.clone());
}
}
}
}
let (missing_caches, missing_public_keys) = self
.get_nix_config()
.await
.map(|nix_conf| detect_missing_caches(&caches, nix_conf))
.unwrap_or_default();

if !missing_caches.is_empty() || !missing_public_keys.is_empty() {
if !Path::new("/etc/NIXOS").exists() {
Expand Down Expand Up @@ -857,13 +839,21 @@ fn display_command(cmd: &std::process::Command) -> String {
format!("{command} {args}")
}

#[derive(Deserialize, Clone)]
/// The Cachix module configuration
#[derive(Deserialize, Default, Clone)]
pub struct CachixConfig {
enable: bool,
#[serde(flatten)]
caches: Cachix,
}

#[derive(Deserialize, Default, Clone)]
pub struct Cachix {
pull: Vec<String>,
push: Option<String>,
pub pull: Vec<String>,
pub push: Option<String>,
}

#[derive(Deserialize, Clone)]
#[derive(Deserialize, Default, Clone)]
pub struct CachixCaches {
caches: Cachix,
known_keys: HashMap<String, String>,
Expand All @@ -880,6 +870,50 @@ struct StorePing {
trusted: Option<u8>,
}

fn detect_missing_caches(caches: &CachixCaches, nix_conf: NixConf) -> (Vec<String>, Vec<String>) {
let mut missing_caches = Vec::new();
let mut missing_public_keys = Vec::new();

let substituters = nix_conf
.get("substituters")
.map(|s| s.split_whitespace().collect::<Vec<_>>());
let extra_substituters = nix_conf
.get("extra-substituters")
.map(|s| s.split_whitespace().collect::<Vec<_>>());
let all_substituters = substituters
.into_iter()
.flatten()
.chain(extra_substituters.into_iter().flatten())
.collect::<Vec<_>>();

for cache in caches.caches.pull.iter() {
let cache_url = format!("https://{}.cachix.org", cache);
if !all_substituters.iter().any(|s| s == &cache_url) {
missing_caches.push(cache_url);
}
}

let trusted_public_keys = nix_conf
.get("trusted-public-keys")
.map(|s| s.split_whitespace().collect::<Vec<_>>());
let extra_trusted_public_keys = nix_conf
.get("extra-trusted-public-keys")
.map(|s| s.split_whitespace().collect::<Vec<_>>());
let all_trusted_public_keys = trusted_public_keys
.into_iter()
.flatten()
.chain(extra_trusted_public_keys.into_iter().flatten())
.collect::<Vec<_>>();

for (_name, key) in caches.known_keys.iter() {
if !all_trusted_public_keys.iter().any(|p| p == key) {
missing_public_keys.push(key.clone());
}
}

(missing_caches, missing_public_keys)
}

#[cfg(test)]
mod tests {
use super::*;
Expand All @@ -904,4 +938,58 @@ mod tests {
let store_ping: StorePing = serde_json::from_str(store_ping).unwrap();
assert_eq!(store_ping.trusted, Some(0));
}

#[test]
fn test_missing_substituters() {
let mut cachix = CachixCaches::default();
cachix.caches.pull = vec!["cache1".to_string(), "cache2".to_string()];
cachix
.known_keys
.insert("cache1".to_string(), "key1".to_string());
cachix
.known_keys
.insert("cache2".to_string(), "key2".to_string());
let nix_conf = NixConf::parse_stdout(
r#"
substituters = https://cache1.cachix.org https://cache3.cachix.org
trusted-public-keys = key1 key3
"#
.as_bytes(),
)
.expect("Failed to parse NixConf");
assert_eq!(
detect_missing_caches(&cachix, nix_conf),
(
vec!["https://cache2.cachix.org".to_string()],
vec!["key2".to_string()]
)
);
}

#[test]
fn test_extra_missing_substituters() {
let mut cachix = CachixCaches::default();
cachix.caches.pull = vec!["cache1".to_string(), "cache2".to_string()];
cachix
.known_keys
.insert("cache1".to_string(), "key1".to_string());
cachix
.known_keys
.insert("cache2".to_string(), "key2".to_string());
let nix_conf = NixConf::parse_stdout(
r#"
extra-substituters = https://cache1.cachix.org https://cache3.cachix.org
extra-trusted-public-keys = key1 key3
"#
.as_bytes(),
)
.expect("Failed to parse NixConf");
assert_eq!(
detect_missing_caches(&cachix, nix_conf),
(
vec!["https://cache2.cachix.org".to_string()],
vec!["key2".to_string()]
)
);
}
}
6 changes: 3 additions & 3 deletions docs/reference/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ package



What caches to pull from.
Which Cachix caches to pull from.



Expand All @@ -933,7 +933,7 @@ list of string


*Default:*
` [ ] `
` [ "devenv" ] `

*Declared by:*
- [https://github.com/cachix/devenv/blob/main/src/modules/cachix.nix](https://github.com/cachix/devenv/blob/main/src/modules/cachix.nix)
Expand All @@ -944,7 +944,7 @@ list of string



What cache to push to. Automatically also adds it to the list of caches to pull from.
Which Cachix cache to push to. This cache is also added to ` cachix.pull `.



Expand Down
7 changes: 4 additions & 3 deletions src/modules/cachix.nix
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,14 @@ in

pull = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "What caches to pull from.";
description = "Which Cachix caches to pull from.";
default = [ ];
defaultText = lib.literalExpression ''[ "devenv" ]'';
};

push = lib.mkOption {
type = lib.types.nullOr lib.types.str;
description = "What cache to push to. Automatically also adds it to the list of caches to pull from.";
description = "Which Cachix cache to push to. This cache is also added to `cachix.pull`.";
default = null;
};

Expand All @@ -30,7 +31,7 @@ in

config = lib.mkIf cfg.enable {
cachix.pull = [ "devenv" ]
++ (lib.optionals (cfg.push != null) [ config.cachix.push ]);
++ (lib.optional (cfg.push != null) config.cachix.push);

warnings = lib.optionals (!config.devenv.flakesIntegration && lib.versionOlder config.devenv.cliVersion "1.0") [
''
Expand Down

0 comments on commit d52ca36

Please sign in to comment.