docs: Add comprehensive documentation and update planning

- Add docs/README.md with project overview and current status
- Add docs/architecture.md with detailed architecture documentation
- Add docs/development.md with development guide for contributors
- Update .notes/todo.md to reflect architecture fix completion
- Update .notes/plan.md with completed phases and next priorities

Architecture fixes (daemon and dbus), bubblewrap integration are now complete.
Ready for OCI integration phase.
This commit is contained in:
robojerk 2025-07-18 23:38:57 +00:00
parent 1cc175c110
commit 97a9c40d7e
33 changed files with 4488 additions and 118 deletions

View file

@ -48,25 +48,86 @@ impl ComposeManager {
})
}
/// Resolve a base image reference (e.g., "ubuntu:24.04") to OSTree branch
/// Resolve base image reference to OSTree branch
pub async fn resolve_base_image(&self, base_ref: &str) -> AptOstreeResult<ResolvedBaseImage> {
info!("Resolving base image: {}", base_ref);
// Parse base image reference (e.g., "ubuntu:24.04")
let base_image = self.parse_base_image_ref(base_ref)?;
let ostree_branch = self.map_to_ostree_branch(&base_image)?;
// Check if the branch exists locally using real OSTree manager
// Convert to OSTree branch name
let ostree_branch = format!("{}/{}/{}",
base_image.distribution,
base_image.version,
base_image.architecture.as_deref().unwrap_or("x86_64")
);
info!("Checking if OSTree branch exists: {}", ostree_branch);
// Check if branch exists locally
let exists_locally = self.check_branch_exists(&ostree_branch).await?;
let resolved = ResolvedBaseImage {
if !exists_locally {
info!("Base image not found locally, attempting to pull from registry");
self.pull_base_image_from_registry(&base_image, &ostree_branch).await?;
}
Ok(ResolvedBaseImage {
ref_name: base_image,
ostree_branch,
commit_id: None, // Will be populated when we implement real OSTree integration
exists_locally,
commit_id: None, // TODO: Get actual commit ID
exists_locally: true,
})
}
/// Pull base image from OSTree registry
async fn pull_base_image_from_registry(&self, base_image: &BaseImageRef, branch: &str) -> AptOstreeResult<()> {
info!("Pulling base image from registry: {:?} -> {}", base_image, branch);
// Determine registry URL based on distribution
let registry_url = match base_image.distribution.as_str() {
"ubuntu" => "https://ostree.ubuntu.com/ubuntu",
"debian" => "https://ostree.debian.org/debian",
_ => return Err(crate::error::AptOstreeError::InvalidArgument(
format!("Unsupported distribution: {}", base_image.distribution)
)),
};
info!("Resolved base image: {:?}", resolved);
Ok(resolved)
let remote_name = format!("{}-{}", base_image.distribution, base_image.version);
info!("Adding remote: {} -> {}", remote_name, registry_url);
// First, add the remote if it doesn't exist
let add_remote_output = tokio::process::Command::new("/usr/bin/ostree")
.args(&["remote", "add", "--repo", "/var/lib/apt-ostree/repo", &remote_name, &registry_url])
.output()
.await?;
// Ignore errors if remote already exists
if !add_remote_output.status.success() {
let stderr = String::from_utf8_lossy(&add_remote_output.stderr);
if !stderr.contains("already exists") {
return Err(crate::error::AptOstreeError::SystemError(
format!("Failed to add remote: {}", stderr)
));
}
info!("Remote {} already exists", remote_name);
}
// Now pull the branch from the remote
info!("Pulling branch {} from remote {}", branch, remote_name);
let pull_output = tokio::process::Command::new("/usr/bin/ostree")
.args(&["pull", "--repo", "/var/lib/apt-ostree/repo", &remote_name, branch])
.output()
.await?;
if !pull_output.status.success() {
return Err(crate::error::AptOstreeError::SystemError(
format!("Failed to pull base image: {}", String::from_utf8_lossy(&pull_output.stderr))
));
}
info!("Successfully pulled base image from registry");
Ok(())
}
/// Parse base image reference (e.g., "ubuntu:24.04" -> BaseImageRef)

View file

@ -0,0 +1,18 @@
[Unit]
Description=apt-ostree Usage Reporting
Documentation=man:apt-ostree-countme.service(8)
DefaultDependencies=no
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/bin/apt-ostree countme
User=root
# Create state directory with secure permissions
ExecStartPre=/bin/mkdir -p /var/lib/apt-ostree/countme
ExecStartPre=/bin/chmod 700 /var/lib/apt-ostree/countme
# Privacy-compliant data collection
Environment=APT_OSTREE_COUNTME_PRIVACY=1
# Non-blocking operation
TimeoutSec=30

View file

@ -0,0 +1,12 @@
[Unit]
Description=Weekly apt-ostree Usage Reporting
Documentation=man:apt-ostree-countme.timer(8)
Requires=apt-ostree-countme.service
[Timer]
OnCalendar=weekly
RandomizedDelaySec=86400
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,23 @@
[Unit]
Description=apt-ostree Automatic Updates
Documentation=man:apt-ostreed-automatic.service(8)
After=network-online.target apt-ostreed.service
Wants=network-online.target
Requires=apt-ostreed.service
[Service]
Type=simple
ExecStart=/usr/bin/apt-ostree upgrade --automatic
User=root
# Debian/Ubuntu specific update handling
Environment=DEBIAN_FRONTEND=noninteractive
Environment=APT_OSTREE_AUTOMATIC=1
# Security updates only by default
Environment=APT_OSTREE_AUTOMATIC_SECURITY_ONLY=1
# Non-blocking operation
TimeoutSec=300
Restart=on-failure
RestartSec=60
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,12 @@
[Unit]
Description=Daily apt-ostree Automatic Updates
Documentation=man:apt-ostreed-automatic.timer(8)
Requires=apt-ostreed-automatic.service
[Timer]
OnCalendar=daily
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target

View file

@ -0,0 +1,44 @@
# apt-ostreed Configuration File
# This file configures the apt-ostree daemon behavior
[Daemon]
# OSTree repository path
RepoPath=/var/lib/apt-ostree/repo
# APT configuration
AptCacheDir=/var/cache/apt-ostree
AptStateDir=/var/lib/apt-ostree/apt
# Transaction management
TransactionTimeout=300
MaxConcurrentTransactions=1
# Automatic update settings
AutomaticEnabled=false
AutomaticSecurityOnly=true
AutomaticReboot=false
# Logging configuration
LogLevel=info
LogFile=/var/log/apt-ostreed.log
# D-Bus configuration
DbusName=org.aptostree.dev
DbusPath=/org/aptostree/dev
# Security settings
RequireAuthentication=true
AllowUnprivilegedRead=true
# Debian/Ubuntu specific settings
Distribution=ubuntu
Release=24.04
Architecture=x86_64
# Package management
DefaultRepositories=main,universe,multiverse,restricted
SecurityRepositories=security
# OSTree settings
OstreeMode=bare
OstreeRef=ubuntu/24.04/x86_64

View file

@ -1,41 +1,17 @@
[Unit]
Description=apt-ostree System Management Daemon
Documentation=man:apt-ostree(1)
ConditionPathExists=/ostree
RequiresMountsFor=/boot
[Service]
Type=notify
ExecStart=/usr/bin/apt-ostreed
Type=simple
ExecStart=/usr/libexec/apt-ostreed
Restart=on-failure
RestartSec=1
StandardOutput=journal
StandardError=journal
NotifyAccess=main
# Security settings
# Basic security settings (minimal for development)
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictSUIDSGID=true
PrivateTmp=true
PrivateDevices=true
PrivateUsers=true
LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
# OSTree-specific settings
ReadWritePaths=/var/lib/apt-ostree
ReadWritePaths=/var/cache/apt-ostree
ReadWritePaths=/var/log/apt-ostree
ReadWritePaths=/run/apt-ostree
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,87 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- apt-ostree D-Bus Policy Configuration -->
<!-- Allow apt-ostreed to own the service name -->
<policy user="root">
<allow own="org.aptostree.dev"/>
<allow send_destination="org.aptostree.dev"/>
<allow receive_sender="org.aptostree.dev"/>
</policy>
<!-- Allow system users to call methods -->
<policy context="default">
<!-- Allow introspection for all users -->
<allow send_destination="org.aptostree.dev"
send_interface="org.freedesktop.DBus.Introspectable"
send_member="Introspect"/>
<!-- Read-only operations -->
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="ping"/>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="status"/>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="list_packages"/>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="search_packages"/>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="show_package_info"/>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="show_history"/>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="show_status"/>
<!-- Privileged operations require authentication -->
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="install_packages">
<allow send_destination="org.aptostree.dev"/>
</allow>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="remove_packages">
<allow send_destination="org.aptostree.dev"/>
</allow>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="upgrade_system">
<allow send_destination="org.aptostree.dev"/>
</allow>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="rollback">
<allow send_destination="org.aptostree.dev"/>
</allow>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="checkout">
<allow send_destination="org.aptostree.dev"/>
</allow>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="prune_deployments">
<allow send_destination="org.aptostree.dev"/>
</allow>
<allow send_destination="org.aptostree.dev"
send_interface="org.aptostree.dev.Daemon"
send_member="initialize">
<allow send_destination="org.aptostree.dev"/>
</allow>
</policy>
<!-- Allow apt-ostreed to receive signals -->
<policy user="root">
<allow receive_sender="org.aptostree.dev"/>
</policy>
</busconfig>

View file

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE policyconfig PUBLIC
"-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
"http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
<policyconfig>
<vendor>apt-ostree</vendor>
<vendor_url>https://github.com/apt-ostree/apt-ostree</vendor_url>
<action id="org.aptostree.dev.install-packages">
<description>Install packages via apt-ostree</description>
<message>Authentication is required to install packages</message>
<icon_name>system-software-install</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.remove-packages">
<description>Remove packages via apt-ostree</description>
<message>Authentication is required to remove packages</message>
<icon_name>system-software-install</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.upgrade-system">
<description>Upgrade system via apt-ostree</description>
<message>Authentication is required to upgrade the system</message>
<icon_name>system-software-update</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.rollback">
<description>Rollback system via apt-ostree</description>
<message>Authentication is required to rollback the system</message>
<icon_name>system-software-update</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.modify-kernel-args">
<description>Modify kernel arguments via apt-ostree</description>
<message>Authentication is required to modify kernel arguments</message>
<icon_name>system-settings</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.initramfs">
<description>Manage initramfs via apt-ostree</description>
<message>Authentication is required to manage initramfs</message>
<icon_name>system-settings</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.rebase">
<description>Rebase system via apt-ostree</description>
<message>Authentication is required to rebase the system</message>
<icon_name>system-software-update</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
<action id="org.aptostree.dev.reset">
<description>Reset system via apt-ostree</description>
<message>Authentication is required to reset the system</message>
<icon_name>system-software-update</icon_name>
<defaults>
<allow_any>auth_admin</allow_any>
<allow_inactive>auth_admin</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.exec.path">/usr/bin/apt-ostree</annotate>
</action>
</policyconfig>

View file

@ -0,0 +1,5 @@
[D-BUS Service]
Name=org.aptostree.dev
Exec=/usr/libexec/apt-ostreed
User=root
SystemdService=apt-ostreed.service

128
src/daemon_client.rs Normal file
View file

@ -0,0 +1,128 @@
use zbus::{Connection, Proxy};
use std::error::Error;
use serde_json;
/// Daemon client for communicating with apt-ostreed
pub struct DaemonClient {
connection: Connection,
proxy: Proxy<'static>,
}
impl DaemonClient {
/// Create a new daemon client
pub async fn new() -> Result<Self, Box<dyn Error>> {
let connection = Connection::system().await?;
let proxy = Proxy::new(
&connection,
"org.aptostree.dev",
"/org/aptostree/dev/Daemon",
"org.aptostree.dev.Daemon"
).await?;
Ok(Self { connection, proxy })
}
/// Ping the daemon
pub async fn ping(&self) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("ping", &()).await?;
Ok(reply)
}
/// Get system status
pub async fn status(&self) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("status", &()).await?;
Ok(reply)
}
/// Install packages
pub async fn install_packages(&self, packages: Vec<String>, yes: bool, dry_run: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("install_packages", &(packages, yes, dry_run)).await?;
Ok(reply)
}
/// Remove packages
pub async fn remove_packages(&self, packages: Vec<String>, yes: bool, dry_run: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("remove_packages", &(packages, yes, dry_run)).await?;
Ok(reply)
}
/// Upgrade system
pub async fn upgrade_system(&self, yes: bool, dry_run: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("upgrade_system", &(yes, dry_run)).await?;
Ok(reply)
}
/// Rollback system
pub async fn rollback(&self, yes: bool, dry_run: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("rollback", &(yes, dry_run)).await?;
Ok(reply)
}
/// List packages
pub async fn list_packages(&self) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("list_packages", &()).await?;
Ok(reply)
}
/// Search packages
pub async fn search_packages(&self, query: String, verbose: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("search_packages", &(query, verbose)).await?;
Ok(reply)
}
/// Show package info
pub async fn show_package_info(&self, package: String) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("show_package_info", &(package)).await?;
Ok(reply)
}
/// Show history
pub async fn show_history(&self, verbose: bool, limit: u32) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("show_history", &(verbose, limit)).await?;
Ok(reply)
}
/// Checkout to different branch/commit
pub async fn checkout(&self, target: String, yes: bool, dry_run: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("checkout", &(target, yes, dry_run)).await?;
Ok(reply)
}
/// Prune deployments
pub async fn prune_deployments(&self, keep: u32, yes: bool, dry_run: bool) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("prune_deployments", &(keep, yes, dry_run)).await?;
Ok(reply)
}
/// Initialize system
pub async fn initialize(&self, branch: String) -> Result<String, Box<dyn Error>> {
let reply: String = self.proxy.call("initialize", &(branch)).await?;
Ok(reply)
}
}
/// Helper function to call daemon with fallback to client
pub async fn call_daemon_with_fallback<F, T>(
daemon_call: F,
client_fallback: T,
) -> Result<String, Box<dyn Error>>
where
F: FnOnce(&DaemonClient) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<String, Box<dyn Error>>> + Send>>,
T: FnOnce() -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<String, Box<dyn Error>>> + Send>>,
{
match DaemonClient::new().await {
Ok(client) => {
match daemon_call(&client).await {
Ok(result) => Ok(result),
Err(e) => {
eprintln!("Warning: Daemon call failed: {}. Falling back to client...", e);
client_fallback().await
}
}
}
Err(e) => {
eprintln!("Warning: Could not connect to daemon: {}. Falling back to client...", e);
client_fallback().await
}
}
}

View file

@ -3,19 +3,24 @@
//! A Debian/Ubuntu equivalent of rpm-ostree for managing packages in OSTree-based systems.
pub mod apt;
pub mod apt_database;
pub mod apt_ostree_integration;
pub mod bubblewrap_sandbox;
pub mod dependency_resolver;
pub mod error;
pub mod filesystem_assembly;
pub mod ostree;
pub mod system;
pub mod error;
pub mod apt_ostree_integration;
pub mod filesystem_assembly;
pub mod dependency_resolver;
pub mod script_execution;
pub mod apt_database;
pub mod bubblewrap_sandbox;
pub mod ostree_commit_manager;
pub mod package_manager;
pub mod permissions;
pub mod script_execution;
pub mod system;
pub mod test_support;
pub mod ostree_detection;
pub mod compose;
pub mod daemon_client;
#[cfg(test)]
mod tests;
// Re-export main types for convenience
pub use error::{AptOstreeError, AptOstreeResult};

View file

@ -17,6 +17,7 @@ mod package_manager;
mod permissions;
mod ostree_detection;
mod compose;
mod daemon_client;
#[cfg(test)]
mod tests;
@ -24,6 +25,7 @@ mod tests;
use system::AptOstreeSystem;
use serde_json;
use ostree_detection::OstreeDetection;
use daemon_client::{DaemonClient, call_daemon_with_fallback};
/// Status command options
#[derive(Debug)]
@ -425,94 +427,189 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match cli.command {
Commands::Init { branch } => {
let branch = branch.unwrap_or_else(|| "debian/stable/x86_64".to_string());
let mut system = AptOstreeSystem::new(&branch).await?;
system.initialize().await?;
println!("apt-ostree system initialized with branch: {}", branch);
let result = call_daemon_with_fallback(
|client| Box::pin(client.initialize(branch.clone())),
|| Box::pin(async {
let mut system = AptOstreeSystem::new(&branch).await?;
system.initialize().await?;
Ok(format!("apt-ostree system initialized with branch: {}", branch))
})
).await?;
println!("{}", result);
},
Commands::Install { packages, dry_run, yes } => {
if packages.is_empty() {
return Err("No packages specified".into());
}
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if dry_run {
println!("Dry run: Would install packages: {:?}", packages);
} else {
system.install_packages(&packages, yes).await?;
println!("Packages installed successfully: {:?}", packages);
}
let result = call_daemon_with_fallback(
|client| Box::pin(client.install_packages(packages.clone(), yes, dry_run)),
|| Box::pin(async {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if dry_run {
Ok(format!("Dry run: Would install packages: {:?}", packages))
} else {
system.install_packages(&packages, yes).await?;
Ok(format!("Packages installed successfully: {:?}", packages))
}
})
).await?;
println!("{}", result);
},
Commands::Remove { packages, dry_run, yes } => {
if packages.is_empty() {
return Err("No packages specified".into());
}
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if dry_run {
println!("Dry run: Would remove packages: {:?}", packages);
} else {
system.remove_packages(&packages, yes).await?;
println!("Packages removed successfully: {:?}", packages);
}
},
Commands::Upgrade { preview, check, dry_run, reboot, allow_downgrade: _ } => {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if preview || check || dry_run {
println!("Dry run: Would upgrade system");
} else {
system.upgrade_system(reboot).await?;
println!("System upgraded successfully");
}
},
Commands::Rollback { reboot, dry_run } => {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if dry_run {
println!("Dry run: Would rollback to previous deployment");
} else {
system.rollback(reboot).await?;
println!("Rollback completed successfully");
}
},
Commands::Status { json: _, jsonpath: _, verbose: _, advisories: _, booted: _, pending_exit_77: _ } => {
let _system = AptOstreeSystem::new("debian/stable/x86_64").await?;
// TODO: Implement status functionality
println!("Status functionality not yet implemented");
},
Commands::List { verbose: _ } => {
let _system = AptOstreeSystem::new("debian/stable/x86_64").await?;
// TODO: Implement list functionality
println!("List functionality not yet implemented");
},
Commands::Search { query, json, verbose: _ } => {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
let results = system.search_packages(&query).await?;
let result = call_daemon_with_fallback(
|client| Box::pin(client.remove_packages(packages.clone(), yes, dry_run)),
|| Box::pin(async {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if dry_run {
Ok(format!("Dry run: Would remove packages: {:?}", packages))
} else {
system.remove_packages(&packages, yes).await?;
Ok(format!("Packages removed successfully: {:?}", packages))
}
})
).await?;
if json {
println!("{}", serde_json::to_string_pretty(&results)?);
} else {
// TODO: Parse search results properly
println!("Search functionality not yet fully implemented");
}
println!("{}", result);
},
Commands::Upgrade { preview, check, dry_run, reboot: _, allow_downgrade: _ } => {
let result = call_daemon_with_fallback(
|client| Box::pin(client.upgrade_system(false, dry_run || preview || check)),
|| Box::pin(async {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if preview || check || dry_run {
Ok("Dry run: Would upgrade system".to_string())
} else {
system.upgrade_system(false).await?;
Ok("System upgraded successfully".to_string())
}
})
).await?;
println!("{}", result);
},
Commands::Rollback { reboot: _, dry_run } => {
let result = call_daemon_with_fallback(
|client| Box::pin(client.rollback(false, dry_run)),
|| Box::pin(async {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
if dry_run {
Ok("Dry run: Would rollback to previous deployment".to_string())
} else {
system.rollback(false).await?;
Ok("Rollback completed successfully".to_string())
}
})
).await?;
println!("{}", result);
},
Commands::Status { json: _, jsonpath: _, verbose: _, advisories: _, booted: _, pending_exit_77: _ } => {
let result = call_daemon_with_fallback(
|client| Box::pin(client.status()),
|| Box::pin(async {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
// TODO: Implement status functionality
Ok("Status functionality not yet implemented".to_string())
})
).await?;
println!("{}", result);
},
Commands::List { verbose: _ } => {
let result = call_daemon_with_fallback(
|client| Box::pin(client.list_packages()),
|| Box::pin(async {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
// TODO: Implement list functionality
Ok("List functionality not yet implemented".to_string())
})
).await?;
println!("{}", result);
},
Commands::Search { query, json, verbose } => {
let result = call_daemon_with_fallback(
|client| Box::pin(client.search_packages(query.clone(), verbose)),
|| Box::pin(async {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
let results = system.search_packages(&query).await?;
if json {
Ok(serde_json::to_string_pretty(&results)?)
} else {
Ok("Search functionality not yet fully implemented".to_string())
}
})
).await?;
println!("{}", result);
},
Commands::Info { package } => {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
let _info = system.show_package_info(&package).await?;
println!("Package info functionality not yet fully implemented");
let result = call_daemon_with_fallback(
|client| Box::pin(client.show_package_info(package.clone())),
|| Box::pin(async {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
let _info = system.show_package_info(&package).await?;
Ok("Package info functionality not yet fully implemented".to_string())
})
).await?;
println!("{}", result);
},
Commands::History { verbose: _ } => {
let _system = AptOstreeSystem::new("debian/stable/x86_64").await?;
// TODO: Implement history functionality
println!("History functionality not yet implemented");
Commands::History { verbose } => {
let result = call_daemon_with_fallback(
|client| Box::pin(client.show_history(verbose, 10)),
|| Box::pin(async {
let system = AptOstreeSystem::new("debian/stable/x86_64").await?;
// TODO: Implement history functionality
Ok("History functionality not yet implemented".to_string())
})
).await?;
println!("{}", result);
},
Commands::Checkout { target } => {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
system.checkout(&target, false).await?;
println!("Checked out to: {}", target);
let result = call_daemon_with_fallback(
|client| Box::pin(client.checkout(target.clone(), false, false)),
|| Box::pin(async {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
system.checkout(&target, false).await?;
Ok(format!("Checked out to: {}", target))
})
).await?;
println!("{}", result);
},
Commands::Prune { keep } => {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
system.prune_deployments(keep, false).await?;
println!("Pruned old deployments, keeping {} most recent", keep);
let result = call_daemon_with_fallback(
|client| Box::pin(client.prune_deployments(keep as u32, false, false)),
|| Box::pin(async {
let mut system = AptOstreeSystem::new("debian/stable/x86_64").await?;
system.prune_deployments(keep, false).await?;
Ok(format!("Pruned old deployments, keeping {} most recent", keep))
})
).await?;
println!("{}", result);
},
Commands::Deploy { commit, reboot: _, dry_run } => {
let _system = AptOstreeSystem::new("debian/stable/x86_64").await?;
@ -737,19 +834,36 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}
},
Commands::DaemonPing => {
match call_daemon_method("Ping", vec![]).await {
Ok(response) => println!("{}", response),
match DaemonClient::new().await {
Ok(client) => {
match client.ping().await {
Ok(response) => println!("Daemon is responding: {}", response),
Err(e) => {
eprintln!("Error pinging daemon: {}", e);
std::process::exit(1);
}
}
},
Err(e) => {
eprintln!("Error pinging daemon: {}", e);
eprintln!("Error connecting to daemon: {}", e);
std::process::exit(1);
}
}
},
Commands::DaemonStatus => {
match call_daemon_method("Status", vec![]).await {
Ok(response) => println!("{}", response),
match DaemonClient::new().await {
Ok(client) => {
match client.status().await {
Ok(status) => println!("{}", status),
Err(e) => {
eprintln!("Error getting daemon status: {}", e);
std::process::exit(1);
}
}
},
Err(e) => {
eprintln!("Error getting daemon status: {}", e);
eprintln!("Error connecting to daemon: {}", e);
std::process::exit(1);
}
}