2025-02-01 00:55:10 +01:00
|
|
|
use anyhow::{
|
|
|
|
Context,
|
|
|
|
Result,
|
|
|
|
};
|
2025-02-08 16:51:16 +01:00
|
|
|
use chrono::{
|
|
|
|
Utc,
|
|
|
|
};
|
2025-02-01 00:55:10 +01:00
|
|
|
use clap::{
|
|
|
|
Parser,
|
|
|
|
};
|
2025-02-09 21:17:13 +01:00
|
|
|
use flake_tracker::{
|
|
|
|
flake::{
|
|
|
|
FlakeLocksNodeInputs,
|
|
|
|
FlakeMetadata,
|
|
|
|
FlakeUri,
|
|
|
|
},
|
2025-02-01 00:55:10 +01:00
|
|
|
};
|
2025-02-01 02:10:06 +01:00
|
|
|
use sqlx::{
|
|
|
|
sqlite::SqlitePoolOptions,
|
|
|
|
};
|
2025-02-01 00:55:10 +01:00
|
|
|
use std::process::Command;
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
#[command(version, about, long_about = None)]
|
|
|
|
struct Cli {
|
|
|
|
flake_uri: String,
|
|
|
|
}
|
|
|
|
|
2025-02-01 02:10:06 +01:00
|
|
|
#[tokio::main]
|
|
|
|
async fn main() -> Result<()> {
|
2025-02-01 00:55:10 +01:00
|
|
|
let cli = Cli::parse();
|
|
|
|
|
2025-02-08 16:51:16 +01:00
|
|
|
let scan_time = Utc::now().timestamp();
|
|
|
|
|
2025-02-01 02:10:06 +01:00
|
|
|
let db = SqlitePoolOptions::new().connect("sqlite://flake-tracker.db").await?;
|
|
|
|
|
2025-02-01 00:55:10 +01:00
|
|
|
let flake_metadata_raw = Command::new("nix")
|
|
|
|
.arg("flake")
|
|
|
|
.arg("metadata")
|
|
|
|
.arg("--json")
|
|
|
|
.arg(cli.flake_uri)
|
|
|
|
.output()
|
|
|
|
.context("Failed to fetch flake metadata")?;
|
|
|
|
|
|
|
|
let flake_metadata: FlakeMetadata = serde_json::from_slice(&flake_metadata_raw.stdout)
|
|
|
|
.context("Failed to parse flake metadata")?;
|
|
|
|
|
2025-02-08 16:51:16 +01:00
|
|
|
sqlx::query("INSERT INTO revisions (revision_uri, flake_uri, nix_store_path, nar_hash, last_modified, tracker_last_scanned)
|
2025-02-01 02:10:06 +01:00
|
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
|
|
ON CONFLICT(revision_uri) DO UPDATE SET
|
2025-02-08 16:51:16 +01:00
|
|
|
flake_uri=excluded.flake_uri,
|
2025-02-01 02:10:06 +01:00
|
|
|
nix_store_path=excluded.nix_store_path,
|
|
|
|
nar_hash=excluded.nar_hash,
|
2025-02-08 16:51:16 +01:00
|
|
|
last_modified=excluded.last_modified,
|
|
|
|
tracker_last_scanned=excluded.tracker_last_scanned
|
2025-02-01 02:10:06 +01:00
|
|
|
")
|
|
|
|
.bind(&flake_metadata.locked.flake_uri()?)
|
|
|
|
.bind(&flake_metadata.resolved.flake_uri()?)
|
|
|
|
.bind(&flake_metadata.path)
|
|
|
|
.bind(&flake_metadata.locked.narHash)
|
|
|
|
.bind(&flake_metadata.locked.lastModified)
|
2025-02-08 16:51:16 +01:00
|
|
|
.bind(&scan_time)
|
2025-02-01 02:10:06 +01:00
|
|
|
.execute(&db).await?;
|
|
|
|
|
|
|
|
let locks_root_name = &flake_metadata.locks.root;
|
|
|
|
let locks_root_node = flake_metadata.locks.nodes.get(locks_root_name)
|
|
|
|
.context("Failed to get locks root node")?;
|
|
|
|
|
|
|
|
for (input_name, locks_input_name) in locks_root_node.inputs.clone().context("No inputs found for flake")? {
|
|
|
|
|
|
|
|
if let FlakeLocksNodeInputs::String(locks_input_name) = locks_input_name {
|
|
|
|
let locks_input_node = flake_metadata.locks.nodes.get(&locks_input_name)
|
|
|
|
.context("Failed to find lock of input")?;
|
|
|
|
|
2025-02-08 16:51:16 +01:00
|
|
|
sqlx::query("INSERT INTO inputs (revision_uri, input_name, locked_revision_uri, locked_flake_uri, locked_nar_hash, last_modified)
|
2025-02-01 02:10:06 +01:00
|
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
2025-02-08 16:51:16 +01:00
|
|
|
ON CONFLICT(revision_uri, input_name) DO UPDATE SET
|
|
|
|
locked_revision_uri=excluded.locked_revision_uri,
|
|
|
|
locked_flake_uri=excluded.locked_flake_uri,
|
|
|
|
locked_nar_hash=excluded.locked_nar_hash,
|
2025-02-01 02:10:06 +01:00
|
|
|
last_modified=excluded.last_modified
|
|
|
|
")
|
|
|
|
.bind(flake_metadata.locked.flake_uri()?)
|
|
|
|
.bind(input_name)
|
|
|
|
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.flake_uri()?)
|
|
|
|
.bind(locks_input_node.original.clone().context("Unexpected missing lock")?.flake_uri()?)
|
|
|
|
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.narHash)
|
|
|
|
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.lastModified)
|
|
|
|
.execute(&db).await?;
|
2025-02-08 16:51:16 +01:00
|
|
|
|
|
|
|
sqlx::query("INSERT INTO revisions (revision_uri, flake_uri)
|
|
|
|
VALUES (?, ?)
|
|
|
|
ON CONFLICT(revision_uri) DO NOTHING
|
|
|
|
")
|
|
|
|
.bind(locks_input_node.locked.clone().context("Unexpected missing lock")?.flake_uri()?)
|
|
|
|
.bind(locks_input_node.original.clone().context("Unexpected missing lock")?.flake_uri()?)
|
|
|
|
.execute(&db).await?;
|
2025-02-01 00:55:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|