mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 21:30:41 +00:00
Add support for partial image creation and improve logging
- Introduced the `ImageType` enum to support both `Full` and `Partial` image types during creation. - Updated `Image::create_image` to accept `ImageType` as a parameter. - Enhanced logging with detailed debug statements for catalog building, image queries, and package processing. - Refactored CLI to include a new `--type` option for specifying image type during image creation. - Simplified path determination logic in `pkg6` with a new `determine_image_path` helper function. - Removed unused imports and unnecessary file checks for cleaner code.
This commit is contained in:
parent
e27cd35d8d
commit
f31d2e11af
6 changed files with 198 additions and 54 deletions
|
|
@ -119,53 +119,79 @@ impl ImageCatalog {
|
||||||
|
|
||||||
/// Build the catalog from downloaded catalogs
|
/// Build the catalog from downloaded catalogs
|
||||||
pub fn build_catalog(&self, publishers: &[String]) -> Result<()> {
|
pub fn build_catalog(&self, publishers: &[String]) -> Result<()> {
|
||||||
|
println!("Building catalog with publishers: {:?}", publishers);
|
||||||
|
println!("Catalog directory: {:?}", self.catalog_dir);
|
||||||
|
println!("Catalog database path: {:?}", self.db_path);
|
||||||
|
|
||||||
if publishers.is_empty() {
|
if publishers.is_empty() {
|
||||||
|
println!("No publishers provided");
|
||||||
return Err(CatalogError::NoPublishers);
|
return Err(CatalogError::NoPublishers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open the database
|
// Open the database
|
||||||
|
println!("Opening database at {:?}", self.db_path);
|
||||||
let db = Database::open(&self.db_path)
|
let db = Database::open(&self.db_path)
|
||||||
.map_err(|e| CatalogError::Database(format!("Failed to open database: {}", e)))?;
|
.map_err(|e| CatalogError::Database(format!("Failed to open database: {}", e)))?;
|
||||||
|
|
||||||
// Begin a writing transaction
|
// Begin a writing transaction
|
||||||
|
println!("Beginning write transaction");
|
||||||
let tx = db.begin_write()
|
let tx = db.begin_write()
|
||||||
.map_err(|e| CatalogError::Database(format!("Failed to begin transaction: {}", e)))?;
|
.map_err(|e| CatalogError::Database(format!("Failed to begin transaction: {}", e)))?;
|
||||||
|
|
||||||
// Open the catalog table
|
// Open the catalog table
|
||||||
|
println!("Opening catalog table");
|
||||||
let mut catalog_table = tx.open_table(CATALOG_TABLE)
|
let mut catalog_table = tx.open_table(CATALOG_TABLE)
|
||||||
.map_err(|e| CatalogError::Database(format!("Failed to open catalog table: {}", e)))?;
|
.map_err(|e| CatalogError::Database(format!("Failed to open catalog table: {}", e)))?;
|
||||||
|
|
||||||
// Open the obsoleted table
|
// Open the obsoleted table
|
||||||
|
println!("Opening obsoleted table");
|
||||||
let mut obsoleted_table = tx.open_table(OBSOLETED_TABLE)
|
let mut obsoleted_table = tx.open_table(OBSOLETED_TABLE)
|
||||||
.map_err(|e| CatalogError::Database(format!("Failed to open obsoleted table: {}", e)))?;
|
.map_err(|e| CatalogError::Database(format!("Failed to open obsoleted table: {}", e)))?;
|
||||||
|
|
||||||
// Process each publisher
|
// Process each publisher
|
||||||
for publisher in publishers {
|
for publisher in publishers {
|
||||||
|
println!("Processing publisher: {}", publisher);
|
||||||
let publisher_catalog_dir = self.catalog_dir.join(publisher);
|
let publisher_catalog_dir = self.catalog_dir.join(publisher);
|
||||||
|
println!("Publisher catalog directory: {:?}", publisher_catalog_dir);
|
||||||
|
|
||||||
// Skip if the publisher catalog directory doesn't exist
|
// Skip if the publisher catalog directory doesn't exist
|
||||||
if !publisher_catalog_dir.exists() {
|
if !publisher_catalog_dir.exists() {
|
||||||
|
println!("Publisher catalog directory not found: {}", publisher_catalog_dir.display());
|
||||||
warn!("Publisher catalog directory not found: {}", publisher_catalog_dir.display());
|
warn!("Publisher catalog directory not found: {}", publisher_catalog_dir.display());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a catalog manager for this publisher
|
// Create a catalog manager for this publisher
|
||||||
|
println!("Creating catalog manager for publisher: {}", publisher);
|
||||||
let mut catalog_manager = CatalogManager::new(&publisher_catalog_dir, publisher)
|
let mut catalog_manager = CatalogManager::new(&publisher_catalog_dir, publisher)
|
||||||
.map_err(|e| CatalogError::Repository(crate::repository::RepositoryError::Other(format!("Failed to create catalog manager: {}", e))))?;
|
.map_err(|e| CatalogError::Repository(crate::repository::RepositoryError::Other(format!("Failed to create catalog manager: {}", e))))?;
|
||||||
|
|
||||||
// Get all catalog parts
|
// Get all catalog parts
|
||||||
|
println!("Getting catalog parts for publisher: {}", publisher);
|
||||||
let parts = catalog_manager.attrs().parts.clone();
|
let parts = catalog_manager.attrs().parts.clone();
|
||||||
|
println!("Catalog parts: {:?}", parts.keys().collect::<Vec<_>>());
|
||||||
|
|
||||||
// Load all catalog parts
|
// Load all catalog parts
|
||||||
for part_name in parts.keys() {
|
for part_name in parts.keys() {
|
||||||
|
println!("Loading catalog part: {}", part_name);
|
||||||
catalog_manager.load_part(part_name)
|
catalog_manager.load_part(part_name)
|
||||||
.map_err(|e| CatalogError::Repository(crate::repository::RepositoryError::Other(format!("Failed to load catalog part: {}", e))))?;
|
.map_err(|e| CatalogError::Repository(crate::repository::RepositoryError::Other(format!("Failed to load catalog part: {}", e))))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each catalog part
|
// Process each catalog part
|
||||||
for (part_name, _) in parts {
|
for (part_name, _) in parts {
|
||||||
|
println!("Processing catalog part: {}", part_name);
|
||||||
if let Some(part) = catalog_manager.get_part(&part_name) {
|
if let Some(part) = catalog_manager.get_part(&part_name) {
|
||||||
|
println!("Found catalog part: {}", part_name);
|
||||||
|
println!("Packages in part: {:?}", part.packages.keys().collect::<Vec<_>>());
|
||||||
|
if let Some(publisher_packages) = part.packages.get(publisher) {
|
||||||
|
println!("Packages for publisher {}: {:?}", publisher, publisher_packages.keys().collect::<Vec<_>>());
|
||||||
|
} else {
|
||||||
|
println!("No packages found for publisher: {}", publisher);
|
||||||
|
}
|
||||||
self.process_catalog_part(&mut catalog_table, &mut obsoleted_table, part, publisher)?;
|
self.process_catalog_part(&mut catalog_table, &mut obsoleted_table, part, publisher)?;
|
||||||
|
} else {
|
||||||
|
println!("Catalog part not found: {}", part_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -190,70 +216,109 @@ impl ImageCatalog {
|
||||||
part: &CatalogPart,
|
part: &CatalogPart,
|
||||||
publisher: &str,
|
publisher: &str,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
println!("Processing catalog part for publisher: {}", publisher);
|
||||||
|
|
||||||
// Get packages for this publisher
|
// Get packages for this publisher
|
||||||
if let Some(publisher_packages) = part.packages.get(publisher) {
|
if let Some(publisher_packages) = part.packages.get(publisher) {
|
||||||
|
println!("Found {} package stems for publisher {}", publisher_packages.len(), publisher);
|
||||||
|
|
||||||
// Process each package stem
|
// Process each package stem
|
||||||
for (stem, versions) in publisher_packages {
|
for (stem, versions) in publisher_packages {
|
||||||
|
println!("Processing package stem: {}", stem);
|
||||||
|
println!("Found {} versions for stem {}", versions.len(), stem);
|
||||||
|
|
||||||
// Process each package version
|
// Process each package version
|
||||||
for version_entry in versions {
|
for version_entry in versions {
|
||||||
|
println!("Processing version: {}", version_entry.version);
|
||||||
|
println!("Actions: {:?}", version_entry.actions);
|
||||||
|
|
||||||
// Create the FMRI
|
// Create the FMRI
|
||||||
let version = if !version_entry.version.is_empty() {
|
let version = if !version_entry.version.is_empty() {
|
||||||
match crate::fmri::Version::parse(&version_entry.version) {
|
match crate::fmri::Version::parse(&version_entry.version) {
|
||||||
Ok(v) => Some(v),
|
Ok(v) => {
|
||||||
|
println!("Parsed version: {:?}", v);
|
||||||
|
Some(v)
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
println!("Failed to parse version '{}': {}", version_entry.version, e);
|
||||||
warn!("Failed to parse version '{}': {}", version_entry.version, e);
|
warn!("Failed to parse version '{}': {}", version_entry.version, e);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
println!("Empty version string");
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let fmri = Fmri::with_publisher(publisher, stem, version);
|
let fmri = Fmri::with_publisher(publisher, stem, version);
|
||||||
|
println!("Created FMRI: {}", fmri);
|
||||||
|
|
||||||
// Create the key for the catalog table (stem@version)
|
// Create the key for the catalog table (stem@version)
|
||||||
let catalog_key = format!("{}@{}", stem, version_entry.version);
|
let catalog_key = format!("{}@{}", stem, version_entry.version);
|
||||||
|
println!("Catalog key: {}", catalog_key);
|
||||||
|
|
||||||
// Create the key for the obsoleted table (full FMRI including publisher)
|
// Create the key for the obsoleted table (full FMRI including publisher)
|
||||||
let obsoleted_key = fmri.to_string();
|
let obsoleted_key = fmri.to_string();
|
||||||
|
println!("Obsoleted key: {}", obsoleted_key);
|
||||||
|
|
||||||
// Check if we already have this package in the catalog
|
// Check if we already have this package in the catalog
|
||||||
let existing_manifest = if let Ok(bytes) = catalog_table.get(catalog_key.as_str()) {
|
let existing_manifest = if let Ok(bytes) = catalog_table.get(catalog_key.as_str()) {
|
||||||
if let Some(bytes) = bytes {
|
if let Some(bytes) = bytes {
|
||||||
|
println!("Found existing manifest for {}", catalog_key);
|
||||||
Some(serde_json::from_slice::<Manifest>(bytes.value())?)
|
Some(serde_json::from_slice::<Manifest>(bytes.value())?)
|
||||||
} else {
|
} else {
|
||||||
|
println!("No existing manifest found for {}", catalog_key);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
println!("Error getting manifest for {}", catalog_key);
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create or update the manifest
|
// Create or update the manifest
|
||||||
|
println!("Creating or updating manifest");
|
||||||
let manifest = self.create_or_update_manifest(existing_manifest, version_entry, stem, publisher)?;
|
let manifest = self.create_or_update_manifest(existing_manifest, version_entry, stem, publisher)?;
|
||||||
|
|
||||||
// Check if the package is obsolete
|
// Check if the package is obsolete
|
||||||
let is_obsolete = self.is_package_obsolete(&manifest);
|
let is_obsolete = self.is_package_obsolete(&manifest);
|
||||||
|
println!("Package is obsolete: {}", is_obsolete);
|
||||||
|
|
||||||
// Serialize the manifest
|
// Serialize the manifest
|
||||||
let manifest_bytes = serde_json::to_vec(&manifest)?;
|
let manifest_bytes = serde_json::to_vec(&manifest)?;
|
||||||
|
println!("Serialized manifest size: {} bytes", manifest_bytes.len());
|
||||||
|
|
||||||
// Store the package in the appropriate table
|
// Store the package in the appropriate table
|
||||||
if is_obsolete {
|
if is_obsolete {
|
||||||
|
println!("Storing obsolete package in obsoleted table");
|
||||||
// Store obsolete packages in the obsoleted table with the full FMRI as key
|
// Store obsolete packages in the obsoleted table with the full FMRI as key
|
||||||
// We don't store any meaningful values in the obsoleted table as per requirements,
|
// We don't store any meaningful values in the obsoleted table as per requirements,
|
||||||
// but we need to provide a valid byte slice
|
// but we need to provide a valid byte slice
|
||||||
let empty_bytes: &[u8] = &[0u8; 0];
|
let empty_bytes: &[u8] = &[0u8; 0];
|
||||||
obsoleted_table.insert(obsoleted_key.as_str(), empty_bytes)
|
match obsoleted_table.insert(obsoleted_key.as_str(), empty_bytes) {
|
||||||
.map_err(|e| CatalogError::Database(format!("Failed to insert into obsoleted table: {}", e)))?;
|
Ok(_) => println!("Successfully inserted into obsoleted table"),
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to insert into obsoleted table: {}", e);
|
||||||
|
return Err(CatalogError::Database(format!("Failed to insert into obsoleted table: {}", e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
println!("Storing non-obsolete package in catalog table");
|
||||||
// Store non-obsolete packages in the catalog table with stem@version as a key
|
// Store non-obsolete packages in the catalog table with stem@version as a key
|
||||||
catalog_table.insert(catalog_key.as_str(), manifest_bytes.as_slice())
|
match catalog_table.insert(catalog_key.as_str(), manifest_bytes.as_slice()) {
|
||||||
.map_err(|e| CatalogError::Database(format!("Failed to insert into catalog table: {}", e)))?;
|
Ok(_) => println!("Successfully inserted into catalog table"),
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to insert into catalog table: {}", e);
|
||||||
|
return Err(CatalogError::Database(format!("Failed to insert into catalog table: {}", e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
println!("No packages found for publisher: {}", publisher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
println!("Finished processing catalog part for publisher: {}", publisher);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::actions::{Attr, Manifest};
|
use crate::actions::{Attr, Manifest};
|
||||||
use crate::fmri::Fmri;
|
use crate::fmri::Fmri;
|
||||||
use redb::ReadableTable;
|
use redb::{Database, ReadableTable};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ fn test_installed_packages() {
|
||||||
let image_path = temp_dir.path().join("image");
|
let image_path = temp_dir.path().join("image");
|
||||||
|
|
||||||
// Create the image
|
// Create the image
|
||||||
let image = Image::create_image(&image_path).unwrap();
|
let image = Image::create_image(&image_path, ImageType::Full).unwrap();
|
||||||
|
|
||||||
// Verify that the installed packages database was initialized
|
// Verify that the installed packages database was initialized
|
||||||
assert!(image.installed_db_path().exists());
|
assert!(image.installed_db_path().exists());
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ mod tests;
|
||||||
|
|
||||||
use miette::Diagnostic;
|
use miette::Diagnostic;
|
||||||
use properties::*;
|
use properties::*;
|
||||||
use redb::Database;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
|
|
@ -455,9 +454,17 @@ impl Image {
|
||||||
///
|
///
|
||||||
/// This method only creates the image structure without adding publishers or downloading catalogs.
|
/// This method only creates the image structure without adding publishers or downloading catalogs.
|
||||||
/// Publisher addition and catalog downloading should be handled separately.
|
/// Publisher addition and catalog downloading should be handled separately.
|
||||||
pub fn create_image<P: AsRef<Path>>(path: P) -> Result<Self> {
|
///
|
||||||
// Create a new image
|
/// # Arguments
|
||||||
let image = Image::new_full(path.as_ref().to_path_buf());
|
///
|
||||||
|
/// * `path` - The path where the image will be created
|
||||||
|
/// * `image_type` - The type of image to create (Full or Partial)
|
||||||
|
pub fn create_image<P: AsRef<Path>>(path: P, image_type: ImageType) -> Result<Self> {
|
||||||
|
// Create a new image based on the specified type
|
||||||
|
let image = match image_type {
|
||||||
|
ImageType::Full => Image::new_full(path.as_ref().to_path_buf()),
|
||||||
|
ImageType::Partial => Image::new_partial(path.as_ref().to_path_buf()),
|
||||||
|
};
|
||||||
|
|
||||||
// Create the directory structure
|
// Create the directory structure
|
||||||
image.create_metadata_dir()?;
|
image.create_metadata_dir()?;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ fn test_image_catalog() {
|
||||||
let image_path = temp_dir.path().join("image");
|
let image_path = temp_dir.path().join("image");
|
||||||
|
|
||||||
// Create the image
|
// Create the image
|
||||||
let image = Image::create_image(&image_path).unwrap();
|
let image = Image::create_image(&image_path, ImageType::Full).unwrap();
|
||||||
|
|
||||||
// Verify that the catalog database was initialized
|
// Verify that the catalog database was initialized
|
||||||
assert!(image.catalog_db_path().exists());
|
assert!(image.catalog_db_path().exists());
|
||||||
|
|
@ -25,14 +25,24 @@ fn test_catalog_methods() {
|
||||||
let image_path = temp_dir.path().join("image");
|
let image_path = temp_dir.path().join("image");
|
||||||
|
|
||||||
// Create the image
|
// Create the image
|
||||||
let mut image = Image::create_image(&image_path).unwrap();
|
let mut image = Image::create_image(&image_path, ImageType::Full).unwrap();
|
||||||
|
|
||||||
|
// Print the image type and paths
|
||||||
|
println!("Image type: {:?}", image.image_type());
|
||||||
|
println!("Image path: {:?}", image.path());
|
||||||
|
println!("Metadata dir: {:?}", image.metadata_dir());
|
||||||
|
println!("Catalog dir: {:?}", image.catalog_dir());
|
||||||
|
|
||||||
// Add a publisher
|
// Add a publisher
|
||||||
image.add_publisher("test", "http://example.com/repo", vec![], true).unwrap();
|
image.add_publisher("test", "http://example.com/repo", vec![], true).unwrap();
|
||||||
|
|
||||||
|
// Print the publishers
|
||||||
|
println!("Publishers: {:?}", image.publishers());
|
||||||
|
|
||||||
// Create the catalog directory structure
|
// Create the catalog directory structure
|
||||||
let catalog_dir = image.catalog_dir();
|
let catalog_dir = image.catalog_dir();
|
||||||
let publisher_dir = catalog_dir.join("test");
|
let publisher_dir = catalog_dir.join("test");
|
||||||
|
println!("Publisher dir: {:?}", publisher_dir);
|
||||||
fs::create_dir_all(&publisher_dir).unwrap();
|
fs::create_dir_all(&publisher_dir).unwrap();
|
||||||
|
|
||||||
// Create a simple catalog.attrs file
|
// Create a simple catalog.attrs file
|
||||||
|
|
@ -42,6 +52,8 @@ fn test_catalog_methods() {
|
||||||
},
|
},
|
||||||
"version": 1
|
"version": 1
|
||||||
}"#;
|
}"#;
|
||||||
|
println!("Writing catalog.attrs to {:?}", publisher_dir.join("catalog.attrs"));
|
||||||
|
println!("catalog.attrs content: {}", attrs_content);
|
||||||
fs::write(publisher_dir.join("catalog.attrs"), attrs_content).unwrap();
|
fs::write(publisher_dir.join("catalog.attrs"), attrs_content).unwrap();
|
||||||
|
|
||||||
// Create a simple base catalog part
|
// Create a simple base catalog part
|
||||||
|
|
@ -71,13 +83,33 @@ fn test_catalog_methods() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}"#;
|
}"#;
|
||||||
|
println!("Writing base catalog part to {:?}", publisher_dir.join("base"));
|
||||||
|
println!("base catalog part content: {}", base_content);
|
||||||
fs::write(publisher_dir.join("base"), base_content).unwrap();
|
fs::write(publisher_dir.join("base"), base_content).unwrap();
|
||||||
|
|
||||||
|
// Verify that the files were written correctly
|
||||||
|
println!("Checking if catalog.attrs exists: {}", publisher_dir.join("catalog.attrs").exists());
|
||||||
|
println!("Checking if base catalog part exists: {}", publisher_dir.join("base").exists());
|
||||||
|
|
||||||
// Build the catalog
|
// Build the catalog
|
||||||
image.build_catalog().unwrap();
|
println!("Building catalog...");
|
||||||
|
match image.build_catalog() {
|
||||||
|
Ok(_) => println!("Catalog built successfully"),
|
||||||
|
Err(e) => println!("Failed to build catalog: {:?}", e),
|
||||||
|
}
|
||||||
|
|
||||||
// Query the catalog
|
// Query the catalog
|
||||||
let packages = image.query_catalog(None).unwrap();
|
println!("Querying catalog...");
|
||||||
|
let packages = match image.query_catalog(None) {
|
||||||
|
Ok(pkgs) => {
|
||||||
|
println!("Found {} packages", pkgs.len());
|
||||||
|
pkgs
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
println!("Failed to query catalog: {:?}", e);
|
||||||
|
panic!("Failed to query catalog: {:?}", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Verify that both non-obsolete and obsolete packages are in the results
|
// Verify that both non-obsolete and obsolete packages are in the results
|
||||||
assert_eq!(packages.len(), 2);
|
assert_eq!(packages.len(), 2);
|
||||||
|
|
|
||||||
|
|
@ -396,8 +396,7 @@ pub struct CatalogManager {
|
||||||
impl CatalogManager {
|
impl CatalogManager {
|
||||||
/// Create a new catalog manager
|
/// Create a new catalog manager
|
||||||
pub fn new<P: AsRef<Path>>(base_dir: P, publisher: &str) -> Result<Self> {
|
pub fn new<P: AsRef<Path>>(base_dir: P, publisher: &str) -> Result<Self> {
|
||||||
let base_dir = base_dir.as_ref().to_path_buf();
|
let publisher_catalog_dir = base_dir.as_ref().to_path_buf();
|
||||||
let publisher_catalog_dir = base_dir.join(publisher).join("catalog");
|
|
||||||
|
|
||||||
// Create catalog directory if it doesn't exist
|
// Create catalog directory if it doesn't exist
|
||||||
if !publisher_catalog_dir.exists() {
|
if !publisher_catalog_dir.exists() {
|
||||||
|
|
|
||||||
115
pkg6/src/main.rs
115
pkg6/src/main.rs
|
|
@ -2,8 +2,6 @@ mod error;
|
||||||
use error::{Pkg6Error, Result};
|
use error::{Pkg6Error, Result};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use libips::fmri::Fmri;
|
|
||||||
use libips::image::Publisher;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
@ -39,6 +37,14 @@ struct PublisherOutput {
|
||||||
#[clap(author, version, about, long_about = None)]
|
#[clap(author, version, about, long_about = None)]
|
||||||
#[clap(propagate_version = true)]
|
#[clap(propagate_version = true)]
|
||||||
struct App {
|
struct App {
|
||||||
|
/// Path to the image to operate on
|
||||||
|
///
|
||||||
|
/// If not specified, the default image is determined as follows:
|
||||||
|
/// - If $HOME/.pkg exists, that directory is used
|
||||||
|
/// - Otherwise, the root directory (/) is used
|
||||||
|
#[clap(short = 'R', global = true)]
|
||||||
|
image_path: Option<PathBuf>,
|
||||||
|
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
command: Commands,
|
command: Commands,
|
||||||
}
|
}
|
||||||
|
|
@ -411,9 +417,39 @@ enum Commands {
|
||||||
/// Publisher origin URL (required if publisher is specified)
|
/// Publisher origin URL (required if publisher is specified)
|
||||||
#[clap(short = 'g', requires = "publisher")]
|
#[clap(short = 'g', requires = "publisher")]
|
||||||
origin: Option<String>,
|
origin: Option<String>,
|
||||||
|
|
||||||
|
/// Type of image to create (full or partial, default: full)
|
||||||
|
#[clap(short = 't', long = "type", default_value = "full")]
|
||||||
|
image_type: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines the image path to use based on the provided argument and default rules
|
||||||
|
///
|
||||||
|
/// If the image_path argument is provided, that path is used.
|
||||||
|
/// Otherwise, if $HOME/.pkg exists, that path is used.
|
||||||
|
/// Otherwise, the root directory (/) is used.
|
||||||
|
fn determine_image_path(image_path: Option<PathBuf>) -> PathBuf {
|
||||||
|
if let Some(path) = image_path {
|
||||||
|
// Use the explicitly provided path
|
||||||
|
debug!("Using explicitly provided image path: {}", path.display());
|
||||||
|
path
|
||||||
|
} else {
|
||||||
|
// Check if $HOME/.pkg exists
|
||||||
|
if let Ok(home_dir) = std::env::var("HOME") {
|
||||||
|
let home_pkg = PathBuf::from(home_dir).join(".pkg");
|
||||||
|
if home_pkg.exists() {
|
||||||
|
debug!("Using user home image path: {}", home_pkg.display());
|
||||||
|
return PathBuf::from(home_pkg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default to root directory
|
||||||
|
debug!("Using root directory as image path");
|
||||||
|
PathBuf::from("/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
// Add debug statement at the very beginning
|
// Add debug statement at the very beginning
|
||||||
eprintln!("MAIN: Starting pkg6 command");
|
eprintln!("MAIN: Starting pkg6 command");
|
||||||
|
|
@ -588,15 +624,16 @@ fn main() -> Result<()> {
|
||||||
debug!("Origin: {:?}", origin);
|
debug!("Origin: {:?}", origin);
|
||||||
debug!("Mirror: {:?}", mirror);
|
debug!("Mirror: {:?}", mirror);
|
||||||
|
|
||||||
// Get the current working directory as the default image path
|
// Determine the image path using the -R argument or default rules
|
||||||
let current_dir = std::env::current_dir()?;
|
let image_path = determine_image_path(cli.image_path.clone());
|
||||||
|
info!("Using image at: {}", image_path.display());
|
||||||
|
|
||||||
// Try to load the image from the current directory
|
// Try to load the image from the determined path
|
||||||
let mut image = match libips::image::Image::load(¤t_dir) {
|
let mut image = match libips::image::Image::load(&image_path) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to load image from current directory: {}", e);
|
error!("Failed to load image from {}: {}", image_path.display(), e);
|
||||||
error!("Make sure you are in an image directory or use pkg6 image-create first");
|
error!("Make sure the path points to a valid image or use pkg6 image-create first");
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -639,15 +676,16 @@ fn main() -> Result<()> {
|
||||||
Commands::UnsetPublisher { publisher } => {
|
Commands::UnsetPublisher { publisher } => {
|
||||||
info!("Unsetting publisher: {}", publisher);
|
info!("Unsetting publisher: {}", publisher);
|
||||||
|
|
||||||
// Get the current working directory as the default image path
|
// Determine the image path using the -R argument or default rules
|
||||||
let current_dir = std::env::current_dir()?;
|
let image_path = determine_image_path(cli.image_path.clone());
|
||||||
|
info!("Using image at: {}", image_path.display());
|
||||||
|
|
||||||
// Try to load the image from the current directory
|
// Try to load the image from the determined path
|
||||||
let mut image = match libips::image::Image::load(¤t_dir) {
|
let mut image = match libips::image::Image::load(&image_path) {
|
||||||
Ok(img) => img,
|
Ok(img) => img,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to load image from current directory: {}", e);
|
error!("Failed to load image from {}: {}", image_path.display(), e);
|
||||||
error!("Make sure you are in an image directory or use pkg6 image-create first");
|
error!("Make sure the path points to a valid image or use pkg6 image-create first");
|
||||||
return Err(e.into());
|
return Err(e.into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -670,28 +708,20 @@ fn main() -> Result<()> {
|
||||||
Commands::Publisher { verbose, output_format, publishers } => {
|
Commands::Publisher { verbose, output_format, publishers } => {
|
||||||
info!("Showing publisher information");
|
info!("Showing publisher information");
|
||||||
|
|
||||||
// Get the current working directory as the default image path
|
// Determine the image path using the -R argument or default rules
|
||||||
let current_dir = std::env::current_dir()?;
|
let image_path = determine_image_path(cli.image_path.clone());
|
||||||
|
info!("Using image at: {}", image_path.display());
|
||||||
|
|
||||||
// Determine the path to the image configuration file
|
// Try to load the image from the determined path
|
||||||
let image_json_path = match libips::image::ImageType::Full {
|
let image = match libips::image::Image::load(&image_path) {
|
||||||
libips::image::ImageType::Full => current_dir.join("var/pkg/pkg6.image.json"),
|
Ok(img) => img,
|
||||||
libips::image::ImageType::Partial => current_dir.join(".pkg/pkg6.image.json"),
|
Err(e) => {
|
||||||
|
error!("Failed to load image from {}: {}", image_path.display(), e);
|
||||||
|
error!("Make sure the path points to a valid image or use pkg6 image-create first");
|
||||||
|
return Err(e.into());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the image configuration file exists
|
|
||||||
if !image_json_path.exists() {
|
|
||||||
error!("Image configuration file not found at {}", image_json_path.display());
|
|
||||||
error!("Make sure you are in an image directory or use pkg6 image-create first");
|
|
||||||
return Err(Pkg6Error::from(format!("Image configuration file not found at {}", image_json_path.display())));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the image configuration file
|
|
||||||
let image_json = std::fs::read_to_string(&image_json_path)?;
|
|
||||||
|
|
||||||
// Parse the image configuration file
|
|
||||||
let image: libips::image::Image = serde_json::from_str(&image_json)?;
|
|
||||||
|
|
||||||
// Get all publishers
|
// Get all publishers
|
||||||
let all_publishers = image.publishers();
|
let all_publishers = image.publishers();
|
||||||
|
|
||||||
|
|
@ -725,8 +755,8 @@ fn main() -> Result<()> {
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let catalog_dir = if *verbose {
|
let catalog_dir = if *verbose {
|
||||||
let dir = match image.image_type() {
|
let dir = match image.image_type() {
|
||||||
libips::image::ImageType::Full => current_dir.join("var/pkg/catalog"),
|
libips::image::ImageType::Full => image_path.join("var/pkg/catalog"),
|
||||||
libips::image::ImageType::Partial => current_dir.join(".pkg/catalog"),
|
libips::image::ImageType::Partial => image_path.join(".pkg/catalog"),
|
||||||
};
|
};
|
||||||
Some(dir.join(&p.name).display().to_string())
|
Some(dir.join(&p.name).display().to_string())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -808,13 +838,24 @@ fn main() -> Result<()> {
|
||||||
info!("Publisher completed successfully");
|
info!("Publisher completed successfully");
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
Commands::ImageCreate { full_path, publisher, origin } => {
|
Commands::ImageCreate { full_path, publisher, origin, image_type } => {
|
||||||
info!("Creating image at: {}", full_path.display());
|
info!("Creating image at: {}", full_path.display());
|
||||||
debug!("Publisher: {:?}", publisher);
|
debug!("Publisher: {:?}", publisher);
|
||||||
debug!("Origin: {:?}", origin);
|
debug!("Origin: {:?}", origin);
|
||||||
|
debug!("Image type: {}", image_type);
|
||||||
|
|
||||||
|
// Convert the image type string to the ImageType enum
|
||||||
|
let image_type = match image_type.to_lowercase().as_str() {
|
||||||
|
"full" => libips::image::ImageType::Full,
|
||||||
|
"partial" => libips::image::ImageType::Partial,
|
||||||
|
_ => {
|
||||||
|
error!("Invalid image type: {}. Using default (full)", image_type);
|
||||||
|
libips::image::ImageType::Full
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Create the image (only creates the basic structure)
|
// Create the image (only creates the basic structure)
|
||||||
let mut image = libips::image::Image::create_image(&full_path)?;
|
let mut image = libips::image::Image::create_image(&full_path, image_type)?;
|
||||||
info!("Image created successfully at: {}", full_path.display());
|
info!("Image created successfully at: {}", full_path.display());
|
||||||
|
|
||||||
// If publisher and origin are provided, add the publisher and download the catalog
|
// If publisher and origin are provided, add the publisher and download the catalog
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue