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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: CI

on:
push:
branches: [ "main", "master" ]
branches: [ "main", "master", "dev" ]
pull_request:
branches: [ "main", "master" ]
branches: [ "main", "master", "dev" ]

env:
CARGO_TERM_COLOR: always
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed
- **Critical: Infinite Build Loop**: The outer retry `loop` around `build_package()` never broke on a successful build — only the inner install-retry loop had a `break`. This caused ax to repeatedly rebuild (and reinstall) the same package indefinitely. Added a `break` to exit the build retry loop after a successful build and install.
- **Resolver**: Refactored AUR dependency resolver to use `pkgbase` consistently for indexing and lookups, fixing redundant builds for split packages and aliased names.
- **Builder**: Optimized AUR build process by making the `makepkg` force-build flag (`-f`) conditional on the `clean-build` configuration.

### CI
- **Workflows**: CI now also triggers on pushes and pull requests targeting the `dev` branch

## [1.0.19] - 2026-03-02

### Fixed
Expand Down
8 changes: 7 additions & 1 deletion src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,13 @@ pub fn build_package(
// 6. Run makepkg
debug!("Starting makepkg for {}", pkg);
let mut makepkg = Command::new("makepkg");
makepkg.arg("-srf"); // Sync deps, Remove deps, Force build

// Base flags: Sync deps, Remove deps
let mut flags = "-sr".to_string();
if config.clean_build {
flags.push('f'); // Force build if cleaning
}
Comment on lines +145 to +149

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-f is added only when config.clean_build is true, but Step 4 already does git clean -fdx, so -f is least useful in the clean-build case. The non-clean-build path is where existing package archives are most likely to remain and require either -f or explicit deletion/reuse logic to avoid makepkg refusing to overwrite. Consider inverting the condition or making force/reuse behavior explicit.

Suggested change
// Base flags: Sync deps, Remove deps
let mut flags = "-sr".to_string();
if config.clean_build {
flags.push('f'); // Force build if cleaning
}
// Base flags: Sync deps, Remove deps, Force overwrite existing artifacts
let mut flags = "-srf".to_string();

Copilot uses AI. Check for mistakes.
makepkg.arg(flags);
if skip_pgp {
makepkg.arg("--skippgpcheck");
}
Expand Down
14 changes: 5 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ async fn install_packages(
loop {
match builder::build_package(&pkgbase, config, config.diff_viewer) {
Ok(package_paths) => {
// Install the built packages using exact paths from makepkg --packagelist
// Install the built packages using exact paths from makepkg --packagelist
if !package_paths.is_empty() {
println!(
Expand Down Expand Up @@ -274,40 +273,37 @@ async fn install_packages(
}
}
} else {
break; // Success, break install loop
break;
}
}
// Move to next package in build order
} else {
println!("!! No packages were built for {}", pkgbase);
break;
}
break;
}
Err(e) => {
// Build failed, prompt user
eprintln!(
"{} Build failed for {}: {:#}",
"!!".red().bold(),
pkgbase,
e
);

// In --noconfirm mode, abort immediately
if config.no_confirm {
anyhow::bail!("Build of {} failed (--noconfirm)", pkgbase);
}

match interactive::prompt_on_error(
&format!("Build of {} failed", pkgbase),
true, // Allow retry for build failures
true,
)? {
interactive::ErrorAction::Retry => {
println!("{}", ":: Retrying build...".yellow());
continue; // Retry loop
continue;
}
interactive::ErrorAction::Skip => {
println!("{}", ":: Skipping package...".yellow());
break; // Skip to next package
break;
}
interactive::ErrorAction::Abort => {
anyhow::bail!("Aborting due to build failure");
Expand Down
4 changes: 3 additions & 1 deletion src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ async fn collect_all_packages(

// Parse .SRCINFO for dependencies
if let Ok(metadata) = crate::parser::parse_srcinfo(&cache_path) {
aur_packages.insert(pkg.clone(), metadata.clone());
// Store by pkgbase to ensure consistent lookup in Phase 3
aur_packages.insert(metadata.pkgbase.clone(), metadata.clone());
Comment on lines 60 to +62

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that aur_packages is keyed by pkgbase, Phase 1 should also resolve pkg to a pkgbase before cloning/pulling and choosing cache_path. As written, the clone URL and cache directory still use the dependency string (pkg), which will fail for split-package pkgnames and can also cause repeated clones/pulls for multiple pkgnames that share one pkgbase. Consider maintaining a pkgname -> pkgbase map during collection and using the resolved base for both the git URL and cache dir.

Copilot uses AI. Check for mistakes.
Comment on lines +61 to +62

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After keying aur_packages by pkgbase, the cycle fallback logic later in this function becomes inconsistent: it iterates aur_packages.keys() (now pkgbase) and then does pkgbase_map.get(pkg) where pkgbase_map is keyed by pkgname. This can yield an empty fallback build list for split packages where no pkgname equals pkgbase. The fallback should use the pkgbase keys directly (or build the fallback from aur_packages.values().map(|m| m.pkgbase.clone())).

Suggested change
// Store by pkgbase to ensure consistent lookup in Phase 3
aur_packages.insert(metadata.pkgbase.clone(), metadata.clone());
// Store by pkgname to remain consistent with downstream resolution logic
aur_packages.insert(pkg.clone(), metadata.clone());

Copilot uses AI. Check for mistakes.

Copilot AI Mar 21, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s trailing whitespace on the blank line after inserting into aur_packages (and it looks like an extra blank line was introduced). This will cause cargo fmt --check to fail if rustfmt hasn’t been run. Please run rustfmt or remove the trailing spaces.

Suggested change

Copilot uses AI. Check for mistakes.
for dep in metadata.depends.iter().chain(metadata.make_depends.iter()) {
let clean_dep = crate::parser::clean_dependency(dep);
if !processed.contains(&clean_dep) {
Expand Down
Loading