mirror of
https://github.com/RGBCube/dix
synced 2025-07-28 12:17:45 +00:00
main: improve memory safety
Guys it's memory safe guys its's MEMORY SA- *shot dead*
This commit is contained in:
parent
28871c9f52
commit
2c6f84e8ac
1 changed files with 115 additions and 54 deletions
139
src/main.rs
139
src/main.rs
|
@ -5,6 +5,7 @@ use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
process::Command,
|
process::Command,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
|
sync::OnceLock,
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
use yansi::Paint;
|
use yansi::Paint;
|
||||||
|
@ -91,64 +92,91 @@ fn main() {
|
||||||
print_changes(changed, &pre, &post);
|
print_changes(changed, &pre, &post);
|
||||||
|
|
||||||
if let Some((pre_handle, post_handle)) = closure_size_handles {
|
if let Some((pre_handle, post_handle)) = closure_size_handles {
|
||||||
let pre_size = pre_handle.join().unwrap();
|
match (pre_handle.join(), post_handle.join()) {
|
||||||
let post_size = post_handle.join().unwrap();
|
(Ok(pre_size), Ok(post_size)) => {
|
||||||
|
|
||||||
println!("{}", "Closure Size:".underline().bold());
|
println!("{}", "Closure Size:".underline().bold());
|
||||||
println!("Before: {pre_size} MiB");
|
println!("Before: {pre_size} MiB");
|
||||||
println!("After: {post_size} MiB");
|
println!("After: {post_size} MiB");
|
||||||
println!("Difference: {} MiB", post_size - pre_size);
|
println!("Difference: {} MiB", post_size - pre_size);
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
eprintln!("Error: Failed to get closure size information due to a thread error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the packages in a closure
|
// gets the packages in a closure
|
||||||
fn get_packages(path: &std::path::Path) -> Vec<String> {
|
fn get_packages(path: &std::path::Path) -> Vec<String> {
|
||||||
// get the nix store paths using nix-store --query --references <path>
|
// get the nix store paths using nix-store --query --references <path>
|
||||||
let references = Command::new("nix-store")
|
let output = Command::new("nix-store")
|
||||||
.arg("--query")
|
.arg("--query")
|
||||||
.arg("--references")
|
.arg("--references")
|
||||||
.arg(path.join("sw"))
|
.arg(path.join("sw"))
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
if let Ok(query) = references {
|
match output {
|
||||||
let list = str::from_utf8(&query.stdout);
|
Ok(query) => {
|
||||||
|
match str::from_utf8(&query.stdout) {
|
||||||
if let Ok(list) = list {
|
Ok(list) => list.lines().map(ToString::to_string).collect(),
|
||||||
let res: Vec<String> = list.lines().map(ToString::to_string).collect();
|
Err(e) => {
|
||||||
return res;
|
eprintln!("Error decoding command output: {}", e);
|
||||||
}
|
|
||||||
}
|
|
||||||
Vec::new()
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error executing nix-store command: {}", e);
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the dependencies of the packages in a closure
|
// gets the dependencies of the packages in a closure
|
||||||
fn get_dependencies(path: &std::path::Path) -> Vec<String> {
|
fn get_dependencies(path: &std::path::Path) -> Vec<String> {
|
||||||
// get the nix store paths using nix-store --query --references <path>
|
// get the nix store paths using nix-store --query --references <path>
|
||||||
let references = Command::new("nix-store")
|
let output = Command::new("nix-store")
|
||||||
.arg("--query")
|
.arg("--query")
|
||||||
.arg("--requisites")
|
.arg("--requisites")
|
||||||
.arg(path.join("sw"))
|
.arg(path.join("sw"))
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
if let Ok(query) = references {
|
match output {
|
||||||
let list = str::from_utf8(&query.stdout);
|
Ok(query) => {
|
||||||
|
match str::from_utf8(&query.stdout) {
|
||||||
if let Ok(list) = list {
|
Ok(list) => list.lines().map(ToString::to_string).collect(),
|
||||||
let res: Vec<String> = list.lines().map(ToString::to_string).collect();
|
Err(e) => {
|
||||||
return res;
|
eprintln!("Error decoding command output: {}", e);
|
||||||
}
|
|
||||||
}
|
|
||||||
Vec::new()
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error executing nix-store command: {}", e);
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a reference to the compiled regex pattern.
|
||||||
|
// The regex is compiled only once.
|
||||||
|
fn store_path_regex() -> &'static Regex {
|
||||||
|
static REGEX: OnceLock<Regex> = OnceLock::new();
|
||||||
|
REGEX.get_or_init(|| {
|
||||||
|
Regex::new(r"^/nix/store/[a-z0-9]+-(.+?)-([0-9].*?)$")
|
||||||
|
.expect("Failed to compile regex pattern for nix store paths")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_version<'a>(pack: impl Into<&'a str>) -> (&'a str, &'a str) {
|
fn get_version<'a>(pack: impl Into<&'a str>) -> (&'a str, &'a str) {
|
||||||
// funny regex to split a nix store path into its name and its version.
|
// funny regex to split a nix store path into its name and its version.
|
||||||
let re = Regex::new(r"^/nix/store/[a-z0-9]+-(.+?)-([0-9].*?)$").unwrap();
|
let path = pack.into();
|
||||||
|
|
||||||
// No cap frfr
|
// Match the regex against the input
|
||||||
if let Some(cap) = re.captures(pack.into()) {
|
if let Some(cap) = store_path_regex().captures(path) {
|
||||||
let name = cap.get(1).unwrap().as_str();
|
// Handle potential missing captures safely
|
||||||
let version = cap.get(2).unwrap().as_str();
|
let name = cap.get(1).map_or("", |m| m.as_str());
|
||||||
|
let version = cap.get(2).map_or("", |m| m.as_str());
|
||||||
return (name, version);
|
return (name, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,21 +192,54 @@ fn check_nix_available() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_closure_size(path: &std::path::Path) -> i64 {
|
fn get_closure_size(path: &std::path::Path) -> i64 {
|
||||||
Command::new("nix")
|
// Run nix path-info command to get closure size
|
||||||
|
match Command::new("nix")
|
||||||
.arg("path-info")
|
.arg("path-info")
|
||||||
.arg("--closure-size")
|
.arg("--closure-size")
|
||||||
.arg(path.join("sw"))
|
.arg(path.join("sw"))
|
||||||
.output()
|
.output()
|
||||||
.ok()
|
{
|
||||||
.and_then(|output| {
|
Ok(output) if output.status.success() => {
|
||||||
str::from_utf8(&output.stdout)
|
// Parse command output to extract the size
|
||||||
.ok()?
|
match str::from_utf8(&output.stdout) {
|
||||||
|
Ok(stdout) => {
|
||||||
|
// Parse the last word in the output as an integer
|
||||||
|
stdout
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.last()?
|
.last()
|
||||||
.parse::<i64>()
|
.and_then(|s| s.parse::<i64>().ok())
|
||||||
.ok()
|
.map_or_else(
|
||||||
})
|
|| {
|
||||||
.map_or(0, |size| size / 1024 / 1024)
|
eprintln!("Failed to parse closure size from output: {}", stdout);
|
||||||
|
0
|
||||||
|
},
|
||||||
|
|size| size / 1024 / 1024, // Convert to MiB
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error decoding command output: {}", e);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(output) => {
|
||||||
|
// Command ran but returned an error
|
||||||
|
match str::from_utf8(&output.stderr) {
|
||||||
|
Ok(stderr) if !stderr.is_empty() => {
|
||||||
|
eprintln!("nix path-info command failed: {}", stderr);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
eprintln!("nix path-info command failed with status: {}", output.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
// Command failed to run
|
||||||
|
eprintln!("Failed to execute nix path-info command: {}", e);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_added(set: HashSet<&str>, post: &HashMap<&str, HashSet<&str>>) {
|
fn print_added(set: HashSet<&str>, post: &HashMap<&str, HashSet<&str>>) {
|
||||||
|
@ -224,9 +285,8 @@ fn print_changes(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// can not fail since maybe_changed is the union of the keys of pre and post
|
// We should handle the case where the package might not exist in one of the maps
|
||||||
let ver_pre = pre.get(p).unwrap();
|
if let (Some(ver_pre), Some(ver_post)) = (pre.get(p), post.get(p)) {
|
||||||
let ver_post = post.get(p).unwrap();
|
|
||||||
let version_str_pre = ver_pre.iter().copied().collect::<Vec<_>>().join(" ");
|
let version_str_pre = ver_pre.iter().copied().collect::<Vec<_>>().join(" ");
|
||||||
let version_str_post = ver_post.iter().copied().collect::<Vec<_>>().join(", ");
|
let version_str_post = ver_post.iter().copied().collect::<Vec<_>>().join(", ");
|
||||||
|
|
||||||
|
@ -241,4 +301,5 @@ fn print_changes(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue