Skip to content

Fix: Issue 71, unbound variable errors in MacOS#77

Open
amegli wants to merge 8 commits into
RchGrav:mainfrom
amegli:71-macos-unbound-variable-error
Open

Fix: Issue 71, unbound variable errors in MacOS#77
amegli wants to merge 8 commits into
RchGrav:mainfrom
amegli:71-macos-unbound-variable-error

Conversation

@amegli
Copy link
Copy Markdown

@amegli amegli commented Sep 21, 2025

Installation on MacOS produces a number of "unbound variable" errors from "cli.sh" - #71. These changes apply default expansions for a few arrays in that file. An existing failing test was also corrected by adjusting the expected profile name count.

Update

This PR has grown as fixes uncovered additional issues. There are now a number of updated bash files, almost all centered around "unbound variable" errors, and a new "test_install.sh" file to try and ensure the build/install process works in multiple bash versions (it did recreate some of the "unbound variable" errors). So far build, install, and basic usage in MacOS seems to work.

Summary by Sourcery

Prevent unbound variable errors on MacOS by adding default expansions for arrays in cli.sh and update the profile name count in the compatibility test.

Bug Fixes:

  • Add default expansions to array references in cli.sh to avoid unbound variable errors
  • Correct the expected profile count in the get_all_profile_names test

Tests:

  • Adjust get_all_profile_names test to expect 21 profiles instead of 20

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented Sep 21, 2025

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

This PR fixes unbound variable errors on MacOS by adding default array expansions in cli.sh and corrects an existing test by updating the expected profile count.

Class diagram for updated shell script functions in cli.sh

classDiagram
    class parse_cli_args {
        +parse_cli_args()
        - Uses default array expansion for all_args, host_flags, control_flags, pass_through
        - Exports CLI_HOST_FLAGS, CLI_CONTROL_FLAGS, CLI_SCRIPT_COMMAND, CLI_PASS_THROUGH
    }
    class process_host_flags {
        +process_host_flags()
        - Uses default array expansion for CLI_HOST_FLAGS
    }
    class debug_parsed_args {
        +debug_parsed_args()
    }
    parse_cli_args --> process_host_flags : Calls
    parse_cli_args --> debug_parsed_args : Calls
Loading

File-Level Changes

Change Details Files
Apply default expansions to arrays to prevent unbound variable errors
  • Use "${all_args[@]:-}" in the parsing loop
  • Use default expansions when exporting host_flags, control_flags, and pass_through
  • Use "${CLI_HOST_FLAGS[@]:-}" in the host flags processing loop
lib/cli.sh
Adjust expected profile name count in compatibility test
  • Update test assertion from expecting 20 profiles to 21
tests/test_bash32_compat.sh

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Extract the repeated '[@]:-' fallback pattern into a small helper or variable to reduce duplication and make maintenance easier.
  • Instead of hardcoding the expected profile count in the test, derive it dynamically from the PROFILE_FUNCS output to avoid breaking this test whenever profiles are added or removed.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Extract the repeated '[@]:-' fallback pattern into a small helper or variable to reduce duplication and make maintenance easier.
- Instead of hardcoding the expected profile count in the test, derive it dynamically from the PROFILE_FUNCS output to avoid breaking this test whenever profiles are added or removed.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@jeff-r-skillrev
Copy link
Copy Markdown

jeff-r-skillrev commented Sep 22, 2025

I just wanted to note that I pulled down amegli:71-macos-unbound-variable-error and built it this morning on an M1 Mac, and it appears to have fixed the issue for me. I was getting: .../.claudebox/source/lib/cli.sh: line 22: all_args[@]: unbound variable

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 22, 2025

No operation ID found for this PR

@jeff-r-skillrev
Copy link
Copy Markdown

I think you missed one in main.sh though, on line 140:

If command doesn't need Docker, skip all Docker setup

if [[ "$cmd_requirements" == "none" ]]; then
    # Dispatch the command directly and exit
    dispatch_command "${CLI_SCRIPT_COMMAND}" "${CLI_PASS_THROUGH[@]}" "${CLI_CONTROL_FLAGS[@]}"
    exit $?
fi

When testing locally I got this:

View build details: docker-desktop://dashboard/build/desktop-linux/desktop-linux/dhpk61lik2wz9qpdewywggsgq

What's next:
    View a summary of image vulnerabilities and recommendations → docker scout quickview 

█▀▀ █   ▄▀█ █ █ █▀▄ █▀▀ █▄▄ █▀█ ▀▄▀
█▄▄ █▄▄ █▀█ █▄█ █▄▀ ██▄ █▄█ █▄█ █ █

Welcome to ClaudeBox!

ClaudeBox is ready to use. Here's how to get started:

1. Navigate to your project directory:
   cd /path/to/your/project

2. Create your first container slot:
   claudebox create

3. Launch Claude:
   claudebox

Other useful commands:
  claudebox help       - Show all available commands
  claudebox profiles   - List available development profiles
  claudebox projects   - List all ClaudeBox projects

(base) jeff@Jeffs-MacBook-Air claudebox % claudebox profiles
/Users/jeff/.local/bin/claudebox: line 140: CLI_PASS_THROUGH[@]: unbound variable

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 22, 2025

No operation ID found for this PR

@jeff-r-skillrev
Copy link
Copy Markdown

You might consider array expansion syntax:

# Examples:
${CLI_PASS_THROUGH[@]:+${CLI_PASS_THROUGH[@]}}
${CLI_CONTROL_FLAGS[@]:+${CLI_CONTROL_FLAGS[@]}}

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 22, 2025

No operation ID found for this PR

@amegli
Copy link
Copy Markdown
Author

amegli commented Sep 22, 2025

@jeff-r-skillrev - there appear to be a number of spots that fail post-build, in addition to the main.sh line you pointed out. I'll attempt to work through them.

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 22, 2025

No operation ID found for this PR

@amegli
Copy link
Copy Markdown
Author

amegli commented Sep 23, 2025

@jeff-r-skillrev - I've made a number of updates and added some build/install tests. On my system this fixes a number of issues but leaves me with an "awk" error when running "claudebox". This is likely another bash incompatibility issue. Let me know if you see the same.

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 23, 2025

No operation ID found for this PR

@jeff-r-skillrev
Copy link
Copy Markdown

jeff-r-skillrev commented Sep 23, 2025

@amegli I rebuilt everything (rm -R ~/.claudebox/ and /bin/bash .builder/build.sh and ./claudebox.run) and ran various commands without issue. For me, running claudebox with no arguments does not produce an awk related error.


(base) jeff@Jeffs-MacBook-Air claudebox % claudebox

█▀▀ █   ▄▀█ █ █ █▀▄ █▀▀ █▄▄ █▀█ ▀▄▀
█▄▄ █▄▄ █▀█ █▄█ █▄▀ ██▄ █▄█ █▄█ █ █

No available slots found

To continue, you'll need an available container slot.

  claudebox create  - Create a new slot
  claudebox slots   - View existing slots

  Hint: Create multiple slots to run parallel authenticated
  Claude sessions in the same project.

(base) jeff@Jeffs-MacBook-Air claudebox %

I'll keep using it today and tomorrow, to see if I find other bugs. But from my perspective, this bug fix is working.

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 23, 2025

No operation ID found for this PR

@jeff-r-skillrev
Copy link
Copy Markdown

I think I might have reproduced your awk issues. Like you said, running just claudebox does it.

(base) jeff@Jeffs-MacBook-Air timbersite-frontend % claudebox

█▀▀ █   ▄▀█ █ █ █▀▄ █▀▀ █▄▄ █▀█ ▀▄▀
█▄▄ █▄▄ █▀█ █▄█ █▄▀ ██▄ █▄█ █▄█ █ █

No available slots found

To continue, you'll need an available container slot.

  claudebox create  - Create a new slot
  claudebox slots   - View existing slots

  Hint: Create multiple slots to run parallel authenticated
  Claude sessions in the same project.

(base) jeff@Jeffs-MacBook-Air ts-frontend % claudebox create

█▀▀ █   ▄▀█ █ █ █▀▄ █▀▀ █▄▄ █▀█ ▀▄▀
█▄▄ █▄▄ █▀█ █▄█ █▄▀ ██▄ █▄█ █▄█ █ █

Commands:

  claudebox create     Create new slot
  claudebox slot <n>   Launch specific slot
  claudebox revoke     Remove highest slot
  claudebox revoke all Remove all unused slots

Slots for /Users/jeff/src/skillrev/ts/ts-frontend:

  Slot     Authentication       Status     Folder
  ────   ─────────────────     ─────────  ────────
   1    🔒 Unauthenticated  🔴  Inactive  80f24b63

Parent directory: /Users/jeff/.claudebox/projects/users_jeff_src_skillrev_ts_ts_frontend_5ce2703a

(base) jeff@Jeffs-MacBook-Air ts-frontend % claudebox       
awk: newline in string LABEL claudebox.prof... at source line 1
awk: newline in string LABEL claudebox.prof... at source line 1
Failed to apply Dockerfile substitutions
(base) jeff@Jeffs-MacBook-Air ts-frontend %

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 23, 2025

No operation ID found for this PR

@jeff-r-skillrev
Copy link
Copy Markdown

I will say, I launched claudebox, gave it the awk error, and it found a decent workaround. Here is the patch it produced, which is now letting me use claudebox on my Macbook M1.

diff --git a/main.sh b/main.sh
index 5194a87..fde4130 100755
--- a/main.sh
+++ b/main.sh
@@ -580,24 +580,25 @@ build_docker_image() {
     # Build labels
     local project_folder_name
     project_folder_name=$(generate_parent_folder_name "$PROJECT_DIR")
-    local labels="\
-LABEL claudebox.profiles=\"$profile_hash\"
-LABEL claudebox.profiles.crc=\"$profiles_file_hash\"
-LABEL claudebox.project=\"$project_folder_name\""
     
-    # Replace placeholders in the project template
+    # Process the template using simpler sed replacements instead of awk
+    # Safer approach that avoids multi-line string issues in awk
     local final_dockerfile="$base_dockerfile"
     
-    # Replace WHOLE lines that contain the placeholders (with optional spaces)
-    local final_dockerfile
-    final_dockerfile=$(awk -v pi="$profile_installations" -v lbs="$labels" '
-    # If the whole line is {{ PROFILE_INSTALLATIONS }}, print injected block and skip
-    /^[[:space:]]*\{\{[[:space:]]*PROFILE_INSTALLATIONS[[:space:]]*\}\}[[:space:]]*$/ { print pi; next }
-    # If the whole line is {{ LABELS }}, print labels block and skip
-    /^[[:space:]]*\{\{[[:space:]]*LABELS[[:space:]]*\}\}[[:space:]]*$/ { print lbs; next }
-    # Otherwise, print the line unchanged
-    { print }
-    ' <<<"$base_dockerfile") || error "Failed to apply Dockerfile substitutions"
+    # First replace the profile installations
+    final_dockerfile=$(sed -e "/^[[:space:]]*{{[[:space:]]*PROFILE_INSTALLATIONS[[:space:]]*}}[[:space:]]*$/c\\
+$profile_installations" <<<"$final_dockerfile")
+    
+    # Then replace the labels section - each on a separate line
+    final_dockerfile=$(sed -e "/^[[:space:]]*{{[[:space:]]*LABELS[[:space:]]*}}[[:space:]]*$/c\\
+LABEL claudebox.profiles=\"$profile_hash\"\\
+LABEL claudebox.profiles.crc=\"$profiles_file_hash\"\\
+LABEL claudebox.project=\"$project_folder_name\"" <<<"$final_dockerfile")
+    
+    # Check if substitution was successful
+    if [[ $? -ne 0 ]]; then
+        error "Failed to apply Dockerfile substitutions"
+    fi
 
     # Guard: ensure no unreplaced placeholders remain
     if grep -q '{{PROFILE_INSTALLATIONS}}' <<<"$final_dockerfile" grep -q '{{LABELS}}' <<<"$final_dockerfile"; then

@agentfarmx
Copy link
Copy Markdown

agentfarmx Bot commented Sep 23, 2025

No operation ID found for this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants