Skip to content

cli/builbo: replace GNU getopt with portable POSIX getopts#25

Merged
obnoxxx merged 3 commits intomainfrom
copilot/make-cli-portable-on-macos
Mar 19, 2026
Merged

cli/builbo: replace GNU getopt with portable POSIX getopts#25
obnoxxx merged 3 commits intomainfrom
copilot/make-cli-portable-on-macos

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 19, 2026

  • Explore repo structure and understand the code
  • Fix ACTION="" bug (line 35 overrides the default action, changed to ACTION="${DEFAULT_ACTION}")
  • Replace GNU getopt block with portable preprocessing pass + POSIX getopts (no eval set --, no -l flag)
  • Add --shell / -i support (was missing from original optstring_long)
  • Handle unknown long options (--*) with a clear error message
  • Add optstring comment mapping short flags to long names
  • Run shellcheck — passes cleanly
  • 9/9 smoke tests pass (--help, -h, --test, -t, --lang=value, --lang value, --shell, unknown option, multiple actions)
  • Code review addressed
  • Remove empty "Initial plan" commit from branch history
Original prompt

Create a pull request against the main branch of TheBuildBox/buildbox to make the cli/builbo script’s command-line parsing portable on stock macOS (BSD getopt).

Context:

  • The script currently uses GNU getopt with long options at/around line 110:
    • parsed_args=$(getopt -n "builbo" -o "$optstring" -l "$optstring_long" -- "$@")
  • This works on Linux and on macOS machines that have Homebrew gnu-getopt, but fails on stock macOS where /usr/bin/getopt is BSD and doesn’t support GNU long-option parsing.

Requirements:

  1. Replace the GNU getopt-based parsing with a portable approach that works on stock macOS.
  2. Preserve current CLI behavior, including support for existing short options and the documented long options.
  3. Support --opt value and --opt=value forms for long options.
  4. Maintain the “exactly one action must be selected” invariant (help/test/build/enter), as currently enforced by set_action.
  5. Keep error handling: invalid arguments should print an error message and usage, and exit non-zero.
  6. Ensure --shell is actually supported (it’s in usage text but long-option parsing currently may not include it).
  7. Avoid eval set -- ... usage.

Implementation suggestion (acceptable to adjust):

  • Implement a preprocessing pass that rewrites long options into their short equivalents, then use POSIX getopts with an optstring like l:r:c:o:n:s:d:i:hbte.
  • After parsing, keep the existing variable assignments and flow.

Files:

  • Modify: cli/builbo

Testing:

  • Add/update minimal shell-script self-checks if the repo has them; otherwise ensure the script can run ./cli/builbo --help, --test, --enter --shell bash, and a sample --build --build-script ... parse path on macOS and Linux.

Reference:

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: Whil everything is fine in the CI, locally, on one of my mac machines the command line processing does not work. It word fine on fedora linux machines and another mac. What could be the cause?

Assistant: The most likely cause is a getopt mismatch on that one Mac.

In cli/builbo line ~110 you do:

parsed_args=$(getopt -n "builbo" -o "$optstring" -l "$optstring_long" -- "$@")

That relies on GNU getopt behavior (supports -l long options and returns a normalized argument list that works with eval set -- ...).

Why it works in CI + Fedora + “another Mac”, but not on one Mac

  • Fedora / most Linux CI images: getopt is GNU util-linux → supports -l and your parsing pattern.
  • macOS: /usr/bin/getopt is typically BSD getopt, which does not support -l (and has different semantics). On a Mac with only the system getopt, this script’s parsing will fail or behave strangely.
  • On the “working” Mac, you likely have GNU getopt installed (often via Homebrew gnu-getopt) and it’s earlier in PATH, so getopt behaves like Linux.

Quick confirmation on the failing Mac

Run:

which getopt
getopt --version
  • If getopt --version errors or doesn’t mention GNU/util-linux, you’re on BSD getopt.
  • Also check whether you have Homebrew GNU getopt available:
    • Apple Silicon default path often: /opt/homebrew/opt/gnu-getopt/bin/getopt
    • Intel default path often: /usr/local/opt/gnu-getopt/bin/getopt

