Compare commits
205 Commits
Author | SHA1 | Date | |
---|---|---|---|
4eea13f059 | |||
3cff2d6469 | |||
df506e4128 | |||
f3b1172d0e | |||
32278533bf | |||
39908f7fc5 | |||
347d79c88d | |||
9bc117e9f5 | |||
ba5fbed9be | |||
211556d5ce | |||
066d7bc217 | |||
f072ceae37 | |||
273dac1ca7 | |||
f3b170ba14 | |||
78d8030ed6 | |||
a300d2f4cf | |||
96a658073e | |||
8395ba407d | |||
f80e3fed2b | |||
b48edf7409 | |||
e0a0eb089d | |||
60b126333d | |||
649a3f4fb5 | |||
9a326928f3 | |||
52f87ca18a | |||
ad2d2cb57f | |||
22c0021ada | |||
2cfc5731fb | |||
1d74e1536c | |||
e6b2ddf2ad | |||
62fda6224e | |||
083f8ebec8 | |||
aec8fb1168 | |||
d5d9b38ed6 | |||
9a6975e3d9 | |||
d1c40f2eb5 | |||
ad58661449 | |||
1d6cfd419e | |||
15182ea15a | |||
c43e00c88d | |||
25c7004368 | |||
02ba57cd64 | |||
c2dc6302c0 | |||
af9f30a123 | |||
28c5754800 | |||
48c1d48573 | |||
582bf0e12c | |||
46b30bbff4 | |||
372011ca08 | |||
7255792910 | |||
0c96b11b05 | |||
ea4da12d3b | |||
8419ebad10 | |||
09a5cf836a | |||
1a1a53b472 | |||
a8bad8447a | |||
ca8f5a8fbe | |||
a0e7aec228 | |||
26badc759e | |||
e21c2168ea | |||
589ab3664e | |||
48b4f9b160 | |||
139e416c3b | |||
ba4ed3b365 | |||
06a8022265 | |||
3b297e07dc | |||
68fa8e523e | |||
768bf06a9d | |||
6a8d66758a | |||
078e6e6f23 | |||
3f80bfb641 | |||
a34389c3a9 | |||
692d3c143f | |||
bc86a45925 | |||
2a412b794a | |||
bf673263d8 | |||
ce498d3019 | |||
e398f089af | |||
e8ba24e48b | |||
e0f40be188 | |||
42848764cf | |||
46ac0c339c | |||
a0fe68f3ab | |||
c952c3d031 | |||
c05cdeda72 | |||
ae7b285eb0 | |||
6b3c562af2 | |||
e3ae878cae | |||
dd43c94e6e | |||
0e8fe1fcfb | |||
293b7f564e | |||
634ffb4c57 | |||
9468a2e9f8 | |||
921ecd99d6 | |||
d06f92051d | |||
97d68f89f1 | |||
115863f1ee | |||
bc27a4d25a | |||
5a0b2f319b | |||
50f003a2bd | |||
bc0b50f5bf | |||
dd20b25900 | |||
d0469467ac | |||
61427ec505 | |||
6cd1d78572 | |||
0ad5049785 | |||
b5c1960260 | |||
e6fbe7c4a4 | |||
537536d443 | |||
f702d14749 | |||
74bb544f3c | |||
dae47e3779 | |||
dc91d0e00c | |||
6187eb3e4e | |||
0fa6d337f2 | |||
a10e1cad11 | |||
7c252deede | |||
224c5c4fe2 | |||
e945b5fe94 | |||
23e534c5c9 | |||
dcddf74830 | |||
9baf69394e | |||
2e58bbb5e8 | |||
bb6abc5e9a | |||
e4f9d491c3 | |||
1ba7ee37db | |||
34cfbae3a9 | |||
9fabda545f | |||
7cd50aed7b | |||
cdc082071d | |||
d1479672c8 | |||
ffb112cfb2 | |||
f5af33c098 | |||
0f464f5814 | |||
776c2095e6 | |||
82a2833161 | |||
b14d7bdf07 | |||
ffa22eea25 | |||
8220e6409d | |||
927e1c02fa | |||
a13a17b106 | |||
18d6d73f94 | |||
54d101acbe | |||
76f720cb71 | |||
033e485ce1 | |||
82ee830de1 | |||
55cd1cccee | |||
5f13ba3d1b | |||
298aa0aa8d | |||
5d49be6f7e | |||
ab81bf5875 | |||
5d8765683a | |||
6c22bc0145 | |||
5c1908668f | |||
94da7fb255 | |||
46d2d35c1a | |||
cba41b29bc | |||
7a8f47b995 | |||
40062c5091 | |||
6081ef6b02 | |||
4cffe5a662 | |||
813aec2b42 | |||
f2452bbc70 | |||
28fb685bfc | |||
0661ca00ff | |||
0b04619003 | |||
85d7b6aa57 | |||
bba961269c | |||
d0f7d2c5e9 | |||
eeeb3eb184 | |||
f00f8d26f6 | |||
74817beec6 | |||
7b6809245c | |||
5b40a8fd41 | |||
193f459be1 | |||
c4c19a5b47 | |||
7d103c70e7 | |||
2ffe90948e | |||
8e61aaacde | |||
29c8fcbde2 | |||
8dd21f46aa | |||
e688dde2aa | |||
987e1e1bdb | |||
510257c436 | |||
bb1572f32a | |||
45276034b1 | |||
0d4a144524 | |||
a0e5102ca7 | |||
69c0f5ace9 | |||
d0962c2387 | |||
4670894cfd | |||
a2f6c70a03 | |||
ef469868d8 | |||
c9ba872529 | |||
1e15042be2 | |||
7647978da5 | |||
f82f3052f2 | |||
10b299ff65 | |||
e4ff0418fd | |||
a2b25e31ca | |||
c4772db808 | |||
38c2d9131b | |||
1566323fca | |||
bf0a923eb2 | |||
e372480249 |
3
.github/FUNDING.yml
vendored
@ -1 +1,2 @@
|
||||
custom: ['https://nicoverbruggen.be/sponsor', 'https://paypal.me/nicoverbruggen']
|
||||
github: nicoverbruggen
|
||||
custom: ['https://nicoverbruggen.be/sponsor']
|
33
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Something going wrong? File a bug report!
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: nicoverbruggen
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Required information**
|
||||
- Did you consult the FAQ in the README? [yes/no]
|
||||
- Did you try "Fix My Valet"? [yes/no]
|
||||
- OS: [e.g. macOS Monterey]
|
||||
- PHP Monitor version [e.g. v5.0.1]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an enhancement.
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: nicoverbruggen
|
||||
|
||||
---
|
||||
|
||||
_Enhancement requests that are not immediately approved will be moved to a discussion instead._
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
60
DEVELOPER.md
Normal file
@ -0,0 +1,60 @@
|
||||
# DEVELOPER README
|
||||
|
||||
## 🔧 Build instructions
|
||||
|
||||
<img src="./docs/build.png" width="404px" alt="build button in Xcode"/>
|
||||
|
||||
If you'd like to build PHP Monitor yourself, you need:
|
||||
|
||||
* Xcode (usually the latest version)
|
||||
* The contents of this repository
|
||||
|
||||
Once you have downloaded this repository, open `PHP Monitor.xcodeproj`, and you should be able to immediately build the app for your system by pressing Cmd-R. This will create a debug build. (If Xcode complains about code signing, you can turn it off.)
|
||||
|
||||
If you'd like to create a production build, choose "Any Mac" as the target and select Product > Archive.
|
||||
|
||||
## 🚀 Release procedure
|
||||
|
||||
1. Merge into `main`
|
||||
2. Create tag
|
||||
3. Add changes to changelog + update security document
|
||||
4. Archive
|
||||
5. Notarize and prepare for own distribution
|
||||
6. After notarization, export .app
|
||||
7. Create zipped version
|
||||
8. Calculate SHA256: `openssl dgst -sha256 phpmon.zip`
|
||||
9. Upload to GitHub and add to tagged release
|
||||
10. Update Cask with new version + hash
|
||||
11. Check new version can be installed via Cask
|
||||
|
||||
## 🐛 Symbolication of crashes
|
||||
|
||||
If you have an archived build of the app and exported the DSYM, it is possible to symbolicate .ips crash logs.
|
||||
|
||||
For example, given the following crash (from an .ips file):
|
||||
|
||||
```
|
||||
Thread 2 Crashed:: Dispatch queue: com.apple.root.user-initiated-qos
|
||||
0 libswiftDispatch.dylib 0x7ff82aa3ab8c static OS_dispatch_source.makeProcessSource(identifier:eventMask:queue:) + 28
|
||||
1 PHP Monitor 0x1096907d8 0x10965e000 + 206808
|
||||
| |
|
||||
address load address
|
||||
2 PHP Monitor 0x1096903ac 0x10965e000 + 205740
|
||||
3 PHP Monitor 0x10968f88b 0x10965e000 + 202891
|
||||
```
|
||||
|
||||
You must use the correct order for the the address and load address in the command below:
|
||||
|
||||
```
|
||||
$ atos -arch x86_64 -o '/path/to/PHP Monitor.app.dSYM/Contents/Resources/DWARF/PHP Monitor' -l 0x10965e000 0x1096907d8
|
||||
| | | |
|
||||
architecture path to DSYM load address address
|
||||
```
|
||||
|
||||
This will return the relevant information, for example:
|
||||
|
||||
```
|
||||
FSWatcher.startMonitoring(_:behaviour:) (in PHP Monitor) (PhpConfigWatcher.swift:95)
|
||||
```
|
||||
|
||||
For more information, see [Apple's documentation](https://developer.apple.com/documentation/xcode/adding-identifiable-symbol-names-to-a-crash-report).
|
2
LICENSE
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Nico Verbruggen
|
||||
Copyright (c) 2019-2022 Nico Verbruggen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,84 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1320"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "C415D3D52770F341005EF286"
|
||||
BuildableName = "phpmon-cli"
|
||||
BlueprintName = "phpmon-cli"
|
||||
ReferencedContainer = "container:PHP Monitor.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "C415D3D52770F341005EF286"
|
||||
BuildableName = "phpmon-cli"
|
||||
BlueprintName = "phpmon-cli"
|
||||
ReferencedContainer = "container:PHP Monitor.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "help"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "C415D3D52770F341005EF286"
|
||||
BuildableName = "phpmon-cli"
|
||||
BlueprintName = "phpmon-cli"
|
||||
ReferencedContainer = "container:PHP Monitor.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@ -61,6 +61,13 @@
|
||||
ReferencedContainer = "container:PHP Monitor.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<EnvironmentVariables>
|
||||
<EnvironmentVariable
|
||||
key = "PHPMON_MARKETING_MODE"
|
||||
value = "YES"
|
||||
isEnabled = "NO">
|
||||
</EnvironmentVariable>
|
||||
</EnvironmentVariables>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
175
README.md
@ -1,15 +1,12 @@
|
||||
# PHP Monitor
|
||||
> 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 leaving [a one-time donation](https://nicoverbruggen.be/sponsor) to support the project.
|
||||
> You can also send me [feedback](https://twitter.com/nicoverbruggen) if the app came in handy.<br>**Thank you!** ⭐️
|
||||
<p align="center"><img src="./docs/logo.png" alt="PHP Monitor Logo" width="500px" /></p>
|
||||
|
||||
<img src="./phpmon/Assets.xcassets/AppIcon.appiconset/icon_128x128@2x.png" alt="phpmon icon" width="128px" />
|
||||
**PHP Monitor** (or *phpmon*) is a lightweight macOS utility app that runs on your Mac and displays the active PHP version in your status bar. It's tightly integrated with [Laravel Valet](https://github.com/laravel/valet), so <u>you need to have it set up before you can use this app</u> (consult the FAQ below with info about how to set up your environment).
|
||||
|
||||
**PHP Monitor** (or phpmon) is a lightweight macOS utility app that runs on your Mac and displays the active PHP version in your status bar. It's tightly integrated with [Laravel Valet](https://github.com/laravel/valet), so you need to have it set up before you can use this.
|
||||
<img src="./docs/screenshot.jpg" width="1085px" alt="phpmon screenshot (menu bar app)"/>
|
||||
|
||||
<img src="./docs/screenshot41.jpg" width="800px" alt="phpmon screenshot (menu bar app)"/>
|
||||
|
||||
<small><i>Screenshot: A menu showing all of the functionality of PHP Monitor.</i></small>
|
||||
<small><i>Screenshot: Showing the key functionality of PHP Monitor.</i></small>
|
||||
|
||||
It's super convenient to switch between different versions of PHP. You'll even get notifications (only if you choose to opt-in, of course)!
|
||||
|
||||
@ -17,20 +14,23 @@ It's super convenient to switch between different versions of PHP. You'll even g
|
||||
|
||||
PHP Monitor also gives you quick access to various useful functionality (like accessing configuration files, restarting services, and more).
|
||||
|
||||
You can also add new domains as links, isolate sites, manage various services, and perform First Aid to fix all kinds of common PHP link issues.
|
||||
|
||||
## 🖥 System requirements
|
||||
|
||||
PHP Monitor is a universal application that runs on Apple Silicon **and** Intel-based Macs.
|
||||
PHP Monitor is a universal application that runs natively on Apple Silicon **and** Intel-based Macs.
|
||||
|
||||
* Your user account can administer your computer (required for some functionality, e.g. certificate generation)
|
||||
* macOS 11 Big Sur or higher (supports macOS 12 Monterey)
|
||||
* Homebrew is installed in `/usr/local/homebrew` or `/opt/homebrew`
|
||||
* The brew formula `php` has to be installed (which version is detected)
|
||||
* Laravel Valet 2.16.2 or higher (older versions might be compatible but are not supported)
|
||||
* Homebrew `php` formula is installed
|
||||
* Laravel Valet 2.16 or newer (supports Valet 3)
|
||||
|
||||
_You may need to update your Valet installation to keep everything working if a major version update of PHP has been released. You can do this by running `composer global update && valet install`._
|
||||
_You may need to update your Valet installation to keep everything working if a major version update of PHP has been released. You can do this by running `composer global update && valet install`. Some features are not supported when running Valet 2._
|
||||
|
||||
## 🚀 How to install
|
||||
|
||||
You can install via Homebrew (recommended), or may download the latest release on GitHub.
|
||||
Again, make sure you have **Laravel Valet** installed first. Once that's done, you can install via Homebrew (recommended), or may download the latest release on GitHub.
|
||||
|
||||
To install via Homebrew, run:
|
||||
|
||||
@ -41,7 +41,17 @@ To upgrade your existing installation, run:
|
||||
|
||||
brew upgrade phpmon
|
||||
|
||||
_The app is signed and notarized, meaning all you have to do is approve its first launch._
|
||||
(You may need to run `brew update` or `brew update-reset` first in order to update the cask file if you ran a Homebrew operation recently.)
|
||||
|
||||
## ⚡️ Launchers (Alfred, Raycast)
|
||||
|
||||
If you would like to integrate with your launcher of choice, you can also download an [Alfred workflow](https://github.com/nicoverbruggen/phpmon/raw/main/integrations/phpmon.alfredworkflow) or [Raycast extension](https://www.raycast.com/nicoverbruggen/php-monitor) that works with PHP Monitor.
|
||||
|
||||
The app must be running in the background for these to work, and the _Allow third-party integrations_ checkbox must be enabled in Preferences (it is by default).
|
||||
|
||||
## 🔑 Is the app signed & notarized?
|
||||
|
||||
Yes, the app is signed and notarized, meaning all you have to do is approve its first launch (or whenever it updates).
|
||||
|
||||
## 👨💻 Why build this?
|
||||
|
||||
@ -51,10 +61,12 @@ Initially, I had an Alfred workflow for this — but it has now been replaced wi
|
||||
|
||||
## 🤬 The app won't start?!
|
||||
|
||||
PHP Monitor performs some integrity checks to ensure a good experience when using the app. You'll get a message telling you that PHP Monitor won't work correctly in a variety of scenarios.
|
||||
PHP Monitor performs some integrity checks to ensure a good experience when using the app. You'll get a message telling you that PHP Monitor won't work correctly in a variety of scenarios.
|
||||
|
||||
**Follow instructions as specified in the alert in order to resolve any issues.**
|
||||
|
||||
(If the app crashes at launch without showing you any of these messages, you might have a non-standard Homebrew and Valet setup. Those are not supported.)
|
||||
|
||||
## 🙋♂️ FAQ & Troubleshooting
|
||||
|
||||
> If you are having issues, the first thing you should be doing is installing the latest version of PHP Monitor _and_ Laravel Valet. This can resolve a variety of issues. To upgrade Valet, run `composer global update`. Don't forget to run `valet install` after upgrading.
|
||||
@ -65,7 +77,7 @@ If you're still having issues, here's a few common questions & answers, as well
|
||||
<summary><strong>Which versions of PHP are supported?</strong></summary>
|
||||
|
||||
<ul>
|
||||
<li>PHP 5.6</li>
|
||||
<li>PHP 5.6 (only if you are running Valet 2)</li>
|
||||
<li>PHP 7.0</li>
|
||||
<li>PHP 7.1</li>
|
||||
<li>PHP 7.2</li>
|
||||
@ -76,7 +88,7 @@ If you're still having issues, here's a few common questions & answers, as well
|
||||
<li>PHP 8.2 (experimental)</li>
|
||||
</ul>
|
||||
|
||||
For more details, consult the [constants file](https://github.com/nicoverbruggen/phpmon/blob/main/phpmon/Constants.swift#L16) file to see which versions are supported.
|
||||
For more details, consult the [constants file](https://github.com/nicoverbruggen/phpmon/blob/main/phpmon/Common/Core/Constants.swift#L16) file to see which versions are supported.
|
||||
|
||||
</details>
|
||||
|
||||
@ -137,6 +149,29 @@ This should install `dnsmasq` and set up Valet. Great, almost there!
|
||||
Finally, run PHP Monitor. Since the app is notarized and signed with a developer ID, it should work.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>I have PHP Monitor installed, and it works. I want to upgrade my PHP installations to the latest version, what's the best way to do this?</strong></summary>
|
||||
|
||||
It's easy to make a mistake here, and end up with an unlinked version of PHP or have versions missing from PHP Monitor.
|
||||
|
||||
Here's what I usually do:
|
||||
|
||||
* Open PHP Monitor and select **First Aid & Services** > **Restore Homebrew Permissions**.
|
||||
* Close PHP Monitor after the pop-up tells you the permissions were restored.
|
||||
* Run `brew update-reset`
|
||||
* Run `brew upgrade`
|
||||
|
||||
If after this, any PHP versions are missing in PHP Monitor, please run the following for the versions that are missing:
|
||||
|
||||
* Run `brew uninstall php@x.x` (where `x.x` is the version)
|
||||
* Run `brew cleanup` (if you get any permission issues you may need to manually clean up the folder)
|
||||
* Run `brew install php@x.x` (where `x.x` is the version)
|
||||
|
||||
You may still need to run `brew link php` after upgrading, too.
|
||||
|
||||
That's it. Now start up PHP Monitor again and you should be golden!
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>PHP Monitor tells me `php` is not installed...</strong></summary>
|
||||
|
||||
@ -189,6 +224,12 @@ You should see an error or a warning here in the output.
|
||||
Usually this is a duplicate extension declaration causing issues, or an extension that couldn't be loaded. You'll have to solve that issue yourself (usually by removing the offending extension or reinstalling).
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>The option to isolate a site is disabled! What's going on?</strong></summary>
|
||||
|
||||
Make sure you have at least **Valet 3.0** installed, since support for isolation was added in this version of Valet. (Please note that this version of Valet drops support for PHP 5.6.)
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>One of the limits (memory limit, max POST size, max upload size) shows an exclamation mark!</strong></summary>
|
||||
@ -223,8 +264,15 @@ Since v3.4 all of the loaded .ini files are sourced to determine which extension
|
||||
<details>
|
||||
<summary><strong>I've got two Homebrew installations on my Apple Silicon Mac, can I choose which installation to use with PHP Monitor?</strong></summary>
|
||||
|
||||
Not at this time, no. PHP Monitor will prefer the `/opt/homebrew` installation over the classic installation directory.
|
||||
If you are using PHP Monitor on an Intel machine or on an Apple Silicon machine with Rosetta enabled, PHP Monitor expects the main Homebrew binary in `/usr/local/bin/brew`.
|
||||
|
||||
If you are using PHP Monitor on Apple Silicon without Rosetta, PHP Monitor expects the main Homebrew binary in `/opt/homebrew/bin/brew`.
|
||||
|
||||
If there's an issue here, you'll get an alert at launch.
|
||||
|
||||
Make sure that the version of Homebrew that you are running normally is the same as the one that PHP Monitor expects. If you are on M1 hardware for example, but still using Rosetta for Homebrew, you'll need to run PHP Monitor under Rosetta as well.
|
||||
|
||||
PHP Monitor is a universal app and supports both architectures, so [find out here](https://support.apple.com/en-us/HT211861) how to enable Rosetta with PHP Monitor.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
@ -258,12 +306,65 @@ You can add your own apps by creating and editing a `~/.phpmon.conf.json` file,
|
||||
You can put as many apps as you'd like in the `scan_apps` array, and PHP Monitor will check for the existence of these apps. You do not need to set the full path, just the name of the app should work. Not all apps support opening a folder, though, so your success might vary.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>How can the app integrate with third party tools, like Alfred or Raycast?</strong></summary>
|
||||
|
||||
PHP Monitor supports third party app integrations by default, and this feature is enabled in Preferences unless you disable it.
|
||||
|
||||
You can grab the official [Alfred workflow](https://github.com/nicoverbruggen/phpmon/raw/main/integrations/phpmon.alfredworkflow) or [Raycast extension](https://www.raycast.com/nicoverbruggen/php-monitor).
|
||||
|
||||
If you'd like to integrate something yourself, all you need to to is use the `phpmon://` protocol and ensure that third party app integrations are enabled in Preferences (in PHP Monitor).
|
||||
|
||||
Using app callbacks, macOS and PHP Monitor allow for the following to be called:
|
||||
|
||||
* phpmon://list
|
||||
* phpmon://services/stop
|
||||
* phpmon://services/restart/all
|
||||
* phpmon://services/restart/nginx
|
||||
* phpmon://services/restart/php
|
||||
* phpmon://services/restart/dnsmasq
|
||||
* phpmon://locate/config
|
||||
* phpmon://locate/composer
|
||||
* phpmon://locate/valet
|
||||
* phpmon://phpinfo
|
||||
* phpmon://switch/php/{version}
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>How does the app know what PHP version is required for my app?</strong></summary>
|
||||
|
||||
The `composer.json` file in the root of the folder (if it exists) is scanned and interpreted.
|
||||
|
||||
If the version is set in `platform`, it takes precendence.
|
||||
If the version is not set in `platform` but it is in `require` (most common) then that version is used.
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>What do the checkmarks next to the PHP version mean in the site list?</strong></summary>
|
||||
|
||||
You'll see a checkmark next to the version number if the currently enabled PHP version is compatible with the version required to run the site.
|
||||
|
||||
This is determined by evaluating the PHP requirement constraint (e.g. `^8.0`, `~8.0` or a specific version: `8.0`).
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>Why can't I see the driver type any more? It says "Project Type" now.</strong></summary>
|
||||
|
||||
PHP Monitor currently checks your `composer.json` file to try to figure out what project you are running.
|
||||
|
||||
This approach is a lot faster than asking for a driver when you have many sites linked, but is slightly less reliable since the framework or type of project inferred via `composer.json` might not be 100% accurate.
|
||||
|
||||
You can always still ask Valet using the command line, should it be necessary. In my experience fetching the drivers slowed down the app unnecessarily.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><strong>After running PHP Monitor, Homebrew sometimes has issues with `brew upgrade` or `brew cleanup`!</strong></summary>
|
||||
|
||||
<strike>This is a security feature of Homebrew. When you start a service as an administrator, the root user becomes the owner of relevant binaries. You will need to manually clean up those folders yourself using `rm -rf` (or by manually removing those folders via Finder).</strike>
|
||||
You can now use **First Aid & Services > Restore Homebrew Permissions** to (temporarily) resolve this issue and allow for a clean and painless `brew upgrade` or `brew cleanup` process.
|
||||
|
||||
**Update**: If you are using the Valet switcher (currently not available in the latest stable build) you will not encounter this issue. For more information on this, see [this issue](https://github.com/nicoverbruggen/phpmon/issues/17) and also [this issue about switching to Valet's switcher](https://github.com/nicoverbruggen/phpmon/issues/34).
|
||||
If you would like to know more, consult [this issue](https://github.com/nicoverbruggen/phpmon/issues/85) for more information about why this is needed.
|
||||
|
||||
</details>
|
||||
|
||||
@ -272,6 +373,10 @@ You can put as many apps as you'd like in the `scan_apps` array, and PHP Monitor
|
||||
|
||||
Please get in touch and open an issue. PHP Monitor shouldn't crash... (unless you are actually removing PHP *while* the app is running, that’s considered normal behaviour!)
|
||||
|
||||
If you would like to report a crash, please include the associated **log files** so I can find out what exactly went wrong.
|
||||
|
||||
To find the logs, take a look in `~/Library/Logs/DiagnosticReports` (in Finder) and see if there's any (log) files that start with "PHP Monitor".
|
||||
|
||||
</details>
|
||||
|
||||
## 📝 Having another issue?
|
||||
@ -288,15 +393,14 @@ Donations really help with the Apple Developer Program cost, and keep me motivat
|
||||
|
||||
## 😎 Acknowledgements
|
||||
|
||||
While I did make this application during my own free time, I have been lucky enough to do various experiments during work hours at [DIVE](https://dive.be). I'd also like to shout out the following folks:
|
||||
While I did make this application during my own free time, PHP Monitor started out from various learning experiments during work hours at my employer, DIVE. I'd also like to shout out the following folks:
|
||||
|
||||
* My colleagues at [DIVE](https://dive.be)
|
||||
* The [Homebrew](https://brew.sh/) team who maintain
|
||||
* The [developers & maintainers of Valet](https://github.com/laravel/valet/graphs/contributors)
|
||||
* The [Homebrew](https://brew.sh/) team & [Valet maintainers](https://github.com/laravel/valet/graphs/contributors)
|
||||
* Various folks who [reached](https://twitter.com/stauffermatt) [out](https://twitter.com/marcelpociot) when PHP Monitor was still very much a small app with a handful of stars or so
|
||||
* My [GitHub Sponsors](https://github.com/sponsors/nicoverbruggen) and those who have donated
|
||||
* Everyone who has left feedback and reported bugs (appreciate it!)
|
||||
* Everyone in the Laravel community who shared the app (thanks!)
|
||||
* Various folks who [reached](https://twitter.com/stauffermatt) [out](https://twitter.com/marcelpociot)
|
||||
* Everyone who left feedback via issues
|
||||
* Everyone who donated to keep the project up and running
|
||||
|
||||
Thank you very much for your contributions, kind words and support.
|
||||
|
||||
@ -312,7 +416,9 @@ In order to save power, this only happens once every 60 seconds.
|
||||
|
||||
This utility will detect which PHP versions you have installed via Homebrew, and then allows you to switch between them.
|
||||
|
||||
The switcher will disable all PHP-FPM services not belonging to the version you wish to use, and link the desired version of PHP. Then, it'll restart your desired PHP version's FPM process. This all happens in parallel, so this should be much faster than Valet’s switcher.
|
||||
The switcher will disable all PHP-FPM services not belonging to the version you wish to use, and link the desired version of PHP. Then, it'll restart your desired PHP version's FPM process. This all happens in parallel, so this should be a bit faster than Valet’s switcher.
|
||||
|
||||
If you're using Valet 3, versions of PHP-FPM required to keep isolated sites up and running will also be started or stopped as needed.
|
||||
|
||||
### Config change detection
|
||||
|
||||
@ -326,7 +432,7 @@ If an extension or other process writes to a single file a bunch of times in a s
|
||||
|
||||
1. **Location of your sites**: PHP Monitor uses the Valet configuration file to determine which folders to look into. Each folder is scanned and then PHP Monitor will validate if a composer.json file exists to determine the desired PHP version.
|
||||
1. **Sites secured or not secured**: Whether the directory has been secured is determined by checking if a matching certificate exists under Valet's `Certificates` directory for that site name.
|
||||
1. **Site drivers**: PHP Monitor runs `valet which` to determine which driver is currently in use for each individual site. This command is executed once for each site whenever the site list is refreshed.
|
||||
1. **Project type**: PHP Monitor checks your `composer.json` file for "notable dependencies". If you have `laravel/framework` in your `require`, there's a good chance the project type is `Laravel`, after all.
|
||||
|
||||
*Note*: If you have linked a folder in Documents, Desktop or Downloads you might need to grant PHP Monitor access to those directories for PHP Monitor to work correctly.
|
||||
|
||||
@ -334,15 +440,8 @@ If an extension or other process writes to a single file a bunch of times in a s
|
||||
|
||||
If you want to know more about how this works, I recommend you check out the source code.
|
||||
|
||||
## 🔧 Build instructions
|
||||
I have done my best to annotate as much as humanly possible, and have avoided using an overly complicated architecture to keep the code as easy to maintain as possible. The code isn't perfect by a long shot (lots of cleanup can still happen!) but the application works well.
|
||||
|
||||
<img src="./docs/build.png" width="404px" alt="build button in Xcode"/>
|
||||
I also have a few tests for key parts of the application that I found needed to be tested. In the future, I would like to add even more tests for some of the UI stuff, but for now the tests are more unit tests than feature tests.
|
||||
|
||||
If you'd like to build PHP Monitor yourself, you need:
|
||||
|
||||
* Xcode (usually the latest version)
|
||||
* The contents of this repository
|
||||
|
||||
Once you have downloaded this repository, open `PHP Monitor.xcodeproj`, and you should be able to immediately build the app for your system by pressing Cmd-R. This will create a debug build. (If Xcode complains about code signing, you can turn it off.)
|
||||
|
||||
If you'd like to create a production build, choose "Any Mac" as the target and select Product > Archive.
|
||||
For more detailed information for developers, please see [the documentation file for developers](./DEVELOPER.md).
|
||||
|
13
RELEASE.md
@ -1,13 +0,0 @@
|
||||
# Release Procedure
|
||||
|
||||
1. Merge into `main`
|
||||
2. Create tag
|
||||
3. Add changes to changelog + update security document
|
||||
4. Archive
|
||||
5. Notarize and prepare for own distribution
|
||||
6. After notarization, export .app
|
||||
7. Create zipped version
|
||||
8. Calculate SHA256: `openssl dgst -sha256 phpmon.zip`
|
||||
9. Upload to GitHub and add to tagged release
|
||||
10. Update Cask with new version + hash
|
||||
11. Check new version can be installed via Cask
|
@ -4,15 +4,17 @@
|
||||
|
||||
Generally speaking, only the latest version of **PHP Monitor** is supported, except during transition periods (for example, when particular system requirements go up):
|
||||
|
||||
| Version | Apple silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Minimum Required Valet Version |
|
||||
| Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Recommended Valet Version |
|
||||
| ------- | ------------- | ------------------ | ----- | ----- | ----- | ----
|
||||
| 5.x | ✅ Universal binary | ✅ Yes | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 | TBD |
|
||||
| 5.x | ✅ Universal binary | ✅ Yes | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 (*) | 3.0 (2.16.2 minimum) |
|
||||
|
||||
_(*) Support for PHP 5.6 is only included if you are using Valet 2.x, since support for PHP 5.6 was dropped in Valet 3.0._
|
||||
|
||||
## Legacy versions
|
||||
|
||||
These versions of PHP Monitor are no longer supported, but if you’re using an older computer with an older version of Homebrew, Valet or macOS, you might want to use one of these versions.
|
||||
|
||||
| Version | Apple silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Minimum Required Valet Version |
|
||||
| Version | Apple Silicon | Supported | Supported macOS | Deployment Target | Detected PHP Versions | Minimum Required Valet Version |
|
||||
| ------- | ------------- | ------------------ | ----- | ----- | ----- | ----
|
||||
| 4.1 | ✅ Universal binary | ❌ | Big Sur (11.0) and Monterey (12.0) | macOS 11+ | PHP 5.6—PHP 8.2 | 2.16.2 |
|
||||
| 4.0 | ✅ Universal binary | ❌ | Big Sur (11.0) and Monterey (12.0) | macOS 10.14+ | PHP 5.6—PHP 8.2 | 2.13 |
|
||||
|
BIN
assets/affinity/icon.afdesign
Normal file
BIN
assets/affinity/icons.afdesign
Normal file
BIN
docs/logo.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
docs/screenshot.jpg
Normal file
After Width: | Height: | Size: 345 KiB |
Before Width: | Height: | Size: 396 KiB |
BIN
integrations/phpmon.alfredworkflow
Normal file
@ -1,26 +0,0 @@
|
||||
//
|
||||
// AllowedArguments.swift
|
||||
// phpmon-cli
|
||||
//
|
||||
// Created by Nico Verbruggen on 20/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum AllowedArguments: String, CaseIterable {
|
||||
case use = "use"
|
||||
case performSwitch = "switch"
|
||||
case fix = "fix"
|
||||
case help = "help"
|
||||
|
||||
static func has(_ string: String) -> Bool {
|
||||
return Self.allCases.contains { arg in
|
||||
return arg.rawValue == string
|
||||
}
|
||||
}
|
||||
|
||||
static var rawValues: [String] {
|
||||
return Self.allCases.map { $0.rawValue }
|
||||
}
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
//
|
||||
// main.swift
|
||||
// phpmon-cli
|
||||
//
|
||||
// Created by Nico Verbruggen on 20/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
let toolver = "0.1 (early access)"
|
||||
|
||||
let log = Log.shared
|
||||
log.verbosity = .info
|
||||
|
||||
if CommandLine.arguments.contains("-q") || CommandLine.arguments.contains("--quiet") {
|
||||
Log.shared.verbosity = .warning
|
||||
}
|
||||
if CommandLine.arguments.contains("-p") || CommandLine.arguments.contains("--performance") {
|
||||
Log.shared.verbosity = .performance
|
||||
}
|
||||
|
||||
var argument = "help"
|
||||
if CommandLine.arguments.count > 1 {
|
||||
argument = CommandLine.arguments[1]
|
||||
}
|
||||
|
||||
if !AllowedArguments.has(argument) {
|
||||
Log.err("The supported arguments are: \(AllowedArguments.rawValues)")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let action = AllowedArguments.init(rawValue: argument)
|
||||
|
||||
switch action {
|
||||
case .use, .performSwitch:
|
||||
if !Shell.fileExists("\(Paths.binPath)/php") {
|
||||
Log.err("PHP is currently not linked. Attempting quick fix...")
|
||||
_ = Shell.user.executeSynchronously("brew link php", requiresPath: true)
|
||||
}
|
||||
|
||||
let phpenv = PhpEnv.shared
|
||||
PhpEnv.detectPhpVersions()
|
||||
|
||||
if CommandLine.arguments.count < 3 {
|
||||
Log.err("You must enter at least two additional arguments when using this command.")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let version = CommandLine.arguments[2].replacingOccurrences(of: "php@", with: "")
|
||||
if phpenv.availablePhpVersions.contains(version) {
|
||||
Log.info("Switching to PHP \(version)...")
|
||||
Actions.switchToPhpVersion(
|
||||
version: version,
|
||||
availableVersions: phpenv.availablePhpVersions,
|
||||
completed: {
|
||||
Log.info("The switch has been completed.")
|
||||
exit(0)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
Log.err("A PHP installation with version \(version) is not installed.")
|
||||
Log.err("The installed versions are: \(phpenv.availablePhpVersions.joined(separator: ", ")).")
|
||||
Log.err("If this version is available, you may be able to install it by using `brew install php@\(version)`.")
|
||||
exit(1)
|
||||
}
|
||||
case .fix:
|
||||
Log.info("Fixing your PHP installation...")
|
||||
Actions.fixMyPhp()
|
||||
Log.info("All operations completed. You can check which version of PHP is linked by using `php -v`.")
|
||||
exit(0)
|
||||
case .help:
|
||||
print("""
|
||||
===============================================================
|
||||
PHP MONITOR CLI \(toolver)
|
||||
by Nico Verbruggen
|
||||
===============================================================
|
||||
|
||||
Gives access to the quick version switcher from PHP Monitor,
|
||||
but without the GUI and 100% of the speed!
|
||||
|
||||
SUPPORTED COMMANDS
|
||||
|
||||
* use {version}: Switch to a specific version of PHP.
|
||||
(e.g. `phpmon-cli use 8.0`)
|
||||
* switch {version}: Alias for the `use` command.
|
||||
* fix Attempts to unlink all PHP versions,
|
||||
and link the latest version of PHP.
|
||||
* help: Show this help.
|
||||
|
||||
SUPPORTED FLAGS
|
||||
|
||||
* `-q / --quiet`: Silences all logs except for warnings and exceptions.
|
||||
* `-p / --perf`: Enables performance mode.
|
||||
|
||||
""")
|
||||
exit(0)
|
||||
case .none:
|
||||
Log.err("Action not recognized!")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
RunLoop.main.run()
|
@ -1,67 +0,0 @@
|
||||
//
|
||||
// Paths.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
The `Paths` class is used to locate various binaries on the system,
|
||||
and provides a full
|
||||
*/
|
||||
public class Paths {
|
||||
|
||||
public static let shared = Paths()
|
||||
|
||||
private var baseDir : Paths.HomebrewDir
|
||||
|
||||
init() {
|
||||
baseDir = Shell.fileExists("\(HomebrewDir.opt.rawValue)/bin/brew") ? .opt : .usr
|
||||
}
|
||||
|
||||
// - MARK: Binaries
|
||||
|
||||
public static var valet: String {
|
||||
return "\(binPath)/valet"
|
||||
}
|
||||
|
||||
public static var brew: String {
|
||||
return "\(binPath)/brew"
|
||||
}
|
||||
|
||||
public static var php: String {
|
||||
return "\(binPath)/php"
|
||||
}
|
||||
|
||||
public static var phpConfig: String {
|
||||
return "\(binPath)/php-config"
|
||||
}
|
||||
|
||||
// - MARK: Paths
|
||||
|
||||
public static var whoami: String {
|
||||
return String(Shell.pipe("whoami").split(separator: "\n")[0])
|
||||
}
|
||||
|
||||
public static var binPath: String {
|
||||
return "\(shared.baseDir.rawValue)/bin"
|
||||
}
|
||||
|
||||
public static var optPath: String {
|
||||
return "\(shared.baseDir.rawValue)/opt"
|
||||
}
|
||||
|
||||
public static var etcPath: String {
|
||||
return "\(shared.baseDir.rawValue)/etc"
|
||||
}
|
||||
|
||||
// MARK: - Enum
|
||||
|
||||
public enum HomebrewDir: String {
|
||||
case opt = "/opt/homebrew"
|
||||
case usr = "/usr/local"
|
||||
}
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
//
|
||||
// HomebrewService.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 11/01/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct HomebrewService: Decodable, Equatable {
|
||||
let name: String
|
||||
let service_name: String
|
||||
let running: Bool
|
||||
let loaded: Bool
|
||||
let pid: Int?
|
||||
let user: String?
|
||||
let status: String?
|
||||
let log_path: String?
|
||||
let error_log_path: String?
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
//
|
||||
// InternalSwitcher.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 24/12/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class InternalSwitcher: PhpSwitcher {
|
||||
|
||||
/**
|
||||
Switching to a new PHP version involves:
|
||||
- unlinking the current version
|
||||
- stopping the active services
|
||||
- linking the new desired version
|
||||
|
||||
Please note that depending on which version is installed,
|
||||
the version that is switched to may or may not be identical to `php`
|
||||
(without @version).
|
||||
*/
|
||||
func performSwitch(to version: String, completion: @escaping () -> Void)
|
||||
{
|
||||
Log.info("Switching to \(version), unlinking all versions...")
|
||||
|
||||
let group = DispatchGroup()
|
||||
|
||||
PhpEnv.shared.availablePhpVersions.forEach { (available) in
|
||||
group.enter()
|
||||
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
let formula = (available == PhpEnv.brewPhpVersion)
|
||||
? "php" : "php@\(available)"
|
||||
|
||||
brew("unlink \(formula)")
|
||||
brew("services stop \(formula)", sudo: true)
|
||||
|
||||
Log.perf("Unlinked and stopped services for \(formula)")
|
||||
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: .global(qos: .userInitiated)) {
|
||||
Log.info("All versions have been unlinked!")
|
||||
Log.info("Linking the new version!")
|
||||
|
||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||
brew("link \(formula) --overwrite --force")
|
||||
brew("services start \(formula)", sudo: true)
|
||||
|
||||
Log.info("The new version has been linked!")
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
32
phpmon-tests/Parsers/NginxConfigParserTest.swift
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// NginxConfigParserTest.swift
|
||||
// phpmon-tests
|
||||
//
|
||||
// Created by Nico Verbruggen on 29/11/2021.
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
|
||||
class NginxConfigParserTest: XCTestCase {
|
||||
|
||||
static var regularUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nicoverbruggen", withExtension: "test")!
|
||||
}
|
||||
|
||||
static var isolatedUrl: URL {
|
||||
return Bundle(for: Self.self).url(forResource: "nicoverbruggen_isolated", withExtension: "test")!
|
||||
}
|
||||
|
||||
func testCanDetermineIsolation() throws {
|
||||
XCTAssertNil(
|
||||
NginxConfigParser(filePath: NginxConfigParserTest.regularUrl.path).isolatedVersion
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
"8.1",
|
||||
NginxConfigParser(filePath: NginxConfigParserTest.isolatedUrl.path).isolatedVersion
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -32,6 +32,7 @@ class ValetConfigParserTest: XCTestCase {
|
||||
"/Users/username/.config/valet/Sites",
|
||||
"/Users/username/Sites"
|
||||
])
|
||||
XCTAssertEqual(config.defaultSite, "/Users/username/default-site")
|
||||
XCTAssertEqual(config.loopback, "127.0.0.1")
|
||||
}
|
||||
|
93
phpmon-tests/Test Files/nicoverbruggen.test
Normal file
@ -0,0 +1,93 @@
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:443 ssl http2;
|
||||
#listen 127.0.0.1:443 ssl http2; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 512M;
|
||||
http2_push_preload on;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
ssl_certificate "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.crt";
|
||||
ssl_certificate_key "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.key";
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:60;
|
||||
#listen 127.0.0.1:60; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
|
||||
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
94
phpmon-tests/Test Files/nicoverbruggen_isolated.test
Normal file
@ -0,0 +1,94 @@
|
||||
server {
|
||||
listen 127.0.0.1:80;
|
||||
#listen 127.0.0.1:80; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:443 ssl http2;
|
||||
#listen 127.0.0.1:443 ssl http2; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 512M;
|
||||
http2_push_preload on;
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
ssl_certificate "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.crt";
|
||||
ssl_certificate_key "/Users/nicoverbruggen/.config/valet/Certificates/nicoverbruggen.test.key";
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
# ISOLATED_PHP_VERSION=php@8.1
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet81.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 127.0.0.1:60;
|
||||
#listen 127.0.0.1:60; # valet loopback
|
||||
server_name nicoverbruggen.test www.nicoverbruggen.test *.nicoverbruggen.test;
|
||||
root /;
|
||||
charset utf-8;
|
||||
client_max_body_size 128M;
|
||||
|
||||
add_header X-Robots-Tag 'noindex, nofollow, nosnippet, noarchive';
|
||||
|
||||
location /41c270e4-5535-4daa-b23e-c269744c2f45/ {
|
||||
internal;
|
||||
alias /;
|
||||
try_files $uri $uri/;
|
||||
}
|
||||
|
||||
location / {
|
||||
rewrite ^ "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php" last;
|
||||
}
|
||||
|
||||
location = /favicon.ico { access_log off; log_not_found off; }
|
||||
location = /robots.txt { access_log off; log_not_found off; }
|
||||
|
||||
access_log off;
|
||||
error_log "/Users/nicoverbruggen/.config/valet/Log/nginx-error.log";
|
||||
|
||||
error_page 404 "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
|
||||
location ~ [^/]\.php(/|$) {
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass "unix:/Users/nicoverbruggen/.config/valet/valet.sock";
|
||||
fastcgi_index "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
include fastcgi_params;
|
||||
fastcgi_param SCRIPT_FILENAME "/Users/nicoverbruggen/.composer/vendor/laravel/valet/server.php";
|
||||
fastcgi_param PATH_INFO $fastcgi_path_info;
|
||||
}
|
||||
|
||||
location ~ /\.ht {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
@ -4,5 +4,6 @@
|
||||
"/Users/username/.config/valet/Sites",
|
||||
"/Users/username/Sites"
|
||||
],
|
||||
"loopback": "127.0.0.1"
|
||||
"loopback": "127.0.0.1",
|
||||
"default": "/Users/username/default-site"
|
||||
}
|
||||
|
@ -22,8 +22,8 @@ class PhpVersionDetectionTest: XCTestCase {
|
||||
"unrelatedphp@1.0", // should be omitted, invalid
|
||||
"php@5.6",
|
||||
"php@5.4" // should be omitted, not supported
|
||||
], checkBinaries: false)
|
||||
], checkBinaries: false, generateHelpers: false)
|
||||
|
||||
XCTAssertEqual(outcome, ["8.0", "7.0", "5.6"])
|
||||
XCTAssertEqual(outcome, ["8.0", "7.0"])
|
||||
}
|
||||
}
|
@ -12,15 +12,23 @@ class PhpVersionNumberTest: XCTestCase {
|
||||
|
||||
func testCanDeconstructPhpVersion() throws {
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumber.make(from: "8.0.11"),
|
||||
try! PhpVersionNumber.parse("PHP 8.2.0-dev"),
|
||||
PhpVersionNumber(major: 8, minor: 2, patch: 0)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
try! PhpVersionNumber.parse("PHP 8.1.0RC5-dev"),
|
||||
PhpVersionNumber(major: 8, minor: 1, patch: 0)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
try! PhpVersionNumber.parse("8.0.11"),
|
||||
PhpVersionNumber(major: 8, minor: 0, patch: 11)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumber.make(from: "7.4.2"),
|
||||
try! PhpVersionNumber.parse("7.4.2"),
|
||||
PhpVersionNumber(major: 7, minor: 4, patch: 2)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumber.make(from: "7.4"),
|
||||
try! PhpVersionNumber.parse("7.4"),
|
||||
PhpVersionNumber(major: 7, minor: 4, patch: nil)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
@ -29,6 +37,12 @@ class PhpVersionNumberTest: XCTestCase {
|
||||
)
|
||||
}
|
||||
|
||||
func testPhpVersionNumberParse() throws {
|
||||
XCTAssertThrowsError(try PhpVersionNumber.parse("OOF")) { error in
|
||||
XCTAssertTrue(error is VersionParseError)
|
||||
}
|
||||
}
|
||||
|
||||
func testCanCheckFixedConstraints() throws {
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
@ -191,4 +205,86 @@ class PhpVersionNumberTest: XCTestCase {
|
||||
.make(from: ["7.4.10", "7.3.10", "7.2.10", "7.1.10", "7.0.10"]).all
|
||||
)
|
||||
}
|
||||
|
||||
func testCanCheckGreaterThanOrEqualConstraints() throws {
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: ">=7.0", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: ">=7.0.0", strict: true),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "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.4", "7.3"]).all
|
||||
)
|
||||
|
||||
// Non-strict check (ignoring patch, 7.2 resolves to 7.2.999)
|
||||
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.4", "7.3", "7.2"]).all
|
||||
)
|
||||
}
|
||||
|
||||
func testCanCheckGreaterThanConstraints() throws {
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: ">7.0"),
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: ">7.2.5"),
|
||||
// 7.2 will be valid due to non-strict mode (resolves to 7.2.999)
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3", "7.2", "7.1", "7.0"])
|
||||
.matching(constraint: ">7.2.5", strict: true),
|
||||
// 7.2 will not be valid due to strict mode (resolves to 7.2.0)
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.4", "7.3"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.3.1", "7.2.9", "7.2.8", "7.2.6", "7.2.5", "7.2"])
|
||||
.matching(constraint: ">7.2.8"),
|
||||
// 7.2 will be valid due to non-strict mode (resolves to 7.2.999)
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.3.1", "7.2.9", "7.2"]).all
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.3.1", "7.2.9", "7.2.8", "7.2.6", "7.2.5", "7.2"])
|
||||
.matching(constraint: ">7.2.8", strict: true),
|
||||
// 7.2 will not be valid due to strict mode (resolves to 7.2.0)
|
||||
PhpVersionNumberCollection
|
||||
.make(from: ["7.3.1", "7.2.9"]).all
|
||||
)
|
||||
}
|
||||
}
|
@ -8,11 +8,11 @@
|
||||
|
||||
import XCTest
|
||||
|
||||
class ValetTest: XCTestCase {
|
||||
class ValetVersionExtractorTest: XCTestCase {
|
||||
|
||||
func testDetermineValetVersion() {
|
||||
let version = valet("--version")
|
||||
XCTAssert(version.contains("Laravel Valet 2."))
|
||||
let version = valet("--version", sudo: false)
|
||||
XCTAssert(version.contains("Laravel Valet 2") || version.contains("Laravel Valet 3"))
|
||||
}
|
||||
|
||||
}
|
Before Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 585 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 134 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_128x128@2x.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16.png
Normal file
After Width: | Height: | Size: 632 B |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_16x16@2x.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_256x256@2x.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_32x32@2x.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
phpmon/Assets.xcassets/AppIconDev.appiconset/icon_512x512@2x.png
Normal file
After Width: | Height: | Size: 163 KiB |
38
phpmon/Assets.xcassets/IconColorGreen.colorset/Contents.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.501",
|
||||
"green" : "0.697",
|
||||
"red" : "0.247"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.501",
|
||||
"green" : "0.765",
|
||||
"red" : "0.247"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "1.000",
|
||||
"green" : "1.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
38
phpmon/Assets.xcassets/IconColorRed.colorset/Contents.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.180",
|
||||
"green" : "0.000",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.426",
|
||||
"green" : "0.363",
|
||||
"red" : "1.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
25
phpmon/Assets.xcassets/IconDefault.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Default.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Default@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
BIN
phpmon/Assets.xcassets/IconDefault.imageset/Default.png
vendored
Normal file
After Width: | Height: | Size: 861 B |
BIN
phpmon/Assets.xcassets/IconDefault.imageset/Default@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -1,11 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Linked.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "link.svg",
|
||||
"filename" : "Linked@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
|
BIN
phpmon/Assets.xcassets/IconLinked.imageset/Linked.png
vendored
Normal file
After Width: | Height: | Size: 978 B |
BIN
phpmon/Assets.xcassets/IconLinked.imageset/Linked@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,11 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Parked.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "car-alt.svg",
|
||||
"filename" : "Parked@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
|
BIN
phpmon/Assets.xcassets/IconParked.imageset/Parked.png
vendored
Normal file
After Width: | Height: | Size: 868 B |
BIN
phpmon/Assets.xcassets/IconParked.imageset/Parked@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 480 512"><!-- Font Awesome Free 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) --><path d="M438.66 212.33l-11.24-28.1-19.93-49.83C390.38 91.63 349.57 64 303.5 64h-127c-46.06 0-86.88 27.63-103.99 70.4l-19.93 49.83-11.24 28.1C17.22 221.5 0 244.66 0 272v48c0 16.12 6.16 30.67 16 41.93V416c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-32h256v32c0 17.67 14.33 32 32 32h32c17.67 0 32-14.33 32-32v-54.07c9.84-11.25 16-25.8 16-41.93v-48c0-27.34-17.22-50.5-41.34-59.67zm-306.73-54.16c7.29-18.22 24.94-30.17 44.57-30.17h127c19.63 0 37.28 11.95 44.57 30.17L368 208H112l19.93-49.83zM80 319.8c-19.2 0-32-12.76-32-31.9S60.8 256 80 256s48 28.71 48 47.85-28.8 15.95-48 15.95zm320 0c-19.2 0-48 3.19-48-15.95S380.8 256 400 256s32 12.76 32 31.9-12.8 31.9-32 31.9z"/></svg>
|
Before Width: | Height: | Size: 918 B |
25
phpmon/Assets.xcassets/Isolated.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Isolated.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Isolated@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
BIN
phpmon/Assets.xcassets/Isolated.imageset/Isolated.png
vendored
Normal file
After Width: | Height: | Size: 690 B |
BIN
phpmon/Assets.xcassets/Isolated.imageset/Isolated@2x.png
vendored
Normal file
After Width: | Height: | Size: 827 B |
6
phpmon/Assets.xcassets/Menu Bar Icons/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
22
phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Menu Bar Elephant.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Menu Bar Elephant@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant.png
vendored
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_elephant.imageset/Menu Bar Elephant@2x.png
vendored
Normal file
After Width: | Height: | Size: 2.5 KiB |
@ -1,11 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "Menu Bar.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "php@2x.png",
|
||||
"filename" : "Menu Bar@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
BIN
phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar.png
vendored
Normal file
After Width: | Height: | Size: 658 B |
BIN
phpmon/Assets.xcassets/Menu Bar Icons/MenuBar_php.imageset/Menu Bar@2x.png
vendored
Normal file
After Width: | Height: | Size: 793 B |
@ -1,11 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ServiceLoading.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "question-circle.svg",
|
||||
"filename" : "ServiceLoading@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
|
BIN
phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading.png
vendored
Normal file
After Width: | Height: | Size: 854 B |
BIN
phpmon/Assets.xcassets/ServiceLoading.imageset/ServiceLoading@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.3 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 448c-110.532 0-200-89.431-200-200 0-110.495 89.472-200 200-200 110.491 0 200 89.471 200 200 0 110.53-89.431 200-200 200zm107.244-255.2c0 67.052-72.421 68.084-72.421 92.863V300c0 6.627-5.373 12-12 12h-45.647c-6.627 0-12-5.373-12-12v-8.659c0-35.745 27.1-50.034 47.579-61.516 17.561-9.845 28.324-16.541 28.324-29.579 0-17.246-21.999-28.693-39.784-28.693-23.189 0-33.894 10.977-48.942 29.969-4.057 5.12-11.46 6.071-16.666 2.124l-27.824-21.098c-5.107-3.872-6.251-11.066-2.644-16.363C184.846 131.491 214.94 112 261.794 112c49.071 0 101.45 38.304 101.45 88.8zM298 368c0 23.159-18.841 42-42 42s-42-18.841-42-42 18.841-42 42-42 42 18.841 42 42z"/></svg>
|
Before Width: | Height: | Size: 966 B |
@ -1,11 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ServiceOff.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "times-circle.svg",
|
||||
"filename" : "ServiceOff@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
|
BIN
phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff.png
vendored
Normal file
After Width: | Height: | Size: 826 B |
BIN
phpmon/Assets.xcassets/ServiceOff.imageset/ServiceOff@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z"/></svg>
|
Before Width: | Height: | Size: 685 B |
@ -1,11 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ServiceOn.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "check-circle.svg",
|
||||
"filename" : "ServiceOn@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
|
BIN
phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn.png
vendored
Normal file
After Width: | Height: | Size: 819 B |
BIN
phpmon/Assets.xcassets/ServiceOn.imageset/ServiceOn@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.2 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 48c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m140.204 130.267l-22.536-22.718c-4.667-4.705-12.265-4.736-16.97-.068L215.346 303.697l-59.792-60.277c-4.667-4.705-12.265-4.736-16.97-.069l-22.719 22.536c-4.705 4.667-4.736 12.265-.068 16.971l90.781 91.516c4.667 4.705 12.265 4.736 16.97.068l172.589-171.204c4.704-4.668 4.734-12.266.067-16.971z"/></svg>
|
Before Width: | Height: | Size: 718 B |
Before Width: | Height: | Size: 940 B |
@ -34,17 +34,39 @@ class Actions {
|
||||
brew("services stop dnsmasq", sudo: true)
|
||||
}
|
||||
|
||||
/**
|
||||
Kindly asks Valet to switch to a specific PHP version.
|
||||
*/
|
||||
public static func switchToPhpVersionUsingValet(
|
||||
version: String,
|
||||
availableVersions: [String],
|
||||
completed: @escaping () -> Void
|
||||
) {
|
||||
Log.info("Switching to \(version) using Valet")
|
||||
Log.info(valet("use php@\(version)"))
|
||||
completed()
|
||||
public static func fixHomebrewPermissions() throws
|
||||
{
|
||||
var servicesCommands = [
|
||||
"\(Paths.brew) services stop nginx",
|
||||
"\(Paths.brew) services stop dnsmasq",
|
||||
]
|
||||
var cellarCommands = [
|
||||
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/nginx",
|
||||
"chown -R \(Paths.whoami):admin \(Paths.cellarPath)/dnsmasq"
|
||||
]
|
||||
|
||||
PhpEnv.shared.availablePhpVersions.forEach { version in
|
||||
let formula = version == PhpEnv.brewPhpVersion
|
||||
? "php"
|
||||
: "php@\(version)"
|
||||
servicesCommands.append("\(Paths.brew) services stop \(formula)")
|
||||
cellarCommands.append("chown -R \(Paths.whoami):admin \(Paths.cellarPath)/\(formula)")
|
||||
}
|
||||
|
||||
let script =
|
||||
servicesCommands.joined(separator: " && ")
|
||||
+ " && "
|
||||
+ cellarCommands.joined(separator: " && ")
|
||||
|
||||
let appleScript = NSAppleScript(
|
||||
source: "do shell script \"\(script)\" with administrator privileges"
|
||||
)
|
||||
|
||||
let eventResult: NSAppleEventDescriptor? = appleScript?.executeAndReturnError(nil)
|
||||
|
||||
if (eventResult == nil) {
|
||||
throw HomebrewPermissionError(kind: .applescriptNilError)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Finding Config Files
|
||||
@ -88,34 +110,27 @@ class Actions {
|
||||
return URL(string: "file:///private/tmp/phpmon_phpinfo.html")!
|
||||
}
|
||||
|
||||
// MARK: - Quick Fix
|
||||
// MARK: - Fix My Valet
|
||||
|
||||
/**
|
||||
Detects all currently available PHP versions,
|
||||
and unlinks each and every one of them.
|
||||
|
||||
This all happens in sequence, nothing runs in parallel.
|
||||
|
||||
After this, the brew services are also stopped,
|
||||
the latest PHP version is linked, and php + nginx are restarted.
|
||||
|
||||
If this does not solve the issue, the user may need to install additional
|
||||
extensions and/or run `composer global update`.
|
||||
*/
|
||||
public static func fixMyPhp()
|
||||
public static func fixMyValet(completed: @escaping () -> Void)
|
||||
{
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
|
||||
PhpEnv.shared.detectPhpVersions().forEach { (version) in
|
||||
let formula = (version == PhpEnv.brewPhpVersion) ? "php" : "php@\(version)"
|
||||
brew("unlink php@\(version)")
|
||||
brew("services stop \(formula)")
|
||||
brew("services stop \(formula)", sudo: true)
|
||||
}
|
||||
|
||||
brew("services stop php")
|
||||
brew("services stop nginx")
|
||||
brew("link php")
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
brew("services stop php", sudo: true)
|
||||
brew("services stop nginx", sudo: true)
|
||||
InternalSwitcher().performSwitch(to: PhpEnv.brewPhpVersion, completion: {
|
||||
brew("services restart dnsmasq", sudo: true)
|
||||
brew("services restart php", sudo: true)
|
||||
brew("services restart nginx", sudo: true)
|
||||
completed()
|
||||
})
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class Constants {
|
||||
struct Constants {
|
||||
|
||||
/**
|
||||
* The latest PHP version that is considered to be stable at the time of release.
|
||||
@ -34,7 +34,7 @@ class Constants {
|
||||
// STABLE RELEASES
|
||||
// ====================
|
||||
// Versions of PHP that are stable and are supported.
|
||||
"5.6",
|
||||
"5.6", // only supported when Valet 2.x is active
|
||||
"7.0",
|
||||
"7.1",
|
||||
"7.2",
|
||||
@ -50,5 +50,19 @@ class Constants {
|
||||
// dev release. In this case, that means that the version below is detected.
|
||||
"8.2"
|
||||
]
|
||||
|
||||
struct Urls {
|
||||
|
||||
static let DonationPayment = URL(
|
||||
string: "https://nicoverbruggen.be/sponsor#pay-now"
|
||||
)!
|
||||
static let DonationPage = URL(
|
||||
string: "https://nicoverbruggen.be/sponsor"
|
||||
)!
|
||||
static let FrequentlyAskedQuestions = URL(
|
||||
string: "https://github.com/nicoverbruggen/phpmon#%EF%B8%8F-faq--troubleshooting"
|
||||
)!
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -9,11 +9,11 @@
|
||||
// MARK: Common Shell Commands
|
||||
|
||||
/**
|
||||
Runs a `valet` command.
|
||||
Runs a `valet` command. Defaults to running as superuser.
|
||||
*/
|
||||
func valet(_ command: String) -> String
|
||||
func valet(_ command: String, sudo: Bool = true) -> String
|
||||
{
|
||||
return Shell.pipe("sudo \(Paths.valet) \(command)", requiresPath: true)
|
||||
return Shell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,7 +35,7 @@ func sed(file: String, original: String, replacement: String)
|
||||
|
||||
// Check if gsed exists; it is able to follow symlinks,
|
||||
// which we want to do to toggle the extension
|
||||
if Shell.fileExists("\(Paths.binPath)/gsed") {
|
||||
if Filesystem.fileExists("\(Paths.binPath)/gsed") {
|
||||
Shell.run("\(Paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)")
|
||||
} else {
|
||||
Shell.run("sed -i '' 's/\(e_original)/\(e_replacement)/g' \(file)")
|
@ -27,25 +27,31 @@ class Log {
|
||||
|
||||
static func err(_ item: Any) {
|
||||
if Verbosity.error.isApplicable() {
|
||||
print(item)
|
||||
print("[E] \(item)")
|
||||
}
|
||||
}
|
||||
|
||||
static func warn(_ item: Any) {
|
||||
if Verbosity.warning.isApplicable() {
|
||||
print(item)
|
||||
print("[W] \(item)")
|
||||
}
|
||||
}
|
||||
|
||||
static func info(_ item: Any) {
|
||||
if Verbosity.info.isApplicable() {
|
||||
print(item)
|
||||
print("\(item)")
|
||||
}
|
||||
}
|
||||
|
||||
static func perf(_ item: Any) {
|
||||
if Verbosity.performance.isApplicable() {
|
||||
print(item)
|
||||
print("[P] \(item)")
|
||||
}
|
||||
}
|
||||
|
||||
static func separator(as verbosity: Verbosity = .info) {
|
||||
if verbosity.isApplicable() {
|
||||
print("==================================")
|
||||
}
|
||||
}
|
||||
|
98
phpmon/Common/Core/Paths.swift
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// Paths.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Copyright © 2021 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
The `Paths` class is used to locate various binaries on the system.
|
||||
The path to the Homebrew directory and the user's name are fetched only once, at boot.
|
||||
*/
|
||||
public class Paths {
|
||||
|
||||
public static let shared = Paths()
|
||||
|
||||
internal var baseDir: Paths.HomebrewDir
|
||||
|
||||
private var userName: String
|
||||
|
||||
init() {
|
||||
baseDir = App.architecture != "x86_64" ? .opt : .usr
|
||||
userName = String(Shell.pipe("whoami").split(separator: "\n")[0])
|
||||
}
|
||||
|
||||
public func detectBinaryPaths() {
|
||||
detectComposerBinary()
|
||||
}
|
||||
|
||||
// - MARK: Binaries
|
||||
|
||||
public static var valet: String {
|
||||
return "\(binPath)/valet"
|
||||
}
|
||||
|
||||
public static var brew: String {
|
||||
return "\(binPath)/brew"
|
||||
}
|
||||
|
||||
public static var php: String {
|
||||
return "\(binPath)/php"
|
||||
}
|
||||
|
||||
public static var phpConfig: String {
|
||||
return "\(binPath)/php-config"
|
||||
}
|
||||
|
||||
// - MARK: Detected Binaries
|
||||
|
||||
/** The path to the Composer binary. Can be in multiple locations, so is detected instead. */
|
||||
public static var composer: String? = nil
|
||||
|
||||
// - MARK: Paths
|
||||
|
||||
public static var whoami: String {
|
||||
return shared.userName
|
||||
}
|
||||
|
||||
public static var cellarPath: String {
|
||||
return "\(shared.baseDir.rawValue)/Cellar"
|
||||
}
|
||||
|
||||
public static var binPath: String {
|
||||
return "\(shared.baseDir.rawValue)/bin"
|
||||
}
|
||||
|
||||
public static var optPath: String {
|
||||
return "\(shared.baseDir.rawValue)/opt"
|
||||
}
|
||||
|
||||
public static var etcPath: String {
|
||||
return "\(shared.baseDir.rawValue)/etc"
|
||||
}
|
||||
|
||||
// MARK: - Flexible Binaries
|
||||
// (these can be in multiple locations, so we scan common places because)
|
||||
// (PHP Monitor will not use the user's own PATH)
|
||||
|
||||
private func detectComposerBinary() {
|
||||
if Filesystem.fileExists("/usr/local/bin/composer") {
|
||||
Paths.composer = "/usr/local/bin/composer"
|
||||
} else if Filesystem.fileExists("/opt/homebrew/bin/composer") {
|
||||
Paths.composer = "/opt/homebrew/bin/composer"
|
||||
} else {
|
||||
Paths.composer = nil
|
||||
Log.warn("Composer was not found.")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Enum
|
||||
|
||||
public enum HomebrewDir: String {
|
||||
case opt = "/opt/homebrew"
|
||||
case usr = "/usr/local"
|
||||
}
|
||||
|
||||
}
|
59
phpmon/Common/Core/Process.swift
Normal file
@ -0,0 +1,59 @@
|
||||
//
|
||||
// Process.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 23/02/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Process {
|
||||
|
||||
/**
|
||||
When a process is running in the background, it can send content to standard
|
||||
output or standard error, just like it would in a terminal. Using `listen`
|
||||
allows us to react whenever data is received by running a particular closure,
|
||||
depending on which type of data is received.
|
||||
*/
|
||||
public func listen(
|
||||
didReceiveStandardOutputData: @escaping (String) -> Void,
|
||||
didReceiveStandardErrorData: @escaping (String) -> Void
|
||||
) {
|
||||
let outputPipe = Pipe()
|
||||
let errorPipe = Pipe()
|
||||
|
||||
self.standardOutput = outputPipe
|
||||
self.standardError = errorPipe
|
||||
|
||||
[
|
||||
(outputPipe, didReceiveStandardOutputData),
|
||||
(errorPipe, didReceiveStandardErrorData)
|
||||
].forEach { (pipe: Pipe, callback: @escaping (String) -> Void) in
|
||||
pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
NotificationCenter.default.addObserver(
|
||||
forName: NSNotification.Name.NSFileHandleDataAvailable,
|
||||
object: pipe.fileHandleForReading,
|
||||
queue: nil
|
||||
) { notification in
|
||||
if let outputString = String(data: pipe.fileHandleForReading.availableData, encoding: String.Encoding.utf8) {
|
||||
callback(outputString)
|
||||
}
|
||||
pipe.fileHandleForReading.waitForDataInBackgroundAndNotify()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
After the process is done running, you'll want to stop listening.
|
||||
*/
|
||||
public func haltListening() {
|
||||
if let pipe = self.standardOutput as? Pipe {
|
||||
NotificationCenter.default.removeObserver(pipe.fileHandleForReading)
|
||||
}
|
||||
if let pipe = self.standardError as? Pipe {
|
||||
NotificationCenter.default.removeObserver(pipe.fileHandleForReading)
|
||||
}
|
||||
}
|
||||
|
||||
}
|