Move .purr folder from the home folder to the correct folder for the host OS#5
Move .purr folder from the home folder to the correct folder for the host OS#5carson-coder wants to merge 5 commits intomainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Moves the purr data directory from the legacy ~/.purr location to OS-appropriate per-user data locations (XDG on Linux, LocalAppData on Windows), and updates installer scripts/docs to use a PURR_BIN_DIR environment variable.
Changes:
- Update CLI data-root resolution to use XDG data dir on Linux and
%LOCALAPPDATA%on Windows, and adjust paths used forbin/andpackages/. - Add
PURR_BIN_DIRto the environment for installer/uninstaller scripts and update sample package installers accordingly. - Refresh documentation and website pages to reflect the new directory layout and PATH instructions.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
purr/Services/PackageManager.cs |
Implements new purr data-root resolution and updates internal references to bin/ + packages/; adds PURR_BIN_DIR. |
purr/README.md |
Updates CLI docs for directory layout, PATH setup, and installer env vars. |
purr-packages/dev/raylib/installer.sh |
Switches install destination to PURR_BIN_DIR. |
purr-packages/dev/raylib/installer.ps1 |
Switches install destination to PURR_BIN_DIR. |
purr-packages/dev/cmake/installer.sh |
Switches install destination to PURR_BIN_DIR. |
purr-packages/dev/cmake/installer.ps1 |
Switches install destination to PURR_BIN_DIR. |
documentation/installer-scripts.md |
Updates PATH guidance to XDG/LocalAppData locations. |
documentation/install-packages.md |
Updates install-path references to XDG/LocalAppData locations. |
documentation/directory-layout.md |
Updates documented directory layout to XDG/LocalAppData locations. |
PurrNet/wwwroot/install.sh |
Removes a now-unused .purr target-dir reference (left as a comment). |
PurrNet/Pages/Documentation/SubmitPackage.cshtml |
Updates examples to use PURR_BIN_DIR and new directory paths. |
PurrNet/Pages/Documentation/InstallerScripts.cshtml |
Updates PATH setup docs to XDG/LocalAppData locations. |
PurrNet/Pages/Documentation/InstallPackages.cshtml |
Updates install-path references to XDG/LocalAppData locations. |
PurrNet/Pages/Documentation/DirectoryLayout.cshtml |
Updates directory-layout docs (with one remaining Windows path reference). |
PurrLauncher/Services/PackageInstallService.cs |
Updates Windows package directory path to %LOCALAPPDATA%\\purr\\packages. |
Comments suppressed due to low confidence (7)
purr/README.md:90
purr_folderis described as$XDG_DATA_DIR/purrhere, but the XDG base directory variable isXDG_DATA_HOME(and the code usesXDG_DATA_HOME). Please update this line to avoid pointing users at a non-standard environment variable.
## Directory Layout
purr_folder is `$XDG_DATA_DIR/purr` (Linux), `~/.purr` (MacOS) or `%LOCALAPPDATA%\purr` (Windows)
purr/README.md:372
- Typo in the new env var table entry: "binarys" → "binaries".
| `PURR_BIN_DIR` | The directory to place package binarys |
purr/README.md:152
- The note says release-asset-installed binaries are not removed by
uninstall, butPackageManager.UninstallPackageAsyncnow deletes candidate binaries from<purr_folder>/bin. Please update this note to match actual behavior (or clarify the remaining limitations, if any).
> **Note:** Release-asset-installed binaries are not currently removed by `uninstall`. Delete them manually if needed.
purr/README.md:399
- The PATH examples use
XDG_DATA_DIR, but the standard variable isXDG_DATA_HOME(and other docs in this repo useXDG_DATA_HOME). Also the current-session example prepends the bin dir while the persist example appends it; please make these consistent and prefer the same variable name as the implementation.
**Bash / Zsh (one-time, current session):**
```bash
export PATH="${XDG_DATA_DIR:-~/.local/share}/purr/bin:$PATH"
Persist in Bash (~/.bashrc) or Zsh (~/.zshrc):
echo 'export PATH="$PATH:${XDG_DATA_DIR:-~/.local/share}/purr/bin"' >> ~/.bashrc
source ~/.bashrcPurrNet/Pages/Documentation/DirectoryLayout.cshtml:24
- This Windows path example still references
%USERPROFILE%\.purr\bin, but the CLI has moved to%LOCALAPPDATA%\purr\binon Windows. Please update this to match the new location.
<li>Release-asset-installed executables are placed in <code>$XDG_DATA_HOME/purr/bin</code> (or <code>%USERPROFILE%\.purr\bin</code> on Windows).</li>
documentation/installer-scripts.md:19
- The Fish PATH instruction hardcodes
$HOME/.local/share/purr/bin. If the user hasXDG_DATA_HOMEset to a non-default location, this will be wrong. Consider using the same${XDG_DATA_HOME:-~/.local/share}/purr/binpattern here too.
- Persist in `~/.bashrc` / `~/.zshrc` by echoing the export line and sourcing the file.
- Fish: use `set -U fish_user_paths $HOME/.local/share/purr/bin $fish_user_paths`.
- PowerShell: add `%LOCALAPPDATA%\purr\bin` to `PATH` for session or persist via `setx`.
purr/Services/PackageManager.cs:15
- The new field name
_purr_folder(and related locals likexdg_data_home,legacy_path) uses snake_case, but the rest of this class uses the C# convention_camelCase(e.g._apiService,_packagesDirectory). Renaming to_purrFolder/xdgDataHome/legacyPathwill keep naming consistent and avoid mixed styles in the same file.
private readonly string _purr_folder;
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
purr/Services/PackageManager.cs
Outdated
| string legacy_path = Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr")); | ||
| Directory.Move(legacy_path, _purr_folder); | ||
| File.CreateSymbolicLink(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), _purr_folder); | ||
| } | ||
|
|
||
| _packagesDirectory = Path.Combine(purr_folder, "packages"); |
There was a problem hiding this comment.
purr_folder is not defined here, so this line will not compile. It looks like this should use the _purr_folder field computed above (or the renamed _purrFolder).
| string legacy_path = Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr")); | |
| Directory.Move(legacy_path, _purr_folder); | |
| File.CreateSymbolicLink(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), _purr_folder); | |
| } | |
| _packagesDirectory = Path.Combine(purr_folder, "packages"); | |
| string legacy_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr"); | |
| Directory.Move(legacy_path, _purr_folder); | |
| File.CreateSymbolicLink(legacy_path, _purr_folder); | |
| } | |
| _packagesDirectory = Path.Combine(_purr_folder, "packages"); |
purr/Services/PackageManager.cs
Outdated
| if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr"))) | ||
| { | ||
| string legacy_path = Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr")); | ||
| Directory.Move(legacy_path, _purr_folder); | ||
| File.CreateSymbolicLink(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), _purr_folder); | ||
| } | ||
|
|
||
| _packagesDirectory = Path.Combine(purr_folder, "packages"); |
There was a problem hiding this comment.
This legacy-migration block is currently broken and unsafe:
Directory.Exists(...)returns abool, so assigning it tostring legacy_pathwill not compile.File.CreateSymbolicLink(Environment.GetFolderPath(UserProfile), _purr_folder)attempts to create a symlink at the home directory path, and also uses the file API for what should be a directory link.
Use alegacyPath = Path.Combine(UserProfile, ".purr"), guard against_purr_folder == legacyPath/ destination existing, and create a directory symlink atlegacyPathpointing to_purr_folder(handling platforms/permissions).
| if (Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr"))) | |
| { | |
| string legacy_path = Directory.Exists(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".purr")); | |
| Directory.Move(legacy_path, _purr_folder); | |
| File.CreateSymbolicLink(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), _purr_folder); | |
| } | |
| _packagesDirectory = Path.Combine(purr_folder, "packages"); | |
| var userProfile = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); | |
| var legacyPath = Path.Combine(userProfile, ".purr"); | |
| if (Directory.Exists(legacyPath)) | |
| { | |
| // Avoid migrating if the legacy path and target path are the same | |
| var legacyFullPath = Path.GetFullPath(legacyPath); | |
| var targetFullPath = Path.GetFullPath(_purr_folder); | |
| if (!string.Equals(legacyFullPath, targetFullPath, StringComparison.OrdinalIgnoreCase)) | |
| { | |
| // Only move if the new target does not already exist | |
| if (!Directory.Exists(_purr_folder)) | |
| { | |
| Directory.Move(legacyPath, _purr_folder); | |
| } | |
| // Attempt to create a directory symlink at legacyPath pointing to _purr_folder | |
| try | |
| { | |
| if (!Directory.Exists(legacyPath) && !File.Exists(legacyPath)) | |
| { | |
| Directory.CreateSymbolicLink(legacyPath, _purr_folder); | |
| } | |
| } | |
| catch (IOException) when (!_verbose) | |
| { | |
| // Ignore migration symlink failures silently when not verbose | |
| } | |
| catch (UnauthorizedAccessException) when (!_verbose) | |
| { | |
| // Ignore permission issues silently when not verbose | |
| } | |
| catch (PlatformNotSupportedException) when (!_verbose) | |
| { | |
| // Ignore platforms that do not support directory symlinks when not verbose | |
| } | |
| catch (Exception ex) when (_verbose) | |
| { | |
| ConsoleHelper.WriteWarning($"Failed to create legacy symlink at '{legacyPath}': {ex.Message}"); | |
| } | |
| } | |
| } | |
| _packagesDirectory = Path.Combine(_purr_folder, "packages"); |
|
I do still need to test this before we merge |

Moves the .purr folder to $XDG_DATA_HOME/purr on linux (if XDG_DATA_HOME is null then it defaults to ~/.local/share), %LOCALAPPDATA%/purr on windows, and on mac os nothing changes because I do not know the correct path for on macos.
I tried to update as much documentation. I searched the repo for
.purrand replace references to the .purr folder. I also addedPURR_BIN_DIRas a env var for install scripts which points to<purr_folder>/binfixes #4