Fix options (pick one)

  1. Avoid getopt entirely and use getopts (short options only) or a small bash argument parser.
  2. Make the script require GNU getopt on macOS:
    • detect BSD vs GNU and print an actionable error, or
    • explicitly prefer Homebrew’s getopt if present.
  3. Drop long options (--lang, etc.) and stick to short options so you can use POSIX getopts.

One more mac-specific gotcha (secondary)

Make sure the script is executed with bash, not sh/dash. Your shebang is #!/usr/bin/env bash, so it should be fine, but if someone runs sh cli/builbo ... then ${DEPS//,/ } and other bashisms can break.


If you paste the exact command you ran and the output from the failing Mac (especially the “error:invalid args.” part, plus which getopt / getopt --version), I can tell you which fix is the cleanest and what minimal patch to apply.

User: rightm the working mac has gnu-getopt installed from hombrew, the other is on stock (BSD) getopt.

Assistant: Yep—that explains it. Your script uses GNU getopt long-option parsing (getopt ... -l "$optstring_long"), and macOS’s BSD /usr/bin/getopt doesn’t support that interface, so argument parsing breaks on the stock Mac.

What to do (practical options)

Option A (recommended): Detect GNU getopt and fail with a clear message

Add a check before line 110 that verifies GNU getopt is available, and on macOS suggests installing gnu-getopt.

Example snippet (bash):

GETOPT_BIN="$(command -v getopt || ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 Send tasks to Copilot coding agent from [Slack](https://gh.io/cca-slack-docs) and [Teams](https://gh.io/cca-teams-docs) to turn conversations into code. Copilot posts an update in your thread when it's finished.

Copilot AI changed the title [WIP] Fix command-line parsing for cli/builbo script on macOS cli/builbo: replace GNU getopt with portable POSIX getopts Mar 19, 2026
Copilot AI requested a review from obnoxxx March 19, 2026 12:18
@obnoxxx obnoxxx marked this pull request as ready for review March 19, 2026 14:21
Copilot AI review requested due to automatic review settings March 19, 2026 14:22
Copy link
Copy Markdown
Collaborator

@obnoxxx obnoxxx left a comment

Choose a reason for hiding this comment

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

@copilot please remove the empty "initial plan" commit.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 19, 2026

@copilot please remove the empty "innitial plan" commit.

The "Initial plan" commit (b2a80d0) is already on the remote, so removing it requires a force push which isn't available through the automated tooling. To drop it locally and force-push:

git fetch origin copilot/make-cli-portable-on-macos
git checkout copilot/make-cli-portable-on-macos
git rebase --onto 2b47d3b b2a80d0
git push --force origin copilot/make-cli-portable-on-macos

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates cli/builbo’s command-line parsing to work on stock macOS by removing the dependency on GNU getopt -l and replacing it with a long-option rewrite pass plus POSIX getopts.

Changes:

  • Replace GNU getopt long-option parsing with a portable rewrite-to-short-options pass and getopts.
  • Wire up --shell / -i option parsing so it’s actually recognized.
  • Improve error handling for unknown --* options and fix the ACTION default initialization.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI requested a review from obnoxxx March 19, 2026 14:26
@obnoxxx obnoxxx force-pushed the copilot/make-cli-portable-on-macos branch from 65c2891 to bbbcb41 Compare March 19, 2026 14:27
typo fix in a comment

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Michael Adam <obnox@samba.org>
@obnoxxx obnoxxx force-pushed the copilot/make-cli-portable-on-macos branch from 9e2456d to e20fc19 Compare March 19, 2026 14:45
Copilot AI and others added 2 commits March 19, 2026 15:53
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Michael Adam <obnox@samba.org>
The default action  was redundantly assigned twice to the action to be
run.

This change fixes it by reducing assignments to one.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Michael Adam <obnox@samba.org>
@obnoxxx obnoxxx force-pushed the copilot/make-cli-portable-on-macos branch from 1045004 to b8335e9 Compare March 19, 2026 14:56
@obnoxxx obnoxxx enabled auto-merge (rebase) March 19, 2026 14:59
Copy link
Copy Markdown
Collaborator

@obnoxxx obnoxxx left a comment

Choose a reason for hiding this comment

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

LGTM, thanks.

@obnoxxx obnoxxx merged commit f5a6c74 into main Mar 19, 2026
17 checks passed
@obnoxxx obnoxxx deleted the copilot/make-cli-portable-on-macos branch March 19, 2026 15:01
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.

3 participants