Write results into sqlite file

This commit is contained in:
clerie 2025-02-01 02:10:06 +01:00
parent 715db25581
commit f9dafecab7
5 changed files with 1744 additions and 21 deletions

1
.gitignore vendored

@ -1 +1,2 @@
/target
flake-tracker.db

1678
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -8,3 +8,5 @@ anyhow = "1.0.95"
clap = { version = "4.5.23", features = ["derive"] }
serde = { version = "1.0.217", features = ["derive"] }
serde_json = "1.0.138"
sqlx = { version = "0.8.3", features = ["runtime-tokio", "sqlite"] }
tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread"] }

22
schema.sql Normal file

@ -0,0 +1,22 @@
CREATE TABLE tracked_flakes (
uri TEXT PRIMARY KEY NOT NULL
);
CREATE TABLE flake_revisions (
revision_uri TEXT PRIMARY KEY NOT NULL,
uri TEXT,
nix_store_path TEXT,
revision TEXT,
nar_hash TEXT,
last_modified INT
);
CREATE TABLE flake_revisions_inputs (
flake_revision_uri TEXT NOT NULL,
input_name TEXT NOT NULL,
revision_uri TEXT,
uri TEXT,
nar_hash TEXT,
last_modified INT,
PRIMARY KEY (flake_revision_uri, input_name)
);

@ -9,6 +9,9 @@ use clap::{
use serde::{
Deserialize,
};
use sqlx::{
sqlite::SqlitePoolOptions,
};
use std::collections::HashMap;
use std::process::Command;
@ -23,7 +26,7 @@ struct FlakeMetadata {
revision: String,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
struct FlakeSource {
owner: Option<String>,
repo: Option<String>,
@ -102,7 +105,7 @@ impl FlakeUri for FlakeSource {
}
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
struct FlakeLockedInfo {
lastModified: i64,
narHash: String,
@ -140,7 +143,7 @@ struct FlakeLocks {
version: u64,
}
#[derive(Deserialize, Debug)]
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
enum FlakeLocksNodeInputs {
String(String),
@ -160,9 +163,12 @@ struct Cli {
flake_uri: String,
}
fn main() -> Result<()> {
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
let db = SqlitePoolOptions::new().connect("sqlite://flake-tracker.db").await?;
let flake_metadata_raw = Command::new("nix")
.arg("flake")
.arg("metadata")
@ -174,14 +180,48 @@ fn main() -> Result<()> {
let flake_metadata: FlakeMetadata = serde_json::from_slice(&flake_metadata_raw.stdout)
.context("Failed to parse flake metadata")?;
println!("{}", flake_metadata.original.flake_uri()?);
sqlx::query("INSERT INTO flake_revisions (revision_uri, uri, nix_store_path, revision, nar_hash, last_modified)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(revision_uri) DO UPDATE SET
uri=excluded.uri,
nix_store_path=excluded.nix_store_path,
revision=excluded.revision,
nar_hash=excluded.nar_hash,
last_modified=excluded.last_modified
")
.bind(&flake_metadata.locked.flake_uri()?)
.bind(&flake_metadata.resolved.flake_uri()?)
.bind(&flake_metadata.path)
.bind(&flake_metadata.revision)
.bind(&flake_metadata.locked.narHash)
.bind(&flake_metadata.locked.lastModified)
.execute(&db).await?;
for (input_name, input_data) in &flake_metadata.locks.nodes {
if let Some(original_flake_source) = &input_data.original {
println!("{}", original_flake_source.flake_uri()?);
}
if let Some(locked_flake_source) = &input_data.locked {
println!("{}", locked_flake_source.flake_uri()?);
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")?;
sqlx::query("INSERT INTO flake_revisions_inputs (flake_revision_uri, input_name, revision_uri, uri, nar_hash, last_modified)
VALUES (?, ?, ?, ?, ?, ?)
ON CONFLICT(flake_revision_uri, input_name) DO UPDATE SET
revision_uri=excluded.revision_uri,
uri=excluded.uri,
nar_hash=excluded.nar_hash,
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?;
}
}