mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 21:30:41 +00:00
Refactor repository structure to use publisher-specific directories
- Introduce publisher-specific hierarchy (`publisher/<publisher_name>`) for catalog, package, and file storage. - Replace hardcoded paths with helper methods (`construct_catalog_path`, `construct_package_dir`, `construct_file_path_with_publisher`) for consistent path generation. - Remove outdated tests and simplify redundant assertions in repository tests. - Update `CatalogManager` and file handling logic to leverage publisher-specific paths. - Enhance debug logs to include publisher context where applicable.
This commit is contained in:
parent
845ffec13b
commit
99dd0fe87c
9 changed files with 259 additions and 188 deletions
|
|
@ -380,6 +380,9 @@ pub struct CatalogManager {
|
|||
/// Path to the catalog directory
|
||||
catalog_dir: PathBuf,
|
||||
|
||||
/// Publisher name
|
||||
publisher: String,
|
||||
|
||||
/// Catalog attributes
|
||||
attrs: CatalogAttrs,
|
||||
|
||||
|
|
@ -392,16 +395,17 @@ pub struct CatalogManager {
|
|||
|
||||
impl CatalogManager {
|
||||
/// Create a new catalog manager
|
||||
pub fn new<P: AsRef<Path>>(catalog_dir: P) -> Result<Self> {
|
||||
let catalog_dir = catalog_dir.as_ref().to_path_buf();
|
||||
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.join(publisher).join("catalog");
|
||||
|
||||
// Create catalog directory if it doesn't exist
|
||||
if !catalog_dir.exists() {
|
||||
fs::create_dir_all(&catalog_dir)?;
|
||||
if !publisher_catalog_dir.exists() {
|
||||
fs::create_dir_all(&publisher_catalog_dir)?;
|
||||
}
|
||||
|
||||
// Try to load existing catalog attributes
|
||||
let attrs_path = catalog_dir.join("catalog.attrs");
|
||||
let attrs_path = publisher_catalog_dir.join("catalog.attrs");
|
||||
let attrs = if attrs_path.exists() {
|
||||
CatalogAttrs::load(&attrs_path)?
|
||||
} else {
|
||||
|
|
@ -409,7 +413,8 @@ impl CatalogManager {
|
|||
};
|
||||
|
||||
Ok(CatalogManager {
|
||||
catalog_dir,
|
||||
catalog_dir: publisher_catalog_dir,
|
||||
publisher: publisher.to_string(),
|
||||
attrs,
|
||||
parts: HashMap::new(),
|
||||
update_logs: HashMap::new(),
|
||||
|
|
@ -537,4 +542,41 @@ impl CatalogManager {
|
|||
pub fn get_update_log_mut(&mut self, name: &str) -> Option<&mut UpdateLog> {
|
||||
self.update_logs.get_mut(name)
|
||||
}
|
||||
|
||||
/// Add a package to a catalog part using the stored publisher
|
||||
pub fn add_package_to_part(
|
||||
&mut self,
|
||||
part_name: &str,
|
||||
fmri: &Fmri,
|
||||
actions: Option<Vec<String>>,
|
||||
signature: Option<String>,
|
||||
) -> Result<()> {
|
||||
if let Some(part) = self.parts.get_mut(part_name) {
|
||||
part.add_package(&self.publisher, fmri, actions, signature);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CatalogError::CatalogPartNotLoaded {
|
||||
name: part_name.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an update to an update log using the stored publisher
|
||||
pub fn add_update_to_log(
|
||||
&mut self,
|
||||
log_name: &str,
|
||||
fmri: &Fmri,
|
||||
op_type: CatalogOperationType,
|
||||
catalog_parts: HashMap<String, HashMap<String, Vec<String>>>,
|
||||
signature: Option<String>,
|
||||
) -> Result<()> {
|
||||
if let Some(log) = self.update_logs.get_mut(log_name) {
|
||||
log.add_update(&self.publisher, fmri, op_type, catalog_parts, signature);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(CatalogError::UpdateLogNotLoaded {
|
||||
name: log_name.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -454,24 +454,45 @@ impl Transaction {
|
|||
let manifest_json = serde_json::to_string_pretty(&self.manifest)?;
|
||||
fs::write(&manifest_path, manifest_json)?;
|
||||
|
||||
// Determine the publisher to use
|
||||
let publisher = match &self.publisher {
|
||||
Some(pub_name) => {
|
||||
debug!("Using specified publisher: {}", pub_name);
|
||||
pub_name.clone()
|
||||
}
|
||||
None => {
|
||||
debug!("No publisher specified, trying to use default publisher");
|
||||
// If no publisher is specified, use the default publisher from the repository config
|
||||
let config_path = self.repo.join(REPOSITORY_CONFIG_FILENAME);
|
||||
if config_path.exists() {
|
||||
let config_content = fs::read_to_string(&config_path)?;
|
||||
let config: RepositoryConfig = serde_json::from_str(&config_content)?;
|
||||
match config.default_publisher {
|
||||
Some(default_pub) => {
|
||||
debug!("Using default publisher: {}", default_pub);
|
||||
default_pub
|
||||
}
|
||||
None => {
|
||||
debug!("No default publisher set in repository");
|
||||
return Err(RepositoryError::Other(
|
||||
"No publisher specified and no default publisher set in repository"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!("Repository configuration not found");
|
||||
return Err(RepositoryError::Other(
|
||||
"No publisher specified and repository configuration not found".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Copy files to their final location
|
||||
for (source_path, hash) in self.files {
|
||||
// Create the destination path using the new directory structure
|
||||
let dest_path = if hash.len() < 4 {
|
||||
// Fallback for very short hashes (shouldn't happen with SHA256)
|
||||
self.repo.join("file").join(&hash)
|
||||
} else {
|
||||
// Extract the first two and next two characters from the hash
|
||||
let first_two = &hash[0..2];
|
||||
let next_two = &hash[2..4];
|
||||
|
||||
// Create the path: $REPO/file/XX/YY/XXYY...
|
||||
self.repo
|
||||
.join("file")
|
||||
.join(first_two)
|
||||
.join(next_two)
|
||||
.join(&hash)
|
||||
};
|
||||
// Create the destination path using the helper function with publisher
|
||||
let dest_path = FileBackend::construct_file_path_with_publisher(&self.repo, &publisher, &hash);
|
||||
|
||||
// Create parent directories if they don't exist
|
||||
if let Some(parent) = dest_path.parent() {
|
||||
|
|
@ -535,7 +556,7 @@ impl Transaction {
|
|||
};
|
||||
|
||||
// Create the package directory if it doesn't exist
|
||||
let pkg_dir = self.repo.join("pkg").join(&publisher).join(&package_stem);
|
||||
let pkg_dir = FileBackend::construct_package_dir(&self.repo, &publisher, &package_stem);
|
||||
debug!("Package directory: {}", pkg_dir.display());
|
||||
if !pkg_dir.exists() {
|
||||
debug!("Creating package directory");
|
||||
|
|
@ -627,8 +648,8 @@ impl ReadableRepository for FileBackend {
|
|||
let mut publishers = Vec::new();
|
||||
|
||||
for publisher_name in &self.config.publishers {
|
||||
// Count packages by scanning the pkg/<publisher> directory
|
||||
let publisher_pkg_dir = self.path.join("pkg").join(publisher_name);
|
||||
// Count packages by scanning the publisher's package directory
|
||||
let publisher_pkg_dir = Self::construct_package_dir(&self.path, publisher_name, "");
|
||||
let mut package_count = 0;
|
||||
let mut latest_timestamp = SystemTime::UNIX_EPOCH;
|
||||
|
||||
|
|
@ -702,7 +723,7 @@ impl ReadableRepository for FileBackend {
|
|||
// For each publisher, list packages
|
||||
for pub_name in publishers {
|
||||
// Get the publisher's package directory
|
||||
let publisher_pkg_dir = self.path.join("pkg").join(&pub_name);
|
||||
let publisher_pkg_dir = Self::construct_package_dir(&self.path, &pub_name, "");
|
||||
|
||||
// Check if the publisher directory exists
|
||||
if publisher_pkg_dir.exists() {
|
||||
|
|
@ -751,7 +772,7 @@ impl ReadableRepository for FileBackend {
|
|||
// For each publisher, process packages
|
||||
for pub_name in publishers {
|
||||
// Get the publisher's package directory
|
||||
let publisher_pkg_dir = self.path.join("pkg").join(&pub_name);
|
||||
let publisher_pkg_dir = Self::construct_package_dir(&self.path, &pub_name, "");
|
||||
|
||||
// Check if the publisher directory exists
|
||||
if publisher_pkg_dir.exists() {
|
||||
|
|
@ -1324,8 +1345,8 @@ impl WritableRepository for FileBackend {
|
|||
self.config.publishers.push(publisher.to_string());
|
||||
|
||||
// Create publisher-specific directories
|
||||
fs::create_dir_all(self.path.join("catalog").join(publisher))?;
|
||||
fs::create_dir_all(self.path.join("pkg").join(publisher))?;
|
||||
fs::create_dir_all(Self::construct_catalog_path(&self.path, publisher))?;
|
||||
fs::create_dir_all(Self::construct_package_dir(&self.path, publisher, ""))?;
|
||||
|
||||
// Set as the default publisher if no default publisher is set
|
||||
if self.config.default_publisher.is_none() {
|
||||
|
|
@ -1346,8 +1367,8 @@ impl WritableRepository for FileBackend {
|
|||
self.config.publishers.remove(pos);
|
||||
|
||||
// Remove publisher-specific directories and their contents recursively
|
||||
let catalog_dir = self.path.join("catalog").join(publisher);
|
||||
let pkg_dir = self.path.join("pkg").join(publisher);
|
||||
let catalog_dir = Self::construct_catalog_path(&self.path, publisher);
|
||||
let pkg_dir = Self::construct_package_dir(&self.path, publisher, "");
|
||||
|
||||
// Remove the catalog directory if it exists
|
||||
if catalog_dir.exists() {
|
||||
|
|
@ -1492,18 +1513,91 @@ impl WritableRepository for FileBackend {
|
|||
}
|
||||
|
||||
impl FileBackend {
|
||||
/// Helper method to construct a catalog path consistently
|
||||
///
|
||||
/// Format: base_path/publisher/publisher_name/catalog
|
||||
pub fn construct_catalog_path(
|
||||
base_path: &Path,
|
||||
publisher: &str,
|
||||
) -> PathBuf {
|
||||
base_path.join("publisher").join(publisher).join("catalog")
|
||||
}
|
||||
|
||||
/// Helper method to construct a manifest path consistently
|
||||
fn construct_manifest_path(
|
||||
///
|
||||
/// Format: base_path/publisher/publisher_name/pkg/stem/encoded_version
|
||||
pub 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 pkg_dir = Self::construct_package_dir(base_path, publisher, stem);
|
||||
let encoded_version = Self::url_encode(version);
|
||||
pkg_dir.join(encoded_version)
|
||||
}
|
||||
|
||||
/// Helper method to construct a package directory path consistently
|
||||
///
|
||||
/// Format: base_path/publisher/publisher_name/pkg/url_encoded_stem
|
||||
pub fn construct_package_dir(
|
||||
base_path: &Path,
|
||||
publisher: &str,
|
||||
stem: &str,
|
||||
) -> PathBuf {
|
||||
let encoded_stem = Self::url_encode(stem);
|
||||
base_path.join("publisher").join(publisher).join("pkg").join(encoded_stem)
|
||||
}
|
||||
|
||||
/// Helper method to construct a file path consistently
|
||||
///
|
||||
/// Format: base_path/file/XX/hash
|
||||
/// Where XX is the first two characters of the hash
|
||||
pub fn construct_file_path(
|
||||
base_path: &Path,
|
||||
hash: &str,
|
||||
) -> PathBuf {
|
||||
if hash.len() < 2 {
|
||||
// Fallback for very short hashes (shouldn't happen with SHA256)
|
||||
base_path.join("file").join(hash)
|
||||
} else {
|
||||
// Extract the first two characters from the hash
|
||||
let first_two = &hash[0..2];
|
||||
|
||||
// Create the path: $REPO/file/XX/XXYY...
|
||||
base_path
|
||||
.join("file")
|
||||
.join(first_two)
|
||||
.join(hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper method to construct a file path consistently with publisher
|
||||
///
|
||||
/// Format: base_path/publisher/publisher_name/file/XX/hash
|
||||
/// Where XX is the first two characters of the hash
|
||||
pub fn construct_file_path_with_publisher(
|
||||
base_path: &Path,
|
||||
publisher: &str,
|
||||
hash: &str,
|
||||
) -> PathBuf {
|
||||
if hash.len() < 2 {
|
||||
// Fallback for very short hashes (shouldn't happen with SHA256)
|
||||
base_path.join("publisher").join(publisher).join("file").join(hash)
|
||||
} else {
|
||||
// Extract the first two characters from the hash
|
||||
let first_two = &hash[0..2];
|
||||
|
||||
// Create the path: $REPO/publisher/publisher_name/file/XX/XXYY...
|
||||
base_path
|
||||
.join("publisher")
|
||||
.join(publisher)
|
||||
.join("file")
|
||||
.join(first_two)
|
||||
.join(hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively find manifest files in a directory and its subdirectories
|
||||
fn find_manifests_recursive(
|
||||
&self,
|
||||
|
|
@ -1642,10 +1736,9 @@ impl FileBackend {
|
|||
/// Create the repository directories
|
||||
fn create_directories(&self) -> Result<()> {
|
||||
// Create the main repository directories
|
||||
fs::create_dir_all(self.path.join("catalog"))?;
|
||||
fs::create_dir_all(self.path.join("publisher"))?;
|
||||
fs::create_dir_all(self.path.join("file"))?;
|
||||
fs::create_dir_all(self.path.join("index"))?;
|
||||
fs::create_dir_all(self.path.join("pkg"))?;
|
||||
fs::create_dir_all(self.path.join("trans"))?;
|
||||
fs::create_dir_all(self.path.join("obsoleted"))?;
|
||||
|
||||
|
|
@ -1655,16 +1748,12 @@ impl FileBackend {
|
|||
/// Rebuild catalog for a publisher
|
||||
///
|
||||
/// This method generates catalog files for a publisher and stores them in the publisher's
|
||||
/// subdirectory within the catalog directory.
|
||||
/// catalog directory.
|
||||
pub fn rebuild_catalog(&self, publisher: &str, create_update_log: bool) -> Result<()> {
|
||||
info!("Rebuilding catalog for publisher: {}", publisher);
|
||||
debug!(
|
||||
"Catalog directory path: {}",
|
||||
self.path.join("catalog").display()
|
||||
);
|
||||
|
||||
// Create the catalog directory for the publisher if it doesn't exist
|
||||
let catalog_dir = self.path.join("catalog").join(publisher);
|
||||
let catalog_dir = Self::construct_catalog_path(&self.path, publisher);
|
||||
debug!("Publisher catalog directory: {}", catalog_dir.display());
|
||||
fs::create_dir_all(&catalog_dir)?;
|
||||
debug!("Created publisher catalog directory");
|
||||
|
|
@ -1936,36 +2025,25 @@ impl FileBackend {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Generate the file path for a given hash using the new directory structure
|
||||
/// The path will be $REPO/file/XX/YY/XXYY... where XX and YY are the first four letters of the hash
|
||||
fn generate_file_path(&self, hash: &str) -> PathBuf {
|
||||
if hash.len() < 4 {
|
||||
// Fallback for very short hashes (shouldn't happen with SHA256)
|
||||
return self.path.join("file").join(hash);
|
||||
}
|
||||
|
||||
// Extract the first two and next two characters from the hash
|
||||
let first_two = &hash[0..2];
|
||||
let next_two = &hash[2..4];
|
||||
|
||||
// Create the path: $REPO/file/XX/YY/XXYY...
|
||||
self.path
|
||||
.join("file")
|
||||
.join(first_two)
|
||||
.join(next_two)
|
||||
.join(hash)
|
||||
/// Generate the file path for a given hash using the new directory structure with publisher
|
||||
/// This is a wrapper around the construct_file_path_with_publisher helper method
|
||||
fn generate_file_path_with_publisher(&self, publisher: &str, hash: &str) -> PathBuf {
|
||||
Self::construct_file_path_with_publisher(&self.path, publisher, hash)
|
||||
}
|
||||
|
||||
/// Get or initialize the catalog manager
|
||||
///
|
||||
/// This method returns a mutable reference to the catalog manager.
|
||||
/// It uses interior mutability with RefCell to allow mutation through an immutable reference.
|
||||
///
|
||||
/// The catalog manager is specific to the given publisher.
|
||||
pub fn get_catalog_manager(
|
||||
&mut self,
|
||||
publisher: &str,
|
||||
) -> Result<std::cell::RefMut<crate::repository::catalog::CatalogManager>> {
|
||||
if self.catalog_manager.is_none() {
|
||||
let catalog_dir = self.path.join("catalog");
|
||||
let manager = crate::repository::catalog::CatalogManager::new(&catalog_dir)?;
|
||||
let publisher_dir = self.path.join("publisher");
|
||||
let manager = crate::repository::catalog::CatalogManager::new(&publisher_dir, publisher)?;
|
||||
let refcell = std::cell::RefCell::new(manager);
|
||||
self.catalog_manager = Some(refcell);
|
||||
}
|
||||
|
|
@ -2015,7 +2093,7 @@ impl FileBackend {
|
|||
let mut index = SearchIndex::new();
|
||||
|
||||
// Get the publisher's package directory
|
||||
let publisher_pkg_dir = self.path.join("pkg").join(publisher);
|
||||
let publisher_pkg_dir = Self::construct_package_dir(&self.path, publisher, "");
|
||||
|
||||
// Check if the publisher directory exists
|
||||
if publisher_pkg_dir.exists() {
|
||||
|
|
@ -2278,7 +2356,8 @@ impl FileBackend {
|
|||
|
||||
// Verify the file was stored
|
||||
let hash = Transaction::calculate_file_hash(&test_file_path)?;
|
||||
let stored_file_path = self.generate_file_path(&hash);
|
||||
// Use the new method with publisher
|
||||
let stored_file_path = self.generate_file_path_with_publisher(publisher, &hash);
|
||||
|
||||
if !stored_file_path.exists() {
|
||||
return Err(RepositoryError::Other(
|
||||
|
|
@ -2288,11 +2367,9 @@ impl FileBackend {
|
|||
|
||||
// Verify the manifest was updated in the publisher-specific directory
|
||||
// The manifest should be named "unknown.manifest" since we didn't set a package name
|
||||
let manifest_path = self
|
||||
.path
|
||||
.join("pkg")
|
||||
.join(publisher)
|
||||
.join("unknown.manifest");
|
||||
// Use the construct_package_dir helper to get the base directory, then join with the manifest name
|
||||
let pkg_dir = Self::construct_package_dir(&self.path, publisher, "unknown");
|
||||
let manifest_path = pkg_dir.join("manifest");
|
||||
|
||||
if !manifest_path.exists() {
|
||||
return Err(RepositoryError::Other(format!(
|
||||
|
|
@ -2383,14 +2460,14 @@ impl FileBackend {
|
|||
}
|
||||
|
||||
/// Store a file in the repository
|
||||
pub fn store_file<P: AsRef<Path>>(&self, file_path: P) -> Result<String> {
|
||||
pub fn store_file<P: AsRef<Path>>(&self, file_path: P, publisher: &str) -> Result<String> {
|
||||
let file_path = file_path.as_ref();
|
||||
|
||||
// Calculate the SHA256 hash of the file
|
||||
let hash = Transaction::calculate_file_hash(file_path)?;
|
||||
|
||||
// Create the destination path using the new directory structure
|
||||
let dest_path = self.generate_file_path(&hash);
|
||||
// Create the destination path using the new directory structure with publisher
|
||||
let dest_path = self.generate_file_path_with_publisher(publisher, &hash);
|
||||
|
||||
// Create parent directories if they don't exist
|
||||
if let Some(parent) = dest_path.parent() {
|
||||
|
|
|
|||
|
|
@ -2513,20 +2513,20 @@ impl ObsoletedPackageManager {
|
|||
}
|
||||
}
|
||||
|
||||
/// URL encode a string
|
||||
/// URL encode a string for use in a filename
|
||||
fn url_encode(s: &str) -> String {
|
||||
let mut encoded = String::new();
|
||||
let mut result = String::new();
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => encoded.push(c),
|
||||
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => result.push(c),
|
||||
' ' => result.push('+'),
|
||||
_ => {
|
||||
for b in c.to_string().as_bytes() {
|
||||
encoded.push_str(&format!("%{:02X}", b));
|
||||
result.push('%');
|
||||
result.push_str(&format!("{:02X}", c as u8));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
encoded
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ mod tests {
|
|||
println!("Transaction committed successfully");
|
||||
|
||||
// Debug: Check if the package manifest was stored in the correct location
|
||||
let publisher_pkg_dir = repo.path.join("pkg").join(publisher);
|
||||
let publisher_pkg_dir = FileBackend::construct_package_dir(&repo.path, publisher, "");
|
||||
println!(
|
||||
"Publisher package directory: {}",
|
||||
publisher_pkg_dir.display()
|
||||
|
|
@ -181,10 +181,9 @@ mod tests {
|
|||
|
||||
// Check that the repository was created
|
||||
assert!(repo_path.exists());
|
||||
assert!(repo_path.join("catalog").exists());
|
||||
assert!(repo_path.join("publisher").exists());
|
||||
assert!(repo_path.join("file").exists());
|
||||
assert!(repo_path.join("index").exists());
|
||||
assert!(repo_path.join("pkg").exists());
|
||||
assert!(repo_path.join("trans").exists());
|
||||
assert!(repo_path.join(REPOSITORY_CONFIG_FILENAME).exists());
|
||||
|
||||
|
|
@ -206,8 +205,8 @@ mod tests {
|
|||
|
||||
// Check that the publisher was added
|
||||
assert!(repo.config.publishers.contains(&"example.com".to_string()));
|
||||
assert!(repo_path.join("catalog").join("example.com").exists());
|
||||
assert!(repo_path.join("pkg").join("example.com").exists());
|
||||
assert!(FileBackend::construct_catalog_path(&repo_path, "example.com").exists());
|
||||
assert!(FileBackend::construct_package_dir(&repo_path, "example.com", "").exists());
|
||||
|
||||
// Clean up
|
||||
cleanup_test_dir(&test_dir);
|
||||
|
|
@ -217,20 +216,22 @@ mod tests {
|
|||
fn test_catalog_manager() {
|
||||
// Create a test directory
|
||||
let test_dir = create_test_dir("catalog_manager");
|
||||
let catalog_dir = test_dir.join("catalog");
|
||||
let publisher_dir = test_dir.join("publisher");
|
||||
let publisher_name = "test";
|
||||
let catalog_dir = publisher_dir.join(publisher_name).join("catalog");
|
||||
|
||||
// Create the catalog directory
|
||||
fs::create_dir_all(&catalog_dir).unwrap();
|
||||
|
||||
// Create a catalog manager
|
||||
let mut catalog_manager = CatalogManager::new(&catalog_dir).unwrap();
|
||||
// Create a catalog manager with the publisher parameter
|
||||
let mut catalog_manager = CatalogManager::new(&publisher_dir, publisher_name).unwrap();
|
||||
|
||||
// Create a catalog part
|
||||
let part = catalog_manager.create_part("test_part");
|
||||
catalog_manager.create_part("test_part");
|
||||
|
||||
// Add a package to the part
|
||||
// Add a package to the part using the stored publisher
|
||||
let fmri = Fmri::parse("pkg://test/example@1.0.0").unwrap();
|
||||
part.add_package("test", &fmri, None, None);
|
||||
catalog_manager.add_package_to_part("test_part", &fmri, None, None).unwrap();
|
||||
|
||||
// Save the part
|
||||
catalog_manager.save_part("test_part").unwrap();
|
||||
|
|
@ -239,7 +240,7 @@ mod tests {
|
|||
assert!(catalog_dir.join("test_part").exists());
|
||||
|
||||
// Create a new catalog manager and load the part
|
||||
let mut new_catalog_manager = CatalogManager::new(&catalog_dir).unwrap();
|
||||
let mut new_catalog_manager = CatalogManager::new(&publisher_dir, publisher_name).unwrap();
|
||||
new_catalog_manager.load_part("test_part").unwrap();
|
||||
|
||||
// Check that the part was loaded
|
||||
|
|
@ -409,16 +410,10 @@ mod tests {
|
|||
fs::write(&test_file_path, "This is a test file").unwrap();
|
||||
|
||||
// Store the file in the repository
|
||||
let hash = repo.store_file(&test_file_path).unwrap();
|
||||
let hash = repo.store_file(&test_file_path, "test").unwrap();
|
||||
|
||||
// Check if the file was stored in the correct directory structure
|
||||
let first_two = &hash[0..2];
|
||||
let next_two = &hash[2..4];
|
||||
let expected_path = repo_path
|
||||
.join("file")
|
||||
.join(first_two)
|
||||
.join(next_two)
|
||||
.join(&hash);
|
||||
let expected_path = FileBackend::construct_file_path_with_publisher(&repo_path, "test", &hash);
|
||||
|
||||
// Verify that the file exists at the expected path
|
||||
assert!(
|
||||
|
|
@ -427,7 +422,7 @@ mod tests {
|
|||
expected_path.display()
|
||||
);
|
||||
|
||||
// Verify that the file does NOT exist at the old path
|
||||
// Verify that the file does NOT exist at the old path (with no directory prefixing)
|
||||
let old_path = repo_path.join("file").join(&hash);
|
||||
assert!(
|
||||
!old_path.exists(),
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ mod e2e_tests {
|
|||
|
||||
// Check that the repository was created
|
||||
assert!(repo_path.exists());
|
||||
assert!(repo_path.join("catalog").exists());
|
||||
assert!(repo_path.join("publisher").exists());
|
||||
assert!(repo_path.join("file").exists());
|
||||
assert!(repo_path.join("index").exists());
|
||||
assert!(repo_path.join("pkg").exists());
|
||||
|
|
@ -174,8 +174,9 @@ mod e2e_tests {
|
|||
);
|
||||
|
||||
// Check that the publisher was added
|
||||
assert!(repo_path.join("catalog").join("example.com").exists());
|
||||
assert!(repo_path.join("pkg").join("example.com").exists());
|
||||
assert!(repo_path.join("publisher").join("example.com").exists());
|
||||
assert!(repo_path.join("publisher").join("example.com").join("catalog").exists());
|
||||
assert!(repo_path.join("publisher").join("example.com").join("pkg").exists());
|
||||
|
||||
// Clean up
|
||||
cleanup_test_dir(&test_dir);
|
||||
|
|
@ -462,6 +463,24 @@ mod e2e_tests {
|
|||
fmri
|
||||
};
|
||||
|
||||
// Print the FMRI and repo path for debugging
|
||||
println!("FMRI: {}", fmri);
|
||||
println!("Repo path: {}", repo_path.display());
|
||||
|
||||
// Check if the package exists in the repository
|
||||
let pkg_dir = repo_path.join("publisher").join("test").join("pkg").join("example");
|
||||
println!("Package directory: {}", pkg_dir.display());
|
||||
println!("Package directory exists: {}", pkg_dir.exists());
|
||||
|
||||
// List files in the package directory if it exists
|
||||
if pkg_dir.exists() {
|
||||
println!("Files in package directory:");
|
||||
for entry in std::fs::read_dir(&pkg_dir).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
println!(" {}", entry.path().display());
|
||||
}
|
||||
}
|
||||
|
||||
// Mark the package as obsoleted
|
||||
let result = run_pkg6repo(&[
|
||||
"obsolete-package",
|
||||
|
|
@ -471,6 +490,10 @@ mod e2e_tests {
|
|||
"-m", "This package is obsoleted for testing purposes",
|
||||
"-r", "pkg://test/example2@1.0"
|
||||
]);
|
||||
|
||||
// Print the result for debugging
|
||||
println!("Result: {:?}", result);
|
||||
|
||||
assert!(
|
||||
result.is_ok(),
|
||||
"Failed to mark package as obsoleted: {:?}",
|
||||
|
|
|
|||
|
|
@ -3,22 +3,6 @@ mod pkg5_import;
|
|||
use error::{Pkg6RepoError, Result};
|
||||
use pkg5_import::Pkg5Importer;
|
||||
|
||||
/// URL encode a string for use in a filename
|
||||
fn url_encode(s: &str) -> String {
|
||||
let mut result = String::new();
|
||||
for c in s.chars() {
|
||||
match c {
|
||||
'a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_' | '.' | '~' => result.push(c),
|
||||
' ' => result.push('+'),
|
||||
_ => {
|
||||
result.push('%');
|
||||
result.push_str(&format!("{:02X}", c as u8));
|
||||
}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use libips::repository::{FileBackend, ReadableRepository, RepositoryVersion, WritableRepository};
|
||||
use serde::Serialize;
|
||||
|
|
@ -1306,10 +1290,18 @@ fn main() -> Result<()> {
|
|||
// Parse the FMRI
|
||||
let parsed_fmri = libips::fmri::Fmri::parse(fmri)?;
|
||||
|
||||
// Get the manifest for the package
|
||||
let pkg_dir = repo.path.join("pkg").join(publisher).join(parsed_fmri.stem());
|
||||
let encoded_version = url_encode(&parsed_fmri.version());
|
||||
let manifest_path = pkg_dir.join(&encoded_version);
|
||||
// Get the manifest for the package using the helper method
|
||||
let manifest_path = FileBackend::construct_manifest_path(
|
||||
&repo.path,
|
||||
publisher,
|
||||
parsed_fmri.stem(),
|
||||
&parsed_fmri.version()
|
||||
);
|
||||
|
||||
println!("Looking for manifest at: {}", manifest_path.display());
|
||||
println!("Publisher: {}", publisher);
|
||||
println!("Stem: {}", parsed_fmri.stem());
|
||||
println!("Version: {}", parsed_fmri.version());
|
||||
|
||||
if !manifest_path.exists() {
|
||||
return Err(Pkg6RepoError::from(format!(
|
||||
|
|
|
|||
|
|
@ -462,7 +462,7 @@ impl Pkg5Importer {
|
|||
// Debug the repository structure
|
||||
debug!(
|
||||
"Publisher directory: {}",
|
||||
dest_repo.path.join("pkg").join(publisher).display()
|
||||
libips::repository::FileBackend::construct_package_dir(&dest_repo.path, publisher, "").display()
|
||||
);
|
||||
|
||||
// Extract files referenced in the manifest
|
||||
|
|
|
|||
|
|
@ -47,10 +47,9 @@ mod tests {
|
|||
|
||||
// Check that the repository was created
|
||||
assert!(repo_path.exists());
|
||||
assert!(repo_path.join("catalog").exists());
|
||||
assert!(repo_path.join("publisher").exists());
|
||||
assert!(repo_path.join("file").exists());
|
||||
assert!(repo_path.join("index").exists());
|
||||
assert!(repo_path.join("pkg").exists());
|
||||
assert!(repo_path.join("trans").exists());
|
||||
assert!(repo_path.join(REPOSITORY_CONFIG_FILENAME).exists());
|
||||
|
||||
|
|
@ -72,8 +71,8 @@ mod tests {
|
|||
|
||||
// Check that the publisher was added
|
||||
assert!(repo.config.publishers.contains(&"example.com".to_string()));
|
||||
assert!(repo_path.join("catalog").join("example.com").exists());
|
||||
assert!(repo_path.join("pkg").join("example.com").exists());
|
||||
assert!(FileBackend::construct_catalog_path(&repo_path, "example.com").exists());
|
||||
assert!(FileBackend::construct_package_dir(&repo_path, "example.com", "").exists());
|
||||
|
||||
// Clean up
|
||||
cleanup_test_dir(&test_dir);
|
||||
|
|
@ -95,8 +94,8 @@ mod tests {
|
|||
assert!(repo.config.publishers.contains(&"example.com".to_string()));
|
||||
|
||||
// Check that the publisher directories were created
|
||||
let catalog_dir = repo_path.join("catalog").join("example.com");
|
||||
let pkg_dir = repo_path.join("pkg").join("example.com");
|
||||
let catalog_dir = FileBackend::construct_catalog_path(&repo_path, "example.com");
|
||||
let pkg_dir = FileBackend::construct_package_dir(&repo_path, "example.com", "");
|
||||
assert!(
|
||||
catalog_dir.exists(),
|
||||
"Catalog directory should exist after adding publisher"
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
use std::fs;
|
||||
use std::path::Path;
|
||||
use libips::repository::{FileBackend, WritableRepository, ReadableRepository, RepositoryVersion};
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Create a temporary directory for the test
|
||||
let test_dir = Path::new("/tmp/pkg6_file_structure_test");
|
||||
if test_dir.exists() {
|
||||
fs::remove_dir_all(test_dir)?;
|
||||
}
|
||||
fs::create_dir_all(test_dir)?;
|
||||
|
||||
println!("Created test directory: {}", test_dir.display());
|
||||
|
||||
// Create a new repository
|
||||
let mut repo = FileBackend::create(test_dir, RepositoryVersion::V1)?;
|
||||
|
||||
// Add a publisher
|
||||
repo.add_publisher("test")?;
|
||||
|
||||
println!("Created repository with publisher 'test'");
|
||||
|
||||
// Create a test file
|
||||
let test_file_path = test_dir.join("test_file.txt");
|
||||
fs::write(&test_file_path, "This is a test file")?;
|
||||
|
||||
println!("Created test file: {}", test_file_path.display());
|
||||
|
||||
// Store the file in the repository
|
||||
let hash = repo.store_file(&test_file_path)?;
|
||||
|
||||
println!("Stored file with hash: {}", hash);
|
||||
|
||||
// Check if the file was stored in the correct directory structure
|
||||
let first_two = &hash[0..2];
|
||||
let next_two = &hash[2..4];
|
||||
let expected_path = test_dir.join("file").join(first_two).join(next_two).join(&hash);
|
||||
|
||||
if expected_path.exists() {
|
||||
println!("SUCCESS: File was stored at the correct path: {}", expected_path.display());
|
||||
} else {
|
||||
println!("ERROR: File was not stored at the expected path: {}", expected_path.display());
|
||||
|
||||
// Check if the file was stored in the old location
|
||||
let old_path = test_dir.join("file").join(&hash);
|
||||
if old_path.exists() {
|
||||
println!("File was stored at the old path: {}", old_path.display());
|
||||
} else {
|
||||
println!("File was not stored at the old path either");
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
fs::remove_dir_all(test_dir)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue