mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 21:30:41 +00:00
Add support for backward compatibility with legacy repository files
- Introduced creation of `pub.p5i` files for publishers to maintain compatibility with older repository formats. - Implemented saving repository configuration in legacy INI format (`pkg5.repository`). - Updated tests to validate the generation and structure of legacy files. - Added new dependencies (`rust-ini`) and updated `Cargo.toml` and `Cargo.lock` accordingly.
This commit is contained in:
parent
fc00304038
commit
dfe8ac1305
4 changed files with 286 additions and 0 deletions
71
Cargo.lock
generated
71
Cargo.lock
generated
|
|
@ -316,6 +316,26 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random"
|
||||||
|
version = "0.1.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359"
|
||||||
|
dependencies = [
|
||||||
|
"const-random-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "const-random-macro"
|
||||||
|
version = "0.1.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.16",
|
||||||
|
"once_cell",
|
||||||
|
"tiny-keccak",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation"
|
name = "core-foundation"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
@ -350,6 +370,12 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|
@ -432,6 +458,15 @@ dependencies = [
|
||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dlv-list"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f"
|
||||||
|
dependencies = [
|
||||||
|
"const-random",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
|
|
@ -627,6 +662,12 @@ version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.4"
|
version = "0.15.4"
|
||||||
|
|
@ -981,6 +1022,7 @@ dependencies = [
|
||||||
"pest_derive",
|
"pest_derive",
|
||||||
"redb",
|
"redb",
|
||||||
"regex",
|
"regex",
|
||||||
|
"rust-ini",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_cbor",
|
"serde_cbor",
|
||||||
|
|
@ -1321,6 +1363,16 @@ dependencies = [
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-multimap"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79"
|
||||||
|
dependencies = [
|
||||||
|
"dlv-list",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.6.1"
|
version = "6.6.1"
|
||||||
|
|
@ -1644,6 +1696,16 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rust-ini"
|
||||||
|
version = "0.21.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e7295b7ce3bf4806b419dc3420745998b447178b7005e2011947b38fc5aa6791"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"ordered-multimap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.25"
|
version = "0.1.25"
|
||||||
|
|
@ -2147,6 +2209,15 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tiny-keccak"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||||
|
dependencies = [
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tinystr"
|
name = "tinystr"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ tempfile = "3.20.0"
|
||||||
walkdir = "2.4.0"
|
walkdir = "2.4.0"
|
||||||
redb = "1.5.0"
|
redb = "1.5.0"
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
|
rust-ini = "0.21.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["redb-index"]
|
default = ["redb-index"]
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ use super::{
|
||||||
PackageContents, PackageInfo, PublisherInfo, ReadableRepository, RepositoryConfig,
|
PackageContents, PackageInfo, PublisherInfo, ReadableRepository, RepositoryConfig,
|
||||||
RepositoryInfo, RepositoryVersion, WritableRepository, REPOSITORY_CONFIG_FILENAME,
|
RepositoryInfo, RepositoryVersion, WritableRepository, REPOSITORY_CONFIG_FILENAME,
|
||||||
};
|
};
|
||||||
|
use ini::Ini;
|
||||||
|
|
||||||
// Define a struct to hold the content vectors for each package
|
// Define a struct to hold the content vectors for each package
|
||||||
struct PackageContentVectors {
|
struct PackageContentVectors {
|
||||||
|
|
@ -586,6 +587,31 @@ impl Transaction {
|
||||||
);
|
);
|
||||||
fs::copy(&manifest_path, &pkg_manifest_path)?;
|
fs::copy(&manifest_path, &pkg_manifest_path)?;
|
||||||
|
|
||||||
|
// Check if we need to create a pub.p5i file for the publisher
|
||||||
|
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)?;
|
||||||
|
|
||||||
|
// Check if this publisher was just added in this transaction
|
||||||
|
let publisher_dir = self.repo.join("publisher").join(&publisher);
|
||||||
|
let pub_p5i_path = publisher_dir.join("pub.p5i");
|
||||||
|
|
||||||
|
if !pub_p5i_path.exists() {
|
||||||
|
debug!("Creating pub.p5i file for publisher: {}", publisher);
|
||||||
|
|
||||||
|
// Create the pub.p5i file
|
||||||
|
let repo = FileBackend {
|
||||||
|
path: self.repo.clone(),
|
||||||
|
config,
|
||||||
|
catalog_manager: None,
|
||||||
|
obsoleted_manager: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
repo.create_pub_p5i_file(&publisher)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Clean up the transaction directory
|
// Clean up the transaction directory
|
||||||
fs::remove_dir_all(self.path)?;
|
fs::remove_dir_all(self.path)?;
|
||||||
|
|
||||||
|
|
@ -1333,9 +1359,14 @@ impl WritableRepository for FileBackend {
|
||||||
|
|
||||||
/// Save the repository configuration
|
/// Save the repository configuration
|
||||||
fn save_config(&self) -> Result<()> {
|
fn save_config(&self) -> Result<()> {
|
||||||
|
// Save the modern JSON format
|
||||||
let config_path = self.path.join(REPOSITORY_CONFIG_FILENAME);
|
let config_path = self.path.join(REPOSITORY_CONFIG_FILENAME);
|
||||||
let config_data = serde_json::to_string_pretty(&self.config)?;
|
let config_data = serde_json::to_string_pretty(&self.config)?;
|
||||||
fs::write(config_path, config_data)?;
|
fs::write(config_path, config_data)?;
|
||||||
|
|
||||||
|
// Save the legacy INI format for backward compatibility
|
||||||
|
self.save_legacy_config()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1348,6 +1379,13 @@ impl WritableRepository for FileBackend {
|
||||||
fs::create_dir_all(Self::construct_catalog_path(&self.path, publisher))?;
|
fs::create_dir_all(Self::construct_catalog_path(&self.path, publisher))?;
|
||||||
fs::create_dir_all(Self::construct_package_dir(&self.path, publisher, ""))?;
|
fs::create_dir_all(Self::construct_package_dir(&self.path, publisher, ""))?;
|
||||||
|
|
||||||
|
// Create the publisher directory if it doesn't exist
|
||||||
|
let publisher_dir = self.path.join("publisher").join(publisher);
|
||||||
|
fs::create_dir_all(&publisher_dir)?;
|
||||||
|
|
||||||
|
// Create the pub.p5i file for backward compatibility
|
||||||
|
self.create_pub_p5i_file(publisher)?;
|
||||||
|
|
||||||
// Set as the default publisher if no default publisher is set
|
// Set as the default publisher if no default publisher is set
|
||||||
if self.config.default_publisher.is_none() {
|
if self.config.default_publisher.is_none() {
|
||||||
self.config.default_publisher = Some(publisher.to_string());
|
self.config.default_publisher = Some(publisher.to_string());
|
||||||
|
|
@ -1513,6 +1551,81 @@ impl WritableRepository for FileBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileBackend {
|
impl FileBackend {
|
||||||
|
/// Save the legacy pkg5.repository INI file for backward compatibility
|
||||||
|
pub fn save_legacy_config(&self) -> Result<()> {
|
||||||
|
let legacy_config_path = self.path.join("pkg5.repository");
|
||||||
|
let mut conf = Ini::new();
|
||||||
|
|
||||||
|
// Add publisher section with default publisher
|
||||||
|
if let Some(default_publisher) = &self.config.default_publisher {
|
||||||
|
conf.with_section(Some("publisher"))
|
||||||
|
.set("prefix", default_publisher);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add repository section with version and default values
|
||||||
|
conf.with_section(Some("repository"))
|
||||||
|
.set("version", "4")
|
||||||
|
.set("trust-anchor-directory", "/etc/certs/CA/")
|
||||||
|
.set("signature-required-names", "[]")
|
||||||
|
.set("check-certificate-revocation", "False");
|
||||||
|
|
||||||
|
// Add CONFIGURATION section with version
|
||||||
|
conf.with_section(Some("CONFIGURATION"))
|
||||||
|
.set("version", "4");
|
||||||
|
|
||||||
|
// Write the INI file
|
||||||
|
conf.write_to_file(legacy_config_path)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a pub.p5i file for a publisher for backward compatibility
|
||||||
|
///
|
||||||
|
/// Format: base_path/publisher/publisher_name/pub.p5i
|
||||||
|
fn create_pub_p5i_file(&self, publisher: &str) -> Result<()> {
|
||||||
|
// Define the structure for the pub.p5i file
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct P5iPublisherInfo {
|
||||||
|
alias: Option<String>,
|
||||||
|
name: String,
|
||||||
|
packages: Vec<String>,
|
||||||
|
repositories: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize)]
|
||||||
|
struct P5iFile {
|
||||||
|
packages: Vec<String>,
|
||||||
|
publishers: Vec<P5iPublisherInfo>,
|
||||||
|
version: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the publisher info
|
||||||
|
let publisher_info = P5iPublisherInfo {
|
||||||
|
alias: None,
|
||||||
|
name: publisher.to_string(),
|
||||||
|
packages: Vec::new(),
|
||||||
|
repositories: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the p5i file content
|
||||||
|
let p5i_content = P5iFile {
|
||||||
|
packages: Vec::new(),
|
||||||
|
publishers: vec![publisher_info],
|
||||||
|
version: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Serialize to JSON
|
||||||
|
let json_content = serde_json::to_string_pretty(&p5i_content)?;
|
||||||
|
|
||||||
|
// Create the path for the pub.p5i file
|
||||||
|
let pub_p5i_path = self.path.join("publisher").join(publisher).join("pub.p5i");
|
||||||
|
|
||||||
|
// Write the file
|
||||||
|
fs::write(pub_p5i_path, json_content)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Helper method to construct a catalog path consistently
|
/// Helper method to construct a catalog path consistently
|
||||||
///
|
///
|
||||||
/// Format: base_path/publisher/publisher_name/catalog
|
/// Format: base_path/publisher/publisher_name/catalog
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,20 @@ mod tests {
|
||||||
assert!(repo.config.publishers.contains(&"example.com".to_string()));
|
assert!(repo.config.publishers.contains(&"example.com".to_string()));
|
||||||
assert!(FileBackend::construct_catalog_path(&repo_path, "example.com").exists());
|
assert!(FileBackend::construct_catalog_path(&repo_path, "example.com").exists());
|
||||||
assert!(FileBackend::construct_package_dir(&repo_path, "example.com", "").exists());
|
assert!(FileBackend::construct_package_dir(&repo_path, "example.com", "").exists());
|
||||||
|
|
||||||
|
// Check that the pub.p5i file was created for backward compatibility
|
||||||
|
let pub_p5i_path = repo_path.join("publisher").join("example.com").join("pub.p5i");
|
||||||
|
assert!(pub_p5i_path.exists(), "pub.p5i file should be created for backward compatibility");
|
||||||
|
|
||||||
|
// Verify the content of the pub.p5i file
|
||||||
|
let pub_p5i_content = fs::read_to_string(&pub_p5i_path).unwrap();
|
||||||
|
let pub_p5i_json: serde_json::Value = serde_json::from_str(&pub_p5i_content).unwrap();
|
||||||
|
|
||||||
|
// Check the structure of the pub.p5i file
|
||||||
|
assert_eq!(pub_p5i_json["version"], 1);
|
||||||
|
assert!(pub_p5i_json["packages"].is_array());
|
||||||
|
assert!(pub_p5i_json["publishers"].is_array());
|
||||||
|
assert_eq!(pub_p5i_json["publishers"][0]["name"], "example.com");
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
cleanup_test_dir(&test_dir);
|
cleanup_test_dir(&test_dir);
|
||||||
|
|
@ -432,4 +446,91 @@ mod tests {
|
||||||
// Clean up
|
// Clean up
|
||||||
cleanup_test_dir(&test_dir);
|
cleanup_test_dir(&test_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_transaction_pub_p5i_creation() {
|
||||||
|
// Run the setup script to prepare the test environment
|
||||||
|
let (prototype_dir, manifest_dir) = run_setup_script();
|
||||||
|
|
||||||
|
// Create a test directory
|
||||||
|
let test_dir = create_test_dir("transaction_pub_p5i");
|
||||||
|
let repo_path = test_dir.join("repo");
|
||||||
|
|
||||||
|
// Create a repository
|
||||||
|
let mut repo = FileBackend::create(&repo_path, RepositoryVersion::V4).unwrap();
|
||||||
|
|
||||||
|
// Create a new publisher through a transaction
|
||||||
|
let publisher = "transaction_test";
|
||||||
|
|
||||||
|
// Start a transaction
|
||||||
|
let mut transaction = repo.begin_transaction().unwrap();
|
||||||
|
|
||||||
|
// Set the publisher for the transaction
|
||||||
|
transaction.set_publisher(publisher);
|
||||||
|
|
||||||
|
// Add a simple manifest to the transaction
|
||||||
|
let manifest_path = manifest_dir.join("example.p5m");
|
||||||
|
let manifest = Manifest::parse_file(&manifest_path).unwrap();
|
||||||
|
transaction.update_manifest(manifest);
|
||||||
|
|
||||||
|
// Commit the transaction
|
||||||
|
transaction.commit().unwrap();
|
||||||
|
|
||||||
|
// Check that the pub.p5i file was created for the new publisher
|
||||||
|
let pub_p5i_path = repo_path.join("publisher").join(publisher).join("pub.p5i");
|
||||||
|
assert!(pub_p5i_path.exists(), "pub.p5i file should be created for new publisher in transaction");
|
||||||
|
|
||||||
|
// Verify the content of the pub.p5i file
|
||||||
|
let pub_p5i_content = fs::read_to_string(&pub_p5i_path).unwrap();
|
||||||
|
let pub_p5i_json: serde_json::Value = serde_json::from_str(&pub_p5i_content).unwrap();
|
||||||
|
|
||||||
|
// Check the structure of the pub.p5i file
|
||||||
|
assert_eq!(pub_p5i_json["version"], 1);
|
||||||
|
assert!(pub_p5i_json["packages"].is_array());
|
||||||
|
assert!(pub_p5i_json["publishers"].is_array());
|
||||||
|
assert_eq!(pub_p5i_json["publishers"][0]["name"], publisher);
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
cleanup_test_dir(&test_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_legacy_pkg5_repository_creation() {
|
||||||
|
// Create a test directory
|
||||||
|
let test_dir = create_test_dir("legacy_pkg5_repository");
|
||||||
|
let repo_path = test_dir.join("repo");
|
||||||
|
|
||||||
|
// Create a repository
|
||||||
|
let mut repo = FileBackend::create(&repo_path, RepositoryVersion::V4).unwrap();
|
||||||
|
|
||||||
|
// Add a publisher
|
||||||
|
let publisher = "openindiana.org";
|
||||||
|
repo.add_publisher(publisher).unwrap();
|
||||||
|
|
||||||
|
// Set as default publisher
|
||||||
|
repo.set_default_publisher(publisher).unwrap();
|
||||||
|
|
||||||
|
// Check that the pkg5.repository file was created
|
||||||
|
let pkg5_repo_path = repo_path.join("pkg5.repository");
|
||||||
|
assert!(pkg5_repo_path.exists(), "pkg5.repository file should be created for backward compatibility");
|
||||||
|
|
||||||
|
// Verify the content of the pkg5.repository file
|
||||||
|
let pkg5_content = fs::read_to_string(&pkg5_repo_path).unwrap();
|
||||||
|
|
||||||
|
// Print the content for debugging
|
||||||
|
println!("pkg5.repository content:\n{}", pkg5_content);
|
||||||
|
|
||||||
|
// Check that the file contains the expected sections and values
|
||||||
|
assert!(pkg5_content.contains("[publisher]"));
|
||||||
|
assert!(pkg5_content.contains("prefix=openindiana.org"));
|
||||||
|
assert!(pkg5_content.contains("[repository]"));
|
||||||
|
assert!(pkg5_content.contains("version=4"));
|
||||||
|
assert!(pkg5_content.contains("trust-anchor-directory=/etc/certs/CA/"));
|
||||||
|
assert!(pkg5_content.contains("signature-required-names=[]"));
|
||||||
|
assert!(pkg5_content.contains("check-certificate-revocation=False"));
|
||||||
|
assert!(pkg5_content.contains("[CONFIGURATION]"));
|
||||||
|
|
||||||
|
// Clean up
|
||||||
|
cleanup_test_dir(&test_dir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue