mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2026-03-27 14:30:08 +01:00
✨ Add automatic fix during startup (sudoers step only for now)
This commit is contained in:
@@ -2621,7 +2621,7 @@
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastSwiftUpdateCheck = 1420;
|
||||
LastUpgradeCheck = 2620;
|
||||
LastUpgradeCheck = 2630;
|
||||
ORGANIZATIONNAME = "Nico Verbruggen";
|
||||
TargetAttributes = {
|
||||
C406A5EF298AD2CE00B5B85A = {
|
||||
@@ -4696,7 +4696,7 @@
|
||||
repositoryURL = "https://github.com/nicoverbruggen/NVAlert";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 2.0.0;
|
||||
minimumVersion = 2.1.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2620"
|
||||
LastUpgradeVersion = "2630"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2620"
|
||||
LastUpgradeVersion = "2630"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2620"
|
||||
LastUpgradeVersion = "2630"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "2620"
|
||||
LastUpgradeVersion = "2630"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
||||
@@ -14,6 +14,7 @@ import Foundation
|
||||
*/
|
||||
struct EnvironmentCheck {
|
||||
let command: (_ container: Container) async -> Bool
|
||||
let fixCommand: ((_ container: Container) async throws -> Void)?
|
||||
let name: String
|
||||
let titleText: String
|
||||
let subtitleText: String
|
||||
@@ -23,6 +24,7 @@ struct EnvironmentCheck {
|
||||
|
||||
init(
|
||||
command: @escaping (_ container: Container) async -> Bool,
|
||||
fix: ((_ container: Container) async throws -> Void)? = nil,
|
||||
name: String,
|
||||
titleText: String,
|
||||
subtitleText: String,
|
||||
@@ -31,6 +33,7 @@ struct EnvironmentCheck {
|
||||
requiresAppRestart: Bool = false,
|
||||
) {
|
||||
self.command = command
|
||||
self.fixCommand = fix
|
||||
self.name = name
|
||||
self.titleText = titleText
|
||||
self.subtitleText = subtitleText
|
||||
|
||||
@@ -44,7 +44,26 @@ class Startup {
|
||||
|
||||
// If we get here, something's gone wrong and the check has failed...
|
||||
Log.info("[FAIL] \(check.name) (\(start.milliseconds) ms)")
|
||||
await showAlert(for: check)
|
||||
|
||||
// We will present the user with an option (potentially)
|
||||
let outcome = await showAlert(for: check)
|
||||
|
||||
if outcome == .shouldRunFix {
|
||||
// First, validate there's a fix
|
||||
guard let command = check.fixCommand else {
|
||||
return false
|
||||
}
|
||||
|
||||
// We will try to run the fix, it may fail!
|
||||
do {
|
||||
try await command(App.shared.container)
|
||||
return await check.succeeds()
|
||||
} catch {
|
||||
// our fix failed :(
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
@@ -59,12 +78,17 @@ class Startup {
|
||||
return true
|
||||
}
|
||||
|
||||
enum EnvironmentAlertOutcome {
|
||||
case shouldRunFix
|
||||
case shouldRetryStartup
|
||||
}
|
||||
|
||||
/**
|
||||
Displays an alert for a particular check. There are two types of alerts:
|
||||
- ones that require an app restart, which prompt the user to exit the app
|
||||
- ones that allow the app to continue, which allow the user to retry
|
||||
*/
|
||||
@MainActor private func showAlert(for check: EnvironmentCheck) {
|
||||
@MainActor private func showAlert(for check: EnvironmentCheck) -> EnvironmentAlertOutcome {
|
||||
// Ensure that the timeout does not fire until we restart
|
||||
Self.startupTimer?.invalidate()
|
||||
|
||||
@@ -80,14 +104,30 @@ class Startup {
|
||||
}).show(urgency: .bringToFront)
|
||||
}
|
||||
|
||||
NVAlert()
|
||||
// Verify if an automatic fix is available
|
||||
let hasAutomaticFix = check.fixCommand != nil
|
||||
|
||||
// Present an alert with one or two buttons (depending on fix)
|
||||
let outcome = NVAlert()
|
||||
.withInformation(
|
||||
title: check.titleText,
|
||||
subtitle: check.subtitleText,
|
||||
description: check.descriptionText
|
||||
)
|
||||
.withPrimary(text: "generic.ok".localized)
|
||||
.show(urgency: .bringToFront)
|
||||
.withPrimary(text: hasAutomaticFix ? "startup.fix_for_me".localized : "startup.fix_manually".localized)
|
||||
.withSecondary(if: hasAutomaticFix, text: "startup.fix_manually".localized)
|
||||
.withTertiary(if: hasAutomaticFix, text: "", action: { _ in
|
||||
NSWorkspace.shared.open(Constants.Urls.FrequentlyAskedQuestions)
|
||||
})
|
||||
.runModal(urgency: .bringToFront)
|
||||
|
||||
// If there's an automatic fix and we chose to fix it, return outcome
|
||||
if hasAutomaticFix && outcome == .alertFirstButtonReturn {
|
||||
return .shouldRunFix
|
||||
}
|
||||
|
||||
// In any other situation, we will require a retry of the startup
|
||||
return .shouldRetryStartup
|
||||
}
|
||||
|
||||
// MARK: - Check (List)
|
||||
@@ -212,6 +252,9 @@ class Startup {
|
||||
.pipe("cat /private/etc/sudoers.d/brew")
|
||||
.out.contains(container.paths.brew)
|
||||
},
|
||||
fix: { container in
|
||||
try sudo("export USER=\(container.paths.whoami) && export PATH=/bin:/usr/bin:\(container.paths.binPath) && valet trust")
|
||||
},
|
||||
name: "`/private/etc/sudoers.d/brew` contains brew",
|
||||
titleText: "startup.errors.sudoers_brew.title".localized,
|
||||
subtitleText: "startup.errors.sudoers_brew.subtitle".localized,
|
||||
|
||||
@@ -73,7 +73,7 @@ class ValetUpgrader {
|
||||
}
|
||||
|
||||
@MainActor private static func notifyAboutCompletion() {
|
||||
return NVAlert().withInformation(
|
||||
NVAlert().withInformation(
|
||||
title: "valet_upgraded.title".localized,
|
||||
subtitle: "valet_upgraded.subtitle".localized,
|
||||
description: "valet_upgraded.description".localized,
|
||||
@@ -85,7 +85,7 @@ class ValetUpgrader {
|
||||
}
|
||||
|
||||
@MainActor private static func notifyAboutUpgrade(latest: String, constraint: String, passing: Bool) {
|
||||
let alert = NVAlert().withInformation(
|
||||
return NVAlert().withInformation(
|
||||
title: "valet_upgrade_available.title".localized,
|
||||
subtitle: "valet_upgrade_available.subtitle".localized(latest),
|
||||
description: passing
|
||||
@@ -97,13 +97,9 @@ class ValetUpgrader {
|
||||
ValetUpgrader.upgradeValet()
|
||||
})
|
||||
.withSecondary(text: "valet_upgrade_available.cancel".localized)
|
||||
|
||||
if !passing {
|
||||
_ = alert.withTertiary(text: "valet_upgrade_available.open_composer".localized, action: { _ in
|
||||
.withTertiary(if: !passing, text: "valet_upgrade_available.open_composer".localized, action: { _ in
|
||||
MainMenu.shared.openGlobalComposerFolder()
|
||||
})
|
||||
}
|
||||
|
||||
alert.show(urgency: .bringToFront)
|
||||
.show(urgency: .bringToFront)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,3 +958,8 @@ PHP Monitor will tell Valet to unsecure and re-secure all expired domains for yo
|
||||
"alert.enable_integrations.desc" = "If you did not trigger this via Alfred or Raycast, there may be another application trying to control PHP Monitor.\n\nIn such a case, I recommend keeping this integration turned off, unless you are fine with another third party app controlling PHP Monitor for you, which could present a potential security risk.";
|
||||
"alert.enable_integrations.ok" = "Allow Integrations";
|
||||
"alert.enable_integrations.cancel" = "Don't Allow";
|
||||
|
||||
// AUTOMATIC FIXES AT STARTUP
|
||||
|
||||
"startup.fix_for_me" = "Fix For Me";
|
||||
"startup.fix_manually" = "I Fixed It";
|
||||
|
||||
Reference in New Issue
Block a user