Skip to content
This repository was archived by the owner on Sep 7, 2025. It is now read-only.
This repository was archived by the owner on Sep 7, 2025. It is now read-only.

Build from source fails for script-based formulas (e.g., asciiquarium) due to missing build system detection #10

@alexykn

Description

@alexykn

Description

When attempting to install certain formulas using --build-from-source, specifically those that consist primarily of scripts and don't use a standard build system (like Make, CMake, Autotools, etc.), the installation fails. This happens because sapphire's build logic attempts to detect a build system within the source directory and fails to find one, halting the installation.

A good example is asciiquarium, which is a Perl script. It requires specific installation steps (copying the main script, installing CPAN dependencies to libexec, setting up environment wrappers) rather than a conventional build process.

Steps to Reproduce

  1. Attempt to install asciiquarium using the build from source flag, preferably with verbose logging:
    sapphire install asciiquarium --build-from-source -vv

Expected Behavior

sapphire should recognize that asciiquarium doesn't have a standard build system and apply the appropriate installation logic for script-based formulas, similar to how Homebrew handles it:

  1. Install CPAN resources (like Curses, Term::Animation) into the formula's libexec directory.
  2. Copy the main asciiquarium script directly into the formula's bin directory.
  3. Make the main script executable.
  4. Create necessary environment wrappers (e.g., setting PERL5LIB) for any executables installed by the resources into libexec/bin, placing these wrappers in the formula's bin directory.
  5. The installation should complete successfully.

Actual Behavior

The installation fails during the build phase after extracting the source code. The build system detection logic does not find a known system (Makefile, CMakeLists.txt, etc.) and errors out.

Relevant Log Output

# ... (Dependency resolution, download, extraction) ...
 INFO sapphire_core::build::formula::source: ==> Building asciiquarium from source in /Users/alxknt/Library/Caches/brew-rs-client/build-temp/asciiquarium-yYHRq4
 INFO sapphire_core::build::formula::source: ==> Setting up build environment
# ... (Build environment setup) ...
 INFO sapphire_core::build::formula::source: Changing working directory to build dir: /Users/alxknt/Library/Caches/brew-rs-client/build-temp/asciiquarium-yYHRq4
 INFO sapphire_core::build::formula::source: ==> Detecting build system and building main formula: asciiquarium
 INFO sapphire_core::build::formula::source: Attempting to detect build system in current directory (CWD)
 INFO sapphire_core::build::formula::source: No subdirectories found to check.
ERROR sapphire_core::build::formula::source: Could not determine build system in CWD or its immediate subdirectory.
DEBUG sapphire_core::build::formula::source: Restored working directory to: /Users/alxknt/Github/sapphire
ERROR sapphire::cli::install: install of asciiquarium failed: Generic Error: Could not determine build system in source directory.
ERROR sapphire::cli::install: Installation failed for:
ERROR sapphire::cli::install:    ✖ asciiquarium: Generic Error: Could not determine build system in source directory.
Error: Installation Error: 1 bottle(s) failed to install.

(Full verbose logs can be provided if needed)

Environment

  • OS: macOS 15.3.2 (Apple Silicon / arm64 / aarch64)
  • Rust Toolchain: v1.88.0-nightly
  • Build Tools: Xcode Command Line Tools, Perl

Analysis / Suggested Solution

The core issue is that the current build logic in sapphire-core/src/build/formula/source/mod.rs (specifically within detect_and_build_in_cwd or similar) assumes a standard build system exists. For "no-build" script formulas like asciiquarium, this detection fails.

A potential solution, inspired by Homebrew's handling and the analysis provided [here/by user], involves adding a check before the standard build system detections (Autotools, CMake, etc.). This check could specifically look for script files matching the formula name in the extracted source directory.

If such a script is found (and perhaps other conditions are met, e.g., presence of Perl dependencies):

  1. Assume it's a script-based installation.
  2. Ensure CPAN/other resources are installed first (likely into libexec, potentially handled by the existing resource loop).
  3. Manually copy the main script (e.g., asciiquarium) to PREFIX/bin.
  4. Set appropriate executable permissions (chmod 0755).
  5. Check for any executables installed by resources into libexec/bin and create wrappers for them in PREFIX/bin that set up the necessary environment (e.g., PERL5LIB pointing to libexec/lib/perl5).

A concrete implementation suggestion involves adding logic similar to this within detect_and_build_in_cwd:

 // --- Add check for Script-only formulas (like Perl/Asciiquarium) ---
 let script_name = formula.name();
 let script_path = Path::new(".").join(&script_name); // Check in current (build) dir

 if script_path.is_file() {
     info!("Detected potential single-file script: {}", script_name);
     // TODO: Add more checks? (e.g., formula language == Perl?)

     // 1. Install script to bin
     let bin_dir = install_dir.join("bin");
     create_dir_all_with_context(&bin_dir, "bin directory")?;
     let dest_script = bin_dir.join(&script_name);
     fs::copy(&script_path, &dest_script).map_err(|e| /* ... error handling ... */ )?;
     // Set executable permissions (e.g., 0o755 on Unix)
     // ... platform-specific chmod ...

     // 2. Wrap executables from libexec/bin (if any)
     let libexec_bin = install_dir.join("libexec/bin");
     if libexec_bin.is_dir() {
         // ... logic to iterate files in libexec_bin ...
         // ... create wrapper script in bin_dir for each exe ...
         // ... wrapper sets env vars (e.g., PERL5LIB=install_dir/libexec/lib/perl5) ...
         // ... wrapper execs the original exe from libexec_bin ...
         // ... set executable permissions on the wrapper ...
     }

     // 3. Return Ok to bypass standard build system checks
     return Ok(());
 }

 // ... existing Autotools / CMake / Meson / etc. checks ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions