Skip to content

chore(project): convert main Meshtastic/ tree to Xcode 16 buildable folders#2102

Open
bruschill wants to merge 7 commits into
meshtastic:mainfrom
bruschill:chore/convert-main-tree-buildable
Open

chore(project): convert main Meshtastic/ tree to Xcode 16 buildable folders#2102
bruschill wants to merge 7 commits into
meshtastic:mainfrom
bruschill:chore/convert-main-tree-buildable

Conversation

@bruschill

@bruschill bruschill commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

What changed?

Converts the main Meshtastic/ app source tree to Xcode 16 buildable folders (PBXFileSystemSynchronizedRootGroup), so files under these folders are compiled by their on-disk location instead of by hand-maintained project.pbxproj entries.

17 source folders converted: Accessory, API, AppIntents, CarPlay, Enums, Export, Extensions, Helpers, Intents, Measurement, Model, Persistence, Provisioning, Router, Services, Tips, Views. Net effect on the project file: +187 / -2,226 lines, roughly 2,000 fewer hand-maintained references.

  • Flipped the 17 folders above to synchronized (buildable) folders. Every .swift physically inside them now compiles automatically.
  • Ground truth via the compiler, not regex: the app was built (BUILD SUCCEEDED) and the compiler's own Meshtastic.SwiftFileList diffed against disk to find true orphans. Of ~418 on-disk .swift files, exactly 9 were orphans (on disk, not compiled). Each was adjudicated by adding it to the target and rebuilding:
  • Resources/ is deliberately left classic (it has an image build-script/exception pipeline, not source). Nested Resources/images and PreferenceKeys synchronized groups are preserved.
  • A handful of loose top-level files (MeshtasticApp.swift, AppState.swift, MeshtasticAppDelegate.swift) remain explicit refs by design.

Builds directly on the groundwork from #2085 by @laconicman, which converted MeshtasticTests/, the Meshtastic Watch App/, and later Widgets/ + a shared Shared/ folder to buildable folders and established the pattern this PR follows for the main app tree.

Behavior note (flagged intentionally): because folders are now synchronized, the 7 previously-orphaned files are compiled again. Most are additive init/update(...) helpers. Model/Model+Sendable.swift (#1846) adds Sendable conformance to 43 @Model entities — it compiles clean and no entity already declared Sendable, so it's purely additive, but it does change the concurrency-checking surface. Called out for reviewer awareness.

Why the two deleted files were genuine orphans (evidence)

Both deleted files were present on disk but never referenced in project.pbxproj, so they were never compiled into any target. Under buildable folders they would have been dragged into the build, so they had to be resolved.

Views/Helpers/Messages/MessageTemplate.swift (struct MessageTemplate) — 0 references anywhere in the codebase, 0 references in upstream's project.pbxproj. Pure dead code.

Views/Nodes/Helpers/NodeInfo.swift — despite its filename, declares struct NodeInfoItem: View, the same type as the sibling NodeInfoItem.swift. Under a synchronized Views/ folder this is an invalid redeclaration causing a build failure. NodeInfo.swift: 0 refs in upstream's pbxproj (orphan). NodeInfoItem.swift: 4 refs (the live, compiled file), kept. The only call site, NodeInfoItem(node:) in NodeDetail.swift, is satisfied by the kept file's init(node:).

Why did it change?

Hand-maintained project.pbxproj file references are the single biggest source of merge conflicts and "file added but forgot to wire it into the target" mistakes in this repo. Buildable folders compile files by their on-disk location, eliminating that whole class of conflict/omission and removing ~2,000 hand-maintained references. The conversion also surfaced and resolved 9 pre-existing orphan files (7 restored to the build, 2 dead files removed).

How is this tested?

  • plutil -lint clean; no duplicate object IDs.
  • xcodebuild BUILD SUCCEEDED for the Meshtastic scheme (iOS Simulator), which builds + embeds WidgetsExtension and the Watch App.
  • Merged with latest upstream/main; all newly-added upstream source files are auto-included via the synced folders (0 new explicit refs needed).
  • Orphan adjudication was compiler-driven (Meshtastic.SwiftFileList diffed against disk), not regex.

Screenshots/Videos (when applicable)

N/A — project-structure/build-configuration change only; no runtime or UI change.

Checklist

  • My code adheres to the project's coding and style guidelines.
  • I have conducted a self-review of my code.
  • I have commented my code, particularly in complex areas.
  • I have verified whether these changes require updates to the in-app documentation under docs/user/ or docs/developer/. No doc update is needed (project-structure/build change, no user-visible behavior) — skip-docs-check label applies.
  • I have tested the change to ensure that it works as intended.

Summary by CodeRabbit

  • Bug Fixes

    • Improved project organization and build configuration for more reliable app compilation.
    • Resolved issues caused by untracked source files and ensured required app components are included in builds.
    • Added coverage for PMTiles extraction functionality.
  • UI Updates

    • Removed legacy message reply preview and node information display components.
  • Documentation

    • Updated build and validation documentation to reflect the completed project structure conversion.

…le-folder plan

Pre-flip gate for converting Meshtastic/ to an Xcode 16 buildable folder
(issue meshtastic#2026, follow-up to meshtastic#2085). Both files are on disk but compiled into
no target; both are non-viable if the folder is synced:

- MessageTemplate.swift: does not compile (type '()' cannot conform to 'View'),
  dead since an old iOS 16 commit, referenced by nothing.
- NodeInfo.swift: re-declares struct NodeInfoItem (already defined by the
  compiled NodeInfoItem.swift); stale superseded copy.

App target still builds after removal (verified). Adds the verified conversion
plan under docs/plans/.
…ldable folders

Follow-up to meshtastic#2085 (issue meshtastic#2026). Converts 17 source folders under Meshtastic/
to PBXFileSystemSynchronizedRootGroups so adding/moving/deleting source files no
longer edits project.pbxproj:

  Accessory, API, AppIntents, CarPlay, Enums, Export, Extensions, Helpers,
  Intents, Measurement, Model, Persistence, Provisioning, Router, Services,
  Tips, Views

Net project.pbxproj: +179 / -2143.

Details:
- The 7 previously-orphaned but valid files (6 SwiftData entity extensions +
  Model+Sendable.swift) are now compiled automatically via the synced folders.
  Verified: 416/416 .swift under Meshtastic/ compile; 0 orphans remain.
- Constants.swift (Extensions/, shared with WidgetsExtension) stays compiled in
  the app via sync and is re-added to WidgetsExtension via an explicit reference.
- The nested PreferenceKeys synced folder is removed (now covered by Views/).
- Removed ~19 stale duplicate file references (the "Recovered References" cruft)
  that would otherwise double-compile once their folders were synced.
- Resources/ intentionally left as a classic group: it holds the images synced
  sub-folder with a build-script-driven SVG exception set / runtime image
  pipeline that must not be disturbed. It is not source.

Validated: Meshtastic, WidgetsExtension, and Watch App targets all BUILD
SUCCEEDED; MeshtasticTests XCTest suite passes (0 failures). A pre-existing
Swift Testing SwiftData ModelContext.reset crash (in the untouched
MeshtasticTests/ folder) is unrelated to these pbxproj-only changes.
…ree-buildable

# Conflicts:
#	Meshtastic.xcodeproj/project.pbxproj
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Xcode project converts the main app tree to synchronized buildable folders, updates target/resource/source wiring, adds the PMTiles test source, removes two SwiftUI helper views, and records the completed conversion and validation plan.

Changes

Buildable folder conversion

Layer / File(s) Summary
Synchronized folder structure
Meshtastic.xcodeproj/project.pbxproj
Adds synchronized root groups and exception sets, and rewires the project and app group hierarchies.
Target references and build phases
Meshtastic.xcodeproj/project.pbxproj
Updates file/resource references, frameworks, app sources, and test sources including PMTilesExtractorTests.swift.
Conversion and validation record
docs/plans/buildable-folders-main-tree.md
Marks the conversion executed and documents orphan handling, cross-target compilation, resource exceptions, validation, and rollback checks.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: garthvh, rcgv1, thebentern

Poem

I’m a rabbit in folders, hopping with care,
Xcode now finds every source hiding there.
Resources sparkle, tests join the queue,
Old views vanish from the morning dew.
Buildable burrows, neatly aligned—
A carrot for every file we find!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarizes the main change: converting the main Meshtastic tree to Xcode 16 buildable folders.
Description check ✅ Passed The description follows the required template with all major sections filled in, including testing, screenshots, and checklist items.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
Meshtastic.xcodeproj/project.pbxproj (1)

31-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the explicit PMTilesExtractorTests.swift wiring.

MeshtasticTests is already a synchronized folder assigned to this target, so its contents are discovered automatically. Remove these four manual entries to avoid redundant target membership and restore the PR’s zero-maintenance model. (developer.apple.com)

Also applies to: 140-140, 511-511, 920-920

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Meshtastic.xcodeproj/project.pbxproj` at line 31, Remove the explicit
PMTilesExtractorTests.swift wiring from the Xcode project: delete its
PBXBuildFile entry, file reference, and both associated target/group membership
entries. Keep MeshtasticTests configured as the synchronized folder so the test
file remains discovered automatically without manual references.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/plans/buildable-folders-main-tree.md`:
- Around line 76-77: Insert a blank line between the “### DELETE — 2 files
(compiler-/collision-confirmed non-viable)” heading and the table header that
begins with “| File | Origin | Verdict |”.

In `@Meshtastic.xcodeproj/project.pbxproj`:
- Around line 207-208: Add uk to every knownRegions list in the Xcode project
configuration, reusing the existing Ukrainian localization references shown by
the PBXFileReference entries. Preserve all existing regions and ordering
conventions while ensuring each project target’s supported-region list includes
uk.

---

Nitpick comments:
In `@Meshtastic.xcodeproj/project.pbxproj`:
- Line 31: Remove the explicit PMTilesExtractorTests.swift wiring from the Xcode
project: delete its PBXBuildFile entry, file reference, and both associated
target/group membership entries. Keep MeshtasticTests configured as the
synchronized folder so the test file remains discovered automatically without
manual references.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 43b48808-68b2-47ca-859d-7a787929953e

📥 Commits

Reviewing files that changed from the base of the PR and between e2b6cec and d601c0e.

📒 Files selected for processing (4)
  • Meshtastic.xcodeproj/project.pbxproj
  • Meshtastic/Views/Helpers/Messages/MessageTemplate.swift
  • Meshtastic/Views/Nodes/Helpers/NodeInfo.swift
  • docs/plans/buildable-folders-main-tree.md
💤 Files with no reviewable changes (2)
  • Meshtastic/Views/Helpers/Messages/MessageTemplate.swift
  • Meshtastic/Views/Nodes/Helpers/NodeInfo.swift

Comment on lines +76 to +77
### DELETE — 2 files (compiler-/collision-confirmed non-viable)
| File | Origin | Verdict |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add a blank line before the table.

Proposed fix
 ### DELETE — 2 files (compiler-/collision-confirmed non-viable)
+
 | File | Origin | Verdict |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
### DELETE — 2 files (compiler-/collision-confirmed non-viable)
| File | Origin | Verdict |
### DELETE — 2 files (compiler-/collision-confirmed non-viable)
| File | Origin | Verdict |
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)

[warning] 77-77: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/buildable-folders-main-tree.md` around lines 76 - 77, Insert a
blank line between the “### DELETE — 2 files (compiler-/collision-confirmed
non-viable)” heading and the table header that begins with “| File | Origin |
Verdict |”.

Source: Linters/SAST tools

Comment on lines +207 to +208
AA000401SIRI000000000027 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = uk; path = uk.lproj/AppIntentVocabulary.plist; sourceTree = "<group>"; };
AA000402IPLS000000000011 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

python3 - <<'PY'
from pathlib import Path

p = Path("Meshtastic.xcodeproj/project.pbxproj")
text = p.read_text(errors="replace").splitlines()

# Print line-numbered excerpts around knownRegions and uk file references
targets = ["knownRegions", "uk.lproj/AppIntentVocabulary.plist", "uk.lproj/InfoPlist.strings"]
for i, line in enumerate(text, 1):
    if any(t in line for t in targets):
        start = max(1, i - 8)
        end = min(len(text), i + 12)
        print(f"\n--- excerpt around line {i} ---")
        for j in range(start, end + 1):
            print(f"{j:5d}: {text[j-1]}")
PY

Repository: meshtastic/Meshtastic-Apple

Length of output: 7832


🏁 Script executed:

python3 - <<'PY'
from pathlib import Path

p = Path("Meshtastic.xcodeproj/project.pbxproj")
lines = p.read_text(errors="replace").splitlines()

# Show every knownRegions block with enough context to include the full list.
for i, line in enumerate(lines, 1):
    if "knownRegions = (" in line:
        print(f"\n=== knownRegions at line {i} ===")
        start = i
        # print until matching ");"
        depth = 0
        for j in range(i, len(lines) + 1):
            s = lines[j - 1]
            print(f"{j:5d}: {s}")
            if "(" in s:
                depth += s.count("(")
            if ")" in s:
                depth -= s.count(")")
                if depth <= 0 and s.strip() == ");":
                    break
PY

Repository: meshtastic/Meshtastic-Apple

Length of output: 540


Add uk to each knownRegions list. Ukrainian localizations are present, but uk is missing from the project’s supported regions, so Xcode won’t treat them consistently.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Meshtastic.xcodeproj/project.pbxproj` around lines 207 - 208, Add uk to every
knownRegions list in the Xcode project configuration, reusing the existing
Ukrainian localization references shown by the PBXFileReference entries.
Preserve all existing regions and ordering conventions while ensuring each
project target’s supported-region list includes uk.

- Add uk to knownRegions (matches the uk.lproj localization files)
- Remove redundant explicit PMTilesExtractorTests.swift wiring; it is
  auto-included via the synchronized MeshtasticTests folder (verified with
  build-for-testing)
@bruschill bruschill added the skip-docs-check Use this label to skip the automatic docs audit label Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

skip-docs-check Use this label to skip the automatic docs audit

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant