1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-11-07 05:10:06 +01:00

WIP: Add support for nginx-full, formulae tweaks

This commit is contained in:
2022-11-21 23:55:37 +01:00
parent c6aa06842c
commit c3e55df9fb
9 changed files with 153 additions and 63 deletions

View File

@@ -13,31 +13,32 @@ class Actions {
// MARK: - Services
public static func restartPhpFpm() async {
await brew("services restart \(PhpEnv.phpInstall.formula)", sudo: true)
await brew("services restart \(Homebrew.Formulae.php.name)", sudo: Homebrew.Formulae.php.elevated)
}
public static func restartNginx() async {
await brew("services restart nginx", sudo: true)
await brew("services restart \(Homebrew.Formulae.nginx.name)", sudo: Homebrew.Formulae.nginx.elevated)
}
public static func restartDnsMasq() async {
await brew("services restart dnsmasq", sudo: true)
await brew("services restart \(Homebrew.Formulae.dnsmasq.name)", sudo: Homebrew.Formulae.dnsmasq.elevated)
}
public static func stopValetServices() async {
await brew("services stop \(PhpEnv.phpInstall.formula)", sudo: true)
await brew("services stop nginx", sudo: true)
await brew("services stop dnsmasq", sudo: true)
await brew("services stop \(Homebrew.Formulae.php)", sudo: Homebrew.Formulae.php.elevated)
await brew("services stop \(Homebrew.Formulae.nginx)", sudo: Homebrew.Formulae.nginx.elevated)
await brew("services stop \(Homebrew.Formulae.dnsmasq)", sudo: Homebrew.Formulae.dnsmasq.elevated)
}
public static func fixHomebrewPermissions() throws {
var servicesCommands = [
"\(Paths.brew) services stop nginx",
"\(Paths.brew) services stop dnsmasq"
"\(Paths.brew) services stop \(Homebrew.Formulae.nginx)",
"\(Paths.brew) services stop \(Homebrew.Formulae.dnsmasq)"
]
var cellarCommands = [
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/nginx",
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/dnsmasq"
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(Homebrew.Formulae.nginx)",
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(Homebrew.Formulae.dnsmasq)"
]
PhpEnv.shared.availablePhpVersions.forEach { version in
@@ -68,7 +69,7 @@ class Actions {
public static func stopService(name: String) async {
await brew(
"services stop \(name)",
sudo: ServicesManager.shared.rootServices.contains { $0.value.name == name }
sudo: ServicesManager.shared.services[name]?.formula.elevated ?? false
)
await ServicesManager.loadHomebrewServices()
}
@@ -76,7 +77,7 @@ class Actions {
public static func startService(name: String) async {
await brew(
"services start \(name)",
sudo: ServicesManager.shared.rootServices.contains { $0.value.name == name }
sudo: ServicesManager.shared.services[name]?.formula.elevated ?? false
)
await ServicesManager.loadHomebrewServices()
}
@@ -138,9 +139,9 @@ class Actions {
public static func fixMyValet(completed: @escaping () -> Void) {
InternalSwitcher().performSwitch(to: PhpEnv.brewPhpAlias, completion: {
Task { // Restart all services asynchronously and fire callback upon completion
await brew("services restart dnsmasq", sudo: true)
await brew("services restart php", sudo: true)
await brew("services restart nginx", sudo: true)
await brew("services restart \(Homebrew.Formulae.dnsmasq)", sudo: Homebrew.Formulae.dnsmasq.elevated)
await brew("services restart \(Homebrew.Formulae.php)", sudo: Homebrew.Formulae.php.elevated)
await brew("services restart \(Homebrew.Formulae.nginx)", sudo: Homebrew.Formulae.nginx.elevated)
completed()
}
})

View File

@@ -0,0 +1,37 @@
//
// Homebrew.swift
// PHP Monitor
//
// Created by Nico Verbruggen on 21/11/2022.
// Copyright © 2022 Nico Verbruggen. All rights reserved.
//
import Foundation
class Homebrew {
struct Formulae {
static var php: HomebrewFormula {
return HomebrewFormula(PhpEnv.phpInstall.formula, elevated: true)
}
static var nginx: HomebrewFormula {
return HomebrewDiagnostics.usesNginxFullFormula
? HomebrewFormula("nginx-full", elevated: true)
: HomebrewFormula("nginx", elevated: true)
}
static var dnsmasq: HomebrewFormula {
return HomebrewFormula("dnsmasq", elevated: true)
}
}
}
class HomebrewFormula {
let name: String
let elevated: Bool
init(_ name: String, elevated: Bool = true) {
self.name = name
self.elevated = elevated
}
}

View File

@@ -83,9 +83,6 @@ class App {
/** List of detected (installed) applications that PHP Monitor can work with. */
var detectedApplications: [Application] = []
/** 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

View File

@@ -13,45 +13,78 @@ class ServicesManager: ObservableObject {
static var shared = ServicesManager()
@Published var rootServices: [String: HomebrewService] = [:]
@Published var userServices: [String: HomebrewService] = [:]
private var formulae: [HomebrewFormula]
public static func loadHomebrewServices() async {
let rootServiceNames = [
PhpEnv.phpInstall.formula,
"nginx",
"dnsmasq"
@Published var services: [String: ServiceWrapper] = [:]
init() {
formulae = [
Homebrew.Formulae.php,
Homebrew.Formulae.nginx,
Homebrew.Formulae.dnsmasq
]
let normalJson = await Shell
.pipe("sudo \(Paths.brew) services info --all --json")
.out.data(using: .utf8)!
let additionalFormulae = (Preferences.custom.services ?? []).map({ item in
return HomebrewFormula(item, elevated: false)
})
let normalServices = try! JSONDecoder()
.decode([HomebrewService].self, from: normalJson)
.filter({ return rootServiceNames.contains($0.name) })
formulae.append(contentsOf: additionalFormulae)
Task { @MainActor in
ServicesManager.shared.rootServices = Dictionary(
uniqueKeysWithValues: normalServices.map { ($0.name, $0) }
)
services = Dictionary(uniqueKeysWithValues: formulae.map { ($0.name, ServiceWrapper(formula: $0)) })
}
public static func loadHomebrewServices() async {
Task {
let rootServiceNames = Self.shared.formulae
.filter { $0.elevated }
.map { $0.name }
let rootJson = await Shell
.pipe("sudo \(Paths.brew) services info --all --json")
.out.data(using: .utf8)!
let rootServices = try! JSONDecoder()
.decode([HomebrewService].self, from: rootJson)
.filter({ return rootServiceNames.contains($0.name) })
Task { @MainActor in
for service in rootServices {
Self.shared.services[service.name]!.service = service
}
}
}
guard let userServiceNames = Preferences.custom.services else { return }
Task {
let userServiceNames = Self.shared.formulae
.filter { !$0.elevated }
.map { $0.name }
let rootJson = await Shell
.pipe("\(Paths.brew) services info --all --json")
.out
.data(using: .utf8)!
let normalJson = await Shell
.pipe("\(Paths.brew) services info --all --json")
.out.data(using: .utf8)!
let rootServices = try! JSONDecoder()
.decode([HomebrewService].self, from: rootJson)
.filter({ return userServiceNames.contains($0.name) })
let userServices = try! JSONDecoder()
.decode([HomebrewService].self, from: normalJson)
.filter({ return userServiceNames.contains($0.name) })
Task { @MainActor in
ServicesManager.shared.userServices = Dictionary(
uniqueKeysWithValues: rootServices.map { ($0.name, $0) }
)
Task { @MainActor in
for service in userServices {
Self.shared.services[service.name]!.service = service
}
}
}
}
/**
Service wrapper, that contains the Homebrew JSON output (if determined) and the formula.
This helps the app determine whether a service should run as an administrator or not.
*/
public class ServiceWrapper {
public let formula: HomebrewFormula
public var service: HomebrewService?
init(formula: HomebrewFormula) {
self.formula = formula
}
}
@@ -60,11 +93,11 @@ class ServicesManager: ObservableObject {
*/
func withDummyServices(_ services: [String: Bool]) -> Self {
for (service, enabled) in services {
let item = HomebrewService.dummy(named: service, enabled: enabled)
self.rootServices[service] = item
let item = ServiceWrapper(formula: HomebrewFormula(service))
item.service = HomebrewService.dummy(named: service, enabled: enabled)
self.services[service] = item
}
return self
}
}

View File

@@ -162,7 +162,7 @@ class Startup {
EnvironmentCheck(
command: {
await HomebrewDiagnostics.loadInstalledTaps()
return await HomebrewDiagnostics.cannotLoadService("nginx")
return await HomebrewDiagnostics.cannotLoadService("dnsmasq")
},
name: "`sudo \(Paths.brew) services info` JSON loaded",
titleText: "startup.errors.services_json_error.title".localized,

View File

@@ -34,6 +34,17 @@ class HomebrewDiagnostics {
return installedTaps.contains("nicoverbruggen/cask")
}()
/**
Determines whether to use the regular `nginx` or `nginx-full` formula.
*/
public static var usesNginxFullFormula: Bool = {
guard let destination = try? FileManager.default
.destinationOfSymbolicLink(atPath: "\(Paths.binPath)/nginx") else { return false }
// Verify that the `nginx` binary is symlinked to a directory that includes `nginx-full`.
return destination.contains("/nginx-full/")
}()
/**
It is possible to have the `shivammathur/php` tap installed, and for the core homebrew information to be outdated.
This will then result in two different aliases claiming to point to the same formula (`php`).

View File

@@ -36,8 +36,13 @@ extension MainMenu {
// Determine install method
Log.info(HomebrewDiagnostics.customCaskInstalled
? "The app has probably been installed via Homebrew Cask."
: "The app has probably been installed directly."
? "[BREW] The app has probably been installed via Homebrew Cask."
: "[BREW] The app has probably been installed directly."
)
Log.info(HomebrewDiagnostics.usesNginxFullFormula
? "[BREW] The app will be using the `nginx-full` formula."
: "[BREW] The app will be using the `nginx` formula."
)
// Attempt to find out more info about Valet

View File

@@ -17,9 +17,9 @@ struct ServicesView: View {
static func asMenuItem(perRow: Int = 3) -> NSMenuItem {
let item = NSMenuItem()
var services = [
PhpEnv.phpInstall.formula,
"nginx",
"dnsmasq"
Homebrew.Formulae.php.name,
Homebrew.Formulae.nginx.name,
Homebrew.Formulae.dnsmasq.name
]
if Preferences.custom.hasServices() {
@@ -76,16 +76,12 @@ struct CheckmarkView: View {
@EnvironmentObject var manager: ServicesManager
public func hasAnyServices() -> Bool {
return !manager.rootServices.isEmpty
return !manager.services.isEmpty
}
public func active() -> Bool? {
if manager.rootServices.keys.contains(serviceName) {
return manager.rootServices[serviceName]!.running
}
if manager.userServices.keys.contains(serviceName) {
return manager.userServices[serviceName]!.running
if manager.services.keys.contains(serviceName) {
return manager.services[serviceName]!.service?.running ?? nil
}
return nil