269 lines
7.4 KiB
Rust
269 lines
7.4 KiB
Rust
use std::path::{Path, PathBuf};
|
|
|
|
pub struct Repository {
|
|
pub name: String,
|
|
}
|
|
|
|
impl Repository {
|
|
pub fn list() -> Vec<String> {
|
|
let mut repos = vec![];
|
|
|
|
for entry in std::fs::read_dir("./data").unwrap() {
|
|
let path = entry.unwrap().path();
|
|
let file_name = path.file_name().unwrap().to_str().unwrap().to_string();
|
|
repos.push(file_name);
|
|
}
|
|
|
|
repos
|
|
}
|
|
|
|
pub fn create(name: &str) -> Repository {
|
|
let path = PathBuf::from("./data").join(name);
|
|
std::fs::create_dir_all(path).unwrap();
|
|
Repository::new(name).unwrap()
|
|
}
|
|
}
|
|
|
|
impl Repository {
|
|
pub fn new(name: &str) -> Option<Self> {
|
|
if PathBuf::from("./data").join(name).exists() {
|
|
Some(Repository {
|
|
name: name.to_string(),
|
|
})
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn arch(&self) -> Vec<String> {
|
|
let dir_path = PathBuf::from("./data").join(&self.name);
|
|
let mut arch = vec![];
|
|
|
|
if let Ok(entries) = std::fs::read_dir(dir_path) {
|
|
for entry in entries.filter_map(Result::ok) {
|
|
let file_name = entry.file_name().into_string().unwrap_or_default();
|
|
arch.push(file_name);
|
|
}
|
|
}
|
|
|
|
arch
|
|
}
|
|
|
|
pub fn base_path(&self, arch: &str) -> PathBuf {
|
|
PathBuf::from("./data").join(&self.name).join(arch)
|
|
}
|
|
|
|
pub fn db_content(&self, arch: &str) -> Option<Vec<u8>> {
|
|
std::fs::read(
|
|
self.base_path(arch)
|
|
.join(format!("{}.db.tar.gz", self.name)),
|
|
)
|
|
.ok()
|
|
}
|
|
|
|
pub fn sig_content(&self, arch: &str) -> Option<Vec<u8>> {
|
|
std::fs::read(
|
|
self.base_path(arch)
|
|
.join(format!("{}.db.tar.gz.sig", self.name)),
|
|
)
|
|
.ok()
|
|
}
|
|
|
|
pub fn extract_pkg_name(name: &str) -> (String, String, String, String) {
|
|
// "{}-{}-{}-{}.pkg.tar.zst"
|
|
let splitted: Vec<&str> = name.split('-').collect();
|
|
let name = splitted.get(0).unwrap();
|
|
let version = splitted.get(1).unwrap();
|
|
let rel = splitted.get(2).unwrap();
|
|
let arch = splitted.get(3).unwrap().trim_end_matches(".pkg.tar.zst");
|
|
|
|
(
|
|
name.to_string(),
|
|
version.to_string(),
|
|
rel.to_string(),
|
|
arch.to_string(),
|
|
)
|
|
}
|
|
|
|
pub fn get_pkg(&self, arch: &str, pkg_name: &str) -> Option<Package> {
|
|
let pkg_name = if pkg_name.ends_with(".sig") {
|
|
pkg_name.trim_end_matches(".sig").to_string()
|
|
} else {
|
|
pkg_name.to_string()
|
|
};
|
|
|
|
let (name, version, _, _) = Repository::extract_pkg_name(&pkg_name);
|
|
|
|
let pkg = Package::new(&self.name, &arch, &name, &version);
|
|
|
|
if pkg.exists() {
|
|
return Some(pkg);
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Package {
|
|
repo: String,
|
|
arch: String,
|
|
name: String,
|
|
version: Option<String>,
|
|
}
|
|
|
|
impl Package {
|
|
pub fn new(repo: &str, arch: &str, pkg_name: &str, version: &str) -> Self {
|
|
Package {
|
|
repo: repo.to_string(),
|
|
arch: arch.to_string(),
|
|
name: pkg_name.to_string(),
|
|
version: Some(version.to_string()),
|
|
}
|
|
}
|
|
|
|
pub fn find(repo: &str, arch: &str, pkg_name: &str) -> Self {
|
|
let mut base = Package {
|
|
repo: repo.to_string(),
|
|
arch: arch.to_string(),
|
|
name: pkg_name.to_string(),
|
|
version: None,
|
|
};
|
|
|
|
let versions = base.versions();
|
|
let ver = versions.first().unwrap();
|
|
|
|
base.version = Some(ver.clone());
|
|
|
|
base
|
|
}
|
|
|
|
pub fn save(&self, pkg: Vec<u8>, sig: Option<Vec<u8>>) {
|
|
let pkg_file = self.base_path().join(&self.file_name());
|
|
let sig_file = self.base_path().join(format!("{}.sig", self.file_name()));
|
|
|
|
std::fs::write(&pkg_file, pkg).unwrap();
|
|
if let Some(sig) = sig {
|
|
std::fs::write(sig_file, sig).unwrap();
|
|
}
|
|
|
|
let db_file = PathBuf::from("./data")
|
|
.join(&self.repo)
|
|
.join(&self.arch)
|
|
.join(format!("{}.db.tar.gz", self.repo));
|
|
|
|
run_command(vec![
|
|
"repo-add",
|
|
db_file.to_str().unwrap(),
|
|
pkg_file.to_str().unwrap(),
|
|
]);
|
|
|
|
if &self.arch == "any" {
|
|
let archs = Repository::new(&self.repo).unwrap().arch();
|
|
|
|
for arch in archs {
|
|
if arch == "any" {
|
|
continue;
|
|
}
|
|
|
|
let db_file = PathBuf::from("./data")
|
|
.join(&self.repo)
|
|
.join(&arch)
|
|
.join(format!("{}.db.tar.gz", self.repo));
|
|
|
|
run_command(vec![
|
|
"repo-add",
|
|
db_file.to_str().unwrap(),
|
|
pkg_file.to_str().unwrap(),
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn base_path(&self) -> PathBuf {
|
|
Path::new("./data").join(&self.repo).join(&self.arch)
|
|
}
|
|
|
|
pub fn switch_arch(&self, arch: &str) -> Self {
|
|
let mut new = self.clone();
|
|
new.arch = arch.to_string();
|
|
new
|
|
}
|
|
|
|
pub fn exists(&self) -> bool {
|
|
let pkg_file = self.base_path().join(self.file_name());
|
|
pkg_file.exists()
|
|
}
|
|
|
|
pub fn get_version(&self, version: &str) -> Self {
|
|
let mut new_pkg = self.clone();
|
|
new_pkg.version = Some(version.to_string());
|
|
new_pkg
|
|
}
|
|
|
|
pub fn is_signed(&self) -> bool {
|
|
let signed_file = self.base_path().join(format!("{}.sig", self.file_name()));
|
|
signed_file.exists()
|
|
}
|
|
|
|
pub fn file_name(&self) -> String {
|
|
format!(
|
|
"{}-{}-{}-{}.pkg.tar.zst",
|
|
self.name,
|
|
if let Some(ver) = &self.version {
|
|
ver.to_string()
|
|
} else {
|
|
let versions = self.versions();
|
|
versions.first().unwrap().clone()
|
|
},
|
|
1,
|
|
self.arch,
|
|
)
|
|
}
|
|
|
|
pub fn versions(&self) -> Vec<String> {
|
|
let dir_path = self.base_path();
|
|
let mut versions = vec![];
|
|
|
|
if let Ok(entries) = std::fs::read_dir(dir_path) {
|
|
for entry in entries.filter_map(Result::ok) {
|
|
let file_name = entry.file_name().into_string().unwrap_or_default();
|
|
if file_name.starts_with(&self.name) && file_name.ends_with(".pkg.tar.zst") {
|
|
// Extract version (assuming the filename is "<pkg_name>-<version>-<relation>-<arch>.pkg.tar.zst")
|
|
if let Some(version) = file_name.split('-').nth(1) {
|
|
versions.push(version.to_string());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort versions in descending order (most recent version first)
|
|
versions.sort_by(|a, b| b.cmp(a));
|
|
versions
|
|
}
|
|
|
|
pub fn pkg_content(&self) -> Option<Vec<u8>> {
|
|
if self.exists() {
|
|
return std::fs::read(self.base_path().join(self.file_name())).ok();
|
|
}
|
|
|
|
None
|
|
}
|
|
|
|
pub fn sig_content(&self) -> Option<Vec<u8>> {
|
|
if self.exists() {
|
|
return std::fs::read(self.base_path().join(format!("{}.sig", &self.file_name()))).ok();
|
|
}
|
|
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn run_command(cmd: Vec<&str>) {
|
|
std::process::Command::new(cmd.first().unwrap())
|
|
.args(cmd.into_iter().skip(1).collect::<Vec<&str>>())
|
|
.spawn()
|
|
.unwrap()
|
|
.wait()
|
|
.unwrap();
|
|
}
|