Fix branch name conversion bug with regex-based solution

- Replace broken sequential replace() logic with robust regex pattern
- Fix architecture name preservation (x86_64, aarch64, arm64)
- Use regex pattern ^([^_]+)_([^_]+)_(.*)$ for proper parsing
- Add lazy_static for efficient regex compilation
- Resolve compose command branch matching issues
- Test: ubuntu_24.04_x86_64 now correctly converts to ubuntu/24.04/x86_64
This commit is contained in:
robojerk 2025-07-18 20:25:07 +00:00
parent 5777c11f85
commit c39d6c03b5
4 changed files with 55 additions and 15 deletions

View file

@ -2,7 +2,7 @@
## Overview ## Overview
Fedora Atomic Desktops, including spins like Silverblue, Kinoite (KDE Plasma), Bazzite, and Bluefin, leverage rpm-ostree to provide a unique approach to operating system management built around an immutable core filesystem. This differs significantly from traditional Linux distributions and introduces some nuances in how the filesystem is structured and interact with applications. Fedora Atomic Desktops, including spins like Silverblue, Kinoite (KDE Plasma), Bazzite, and Bluefin, leverage rpm-ostree to provide a unique approach to operating system management built around an immutable core filesystem. This differs significantly from traditional Linux distributions and introduces some nuances in how the filesystem is structured and interact with applications.
**NEW: apt-ostree Integration** **NEW: apt-ostree Integration**
The apt-ostree project brings similar atomic filesystem concepts to Ubuntu/Debian systems, adapting OSTree's immutable filesystem model for APT package management. The apt-ostree project brings similar atomic filesystem concepts to Ubuntu/Debian systems, adapting OSTree's immutable filesystem model for APT package management.

View file

@ -60,6 +60,9 @@ jsonpath-rust = "0.1"
# Regular expressions # Regular expressions
regex = "1.0" regex = "1.0"
# Lazy static initialization
lazy_static = "1.4"
# UUID generation # UUID generation
uuid = { version = "1.0", features = ["v4"] } uuid = { version = "1.0", features = ["v4"] }

View file

@ -1,7 +1,6 @@
use std::path::PathBuf;
use tracing::{info, warn}; use tracing::{info, warn};
use crate::error::AptOstreeResult; use crate::error::AptOstreeResult;
use crate::system::AptOstreeSystem; use crate::ostree::OstreeManager;
/// Base image reference (e.g., "ubuntu:24.04") /// Base image reference (e.g., "ubuntu:24.04")
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -32,15 +31,18 @@ pub struct ComposeOptions {
/// Compose manager for handling base image resolution and compose operations /// Compose manager for handling base image resolution and compose operations
pub struct ComposeManager { pub struct ComposeManager {
branch: String, branch: String,
ostree_manager: OstreeManager,
} }
impl ComposeManager { impl ComposeManager {
/// Create a new compose manager /// Create a new compose manager
pub async fn new(branch: &str) -> AptOstreeResult<Self> { pub async fn new(branch: &str) -> AptOstreeResult<Self> {
// For now, don't initialize the full system to avoid OSTree validation // Initialize OSTree manager for real branch operations
// TODO: Add proper system initialization when OSTree integration is complete let ostree_manager = OstreeManager::new("/var/lib/apt-ostree/repo")?;
Ok(Self { Ok(Self {
branch: branch.to_string(), branch: branch.to_string(),
ostree_manager,
}) })
} }
@ -51,7 +53,7 @@ impl ComposeManager {
let base_image = self.parse_base_image_ref(base_ref)?; let base_image = self.parse_base_image_ref(base_ref)?;
let ostree_branch = self.map_to_ostree_branch(&base_image)?; let ostree_branch = self.map_to_ostree_branch(&base_image)?;
// Check if the branch exists locally // Check if the branch exists locally using real OSTree manager
let exists_locally = self.check_branch_exists(&ostree_branch).await?; let exists_locally = self.check_branch_exists(&ostree_branch).await?;
let resolved = ResolvedBaseImage { let resolved = ResolvedBaseImage {
@ -127,12 +129,24 @@ impl ComposeManager {
Ok(branch) Ok(branch)
} }
/// Check if an OSTree branch exists locally /// Check if an OSTree branch exists locally using real OSTree manager
async fn check_branch_exists(&self, _branch: &str) -> AptOstreeResult<bool> { async fn check_branch_exists(&self, branch: &str) -> AptOstreeResult<bool> {
// TODO: Implement real OSTree branch checking info!("Checking if OSTree branch exists: {}", branch);
// For now, return false to indicate we need to pull from registry
warn!("OSTree branch existence checking not yet implemented"); // Use the existing OSTree manager to check branch existence
Ok(false) match self.ostree_manager.list_branches() {
Ok(branches) => {
info!("Available branches: {:?}", branches);
let exists = branches.contains(&branch.to_string());
info!("Branch {} exists locally: {}", branch, exists);
Ok(exists)
},
Err(e) => {
warn!("Failed to check branch existence: {}", e);
// If we can't check, assume it doesn't exist
Ok(false)
}
}
} }
/// Create a new deployment from a base image /// Create a new deployment from a base image

View file

@ -1,12 +1,19 @@
//! Simplified OSTree-like repository manager for apt-ostree //! Simplified OSTree-like repository manager for apt-ostree
use tracing::{info}; use tracing::{info, warn};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::fs; use std::fs;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use tokio::process::Command; use tokio::process::Command;
use regex::Regex;
use lazy_static::lazy_static;
use crate::error::{AptOstreeError, AptOstreeResult}; use crate::error::{AptOstreeError, AptOstreeResult};
// Lazily initialize the regex to compile it only once
lazy_static! {
static ref BRANCH_NAME_RE: Regex = Regex::new(r"^([^_]+)_([^_]+)_(.*)$").unwrap();
}
/// Simplified OSTree-like repository manager /// Simplified OSTree-like repository manager
pub struct OstreeManager { pub struct OstreeManager {
repo_path: PathBuf, repo_path: PathBuf,
@ -198,8 +205,24 @@ impl OstreeManager {
for entry in fs::read_dir(&refs_dir)? { for entry in fs::read_dir(&refs_dir)? {
let entry = entry?; let entry = entry?;
if entry.file_type()?.is_file() { if entry.file_type()?.is_file() {
let name = entry.file_name().to_string_lossy().replace("_", "/"); let name = entry.file_name().to_string_lossy().to_string();
branches.push(name); info!("DEBUG: Original name: '{}'", name);
// Use regex to properly parse distribution_version_architecture pattern
let converted_name = if let Some(captures) = BRANCH_NAME_RE.captures(&name) {
let distribution = captures.get(1).unwrap().as_str();
let version = captures.get(2).unwrap().as_str();
let architecture = captures.get(3).unwrap().as_str(); // This correctly preserves "x86_64"
format!("{}/{}/{}", distribution, version, architecture)
} else {
// Handle cases where the branch name doesn't match the expected pattern
warn!("Branch name '{}' does not match expected pattern, returning as-is", name);
name
};
info!("DEBUG: Final converted name: '{}'", converted_name);
branches.push(converted_name);
} }
} }