mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 21:30:41 +00:00
chore: cargo fmt
This commit is contained in:
parent
8f089656ba
commit
9512eb3b12
6 changed files with 288 additions and 123 deletions
|
|
@ -18,7 +18,11 @@ use super::{RepositoryError, Result};
|
|||
struct PythonFormatter;
|
||||
|
||||
impl Formatter for PythonFormatter {
|
||||
fn begin_object_key<W: ?Sized + Write>(&mut self, writer: &mut W, first: bool) -> std::io::Result<()> {
|
||||
fn begin_object_key<W: ?Sized + Write>(
|
||||
&mut self,
|
||||
writer: &mut W,
|
||||
first: bool,
|
||||
) -> std::io::Result<()> {
|
||||
if !first {
|
||||
writer.write_all(b",")?;
|
||||
}
|
||||
|
|
@ -29,7 +33,11 @@ impl Formatter for PythonFormatter {
|
|||
writer.write_all(b":")
|
||||
}
|
||||
|
||||
fn begin_array_value<W: ?Sized + Write>(&mut self, writer: &mut W, first: bool) -> std::io::Result<()> {
|
||||
fn begin_array_value<W: ?Sized + Write>(
|
||||
&mut self,
|
||||
writer: &mut W,
|
||||
first: bool,
|
||||
) -> std::io::Result<()> {
|
||||
if !first {
|
||||
writer.write_all(b",")?;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use lz4::EncoderBuilder;
|
|||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest as Sha2Digest, Sha256};
|
||||
use std::collections::{HashMap, HashSet, BTreeMap};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
|
|
@ -23,7 +23,7 @@ use walkdir::WalkDir;
|
|||
use crate::actions::{File as FileAction, Manifest};
|
||||
use crate::digest::Digest;
|
||||
use crate::fmri::Fmri;
|
||||
use crate::payload::{Payload, PayloadCompressionAlgorithm, PayloadArchitecture, PayloadBits};
|
||||
use crate::payload::{Payload, PayloadArchitecture, PayloadBits, PayloadCompressionAlgorithm};
|
||||
|
||||
use super::catalog_writer;
|
||||
use super::{
|
||||
|
|
@ -74,17 +74,48 @@ struct SearchQuery {
|
|||
|
||||
fn parse_query(query: &str) -> SearchQuery {
|
||||
if !query.contains(':') {
|
||||
return SearchQuery { pkg: None, action: None, index: None, token: query.to_string() };
|
||||
return SearchQuery {
|
||||
pkg: None,
|
||||
action: None,
|
||||
index: None,
|
||||
token: query.to_string(),
|
||||
};
|
||||
}
|
||||
|
||||
let parts: Vec<&str> = query.split(':').collect();
|
||||
let get_opt = |s: &str| if s.is_empty() { None } else { Some(s.to_string()) };
|
||||
let get_opt = |s: &str| {
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(s.to_string())
|
||||
}
|
||||
};
|
||||
|
||||
match parts.len() {
|
||||
2 => SearchQuery { pkg: None, action: None, index: get_opt(parts[0]), token: parts[1].to_string() },
|
||||
3 => SearchQuery { pkg: None, action: get_opt(parts[0]), index: get_opt(parts[1]), token: parts[2].to_string() },
|
||||
4 => SearchQuery { pkg: get_opt(parts[0]), action: get_opt(parts[1]), index: get_opt(parts[2]), token: parts[3].to_string() },
|
||||
_ => SearchQuery { pkg: None, action: None, index: None, token: query.to_string() },
|
||||
2 => SearchQuery {
|
||||
pkg: None,
|
||||
action: None,
|
||||
index: get_opt(parts[0]),
|
||||
token: parts[1].to_string(),
|
||||
},
|
||||
3 => SearchQuery {
|
||||
pkg: None,
|
||||
action: get_opt(parts[0]),
|
||||
index: get_opt(parts[1]),
|
||||
token: parts[2].to_string(),
|
||||
},
|
||||
4 => SearchQuery {
|
||||
pkg: get_opt(parts[0]),
|
||||
action: get_opt(parts[1]),
|
||||
index: get_opt(parts[2]),
|
||||
token: parts[3].to_string(),
|
||||
},
|
||||
_ => SearchQuery {
|
||||
pkg: None,
|
||||
action: None,
|
||||
index: None,
|
||||
token: query.to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +161,15 @@ impl SearchIndex {
|
|||
}
|
||||
|
||||
/// Add a term to the index for a package
|
||||
fn add_term(&mut self, term: &str, fmri: &str, action_type: &str, index_type: &str, value: &str, attributes: Option<BTreeMap<String, String>>) {
|
||||
fn add_term(
|
||||
&mut self,
|
||||
term: &str,
|
||||
fmri: &str,
|
||||
action_type: &str,
|
||||
index_type: &str,
|
||||
value: &str,
|
||||
attributes: Option<BTreeMap<String, String>>,
|
||||
) {
|
||||
let token = term.to_string();
|
||||
// Convert term to lowercase for case-insensitive search
|
||||
let term_lower = term.to_lowercase();
|
||||
|
|
@ -269,14 +308,20 @@ impl SearchIndex {
|
|||
}
|
||||
|
||||
// Filter entries based on structured query and case sensitivity
|
||||
let filtered: Vec<&IndexEntry> = term_entries.into_iter().filter(|e| {
|
||||
let filtered: Vec<&IndexEntry> = term_entries
|
||||
.into_iter()
|
||||
.filter(|e| {
|
||||
// Check Index Type
|
||||
if let Some(idx) = &parsed.index {
|
||||
if &e.index_type != idx { return false; }
|
||||
if &e.index_type != idx {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check Action Type
|
||||
if let Some(act) = &parsed.action {
|
||||
if &e.action_type != act { return false; }
|
||||
if &e.action_type != act {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check Package Name (FMRI)
|
||||
if let Some(pkg) = &parsed.pkg {
|
||||
|
|
@ -285,10 +330,14 @@ impl SearchIndex {
|
|||
let re_str = glob_to_regex(&pkg.to_lowercase());
|
||||
if let Ok(re) = Regex::new(&re_str) {
|
||||
// FMRIs are usually lowercase, but let's compare lowercase to be safe/consistent
|
||||
if !re.is_match(&e.fmri.to_lowercase()) { return false; }
|
||||
if !re.is_match(&e.fmri.to_lowercase()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if !e.fmri.contains(pkg) { return false; }
|
||||
if !e.fmri.contains(pkg) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,15 +346,20 @@ impl SearchIndex {
|
|||
if token_has_wildcard {
|
||||
let re_str = glob_to_regex(&parsed.token); // Original token
|
||||
if let Ok(re) = Regex::new(&re_str) {
|
||||
if !re.is_match(&e.token) { return false; }
|
||||
if !re.is_match(&e.token) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if e.token != parsed.token { return false; }
|
||||
if e.token != parsed.token {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
}).collect();
|
||||
})
|
||||
.collect();
|
||||
|
||||
if filtered.is_empty() {
|
||||
return Vec::new(); // Term found no matches
|
||||
|
|
@ -334,7 +388,8 @@ impl SearchIndex {
|
|||
}
|
||||
|
||||
results.sort_by(|a, b| {
|
||||
a.fmri.cmp(&b.fmri)
|
||||
a.fmri
|
||||
.cmp(&b.fmri)
|
||||
.then(a.action_type.cmp(&b.action_type))
|
||||
.then(a.index_type.cmp(&b.index_type))
|
||||
.then(a.value.cmp(&b.value))
|
||||
|
|
@ -388,7 +443,6 @@ pub struct FileBackend {
|
|||
Option<std::cell::RefCell<crate::repository::obsoleted::ObsoletedPackageManager>>,
|
||||
}
|
||||
|
||||
|
||||
/// Transaction for publishing packages
|
||||
pub struct Transaction {
|
||||
/// Unique ID for the transaction
|
||||
|
|
@ -2444,7 +2498,11 @@ impl FileBackend {
|
|||
info!("Rebuilding catalog (batched) for publisher: {}", publisher);
|
||||
|
||||
let quote_action_value = |s: &str| -> String {
|
||||
if s.is_empty() || s.contains(char::is_whitespace) || s.contains('"') || s.contains('\'') {
|
||||
if s.is_empty()
|
||||
|| s.contains(char::is_whitespace)
|
||||
|| s.contains('"')
|
||||
|| s.contains('\'')
|
||||
{
|
||||
format!("\"{}\"", s.replace("\"", "\\\""))
|
||||
} else {
|
||||
s.to_string()
|
||||
|
|
@ -2541,7 +2599,12 @@ impl FileBackend {
|
|||
// Extract variant and facet actions
|
||||
for attr in &manifest.attributes {
|
||||
if attr.key.starts_with("variant.") || attr.key.starts_with("facet.") {
|
||||
let values_str = attr.values.iter().map(|s| quote_action_value(s)).collect::<Vec<_>>().join(" value=");
|
||||
let values_str = attr
|
||||
.values
|
||||
.iter()
|
||||
.map(|s| quote_action_value(s))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" value=");
|
||||
dependency_actions.push(format!("set name={} value={}", attr.key, values_str));
|
||||
}
|
||||
}
|
||||
|
|
@ -2562,7 +2625,12 @@ impl FileBackend {
|
|||
&& !attr.key.starts_with("facet.")
|
||||
&& attr.key != "pkg.fmri"
|
||||
{
|
||||
let values_str = attr.values.iter().map(|s| quote_action_value(s)).collect::<Vec<_>>().join(" value=");
|
||||
let values_str = attr
|
||||
.values
|
||||
.iter()
|
||||
.map(|s| quote_action_value(s))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" value=");
|
||||
summary_actions.push(format!("set name={} value={}", attr.key, values_str));
|
||||
}
|
||||
}
|
||||
|
|
@ -2734,7 +2802,8 @@ impl FileBackend {
|
|||
);
|
||||
}
|
||||
|
||||
let update_log_sig = catalog_writer::write_update_log(&update_log_path, &mut update_log)?;
|
||||
let update_log_sig =
|
||||
catalog_writer::write_update_log(&update_log_path, &mut update_log)?;
|
||||
debug!("Wrote update log file");
|
||||
|
||||
// Add an update log to catalog.attrs
|
||||
|
|
@ -2932,7 +3001,11 @@ impl FileBackend {
|
|||
match Manifest::parse_file(&path) {
|
||||
Ok(manifest) => {
|
||||
// Look for the pkg.fmri attribute
|
||||
let fmri_opt = manifest.attributes.iter().find(|a| a.key == "pkg.fmri").and_then(|a| a.values.first());
|
||||
let fmri_opt = manifest
|
||||
.attributes
|
||||
.iter()
|
||||
.find(|a| a.key == "pkg.fmri")
|
||||
.and_then(|a| a.values.first());
|
||||
|
||||
if let Some(fmri_str) = fmri_opt {
|
||||
// Parse the FMRI using our Fmri type
|
||||
|
|
@ -2948,19 +3021,30 @@ impl FileBackend {
|
|||
index.add_term(&stem, &fmri, "pkg", "name", &stem, None);
|
||||
for part in stem.split('/') {
|
||||
if part != stem {
|
||||
index.add_term(part, &fmri, "pkg", "name", &stem, None);
|
||||
index.add_term(
|
||||
part, &fmri, "pkg", "name", &stem, None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Index Publisher
|
||||
if let Some(publ) = &parsed_fmri.publisher {
|
||||
index.add_term(publ, &fmri, "pkg", "publisher", publ, None);
|
||||
index.add_term(
|
||||
publ,
|
||||
&fmri,
|
||||
"pkg",
|
||||
"publisher",
|
||||
publ,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
// 3. Index Version
|
||||
let version = parsed_fmri.version();
|
||||
if !version.is_empty() {
|
||||
index.add_term(&version, &fmri, "pkg", "version", &version, None);
|
||||
index.add_term(
|
||||
&version, &fmri, "pkg", "version", &version, None,
|
||||
);
|
||||
}
|
||||
|
||||
// 4. Index Files with attributes
|
||||
|
|
@ -2975,22 +3059,31 @@ impl FileBackend {
|
|||
let arch_str = match payload.architecture {
|
||||
PayloadArchitecture::I386 => Some("i386"),
|
||||
PayloadArchitecture::SPARC => Some("sparc"),
|
||||
_ => None
|
||||
_ => None,
|
||||
};
|
||||
if let Some(a) = arch_str {
|
||||
attrs.insert("elfarch".to_string(), a.to_string());
|
||||
attrs.insert(
|
||||
"elfarch".to_string(),
|
||||
a.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
let bits_str = match payload.bitness {
|
||||
PayloadBits::Bits64 => Some("64"),
|
||||
PayloadBits::Bits32 => Some("32"),
|
||||
_ => None
|
||||
_ => None,
|
||||
};
|
||||
if let Some(b) = bits_str {
|
||||
attrs.insert("elfbits".to_string(), b.to_string());
|
||||
attrs.insert(
|
||||
"elfbits".to_string(),
|
||||
b.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
attrs.insert("pkg.content-hash".to_string(), payload.primary_identifier.to_string());
|
||||
attrs.insert(
|
||||
"pkg.content-hash".to_string(),
|
||||
payload.primary_identifier.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
for prop in file.properties {
|
||||
|
|
@ -2998,11 +3091,28 @@ impl FileBackend {
|
|||
}
|
||||
|
||||
// index=path
|
||||
index.add_term(&file.path, &fmri, "file", "path", &file.path, Some(attrs.clone()));
|
||||
index.add_term(
|
||||
&file.path,
|
||||
&fmri,
|
||||
"file",
|
||||
"path",
|
||||
&file.path,
|
||||
Some(attrs.clone()),
|
||||
);
|
||||
|
||||
// index=basename
|
||||
if let Some(basename) = Path::new(&file.path).file_name().and_then(|s| s.to_str()) {
|
||||
index.add_term(basename, &fmri, "file", "basename", &file.path, Some(attrs));
|
||||
if let Some(basename) = Path::new(&file.path)
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
{
|
||||
index.add_term(
|
||||
basename,
|
||||
&fmri,
|
||||
"file",
|
||||
"basename",
|
||||
&file.path,
|
||||
Some(attrs),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3015,11 +3125,28 @@ impl FileBackend {
|
|||
attrs.insert("mode".to_string(), dir.mode.clone());
|
||||
|
||||
// index=path
|
||||
index.add_term(&dir.path, &fmri, "dir", "path", &dir.path, Some(attrs.clone()));
|
||||
index.add_term(
|
||||
&dir.path,
|
||||
&fmri,
|
||||
"dir",
|
||||
"path",
|
||||
&dir.path,
|
||||
Some(attrs.clone()),
|
||||
);
|
||||
|
||||
// index=basename
|
||||
if let Some(basename) = Path::new(&dir.path).file_name().and_then(|s| s.to_str()) {
|
||||
index.add_term(basename, &fmri, "dir", "basename", &dir.path, Some(attrs));
|
||||
if let Some(basename) = Path::new(&dir.path)
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
{
|
||||
index.add_term(
|
||||
basename,
|
||||
&fmri,
|
||||
"dir",
|
||||
"basename",
|
||||
&dir.path,
|
||||
Some(attrs),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3030,15 +3157,32 @@ impl FileBackend {
|
|||
let mut attrs = BTreeMap::new();
|
||||
|
||||
if !dep.dependency_type.is_empty() {
|
||||
attrs.insert("type".to_string(), dep.dependency_type.clone());
|
||||
attrs.insert(
|
||||
"type".to_string(),
|
||||
dep.dependency_type.clone(),
|
||||
);
|
||||
}
|
||||
|
||||
for prop in dep.optional {
|
||||
attrs.insert(prop.key, prop.value);
|
||||
}
|
||||
|
||||
index.add_term(&dep_fmri_str, &fmri, "depend", "fmri", &dep_fmri_str, Some(attrs.clone()));
|
||||
index.add_term(dep_fmri.stem(), &fmri, "depend", "fmri", &dep_fmri_str, Some(attrs));
|
||||
index.add_term(
|
||||
&dep_fmri_str,
|
||||
&fmri,
|
||||
"depend",
|
||||
"fmri",
|
||||
&dep_fmri_str,
|
||||
Some(attrs.clone()),
|
||||
);
|
||||
index.add_term(
|
||||
dep_fmri.stem(),
|
||||
&fmri,
|
||||
"depend",
|
||||
"fmri",
|
||||
&dep_fmri_str,
|
||||
Some(attrs),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3101,7 +3245,10 @@ impl FileBackend {
|
|||
let entries = index.search(query, case_sensitive, limit);
|
||||
results.extend(entries);
|
||||
} else {
|
||||
debug!("No search index found for publisher: {}, falling back to simple listing", pub_name);
|
||||
debug!(
|
||||
"No search index found for publisher: {}, falling back to simple listing",
|
||||
pub_name
|
||||
);
|
||||
// Fallback: list packages and convert to basic IndexEntries
|
||||
let all_packages = self.list_packages(Some(&pub_name), None)?;
|
||||
let matching_packages: Vec<IndexEntry> = all_packages
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ pub mod file;
|
|||
pub mod info;
|
||||
pub mod manifest;
|
||||
pub mod publisher;
|
||||
pub mod versions;
|
||||
pub mod search;
|
||||
pub mod versions;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@ pub async fn get_search_v0(
|
|||
));
|
||||
}
|
||||
|
||||
Ok((
|
||||
[(axum::http::header::CONTENT_TYPE, "text/plain")],
|
||||
body,
|
||||
)
|
||||
.into_response())
|
||||
Ok(([(axum::http::header::CONTENT_TYPE, "text/plain")], body).into_response())
|
||||
}
|
||||
|
||||
pub async fn get_search_v1(
|
||||
|
|
@ -81,7 +77,13 @@ pub async fn get_search_v1(
|
|||
fn split_v1_token(token: &str) -> Option<(&str, &str)> {
|
||||
// Try to find the 4th underscore
|
||||
let mut parts = token.splitn(5, '_');
|
||||
if let (Some(_), Some(_), Some(_), Some(_), Some(_)) = (parts.next(), parts.next(), parts.next(), parts.next(), parts.next()) {
|
||||
if let (Some(_), Some(_), Some(_), Some(_), Some(_)) = (
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
parts.next(),
|
||||
) {
|
||||
// We found 4 parts and a remainder.
|
||||
// We need to reconstruct where the split happened to return slices
|
||||
// Actually, splitn(5) returns 5 parts. The last part is the remainder.
|
||||
|
|
@ -100,4 +102,3 @@ fn split_v1_token(token: &str) -> Option<(&str, &str)> {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::config::Config;
|
||||
use crate::errors::{DepotError, Result};
|
||||
use libips::fmri::Fmri;
|
||||
use libips::repository::{FileBackend, ReadableRepository, IndexEntry};
|
||||
use libips::repository::{FileBackend, IndexEntry, ReadableRepository};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Mutex;
|
||||
|
||||
|
|
@ -23,7 +23,12 @@ impl DepotRepo {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn search(&self, publisher: Option<&str>, query: &str, case_sensitive: bool) -> Result<Vec<IndexEntry>> {
|
||||
pub fn search(
|
||||
&self,
|
||||
publisher: Option<&str>,
|
||||
query: &str,
|
||||
case_sensitive: bool,
|
||||
) -> Result<Vec<IndexEntry>> {
|
||||
let backend = self
|
||||
.backend
|
||||
.lock()
|
||||
|
|
|
|||
|
|
@ -378,6 +378,10 @@ async fn test_file_url_without_algo() {
|
|||
|
||||
let resp = client.get(&url).send().await.unwrap();
|
||||
|
||||
assert_eq!(resp.status(), 200, "Should handle file URL without algorithm");
|
||||
assert_eq!(
|
||||
resp.status(),
|
||||
200,
|
||||
"Should handle file URL without algorithm"
|
||||
);
|
||||
let _content = resp.text().await.unwrap();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue