git.delta.rocks / jrsonnet / refs/commits / 81ddc194a4bf

difftreelog

feat basic primop interface

kkosuqksYaroslav Bolyukin2025-11-22parent: #0c1bf1b.patch.diff
in: trunk

3 files changed

modifiedcrates/nix-eval/src/lib.rsdiffbeforeafterboth
--- a/crates/nix-eval/src/lib.rs
+++ b/crates/nix-eval/src/lib.rs
@@ -1,12 +1,13 @@
 use std::borrow::Cow;
 use std::cell::RefCell;
 use std::ffi::{CStr, CString, c_char, c_int, c_uint, c_void};
-use std::ptr::null_mut;
+use std::ptr::{null, null_mut};
 use std::sync::LazyLock;
+use std::{array, fmt, slice};
 use std::{collections::HashMap, path::PathBuf};
-use std::{fmt, slice};
 
 use anyhow::{Context, anyhow, bail};
+use itertools::Itertools;
 use serde::Serialize;
 use serde::de::DeserializeOwned;
 
@@ -18,25 +19,26 @@
 use self::nix_raw::{
 	BindingsBuilder as c_bindings_builder, EvalState as c_eval_state, GC_SUCCESS,
 	GC_allow_register_threads, GC_get_stack_base, GC_register_my_thread, GC_stack_base,
-	GC_thread_is_registered, GC_unregister_my_thread, ListBuilder as c_list_builder,
-	Store as c_store, StorePath as c_store_path, alloc_value, bindings_builder_free,
-	bindings_builder_insert, c_context, c_context_create, c_context_free, clear_err, err_code,
-	err_info_msg, err_msg, eval_state_build, eval_state_builder_load, eval_state_builder_new,
-	eval_state_builder_set_eval_setting, expr_eval_from_string, fetchers_settings,
-	fetchers_settings_free, fetchers_settings_new, flake_lock, flake_lock_flags,
-	flake_lock_flags_free, flake_lock_flags_new, flake_reference,
+	GC_thread_is_registered, GC_unregister_my_thread, ListBuilder as c_list_builder, PrimOp,
+	PrimOpFun, Store as c_store, StorePath as c_store_path, alloc_primop, alloc_value,
+	bindings_builder_free, bindings_builder_insert, c_context, c_context_create, c_context_free,
+	clear_err, copy_value, err_code, err_info_msg, err_msg, eval_state_build,
+	eval_state_builder_load, eval_state_builder_new, eval_state_builder_set_eval_setting,
+	expr_eval_from_string, fetchers_settings, fetchers_settings_free, fetchers_settings_new,
+	flake_lock, flake_lock_flags, flake_lock_flags_free, flake_lock_flags_new, flake_reference,
 	flake_reference_and_fragment_from_string, flake_reference_parse_flags,
 	flake_reference_parse_flags_free, flake_reference_parse_flags_new,
 	flake_reference_parse_flags_set_base_directory, flake_settings, flake_settings_free,
 	flake_settings_new, gc_now as gc_now_raw, get_attr_byname, get_attr_name_byidx, get_attrs_size,
 	get_list_byidx, get_list_size, get_string, get_type, has_attr_byname, init_bool, init_int,
-	init_string, libexpr_init, libstore_init, libutil_init, list_builder_free, list_builder_insert,
-	locked_flake, locked_flake_free, locked_flake_get_output_attrs, make_attrs,
-	make_bindings_builder, make_list, make_list_builder, realised_string, realised_string_free,
-	realised_string_get_buffer_size, realised_string_get_buffer_start,
-	realised_string_get_store_path, realised_string_get_store_path_count, set_err_msg, setting_set,
-	state_free, store_open, store_parse_path, store_path_free, store_path_name, string_realise,
-	value, value_call, value_decref, value_incref,
+	init_primop, init_string, libexpr_init, libstore_init, libutil_init, list_builder_free,
+	list_builder_insert, locked_flake, locked_flake_free, locked_flake_get_output_attrs,
+	make_attrs, make_bindings_builder, make_list, make_list_builder, realised_string,
+	realised_string_free, realised_string_get_buffer_size, realised_string_get_buffer_start,
+	realised_string_get_store_path, realised_string_get_store_path_count, register_primop,
+	set_err_msg, setting_set, state_free, store_copy_closure, store_get_fs_closure, store_open,
+	store_parse_path, store_path_free, store_path_name, string_realise, value, value_call,
+	value_decref, value_incref,
 };
 
 // Contains macros helpers
@@ -166,6 +168,7 @@
 	}
 }
 
+#[repr(transparent)]
 pub struct NixContext(*mut c_context);
 impl NixContext {
 	pub fn set_err(&mut self, err: NixErrorKind, msg: &CStr) {
@@ -540,6 +543,7 @@
 	}
 }
 
+#[repr(transparent)]
 pub struct Value(*mut value);
 
 unsafe impl Send for Value {}
@@ -626,6 +630,12 @@
 }
 
 impl Value {
+	pub fn new_primop(v: NativeFn) -> Self {
+		let out = Self::new_uninit();
+		with_default_context(|c, _| unsafe { init_primop(c, out.0, v.0) })
+			.expect("primop initialization should not fail");
+		out
+	}
 	pub fn new_attrs(v: HashMap<&str, Value>) -> Self {
 		let out = Self::new_uninit();
 		let mut b = AttrsBuilder::new(v.len());
@@ -913,6 +923,70 @@
 	nix_logging_cxx::apply_tracing_logger();
 }
 
+unsafe extern "C" fn nix_primop_closure_adapter<const N: usize>(
+	user_data: *mut c_void,
+	context: *mut c_context,
+	state: *mut nix_raw::EvalState,
+	args: *mut *mut value,
+	ret: *mut value,
+) {
+	let user_closure: &UserClosure<N> = unsafe { &*user_data.cast_const().cast() };
+	let args: [&Value; N] = array::from_fn(|i| {
+		let v: &Value = unsafe { &*args.add(i).cast_const().cast() };
+		v
+	});
+	let ctx: &mut NixContext = unsafe { &mut *context.cast() };
+
+	match user_closure(args) {
+		Ok(v) => {
+			unsafe { copy_value(context, ret, v.0) };
+		}
+		Err(e) => {
+			ctx.set_err(
+				NixErrorKind::Unknown,
+				&CString::new(e.to_string()).expect("error should not contain internal nuls"),
+			);
+		}
+	}
+}
+
+type UserClosure<const N: usize> = Box<dyn Fn([&Value; N]) -> Result<Value>>;
+
+struct NativeFn(*mut PrimOp);
+impl NativeFn {
+	pub fn new<const N: usize>(
+		name: &'static CStr,
+		doc: &'static CStr,
+		args: [&'static CStr; N],
+		f: impl Fn([&Value; N]) -> Result<Value> + 'static,
+	) -> Self {
+		// Double-boxing to make it thin pointer, as vtable gets outside of first Box
+		let closure: Box<UserClosure<N>> = Box::new(Box::new(f));
+		let f: PrimOpFun = Some(nix_primop_closure_adapter::<N>);
+		let mut args = args.into_iter().map(|v| v.as_ptr()).collect_vec();
+		args.push(null());
+		let args = args.as_mut_ptr();
+		let primop = with_default_context(|c, _| unsafe {
+			alloc_primop(
+				c,
+				f,
+				N as i32,
+				name.as_ptr(),
+				args,
+				doc.as_ptr(),
+				Box::into_raw(closure).cast(),
+			)
+		})
+		.expect("primop allocation should not fail");
+
+		Self(primop)
+	}
+	pub fn register(self) {
+		with_default_context(|c, _| unsafe { register_primop(c, self.0) })
+			.expect("primop registration should not fail");
+	}
+}
+
 struct StorePath(*mut c_store_path);
 impl StorePath {}
 
@@ -949,6 +1023,20 @@
 	let s = nix_go!(attrs.packages["x86_64-linux"].fleet.drvPath);
 	let s = CString::new(s.to_string()?).expect("path str is cstring");
 
+	let uppercase_suffix = Value::new_primop(NativeFn::new(
+		c"uppercase_suffix",
+		c"make string uppercase and add suffix",
+		[c"str", c"suffix"],
+		|[str, suffix]: [&Value; 2]| {
+			let str = str.to_string()?;
+			let suffix = suffix.to_string()?;
+			Ok(Value::new_str(&format!("{}{suffix}", str.to_uppercase())))
+		},
+	));
+
+	let test_result: String = nix_go_json!(test_data.testPrimop(uppercase_suffix));
+	assert_eq!(test_result, "PREFIX_BODY_SUFFIX");
+
 	let nix_ctx = NixContext::new();
 	let store = GLOBAL_STATE.store.parse_path(s.as_c_str())?;
 
modifiedflake.lockdiffbeforeafterboth
--- a/flake.lock
+++ b/flake.lock
@@ -2,11 +2,10 @@
   "nodes": {
     "crane": {
       "locked": {
-        "lastModified": 1762538466,
-        "narHash": "sha256-8zrIPl6J+wLm9MH5ksHcW7BUHo7jSNOu0/hA0ohOOaM=",
+        "lastModified": 1763511871,
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "0cea393fffb39575c46b7a0318386467272182fe",
+        "rev": "099f9014bc8d0cd6e445470ea1df0fd691d5a548",
         "type": "github"
       },
       "original": {
@@ -38,11 +37,10 @@
         ]
       },
       "locked": {
-        "lastModified": 1762810396,
-        "narHash": "sha256-dxFVgQPG+R72dkhXTtqUm7KpxElw3u6E+YlQ2WaDgt8=",
+        "lastModified": 1763759067,
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "0bdadb1b265fb4143a75bd1ec7d8c915898a9923",
+        "rev": "2cccadc7357c0ba201788ae99c4dfa90728ef5e0",
         "type": "github"
       },
       "original": {
@@ -51,26 +49,6 @@
         "type": "github"
       }
     },
-    "flake-parts_2": {
-      "inputs": {
-        "nixpkgs-lib": [
-          "nix",
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1748821116,
-        "narHash": "sha256-F82+gS044J1APL0n4hH50GYdPRv/5JWm34oCJYmVKdE=",
-        "rev": "49f0870db23e8c1ca0b5259734a02cd9e1e371a1",
-        "revCount": 377,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/hercules-ci/flake-parts/0.1.377%2Brev-49f0870db23e8c1ca0b5259734a02cd9e1e371a1/01972f28-554a-73f8-91f4-d488cc502f08/source.tar.gz"
-      },
-      "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/hercules-ci/flake-parts/0.1"
-      }
-    },
     "fleet-tf": {
       "inputs": {
         "flake-parts": [
@@ -85,7 +63,6 @@
       },
       "locked": {
         "lastModified": 1759080490,
-        "narHash": "sha256-6eog70ItEoiusftwCp1vjY/7kA1+BDTUuRwg4KmszUs=",
         "owner": "CertainLach",
         "repo": "fleet-tf",
         "rev": "878bd8c23933d628bf750378bbe527b841901c3d",
@@ -123,18 +100,21 @@
     },
     "nix": {
       "inputs": {
-        "flake-parts": "flake-parts_2",
+        "flake-parts": [
+          "flake-parts"
+        ],
         "git-hooks-nix": "git-hooks-nix",
-        "nixpkgs": "nixpkgs",
+        "nixpkgs": [
+          "nixpkgs"
+        ],
         "nixpkgs-23-11": "nixpkgs-23-11",
         "nixpkgs-regression": "nixpkgs-regression"
       },
       "locked": {
-        "lastModified": 1762216145,
-        "narHash": "sha256-ff2SX5zKVsOAvN84AT+81TmWob5B5dxlkMcFexPZHAA=",
+        "lastModified": 1763844027,
         "owner": "deltarocks",
         "repo": "nix",
-        "rev": "dece43d5bae876aa475033d5a5a389b478b1644e",
+        "rev": "6b07ab20f1a65bd4aa54ec1418ff6f179dde64ac",
         "type": "github"
       },
       "original": {
@@ -146,16 +126,17 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1755922037,
-        "narHash": "sha256-wY1+2JPH0ZZC4BQefoZw/k+3+DowFyfOxv17CN/idKs=",
-        "rev": "b1b3291469652d5a2edb0becc4ef0246fff97a7c",
-        "revCount": 808723,
-        "type": "tarball",
-        "url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.2505.808723%2Brev-b1b3291469652d5a2edb0becc4ef0246fff97a7c/0198daf7-011a-7703-95d7-57146e794342/source.tar.gz"
+        "lastModified": 1763844746,
+        "owner": "nixos",
+        "repo": "nixpkgs",
+        "rev": "d20f025296df84f7d97dee7c1a069bea8b17c8f2",
+        "type": "github"
       },
       "original": {
-        "type": "tarball",
-        "url": "https://flakehub.com/f/NixOS/nixpkgs/0.2505"
+        "owner": "nixos",
+        "ref": "release-25.05",
+        "repo": "nixpkgs",
+        "type": "github"
       }
     },
     "nixpkgs-23-11": {
@@ -190,29 +171,13 @@
         "type": "github"
       }
     },
-    "nixpkgs_2": {
-      "locked": {
-        "lastModified": 1762881507,
-        "narHash": "sha256-P59mF2fC4/ijf5ZoCQA+wcaN6b0OgKKA3BQZpfPqHtY=",
-        "owner": "nixos",
-        "repo": "nixpkgs",
-        "rev": "2bbfb713196ae4cf5428530e8387cadcf95d3e2f",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nixos",
-        "ref": "release-25.05",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
     "root": {
       "inputs": {
         "crane": "crane",
         "flake-parts": "flake-parts",
         "fleet-tf": "fleet-tf",
         "nix": "nix",
-        "nixpkgs": "nixpkgs_2",
+        "nixpkgs": "nixpkgs",
         "rust-overlay": "rust-overlay",
         "shelly": "shelly",
         "treefmt-nix": "treefmt-nix"
@@ -225,11 +190,10 @@
         ]
       },
       "locked": {
-        "lastModified": 1762828736,
-        "narHash": "sha256-RxtFHWZpKwVcWHhx88E2NhWuBbgYVqIoIDynGs5FoJs=",
+        "lastModified": 1763778964,
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "8d5baa5628f6dbd7ce6beca3c299bae27755204c",
+        "rev": "7f3aa46dfa230ec2a4ca9281186a24771650ccd1",
         "type": "github"
       },
       "original": {
@@ -241,7 +205,6 @@
     "shelly": {
       "locked": {
         "lastModified": 1756323923,
-        "narHash": "sha256-sKUaQrgnYVBmG5cGmGoFYXc61g74ufWpPYGPoJia58k=",
         "owner": "CertainLach",
         "repo": "shelly",
         "rev": "b5dd29a500db04f54a9f1c2bf81cdd84df8b0cd7",
@@ -260,11 +223,10 @@
         ]
       },
       "locked": {
-        "lastModified": 1762410071,
-        "narHash": "sha256-aF5fvoZeoXNPxT0bejFUBXeUjXfHLSL7g+mjR/p5TEg=",
+        "lastModified": 1762938485,
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "97a30861b13c3731a84e09405414398fbf3e109f",
+        "rev": "5b4ee75aeefd1e2d5a1cc43cf6ba65eba75e83e4",
         "type": "github"
       },
       "original": {
modifiedflake.nixdiffbeforeafterboth
before · flake.nix
1{2  description = "NixOS cluster configuration management";34  inputs = {5    nixpkgs.url = "github:nixos/nixpkgs/release-25.05";6    rust-overlay = {7      url = "github:oxalica/rust-overlay";8      inputs.nixpkgs.follows = "nixpkgs";9    };10    flake-parts = {11      url = "github:hercules-ci/flake-parts";12      inputs.nixpkgs-lib.follows = "nixpkgs";13    };14    crane.url = "github:ipetkov/crane";15    shelly.url = "github:CertainLach/shelly";16    fleet-tf = {17      url = "github:CertainLach/fleet-tf";18      inputs.nixpkgs.follows = "nixpkgs";19      inputs.shelly.follows = "shelly";20      inputs.flake-parts.follows = "flake-parts";21    };22    treefmt-nix = {23      url = "github:numtide/treefmt-nix";24      inputs.nixpkgs.follows = "nixpkgs";25    };26    # DeterminateSystem's nix fork is controversial, but I don't mind it,27    # and it has lazy-trees support which is useful for fleet.28    nix.url = "github:deltarocks/nix/fleet";29  };30  outputs =31    inputs:32    inputs.flake-parts.lib.mkFlake33      {34        inherit inputs;35      }36      {37        imports = [ inputs.shelly.flakeModule ];38        flake = rec {39          lib =40            (import ./lib {41              inherit (inputs.nixpkgs) lib;42            })43            // {44              fleetConfiguration = throw "function-based interface is deprecated, use flake-parts syntax instead";45            };46          flakeModules.default = import ./lib/flakePart.nix {47            inherit (inputs) crane;48          };49          flakeModule = flakeModules.default;5051          flakeModules.fleet-tf = ./modules/extras/tf.nix;5253          # Used to test nix-eval bindings54          testData = {55            testObj = {56              v = "Hello";57            };58            testString = "hello";59          };6061          # To be used with https://github.com/NixOS/nix/pull/889262          schemas =63            let64              inherit (inputs.nixpkgs.lib) mapAttrs;65            in66            {67              fleetConfigurations = {68                version = 1;69                doc = ''70                  The `fleetConfigurations` flake output defines fleet cluster configurations.71                '';72                inventory = output: {73                  children = mapAttrs (configName: cluster: {74                    what = "fleet cluster configuration";7576                    children = mapAttrs (hostName: host: {77                      what = "host [${host.system}]";78                    }) cluster.config.hosts;79                    # It is possible to implement this inventory right now, but I want to80                    # get rid of `fleet.nix` file in the future.81                    # children.secrets = { };82                  }) output;83                };84              };85            };86        };87        # Supported and tested list of deployment targets.88        systems = [89          "x86_64-linux"90          "aarch64-linux"91          "armv7l-linux"92          "armv6l-linux"93        ];94        perSystem =95          {96            config,97            system,98            pkgs,99            self,100            inputs',101            ...102          }:103          let104            inherit (lib.attrsets) mapAttrs';105            inherit (lib.lists) elem;106            # Can also be built for darwin, through it is not usual to deploy nixos systems from macos machines.107            # I have no hardware for such testing, thus only adding machines I actually have and use.108            #109            # It is not possible to deploy any host from armv6/armv7 hardware, and I don't think it even makes sense.110            deployerSystems = [111              "aarch64-linux"112              "x86_64-linux"113            ];114            deployerSystem = elem system deployerSystems;115            lib = pkgs.lib;116            rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;117            craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rust;118            treefmt = (inputs.treefmt-nix.lib.evalModule pkgs ./treefmt.nix).config.build;119          in120          {121            _module.args.pkgs = import inputs.nixpkgs {122              inherit system;123              overlays = [124                (inputs.rust-overlay.overlays.default)125                (final: prev: {126                  boehmgc = prev.boehmgc.overrideAttrs (prevAttrs: {127                    configureFlags = prevAttrs.configureFlags ++ [128                      "--enable-gc-assertions"129                    ];130                  });131                })132              ];133            };134            # Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.135            packages = lib.mkIf deployerSystem (136              let137                packages = pkgs.callPackages ./pkgs {138                  inherit craneLib inputs';139                };140              in141              packages // { default = packages.fleet; }142            );143            # fleet-install-secrets will not be built normally, because they are not ran directly by user most of the time.144            # checks there build packages for default nixpkgs rustPlatform packages.145            checks =146              let147                nixpkgsCraneLib = inputs.crane.mkLib pkgs;148                packages = pkgs.callPackages ./pkgs {149                  craneLib = nixpkgsCraneLib;150                  inherit inputs;151                };152                prefixAttrs =153                  prefix: attrs:154                  mapAttrs' (name: value: {155                    name = "${prefix}${name}";156                    value = value.overrideAttrs (prev: {157                      pname = "${prefix}${prev.pname}";158                    });159                  }) attrs;160              in161              # fleet-install-secrets is installed to remote systems, thus needs to work162              # with rust in nixpkgs.163              (prefixAttrs "nixpkgs-" {164                inherit (packages) fleet-install-secrets;165              })166              // {167                formatting = treefmt.check self;168              };169            # TODO: It should be possible to move lib.mkIf to default attribute, instead of disabling the whole170            # devShells block, yet nix flake check fails here, due to no default shell found. It is nix or flake-parts bug?171            shelly.shells.default = lib.mkIf deployerSystem {172              factory = craneLib.devShell;173              packages = with pkgs; [174                rust175176                pkg-config177                openssl178                rustPlatform.bindgenHook179                inputs'.nix.packages.nix-expr-c180                inputs'.nix.packages.nix-flake-c181                inputs'.nix.packages.nix-fetchers-c182                inputs'.nix.packages.nix-store-c183184                (rage.overrideAttrs { cargoFeatures = [ "plugin" ]; })185              ];186              environment.PROTOC = "${pkgs.protobuf}/bin/protoc";187            };188            formatter = treefmt.wrapper;189          };190      };191}
after · flake.nix
1{2  description = "NixOS cluster configuration management";34  inputs = {5    nixpkgs.url = "github:nixos/nixpkgs/release-25.05";6    rust-overlay = {7      url = "github:oxalica/rust-overlay";8      inputs.nixpkgs.follows = "nixpkgs";9    };10    flake-parts = {11      url = "github:hercules-ci/flake-parts";12      inputs.nixpkgs-lib.follows = "nixpkgs";13    };14    crane.url = "github:ipetkov/crane";15    shelly.url = "github:CertainLach/shelly";16    fleet-tf = {17      url = "github:CertainLach/fleet-tf";18      inputs.nixpkgs.follows = "nixpkgs";19      inputs.shelly.follows = "shelly";20      inputs.flake-parts.follows = "flake-parts";21    };22    treefmt-nix = {23      url = "github:numtide/treefmt-nix";24      inputs.nixpkgs.follows = "nixpkgs";25    };26    # DeterminateSystem's nix fork is controversial, but I don't mind it,27    # and it has lazy-trees support which is useful for fleet.28    nix = {29      url = "github:deltarocks/nix/fleet";30      inputs.nixpkgs.follows = "nixpkgs";31      inputs.flake-parts.follows = "flake-parts";32    };33  };34  outputs =35    inputs:36    inputs.flake-parts.lib.mkFlake37      {38        inherit inputs;39      }40      {41        imports = [ inputs.shelly.flakeModule ];42        flake = rec {43          lib =44            (import ./lib {45              inherit (inputs.nixpkgs) lib;46            })47            // {48              fleetConfiguration = throw "function-based interface is deprecated, use flake-parts syntax instead";49            };50          flakeModules.default = import ./lib/flakePart.nix {51            inherit (inputs) crane;52          };53          flakeModule = flakeModules.default;5455          flakeModules.fleet-tf = ./modules/extras/tf.nix;5657          # Used to test nix-eval bindings58          testData = {59            testObj = {60              v = "Hello";61            };62            testString = "hello";63            testPrimop = op: "PREFIX_" + (op "body" "_SUFFIX");64          };6566          # To be used with https://github.com/NixOS/nix/pull/889267          schemas =68            let69              inherit (inputs.nixpkgs.lib) mapAttrs;70            in71            {72              fleetConfigurations = {73                version = 1;74                doc = ''75                  The `fleetConfigurations` flake output defines fleet cluster configurations.76                '';77                inventory = output: {78                  children = mapAttrs (configName: cluster: {79                    what = "fleet cluster configuration";8081                    children = mapAttrs (hostName: host: {82                      what = "host [${host.system}]";83                    }) cluster.config.hosts;84                    # It is possible to implement this inventory right now, but I want to85                    # get rid of `fleet.nix` file in the future.86                    # children.secrets = { };87                  }) output;88                };89              };90            };91        };92        # Supported and tested list of deployment targets.93        systems = [94          "x86_64-linux"95          "aarch64-linux"96          "armv7l-linux"97          "armv6l-linux"98        ];99        perSystem =100          {101            config,102            system,103            pkgs,104            self,105            inputs',106            ...107          }:108          let109            inherit (lib.attrsets) mapAttrs';110            inherit (lib.lists) elem;111            # Can also be built for darwin, through it is not usual to deploy nixos systems from macos machines.112            # I have no hardware for such testing, thus only adding machines I actually have and use.113            #114            # It is not possible to deploy any host from armv6/armv7 hardware, and I don't think it even makes sense.115            deployerSystems = [116              "aarch64-linux"117              "x86_64-linux"118            ];119            deployerSystem = elem system deployerSystems;120            lib = pkgs.lib;121            rust = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;122            craneLib = (inputs.crane.mkLib pkgs).overrideToolchain rust;123            treefmt = (inputs.treefmt-nix.lib.evalModule pkgs ./treefmt.nix).config.build;124          in125          {126            _module.args.pkgs = import inputs.nixpkgs {127              inherit system;128              overlays = [129                (inputs.rust-overlay.overlays.default)130                (final: prev: {131                  boehmgc = prev.boehmgc.overrideAttrs (prevAttrs: {132                    configureFlags = prevAttrs.configureFlags ++ [133                      "--enable-gc-assertions"134                    ];135                  });136                })137              ];138            };139            # Reference fleet package should be built with nightly rust, specified in rust-toolchain.toml.140            packages = lib.mkIf deployerSystem (141              let142                packages = pkgs.callPackages ./pkgs {143                  inherit craneLib inputs';144                };145              in146              packages // { default = packages.fleet; }147            );148            # fleet-install-secrets will not be built normally, because they are not ran directly by user most of the time.149            # checks there build packages for default nixpkgs rustPlatform packages.150            checks =151              let152                nixpkgsCraneLib = inputs.crane.mkLib pkgs;153                packages = pkgs.callPackages ./pkgs {154                  craneLib = nixpkgsCraneLib;155                  inherit inputs;156                };157                prefixAttrs =158                  prefix: attrs:159                  mapAttrs' (name: value: {160                    name = "${prefix}${name}";161                    value = value.overrideAttrs (prev: {162                      pname = "${prefix}${prev.pname}";163                    });164                  }) attrs;165              in166              # fleet-install-secrets is installed to remote systems, thus needs to work167              # with rust in nixpkgs.168              (prefixAttrs "nixpkgs-" {169                inherit (packages) fleet-install-secrets;170              })171              // {172                formatting = treefmt.check self;173              };174            # TODO: It should be possible to move lib.mkIf to default attribute, instead of disabling the whole175            # devShells block, yet nix flake check fails here, due to no default shell found. It is nix or flake-parts bug?176            shelly.shells.default = lib.mkIf deployerSystem {177              factory = craneLib.devShell;178              packages = with pkgs; [179                rust180181                pkg-config182                openssl183                rustPlatform.bindgenHook184                inputs'.nix.packages.nix-expr-c185                inputs'.nix.packages.nix-flake-c186                inputs'.nix.packages.nix-fetchers-c187                inputs'.nix.packages.nix-store-c188189                (rage.overrideAttrs { cargoFeatures = [ "plugin" ]; })190              ];191              environment.PROTOC = "${pkgs.protobuf}/bin/protoc";192            };193            formatter = treefmt.wrapper;194          };195      };196}