mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 03:50:08 +02:00
✨ Check if running the app with Rosetta
This commit is contained in:
@ -166,6 +166,8 @@
|
||||
C4927F0C27B2DFC200C55AFD /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4927F0A27B2DFC200C55AFD /* Errors.swift */; };
|
||||
C493084A279F331F009C240B /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; };
|
||||
C493084B279F331F009C240B /* AddSiteVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4930849279F331F009C240B /* AddSiteVC.swift */; };
|
||||
C495F5AF28A42E080087F70A /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; };
|
||||
C495F5B028A42E080087F70A /* EnvironmentCheck.swift in Sources */ = {isa = PBXBuildFile; fileRef = C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */; };
|
||||
C4998F0A2617633900B2526E /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PreferencesWindowController.swift */; };
|
||||
C4998F0B2617633900B2526E /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4998F092617633900B2526E /* PreferencesWindowController.swift */; };
|
||||
C4AC51FC27E27F47008528CA /* DomainListKindCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */; };
|
||||
@ -398,6 +400,7 @@
|
||||
C48D6C73279CD3E400F26D7E /* PhpVersionNumberTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhpVersionNumberTest.swift; sourceTree = "<group>"; };
|
||||
C4927F0A27B2DFC200C55AFD /* Errors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = "<group>"; };
|
||||
C4930849279F331F009C240B /* AddSiteVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddSiteVC.swift; sourceTree = "<group>"; };
|
||||
C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentCheck.swift; sourceTree = "<group>"; };
|
||||
C4998F092617633900B2526E /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
||||
C4AC51FB27E27F47008528CA /* DomainListKindCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListKindCell.swift; sourceTree = "<group>"; };
|
||||
C4ACA38E25C754C100060C66 /* PhpExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpExtension.swift; sourceTree = "<group>"; };
|
||||
@ -890,6 +893,7 @@
|
||||
C4B97B7A275CF20A003F3378 /* App+GlobalHotkey.swift */,
|
||||
C4EED88827A48778006D7272 /* InterAppHandler.swift */,
|
||||
C4D8016522B1584700C6DA1B /* Startup.swift */,
|
||||
C495F5AE28A42E080087F70A /* EnvironmentCheck.swift */,
|
||||
C46E206C28299B3800D909D6 /* AppUpdateChecker.swift */,
|
||||
C40FE736282ABA4F00A302C2 /* AppVersion.swift */,
|
||||
C45E76132854A65300B4FE0C /* ServicesManager.swift */,
|
||||
@ -1322,6 +1326,7 @@
|
||||
C422DDAD28A2DAC600CEAC97 /* WarningsWindowController.swift in Sources */,
|
||||
C415937F27A1B54F00D2E1B7 /* PhpFrameworks.swift in Sources */,
|
||||
C4811D2422D70A4700B5F6B3 /* App.swift in Sources */,
|
||||
C495F5AF28A42E080087F70A /* EnvironmentCheck.swift in Sources */,
|
||||
C41C1B4922B00A9800E7CF16 /* MenuBarImageGenerator.swift in Sources */,
|
||||
C4F30B03278E16BA00755FCE /* HomebrewService.swift in Sources */,
|
||||
54D9E0B427E4F51E003B9AD9 /* Key.swift in Sources */,
|
||||
@ -1453,6 +1458,7 @@
|
||||
C4B97B76275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
|
||||
C4F780CD25D80B75000DBC97 /* Alert.swift in Sources */,
|
||||
C481F79726164A78004FBCFF /* PrefsVC.swift in Sources */,
|
||||
C495F5B028A42E080087F70A /* EnvironmentCheck.swift in Sources */,
|
||||
C41E871B2763D42300161EE0 /* DomainListVC+ContextMenu.swift in Sources */,
|
||||
C40C7F3127722E8D00DDDCDC /* Logger.swift in Sources */,
|
||||
C4068CAB27B0890D00544CD5 /* MenuBarIcons.swift in Sources */,
|
||||
|
@ -68,6 +68,9 @@ class App {
|
||||
/** The services manager, responsible for figuring out what services are active/inactive. */
|
||||
var services = ServicesManager.shared
|
||||
|
||||
/** The warning manager, responsible for keeping track of warnings. */
|
||||
var warnings = WarningManager.shared
|
||||
|
||||
/** Timer that will periodically reload info about the user's PHP installation. */
|
||||
var timer: Timer?
|
||||
|
||||
|
45
phpmon/Domain/App/EnvironmentCheck.swift
Normal file
45
phpmon/Domain/App/EnvironmentCheck.swift
Normal file
@ -0,0 +1,45 @@
|
||||
//
|
||||
// EnvironmentCheck.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 10/08/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
The `EnvironmentCheck` is used to defer the execution of all of these commands until necessary.
|
||||
Checks that require an app restart will always lead to an alert and app termination shortly after.
|
||||
*/
|
||||
struct EnvironmentCheck {
|
||||
let command: () async -> Bool
|
||||
let name: String
|
||||
let titleText: String
|
||||
let subtitleText: String
|
||||
let descriptionText: String
|
||||
let buttonText: String
|
||||
let requiresAppRestart: Bool
|
||||
|
||||
init(
|
||||
command: @escaping () async -> Bool,
|
||||
name: String,
|
||||
titleText: String,
|
||||
subtitleText: String,
|
||||
descriptionText: String = "",
|
||||
buttonText: String = "OK",
|
||||
requiresAppRestart: Bool = false
|
||||
) {
|
||||
self.command = command
|
||||
self.name = name
|
||||
self.titleText = titleText
|
||||
self.subtitleText = subtitleText
|
||||
self.descriptionText = descriptionText
|
||||
self.buttonText = buttonText
|
||||
self.requiresAppRestart = requiresAppRestart
|
||||
}
|
||||
|
||||
public func succeeds() async -> Bool {
|
||||
return await !self.command()
|
||||
}
|
||||
}
|
@ -238,42 +238,4 @@ class Startup {
|
||||
descriptionText: "startup.errors.valet_version_unknown.desc".localized
|
||||
)
|
||||
]
|
||||
|
||||
// MARK: - EnvironmentCheck struct
|
||||
|
||||
/**
|
||||
The `EnvironmentCheck` is used to defer the execution of all of these commands until necessary.
|
||||
Checks that require an app restart will always lead to an alert and app termination shortly after.
|
||||
*/
|
||||
struct EnvironmentCheck {
|
||||
let command: () async -> Bool
|
||||
let name: String
|
||||
let titleText: String
|
||||
let subtitleText: String
|
||||
let descriptionText: String
|
||||
let buttonText: String
|
||||
let requiresAppRestart: Bool
|
||||
|
||||
init(
|
||||
command: @escaping () async -> Bool,
|
||||
name: String,
|
||||
titleText: String,
|
||||
subtitleText: String,
|
||||
descriptionText: String = "",
|
||||
buttonText: String = "OK",
|
||||
requiresAppRestart: Bool = false
|
||||
) {
|
||||
self.command = command
|
||||
self.name = name
|
||||
self.titleText = titleText
|
||||
self.subtitleText = subtitleText
|
||||
self.descriptionText = descriptionText
|
||||
self.buttonText = buttonText
|
||||
self.requiresAppRestart = requiresAppRestart
|
||||
}
|
||||
|
||||
public func succeeds() async -> Bool {
|
||||
return await !self.command()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -79,21 +79,25 @@ extension MainMenu {
|
||||
// A non-default TLD is not officially supported since Valet 3.2.x
|
||||
Valet.notifyAboutUnsupportedTLD()
|
||||
|
||||
// Find out which services are active
|
||||
ServicesManager.shared.loadData()
|
||||
|
||||
// Start the background refresh timer
|
||||
startSharedTimer()
|
||||
|
||||
// Check warnings
|
||||
WarningManager.shared.evaluateWarnings()
|
||||
|
||||
// Update the stats
|
||||
Stats.incrementSuccessfulLaunchCount()
|
||||
Stats.evaluateSponsorMessageShouldBeDisplayed()
|
||||
|
||||
// Present first launch screen if needed
|
||||
#warning("The launch screen will be presented every time you launch the app.")
|
||||
if Stats.successfulLaunchCount >= 1 && !isRunningSwiftUIPreview {
|
||||
#warning("You should definitely tweak this view again")
|
||||
if Stats.successfulLaunchCount == 0 && !isRunningSwiftUIPreview {
|
||||
Log.info("Should present the first launch screen!")
|
||||
DispatchQueue.main.async {
|
||||
// OnboardingWindowController.show()
|
||||
OnboardingWindowController.show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@ class MainMenu: NSObject, NSWindowDelegate, NSMenuDelegate, PhpSwitcherDelegate
|
||||
menu.addRemainingMenuItems()
|
||||
menu.addItem(NSMenuItem.separator())
|
||||
|
||||
menu.addWarningsMenuItem()
|
||||
menu.addCoreMenuItems()
|
||||
|
||||
menu.items.forEach({ (item) in
|
||||
|
@ -74,12 +74,21 @@ class StatusMenu: NSMenu {
|
||||
self.addFirstAidAndServicesMenuItems()
|
||||
}
|
||||
|
||||
func addWarningsMenuItem() {
|
||||
if !WarningManager.shared.hasWarnings() {
|
||||
return
|
||||
}
|
||||
|
||||
self.addItem(NSMenuItem.separator())
|
||||
|
||||
let count = WarningManager.shared.warnings.count
|
||||
self.addItem(NSMenuItem(title: (count == 1 ? "mi_warning" : "mi_warnings").localized(count),
|
||||
action: #selector(MainMenu.openWarnings), keyEquivalent: ""))
|
||||
}
|
||||
|
||||
func addCoreMenuItems() {
|
||||
self.addItem(NSMenuItem.separator())
|
||||
if (WarningManager.hasWarnings()) {
|
||||
self.addItem(NSMenuItem(title: "mi_warnings".localized(2),
|
||||
action: #selector(MainMenu.openWarnings), keyEquivalent: ""))
|
||||
}
|
||||
|
||||
self.addItem(NSMenuItem(title: "mi_preferences".localized,
|
||||
action: #selector(MainMenu.openPrefs), keyEquivalent: ","))
|
||||
self.addItem(NSMenuItem(title: "mi_check_for_updates".localized,
|
||||
|
@ -12,17 +12,14 @@ struct WarningListView: View {
|
||||
var body: some View {
|
||||
List {
|
||||
VStack(alignment: .leading) {
|
||||
WarningView(
|
||||
title: "warnings.arm_compatibility_title",
|
||||
description: "warnings.arm_compatibility.description",
|
||||
documentationUrl: "https://phpmon.app/documentation/apple-silicon-transition"
|
||||
)
|
||||
Divider()
|
||||
WarningView(
|
||||
title: "warnings.helper_permissions_title",
|
||||
description: "warnings.helper_permissions.description"
|
||||
)
|
||||
Divider()
|
||||
ForEach(WarningManager.shared.warnings) { warning in
|
||||
WarningView(
|
||||
title: warning.titleText,
|
||||
description: warning.descriptionText,
|
||||
documentationUrl: warning.url
|
||||
)
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,29 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct Warning {
|
||||
struct Warning: Identifiable {
|
||||
var id = UUID()
|
||||
let command: () async -> Bool
|
||||
let name: String
|
||||
let titleText: String
|
||||
let descriptionText: String
|
||||
let url: String?
|
||||
|
||||
init(
|
||||
command: @escaping () async -> Bool,
|
||||
name: String,
|
||||
titleText: String,
|
||||
descriptionText: String,
|
||||
url: String?
|
||||
) {
|
||||
self.command = command
|
||||
self.name = name
|
||||
self.titleText = titleText
|
||||
self.descriptionText = descriptionText
|
||||
self.url = url
|
||||
}
|
||||
|
||||
public func applies() async -> Bool {
|
||||
return await self.command()
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,43 @@ import Foundation
|
||||
|
||||
class WarningManager {
|
||||
|
||||
// TODO: Singleton initialization at launch
|
||||
static var shared = WarningManager()
|
||||
|
||||
public let evaluations: [Warning] = [
|
||||
Warning(
|
||||
command: {
|
||||
return Shell.pipe("sysctl -n sysctl.proc_translated")
|
||||
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
|
||||
},
|
||||
name: "Running PHP Monitor with Rosetta on M1",
|
||||
titleText: "warnings.arm_compatibility.title",
|
||||
descriptionText: "warnings.arm_compatibility.description",
|
||||
url: nil
|
||||
)
|
||||
]
|
||||
|
||||
@Published public var warnings: [Warning] = []
|
||||
|
||||
public func hasWarnings() -> Bool {
|
||||
return !warnings.isEmpty
|
||||
}
|
||||
|
||||
func evaluateWarnings() {
|
||||
Task { await WarningManager.shared.checkEnvironment() }
|
||||
}
|
||||
|
||||
/**
|
||||
Checks the user's environment and checks if any special warnings apply.
|
||||
*/
|
||||
func checkEnvironment() async {
|
||||
self.warnings = []
|
||||
for check in self.evaluations {
|
||||
if await check.applies() {
|
||||
Log.info("[WARNING] \(check.name)")
|
||||
self.warnings.append(check)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -55,6 +55,7 @@
|
||||
"mi_detected_extensions" = "Detected Extensions";
|
||||
"mi_no_extensions_detected" = "No additional extensions detected.";
|
||||
|
||||
"mi_warning" = "⚠️ %i Warning";
|
||||
"mi_warnings" = "⚠️ %i Warnings...";
|
||||
|
||||
"mi_valet" = "Laravel Valet";
|
||||
@ -510,10 +511,10 @@ If you are seeing this message but are confused why this folder has gone missing
|
||||
|
||||
"warnings.title" = "Warnings";
|
||||
|
||||
"warnings.helper_permissions_title" = "Helpers could not be written!";
|
||||
"warnings.helper_permissions.title" = "Helpers could not be written!";
|
||||
"warnings.helper_permissions.description" = "The helper files in `/usr/local/bin` could not be written because PHP Monitor does not have permission to write there.";
|
||||
|
||||
"warnings.arm_compatibility_title" = "You are running PHP Monitor using Rosetta";
|
||||
"warnings.arm_compatibility.title" = "You are running PHP Monitor using Rosetta";
|
||||
"warnings.arm_compatibility.description" = "You appear to be running an ARM-compatible version of macOS, but you are currently running PHP Monitor using Rosetta. While this will work correctly, it is recommended that you use the native version of Homebrew.";
|
||||
|
||||
// ONBOARDING
|
||||
|
Reference in New Issue
Block a user