Skip to content

Conversation

@fletchgqc
Copy link
Contributor

@fletchgqc fletchgqc commented Aug 27, 2025

Summary

This PR fixes issue #45 where users encountered an awk: newline in string error when adding the Java profile to ClaudeBox.

Problem

The awk command used for Dockerfile placeholder substitution was failing when processing multi-line content in the profile_installations variable. The error manifested as:

awk: newline in string 
RUN apt-get update ... at source line 1
Failed to apply Dockerfile substitutions

Solution

  • Replaced awk-based substitution with a pure bash line-by-line processing approach
  • Fixed a syntax error where the || operator was missing between two grep conditions in the guard clause
  • The new implementation reliably handles multi-line content without the awk limitations

Testing

The fix has been tested with the Java profile and successfully builds without errors.

Fixes #45

🤖 Generated with Claude Code

Summary by Sourcery

Replace awk-based Dockerfile placeholder substitution with a bash line-by-line loop to reliably handle multi-line PROFILE_INSTALLATIONS and avoid newline-in-string errors

Bug Fixes:

  • Resolve newline-in-string error when injecting multi-line PROFILE_INSTALLATIONS into Dockerfile by switching from awk to bash processing
  • Fix missing '||' operator in the placeholder guard clause to properly detect unreplaced placeholders

Enhancements:

  • Improve Dockerfile template substitution logic for better reliability

The awk command used for placeholder substitution in Dockerfiles was
failing with 'newline in string' errors when processing multi-line
profile installations. This particularly affected the Java profile.

Changes:
- Replace awk-based substitution with pure bash line-by-line processing
- Fix syntax error: add missing || operator in placeholder guard clause
- Ensure reliable handling of multi-line content in profile installations

This approach is more portable and avoids awk's limitations with
multi-line string variables passed via -v.

Fixes RchGrav#45

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
@sourcery-ai
Copy link

sourcery-ai bot commented Aug 27, 2025

Reviewer's Guide

Replaces the awk-based Dockerfile placeholder substitution with a robust bash line-by-line loop to properly inject multi-line content, and corrects the guard clause by adding the missing logical OR between placeholder checks.

Sequence diagram for Dockerfile placeholder substitution process

sequenceDiagram
    participant main_sh as main.sh
    participant Dockerfile as Dockerfile
    participant Bash as Bash
    main_sh->Dockerfile: Read base_dockerfile
    main_sh->Bash: Process each line
    Bash->main_sh: For each line
    alt PROFILE_INSTALLATIONS placeholder
        Bash->main_sh: Inject profile_installations content
    else LABELS placeholder
        Bash->main_sh: Inject labels content
    else Other lines
        Bash->main_sh: Keep line unchanged
    end
    main_sh->Dockerfile: Write final_dockerfile
    main_sh->main_sh: Check for unreplaced placeholders
    main_sh->main_sh: Error if any remain
Loading

Class diagram for updated Dockerfile substitution logic in main.sh

classDiagram
    class MainSh {
        - base_dockerfile: string
        - profile_installations: string
        - labels: string
        - final_dockerfile: string
        + processDockerfile()
    }
    MainSh : processDockerfile() replaces awk with bash loop
    MainSh : processDockerfile() checks for unreplaced placeholders
    MainSh : processDockerfile() writes final_dockerfile
Loading

File-Level Changes

Change Details Files
Replaced awk-based placeholder substitution with bash line-by-line processing
  • Removed awk invocation and related variable redefinitions
  • Set IFS to newline and introduced a while-read loop over base_dockerfile
  • Used regex to detect PROFILE_INSTALLATIONS and LABELS placeholders
  • Appended profile_installations or labels blocks followed by newlines
  • Trimmed trailing newline from the assembled final_dockerfile
main.sh
Fixed guard clause syntax for unreplaced placeholders
  • Added missing '

Assessment against linked issues

Issue Objective Addressed Explanation
#45 Replace the {{PROFILE_INSTALLATIONS}} placeholder in the Dockerfile with the correct profile installation commands during build.
#45 Ensure that unreplaced placeholders (such as {{PROFILE_INSTALLATIONS}} and {{LABELS}}) do not remain in the generated Dockerfile.
#45 Fix the build failure caused by incorrect placeholder substitution when adding core profiles.

Possibly linked issues

  • Build is failing with core profile #45: The PR replaces the awk-based Dockerfile placeholder substitution with a bash loop, directly fixing the failure to replace {{PROFILE_INSTALLATIONS}} that caused the build to fail.

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

@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:

  • Consider using readarray (mapfile) to load base_dockerfile into an array and iterate, which can simplify the loop and eliminate manual newline handling.
  • Instead of accumulating final_dockerfile in memory, stream the substituted lines directly to the output file (e.g. via a here-doc or process substitution) for better memory efficiency on larger templates.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider using readarray (mapfile) to load base_dockerfile into an array and iterate, which can simplify the loop and eliminate manual newline handling.
- Instead of accumulating final_dockerfile in memory, stream the substituted lines directly to the output file (e.g. via a here-doc or process substitution) for better memory efficiency on larger templates.

## Individual Comments

### Comment 1
<location> `main.sh:619` </location>
<code_context>
     # Guard: ensure no unreplaced placeholders remain
-    if grep -q '{{PROFILE_INSTALLATIONS}}' <<<"$final_dockerfile" grep -q '{{LABELS}}' <<<"$final_dockerfile"; then
-    error "Unreplaced placeholders remain in generated Dockerfile"
+    if grep -q '{{PROFILE_INSTALLATIONS}}' <<<"$final_dockerfile" || grep -q '{{LABELS}}' <<<"$final_dockerfile"; then
+        error "Unreplaced placeholders remain in generated Dockerfile"
     fi
</code_context>

<issue_to_address>
Corrected logic for placeholder check, but could be simplified.

Consider using a single grep command with an extended regex to check for both placeholders at once: grep -qE '{{PROFILE_INSTALLATIONS}}|{{LABELS}}'.
</issue_to_address>

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.

main.sh Outdated
# Guard: ensure no unreplaced placeholders remain
if grep -q '{{PROFILE_INSTALLATIONS}}' <<<"$final_dockerfile" grep -q '{{LABELS}}' <<<"$final_dockerfile"; then
error "Unreplaced placeholders remain in generated Dockerfile"
if grep -q '{{PROFILE_INSTALLATIONS}}' <<<"$final_dockerfile" || grep -q '{{LABELS}}' <<<"$final_dockerfile"; then
Copy link

Choose a reason for hiding this comment

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

suggestion: Corrected logic for placeholder check, but could be simplified.

Consider using a single grep command with an extended regex to check for both placeholders at once: grep -qE '{{PROFILE_INSTALLATIONS}}|{{LABELS}}'.

Use a single grep command with extended regex to check for both
placeholders instead of two separate grep commands with ||.

This is more efficient and cleaner while maintaining the same functionality.
@fletchgqc
Copy link
Contributor Author

fletchgqc commented Aug 27, 2025

Claude response to review:

I've implemented the grep simplification as suggested - it's indeed cleaner to use a single
grep with extended regex.

Regarding the other suggestions:

  1. readarray/mapfile for loading base_dockerfile: Cannot implement this as ClaudeBox requires Bash 3.2 compatibility (per CLAUDE.md) to support macOS's default bash. The readarray/mapfile commands were introduced in Bash 4.0 and would break compatibility on macOS. The current line-by-line approach is the most portable solution for Bash 3.2+.
  2. Streaming output instead of accumulating in memory: While this could theoretically improve memory efficiency,
    Dockerfiles are typically very small files (< 1KB). The current approach is clearer and more maintainable, and the
    memory usage is negligible. The added complexity of streaming isn't justified for such small files.

The implemented solution successfully fixes the original issue (#45) while maintaining full compatibility with both
macOS (Bash 3.2) and Linux systems, which is a core requirement of the ClaudeBox project.

@agentfarmx
Copy link

agentfarmx bot commented Aug 27, 2025

No operation ID found for this PR

thieso2 added a commit to thieso2/claudebox that referenced this pull request Oct 24, 2025
Applies critical fixes from RchGrav/claudebox to enable ClaudeBox to run properly on macOS Tahoe (Sequoia 15.x):

- Fix unbound variable errors on macOS (PR RchGrav#78)
  - Add :- operator to all array expansions for Bash 3.2 compatibility
  - Prevents "unbound variable" errors with set -u flag

- Fix MCP cleanup trap scoping issue (PR RchGrav#73)
  - Consolidate MCP temp files into trap-accessible array
  - Eliminates exit errors when MCP servers are configured

- Fix Python profile error handling (PR RchGrav#74)
  - Add proper error handling without masking failures
  - Implement broken symlink detection and auto-recovery
  - Ensure Bash 3.2 compatibility in docker-entrypoint

- Fix awk newline error in Dockerfile substitution (PR RchGrav#55)
  - Replace awk-based substitution with pure bash processing
  - Handles multi-line LABEL and PROFILE_INSTALLATIONS content
  - Fixes "awk: newline in string" error

Modified files:
- build/docker-entrypoint: Python profile error handling
- lib/*.sh: Array expansion fixes across all library modules
- main.sh: Dockerfile template substitution fix
- tooling/profiles/rust.sh: Array expansion fix

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
conroywhitney added a commit to conroywhitney/claudebox that referenced this pull request Jan 10, 2026
## Summary

Cherry-picked fix for the awk newline error that occurs when building
Docker images with certain profiles (e.g., Java).

**Original author:** [@fletchgqc](https://github.com/fletchgqc)

## Cherry-picked commits

- `dc29541` - Fix issue RchGrav#45: Resolve awk newline error when adding Java
profile
- `8ad65c3` - Simplify placeholder check with extended regex

## Attribution

This fix was developed by @fletchgqc in their fork. We cherry-picked it
into our sibling fork since the upstream PR is still pending review.

**References:**
- Upstream PR:
[RchGrav#55](RchGrav#55)
- Original branch:
[fletchgqc/fix/issue-45-java-profile-awk-error](https://github.com/fletchgqc/claudebox/tree/fix/issue-45-java-profile-awk-error)
- Original issue:
[RchGrav#45](RchGrav#45)

## Changes

Replaces awk-based Dockerfile placeholder substitution with pure bash
line-by-line processing, fixing multi-line content handling while
maintaining Bash 3.2 compatibility for macOS.

---------

Co-authored-by: John Fletcher <john.fletcher@codecentric.de>
Co-authored-by: Claude <noreply@anthropic.com>
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.

Build is failing with core profile

1 participant