1
Fork 0
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:
Dragyx 2025-05-06 01:15:50 +02:00
parent 55c969cfdf
commit eee8c920a7
6 changed files with 203 additions and 2169 deletions

1998
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -10,5 +10,4 @@ yansi = "1.0.1"
thiserror = "2.0.12" thiserror = "2.0.12"
log = "0.4.20" log = "0.4.20"
env_logger = "0.11.3" env_logger = "0.11.3"
sqlx = { version = "0.8.5", features = ["runtime-async-std", "sqlite"] } rusqlite = { version = "0.35.0", features = ["bundled"] }
async-std = "1.13.1"

View file

@ -1,2 +0,0 @@
[env]
DATABASE_URL="sqlite:///nix/var/nix/db/db.sqlite"

134
src/error.rs Normal file
View 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(),
}
}
}

View file

@ -1,7 +1,6 @@
mod print; mod print;
use clap::Parser; use clap::Parser;
use core::str; use core::str;
use env_logger;
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
use regex::Regex; use regex::Regex;
use std::{ use std::{
@ -11,133 +10,10 @@ use std::{
sync::OnceLock, sync::OnceLock,
thread, thread,
}; };
use thiserror::Error;
use yansi::Paint; use yansi::Paint;
mod error;
mod store; mod store;
use error::AppError;
/// 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 type alias for Result with our custom error type // Use type alias for Result with our custom error type
type Result<T> = std::result::Result<T, AppError>; type Result<T> = std::result::Result<T, AppError>;

View file

@ -1,29 +1,10 @@
use async_std::task; use crate::error::AppError;
use sqlx::{Connection, SqliteConnection}; use rusqlite::Connection;
use std::future;
// executes a query on the nix db directly // Use type alias for Result with our custom error type
// to gather all derivations that the derivation given by the path type Result<T> = std::result::Result<T, AppError>;
// 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")?;
task::block_on(async { const QUERY_PKGS: &str = "
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,
"
WITH RECURSIVE WITH RECURSIVE
graph(p) AS ( graph(p) AS (
SELECT id SELECT id
@ -35,41 +16,9 @@ WITH RECURSIVE
) )
SELECT path from graph SELECT path from graph
JOIN ValidPaths ON id = p; 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 const QUERY_CLOSURE_SIZE: &str = "
// 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,
"
WITH RECURSIVE WITH RECURSIVE
graph(p) AS ( graph(p) AS (
SELECT id SELECT id
@ -81,18 +30,34 @@ WITH RECURSIVE
) )
SELECT SUM(narSize) as sum from graph SELECT SUM(narSize) as sum from graph
JOIN ValidPaths ON p = id; JOIN ValidPaths ON p = id;
", ";
p
) /// executes a query on the nix db directly
.fetch_one(&mut conn) /// to gather all derivations that the derivation given by the path
.await /// depends on
.map_err(|_| "Could not execute package query")? ///
.sum /// in the future, we might wan't to switch to async
.ok_or("Could not get closure size sum")?; pub fn get_packages(path: &std::path::Path) -> Result<Vec<String>> {
Ok::<_, String>(query_res) let p: String = path.canonicalize()?.to_string_lossy().into_owned();
}); let conn = Connection::open("/nix/var/nix/db/db.sqlite")?;
size
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)
}