mirror of
https://github.com/RGBCube/dix
synced 2025-07-28 04:07:46 +00:00
remove bloated dependency sqlx, switch to libsqlite3-sys
sqlx is way to large for this utility and also async, which we currently do not use
This commit is contained in:
parent
55c969cfdf
commit
eee8c920a7
6 changed files with 203 additions and 2169 deletions
1998
Cargo.lock
generated
1998
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -10,5 +10,4 @@ yansi = "1.0.1"
|
|||
thiserror = "2.0.12"
|
||||
log = "0.4.20"
|
||||
env_logger = "0.11.3"
|
||||
sqlx = { version = "0.8.5", features = ["runtime-async-std", "sqlite"] }
|
||||
async-std = "1.13.1"
|
||||
rusqlite = { version = "0.35.0", features = ["bundled"] }
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[env]
|
||||
DATABASE_URL="sqlite:///nix/var/nix/db/db.sqlite"
|
134
src/error.rs
Normal file
134
src/error.rs
Normal file
|
@ -0,0 +1,134 @@
|
|||
use thiserror::Error;
|
||||
|
||||
/// Application errors with thiserror
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AppError {
|
||||
#[error("Command failed: {command} {args:?} - {message}")]
|
||||
CommandFailed {
|
||||
command: String,
|
||||
args: Vec<String>,
|
||||
message: String,
|
||||
},
|
||||
|
||||
#[error("Failed to decode command output from {context}: {source}")]
|
||||
CommandOutputError {
|
||||
source: std::str::Utf8Error,
|
||||
context: String,
|
||||
},
|
||||
|
||||
#[error("Failed to parse data in {context}: {message}")]
|
||||
ParseError {
|
||||
message: String,
|
||||
context: String,
|
||||
#[source]
|
||||
source: Option<Box<dyn std::error::Error + Send + Sync>>,
|
||||
},
|
||||
|
||||
#[error("Regex error in {context}: {source}")]
|
||||
RegexError {
|
||||
source: regex::Error,
|
||||
context: String,
|
||||
},
|
||||
|
||||
#[error("IO error in {context}: {source}")]
|
||||
IoError {
|
||||
source: std::io::Error,
|
||||
context: String,
|
||||
},
|
||||
|
||||
#[error("Database error: {source}")]
|
||||
DatabaseError { source: rusqlite::Error },
|
||||
|
||||
#[error("Nix store error: {message} for path: {store_path}")]
|
||||
NixStoreError { message: String, store_path: String },
|
||||
}
|
||||
|
||||
// Implement From traits to support the ? operator
|
||||
impl From<std::io::Error> for AppError {
|
||||
fn from(source: std::io::Error) -> Self {
|
||||
Self::IoError {
|
||||
source,
|
||||
context: "unknown context".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::str::Utf8Error> for AppError {
|
||||
fn from(source: std::str::Utf8Error) -> Self {
|
||||
Self::CommandOutputError {
|
||||
source,
|
||||
context: "command output".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<rusqlite::Error> for AppError {
|
||||
fn from(source: rusqlite::Error) -> Self {
|
||||
Self::DatabaseError { source }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<regex::Error> for AppError {
|
||||
fn from(source: regex::Error) -> Self {
|
||||
Self::RegexError {
|
||||
source,
|
||||
context: "regex operation".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
/// Create a command failure error with context
|
||||
pub fn command_failed<S: Into<String>>(command: S, args: &[&str], message: S) -> Self {
|
||||
Self::CommandFailed {
|
||||
command: command.into(),
|
||||
args: args.iter().map(|&s| s.to_string()).collect(),
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a parse error with context
|
||||
pub fn parse_error<S: Into<String>, C: Into<String>>(
|
||||
message: S,
|
||||
context: C,
|
||||
source: Option<Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> Self {
|
||||
Self::ParseError {
|
||||
message: message.into(),
|
||||
context: context.into(),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an IO error with context
|
||||
pub fn io_error<C: Into<String>>(source: std::io::Error, context: C) -> Self {
|
||||
Self::IoError {
|
||||
source,
|
||||
context: context.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a regex error with context
|
||||
pub fn regex_error<C: Into<String>>(source: regex::Error, context: C) -> Self {
|
||||
Self::RegexError {
|
||||
source,
|
||||
context: context.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a command output error with context
|
||||
pub fn command_output_error<C: Into<String>>(source: std::str::Utf8Error, context: C) -> Self {
|
||||
Self::CommandOutputError {
|
||||
source,
|
||||
context: context.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a Nix store error
|
||||
pub fn nix_store_error<M: Into<String>, P: Into<String>>(message: M, store_path: P) -> Self {
|
||||
Self::NixStoreError {
|
||||
message: message.into(),
|
||||
store_path: store_path.into(),
|
||||
}
|
||||
}
|
||||
}
|
128
src/main.rs
128
src/main.rs
|
@ -1,7 +1,6 @@
|
|||
mod print;
|
||||
use clap::Parser;
|
||||
use core::str;
|
||||
use env_logger;
|
||||
use log::{debug, error, info, warn};
|
||||
use regex::Regex;
|
||||
use std::{
|
||||
|
@ -11,133 +10,10 @@ use std::{
|
|||
sync::OnceLock,
|
||||
thread,
|
||||
};
|
||||
use thiserror::Error;
|
||||
use yansi::Paint;
|
||||
mod error;
|
||||
mod store;
|
||||
|
||||
/// Application errors with thiserror
|
||||
#[derive(Debug, Error)]
|
||||
enum AppError {
|
||||
#[error("Command failed: {command} {args:?} - {message}")]
|
||||
CommandFailed {
|
||||
command: String,
|
||||
args: Vec<String>,
|
||||
message: String,
|
||||
},
|
||||
|
||||
#[error("Failed to decode command output from {context}: {source}")]
|
||||
CommandOutputError {
|
||||
source: std::str::Utf8Error,
|
||||
context: String,
|
||||
},
|
||||
|
||||
#[error("Failed to parse data in {context}: {message}")]
|
||||
ParseError {
|
||||
message: String,
|
||||
context: String,
|
||||
#[source]
|
||||
source: Option<Box<dyn std::error::Error + Send + Sync>>,
|
||||
},
|
||||
|
||||
#[error("Regex error in {context}: {source}")]
|
||||
RegexError {
|
||||
source: regex::Error,
|
||||
context: String,
|
||||
},
|
||||
|
||||
#[error("IO error in {context}: {source}")]
|
||||
IoError {
|
||||
source: std::io::Error,
|
||||
context: String,
|
||||
},
|
||||
|
||||
#[error("Nix store error: {message} for path: {store_path}")]
|
||||
NixStoreError { message: String, store_path: String },
|
||||
}
|
||||
|
||||
// Implement From traits to support the ? operator
|
||||
impl From<std::io::Error> for AppError {
|
||||
fn from(source: std::io::Error) -> Self {
|
||||
Self::IoError {
|
||||
source,
|
||||
context: "unknown context".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::str::Utf8Error> for AppError {
|
||||
fn from(source: std::str::Utf8Error) -> Self {
|
||||
Self::CommandOutputError {
|
||||
source,
|
||||
context: "command output".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<regex::Error> for AppError {
|
||||
fn from(source: regex::Error) -> Self {
|
||||
Self::RegexError {
|
||||
source,
|
||||
context: "regex operation".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AppError {
|
||||
/// Create a command failure error with context
|
||||
pub fn command_failed<S: Into<String>>(command: S, args: &[&str], message: S) -> Self {
|
||||
Self::CommandFailed {
|
||||
command: command.into(),
|
||||
args: args.iter().map(|&s| s.to_string()).collect(),
|
||||
message: message.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a parse error with context
|
||||
pub fn parse_error<S: Into<String>, C: Into<String>>(
|
||||
message: S,
|
||||
context: C,
|
||||
source: Option<Box<dyn std::error::Error + Send + Sync>>,
|
||||
) -> Self {
|
||||
Self::ParseError {
|
||||
message: message.into(),
|
||||
context: context.into(),
|
||||
source,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an IO error with context
|
||||
pub fn io_error<C: Into<String>>(source: std::io::Error, context: C) -> Self {
|
||||
Self::IoError {
|
||||
source,
|
||||
context: context.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a regex error with context
|
||||
pub fn regex_error<C: Into<String>>(source: regex::Error, context: C) -> Self {
|
||||
Self::RegexError {
|
||||
source,
|
||||
context: context.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a command output error with context
|
||||
pub fn command_output_error<C: Into<String>>(source: std::str::Utf8Error, context: C) -> Self {
|
||||
Self::CommandOutputError {
|
||||
source,
|
||||
context: context.into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a Nix store error
|
||||
pub fn nix_store_error<M: Into<String>, P: Into<String>>(message: M, store_path: P) -> Self {
|
||||
Self::NixStoreError {
|
||||
message: message.into(),
|
||||
store_path: store_path.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
use error::AppError;
|
||||
|
||||
// Use type alias for Result with our custom error type
|
||||
type Result<T> = std::result::Result<T, AppError>;
|
||||
|
|
107
src/store.rs
107
src/store.rs
|
@ -1,29 +1,10 @@
|
|||
use async_std::task;
|
||||
use sqlx::{Connection, SqliteConnection};
|
||||
use std::future;
|
||||
use crate::error::AppError;
|
||||
use rusqlite::Connection;
|
||||
|
||||
// executes a query on the nix db directly
|
||||
// to gather all derivations that the derivation given by the path
|
||||
// depends on
|
||||
//
|
||||
// in the future, we might wan't to switch to async
|
||||
pub fn get_packages(path: &std::path::Path) -> Result<Vec<String>, String> {
|
||||
let p = path
|
||||
.canonicalize()
|
||||
.ok()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.ok_or("Could not convert resolve path")?;
|
||||
// Use type alias for Result with our custom error type
|
||||
type Result<T> = std::result::Result<T, AppError>;
|
||||
|
||||
task::block_on(async {
|
||||
struct Col {
|
||||
path: String,
|
||||
}
|
||||
let mut conn = SqliteConnection::connect("sqlite:///nix/var/nix/db/db.sqlite")
|
||||
.await
|
||||
.map_err(|_| "Could not establish DB connection")?;
|
||||
let query_res = sqlx::query_as!(
|
||||
Col,
|
||||
"
|
||||
const QUERY_PKGS: &str = "
|
||||
WITH RECURSIVE
|
||||
graph(p) AS (
|
||||
SELECT id
|
||||
|
@ -35,41 +16,9 @@ WITH RECURSIVE
|
|||
)
|
||||
SELECT path from graph
|
||||
JOIN ValidPaths ON id = p;
|
||||
",
|
||||
p
|
||||
)
|
||||
.fetch_all(&mut conn)
|
||||
.await
|
||||
.map_err(|_| "Could not execute package query")?
|
||||
.into_iter()
|
||||
.map(|c| c.path)
|
||||
.collect();
|
||||
Ok::<_, String>(query_res)
|
||||
})
|
||||
}
|
||||
";
|
||||
|
||||
// executes a query on the nix db directly
|
||||
// to get the total closure size of the derivation
|
||||
// by summing up the nar size of all derivations
|
||||
// depending on the derivation
|
||||
//
|
||||
// in the future, we might wan't to switch to async
|
||||
pub fn get_closure_size(path: &std::path::Path) -> Result<i64, String> {
|
||||
let p = path
|
||||
.canonicalize()
|
||||
.ok()
|
||||
.map(|p| p.to_string_lossy().to_string())
|
||||
.ok_or("Could not convert resolve path")?;
|
||||
let size = task::block_on(async {
|
||||
struct Res {
|
||||
sum: Option<i64>,
|
||||
}
|
||||
let mut conn = SqliteConnection::connect("sqlite:///nix/var/nix/db/db.sqlite")
|
||||
.await
|
||||
.map_err(|_| "Could not establish DB connection")?;
|
||||
let query_res = sqlx::query_as!(
|
||||
Res,
|
||||
"
|
||||
const QUERY_CLOSURE_SIZE: &str = "
|
||||
WITH RECURSIVE
|
||||
graph(p) AS (
|
||||
SELECT id
|
||||
|
@ -81,18 +30,34 @@ WITH RECURSIVE
|
|||
)
|
||||
SELECT SUM(narSize) as sum from graph
|
||||
JOIN ValidPaths ON p = id;
|
||||
",
|
||||
p
|
||||
)
|
||||
.fetch_one(&mut conn)
|
||||
.await
|
||||
.map_err(|_| "Could not execute package query")?
|
||||
.sum
|
||||
.ok_or("Could not get closure size sum")?;
|
||||
Ok::<_, String>(query_res)
|
||||
});
|
||||
size
|
||||
";
|
||||
|
||||
/// executes a query on the nix db directly
|
||||
/// to gather all derivations that the derivation given by the path
|
||||
/// depends on
|
||||
///
|
||||
/// in the future, we might wan't to switch to async
|
||||
pub fn get_packages(path: &std::path::Path) -> Result<Vec<String>> {
|
||||
let p: String = path.canonicalize()?.to_string_lossy().into_owned();
|
||||
let conn = Connection::open("/nix/var/nix/db/db.sqlite")?;
|
||||
|
||||
let mut stmt = conn.prepare(QUERY_PKGS)?;
|
||||
let queried_pkgs: std::result::Result<Vec<String>, _> =
|
||||
stmt.query_map([p], |row| row.get(0))?.collect();
|
||||
Ok(queried_pkgs?)
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
/// executes a query on the nix db directly
|
||||
/// to get the total closure size of the derivation
|
||||
/// by summing up the nar size of all derivations
|
||||
/// depending on the derivation
|
||||
///
|
||||
/// in the future, we might wan't to switch to async
|
||||
pub fn get_closure_size(path: &std::path::Path) -> Result<i64> {
|
||||
let p: String = path.canonicalize()?.to_string_lossy().into_owned();
|
||||
let conn = Connection::open("/nix/var/nix/db/db.sqlite")?;
|
||||
|
||||
let mut stmt = conn.prepare(QUERY_CLOSURE_SIZE)?;
|
||||
let queried_sum = stmt.query_row([p], |row| row.get(0))?;
|
||||
Ok(queried_sum)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue