git.delta.rocks / jrsonnet / refs/commits / 064468b85673

difftreelog

feat batch builds in legacy eval

Yaroslav Bolyukin2024-11-14parent: #dfbdb4a.patch.diff
in: trunk

17 files changed

modifiedCargo.lockdiffbeforeafterboth
after · Cargo.lock
397 packageslockfile v3
modifiedCargo.tomldiffbeforeafterboth
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -17,12 +17,8 @@
 	"time",
 	"rt-multi-thread",
 ] }
-clap = { version = "4.5", features = [
-	"derive",
-	"env",
-	"wrap_help",
-	"unicode",
-] }
+tokio-util = { version = "0.7.11", features = ["codec"] }
+clap = { version = "4.5", features = ["derive", "env", "wrap_help", "unicode"] }
 clap_complete = "4.5"
 age = { version = "0.10", features = ["ssh"] }
 anyhow = "1.0"
@@ -32,3 +28,4 @@
 serde_json = "1.0"
 tempfile = "3.10"
 nix = { version = "0.29.0", features = ["user", "fs"] }
+thiserror = "2.0.3"
modifiedcmds/fleet/src/cmds/build_systems.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/build_systems.rs
+++ b/cmds/fleet/src/cmds/build_systems.rs
@@ -7,7 +7,7 @@
 	opts::FleetOpts,
 };
 use itertools::Itertools as _;
-use nix_eval::nix_go;
+use nix_eval::{nix_go, NixBuildBatch};
 use tokio::{task::LocalSet, time::sleep};
 use tracing::{error, field, info, info_span, warn, Instrument};
 
@@ -251,18 +251,18 @@
 	Ok(())
 }
 
-async fn build_task(config: Config, host: String, build_attr: &str) -> Result<PathBuf> {
+async fn build_task(
+	config: Config,
+	host: String,
+	build_attr: &str,
+	batch: Option<NixBuildBatch>,
+) -> Result<PathBuf> {
 	info!("building");
 	let host = config.host(&host).await?;
 	// let action = Action::from(self.subcommand.clone());
 	let nixos = host.nixos_config().await?;
 	let drv = nix_go!(nixos.system.build[{ build_attr }]);
-	let outputs = drv.build().await.inspect_err(|_| {
-			if build_attr == "sdImage" {
-				info!("sd-image build failed");
-				info!("Make sure you have imported modulesPath/installer/sd-card/sd-image-<arch>[-installer].nix (For installer, you may want to check config)");
-			}
-		})?;
+	let outputs = drv.build_maybe_batch(batch).await?;
 	let out_output = outputs
 		.get("out")
 		.ok_or_else(|| anyhow!("system build should produce \"out\" output"))?;
@@ -296,7 +296,8 @@
 			// multiple hosts.
 			set.spawn_local(
 				(async move {
-					let built = match build_task(config, hostname.clone(), &build_attr).await {
+					let built = match build_task(config, hostname.clone(), &build_attr, None).await
+					{
 						Ok(path) => path,
 						Err(e) => {
 							error!("failed to deploy host: {}", e);
@@ -324,6 +325,7 @@
 	pub async fn run(self, config: &Config, opts: &FleetOpts) -> Result<()> {
 		let hosts = config.list_hosts().await?;
 		let set = LocalSet::new();
+		let batch = Some(config.nix_session.new_build_batch(format!("deploy-hosts")));
 		for host in hosts.into_iter() {
 			if opts.should_skip(&host).await? {
 				continue;
@@ -333,17 +335,19 @@
 			let hostname = host.name.clone();
 			let local_host = config.local_host();
 			let opts = opts.clone();
+			let batch = batch.clone();
 			// FIXME: Fix repl concurrency (see build-systems)
 			set.spawn_local(
 				(async move {
-					let built = match build_task(config.clone(), hostname.clone(), "toplevel").await
-					{
-						Ok(path) => path,
-						Err(e) => {
-							error!("failed to deploy host: {}", e);
-							return;
-						}
-					};
+					let built =
+						match build_task(config.clone(), hostname.clone(), "toplevel", batch).await
+						{
+							Ok(path) => path,
+							Err(e) => {
+								error!("failed to deploy host: {}", e);
+								return;
+							}
+						};
 					if !opts.is_local(&hostname) {
 						info!("uploading system closure");
 						{
@@ -405,6 +409,7 @@
 				.instrument(span),
 			);
 		}
+		drop(batch);
 		set.await;
 		Ok(())
 	}
modifiedcmds/fleet/src/cmds/secrets/mod.rsdiffbeforeafterboth
--- a/cmds/fleet/src/cmds/secrets/mod.rs
+++ b/cmds/fleet/src/cmds/secrets/mod.rs
@@ -231,9 +231,7 @@
 		let key = config.key(owner).await?;
 		recipients.push(key);
 	}
-	let generators = nix_go!(mk_secret_generators(Obj {
-		recipients: { recipients },
-	}));
+	let generators = nix_go!(mk_secret_generators(Obj { recipients }));
 
 	let generator = nix_go!(call_package(generator)(generators));
 
@@ -316,7 +314,7 @@
 	// I don't want to make modules always responsible for additional secret data anyway,
 	// so it should be in derivation, and not in the secret data itself.
 	let generators = nix_go!(default_mk_secret_generators(Obj {
-		recipients: { <Vec<String>>::new() },
+		recipients: <Vec<String>>::new(),
 	}));
 	let default_generator = nix_go!(default_call_package(generator)(generators));
 
modifiedcrates/fleet-base/src/host.rsdiffbeforeafterboth
--- a/crates/fleet-base/src/host.rs
+++ b/crates/fleet-base/src/host.rs
@@ -11,7 +11,7 @@
 
 use anyhow::{anyhow, bail, ensure, Context, Result};
 use fleet_shared::SecretData;
-use nix_eval::{nix_go, nix_go_json, util::assert_warn, Value};
+use nix_eval::{nix_go, nix_go_json, util::assert_warn, NixSession, Value};
 use openssh::SessionBuilder;
 use serde::de::DeserializeOwned;
 use tempfile::NamedTempFile;
@@ -33,6 +33,8 @@
 
 	/// import nixpkgs {system = local};
 	pub default_pkgs: Value,
+
+	pub nix_session: NixSession,
 }
 
 // TODO: Make field not pub
modifiedcrates/fleet-base/src/opts.rsdiffbeforeafterboth
--- a/crates/fleet-base/src/opts.rs
+++ b/crates/fleet-base/src/opts.rs
@@ -173,9 +173,9 @@
 		let directory = current_dir()?;
 
 		let pool = NixSessionPool::new(directory.as_os_str().to_owned(), nix_args.clone()).await?;
-		let root_field = pool.get().await?;
+		let nix_session = pool.get().await?;
 
-		let builtins_field = Value::binding(root_field.clone(), "builtins").await?;
+		let builtins_field = Value::binding(nix_session.clone(), "builtins").await?;
 		let local_system = if self.local_system == "detect" {
 			nix_go_json!(builtins_field.currentSystem)
 		} else {
@@ -187,7 +187,7 @@
 		let bytes = std::fs::read_to_string(fleet_data_path)?;
 		let data: Mutex<FleetData> = nixlike::parse_str(&bytes)?;
 
-		let fleet_root = Value::binding(root_field, "fleetConfigurations").await?;
+		let fleet_root = Value::binding(nix_session.clone(), "fleetConfigurations").await?;
 		let fleet_field = nix_go!(fleet_root.default({ data }));
 
 		let config_field = nix_go!(fleet_field.config);
@@ -200,10 +200,11 @@
 
 		let default_pkgs = nix_go!(nixpkgs(Obj {
 			overlays,
-			system: { local_system.clone() },
+			system: local_system.clone(),
 		}));
 
 		Ok(Config(Arc::new(FleetConfigInternals {
+			nix_session,
 			directory,
 			data,
 			local_system,
modifiedcrates/nix-eval/Cargo.tomldiffbeforeafterboth
--- a/crates/nix-eval/Cargo.toml
+++ b/crates/nix-eval/Cargo.toml
@@ -14,9 +14,9 @@
 regex = "1.10.6"
 serde = { workspace = true, features = ["derive"] }
 serde_json.workspace = true
-thiserror = "1.0.61"
+thiserror.workspace = true
 tokio = { workspace = true, features = ["process", "io-util"] }
-tokio-util = { version = "0.7.11", features = ["codec"] }
+tokio-util.workspace = true
 tracing.workspace = true
 unindent = "0.2.3"
 
modifiedcrates/nix-eval/src/lib.rsdiffbeforeafterboth
--- a/crates/nix-eval/src/lib.rs
+++ b/crates/nix-eval/src/lib.rs
@@ -3,12 +3,17 @@
 //!
 //! Current api is awful, little effort was put into this implementation.
 
-use std::sync::Arc;
+use std::{collections::HashMap, path::PathBuf, sync::Arc};
 
 pub use pool::NixSessionPool;
 use pool::NixSessionPoolInner;
 use r2d2::PooledConnection;
 pub use session::{Error, Result};
+use tokio::{
+	sync::{mpsc, oneshot},
+	task::AbortHandle,
+};
+use tracing::{info, instrument, Instrument};
 pub use value::{Index, Value};
 
 mod pool;
@@ -30,10 +35,82 @@
 #[derive(Clone)]
 pub struct NixSession(pub(crate) Arc<tokio::sync::Mutex<PooledConnection<NixSessionPoolInner>>>);
 
+struct NixBuildTask(Value, oneshot::Sender<Result<HashMap<String, PathBuf>>>);
+
+#[derive(Clone)]
+pub struct NixBuildBatch {
+	tx: mpsc::UnboundedSender<NixBuildTask>,
+}
+
+#[instrument(skip(session, values))]
+async fn build_multiple(name: String, session: NixSession, values: Vec<Value>) -> Result<()> {
+	let builtins = Value::binding(session, "builtins").await?;
+	let system = nix_go!(builtins.currentSystem);
+	let drv = nix_go!(builtins.derivation(Obj {
+		system,
+		name,
+		builder: "/bin/sh",
+		// we want nothing from this derivation, it is only used to perform multiple builds at once.
+		args: vec!["-c", "echo > $out"],
+		preferLocalBuild: true,
+		allowSubstitutes: false,
+		buildInputs: values,
+	}));
+	drv.build().await?;
+	Ok(())
+}
+
+impl NixBuildBatch {
+	fn new(name: String, session: NixSession) -> Self {
+		let (tx, mut rx) = mpsc::unbounded_channel::<NixBuildTask>();
+
+		tokio::task::spawn(async move {
+			let mut deps = vec![];
+			let mut build_data = vec![];
+			while let Some(task) = rx.recv().await {
+				build_data.push(task.0.clone());
+				deps.push(task);
+			}
+			if deps.is_empty() {
+				return;
+			}
+			match build_multiple(name, session, build_data).await {
+				Ok(_) => {
+					for NixBuildTask(v, o) in deps {
+						let _ = o.send(v.build().await);
+					}
+				}
+				Err(e) => {
+					for NixBuildTask(v, o) in deps {
+						let s = v.to_string_weak().await.expect("drv is string-like");
+						if PathBuf::from(s).exists() {
+							let _ = o.send(v.build().await);
+						} else {
+							let _ = o.send(Err(e.clone()));
+						}
+					}
+				}
+			};
+		});
+		Self { tx }
+	}
+	pub async fn submit(self, task: Value) -> Result<HashMap<String, PathBuf>> {
+		let Self { tx: task_tx } = self;
+		let (tx, rx) = oneshot::channel();
+		let _ = task_tx.send(NixBuildTask(task, tx));
+		drop(task_tx);
+		rx.await.expect("shoudn't be cancelled here")
+	}
+}
+
 impl NixSession {
 	fn ptr_eq(a: &Self, b: &Self) -> bool {
 		Arc::ptr_eq(&a.0, &b.0)
 	}
+
+	pub fn new_build_batch(&self, name: String) -> NixBuildBatch {
+		NixBuildBatch::new(name, self.clone())
+	}
 }
 
 pub fn init_tokio() {
modifiedcrates/nix-eval/src/macros.rsdiffbeforeafterboth
--- a/crates/nix-eval/src/macros.rs
+++ b/crates/nix-eval/src/macros.rs
@@ -7,6 +7,55 @@
 	pub(crate) out: String,
 	used_fields: Vec<Value>,
 }
+trait AttrSetValue {
+	fn to_builder(self) -> NixExprBuilder;
+}
+trait Primitive {}
+
+macro_rules! impl_primitive {
+	($($t:ty),+) => {
+			$(
+				impl Primitive for $t {}
+			)+
+	};
+}
+impl_primitive!(String, bool, &'static str);
+
+impl<T> AttrSetValue for T
+where
+	// Limited by Primitive trait to avoid orphan rules violation with Vec<T: AttrSetValue>
+	T: Serialize + Primitive,
+{
+	fn to_builder(self) -> NixExprBuilder {
+		let serialized = nixlike::serialize(self).expect("invalid value for apply");
+		NixExprBuilder {
+			out: serialized.trim_end().to_owned(),
+			used_fields: Vec::new(),
+		}
+	}
+}
+impl AttrSetValue for Value {
+	fn to_builder(self) -> NixExprBuilder {
+		NixExprBuilder {
+			out: format!("sess_field_{}", self.session_field_id()),
+			used_fields: vec![self],
+		}
+	}
+}
+impl<T> AttrSetValue for Vec<T>
+where
+	T: AttrSetValue,
+{
+	fn to_builder(self) -> NixExprBuilder {
+		let mut builder = NixExprBuilder::list();
+		for v in self {
+			builder.list_value(NixExprBuilder::attrset_value(v));
+		}
+		builder.list_end();
+		builder
+	}
+}
+
 impl NixExprBuilder {
 	pub fn object() -> Self {
 		NixExprBuilder {
@@ -14,6 +63,12 @@
 			used_fields: Vec::new(),
 		}
 	}
+	pub fn list() -> Self {
+		NixExprBuilder {
+			out: "[".to_owned(),
+			used_fields: Vec::new(),
+		}
+	}
 	pub fn string(s: &str) -> Self {
 		NixExprBuilder {
 			out: nixlike::serialize(s)
@@ -23,6 +78,9 @@
 			used_fields: Vec::new(),
 		}
 	}
+	pub fn attrset_value(v: impl AttrSetValue) -> Self {
+		v.to_builder()
+	}
 	pub fn serialized(v: impl Serialize) -> Self {
 		let serialized = nixlike::serialize(v).expect("invalid value for apply");
 		Self {
@@ -46,6 +104,13 @@
 		self.extend(value);
 		self.out.push_str("; ");
 	}
+	pub fn list_value(&mut self, value: Self) {
+		self.extend(value);
+		self.out.push(' ');
+	}
+	pub fn list_end(&mut self) {
+		self.out.push(']');
+	}
 
 	pub fn extend(&mut self, e: Self) {
 		self.out.push_str(&e.out);
@@ -80,19 +145,19 @@
 #[macro_export]
 macro_rules! nix_expr_inner {
 	//(@munch_object FIXME: value should be arbitrary nix_expr_inner input... Time to write proc-macro?
-	(@obj($o:ident) $field:ident, $($tt:tt)*) => {{
+	(@obj($o:ident) $field:ident$(, $($tt:tt)*)?) => {{
 		$o.obj_key(
 			NixExprBuilder::string(stringify!($field)),
-			NixExprBuilder::value($field),
+			NixExprBuilder::attrset_value($field),
 		);
-		nix_expr_inner!(@obj($o) $($tt)*);
+		$(nix_expr_inner!(@obj($o) $($tt)*);)?
 	}};
-	(@obj($o:ident) $field:ident: $v:block, $($tt:tt)*) => {{
+	(@obj($o:ident) $field:ident: $v:expr$(, $($tt:tt)*)?) => {{
 		$o.obj_key(
 			NixExprBuilder::string(stringify!($field)),
-			NixExprBuilder::serialized(&$v),
+			NixExprBuilder::attrset_value($v),
 		);
-		nix_expr_inner!(@obj($o) $($tt)*);
+		$(nix_expr_inner!(@obj($o) $($tt)*);)?
 	}};
 	(@obj($o:ident)) => {{}};
 	(Obj { $($tt:tt)* }) => {{
modifiedcrates/nix-eval/src/session.rsdiffbeforeafterboth
--- a/crates/nix-eval/src/session.rs
+++ b/crates/nix-eval/src/session.rs
@@ -14,7 +14,7 @@
 use tokio_util::codec::{FramedRead, LinesCodec};
 use tracing::{debug, error, warn, Level};
 
-#[derive(Error, Debug)]
+#[derive(Error, Debug, Clone)]
 pub enum Error {
 	#[error("failed to create nix repl session: {0}")]
 	SessionInit(&'static str),
@@ -33,15 +33,15 @@
 	BuildFailed { attribute: String, error: String },
 
 	#[error("output: {0}")]
-	Json(#[from] serde_json::Error),
+	Json(Arc<serde_json::Error>),
 	// int outputs are too specific, and should not be used,
 	// thus error is ok to be not informative.
 	#[error("int output: {0}")]
 	Int(ParseIntError),
 	#[error("pool: {0}")]
-	Pool(#[from] r2d2::Error),
+	Pool(Arc<r2d2::Error>),
 	#[error("io: {0}")]
-	Io(#[from] std::io::Error),
+	Io(Arc<std::io::Error>),
 
 	// TODO: Should be done by wrapper/in different type.
 	#[error("at {0}: {1}")]
@@ -50,6 +50,21 @@
 	#[error("error: {0}")]
 	NixError(String),
 }
+impl From<r2d2::Error> for Error {
+	fn from(value: r2d2::Error) -> Self {
+		Self::Pool(Arc::new(value))
+	}
+}
+impl From<std::io::Error> for Error {
+	fn from(value: std::io::Error) -> Self {
+		Self::Io(Arc::new(value))
+	}
+}
+impl From<serde_json::Error> for Error {
+	fn from(value: serde_json::Error) -> Self {
+		Self::Json(Arc::new(value))
+	}
+}
 impl Error {
 	pub(crate) fn context(self, context: String) -> Self {
 		Self::InContext(context, Box::new(self))
modifiedcrates/nix-eval/src/value.rsdiffbeforeafterboth
--- a/crates/nix-eval/src/value.rs
+++ b/crates/nix-eval/src/value.rs
@@ -3,7 +3,7 @@
 use better_command::NixHandler;
 use serde::{de::DeserializeOwned, Serialize};
 
-use crate::{macros::NixExprBuilder, nix_go, Error, NixSession, Result};
+use crate::{macros::NixExprBuilder, nix_go, Error, NixBuildBatch, NixSession, Result};
 
 #[derive(Clone)]
 pub enum Index {
@@ -230,6 +230,16 @@
 		let import = Self::new(self.0.session.clone(), "import").await?;
 		Ok(nix_go!(self | import))
 	}
+	pub async fn build_maybe_batch(
+		&self,
+		batch: Option<NixBuildBatch>,
+	) -> Result<HashMap<String, PathBuf>> {
+		if let Some(batch) = batch {
+			batch.submit(self.clone()).await
+		} else {
+			self.build().await
+		}
+	}
 	pub async fn build(&self) -> Result<HashMap<String, PathBuf>> {
 		let id = self.0.value.expect("can't use build on not-value");
 		let query = format!(":b sess_field_{id}");
@@ -262,6 +272,20 @@
 			.collect();
 		Ok(outputs)
 	}
+	/// Weakly convert string-like types (derivation/path/string) to string
+	pub async fn to_string_weak(&self) -> Result<String> {
+		let id = self.0.value.expect("can't use build on not-value");
+		let query = format!("\"${{sess_field_{id}}}\"");
+		let vid: String = self
+			.0
+			.session
+			.0
+			.lock()
+			.await
+			.execute_expression_to_json(&query)
+			.await?;
+		Ok(vid)
+	}
 
 	fn attribute(&self) -> String {
 		if let Some(full_path) = &self.0.full_path {
addedcrates/nix-native-eval/Cargo.tomldiffbeforeafterboth
--- /dev/null
+++ b/crates/nix-native-eval/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "nix-native-eval"
+edition = "2021"
+version.workspace = true
+
+[dependencies]
+nixrs = { git = "https://github.com/Anillc/nixrs", version = "0.1.0" }
addedcrates/nix-native-eval/src/lib.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/nix-native-eval/src/lib.rs
@@ -0,0 +1,7 @@
+use nixrs::{State, Store};
+
+fn init() {
+	nixrs::init();
+	let store = Store::new("daemon")?;
+	let state = State::new(store)
+}
modifiedcrates/nixlike/Cargo.tomldiffbeforeafterboth
--- a/crates/nixlike/Cargo.toml
+++ b/crates/nixlike/Cargo.toml
@@ -4,11 +4,11 @@
 edition = "2021"
 
 [dependencies]
+thiserror.workspace = true
 alejandra = { git = "https://github.com/kamadorueda/alejandra" }
 linked-hash-map = "0.5.6"
 peg = "0.8.2"
 serde = "1.0.196"
-thiserror = "1.0.57"
 serde_json = "1.0.113"
 ron = "0.8.1"
 serde-transcode = "1.1.1"
modifiedflake.lockdiffbeforeafterboth
--- a/flake.lock
+++ b/flake.lock
@@ -1,17 +1,12 @@
 {
   "nodes": {
     "crane": {
-      "inputs": {
-        "nixpkgs": [
-          "nixpkgs"
-        ]
-      },
       "locked": {
-        "lastModified": 1721699339,
-        "narHash": "sha256-UqtSwU13vpzzM6w8tGghEbA7ObM3NCDzSpz19QQo9XE=",
+        "lastModified": 1731098351,
+        "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "0081e9c447f3b70822c142908f08ceeb436982b8",
+        "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28",
         "type": "github"
       },
       "original": {
@@ -22,14 +17,16 @@
     },
     "flake-parts": {
       "inputs": {
-        "nixpkgs-lib": "nixpkgs-lib"
+        "nixpkgs-lib": [
+          "nixpkgs"
+        ]
       },
       "locked": {
-        "lastModified": 1719994518,
-        "narHash": "sha256-pQMhCCHyQGRzdfAkdJ4cIWiw+JNuWsTX7f0ZYSyz0VY=",
+        "lastModified": 1730504689,
+        "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "9227223f6d922fee3c7b190b2cc238a99527bbb7",
+        "rev": "506278e768c2a08bec68eb62932193e341f55c90",
         "type": "github"
       },
       "original": {
@@ -40,11 +37,11 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1721814637,
-        "narHash": "sha256-L3QkCvxeByJfW45wLkdZ9pL5h9PezOwwfx7G2sRfjiU=",
+        "lastModified": 1731514040,
+        "narHash": "sha256-4VkY8gwyR83N6MPT7ipXTOSBXpVL2Hrwh898UAR3HZ8=",
         "owner": "nixos",
         "repo": "nixpkgs",
-        "rev": "e0c444a0b8413a31df199052f5714d409dc4c1d0",
+        "rev": "155168226cb666d242306e13d7dbdaa8a76d20e1",
         "type": "github"
       },
       "original": {
@@ -52,18 +49,6 @@
         "ref": "master",
         "repo": "nixpkgs",
         "type": "github"
-      }
-    },
-    "nixpkgs-lib": {
-      "locked": {
-        "lastModified": 1719876945,
-        "narHash": "sha256-Fm2rDDs86sHy0/1jxTOKB1118Q0O3Uc7EC0iXvXKpbI=",
-        "type": "tarball",
-        "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz"
-      },
-      "original": {
-        "type": "tarball",
-        "url": "https://github.com/NixOS/nixpkgs/archive/5daf0514482af3f97abaefc78a6606365c9108e2.tar.gz"
       }
     },
     "root": {
@@ -81,11 +66,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1721810656,
-        "narHash": "sha256-33UCMmgPL+sz06+iupNkl99hcBABP56ENcxSoKqr0TY=",
+        "lastModified": 1731464916,
+        "narHash": "sha256-WZ5rpjr/wCt7yBOUsvDE2i22hYz9g8W921jlwVktRQ4=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "a6afdaab4a47d6ecf647a74968e92a51c4a18e5a",
+        "rev": "2c19bad6e881b5a154cafb7f9106879b5b356d1f",
         "type": "github"
       },
       "original": {
modifiedflake.nixdiffbeforeafterboth
--- a/flake.nix
+++ b/flake.nix
@@ -5,23 +5,16 @@
     nixpkgs.url = "github:nixos/nixpkgs/master";
     rust-overlay = {
       url = "github:oxalica/rust-overlay";
-      inputs = {
-        nixpkgs.follows = "nixpkgs";
-      };
+      inputs.nixpkgs.follows = "nixpkgs";
     };
-    flake-parts.url = "github:hercules-ci/flake-parts";
-    crane = {
-      url = "github:ipetkov/crane";
-      inputs.nixpkgs.follows = "nixpkgs";
+    flake-parts = {
+      url = "github:hercules-ci/flake-parts";
+      inputs.nixpkgs-lib.follows = "nixpkgs";
     };
+    crane.url = "github:ipetkov/crane";
   };
-  outputs = inputs @ {
-    self,
-    flake-parts,
-    crane,
-    ...
-  }:
-    flake-parts.lib.mkFlake {
+  outputs = inputs:
+    inputs.flake-parts.lib.mkFlake {
       inherit inputs;
     } {
       flake = rec {
@@ -33,7 +26,7 @@
             fleetConfiguration = throw "function-based interface is deprecated, use flake-parts syntax instead";
           };
         flakeModules.default = import ./lib/flakePart.nix {
-          inherit crane;
+          inherit (inputs) crane;
         };
         flakeModule = flakeModules.default;
 
@@ -85,7 +78,7 @@
         deployerSystem = elem system deployerSystems;
         lib = pkgs.lib;
         rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
-        craneLib = (crane.mkLib pkgs).overrideToolchain rust;
+        craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rust;
       in {
         _module.args.pkgs = import inputs.nixpkgs {
           inherit system;
@@ -132,6 +125,8 @@
               openssl
               bacon
               nil
+              rustPlatform.bindgenHook
+              nixVersions.nix_2_22
             ];
             env.PROTOC = "${pkgs.protobuf}/bin/protoc";
           };
modifiedrust-toolchain.tomldiffbeforeafterboth
--- a/rust-toolchain.toml
+++ b/rust-toolchain.toml
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-07-08"
+channel = "nightly-2024-11-12"
 components = ["rustfmt", "clippy", "rust-analyzer", "rust-src"]