platformio / platformio/platformio-core

macOS: default `projects_dir` is placed inside `~/Documents`, which iCloud syncs

Open
#5,502 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

feature
Dominant language
Python
Stars
9.5k
Forks
905
Avg merge
2d 13h
Merged PRs (30d)
2

Description

Verified against: PlatformIO Core 6.1.19, PlatformIO IDE for VSCode 3.3.4, macOS 26.5.2

Summary

On macOS, get_default_projects_dir() unconditionally resolves to
~/Documents/PlatformIO/Projects. When a user has iCloud Drive's
"Desktop & Documents Folders" enabled — an option macOS actively prompts for during setup —
that directory is managed by fileproviderd. PlatformIO then writes .pio/ build trees,
hundreds of MB of churn per rebuild, into a live sync target. This produces build and
toolchain failures that are hard to attribute, because the sync daemon acts after the
operation reports success.

platformio/project/helpers.py:

def get_default_projects_dir():
    docs_dir = os.path.join(fs.expanduser("~"), "Documents")
    try:
        assert IS_WINDOWS
        ...
    except:
        if not IS_MACOS:
            try:
                docs_dir = subprocess.check_output(["xdg-user-dir", "DOCUMENTS"]) ...

macOS is the one platform with no path to a different answer: the Windows branch is behind
assert IS_WINDOWS, and the xdg-user-dir branch is explicitly excluded by if not IS_MACOS.

Impact observed

An ESP32 project living at the default location hit three independent failure classes, all
traced to FileProvider and all resolved by moving the repo out of ~/Documents:

  1. Code signing broken by xattr churn — FileProvider re-stamps extended attributes faster
    than they can be cleared, so signing an artifact built in-tree fails intermittently.
  2. Duplicate symbols at link time — iCloud conflict copies (provision 2.cpp beside
    provision.cpp) are picked up by build_src_filter globs and compiled as real sources.
  3. managed_components eviction races — the component manager failed with
    "CHANGELOG.md missing" and rmtree: Directory not empty three times in one night while
    iCloud evicted and re-materialised that directory mid-build.

Plus the silent cost: every hybrid rebuild pushes hundreds of MB of .pio churn through the
user's iCloud quota and uplink.

Why the existing mitigations do not cover this

  • platformio-core#4497 (OneDrive, closed in 6.1.7) hardened .pio/build removal. That is
    the symptom; the default location is the cause, and it is still cloud-synced.
  • The setting is changeable — pio settings set projects_dir <path> — but there is no UI
    for it anywhere. PIO Home reads coreSettings and cannot write them: AppRPC.load_state
    rebuilds them per call and sets state.modified = False, the frontend deletes
    storage.coreSettings before app.save_state, and no settings-write RPC handler exists.
    The VSCode extension contributes no corresponding configuration key either. So a user who
    hits this must discover a CLI command that the GUI never mentions — which is consistent
    with the number of forum threads asking exactly this question.

Suggested fix

Any one of these would close it; they are listed cheapest-first.

  1. Detect and avoid. On macOS, check whether ~/Documents is under FileProvider
    management before using it as the default, and fall back to ~/PlatformIO/Projects.
    A cheap signal is the presence of ~/Library/Mobile Documents/com~apple~CloudDocs plus
    ~/Documents resolving into the FileProvider tree.
  2. Change the macOS default outright to ~/PlatformIO/Projects (or
    ~/Library/Application Support/PlatformIO/Projects). Existing installs are unaffected —
    they carry an explicit value in appstate.json.
  3. At minimum, warn once. If a build's project path is inside a synced directory, emit a
    one-line warning naming the risk and the pio settings set projects_dir command. This
    alone would have saved the debugging described above.

Additionally, surfacing projects_dir in PIO Home's UI would make (3) actionable at the
moment the user reads it.

Workaround for anyone who finds this issue

pio settings set projects_dir ~/YourProjects        # persists in ~/.platformio/appstate.json
export PLATFORMIO_SETTING_PROJECTS_DIR=~/YourProjects  # wins over the above; survives a settings reset

Note the env var is PLATFORMIO_SETTING_<NAME>, not PLATFORMIO_<NAME>. The path must
already exist — projects_dir_validate asserts os.path.isdir on every read.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in platformio/project/helpers.py at get_default_projects_dir() and trace how projects_dir is read and validated, using the described macOS path behavior as the reproduction case. Review the mentioned PIO Home AppRPC.load_state and settings persistence paths if considering the UI or warning alternatives; done means the default no longer causes the reported iCloud-synced location problem and existing explicit settings continue to work.

Written by the indexing model from the issue text.

Assessment

Tech stack
macos, python
Domain
operating-systems, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.