mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-08 04:20:07 +02:00
Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
45704fc736 | |||
f28354e634 | |||
8055a32bde | |||
5b3054326e | |||
e7f3c7e59c | |||
a407515534 | |||
b827ffb869 | |||
bdb718598e | |||
ddfc73e033 | |||
cfae520984 | |||
0c176493e5 | |||
71da62f954 | |||
d6781568a3 | |||
c9c7e14416 |
23
.github/contributing.md
vendored
Normal file
23
.github/contributing.md
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
Thank you for your interest in contributing to PHP Monitor.
|
||||
|
||||
I consider this project a bit of a nice side-project to my daily gig, so it is very much a personal affair where I love to tinker around.
|
||||
|
||||
**While the code of the latest PHP Monitor release is public, many things are constantly in flux that may not be pushed to this repository yet.**
|
||||
|
||||
I don't mean to be rude, but I don't want other people involved with the project beyond simply contributing a few small things here and there, as has been the case in the past.
|
||||
|
||||
The extra mental overhead of having additional contributors to report to, whose code will need to be reviewed... it's a lot and it makes working on PHP Monitor less enjoyable for me.
|
||||
|
||||
Plus, at this point, the majority of PHP Monitor's main functionality is also done.
|
||||
|
||||
As a result, I may refer you to this file at some point. Again, I don't wish to be rude, but this general rule stands:
|
||||
|
||||
**Making any changes in a fork and opening a pull request without opening an issue first will most likely result in your PR being closed without mercy.**
|
||||
|
||||
To repeat, I am **not opposed** to small contributions and fixes, if they are **meaningful or insightful**.
|
||||
|
||||
To learn more, please check out the [pull request template](/.github/pull_request_template.md) which contains more information about my contribution requirements. (This will also show up when you open a new PR.)
|
||||
|
||||
Thank you for respecting this!
|
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@ -16,7 +16,7 @@ In short: It is usually best to *get in touch first* if you are making substanti
|
||||
|
||||
## About destination branches
|
||||
|
||||
Please keep in mind that `main` is reserved for the current code state of the latest release and should *never* be the destination branch unless a new release is happening. **Merge requests that target `main` will be closed without mercy.**
|
||||
Please keep in mind that `main` is reserved for the current code state of the latest release and should *never* be the destination branch unless a new release is happening. **Pull requests that target `main` will be closed without mercy.**
|
||||
|
||||
Usually, the best target is the stable `dev/x.x` branch that corresponds with the latest major version that is released.
|
||||
|
||||
|
@ -1741,7 +1741,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 965;
|
||||
CURRENT_PROJECT_VERSION = 976;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = YES;
|
||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||
@ -1752,7 +1752,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 5.6.0;
|
||||
MARKETING_VERSION = 5.6.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -1769,7 +1769,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
CURRENT_PROJECT_VERSION = 965;
|
||||
CURRENT_PROJECT_VERSION = 976;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEBUG = NO;
|
||||
DEVELOPMENT_TEAM = 8M54J5J787;
|
||||
@ -1780,7 +1780,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||
MARKETING_VERSION = 5.6.0;
|
||||
MARKETING_VERSION = 5.6.2;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.nicoverbruggen.phpmon;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -1,5 +1,5 @@
|
||||
> **Note**
|
||||
> If this software has been useful to you, I ask that you **please star the repository**, that way I know that the software is being used. Also, please consider leaving [a one-time donation](https://nicoverbruggen.be/sponsor) to support the project, as this is something I make in my free time. **Thank you!** ⭐️
|
||||
> If this software has been useful to you, I ask that you **please star the repository**, that way I know that the software is being used. Also, please consider [sponsoring](https://nicoverbruggen.be/sponsor) to support the project, as this is something I make in my free time. **Thank you!** ⭐️
|
||||
|
||||
<p align="center"><img src="./docs/logo.png" alt="PHP Monitor Logo" width="500px" /></p>
|
||||
|
||||
|
@ -18,4 +18,30 @@ class AppUpdaterCheckTest: XCTestCase {
|
||||
XCTAssertNotNil(version)
|
||||
}
|
||||
|
||||
func testTaggedReleaseOmitsZeroPatch() {
|
||||
let version = AppVersion.from("3.5.0_333")!
|
||||
|
||||
XCTAssertEqual(version.tagged, "3.5")
|
||||
XCTAssertEqual(version.version, "3.5.0")
|
||||
}
|
||||
|
||||
func testTaggedReleaseDoesntOmitNonZeroPatch() {
|
||||
let version = AppVersion.from("3.5.1_333")!
|
||||
|
||||
XCTAssertEqual(version.tagged, "3.5.1")
|
||||
XCTAssertEqual(version.version, "3.5.1")
|
||||
}
|
||||
|
||||
func testTagTruncationDoesntAffectMajorVersions() {
|
||||
var version = AppVersion.from("5.0_333")!
|
||||
|
||||
XCTAssertEqual(version.tagged, "5.0")
|
||||
XCTAssertEqual(version.version, "5.0")
|
||||
|
||||
version = AppVersion.from("5.0.0_333")!
|
||||
|
||||
XCTAssertEqual(version.tagged, "5.0")
|
||||
XCTAssertEqual(version.version, "5.0.0")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
import XCTest
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
class PhpVersionNumberTest: XCTestCase {
|
||||
|
||||
func testCanDeconstructPhpVersion() throws {
|
||||
@ -287,4 +288,76 @@ class PhpVersionNumberTest: XCTestCase {
|
||||
.make(from: ["7.3.1", "7.2.9"]).all
|
||||
)
|
||||
}
|
||||
|
||||
func testCanCheckLessThanOrEqualConstraints() throws {
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<=7.2", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.2", "7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<=7.2.0", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.2", "7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
// Strict check (>7.2.5 is too new for 7.2 which resolves to 7.2.0)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<=7.2.5", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.2", "7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
// Non-strict check (ignoring patch has no effect)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<=7.2.5", strict: false),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.2", "7.1", "7.0"]).all
|
||||
)
|
||||
}
|
||||
|
||||
func testCanCheckLessThanConstraints() throws {
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<7.2", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<7.2.0", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
// Strict check (>7.2.5 is too new for 7.2 which resolves to 7.2.0)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<7.2.5", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.2", "7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
// Non-strict check (patch resolves to 7.2.999, which is bigger than 7.2.5)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: "<7.2.5", strict: false),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.1", "7.0"]).all
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -14,12 +14,18 @@ extension Shell {
|
||||
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 command = Filesystem.fileExists("~/.zshrc")
|
||||
// source the user's .zshrc file if it exists to complete $PATH
|
||||
? ". ~/.zshrc && echo $PATH"
|
||||
// otherwise, non-interactive mode is sufficient
|
||||
: "echo $PATH"
|
||||
|
||||
task.arguments = ["--login", "-lc", command]
|
||||
|
||||
let pipe = Pipe()
|
||||
task.standardOutput = pipe
|
||||
task.launch()
|
||||
|
||||
let data = pipe.fileHandleForReading.readDataToEndOfFile()
|
||||
|
||||
return String(data: data, encoding: String.Encoding.utf8) ?? ""
|
||||
|
@ -30,7 +30,7 @@ class PMWindowController: NSWindowController, NSWindowDelegate {
|
||||
}
|
||||
|
||||
deinit {
|
||||
Log.perf("Window controller '\(windowName)' was deinitialized")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -87,6 +87,14 @@ public struct PhpVersionNumberCollection: Equatable {
|
||||
return self.versions.filter { $0.isNewerThan(version, strict) }
|
||||
}
|
||||
|
||||
if let version = PhpVersionNumber.make(from: constraint, type: .smallerThanOrEqual) {
|
||||
return self.versions.filter { $0.isSameAs(version, strict) || $0.isOlderThan(version, strict)}
|
||||
}
|
||||
|
||||
if let version = PhpVersionNumber.make(from: constraint, type: .smallerThan) {
|
||||
return self.versions.filter { $0.isOlderThan(version, strict)}
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
||||
@ -116,12 +124,8 @@ public struct PhpVersionNumber: Equatable, Hashable {
|
||||
case tildeVersionRange = #"^~(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||
case greaterThanOrEqual = #"^>=(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||
case greaterThan = #"^>(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||
|
||||
// TODO: (6.0) Handle these cases (even though I suspect these are uncommon)
|
||||
/*
|
||||
case smallerThanOrEqual = #"^<=(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||
case smallerThan = #"^<(?<major>\d+).(?<minor>\d+).?(?<patch>\d+)?\z"#
|
||||
*/
|
||||
}
|
||||
|
||||
public static func parse(_ text: String) throws -> Self {
|
||||
@ -175,6 +179,15 @@ public struct PhpVersionNumber: Equatable, Hashable {
|
||||
)
|
||||
}
|
||||
|
||||
internal func isOlderThan(_ version: PhpVersionNumber, _ strict: Bool) -> Bool {
|
||||
return (
|
||||
self.major < version.major ||
|
||||
self.major == version.major && self.minor < version.minor ||
|
||||
self.major == version.major && self.minor == version.minor
|
||||
&& self.patch(strict) < version.patch(strict)
|
||||
)
|
||||
}
|
||||
|
||||
internal func hasNewerMinorVersionOrPatch(_ version: PhpVersionNumber, _ strict: Bool) -> Bool {
|
||||
return self.major == version.major &&
|
||||
(
|
||||
|
@ -65,7 +65,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
|
||||
override init() {
|
||||
logger.verbosity = .info
|
||||
#if DEBUG
|
||||
// logger.verbosity = .performance
|
||||
logger.verbosity = .performance
|
||||
#endif
|
||||
if CommandLine.arguments.contains("--v") {
|
||||
logger.verbosity = .performance
|
||||
|
@ -146,8 +146,9 @@ class AppUpdateChecker {
|
||||
text: "updater.alerts.buttons.release_notes".localized,
|
||||
action: { vc in
|
||||
vc.close(with: .OK)
|
||||
|
||||
NSWorkspace.shared.open(
|
||||
Constants.Urls.GitHubReleases.appendingPathComponent("/tag/v\(version.version)\(devSuffix)")
|
||||
Constants.Urls.GitHubReleases.appendingPathComponent("/tag/v\(version.tagged)\(devSuffix)")
|
||||
)
|
||||
}
|
||||
)
|
||||
|
@ -66,6 +66,14 @@ class AppVersion {
|
||||
return AppVersion.from("\(App.shortVersion)_\(App.bundleVersion)")!
|
||||
}
|
||||
|
||||
var tagged: String {
|
||||
if version.suffix(2) == ".0" && version.count > 3 {
|
||||
return String(version.dropLast(2))
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
||||
|
||||
var computerReadable: String {
|
||||
return "\(version)_\(build ?? "0")"
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ extension DomainListVC {
|
||||
let originalSecureStatus = selectedSite!.secured
|
||||
let action = selectedSite!.secured ? "unsecure" : "secure"
|
||||
let selectedSite = selectedSite!
|
||||
let command = "cd '\(selectedSite.absolutePath)' && sudo \(Paths.valet) \(action) && exit;"
|
||||
let command = "sudo \(Paths.valet) \(action) '\(selectedSite.name)' && exit;"
|
||||
|
||||
waitAndExecute {
|
||||
Shell.run(command, requiresPath: true)
|
||||
|
@ -292,6 +292,6 @@ class DomainListVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
|
||||
// MARK: - Deinitialization
|
||||
|
||||
deinit {
|
||||
Log.perf("DomainListVC deallocated")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
}
|
||||
|
@ -52,15 +52,15 @@ class ComposerWindow {
|
||||
}
|
||||
|
||||
task.listen(
|
||||
didReceiveStandardOutputData: { string in
|
||||
didReceiveStandardOutputData: { [weak self] string in
|
||||
DispatchQueue.main.async {
|
||||
self.window?.addToConsole(string)
|
||||
self?.window?.addToConsole(string)
|
||||
}
|
||||
// Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
||||
},
|
||||
didReceiveStandardErrorData: { string in
|
||||
didReceiveStandardErrorData: { [weak self] string in
|
||||
DispatchQueue.main.async {
|
||||
self.window?.addToConsole(string)
|
||||
self?.window?.addToConsole(string)
|
||||
}
|
||||
// Log.perf("\(string.trimmingCharacters(in: .newlines))")
|
||||
}
|
||||
@ -91,6 +91,7 @@ class ComposerWindow {
|
||||
}
|
||||
window = nil
|
||||
removeBusyStatus()
|
||||
menu = nil
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
@ -103,6 +104,7 @@ class ComposerWindow {
|
||||
window?.progressView?.labelDescription.stringValue = "alert.composer_failure.info".localized
|
||||
window = nil
|
||||
removeBusyStatus()
|
||||
menu = nil
|
||||
completion(false)
|
||||
}
|
||||
}
|
||||
@ -128,4 +130,8 @@ class ComposerWindow {
|
||||
.withPrimary(text: "OK")
|
||||
.show()
|
||||
}
|
||||
|
||||
deinit {
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
}
|
||||
|
@ -155,11 +155,11 @@ extension MainMenu {
|
||||
|
||||
App.shared.detectedApplications = Application.detectPresetApplications()
|
||||
|
||||
let customApps = Preferences.custom.scanApps.map { appName in
|
||||
let customApps = Preferences.custom.scanApps?.map { appName in
|
||||
return Application(appName, .user_supplied)
|
||||
}.filter { app in
|
||||
return app.isInstalled()
|
||||
}
|
||||
} ?? []
|
||||
|
||||
App.shared.detectedApplications.append(contentsOf: customApps)
|
||||
|
||||
|
@ -212,18 +212,19 @@ extension StatusMenu {
|
||||
|
||||
func addXdebugMenuItem() {
|
||||
if !Xdebug.enabled {
|
||||
addItem(NSMenuItem.separator())
|
||||
return
|
||||
}
|
||||
|
||||
addItems([
|
||||
NSMenuItem.separator(),
|
||||
NSMenuItem(title: "mi_xdebug_mode".localized, submenu: [
|
||||
HeaderView.asMenuItem(text: "mi_xdebug_available_modes".localized)
|
||||
] + Xdebug.asMenuItems() + [
|
||||
HeaderView.asMenuItem(text: "mi_xdebug_actions".localized),
|
||||
NSMenuItem(title: "mi_xdebug_disable_all".localized,
|
||||
action: #selector(MainMenu.disableAllXdebugModes))
|
||||
], target: MainMenu.shared)
|
||||
], target: MainMenu.shared),
|
||||
NSMenuItem.separator()
|
||||
], target: MainMenu.shared)
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,9 @@ class StatusMenu: NSMenu {
|
||||
|
||||
if Preferences.isEnabled(.displayExtensions) {
|
||||
addExtensionsMenuItems()
|
||||
addXdebugMenuItem()
|
||||
NSMenuItem.separator()
|
||||
|
||||
addXdebugMenuItem()
|
||||
}
|
||||
|
||||
addPhpDoctorMenuItem()
|
||||
|
@ -47,7 +47,7 @@ class BetterAlertVC: NSViewController {
|
||||
}
|
||||
|
||||
deinit {
|
||||
Log.perf("A BetterAlert has been deinitialized.")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
|
||||
// MARK: Outlet Actions
|
||||
|
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
struct CustomPrefs: Decodable {
|
||||
let scanApps: [String]
|
||||
let scanApps: [String]?
|
||||
let presets: [Preset]?
|
||||
let services: [String]?
|
||||
let environmentVariables: [String: String]?
|
||||
|
@ -25,7 +25,7 @@ class GenericPreferenceVC: NSViewController {
|
||||
// MARK: - Deinitialization
|
||||
|
||||
deinit {
|
||||
Log.perf("PrefsVC deallocated")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
|
||||
func getDynamicIconPV() -> NSView {
|
||||
|
@ -18,7 +18,7 @@ class ProgressViewController: NSViewController {
|
||||
@IBOutlet weak var imageViewType: NSImageView!
|
||||
|
||||
deinit {
|
||||
Log.perf("Deinitializing ProgressViewController")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ class TerminalProgressWindowController: NSWindowController, NSWindowDelegate {
|
||||
}
|
||||
|
||||
deinit {
|
||||
Log.perf("Deinitializing ProgressWindowController")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,8 +10,13 @@ import Foundation
|
||||
import SwiftUI
|
||||
|
||||
var isRunningSwiftUIPreview: Bool {
|
||||
return ProcessInfo.processInfo
|
||||
.environment["XCODE_RUNNING_FOR_PREVIEWS"] != nil
|
||||
#if DEBUG
|
||||
// If running SwiftUI *and* when debugging
|
||||
return ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] != nil
|
||||
#else
|
||||
// Release builds should always return false here
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
|
||||
extension Color {
|
||||
|
@ -68,7 +68,7 @@ class PhpConfigWatcher {
|
||||
}
|
||||
|
||||
deinit {
|
||||
Log.perf("A PhpConfigWatcher has been deinitialized.")
|
||||
Log.perf("deinit: \(String(describing: self)).\(#function)")
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user