apt-ostree/src/commands/internals.rs
robojerk 45b319046f Fix compilation errors for development commands
- Fix feature gate placement for development commands
- Make struct definitions always available, only gate implementations
- Fix Self constructor usage in unit structs
- Ensure development commands compile without development feature enabled
- Fix CLI argument handling for development commands
- Project now compiles successfully in CI/CD environment
2025-08-18 11:53:14 -07:00

382 lines
13 KiB
Rust

//! Internal system commands for advanced operations
use crate::commands::Command;
use apt_ostree::lib::error::{AptOstreeError, AptOstreeResult};
use apt_ostree::lib::ostree::OstreeManager;
use apt_ostree::lib::apt::AptManager;
use std::fs;
use std::path::Path;
use std::process::Command as ProcessCommand;
use std::os::unix::fs::PermissionsExt;
/// Internals command - Internal system commands for advanced operations
pub struct InternalsCommand;
impl InternalsCommand {
pub fn new() -> Self {
InternalsCommand
}
}
#[cfg(feature = "development")]
impl Command for InternalsCommand {
fn execute(&self, args: &[String]) -> AptOstreeResult<()> {
if args.is_empty() || args.contains(&"--help".to_string()) || args.contains(&"-h".to_string()) {
self.show_help();
return Ok(());
}
let subcommand = &args[0];
let sub_args = &args[1..];
match subcommand.as_str() {
"diagnostics" => self.handle_diagnostics(sub_args),
"validate-state" => self.handle_validate_state(sub_args),
"debug-dump" => self.handle_debug_dump(sub_args),
_ => {
println!("Unknown internals subcommand: {}", subcommand);
println!("Use 'apt-ostree internals --help' for available subcommands");
Ok(())
}
}
}
fn name(&self) -> &'static str {
"internals"
}
fn description(&self) -> &'static str {
"Internal system commands for advanced operations"
}
fn show_help(&self) {
println!("Usage: apt-ostree internals <SUBCOMMAND> [OPTIONS]");
println!();
println!("Internal system commands for apt-ostree.");
println!("These commands are for advanced system operations and diagnostics.");
println!();
println!("Subcommands:");
println!(" diagnostics Internal system diagnostics");
println!(" validate-state System state validation");
println!(" debug-dump Debug information dump");
println!();
println!("Options:");
println!(" --help, -h Show this help message");
println!();
println!("Examples:");
println!(" apt-ostree internals diagnostics");
println!(" apt-ostree internals validate-state");
println!(" apt-ostree internals debug-dump");
}
}
impl InternalsCommand {
fn handle_diagnostics(&self, _args: &[String]) -> AptOstreeResult<()> {
println!("🔍 Running Internal Diagnostics");
println!("===============================");
// Check system components
self.check_ostree_system()?;
self.check_apt_system()?;
self.check_daemon_status()?;
self.check_file_permissions()?;
println!("Diagnostics completed successfully");
Ok(())
}
fn handle_validate_state(&self, _args: &[String]) -> AptOstreeResult<()> {
println!("✅ Validating System State");
println!("===========================");
// Validate OSTree state
let ostree_manager = OstreeManager::new();
if ostree_manager.is_available() {
println!("OSTree: Available");
self.validate_ostree_state(&ostree_manager)?;
} else {
println!("OSTree: Not available");
}
// Validate APT state
let apt_manager = AptManager::new();
self.validate_apt_state(&apt_manager)?;
println!("System state validation completed");
Ok(())
}
fn handle_debug_dump(&self, _args: &[String]) -> AptOstreeResult<()> {
println!("🐛 Debug Information Dump");
println!("=========================");
// System information
self.dump_system_info()?;
// OSTree information
self.dump_ostree_info()?;
// APT information
self.dump_apt_info()?;
// Daemon information
self.dump_daemon_info()?;
println!("Debug information dump completed");
Ok(())
}
fn check_ostree_system(&self) -> AptOstreeResult<()> {
println!("Checking OSTree system...");
let ostree_manager = OstreeManager::new();
if ostree_manager.is_available() {
println!(" ✓ OSTree is available");
if ostree_manager.is_ostree_booted() {
println!(" ✓ System is booted from OSTree");
} else {
println!(" ⚠ System is not booted from OSTree");
}
} else {
println!(" ❌ OSTree is not available");
}
Ok(())
}
fn check_apt_system(&self) -> AptOstreeResult<()> {
println!("Checking APT system...");
let _apt_manager = AptManager::new();
// Check if apt-get is available
if ProcessCommand::new("apt-get").arg("--version").output().is_ok() {
println!(" ✓ apt-get is available");
} else {
println!(" ❌ apt-get is not available");
}
// Check APT cache directory
let cache_dir = "/var/cache/apt";
if Path::new(cache_dir).exists() {
println!(" ✓ APT cache directory exists: {}", cache_dir);
} else {
println!(" ❌ APT cache directory missing: {}", cache_dir);
}
Ok(())
}
fn check_daemon_status(&self) -> AptOstreeResult<()> {
println!("Checking daemon status...");
// Check if daemon service is running
let output = ProcessCommand::new("systemctl")
.arg("is-active")
.arg("apt-ostreed")
.output();
match output {
Ok(output) => {
let status = String::from_utf8_lossy(&output.stdout).trim().to_string();
if status == "active" {
println!(" ✓ apt-ostreed service is active");
} else {
println!(" ⚠ apt-ostreed service status: {}", status);
}
}
Err(_) => {
println!(" ❌ Could not check apt-ostreed service status");
}
}
Ok(())
}
fn check_file_permissions(&self) -> AptOstreeResult<()> {
println!("Checking file permissions...");
// Check key directories
let dirs = [
("/etc/apt", "APT configuration"),
("/var/lib/apt", "APT state"),
("/var/cache/apt", "APT cache"),
("/var/lib/ostree", "OSTree data"),
];
for (path, description) in &dirs {
if Path::new(path).exists() {
let metadata = fs::metadata(path)
.map_err(|_| AptOstreeError::System(format!("Could not read metadata for {}", path)))?;
let permissions = metadata.permissions();
let mode = permissions.mode();
println!("{}: {:o}", description, mode & 0o777);
} else {
println!("{}: directory does not exist", description);
}
}
Ok(())
}
fn validate_ostree_state(&self, ostree_manager: &OstreeManager) -> AptOstreeResult<()> {
println!("Validating OSTree state...");
// Check deployments
match ostree_manager.list_deployments() {
Ok(deployments) => {
println!(" ✓ Found {} deployments", deployments.len());
for deployment in &deployments {
let status = if deployment.booted { "Booted" } else { "Available" };
println!(" - {}: {} ({})", deployment.id, status, deployment.commit);
}
}
Err(e) => {
println!(" ❌ Failed to list deployments: {}", e);
}
}
// Check current deployment
match ostree_manager.get_current_deployment() {
Ok(Some(current)) => {
println!(" ✓ Current deployment: {} ({})", current.id, current.commit);
}
Ok(None) => {
println!(" ⚠ No current deployment found");
}
Err(e) => {
println!(" ❌ Failed to get current deployment: {}", e);
}
}
Ok(())
}
fn validate_apt_state(&self, _apt_manager: &AptManager) -> AptOstreeResult<()> {
println!("Validating APT state...");
// Check APT sources
let sources_list = "/etc/apt/sources.list";
if Path::new(sources_list).exists() {
println!(" ✓ APT sources list exists");
} else {
println!(" ⚠ APT sources list missing");
}
// Check APT cache
let cache_dir = "/var/cache/apt";
if Path::new(cache_dir).exists() {
let entries = fs::read_dir(cache_dir)
.map_err(|_| AptOstreeError::System("Could not read APT cache directory".to_string()))?;
let count = entries.count();
println!(" ✓ APT cache contains {} entries", count);
}
Ok(())
}
fn dump_system_info(&self) -> AptOstreeResult<()> {
println!("System Information:");
println!("===================");
// OS information
if let Ok(os_release) = fs::read_to_string("/etc/os-release") {
for line in os_release.lines() {
if line.starts_with("PRETTY_NAME=") || line.starts_with("VERSION=") {
println!(" {}", line);
}
}
}
// Architecture
if let Ok(output) = ProcessCommand::new("uname").arg("-m").output() {
let arch = String::from_utf8_lossy(&output.stdout).trim().to_string();
println!(" Architecture: {}", arch);
}
// Kernel version
if let Ok(output) = ProcessCommand::new("uname").arg("-r").output() {
let kernel = String::from_utf8_lossy(&output.stdout).trim().to_string();
println!(" Kernel: {}", kernel);
}
Ok(())
}
fn dump_ostree_info(&self) -> AptOstreeResult<()> {
println!("OSTree Information:");
println!("===================");
let ostree_manager = OstreeManager::new();
if ostree_manager.is_available() {
let system_info = ostree_manager.get_system_info();
println!(" OS: {}", system_info.os);
println!(" Kernel: {}", system_info.kernel);
println!(" Architecture: {}", system_info.architecture);
match ostree_manager.get_repo_info() {
Ok(repo_info) => {
println!(" Repository: {}", repo_info.path);
println!(" Available refs: {}", repo_info.refs.len());
}
Err(e) => {
println!(" ❌ Failed to get repo info: {}", e);
}
}
} else {
println!(" OSTree not available");
}
Ok(())
}
fn dump_apt_info(&self) -> AptOstreeResult<()> {
println!("APT Information:");
println!("================");
// APT version
if let Ok(output) = ProcessCommand::new("apt-get").arg("--version").output() {
let version = String::from_utf8_lossy(&output.stdout).lines().next().unwrap_or("Unknown").to_string();
println!(" Version: {}", version);
}
// APT configuration
let config_dirs = ["/etc/apt/apt.conf.d", "/etc/apt/sources.list.d"];
for dir in &config_dirs {
if Path::new(dir).exists() {
if let Ok(entries) = fs::read_dir(dir) {
let count = entries.count();
println!(" Config files in {}: {}", dir, count);
}
}
}
Ok(())
}
fn dump_daemon_info(&self) -> AptOstreeResult<()> {
println!("Daemon Information:");
println!("===================");
// Service status
if let Ok(output) = ProcessCommand::new("systemctl").arg("show").arg("apt-ostreed").arg("--property=ActiveState").output() {
let status = String::from_utf8_lossy(&output.stdout).lines().next().unwrap_or("Unknown").to_string();
println!(" Service status: {}", status);
}
// Process information
if let Ok(output) = ProcessCommand::new("pgrep").arg("-f").arg("apt-ostreed").output() {
let pids: Vec<String> = String::from_utf8_lossy(&output.stdout).lines().map(|s| s.to_string()).collect();
if !pids.is_empty() {
println!(" Running processes: {}", pids.join(", "));
} else {
println!(" No running processes found");
}
}
Ok(())
}
}