difftreelog
feat experimental opentofu integration
in: trunk
9 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1438,6 +1438,7 @@
"itertools",
"nixlike",
"r2d2",
+ "regex",
"serde",
"serde_json",
"thiserror",
@@ -1866,9 +1867,9 @@
[[package]]
name = "regex"
-version = "1.10.4"
+version = "1.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
dependencies = [
"aho-corasick",
"memchr",
cmds/fleet/src/cmds/mod.rsdiffbeforeafterboth--- a/cmds/fleet/src/cmds/mod.rs
+++ b/cmds/fleet/src/cmds/mod.rs
@@ -2,3 +2,4 @@
pub mod complete;
pub mod info;
pub mod secrets;
+pub mod tf;
cmds/fleet/src/cmds/tf.rsdiffbeforeafterboth--- /dev/null
+++ b/cmds/fleet/src/cmds/tf.rs
@@ -0,0 +1,23 @@
+use anyhow::Result;
+use clap::Parser;
+use nix_eval::nix_go_json;
+use serde_json::Value;
+use tokio::fs::write;
+use tracing::info;
+
+use crate::host::Config;
+
+#[derive(Parser)]
+pub struct Tf;
+impl Tf {
+ pub async fn run(&self, config: &Config) -> Result<()> {
+ let system = &config.local_system;
+ let config = &config.config_field;
+ let data: Value = nix_go_json!(config.tf({ system }).config);
+ let str = serde_json::to_string_pretty(&data)?;
+
+ write("fleet.tf.json", str.as_bytes()).await?;
+
+ Ok(())
+ }
+}
cmds/fleet/src/main.rsdiffbeforeafterboth--- a/cmds/fleet/src/main.rs
+++ b/cmds/fleet/src/main.rs
@@ -19,6 +19,7 @@
complete::Complete,
info::Info,
secrets::Secret,
+ tf::Tf,
};
use futures::{future::LocalBoxFuture, stream::FuturesUnordered, TryStreamExt};
use host::{Config, FleetOpts};
@@ -86,6 +87,8 @@
/// Command completions
#[clap(hide(true))]
Complete(Complete),
+ /// Compile and evaluate terranix configuration
+ Tf(Tf),
}
#[derive(Parser)]
@@ -104,6 +107,7 @@
Opts::Secret(s) => s.run(config).await?,
Opts::Info(i) => i.run(config).await?,
Opts::Prefetch(p) => p.run(config).await?,
+ Opts::Tf(t) => t.run(config).await?,
// TODO: actually parse commands before starting the async runtime
Opts::Complete(c) => {
tokio::task::spawn_blocking(move || c.run(RootOpts::command())).await?
crates/nix-eval/Cargo.tomldiffbeforeafterboth--- a/crates/nix-eval/Cargo.toml
+++ b/crates/nix-eval/Cargo.toml
@@ -11,6 +11,7 @@
itertools = "0.13.0"
nixlike.workspace = true
r2d2 = "0.8.10"
+regex = "1.10.6"
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror = "1.0.61"
crates/nix-eval/src/session.rsdiffbeforeafterboth--- a/crates/nix-eval/src/session.rs
+++ b/crates/nix-eval/src/session.rs
@@ -12,7 +12,7 @@
sync::{mpsc, oneshot, Mutex},
};
use tokio_util::codec::{FramedRead, LinesCodec};
-use tracing::{debug, error, warn, Level};
+use tracing::{debug, error, info, warn, Level};
#[derive(Error, Debug)]
pub enum Error {
@@ -327,8 +327,16 @@
n.parse::<u64>().map_err(Error::Int)
}
async fn execute_expression_string(&mut self, expr: impl AsRef<[u8]>) -> Result<String> {
+ // builtins.toJSON escapes some thing in incorrect way, e.g escaped "$" in "\${" is being outputed as "\$",
+ // while this escape should be removed as it is intended for nix itself, not for json output.
+ //
+ // This regex only allows \$ in the beginning of the string, it is easier to implement correctly.
+ // TODO: Add peg parser for nix-produced JSON?..
+ let regex = regex::Regex::new(r#"(?<prefix>[: {,\[]\\")\\\$"#).expect("fixup json");
+
let num = self.string_wrapping.clone();
let n = self.execute_expression_wrapping(expr, &num).await?;
+ let n = regex.replace_all(&n, "$prefix$$");
let str: String = serde_json::from_str(&n)?;
Ok(str)
}
@@ -339,6 +347,7 @@
let mut fexpr = b"builtins.toJSON (".to_vec();
fexpr.extend_from_slice(expr.as_ref());
fexpr.push(b')');
+ let s = String::from_utf8_lossy(expr.as_ref());
let v = self.execute_expression_string(fexpr).await?;
Ok(serde_json::from_str(&v)?)
}
flake.nixdiffbeforeafterboth--- a/flake.nix
+++ b/flake.nix
@@ -37,6 +37,8 @@
};
flakeModule = flakeModules.default;
+ fleetModules.tf = ./modules/extras/tf.nix;
+
# To be used with https://github.com/NixOS/nix/pull/8892
schemas = let
inherit (inputs.nixpkgs.lib) mapAttrs;
lib/flakePart.nixdiffbeforeafterboth--- a/lib/flakePart.nix
+++ b/lib/flakePart.nix
@@ -2,6 +2,7 @@
fleetLib,
lib,
config,
+ inputs ? {},
...
}: let
inherit (lib.options) mkOption;
@@ -58,8 +59,11 @@
};
}
];
- specialArgs.fleetLib = import ../lib {
- inherit (bootstrapNixpkgs) lib;
+ specialArgs = {
+ fleetLib = import ../lib {
+ inherit (bootstrapNixpkgs) lib;
+ };
+ inputs = inputs;
};
};
in
modules/extras/tf.nixdiffbeforeafterboth1{2 config,3 lib,4 inputs,5 ...6}: let7 inherit (lib) mkOption;8 inherit (lib.types) deferredModule;9in {10 options.tf = mkOption {11 type = deferredModule;12 apply = module: system:13 inputs.terranix.lib.terranixConfigurationAst {14 inherit system;15 pkgs = config.nixpkgs.buildUsing.legacyPackages.${system};16 modules = [module];17 };18 };19 config.tf.output.fleet = {20 value = {21 managed = true;22 };23 # Just to avoid printing this attribute on every apply.24 sensitive = true;25 };26}