mirror of
https://github.com/RGBCube/dix
synced 2025-07-28 12:17:45 +00:00
feat: Connection newtype
This commit is contained in:
parent
db09147da6
commit
574142c4a0
2 changed files with 125 additions and 116 deletions
20
src/lib.rs
20
src/lib.rs
|
@ -1,4 +1,24 @@
|
||||||
|
use std::path::{
|
||||||
|
Path,
|
||||||
|
PathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
|
use derive_more::Deref;
|
||||||
|
use ref_cast::RefCast;
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod print;
|
pub mod print;
|
||||||
|
|
||||||
pub mod store;
|
pub mod store;
|
||||||
|
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
|
||||||
|
#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct DerivationId(i64);
|
||||||
|
|
||||||
|
#[derive(RefCast, Deref, Debug, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct StorePath(Path);
|
||||||
|
|
||||||
|
#[derive(Deref, Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct StorePathBuf(PathBuf);
|
||||||
|
|
221
src/store.rs
221
src/store.rs
|
@ -1,23 +1,21 @@
|
||||||
use std::{
|
use std::result;
|
||||||
path::{
|
|
||||||
Path,
|
|
||||||
PathBuf,
|
|
||||||
},
|
|
||||||
result,
|
|
||||||
};
|
|
||||||
|
|
||||||
use anyhow::{
|
use anyhow::{
|
||||||
Context as _,
|
Context as _,
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
use derive_more::Deref;
|
use derive_more::Deref;
|
||||||
use ref_cast::RefCast;
|
|
||||||
use rusqlite::Connection;
|
|
||||||
use rustc_hash::{
|
use rustc_hash::{
|
||||||
FxBuildHasher,
|
FxBuildHasher,
|
||||||
FxHashMap,
|
FxHashMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
DerivationId,
|
||||||
|
StorePath,
|
||||||
|
StorePathBuf,
|
||||||
|
};
|
||||||
|
|
||||||
macro_rules! path_to_str {
|
macro_rules! path_to_str {
|
||||||
($path:ident) => {
|
($path:ident) => {
|
||||||
let $path = $path.canonicalize().with_context(|| {
|
let $path = $path.canonicalize().with_context(|| {
|
||||||
|
@ -36,50 +34,43 @@ macro_rules! path_to_str {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deref, Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Deref)]
|
||||||
pub struct DerivationId(i64);
|
pub struct Connection(rusqlite::Connection);
|
||||||
|
|
||||||
#[expect(clippy::module_name_repetitions)]
|
|
||||||
#[derive(RefCast, Deref, Debug, PartialEq, Eq)]
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct StorePath(Path);
|
|
||||||
|
|
||||||
#[expect(clippy::module_name_repetitions)]
|
|
||||||
#[derive(Deref, Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct StorePathBuf(PathBuf);
|
|
||||||
|
|
||||||
/// Connects to the Nix database.
|
/// Connects to the Nix database.
|
||||||
pub fn connect() -> Result<Connection> {
|
pub fn connect() -> Result<Connection> {
|
||||||
const DATABASE_PATH: &str = "/nix/var/nix/db/db.sqlite";
|
const DATABASE_PATH: &str = "/nix/var/nix/db/db.sqlite";
|
||||||
|
|
||||||
Connection::open(DATABASE_PATH).with_context(|| {
|
let inner = rusqlite::Connection::open(DATABASE_PATH).with_context(|| {
|
||||||
format!("failed to connect to Nix database at {DATABASE_PATH}")
|
format!("failed to connect to Nix database at {DATABASE_PATH}")
|
||||||
})
|
})?;
|
||||||
|
|
||||||
|
Ok(Connection(inner))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gathers all derivations that the given store path depends on.
|
impl Connection {
|
||||||
pub fn query_depdendents(
|
/// Gathers all derivations that the given store path depends on.
|
||||||
connection: &mut Connection,
|
pub fn query_depdendents(
|
||||||
path: &StorePath,
|
&mut self,
|
||||||
) -> Result<Vec<(DerivationId, StorePathBuf)>> {
|
path: &StorePath,
|
||||||
const QUERY: &str = "
|
) -> Result<Vec<(DerivationId, StorePathBuf)>> {
|
||||||
WITH RECURSIVE
|
const QUERY: &str = "
|
||||||
graph(p) AS (
|
WITH RECURSIVE
|
||||||
SELECT id
|
graph(p) AS (
|
||||||
FROM ValidPaths
|
SELECT id
|
||||||
WHERE path = ?
|
FROM ValidPaths
|
||||||
UNION
|
WHERE path = ?
|
||||||
SELECT reference FROM Refs
|
UNION
|
||||||
JOIN graph ON referrer = p
|
SELECT reference FROM Refs
|
||||||
)
|
JOIN graph ON referrer = p
|
||||||
SELECT id, path from graph
|
)
|
||||||
JOIN ValidPaths ON id = p;
|
SELECT id, path from graph
|
||||||
";
|
JOIN ValidPaths ON id = p;
|
||||||
|
";
|
||||||
|
|
||||||
path_to_str!(path);
|
path_to_str!(path);
|
||||||
|
|
||||||
let packages: result::Result<Vec<(DerivationId, StorePathBuf)>, _> =
|
let packages: result::Result<Vec<(DerivationId, StorePathBuf)>, _> = self
|
||||||
connection
|
|
||||||
.prepare_cached(QUERY)?
|
.prepare_cached(QUERY)?
|
||||||
.query_map([path], |row| {
|
.query_map([path], |row| {
|
||||||
Ok((
|
Ok((
|
||||||
|
@ -89,79 +80,77 @@ pub fn query_depdendents(
|
||||||
})?
|
})?
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(packages?)
|
Ok(packages?)
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the total closure size of the given store path by summing up the nar
|
|
||||||
/// size of all depdendent derivations.
|
|
||||||
pub fn query_closure_size(
|
|
||||||
connection: &mut Connection,
|
|
||||||
path: &StorePath,
|
|
||||||
) -> Result<usize> {
|
|
||||||
const QUERY: &str = "
|
|
||||||
WITH RECURSIVE
|
|
||||||
graph(p) AS (
|
|
||||||
SELECT id
|
|
||||||
FROM ValidPaths
|
|
||||||
WHERE path = ?
|
|
||||||
UNION
|
|
||||||
SELECT reference FROM Refs
|
|
||||||
JOIN graph ON referrer = p
|
|
||||||
)
|
|
||||||
SELECT SUM(narSize) as sum from graph
|
|
||||||
JOIN ValidPaths ON p = id;
|
|
||||||
";
|
|
||||||
|
|
||||||
path_to_str!(path);
|
|
||||||
|
|
||||||
let closure_size = connection
|
|
||||||
.prepare_cached(QUERY)?
|
|
||||||
.query_row([path], |row| row.get(0))?;
|
|
||||||
|
|
||||||
Ok(closure_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gathers the complete dependency graph of of the store path as an adjacency
|
|
||||||
/// list.
|
|
||||||
///
|
|
||||||
/// We might want to collect the paths in the graph directly as
|
|
||||||
/// well in the future, depending on how much we use them
|
|
||||||
/// in the operations on the graph.
|
|
||||||
pub fn query_dependency_graph(
|
|
||||||
connection: &mut Connection,
|
|
||||||
path: &StorePath,
|
|
||||||
) -> Result<FxHashMap<DerivationId, Vec<DerivationId>>> {
|
|
||||||
const QUERY: &str = "
|
|
||||||
WITH RECURSIVE
|
|
||||||
graph(p, c) AS (
|
|
||||||
SELECT id as par, reference as chd
|
|
||||||
FROM ValidPaths
|
|
||||||
JOIN Refs ON referrer = id
|
|
||||||
WHERE path = ?
|
|
||||||
UNION
|
|
||||||
SELECT referrer as par, reference as chd FROM Refs
|
|
||||||
JOIN graph ON referrer = c
|
|
||||||
)
|
|
||||||
SELECT p, c from graph;
|
|
||||||
";
|
|
||||||
|
|
||||||
path_to_str!(path);
|
|
||||||
|
|
||||||
let mut adj =
|
|
||||||
FxHashMap::<DerivationId, Vec<DerivationId>>::with_hasher(FxBuildHasher);
|
|
||||||
|
|
||||||
let mut statement = connection.prepare_cached(QUERY)?;
|
|
||||||
|
|
||||||
let edges = statement.query_map([path], |row| {
|
|
||||||
Ok((DerivationId(row.get(0)?), DerivationId(row.get(1)?)))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
for row in edges {
|
|
||||||
let (from, to) = row?;
|
|
||||||
|
|
||||||
adj.entry(from).or_default().push(to);
|
|
||||||
adj.entry(to).or_default();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(adj)
|
/// Gets the total closure size of the given store path by summing up the nar
|
||||||
|
/// size of all depdendent derivations.
|
||||||
|
pub fn query_closure_size(&mut self, path: &StorePath) -> Result<usize> {
|
||||||
|
const QUERY: &str = "
|
||||||
|
WITH RECURSIVE
|
||||||
|
graph(p) AS (
|
||||||
|
SELECT id
|
||||||
|
FROM ValidPaths
|
||||||
|
WHERE path = ?
|
||||||
|
UNION
|
||||||
|
SELECT reference FROM Refs
|
||||||
|
JOIN graph ON referrer = p
|
||||||
|
)
|
||||||
|
SELECT SUM(narSize) as sum from graph
|
||||||
|
JOIN ValidPaths ON p = id;
|
||||||
|
";
|
||||||
|
|
||||||
|
path_to_str!(path);
|
||||||
|
|
||||||
|
let closure_size = self
|
||||||
|
.prepare_cached(QUERY)?
|
||||||
|
.query_row([path], |row| row.get(0))?;
|
||||||
|
|
||||||
|
Ok(closure_size)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gathers the complete dependency graph of of the store path as an adjacency
|
||||||
|
/// list.
|
||||||
|
///
|
||||||
|
/// We might want to collect the paths in the graph directly as
|
||||||
|
/// well in the future, depending on how much we use them
|
||||||
|
/// in the operations on the graph.
|
||||||
|
pub fn query_dependency_graph(
|
||||||
|
&mut self,
|
||||||
|
path: &StorePath,
|
||||||
|
) -> Result<FxHashMap<DerivationId, Vec<DerivationId>>> {
|
||||||
|
const QUERY: &str = "
|
||||||
|
WITH RECURSIVE
|
||||||
|
graph(p, c) AS (
|
||||||
|
SELECT id as par, reference as chd
|
||||||
|
FROM ValidPaths
|
||||||
|
JOIN Refs ON referrer = id
|
||||||
|
WHERE path = ?
|
||||||
|
UNION
|
||||||
|
SELECT referrer as par, reference as chd FROM Refs
|
||||||
|
JOIN graph ON referrer = c
|
||||||
|
)
|
||||||
|
SELECT p, c from graph;
|
||||||
|
";
|
||||||
|
|
||||||
|
path_to_str!(path);
|
||||||
|
|
||||||
|
let mut adj =
|
||||||
|
FxHashMap::<DerivationId, Vec<DerivationId>>::with_hasher(FxBuildHasher);
|
||||||
|
|
||||||
|
let mut statement = self.prepare_cached(QUERY)?;
|
||||||
|
|
||||||
|
let edges = statement.query_map([path], |row| {
|
||||||
|
Ok((DerivationId(row.get(0)?), DerivationId(row.get(1)?)))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
for row in edges {
|
||||||
|
let (from, to) = row?;
|
||||||
|
|
||||||
|
adj.entry(from).or_default().push(to);
|
||||||
|
adj.entry(to).or_default();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(adj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue