Skip to content

Add fstab-backed custom mount point support for volumes#50

Open
DrapNard wants to merge 2 commits intohomielab:mainfrom
DrapNard:add-custom-mount-points
Open

Add fstab-backed custom mount point support for volumes#50
DrapNard wants to merge 2 commits intohomielab:mainfrom
DrapNard:add-custom-mount-points

Conversation

@DrapNard
Copy link
Copy Markdown

@DrapNard DrapNard commented Apr 4, 2026

Summary

  • add an inline per-volume custom mount point editor in the menu bar UI
  • persist custom mount point settings by stable volume identity, including bookmark-backed folder selection metadata
  • switch custom mount point application from diskutil mount -mountPoint remounts to /etc/fstab updates so normal mounts and plug-in auto-mount can use the custom path
  • keep manual mount/unmount behavior lightweight by returning DriveManager to plain diskutil mount and surfacing clear validation and system-rule errors
  • localize the new custom mount point labels, helper text, and validation messages
  • move menu bar presentation onto the app-owned status item/popover flow used by the updated inline editor

Testing

  • xcodebuild -project MountMate.xcodeproj -scheme MountMate -configuration Debug -derivedDataPath .codex-build/DerivedData -clonedSourcePackagesDirPath .codex-build/SourcePackages CODE_SIGNING_ALLOWED=NO CODE_SIGNING_REQUIRED=NO build

Copilot AI review requested due to automatic review settings April 4, 2026 18:05
Copy link
Copy Markdown

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

Adds per-volume custom mount point support that’s persisted by stable volume identity and applied via /etc/fstab, alongside a menu bar popover UI flow for managing mounts.

Changes:

  • Adds an inline “Custom Mount Point” editor to each volume row and persists mount point + optional bookmark metadata.
  • Applies custom mount points by writing managed entries into /etc/fstab (and removing them when cleared).
  • Reworks menu bar presentation to an app-owned NSStatusItem + NSPopover, and adds shell quoting helpers for safer command construction.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
MountMate/Views/Main/MainView.swift Adds global editor state + inline custom mount point editor UI and save flow.
MountMate/Views/Components/PopoverContent.swift Adjusts popover container sizing behavior (removes fixedSize).
MountMate/Utilities/Shell.swift Adds String helpers for shell-quoting and AppleScript string literal escaping.
MountMate/Utilities/AppDelegate.swift Implements status item + popover lifecycle, sizing, and outside-click closing logic.
MountMate/Resources/en.lproj/Localizable.strings Adds localized strings for the custom mount point feature.
MountMate/Resources/zh-Hans.lproj/Localizable.strings Adds localized strings for the custom mount point feature.
MountMate/Resources/zh-Hant.lproj/Localizable.strings Adds localized strings for the custom mount point feature.
MountMate/Resources/vi.lproj/Localizable.strings Adds localized strings for the custom mount point feature.
MountMate/Resources/uk.lproj/Localizable.strings Adds localized strings for the custom mount point feature.
MountMate/Models/ManagedVolumeInfo.swift Introduces VolumeCustomMountPoint model for persisted settings.
MountMate/Managers/PersistenceManager.swift Adds persistence + /etc/fstab read/modify/install logic for custom mount points.
MountMate/Managers/DriveManager.swift Adds remount + mount point validation/inspection helpers and improves shell quoting for mount/unmount.
MountMate/App/MountMateApp.swift Removes MenuBarExtra-based UI; relies on AppDelegate-owned status item/popover.
MountMate.xcodeproj/project.pbxproj Updates signing team ID in project settings.

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

Comment on lines +770 to +774
let selectedFolderURL =
editorState.selectedFolderURL?.path == path ? editorState.selectedFolderURL : nil
if let error = persistence.applyCustomMountPoint(path, selectedURL: selectedFolderURL, for: volume)
{
editorState.inlineError = error
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

applyCustomMountPoint(...) performs filesystem reads/writes and runs osascript for privilege escalation; calling it directly from the button action will block the SwiftUI main thread (and can appear frozen while the password prompt is pending). Consider moving this work onto a background task/queue and surfacing a saving state (disable buttons/spinner), then update editorState back on the main thread.

Copilot uses AI. Check for mistakes.
Comment on lines +406 to +409
let script = "do shell script \(command.appleScriptStringLiteral) with administrator privileges"
let result = runShell("/usr/bin/osascript -e \(script.shellQuoted)")
if let error = result.error, !error.isEmpty {
throw NSError(
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

This uses runShell(...) to execute an osascript ... with administrator privileges operation. runShell currently hard-times-out after 15 seconds, which is very likely to fail if the user takes longer than 15 seconds to respond to the admin password prompt (or if the prompt is slow to appear). Consider adding a configurable/longer timeout (or no timeout) for privileged operations and reporting cancellation separately from timeout.

Copilot uses AI. Check for mistakes.
Comment on lines +421 to +423
let trimmed = line.trimmingCharacters(in: .whitespaces)
guard !trimmed.isEmpty, !trimmed.hasPrefix("#") else { return false }
return trimmed.hasPrefix("UUID=\(volumeUUID) ")
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

Conflict detection only checks for the literal prefix "UUID=<uuid> " (single space). /etc/fstab fields are whitespace-separated and may use tabs or multiple spaces, so this can miss real conflicts and allow MountMate to write a duplicate entry. Consider parsing the line by whitespace (or using a regex for UUID=<uuid>\s) before deciding there is no conflict.

Suggested change
let trimmed = line.trimmingCharacters(in: .whitespaces)
guard !trimmed.isEmpty, !trimmed.hasPrefix("#") else { return false }
return trimmed.hasPrefix("UUID=\(volumeUUID) ")
let trimmed = line.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty, !trimmed.hasPrefix("#") else { return false }
let fields = trimmed.split(whereSeparator: \.isWhitespace)
guard let firstField = fields.first else { return false }
return firstField == "UUID=\(volumeUUID)"

Copilot uses AI. Check for mistakes.
Comment thread MountMate.xcodeproj/project.pbxproj Outdated
Comment on lines 453 to 456
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 21;
DEVELOPMENT_TEAM = 79LQ4MHVMG;
DEVELOPMENT_TEAM = 5TU767C42B;
ENABLE_HARDENED_RUNTIME = YES;
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

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

This PR changes the Xcode project DEVELOPMENT_TEAM setting. This is usually machine/account-specific and can break signing for other contributors/CI. Consider reverting these changes and managing signing via local xcconfig/user settings (or leaving DEVELOPMENT_TEAM unset in the shared project).

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.

2 participants