mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
♻️ Rework how the user's PATH is loaded
This commit is contained in:
@ -98,6 +98,8 @@
|
||||
C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; };
|
||||
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; };
|
||||
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; };
|
||||
C42E3BF428A9BF5100AFECFC /* Shell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */; };
|
||||
C42E3BF528A9BF5100AFECFC /* Shell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */; };
|
||||
C42F26732805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
|
||||
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
|
||||
C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; };
|
||||
@ -356,6 +358,7 @@
|
||||
C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; };
|
||||
C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; };
|
||||
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; };
|
||||
C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Shell+PATH.swift"; sourceTree = "<group>"; };
|
||||
C42F26722805B4B400938AC7 /* DomainListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListable.swift; sourceTree = "<group>"; };
|
||||
C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; };
|
||||
C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; };
|
||||
@ -608,6 +611,7 @@
|
||||
C4B5853D2770FE3900DA4FBE /* Command.swift */,
|
||||
C4B5853B2770FE3900DA4FBE /* Paths.swift */,
|
||||
C4B5853C2770FE3900DA4FBE /* Shell.swift */,
|
||||
C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */,
|
||||
C4C1019A27C65C6F001FACC2 /* Process.swift */,
|
||||
C40C7F2F27722E8D00DDDCDC /* Logger.swift */,
|
||||
C417DC73277614690015E6EE /* Helpers.swift */,
|
||||
@ -1386,6 +1390,7 @@
|
||||
C4C3ED412783497000AB15D8 /* MainMenu+Startup.swift in Sources */,
|
||||
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
|
||||
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */,
|
||||
C42E3BF428A9BF5100AFECFC /* Shell+PATH.swift in Sources */,
|
||||
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */,
|
||||
C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
|
||||
C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */,
|
||||
@ -1430,6 +1435,7 @@
|
||||
C449B4F027EE7FB800C47E8A /* DomainListTLSCell.swift in Sources */,
|
||||
C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */,
|
||||
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */,
|
||||
C42E3BF528A9BF5100AFECFC /* Shell+PATH.swift in Sources */,
|
||||
C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */,
|
||||
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */,
|
||||
C4F319C927B034A500AFF46F /* Stats.swift in Sources */,
|
||||
|
@ -19,12 +19,9 @@ public class Paths {
|
||||
|
||||
private var userName: String
|
||||
|
||||
private var PATH: String
|
||||
|
||||
init() {
|
||||
baseDir = App.architecture != "x86_64" ? .opt : .usr
|
||||
userName = String(Shell.pipe("whoami").split(separator: "\n")[0])
|
||||
PATH = String(Shell.pipe("echo $PATH")).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
public func detectBinaryPaths() {
|
||||
@ -60,10 +57,6 @@ public class Paths {
|
||||
return shared.userName
|
||||
}
|
||||
|
||||
public static var PATH: String {
|
||||
return shared.PATH
|
||||
}
|
||||
|
||||
public static var cellarPath: String {
|
||||
return "\(shared.baseDir.rawValue)/Cellar"
|
||||
}
|
||||
|
27
phpmon/Common/Core/Shell+PATH.swift
Normal file
27
phpmon/Common/Core/Shell+PATH.swift
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// Shell+PATH.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 15/08/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Shell {
|
||||
|
||||
var PATH: String {
|
||||
let task = Process()
|
||||
task.launchPath = "/bin/zsh"
|
||||
|
||||
// We need an interactive shell so the user's PATH is loaded in correctly
|
||||
task.arguments = ["--login", "-ilc", "echo $PATH"]
|
||||
|
||||
let pipe = Pipe()
|
||||
task.standardOutput = pipe
|
||||
task.launch()
|
||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
|
||||
return String(data: data, encoding: String.Encoding.utf8) ?? ""
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ class PhpHelper {
|
||||
let destination = "/Users/\(Paths.whoami)/.config/phpmon/bin/pm\(dotless)"
|
||||
|
||||
// Check if the ~/.config/phpmon/bin directory is in the PATH
|
||||
let inPath = Paths.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin")
|
||||
let inPath = Shell.user.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin")
|
||||
|
||||
// Check if we can create symlinks (`/usr/local/bin` must be writable)
|
||||
let canWriteSymlinks = FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
|
||||
|
@ -13,9 +13,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<br>
|
||||
<p><b>Want to spread the love?</b> Leave a <a href="https://github.com/nicoverbruggen/phpmon">star on GitHub</a>!</p>
|
||||
<p><b>Having issues?</b> Consult the <a href="https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting">FAQ & Troubleshooting</a> section.</p>
|
||||
<p><b>Want to support me?</b> You can <a href="https://nicoverbruggen.be/sponsor">financially support</a> the continued development of this app.</p>
|
||||
<p><b>Do you enjoy using the app?</b> Leave a <a href="https://github.com/nicoverbruggen/phpmon">star on GitHub</a>!</p>
|
||||
<p><b>Having issues?</b> Consult the <a href="https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting">FAQ</a> section, I did my best to ensure everything is documented.</p>
|
||||
<p><b>Want to support further development of PHP Monitor?</b> You can <a href="https://nicoverbruggen.be/sponsor">financially support</a> the continued development of this app.</p>
|
||||
<p><b>Get the latest on Twitter</b> Give me a <a href="https://twitter.com/nicoverbruggen">follow on Twitter</a> to learn about the latest and greatest updates of this app.</p>
|
||||
<br>
|
||||
</body>
|
||||
|
@ -64,7 +64,6 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
||||
menu.addRemainingMenuItems()
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addWarningsMenuItem()
|
||||
menu.addCoreMenuItems()
|
||||
|
||||
menu.items.forEach({ (item) in
|
||||
|
@ -157,6 +157,7 @@ extension StatusMenu {
|
||||
return
|
||||
}
|
||||
|
||||
self.addItem(NSMenuItem.separator())
|
||||
let xdebugSwitch = NSMenuItem(
|
||||
title: "mi_xdebug_mode".localized,
|
||||
action: nil,
|
||||
|
@ -66,25 +66,34 @@ class StatusMenu: NSMenu {
|
||||
|
||||
self.addExtensionsMenuItems()
|
||||
|
||||
self.addXdebugMenuItem()
|
||||
|
||||
self.addPhpDoctorMenuItem()
|
||||
|
||||
self.addItem(NSMenuItem.separator())
|
||||
|
||||
self.addXdebugMenuItem()
|
||||
self.addPresetsMenuItem()
|
||||
|
||||
self.addFirstAidAndServicesMenuItems()
|
||||
}
|
||||
|
||||
func addWarningsMenuItem() {
|
||||
func addPhpDoctorMenuItem() {
|
||||
if !Preferences.isEnabled(.showPhpDoctorSuggestions) ||
|
||||
!WarningManager.shared.hasWarnings() {
|
||||
return
|
||||
}
|
||||
|
||||
self.addItem(NSMenuItem.separator())
|
||||
|
||||
let count = WarningManager.shared.warnings.count
|
||||
self.addItem(NSMenuItem(title: "mi_warnings".localized(count),
|
||||
action: #selector(MainMenu.openWarnings), keyEquivalent: ""))
|
||||
self.addItem(HeaderView.asMenuItem(text: "mi_php_doctor".localized))
|
||||
self.addItem(NSMenuItem(
|
||||
title: "mi_recommendations_count".localized(WarningManager.shared.warnings.count),
|
||||
action: nil,
|
||||
keyEquivalent: ""
|
||||
))
|
||||
self.addItem(NSMenuItem(
|
||||
title: "mi_view_recommendations".localized,
|
||||
action: #selector(MainMenu.openWarnings),
|
||||
keyEquivalent: ""
|
||||
))
|
||||
}
|
||||
|
||||
func addCoreMenuItems() {
|
||||
|
@ -28,9 +28,9 @@ struct OnboardingTextItem: View {
|
||||
Text(description.localizedForSwiftUI)
|
||||
.foregroundColor(Color.secondary)
|
||||
.font(.system(size: 13))
|
||||
.lineLimit(6)
|
||||
.lineLimit(4)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
.frame(minWidth: 0, maxWidth: 800, alignment: .leading)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
@ -41,8 +41,7 @@ struct OnboardingTextItem: View {
|
||||
|
||||
struct OnboardingView: View {
|
||||
var body: some View {
|
||||
VStack(spacing: 10) {
|
||||
VStack(alignment: .center) {
|
||||
VStack(alignment: .center, spacing: 5) {
|
||||
HStack {
|
||||
Image(nsImage: NSApp.applicationIconImage)
|
||||
.resizable()
|
||||
@ -111,10 +110,10 @@ struct OnboardingView: View {
|
||||
App.shared.onboardingWindowController?.close()
|
||||
}
|
||||
}
|
||||
}.padding()
|
||||
}
|
||||
.padding(.leading)
|
||||
.padding(.trailing)
|
||||
}
|
||||
.padding(.top, 8)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,23 +11,35 @@ import SwiftUI
|
||||
struct WarningListView: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack(spacing: 15) {
|
||||
HStack(alignment: .center, spacing: 15) {
|
||||
Image(systemName: "stethoscope.circle.fill")
|
||||
.resizable()
|
||||
.frame(width: 40, height: 40)
|
||||
.foregroundColor(Color.red)
|
||||
.padding(12)
|
||||
VStack(alignment: .trailing, spacing: 5) {
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text("warnings.description".localizedForSwiftUI)
|
||||
.font(.system(size: 12))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text("warnings.disclaimer".localizedForSwiftUI)
|
||||
.font(.system(size: 12))
|
||||
.foregroundColor(.gray)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
.padding(10)
|
||||
|
||||
Divider()
|
||||
|
||||
HStack(alignment: .center, spacing: 15) {
|
||||
Button("warnings.refresh.button".localizedForSwiftUI) {
|
||||
WarningManager.shared.evaluateWarnings()
|
||||
}
|
||||
Text("warnings.refresh.button.description".localizedForSwiftUI)
|
||||
.foregroundColor(.gray)
|
||||
.font(.system(size: 11))
|
||||
}
|
||||
.padding(10)
|
||||
|
||||
List {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(WarningManager.shared.warnings) { warning in
|
||||
|
@ -32,7 +32,7 @@ class WarningManager {
|
||||
),
|
||||
Warning(
|
||||
command: {
|
||||
!Paths.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin") &&
|
||||
return !Shell.user.PATH.contains("/Users/\(Paths.whoami)/.config/phpmon/bin") &&
|
||||
!FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
|
||||
},
|
||||
name: "Helpers cannot be symlinked and not in PATH",
|
||||
@ -74,6 +74,8 @@ class WarningManager {
|
||||
if ProcessInfo.processInfo.environment["EXTREME_DOCTOR_MODE"] != nil {
|
||||
self.warnings = self.evaluations
|
||||
}
|
||||
|
||||
MainMenu.shared.rebuild()
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,7 +55,9 @@
|
||||
"mi_detected_extensions" = "Detected Extensions";
|
||||
"mi_no_extensions_detected" = "No additional extensions detected.";
|
||||
|
||||
"mi_warnings" = "(%i) PHP Doctor...";
|
||||
"mi_php_doctor" = "PHP Doctor";
|
||||
"mi_recommendations_count" = "%i Issue(s) Detected!";
|
||||
"mi_view_recommendations" = "View Recommendations...";
|
||||
|
||||
"mi_valet" = "Laravel Valet";
|
||||
"mi_domain_list" = "View Domains List...";
|
||||
@ -517,6 +519,8 @@ If you are seeing this message but are confused why this folder has gone missing
|
||||
"warnings.title" = "PHP Doctor";
|
||||
"warnings.description" = "**PHP Doctor** will suggest improvements to your active system configuration.";
|
||||
"warnings.disclaimer" = "You may choose to hide all recommendations from the PHP Monitor menu in Preferences, but it is recommended that you deal with all actionable items.";
|
||||
"warnings.refresh.button" = "Scan Again";
|
||||
"warnings.refresh.button.description" = "Press this button once you've fixed an issue. This will cause PHP Monitor to re-evaluate your environment. If it's really fixed, the recommendation should disappear.";
|
||||
|
||||
"warnings.helper_permissions.title" = "PHP Monitor’s helpers are currently unavailable.";
|
||||
"warnings.helper_permissions.description" = "PHP Monitor comes with various helper binaries. Using these binaries allows you to easily invoke a specific version of PHP without switching the linked PHP version.";
|
||||
@ -531,14 +535,14 @@ If you are seeing this message but are confused why this folder has gone missing
|
||||
"onboarding.title" = "Welcome Tour";
|
||||
"onboarding.welcome" = "Welcome to PHP Monitor!";
|
||||
"onboarding.explore" = "Learn more about some of the features that PHP Monitor has to offer. You can find a more comprehensive list of features on GitHub.";
|
||||
"onboarding.tour.menu_bar.title" = "Get Started";
|
||||
"onboarding.tour.menu_bar" = "PHP Monitor lives in your menu bar. From here, you can switch the globally linked PHP version, start or stop services, locate config files, and more.";
|
||||
"onboarding.tour.menu_bar.title" = "Power In Your Menu Bar";
|
||||
"onboarding.tour.menu_bar" = "PHP Monitor lives in your menu bar. From this menu, you can access most of PHP Monitor's key functionality, including switching the globally linked PHP version, locating config files, and much more.";
|
||||
"onboarding.tour.faq_hint" = "I recommend that you check out the [README](https://github.com/nicoverbruggen/phpmon/blob/main/README.md) on GitHub: it contains a comprehensive FAQ with various tips and common questions and answers.";
|
||||
"onboarding.tour.services.title" = "Manage Services";
|
||||
"onboarding.tour.services" = "Once you click on the menu bar item, you can see at a glance based on the checkmarks or crosses if all of the Homebrew services are up and running. You can also click on a service to quickly toggle it. You can also add your own!";
|
||||
"onboarding.tour.services.title" = "Manage Homebrew Services";
|
||||
"onboarding.tour.services" = "Once you click on the menu bar item, you can see at a glance based on the checkmarks or crosses if all of the Homebrew services are up and running. You can also click on a service to quickly toggle it.";
|
||||
"onboarding.tour.domains.title" = "Manage Domains";
|
||||
"onboarding.tour.domains" = "By opening the Domains window via the menu bar item, you can view which domains are linked and parked, as well as active nginx proxies.";
|
||||
"onboarding.tour.isolation.title" = "Isolate Domains";
|
||||
"onboarding.tour.isolation" = "If you have Valet 3 installed, you can even use domain isolation by right-clicking on a given domain in the Domains window. This allows you to pick a specific version of PHP to use for that domain, and that domain only!";
|
||||
"onboarding.tour.isolation" = "If you have Valet 3 installed, you can even use domain isolation by right-clicking on a given domain in the Domains window. This allows you to pick a specific version of PHP to use for that domain, and that domain only.";
|
||||
"onboarding.tour.once" = "You will only see the Welcome Tour once. You can re-open the Welcome Tour later via the menu bar icon (under First Aid & Services).";
|
||||
"onboarding.tour.close" = "Close Tour";
|
||||
|
Reference in New Issue
Block a user