Fetch flake outputs and display them
This commit is contained in:
54
src/scan.rs
54
src/scan.rs
@@ -13,12 +13,29 @@ use crate::{
|
||||
},
|
||||
storage::{
|
||||
FlakeRow,
|
||||
OutputAttributeRow,
|
||||
RevisionRow,
|
||||
Storage,
|
||||
},
|
||||
};
|
||||
use serde::{
|
||||
Deserialize,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct OutputAttribute {
|
||||
pub derivation_path: String,
|
||||
pub name: String,
|
||||
pub outputs: HashMap<String, BuildOutput>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct BuildOutput {
|
||||
pub store_path: String,
|
||||
}
|
||||
|
||||
pub async fn scan_flake(storage: Storage, flake_uri: &str) -> Result<()> {
|
||||
let scan_time = Utc::now().timestamp();
|
||||
|
||||
@@ -30,6 +47,20 @@ pub async fn scan_flake(storage: Storage, flake_uri: &str) -> Result<()> {
|
||||
storage.set_revision(revision_row)
|
||||
.await?;
|
||||
|
||||
let flake_outputs = fetch_outputs(flake_uri)
|
||||
.await?;
|
||||
|
||||
for (output_attribute_name, derivation_info) in &flake_outputs {
|
||||
let output_attribute_row = OutputAttributeRow {
|
||||
revision_uri: flake_metadata.locked.flake_uri()?.clone(),
|
||||
output_attribute_name: output_attribute_name.clone(),
|
||||
derivation_path: derivation_info.derivation_path.clone(),
|
||||
};
|
||||
|
||||
storage.set_output_attribute(output_attribute_row)
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -52,9 +83,28 @@ pub fn get_revision_from_metadata(flake_metadata: &FlakeMetadata) -> Result<Revi
|
||||
let revision_row = RevisionRow {
|
||||
revision_uri: flake_metadata.locked.flake_uri()?.clone(),
|
||||
flake_uri: flake_metadata.resolved.flake_uri()?.clone(),
|
||||
store_path: Some(flake_metadata.path.clone()),
|
||||
last_modified: Some(flake_metadata.locked.last_modified.clone()),
|
||||
store_path: flake_metadata.path.clone(),
|
||||
last_modified: flake_metadata.locked.last_modified.clone(),
|
||||
};
|
||||
|
||||
Ok(revision_row)
|
||||
}
|
||||
|
||||
pub async fn fetch_outputs(flake_uri: &str) -> Result<HashMap<String, OutputAttribute>> {
|
||||
let figure_out_flake_outputs = std::include_str!("../figure-out-flake-outputs.nix");
|
||||
|
||||
let flake_outputs_raw = Command::new("nix")
|
||||
.arg("eval")
|
||||
.arg("--json")
|
||||
.arg(format!("{}#hydraJobs", flake_uri))
|
||||
.arg("--apply")
|
||||
.arg(figure_out_flake_outputs)
|
||||
.output()
|
||||
.context("Failed to fetch flake outputs")?;
|
||||
|
||||
println!("{}", str::from_utf8(&flake_outputs_raw.stdout)?);
|
||||
let flake_outputs: HashMap<String, OutputAttribute> = serde_json::from_slice(&flake_outputs_raw.stdout)
|
||||
.context("Failed to parse flake outputs")?;
|
||||
|
||||
Ok(flake_outputs)
|
||||
}
|
||||
|
@@ -97,14 +97,44 @@ impl Storage {
|
||||
.await
|
||||
.context("Failed to fetch data from database")
|
||||
}
|
||||
|
||||
pub async fn set_output_attribute(&self, output_attribute_row: OutputAttributeRow) -> Result<SqliteQueryResult> {
|
||||
sqlx::query("INSERT INTO output_attributes (revision_uri, output_attribute_name, derivation_path)
|
||||
VALUES (?, ?, ?)
|
||||
ON CONFLICT(revision_uri, output_attribute_name) DO UPDATE SET
|
||||
derivation_path=excluded.derivation_path
|
||||
")
|
||||
.bind(&output_attribute_row.revision_uri)
|
||||
.bind(&output_attribute_row.output_attribute_name)
|
||||
.bind(&output_attribute_row.derivation_path)
|
||||
.execute(&self.db)
|
||||
.await
|
||||
.context("Failed to execute database query")
|
||||
}
|
||||
|
||||
pub async fn output_attributes_for_revision(&self, revision_uri: &str) -> Result<Vec<OutputAttributeRow>> {
|
||||
sqlx::query_as("
|
||||
SELECT
|
||||
revision_uri,
|
||||
output_attribute_name,
|
||||
derivation_path
|
||||
FROM output_attributes
|
||||
WHERE revision_uri = ?
|
||||
ORDER BY output_attribute_name DESC
|
||||
")
|
||||
.bind(&revision_uri)
|
||||
.fetch_all(&self.db)
|
||||
.await
|
||||
.context("Failed to fetch data from database")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct RevisionRow {
|
||||
pub revision_uri: String,
|
||||
pub flake_uri: String,
|
||||
pub store_path: Option<String>,
|
||||
pub last_modified: Option<i64>,
|
||||
pub store_path: String,
|
||||
pub last_modified: i64,
|
||||
}
|
||||
|
||||
impl RevisionRow {
|
||||
@@ -117,10 +147,7 @@ impl RevisionRow {
|
||||
}
|
||||
|
||||
pub fn last_modified_time(&self) -> Option<DateTime<Utc>> {
|
||||
match &self.last_modified {
|
||||
Some(last_modified) => DateTime::from_timestamp(last_modified.clone(), 0),
|
||||
None => None,
|
||||
}
|
||||
DateTime::from_timestamp(self.last_modified.clone(), 0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,3 +162,33 @@ impl FlakeRow {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct OutputAttributeRow {
|
||||
pub revision_uri: String,
|
||||
pub output_attribute_name: String,
|
||||
pub derivation_path: String,
|
||||
}
|
||||
|
||||
impl OutputAttributeRow {
|
||||
pub fn revision_link(&self) -> String {
|
||||
format!("/revisions/{}", urlencode(&self.revision_uri))
|
||||
}
|
||||
|
||||
pub fn derivation_link(&self) -> String {
|
||||
format!("/derivations/{}", urlencode(&self.derivation_path))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(FromRow)]
|
||||
pub struct BuildOutputRow {
|
||||
pub derivation_path: String,
|
||||
pub build_output_name: String,
|
||||
pub store_path: String,
|
||||
}
|
||||
|
||||
impl BuildOutputRow {
|
||||
pub fn derivation_link(&self ) -> String {
|
||||
format!("/derivations/{}", urlencode(&self.derivation_path))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ use askama::{
|
||||
use crate::{
|
||||
storage::{
|
||||
FlakeRow,
|
||||
OutputAttributeRow,
|
||||
RevisionRow,
|
||||
},
|
||||
};
|
||||
@@ -26,4 +27,5 @@ pub struct FlakeTemplate {
|
||||
pub struct RevisionTemplate {
|
||||
pub revision_uri: String,
|
||||
pub revision: RevisionRow,
|
||||
pub output_attributes: Vec<OutputAttributeRow>,
|
||||
}
|
||||
|
@@ -118,5 +118,6 @@ async fn route_revision(
|
||||
Ok(render_template(&RevisionTemplate {
|
||||
revision_uri: revision_uri.clone(),
|
||||
revision: state.storage.revision(&revision_uri).await?,
|
||||
output_attributes: state.storage.output_attributes_for_revision(&revision_uri).await?,
|
||||
})?)
|
||||
}
|
||||
|
Reference in New Issue
Block a user