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:
parent
1cc175c110
commit
97a9c40d7e
33 changed files with 4488 additions and 118 deletions
|
|
@ -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, ®istry_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)
|
||||
|
|
|
|||
18
src/daemon/apt-ostree-countme.service
Normal file
18
src/daemon/apt-ostree-countme.service
Normal 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
|
||||
12
src/daemon/apt-ostree-countme.timer
Normal file
12
src/daemon/apt-ostree-countme.timer
Normal 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
|
||||
23
src/daemon/apt-ostreed-automatic.service
Normal file
23
src/daemon/apt-ostreed-automatic.service
Normal 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
|
||||
12
src/daemon/apt-ostreed-automatic.timer
Normal file
12
src/daemon/apt-ostreed-automatic.timer
Normal 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
|
||||
44
src/daemon/apt-ostreed.conf
Normal file
44
src/daemon/apt-ostreed.conf
Normal 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
|
||||
|
|
@ -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
|
||||
87
src/daemon/org.aptostree.dev.conf
Normal file
87
src/daemon/org.aptostree.dev.conf
Normal 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>
|
||||
106
src/daemon/org.aptostree.dev.policy
Normal file
106
src/daemon/org.aptostree.dev.policy
Normal 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>
|
||||
5
src/daemon/org.aptostree.dev.service
Normal file
5
src/daemon/org.aptostree.dev.service
Normal 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
128
src/daemon_client.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
23
src/lib.rs
23
src/lib.rs
|
|
@ -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};
|
||||
|
|
|
|||
262
src/main.rs
262
src/main.rs
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue