Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/security-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
key: security-cargo-${{ hashFiles('**/Cargo.lock') }}

- name: Install cargo-audit
run: cargo install cargo-audit --locked
run: cargo install cargo-audit --locked --force

- name: Security audit
run: cargo audit
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "avocado-cli"
version = "0.20.0"
version = "0.21.0"
edition = "2021"
description = "Command line interface for Avocado."
authors = ["Avocado"]
Expand Down
43 changes: 33 additions & 10 deletions src/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pub struct BuildCommand {
pub dnf_args: Option<Vec<String>>,
/// Disable stamp validation and writing
pub no_stamps: bool,
/// Remote host to run on (format: user@host)
pub runs_on: Option<String>,
/// NFS port for remote execution
pub nfs_port: Option<u16>,
}

impl BuildCommand {
Expand All @@ -63,6 +67,8 @@ impl BuildCommand {
container_args,
dnf_args,
no_stamps: false,
runs_on: None,
nfs_port: None,
}
}

Expand All @@ -72,6 +78,13 @@ impl BuildCommand {
self
}

/// Set remote execution options
pub fn with_runs_on(mut self, runs_on: Option<String>, nfs_port: Option<u16>) -> Self {
self.runs_on = runs_on;
self.nfs_port = nfs_port;
self
}

/// Execute the build command
pub async fn execute(&self) -> Result<()> {
// Early target validation - load basic config first
Expand Down Expand Up @@ -143,7 +156,8 @@ impl BuildCommand {
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
ext_build_cmd.execute().await.with_context(|| {
format!("Failed to build extension '{extension_name}'")
})?;
Expand Down Expand Up @@ -212,7 +226,8 @@ impl BuildCommand {
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
ext_image_cmd.execute().await.with_context(|| {
format!("Failed to create image for extension '{extension_name}'")
})?;
Expand Down Expand Up @@ -275,7 +290,8 @@ impl BuildCommand {
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
runtime_build_cmd
.execute()
.await
Expand Down Expand Up @@ -600,7 +616,8 @@ impl BuildCommand {
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);

// Execute the extension build using the external config
match ext_build_cmd.execute().await {
Expand Down Expand Up @@ -661,7 +678,8 @@ impl BuildCommand {
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);

// Execute the image creation
ext_image_cmd.execute().await.with_context(|| {
Expand Down Expand Up @@ -917,7 +935,8 @@ echo "Successfully created image for versioned extension '$EXT_NAME-$EXT_VERSION
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
ext_build_cmd
.execute()
.await
Expand Down Expand Up @@ -954,7 +973,8 @@ echo "Successfully created image for versioned extension '$EXT_NAME-$EXT_VERSION
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
ext_image_cmd.execute().await.with_context(|| {
format!("Failed to create image for extension '{ext_name}'")
})?;
Expand Down Expand Up @@ -1070,7 +1090,8 @@ echo "Successfully created image for versioned extension '$EXT_NAME-$EXT_VERSION
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
ext_build_cmd.execute().await.with_context(|| {
format!("Failed to build extension '{extension_name}'")
})?;
Expand All @@ -1084,7 +1105,8 @@ echo "Successfully created image for versioned extension '$EXT_NAME-$EXT_VERSION
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
ext_image_cmd.execute().await.with_context(|| {
format!("Failed to create image for extension '{extension_name}'")
})?;
Expand Down Expand Up @@ -1150,7 +1172,8 @@ echo "Successfully created image for versioned extension '$EXT_NAME-$EXT_VERSION
self.container_args.clone(),
self.dnf_args.clone(),
)
.with_no_stamps(self.no_stamps);
.with_no_stamps(self.no_stamps)
.with_runs_on(self.runs_on.clone(), self.nfs_port);
runtime_build_cmd
.execute()
.await
Expand Down
34 changes: 28 additions & 6 deletions src/commands/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ pub struct CleanCommand {
config_path: Option<String>,
/// Target architecture (needed for --stamps)
target: Option<String>,
/// Force removal by killing and removing containers using the volume
force: bool,
}

impl CleanCommand {
Expand All @@ -50,6 +52,7 @@ impl CleanCommand {
stamps: false,
config_path: None,
target: None,
force: false,
}
}

Expand All @@ -71,6 +74,12 @@ impl CleanCommand {
self
}

/// Set whether to force removal by killing containers
pub fn with_force(mut self, force: bool) -> Self {
self.force = force;
self
}

/// Executes the clean command, removing volumes, state files, and optionally legacy directories.
///
/// # Returns
Expand Down Expand Up @@ -174,12 +183,25 @@ fi
);
}

volume_manager
.remove_volume(&volume_state.volume_name)
.await
.with_context(|| {
format!("Failed to remove volume: {}", volume_state.volume_name)
})?;
if self.force {
// Force removal: kill and remove all containers using the volume first
volume_manager
.force_remove_volume(&volume_state.volume_name)
.await
.with_context(|| {
format!(
"Failed to force remove volume: {}",
volume_state.volume_name
)
})?;
} else {
volume_manager
.remove_volume(&volume_state.volume_name)
.await
.with_context(|| {
format!("Failed to remove volume: {}", volume_state.volume_name)
})?;
}

print_success(
&format!("Removed docker volume: {}", volume_state.volume_name),
Expand Down
Loading