difftreelog
fix do not require wildcard with callPackage
in: trunk
6 files changed
cmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -265,13 +265,14 @@
let generator = nix_go!(secret.generator);
let on: Option<String> = nix_go_json!(default_generator.impureOn);
+ let nixpkgs = &config.nixpkgs;
+
let host = if let Some(on) = &on {
config.host(on).await?
} else {
config.local_host()
};
let on_pkgs = host.pkgs().await?;
- let call_package = nix_go!(on_pkgs.callPackage);
let mk_secret_generators = nix_go!(on_pkgs.mkSecretGenerators);
let mut recipients = Vec::new();
@@ -280,8 +281,11 @@
recipients.push(key);
}
let generators = nix_go!(mk_secret_generators(Obj { recipients }));
+ let pkgs_and_generators = nix_go!(on_pkgs + generators);
+
+ let call_package = nix_go!(nixpkgs.lib.callPackageWith(pkgs_and_generators));
- let generator = nix_go!(call_package(generator)(generators));
+ let generator = nix_go!(call_package(generator)(Obj {}));
let generator = generator.build_maybe_batch(batch).await?;
let generator = generator
@@ -353,8 +357,8 @@
bail!("generator should be lambda, got {gen_ty}");
}
}
+ let nixpkgs = &config.nixpkgs;
let default_pkgs = &config.default_pkgs;
- let default_call_package = nix_go!(default_pkgs.callPackage);
let default_mk_secret_generators = nix_go!(default_pkgs.mkSecretGenerators);
// Generators provide additional information in passthru, to access
// passthru we should call generator, but information about where this generator is supposed to build
@@ -367,7 +371,10 @@
let generators = nix_go!(default_mk_secret_generators(Obj {
recipients: <Vec<String>>::new(),
}));
- let default_generator = nix_go!(default_call_package(generator)(generators));
+ let pkgs_and_generators = nix_go!(default_pkgs + generators);
+
+ let call_package = nix_go!(nixpkgs.lib.callPackageWith(pkgs_and_generators));
+ let default_generator = nix_go!(call_package(generator)(Obj {}));
let kind: GeneratorKind = nix_go_json!(default_generator.generatorKind);
crates/fleet-base/src/host.rsdiffbeforeafterboth--- a/crates/fleet-base/src/host.rs
+++ b/crates/fleet-base/src/host.rs
@@ -34,6 +34,7 @@
/// import nixpkgs {system = local};
pub default_pkgs: Value,
+ pub nixpkgs: Value,
pub nix_session: NixSession,
}
crates/fleet-base/src/opts.rsdiffbeforeafterboth--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -225,6 +225,7 @@
nix_args,
config_field,
default_pkgs,
+ nixpkgs,
localhost: self.localhost.to_owned(),
})))
}
crates/nix-eval/src/macros.rsdiffbeforeafterboth--- a/crates/nix-eval/src/macros.rs
+++ b/crates/nix-eval/src/macros.rs
@@ -231,6 +231,9 @@
(@o($o:ident) | $($var:tt)*) => {
$o.push(Index::Pipe($crate::nix_expr_inner!($($var)+)));
};
+ (@o($o:ident) + $($var:tt)*) => {
+ $o.push(Index::Merge($crate::nix_expr_inner!($($var)+)));
+ };
(@o($o:ident)) => {};
($field:ident $($tt:tt)+) => {{
use $crate::{nix_go, Index};
crates/nix-eval/src/value.rsdiffbeforeafterboth1use std::{collections::HashMap, fmt, path::PathBuf, sync::Arc};23use better_command::NixHandler;4use serde::{de::DeserializeOwned, Serialize};56use crate::{macros::NixExprBuilder, nix_go, Error, NixBuildBatch, NixSession, Result};78#[derive(Clone)]9pub enum Index {10 Var(String),11 String(String),12 #[allow(dead_code)]13 Apply(String),14 #[allow(dead_code)]15 Expr(NixExprBuilder),16 ExprApply(NixExprBuilder),17 Pipe(NixExprBuilder),18}19impl Index {20 pub fn var(v: impl AsRef<str>) -> Self {21 let v = v.as_ref();22 assert!(23 !(v.contains('.') | v.contains(' ')),24 "bad variable name: {v}"25 );26 Self::Var(v.to_owned())27 }28 pub fn attr(v: impl AsRef<str>) -> Self {29 Self::String(v.as_ref().to_owned())30 }31 #[allow(dead_code)]32 pub fn apply(v: impl Serialize) -> Self {33 let serialized = nixlike::serialize(v).expect("invalid value for apply");34 Self::Apply(serialized.trim_end().to_owned())35 }36}37impl fmt::Display for Index {38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {39 match self {40 Index::Var(v) => {41 write!(f, "{v}")42 }43 Index::String(k) => {44 let v = nixlike::format_identifier(k.as_str());45 write!(f, ".{v}")46 }47 Index::Apply(_) => {48 write!(f, "<apply>(...)")49 }50 Index::Expr(e) => {51 write!(f, "[{}]", e.out)52 }53 Index::ExprApply(_) => {54 write!(f, "<apply>(...)")55 }56 Index::Pipe(e) => {57 write!(f, "<map>({})", e.out)58 }59 }60 }61}62impl fmt::Debug for Index {63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {64 write!(f, "{self}")65 }66}67struct PathDisplay<'i>(&'i [Index]);68impl fmt::Display for PathDisplay<'_> {69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {70 for i in self.0 {71 write!(f, "{i}")?;72 }73 Ok(())74 }75}76struct ValueInner {77 full_path: Option<Vec<Index>>,78 session: NixSession,79 value: Option<u32>,80}81#[derive(Clone)]82pub struct Value(Arc<ValueInner>);83impl Value {84 fn root(session: NixSession) -> Self {85 Self(Arc::new(ValueInner {86 full_path: Some(vec![]),87 session,88 value: None,89 }))90 }91 async fn new(session: NixSession, query: &str) -> Result<Self> {92 let vid = session.0.lock().await.execute_assign(query).await?;93 Ok(Self(Arc::new(ValueInner {94 full_path: None,95 session,96 value: Some(vid),97 })))98 }99 /// Get a top-level binding.100 ///101 /// In flake repl session, every output is exposed as top-level binding.102 pub async fn binding(session: NixSession, field: &str) -> Result<Self> {103 Self::root(session).select([Index::var(field)]).await104 }105 pub async fn select<'a>(&self, name: impl IntoIterator<Item = Index>) -> Result<Self> {106 let mut used_fields = Vec::new();107 let mut name = name.into_iter();108109 let mut full_path = self.0.full_path.clone();110 let mut query = if let Some(id) = self.0.value {111 format!("sess_field_{id}")112 } else {113 let first = name.next();114 if let Some(Index::Var(i)) = first {115 if let Some(full_path) = &mut full_path {116 full_path.push(Index::Var(i.clone()));117 }118 i.clone()119 } else {120 panic!("first path item should be variable, got {first:?}")121 }122 };123 for v in name {124 if let Some(full_path) = &mut full_path {125 full_path.push(v.clone());126 }127 match v {128 Index::Var(_) => panic!("var item may only be first"),129 Index::String(s) => {130 let escaped =131 nixlike::serialize(s).expect("strings are always serialized successfully");132 query.push('.');133 query.push_str(escaped.trim());134 }135 Index::Apply(a) => {136 // In cases like `a {}.b` first `{}.b` will be evaluated, so `a {}` should be encased in `()`137 query = format!("({query} {a})");138 }139 Index::Expr(e) => {140 let index = Value::new(self.0.session.clone(), &e.out).await?;141 used_fields.push(index.clone());142 query.push('.');143 let index = format!("${{sess_field_{}}}", index.0.value.expect("value"));144 query.push_str(&index);145 }146 Index::ExprApply(e) => {147 let index = Value::new(self.0.session.clone(), &e.out).await?;148 used_fields.push(index.clone());149 query.push(' ');150 let index = format!("sess_field_{}", index.0.value.expect("value"));151 query.push_str(&index);152 query = format!("({query})");153 }154 Index::Pipe(v) => {155 let index = Value::new(self.0.session.clone(), &v.out).await?;156 used_fields.push(index.clone());157 let index = format!("sess_field_{}", index.0.value.expect("value"));158 query = format!("({index} {query})");159 }160 }161 }162163 let vid = self164 .0165 .session166 .0167 .lock()168 .await169 .execute_assign(&query)170 .await171 .map_err(|e| e.context(self.attribute()))?;172 Ok(Self(Arc::new(ValueInner {173 full_path,174 session: self.0.session.clone(),175 value: Some(vid),176 })))177 }178 pub async fn as_json<V: DeserializeOwned>(&self) -> Result<V> {179 let id = self.0.value.expect("can't serialize root field");180 let query = format!("sess_field_{id}");181 self.0182 .session183 .0184 .lock()185 .await186 .execute_expression_to_json(&query)187 .await188 .map_err(|e| e.context(self.attribute()))189 }190 #[allow(dead_code)]191 pub async fn has_field(&self, name: &str) -> Result<bool> {192 let id = self.0.value.expect("can't list root fields");193 let key = nixlike::escape_string(name);194 let query = format!("sess_field_{id} ? {key}");195 self.0196 .session197 .0198 .lock()199 .await200 .execute_expression_to_json(&query)201 .await202 .map_err(|e| e.context(self.attribute()))203 }204 pub async fn list_fields(&self) -> Result<Vec<String>> {205 let id = self.0.value.expect("can't list root fields");206 let query = format!("builtins.attrNames sess_field_{id}");207 self.0208 .session209 .0210 .lock()211 .await212 .execute_expression_to_json(&query)213 .await214 .map_err(|e| e.context(self.attribute()))215 }216 pub async fn type_of(&self) -> Result<String> {217 let id = self.0.value.expect("can't list root fields");218 let query = format!("builtins.typeOf sess_field_{id}");219 self.0220 .session221 .0222 .lock()223 .await224 .execute_expression_to_json(&query)225 .await226 .map_err(|e| e.context(self.attribute()))227 }228 #[allow(dead_code)]229 pub async fn import(&self) -> Result<Self> {230 let import = Self::new(self.0.session.clone(), "import").await?;231 Ok(nix_go!(self | import))232 }233 pub async fn build_maybe_batch(234 &self,235 batch: Option<NixBuildBatch>,236 ) -> Result<HashMap<String, PathBuf>> {237 if let Some(batch) = batch {238 batch.submit(self.clone()).await239 } else {240 self.build().await241 }242 }243 pub async fn build(&self) -> Result<HashMap<String, PathBuf>> {244 let id = self.0.value.expect("can't use build on not-value");245 let query = format!(":b sess_field_{id}");246 let vid = self247 .0248 .session249 .0250 .lock()251 .await252 .execute_expression_raw(&query, &mut NixHandler::default())253 .await?;254 if vid.is_empty() {255 return Err(Error::BuildFailed {256 attribute: self.attribute(),257 error: "build produced no output".to_owned(),258 });259 }260 let Some(vid) = vid.strip_prefix("This derivation produced the following outputs:\n")261 else {262 return Err(Error::BuildFailed {263 attribute: self.attribute(),264 error: format!("failed to parse output: {vid}"),265 });266 };267 let outputs = vid268 .split('\n')269 .filter(|v| !v.is_empty())270 .map(|v| v.split_once(" -> ").expect("unexpected build output"))271 .map(|(a, b)| (a.trim_start().to_owned(), PathBuf::from(b)))272 .collect();273 Ok(outputs)274 }275 /// Weakly convert string-like types (derivation/path/string) to string276 pub async fn to_string_weak(&self) -> Result<String> {277 let id = self.0.value.expect("can't use build on not-value");278 let query = format!("\"${{sess_field_{id}}}\"");279 let vid: String = self280 .0281 .session282 .0283 .lock()284 .await285 .execute_expression_to_json(&query)286 .await?;287 Ok(vid)288 }289290 fn attribute(&self) -> String {291 if let Some(full_path) = &self.0.full_path {292 PathDisplay(full_path).to_string()293 } else {294 "<root>".to_owned()295 }296 }297298 pub(crate) fn session(&self) -> NixSession {299 self.0.session.clone()300 }301302 pub(crate) fn session_field_id(&self) -> u32 {303 self.0.value.expect("not root")304 }305}306impl Drop for ValueInner {307 fn drop(&mut self) {308 if let Some(id) = self.value {309 if let Ok(mut lock) = self.session.0.try_lock() {310 lock.free_list.push(id)311 }312 // Leaked313 }314 }315}lib/default.nixdiffbeforeafterboth--- a/lib/default.nix
+++ b/lib/default.nix
@@ -46,7 +46,6 @@
mkPassword = {size ? 32}: {
coreutils,
mkSecretGenerator,
- ...
}:
mkSecretGenerator {
script = ''
@@ -58,7 +57,7 @@
mkEd25519 = {
noEmbedPublic ? false,
encoding ? null,
- }: {mkSecretGenerator, ...}:
+ }: {mkSecretGenerator}:
mkSecretGenerator {
script = ''
mkdir $out
@@ -68,7 +67,7 @@
'';
};
- mkX25519 = {encoding ? null}: {mkSecretGenerator, ...}:
+ mkX25519 = {encoding ? null}: {mkSecretGenerator}:
mkSecretGenerator {
script = ''
mkdir $out
@@ -80,7 +79,6 @@
mkRsa = {size ? 4096}: {
openssl,
mkSecretGenerator,
- ...
}:
mkSecretGenerator {
script = ''
@@ -98,7 +96,7 @@
count ? 32,
encoding,
noNuls ? false,
- }: {mkSecretGenerator, ...}:
+ }: {mkSecretGenerator}:
mkSecretGenerator {
script = ''
mkdir $out