mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 13:20:42 +00:00
Refactor FileBackend for improved manifest handling and directory structure
- Extract manifest path construction and recursive manifest search into helper methods (`construct_manifest_path` and `find_manifests_recursive`). - Enhance package information extraction by separating stem and version details from FMRI. - Adjust directory creation logic to include per-package subdirectories for better organization. - Simplify and centralize manifest parsing logic, improving error handling and maintainability.
This commit is contained in:
parent
f4d1ce73b6
commit
abb997df43
1 changed files with 155 additions and 109 deletions
|
|
@ -440,13 +440,16 @@ impl Transaction {
|
|||
}
|
||||
}
|
||||
|
||||
// Extract package name from manifest
|
||||
let mut package_name = String::from("unknown");
|
||||
// Extract package information from manifest
|
||||
let mut package_stem = String::from("unknown");
|
||||
let mut package_version = String::from("");
|
||||
for attr in &self.manifest.attributes {
|
||||
if attr.key == "pkg.fmri" && !attr.values.is_empty() {
|
||||
if let Ok(fmri) = Fmri::parse(&attr.values[0]) {
|
||||
package_name = fmri.name.to_string();
|
||||
debug!("Extracted package name from FMRI: {}", package_name);
|
||||
package_stem = fmri.stem().to_string();
|
||||
package_version = fmri.version();
|
||||
debug!("Extracted package stem from FMRI: {}", package_stem);
|
||||
debug!("Extracted package version from FMRI: {}", package_version);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -486,16 +489,16 @@ impl Transaction {
|
|||
}
|
||||
};
|
||||
|
||||
// Create a publisher directory if it doesn't exist
|
||||
let publisher_dir = self.repo.join("pkg").join(&publisher);
|
||||
debug!("Publisher directory: {}", publisher_dir.display());
|
||||
if !publisher_dir.exists() {
|
||||
debug!("Creating publisher directory");
|
||||
fs::create_dir_all(&publisher_dir)?;
|
||||
// Create the package directory if it doesn't exist
|
||||
let pkg_dir = self.repo.join("pkg").join(&publisher).join(&package_stem);
|
||||
debug!("Package directory: {}", pkg_dir.display());
|
||||
if !pkg_dir.exists() {
|
||||
debug!("Creating package directory");
|
||||
fs::create_dir_all(&pkg_dir)?;
|
||||
}
|
||||
|
||||
// Store in publisher-specific directory with package name
|
||||
let pkg_manifest_path = publisher_dir.join(format!("{}.manifest", package_name));
|
||||
// Construct the manifest path using the helper method
|
||||
let pkg_manifest_path = FileBackend::construct_manifest_path(&self.repo, &publisher, &package_stem, &package_version);
|
||||
debug!("Manifest path: {}", pkg_manifest_path.display());
|
||||
|
||||
// Create parent directories if they don't exist
|
||||
|
|
@ -655,95 +658,10 @@ impl ReadableRepository for FileBackend {
|
|||
));
|
||||
}
|
||||
|
||||
// Walk through the directory and collect package manifests
|
||||
if let Ok(entries) = fs::read_dir(&publisher_pkg_dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
|
||||
// Skip directories, only process files with .manifest extension
|
||||
if path.is_file() && path.extension().map_or(false, |ext| ext == "manifest")
|
||||
{
|
||||
// Parse the manifest file to get real package information
|
||||
match Manifest::parse_file(&path) {
|
||||
Ok(manifest) => {
|
||||
// Look for the pkg.fmri attribute
|
||||
for attr in &manifest.attributes {
|
||||
if attr.key == "pkg.fmri" && !attr.values.is_empty() {
|
||||
let fmri = &attr.values[0];
|
||||
|
||||
// Parse the FMRI using our Fmri type
|
||||
match Fmri::parse(fmri) {
|
||||
Ok(parsed_fmri) => {
|
||||
// Filter by pattern if specified
|
||||
if let Some(pat) = pattern {
|
||||
// Try to compile the pattern as a regex
|
||||
match Regex::new(pat) {
|
||||
Ok(regex) => {
|
||||
// Use regex matching
|
||||
if !regex
|
||||
.is_match(parsed_fmri.stem())
|
||||
{
|
||||
continue;
|
||||
// Recursively walk through the directory and collect package manifests
|
||||
self.find_manifests_recursive(&publisher_pkg_dir, &pub_name, pattern, &mut packages)?;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// Log the error but fall back to the simple string contains
|
||||
error!("FileBackend::list_packages: Error compiling regex pattern '{}': {}", pat, err);
|
||||
if !parsed_fmri.stem().contains(pat)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the publisher is not set in the FMRI, use the current publisher
|
||||
if parsed_fmri.publisher.is_none() {
|
||||
let mut fmri_with_publisher =
|
||||
parsed_fmri.clone();
|
||||
fmri_with_publisher.publisher =
|
||||
Some(pub_name.clone());
|
||||
|
||||
// Create a PackageInfo struct and add it to the list
|
||||
packages.push(PackageInfo {
|
||||
fmri: fmri_with_publisher,
|
||||
});
|
||||
} else {
|
||||
// Create a PackageInfo struct and add it to the list
|
||||
packages.push(PackageInfo {
|
||||
fmri: parsed_fmri.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// Found the package info, no need to check other attributes
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
// Log the error but continue processing
|
||||
error!(
|
||||
"FileBackend::list_packages: Error parsing FMRI '{}': {}",
|
||||
fmri, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// Log the error but continue processing other files
|
||||
error!(
|
||||
"FileBackend::list_packages: Error parsing manifest file {}: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// No else clause - we don't return placeholder data anymore
|
||||
}
|
||||
|
||||
Ok(packages)
|
||||
}
|
||||
|
|
@ -1308,6 +1226,129 @@ impl WritableRepository for FileBackend {
|
|||
}
|
||||
|
||||
impl FileBackend {
|
||||
/// Helper method to construct a manifest path consistently
|
||||
fn construct_manifest_path(base_path: &Path, publisher: &str, stem: &str, version: &str) -> PathBuf {
|
||||
let pkg_dir = base_path.join("pkg").join(publisher).join(stem);
|
||||
let encoded_version = Self::url_encode(version);
|
||||
pkg_dir.join(encoded_version)
|
||||
}
|
||||
|
||||
/// Recursively find manifest files in a directory and its subdirectories
|
||||
fn find_manifests_recursive(
|
||||
&self,
|
||||
dir: &Path,
|
||||
publisher: &str,
|
||||
pattern: Option<&str>,
|
||||
packages: &mut Vec<PackageInfo>,
|
||||
) -> Result<()> {
|
||||
if let Ok(entries) = fs::read_dir(dir) {
|
||||
for entry in entries.flatten() {
|
||||
let path = entry.path();
|
||||
|
||||
if path.is_dir() {
|
||||
// Recursively search subdirectories
|
||||
self.find_manifests_recursive(&path, publisher, pattern, packages)?;
|
||||
} else if path.is_file() {
|
||||
// Try to read the first few bytes of the file to check if it's a manifest file
|
||||
let mut file = match fs::File::open(&path) {
|
||||
Ok(file) => file,
|
||||
Err(err) => {
|
||||
error!("FileBackend::find_manifests_recursive: Error opening file {}: {}", path.display(), err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
let mut buffer = [0; 1024];
|
||||
let bytes_read = match file.read(&mut buffer) {
|
||||
Ok(bytes) => bytes,
|
||||
Err(err) => {
|
||||
error!("FileBackend::find_manifests_recursive: Error reading file {}: {}", path.display(), err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// Check if the file starts with a valid manifest marker
|
||||
// For example, if it's a JSON file, it should start with '{'
|
||||
if bytes_read == 0 || (buffer[0] != b'{' && buffer[0] != b'<' && buffer[0] != b's') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process manifest files
|
||||
match Manifest::parse_file(&path) {
|
||||
Ok(manifest) => {
|
||||
// Look for the pkg.fmri attribute
|
||||
for attr in &manifest.attributes {
|
||||
if attr.key == "pkg.fmri" && !attr.values.is_empty() {
|
||||
let fmri = &attr.values[0];
|
||||
|
||||
// Parse the FMRI using our Fmri type
|
||||
match Fmri::parse(fmri) {
|
||||
Ok(parsed_fmri) => {
|
||||
// Filter by pattern if specified
|
||||
if let Some(pat) = pattern {
|
||||
// Try to compile the pattern as a regex
|
||||
match Regex::new(pat) {
|
||||
Ok(regex) => {
|
||||
// Use regex matching
|
||||
if !regex.is_match(parsed_fmri.stem()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// Log the error but fall back to the simple string contains
|
||||
error!("FileBackend::find_manifests_recursive: Error compiling regex pattern '{}': {}", pat, err);
|
||||
if !parsed_fmri.stem().contains(pat) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the publisher is not set in the FMRI, use the current publisher
|
||||
if parsed_fmri.publisher.is_none() {
|
||||
let mut fmri_with_publisher = parsed_fmri.clone();
|
||||
fmri_with_publisher.publisher = Some(publisher.to_string());
|
||||
|
||||
// Create a PackageInfo struct and add it to the list
|
||||
packages.push(PackageInfo {
|
||||
fmri: fmri_with_publisher,
|
||||
});
|
||||
} else {
|
||||
// Create a PackageInfo struct and add it to the list
|
||||
packages.push(PackageInfo {
|
||||
fmri: parsed_fmri.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
// Found the package info, no need to check other attributes
|
||||
break;
|
||||
}
|
||||
Err(err) => {
|
||||
// Log the error but continue processing
|
||||
error!(
|
||||
"FileBackend::find_manifests_recursive: Error parsing FMRI '{}': {}",
|
||||
fmri, err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
// Log the error but continue processing other files
|
||||
error!(
|
||||
"FileBackend::find_manifests_recursive: Error parsing manifest file {}: {}",
|
||||
path.display(),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
/// Create the repository directories
|
||||
fn create_directories(&self) -> Result<()> {
|
||||
// Create the main repository directories
|
||||
|
|
@ -1357,24 +1398,29 @@ impl FileBackend {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Get the package manifest
|
||||
let pkg_dir = self.path.join("pkg").join(publisher).join(stem);
|
||||
if !pkg_dir.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the package version
|
||||
let version = fmri.version();
|
||||
let encoded_version = Self::url_encode(&version);
|
||||
let manifest_path = pkg_dir.join(encoded_version);
|
||||
|
||||
// Construct the manifest path using the helper method
|
||||
let manifest_path = Self::construct_manifest_path(&self.path, publisher, stem, &version);
|
||||
|
||||
// Check if the package directory exists
|
||||
if let Some(pkg_dir) = manifest_path.parent() {
|
||||
if !pkg_dir.exists() {
|
||||
error!("Package directory {} does not exist skipping", pkg_dir.display());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if !manifest_path.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the manifest
|
||||
// Read the manifest content for hash calculation
|
||||
let manifest_content = fs::read_to_string(&manifest_path)?;
|
||||
let manifest = Manifest::parse_string(manifest_content.clone())?;
|
||||
|
||||
// Parse the manifest using parse_file which handles JSON correctly
|
||||
let manifest = Manifest::parse_file(&manifest_path)?;
|
||||
|
||||
// Calculate SHA-256 hash of the manifest (as a substitute for SHA-1)
|
||||
let mut hasher = sha2::Sha256::new();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue