trim + fixes

This commit is contained in:
2025-09-18 12:21:01 +03:00
parent 35fafb1ca6
commit 28ba2135ec
10 changed files with 139 additions and 25 deletions

View File

@ -6,6 +6,8 @@ edition='2024'
[dependencies] [dependencies]
clap = "4.5.39" clap = "4.5.39"
rayon = "1.10.0" rayon = "1.10.0"
glob = "0.3"
chrono = { version = "0.4", features = ["serde"] }
[profile.release] [profile.release]
opt-level = 3 opt-level = 3

View File

@ -14,24 +14,17 @@ musl /pkg/gnu/aeropkg/var/musl
> Trimming removes unused files for a specified period > Trimming removes unused files for a specified period
> >
> Usage: > Usage:
> pkg trim \<repo\> \<period\> > pkg trim \<repo\> \<date\> \[time\]
> period relative time format: > date: DD.MM.YYYY
> y — years, M — months, d — days, h — hours, m — minutes, s — seconds > time: HH:mm:ss
> period absolute date format:
> DD.MM.YYYY HH:mm:ss
>
> Example:
> pkg trim musl 2d 10h
> pkg trim musl 04.09.2025 08:57:07
> >
> Configure format > Configure format
> Any Linux path format, relative from /pkg/\<repo\> > Relative paths with /pkg/<repo>, support wildcard
> Add ! to exclude
``` cfg *** Trim exclude *** ``` cfg *** Trim rules ***
* !**
``` !aeropkg
``` cfg *** Trim include ***
``` ```

View File

@ -11,6 +11,7 @@ SCRIPT_DIR=$(dirname "$(readlink -f "$0")")
echo "Установка в '$INSTALL_PATH'..." echo "Установка в '$INSTALL_PATH'..."
AEROPKG_HOME=$INSTALL_PATH cargo install --path . --root "$INSTALL_PATH" AEROPKG_HOME=$INSTALL_PATH cargo install --path . --root "$INSTALL_PATH"
patchelf --set-interpreter /pkg/gnu/glibc/lib/ld-linux-x86-64.so.2 /pkg/gnu/aeropkg/bin/pkg
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Ошибка при установке." echo "Ошибка при установке."

View File

@ -3,6 +3,7 @@ pub mod delete;
pub mod link; pub mod link;
pub mod disable; pub mod disable;
pub mod enable; pub mod enable;
pub mod trim;
use std::path::PathBuf; use std::path::PathBuf;
@ -10,3 +11,8 @@ use std::path::PathBuf;
pub fn get_var_path() -> PathBuf { pub fn get_var_path() -> PathBuf {
PathBuf::from(env!("AEROPKG_HOME")).join("var") PathBuf::from(env!("AEROPKG_HOME")).join("var")
} }
pub fn get_etc_path() -> PathBuf {
PathBuf::from(env!("AEROPKG_HOME")).join("etc")
}

78
src/commands/trim.rs Normal file
View File

@ -0,0 +1,78 @@
use std::path::{Path, PathBuf};
use std::fs;
use std::os::unix::fs::MetadataExt;
use glob::Pattern;
fn trim(repo: &String, path: &Path, trim_date: i64, rules: &String) -> Result<(), std::io::Error> {
let metadata = fs::symlink_metadata(path)?;
if metadata.is_dir() {
if rules_check(repo, path, rules) {
for entry in fs::read_dir(path)? {
let entry = entry?;
let entry_path = entry.path();
trim(repo, &entry_path, trim_date, rules)?;
}
}
} else if metadata.is_file() {
if rules_check(repo, path, rules) {
let atime = metadata.atime();
if atime < trim_date {
fs::remove_file(path)?;
}
}
} else if metadata.file_type().is_symlink() {
if let Ok(symlink_value) = fs::read_link(path) {
let symlink_path = if symlink_value.is_relative() { path.parent().unwrap().join(&symlink_value) } else { symlink_value };
if !symlink_path.exists() {
println!("remove symlink: {} {}", path.display(), symlink_path.display());
fs::remove_file(path)?;
}
}
}
Ok(())
}
pub fn trim_handler(repo: &String, trim_date: i64) {
let etc_path = super::get_etc_path();
let cfg_path = etc_path.join("aeropkg.md");
let rules = crate::utils::parser::get_trim_rules(&cfg_path).unwrap();
let pkg_dir = PathBuf::from("/pkg").join(repo);
trim(repo, &pkg_dir, trim_date, &rules).unwrap();
}
fn rules_check(repo: &String, path: &Path, rules: &String) -> bool {
let mut confirm = true;
for rule in rules.lines() {
let mut rule = rule.trim();
let invert = rule.starts_with('!');
if invert {
rule = &rule[1..];
}
let wildcard_string = if rule.starts_with('/') {
rule.to_string()
} else {
format!("/pkg/{}/{}", repo, rule)
};
let path_str = path.to_str().unwrap_or("");
if let Ok(pattern) = Pattern::new(&wildcard_string) {
if pattern.matches(path_str) {
confirm = !invert;
}
}
}
confirm
}

View File

@ -1,5 +1,6 @@
mod commands; mod commands;
mod utils; mod utils;
use chrono::NaiveDateTime;
fn main() { fn main() {
let matches = clap::Command::new("pkg") let matches = clap::Command::new("pkg")
@ -53,6 +54,28 @@ fn main() {
.index(2), .index(2),
), ),
) )
.subcommand(
clap::Command::new("trim")
.about("Remove unused files within a specified period")
.arg(
clap::Arg::new("repo")
.help("Repository name")
.required(true)
.index(1),
)
.arg(
clap::Arg::new("date")
.help("DD.MM.YYYY")
.required(true)
.index(2),
)
.arg(
clap::Arg::new("time")
.help("HH:mm:ss")
.required(false)
.index(3),
),
)
.subcommand( .subcommand(
clap::Command::new("disable") clap::Command::new("disable")
.about("Disable package") .about("Disable package")
@ -120,6 +143,20 @@ fn main() {
Ok(_) => println!("link completed successfully."), Ok(_) => println!("link completed successfully."),
Err(e) => eprintln!("Error during link: {}", e), Err(e) => eprintln!("Error during link: {}", e),
} }
} else if let Some(trim_matches) = matches.subcommand_matches("trim") {
let repo = trim_matches.get_one::<String>("repo").unwrap();
let date = trim_matches.get_one::<String>("date").unwrap();
let time = trim_matches.get_one::<String>("time").map(|s| s.as_str()).unwrap_or("00:00:00");
let datetime_str = format!("{} {}", date, time);
let datetime = NaiveDateTime::parse_from_str(&datetime_str, "%d.%m.%Y %H:%M:%S")
.expect("Invalid date or time format. Expected format: DD.MM.YYYY HH:mm:ss");
let trim_date = datetime.and_utc().timestamp();
commands::trim::trim_handler(&repo, trim_date);
} else if let Some(disable_matches) = matches.subcommand_matches("disable") { } else if let Some(disable_matches) = matches.subcommand_matches("disable") {
let repo = disable_matches.get_one::<String>("repo").unwrap(); let repo = disable_matches.get_one::<String>("repo").unwrap();
let pkgname = disable_matches.get_one::<String>("pkgname").unwrap(); let pkgname = disable_matches.get_one::<String>("pkgname").unwrap();

0
src/utils/env.rs Normal file
View File

View File

@ -76,7 +76,7 @@ fn hardcopy(
})?; })?;
} else if metadata.file_type().is_symlink() { } else if metadata.file_type().is_symlink() {
let symlink_value = fs::read_link(source)?; let symlink_value = fs::read_link(source)?;
fs::remove_file(destination)?; if destination.exists() { fs::remove_file(destination)? }
unix::fs::symlink(symlink_value, destination)?; unix::fs::symlink(symlink_value, destination)?;
} }

0
src/utils/hooks.rs Normal file
View File

View File

@ -1,5 +1,4 @@
use std::fs; use std::fs;
use std::env;
use std::io::{self, BufRead}; use std::io::{self, BufRead};
use std::path::{Path,PathBuf}; use std::path::{Path,PathBuf};
@ -59,10 +58,12 @@ pub fn get_patch_script<P: AsRef<Path>>(file_path: P) -> io::Result<String> {
extract_block(file_path, "``` sh *** config ***", "```") extract_block(file_path, "``` sh *** config ***", "```")
} }
pub fn get_trim_rules<P: AsRef<Path>>(file_path: P) -> io::Result<String> {
extract_block(file_path, "``` cfg *** Trim rules ***", "```")
}
pub fn get_repo_list() -> io::Result<Vec<String>> { pub fn get_repo_list() -> io::Result<Vec<String>> {
let file_path = crate::commands::get_var_path().join("aeropkg.md"); let file_path = crate::commands::get_etc_path().join("aeropkg.md");
let block = extract_block(file_path, "``` cfg *** Repository list and priority ***", "```")?; let block = extract_block(file_path, "``` cfg *** Repository list and priority ***", "```")?;
@ -82,13 +83,9 @@ pub fn get_repo_list() -> io::Result<Vec<String>> {
pub fn get_repo_addr(repo: &str) -> io::Result<String> { pub fn get_repo_addr(repo: &str) -> io::Result<String> {
let exe_path = env::current_exe()?; let file_path = crate::commands::get_etc_path().join("aeropkg.md");
let file_path = exe_path
.parent()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to get executable directory"))?
.join("../etc/aeropkg.md");
let block = extract_block(file_path, "``` sh *** Repository list and priority ***", "```")?; let block = extract_block(file_path, "``` cfg *** Repository list and priority ***", "```")?;
for line in block.lines() { for line in block.lines() {
let trimmed_line = line.trim(); let trimmed_line = line.trim();