Skip to content

[#53] Add Flutter setup option and modernize Apple mobile tooling#54

Open
ducbm051291 wants to merge 1 commit into
mainfrom
feature/#53-add-flutter-setup-option-and-modernize-apple-mobile-tooling
Open

[#53] Add Flutter setup option and modernize Apple mobile tooling#54
ducbm051291 wants to merge 1 commit into
mainfrom
feature/#53-add-flutter-setup-option-and-modernize-apple-mobile-tooling

Conversation

@ducbm051291

@ducbm051291 ducbm051291 commented May 4, 2026

Copy link
Copy Markdown

What happened

Modernizes the mobile setup in mac / README.md so a fresh macOS machine is closer to being fully ready for Apple-platform and Flutter development after running Laptop. Resolves #53.

  • New Flutter option. Adds a Do you want to install Flutter's dependencies? [y|N] prompt that installs the Flutter SDK cask plus cocoapods (needed for Flutter iOS builds). Prints a post-install note pointing teammates at flutter doctor -v and flutter doctor --android-licenses.
  • Modernized Apple mobile tooling.
    • Renames the iOS cask from xcodes to the current canonical token xcodes-app (Homebrew renamed this cask; xcodes is now a former token).
    • Drops the stale cask "xcode" reference from the README — Xcode isn't installable via Homebrew and should come from the App Store or the Xcodes app.
    • Adds a post-install note (and matching README admonition) that walks the user through the modern Xcode bring-up: xcode-select, xcodebuild -license accept, xcodebuild -runFirstLaunch, and xcodebuild -downloadPlatform iOS to fetch platform support and Simulator runtimes.
  • README cleanup.
    • Tagline: "web development" → "software development" (the script covers Web, iOS, Android, Flutter).
    • Reorders platform sections to match the prompt order: Web → iOS → Android → Flutter.
    • Renames ### M1 incompatible dependecies### Apple Silicon incompatible dependencies (also fixes the typo and aligns with the existing "Both Apple Silicon and Intel are supported" note).
    • Removes the now-unused [xcode] link reference.

Out of scope but worth flagging as a follow-up: brew bundle check emits Warning: docker was renamed to docker-desktop for the pre-existing Web block. Same modernization pattern as xcodes → xcodes-app. Happy to do it here in a follow-up commit or a separate issue — whichever the team prefers.

Insight

How to test

Static checks (no side effects):

cd /path/to/laptop
bash -n mac                                    # syntax
brew install shellcheck && shellcheck mac      # lint; changed lines should be clean
grep -n 'cask "xcodes-app"' mac                # renamed cask present
grep -n 'append_flutter_dependencies' mac      # Flutter function present
grep -n 'print_flutter_setup_notes' mac        # Flutter notes wired
grep -n 'Apple Silicon incompatible' README.md # section renamed
! grep -Eq '\bM1\b|dependecies|\[XCode\]' README.md  # no leftovers

Dry-run the generated Brewfile (validates cask/formula tokens without installing):

TMP="$(mktemp -d)"; cd "$TMP"; touch .Brewfile
export HOME="$TMP"
# source only the function definitions from mac
head -n "$(grep -n '^# Run' /path/to/laptop/mac | head -1 | cut -d: -f1)" /path/to/laptop/mac > funcs.sh
fancy_echo() { :; }; append_to_zshrc() { :; }
source funcs.sh
pre_setup
append_general_dependencies
append_web_dependencies
append_ios_dependencies
append_android_dependencies
append_flutter_dependencies
cat "$HOME/.Brewfile"
HOMEBREW_BUNDLE_FILE="$HOME/.Brewfile" brew bundle check --verbose

Expect cask "xcodes-app", cask "flutter", and brew "cocoapods" to be present, and brew bundle check to report only "needs to be installed" — never "unknown cask/formula".

End-to-end on a clean machine — the real test. Options:

  1. Create a fresh user account on macOS (System Settings → Users & Groups → add a test user), log in as that user, and run bash mac 2>&1 | tee ~/laptop.log.
  2. Use a macOS VM (UTM / Parallels / Tart / VirtualBuddy) with a Sonoma+ base snapshot; snapshot → run → roll back.

Things to eyeball during the real run:

  • All four prompts appear in order: Web → iOS → Android → Flutter.
  • ~/.Brewfile contains cask "xcodes-app" and the # Flutter block.
  • brew bundle --global completes without "unknown cask" errors.
  • Post-install notes print at the end (iOS and/or Flutter, depending on which were selected).
  • which flutter / flutter --version work on a Flutter install.
  • On Apple Silicon, the Keybase block from append_general_intel_dependencies is skipped (matches the renamed "Apple Silicon incompatible dependencies" README section).

Alternatives considered

  • Keeping cask "xcodes" — Homebrew redirects the former token, so it "works" today, but the cask has been renamed and brew bundle already emits rename warnings for other casks in this file. Using the canonical xcodes-app keeps us future-proof and consistent with formulae.brew.sh/cask/xcodes-app (Former tokens: xcodes).
  • Automating sudo xcodebuild -runFirstLaunch inside the script — rejected because it requires sudo and an already-installed Xcode.app, neither of which Laptop can guarantee when the iOS option runs. Surfacing the commands in a post-install note is lower risk and matches Apple's documented bring-up flow.
  • Making the Flutter option skip CocoaPods when iOS is not selected — rejected. CocoaPods is required by Flutter's iOS plugin toolchain even for non-iOS-primary workflows, and brew bundle de-dupes if the iOS option is also selected, so there's no cost to including it unconditionally.
  • Installing Flutter via a version manager (fvm / asdf-flutter) instead of the Homebrew cask — deferred. The cask mirrors the current onboarding docs and keeps parity with how iOS/Android tools are installed in this script. Swapping to a version manager is a larger conversation worth its own issue.
  • Using the old ### M1 incompatible dependecies heading — replaced with ### Apple Silicon incompatible dependencies to match Apple's current naming, fix the typo, and align with the existing note near the top of the README (Both Apple Silicon and Intel are supported).

References

Proof Of Work

Verification table

# Check Result
1 bash -n mac (syntax) ✅ OK
2 shellcheck mac (v0.11.0) ✅ Zero warnings on changed lines. All 11 warnings are pre-existing (lines 73, 80, 190, 202, 223, 224, 229, 238, 247, 344, 395)
3 Brewfile generation (all 4 append functions) ✅ Generates expected blocks including # Flutter with cask "flutter" + brew "cocoapods"
4 brew bundle check --verbose ✅ No unknown-token errors
5 brew info --cask xcodes-app ✅ Xcodes 3.0.2b34
6 brew info --cask flutter ✅ Flutter SDK 3.41.7
7 brew info cocoapods ✅ 1.16.2 stable
8 print_ios_setup_notes render ✅ Prints xcode-select, xcodebuild -license accept, -runFirstLaunch, xcodebuild -downloadPlatform iOS
9 print_flutter_setup_notes render ✅ Prints flutter doctor -v and flutter doctor --android-licenses
10 Prompt flow with y/y/y/y ✅ All four append_*_dependencies fire
11 install() post-install wiring ✅ Both print_*_setup_notes gated on their *_dep answers
12 Sanity greps (no leftovers) ✅ No M1, no dependecies, no [XCode], no bare cask "xcodes"
Diff size 2 files changed, +84 / -7

New prompt flow

Do you want to install Web's dependencies? [y|N]
Do you want to install iOS's dependencies? [y|N]
Do you want to install Android's dependencies? [y|N]
Do you want to install Flutter's dependencies? [y|N]

Generated Brewfile — new/changed blocks

# iOS
brew "cocoapods"
cask "figma"
cask "proxyman"
cask "sourcetree"
cask "xcodes-app"

# Flutter
cask "flutter"
brew "cocoapods"

iOS post-install note

Apple mobile setup installed helper tools and Xcodes.
Install Xcode separately with the App Store or Xcodes, then run:

  sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  sudo xcodebuild -license accept
  sudo xcodebuild -runFirstLaunch

Download the platform support and Simulator runtimes you need in
Xcode > Settings > Components or with:

  xcodebuild -downloadPlatform iOS

Flutter post-install note

Flutter setup installed the Flutter SDK and CocoaPods.
Validate the toolchain with:

  flutter doctor -v

If you also installed the Android option, accept the Android SDK
licenses once with:

  flutter doctor --android-licenses

Homebrew token resolution

==> xcodes-app (Xcodes): 3.0.2b34 (auto_updates)
Install and switch between multiple versions of Xcode
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/x/xcodes-app.rb

==> flutter (Flutter SDK): 3.41.7 (auto_updates)
UI toolkit for building applications for mobile, web and desktop
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/f/flutter.rb

==> cocoapods: stable 1.16.2
Dependency manager for Cocoa projects

Logs:

==============================================
Laptop script verification log
Generated: 2026-05-04 02:41:31 UTC
Host: MBP14-M2-David.local
macOS: 26.4.1
Arch: arm64
Repo: /Users/david/Documents/laptop
Commit: 17b65d4
==============================================

NOTE: brew bundle check exits 1 when the Brewfile is not fully
satisfied on this machine. That is expected. For PoW, confirm:
  - No 'unknown cask' / 'unknown formula' errors
  - xcodes-app, flutter, cocoapods appear in the dependency list
==============================================

=== 1. bash -n mac (syntax) ===
[ok] syntax

=== 2. shellcheck mac ===

In mac line 73:
  echo -e "$text\n\n$(cat $zshrc)" > $zshrc
                          ^----^ SC2086 (info): Double quote to prevent globbing and word splitting.
                                     ^----^ SC2086 (info): Double quote to prevent globbing and word splitting.

Did you mean:
  echo -e "$text\n\n$(cat "$zshrc")" > "$zshrc"


In mac line 80:
    sudo chsh -s $(which zsh)
                 ^----------^ SC2046 (warning): Quote this to prevent word splitting.


In mac line 190:
  . "$(brew --prefix asdf)/libexec/asdf.sh"
    ^-- SC1091 (info): Not following: ./libexec/asdf.sh was not specified as input (see shellcheck -x).


In mac line 202:
  . "$(brew --prefix asdf)/libexec/asdf.sh"
    ^-- SC1091 (info): Not following: ./libexec/asdf.sh was not specified as input (see shellcheck -x).


In mac line 223:
  append_to_zshrc 'export NVM_DIR="$HOME/.nvm"'
                  ^---------------------------^ SC2016 (info): Expressions don't expand in single quotes, use double quotes for that.


In mac line 224:
  append_to_zshrc '[ -s "$(brew --prefix nvm)/nvm.sh" ] && \. "$(brew --prefix nvm)/nvm.sh"'
                  ^-- SC2016 (info): Expressions don't expand in single quotes, use double quotes for that.


In mac line 229:
  . "$(brew --prefix asdf)/libexec/asdf.sh"
    ^-- SC1091 (info): Not following: ./libexec/asdf.sh was not specified as input (see shellcheck -x).


In mac line 238:
  . "$(brew --prefix asdf)/libexec/asdf.sh"
    ^-- SC1091 (info): Not following: ./libexec/asdf.sh was not specified as input (see shellcheck -x).


In mac line 247:
  . "$(brew --prefix asdf)/libexec/asdf.sh"
    ^-- SC1091 (info): Not following: ./libexec/asdf.sh was not specified as input (see shellcheck -x).


In mac line 344:
  append_to_zshrc 'export PATH="/opt/homebrew/opt/libpq/bin:$PATH"'
                  ^-- SC2016 (info): Expressions don't expand in single quotes, use double quotes for that.


In mac line 395:
    . "$HOME/.laptop.local"
      ^-------------------^ SC1091 (info): Not following: ./.laptop.local was not specified as input (see shellcheck -x).

For more information:
  https://www.shellcheck.net/wiki/SC2046 -- Quote this to prevent word splitt...
  https://www.shellcheck.net/wiki/SC1091 -- Not following: ./.laptop.local wa...
  https://www.shellcheck.net/wiki/SC2016 -- Expressions don't expand in singl...
[shellcheck exit code: 1]

=== 3. Sanity greps ===
[ok] xcodes-app in mac
[ok] append_flutter_dependencies
[ok] print_flutter_setup_notes
[ok] README Apple Silicon section
[ok] license accept in mac+README
[ok] flutter doctor in mac+README
[ok] no M1/typo/XCode/old-xcodes leftovers

=== 4. Brewfile generation (temp HOME, mac truncated before # Run) ===

Appending general dependencies to Brewfile
    # General
    tap "thoughtbot/formulae"
    tap "universal-ctags/universal-ctags"
    tap "github/gh"

    # mas-cli to install macOS apps
    brew "mas"

    # General apps
    cask "slack" unless File.directory?("/Applications/Slack.app")
    cask "google-chrome" unless File.directory?("/Applications/Google Chrome.app")
    cask "1password" unless File.directory?("/Applications/1Password 7.app")
    cask "1password-cli"

    cask "postman" unless File.directory?("/Applications/Postman.app")
    cask "iterm2" unless File.directory?("/Applications/iTerm.app")

    # Unix
    brew "universal-ctags", args: ["HEAD"]
    brew "git"
    brew "openssl"
    brew "gpg"
    brew "zsh"

    # GitHub extensions
    brew "gh"
    cask "github" unless File.directory?("/Applications/GitHub Desktop.app")
    brew "git-lfs"

    # Editor
    cask "visual-studio-code" unless File.directory?("/Applications/Visual Studio Code.app")

    # Programming language prerequisites and package managers
    brew "libyaml" # should come after openssl
    brew "coreutils"

Appending web's dependencies to Brewfile
    # Web
    tap "heroku/brew"
    tap "phrase/brewed"

    # Devops
    cask "docker"
    brew "heroku"
    brew "awscli"

    # Image manipulation
    brew "imagemagick"

    # Others
    brew "yarn"
    brew "phrase"
    brew "libpq"
    cask "jetbrains-toolbox"

Appending iOS's dependencies to Brewfile
    # iOS
    brew "cocoapods"
    cask "figma"
    cask "proxyman"
    cask "sourcetree"
    cask "xcodes-app"

Appending Android's dependencies to Brewfile
    # Android
    cask "temurin"
    cask "android-studio"
    cask "android-commandlinetools"

Appending Flutter's dependencies to Brewfile
    # Flutter
    cask "flutter"
    brew "cocoapods"
    # iOS
    brew "cocoapods"
    cask "figma"
    cask "proxyman"
    cask "sourcetree"
    cask "xcodes-app"
---
    # Flutter
    cask "flutter"
    brew "cocoapods"

=== 5. brew bundle check (last 50 lines) ===
tuist/tuist/tuist@4.188.4
tuist/tuist/tuist@4.188.5
tuist/tuist/tuist@4.189.0
tuist/tuist/tuist@4.190.0
tuist/tuist/tuist@4.190.1
tuist/tuist/tuist@4.191.0
tuist/tuist/tuist@4.191.1
tuist/tuist/tuist@4.191.2
tuist/tuist/tuist@4.191.3
tuist/tuist/tuist@4.191.4
tuist/tuist/tuist@4.191.5
==> New Casks
tuist@0.25.3

You have 113 outdated formulae installed.

Warning: docker was renamed to docker-desktop
brew bundle can't satisfy your Brewfile's dependencies.
→ Tap universal-ctags/universal-ctags needs to be tapped.
→ Tap github/gh needs to be tapped.
→ Cask google-chrome needs to be installed or updated.
→ Cask 1password needs to be installed or updated.
→ Cask 1password-cli needs to be installed or updated.
→ Cask postman needs to be installed or updated.
→ Cask iterm2 needs to be installed or updated.
→ Cask github needs to be installed or updated.
→ Cask visual-studio-code needs to be installed or updated.
→ Cask jetbrains-toolbox needs to be installed or updated.
→ Cask figma needs to be installed or updated.
→ Cask proxyman needs to be installed or updated.
→ Cask sourcetree needs to be installed or updated.
→ Cask xcodes-app needs to be installed or updated.
→ Cask temurin needs to be installed or updated.
→ Cask android-studio needs to be installed or updated.
→ Cask android-commandlinetools needs to be installed or updated.
→ Formula mas needs to be installed or updated.
→ Formula universal-ctags needs to be installed or updated.
→ Formula git needs to be installed or updated.
→ Formula openssl needs to be installed or updated.
→ Formula gpg needs to be installed or updated.
→ Formula gh needs to be installed or updated.
→ Formula git-lfs needs to be installed or updated.
→ Formula coreutils needs to be installed or updated.
→ Formula awscli needs to be installed or updated.
→ Formula imagemagick needs to be installed or updated.
→ Formula phrase needs to be installed or updated.
→ Formula libpq needs to be installed or updated.
→ Formula cocoapods needs to be installed or updated.
→ Formula cocoapods needs to be installed or updated.
Satisfy missing dependencies with `brew bundle install`.
[brew bundle check exit: 1 — 1 = deps not fully installed; invalid tokens would error differently]

=== 6. brew info (xcodes-app, flutter, cocoapods) ===
==> xcodes-app (Xcodes): 3.0.2b34 (auto_updates)
Install and switch between multiple versions of Xcode
https://github.com/XcodesOrg/XcodesApp
Not installed
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/x/xcodes-app.rb
==> Requirements
Required: macOS >= 13
==> Artifacts
---
==> flutter (Flutter SDK): 3.41.9 (auto_updates)
UI toolkit for building applications for mobile, web and desktop
https://flutter.dev/
Installed (on request)
/opt/homebrew/Caskroom/flutter/3.38.3 (4.2GB)
  Installed using the formulae.brew.sh API on 2025-12-04 at 09:43:11
From: https://github.com/Homebrew/homebrew-cask/blob/HEAD/Casks/f/flutter.rb
==> Requirements
---
==> cocoapods: stable 1.16.2 (bottled)
Dependency manager for Cocoa projects
https://cocoapods.org/
Not installed
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/c/cocoapods.rb
License: MIT

=== 7. Rendered post-install notes ===

Apple mobile setup installed helper tools and Xcodes.
Install Xcode separately with the App Store or Xcodes, then run:

  sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  sudo xcodebuild -license accept
  sudo xcodebuild -runFirstLaunch

Download the platform support and Simulator runtimes you need in
Xcode > Settings > Components or with:

  xcodebuild -downloadPlatform iOS

Flutter setup installed the Flutter SDK and CocoaPods.
Validate the toolchain with:

  flutter doctor -v

If you also installed the Android option, accept the Android SDK
licenses once with:

  flutter doctor --android-licenses

=== 8. install() tail (post-install hooks) ===
  fi

  install_dependencies

  if [[ $web_dep =~ (y|yes|Y) ]];then
    install_asdf
    install_asdf_ruby
    install_node_manager
    install_asdf_erlang
    install_asdf_elixir
    install_asdf_golang
  fi

  install_laptop_local

  brew cleanup

  if [[ $ios_dep =~ (y|yes|Y) ]];then
    print_ios_setup_notes
  fi

  if [[ $flutter_dep =~ (y|yes|Y) ]];then
    print_flutter_setup_notes
  fi
}

==============================================
End of log
==============================================

- Add Flutter prompt installing the Flutter SDK and CocoaPods, plus a
  post-install note pointing users at `flutter doctor -v` and
  `flutter doctor --android-licenses`.
- Rename the iOS cask `xcodes` to its current canonical token
  `xcodes-app` and drop the stale `cask "xcode"` reference.
- Print iOS post-install guidance covering `xcode-select`,
  `xcodebuild -license accept`, `-runFirstLaunch`, and
  `xcodebuild -downloadPlatform iOS` for platform support and
  Simulator runtimes.
- Update README: tagline to "software development", reorder platform
  sections to match prompt order (Web, iOS, Android, Flutter), rename
  "M1 incompatible dependecies" to "Apple Silicon incompatible
  dependencies" (also fixes the typo), and remove the unused [xcode]
  link reference.

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Flutter setup option and modernize Apple mobile tooling

1 participant