mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 13:20:42 +00:00
Add package publishing functionality and default publisher management
Signed-off-by: Till Wegmueller <toasterson@gmail.com>
This commit is contained in:
parent
8a32bf3176
commit
a9584fa6d2
4 changed files with 189 additions and 4 deletions
|
|
@ -64,6 +64,37 @@ impl Transaction {
|
|||
})
|
||||
}
|
||||
|
||||
/// Update the manifest in the transaction
|
||||
///
|
||||
/// This intelligently merges the provided manifest with the existing one,
|
||||
/// preserving file actions that have already been added to the transaction.
|
||||
///
|
||||
/// The merge strategy:
|
||||
/// - Keeps all file actions from the transaction's manifest (these have been processed with checksums, etc.)
|
||||
/// - Adds any file actions from the provided manifest that don't exist in the transaction's manifest
|
||||
/// - Merges other types of actions (attributes, directories, dependencies, licenses, links) from both manifests
|
||||
pub fn update_manifest(&mut self, manifest: Manifest) {
|
||||
// Keep track of file paths that are already in the transaction's manifest
|
||||
let existing_file_paths: std::collections::HashSet<String> = self.manifest.files
|
||||
.iter()
|
||||
.map(|f| f.path.clone())
|
||||
.collect();
|
||||
|
||||
// Add file actions from the provided manifest that don't exist in the transaction's manifest
|
||||
for file in manifest.files {
|
||||
if !existing_file_paths.contains(&file.path) {
|
||||
self.manifest.add_file(file);
|
||||
}
|
||||
}
|
||||
|
||||
// Merge other types of actions
|
||||
self.manifest.attributes.extend(manifest.attributes);
|
||||
self.manifest.directories.extend(manifest.directories);
|
||||
self.manifest.dependencies.extend(manifest.dependencies);
|
||||
self.manifest.licenses.extend(manifest.licenses);
|
||||
self.manifest.links.extend(manifest.links);
|
||||
}
|
||||
|
||||
/// Process a file for the transaction
|
||||
///
|
||||
/// Takes a FileAction and a path to a file in a prototype directory.
|
||||
|
|
@ -299,6 +330,11 @@ impl Repository for FileBackend {
|
|||
fs::create_dir_all(self.path.join("catalog").join(publisher))?;
|
||||
fs::create_dir_all(self.path.join("pkg").join(publisher))?;
|
||||
|
||||
// Set as default publisher if no default publisher is set
|
||||
if self.config.default_publisher.is_none() {
|
||||
self.config.default_publisher = Some(publisher.to_string());
|
||||
}
|
||||
|
||||
// Save the updated configuration
|
||||
self.save_config()?;
|
||||
}
|
||||
|
|
@ -417,7 +453,7 @@ impl Repository for FileBackend {
|
|||
// For each package, list contents
|
||||
let mut contents = Vec::new();
|
||||
|
||||
for (pkg_name, pkg_version, pub_name) in packages {
|
||||
for (pkg_name, pkg_version, _pub_name) in packages {
|
||||
// Example content data (package, path, type)
|
||||
let example_contents = vec![
|
||||
(format!("{}@{}", pkg_name, pkg_version), "/usr/bin/example".to_string(), "file".to_string()),
|
||||
|
|
@ -504,6 +540,22 @@ impl Repository for FileBackend {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the default publisher for the repository
|
||||
fn set_default_publisher(&mut self, publisher: &str) -> Result<()> {
|
||||
// Check if the publisher exists
|
||||
if !self.config.publishers.contains(&publisher.to_string()) {
|
||||
return Err(anyhow!("Publisher does not exist: {}", publisher));
|
||||
}
|
||||
|
||||
// Set the default publisher
|
||||
self.config.default_publisher = Some(publisher.to_string());
|
||||
|
||||
// Save the updated configuration
|
||||
self.save_config()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBackend {
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ pub struct RepositoryConfig {
|
|||
pub version: RepositoryVersion,
|
||||
pub publishers: Vec<String>,
|
||||
pub properties: HashMap<String, String>,
|
||||
pub default_publisher: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for RepositoryConfig {
|
||||
|
|
@ -53,6 +54,7 @@ impl Default for RepositoryConfig {
|
|||
version: RepositoryVersion::default(),
|
||||
publishers: Vec::new(),
|
||||
properties: HashMap::new(),
|
||||
default_publisher: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,4 +96,7 @@ pub trait Repository {
|
|||
|
||||
/// Refresh repository metadata
|
||||
fn refresh(&self, publisher: Option<&str>, no_catalog: bool, no_index: bool) -> Result<()>;
|
||||
|
||||
/// Set the default publisher for the repository
|
||||
fn set_default_publisher(&mut self, publisher: &str) -> Result<()>;
|
||||
}
|
||||
|
|
@ -3,9 +3,8 @@
|
|||
// MPL was not distributed with this file, You can
|
||||
// obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::collections::HashMap;
|
||||
|
||||
use super::{Repository, RepositoryConfig, RepositoryVersion};
|
||||
|
||||
|
|
@ -299,6 +298,25 @@ impl Repository for RestBackend {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the default publisher for the repository
|
||||
fn set_default_publisher(&mut self, publisher: &str) -> Result<()> {
|
||||
// This is a stub implementation
|
||||
// In a real implementation, we would make a REST API call to set the default publisher
|
||||
|
||||
// Check if the publisher exists
|
||||
if !self.config.publishers.contains(&publisher.to_string()) {
|
||||
return Err(anyhow!("Publisher does not exist: {}", publisher));
|
||||
}
|
||||
|
||||
// Set the default publisher
|
||||
self.config.default_publisher = Some(publisher.to_string());
|
||||
|
||||
// Save the updated configuration
|
||||
self.save_config()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl RestBackend {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
use clap::{Parser, Subcommand};
|
||||
use libips::actions::{ActionError, File, Manifest};
|
||||
use libips::repository::{Repository, FileBackend};
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{Result, anyhow};
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{read_dir, OpenOptions};
|
||||
use std::io::Write;
|
||||
|
|
@ -31,6 +32,24 @@ enum Commands {
|
|||
ShowComponent {
|
||||
component: String,
|
||||
},
|
||||
/// Publish a package to a repository
|
||||
Publish {
|
||||
/// Path to the manifest file
|
||||
#[clap(short = 'm', long)]
|
||||
manifest_path: PathBuf,
|
||||
|
||||
/// Path to the prototype directory containing the files to publish
|
||||
#[clap(short = 'p', long)]
|
||||
prototype_dir: PathBuf,
|
||||
|
||||
/// Path to the repository
|
||||
#[clap(short = 'r', long)]
|
||||
repo_path: PathBuf,
|
||||
|
||||
/// Publisher name (defaults to "test" if not specified)
|
||||
#[clap(short = 'u', long)]
|
||||
publisher: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
|
|
@ -43,6 +62,12 @@ fn main() -> Result<()> {
|
|||
replacements,
|
||||
output_manifest,
|
||||
} => diff_component(component, replacements, output_manifest),
|
||||
Commands::Publish {
|
||||
manifest_path,
|
||||
prototype_dir,
|
||||
repo_path,
|
||||
publisher,
|
||||
} => publish_package(manifest_path, prototype_dir, repo_path, publisher),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,3 +310,88 @@ fn make_file_map(files: Vec<File>) -> HashMap<String, File> {
|
|||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Publish a package to a repository
|
||||
///
|
||||
/// This function:
|
||||
/// 1. Opens the repository at the specified path
|
||||
/// 2. Parses the manifest file
|
||||
/// 3. Uses the FileBackend's publish_files method to publish the files from the prototype directory
|
||||
fn publish_package(
|
||||
manifest_path: &PathBuf,
|
||||
prototype_dir: &PathBuf,
|
||||
repo_path: &PathBuf,
|
||||
publisher: &Option<String>,
|
||||
) -> Result<()> {
|
||||
// Check if the manifest file exists
|
||||
if !manifest_path.exists() {
|
||||
return Err(anyhow!("Manifest file does not exist: {}", manifest_path.display()));
|
||||
}
|
||||
|
||||
// Check if the prototype directory exists
|
||||
if !prototype_dir.exists() {
|
||||
return Err(anyhow!("Prototype directory does not exist: {}", prototype_dir.display()));
|
||||
}
|
||||
|
||||
// Parse the manifest file
|
||||
println!("Parsing manifest file: {}", manifest_path.display());
|
||||
let manifest = Manifest::parse_file(manifest_path)?;
|
||||
|
||||
// Open the repository
|
||||
println!("Opening repository at: {}", repo_path.display());
|
||||
let repo = match FileBackend::open(repo_path) {
|
||||
Ok(repo) => repo,
|
||||
Err(_) => {
|
||||
println!("Repository does not exist, creating a new one...");
|
||||
// Create a new repository with version 4
|
||||
FileBackend::create(repo_path, libips::repository::RepositoryVersion::V4)?
|
||||
}
|
||||
};
|
||||
|
||||
// Determine which publisher to use
|
||||
let publisher_name = if let Some(pub_name) = publisher {
|
||||
// Use the explicitly specified publisher
|
||||
if !repo.config.publishers.contains(pub_name) {
|
||||
return Err(anyhow!("Publisher '{}' does not exist in the repository. Please add it first using pkg6repo add-publisher.", pub_name));
|
||||
}
|
||||
pub_name.clone()
|
||||
} else {
|
||||
// Use the default publisher
|
||||
match &repo.config.default_publisher {
|
||||
Some(default_pub) => default_pub.clone(),
|
||||
None => return Err(anyhow!("No default publisher set in the repository. Please specify a publisher using the --publisher option or set a default publisher."))
|
||||
}
|
||||
};
|
||||
|
||||
// Begin a transaction
|
||||
println!("Beginning transaction for publisher: {}", publisher_name);
|
||||
let mut transaction = repo.begin_transaction()?;
|
||||
|
||||
// Add files from the prototype directory to the transaction
|
||||
println!("Adding files from prototype directory: {}", prototype_dir.display());
|
||||
for file_action in manifest.files.iter() {
|
||||
// Construct the full path to the file in the prototype directory
|
||||
let file_path = prototype_dir.join(&file_action.path);
|
||||
|
||||
// Check if the file exists
|
||||
if !file_path.exists() {
|
||||
println!("Warning: File does not exist in prototype directory: {}", file_path.display());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add the file to the transaction
|
||||
println!("Adding file: {}", file_action.path);
|
||||
transaction.add_file(file_action.clone(), &file_path)?;
|
||||
}
|
||||
|
||||
// Update the manifest in the transaction
|
||||
println!("Updating manifest in the transaction...");
|
||||
transaction.update_manifest(manifest);
|
||||
|
||||
// Commit the transaction
|
||||
println!("Committing transaction...");
|
||||
transaction.commit()?;
|
||||
|
||||
println!("Package published successfully!");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue