1
0
mirror of https://github.com/nicoverbruggen/phpmon.git synced 2025-08-07 03:50:08 +02:00

🏗 WIP: Shell rework

This commit is contained in:
2022-09-27 20:26:11 +02:00
parent 5399bddfeb
commit 3483569410
27 changed files with 93 additions and 87 deletions

View File

@ -7,8 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
03E36FE728D9219000636F7F /* NxtShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* NxtShell.swift */; };
03E36FE828D9219000636F7F /* NxtShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* NxtShell.swift */; };
03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* ActiveShell.swift */; };
03E36FE828D9219000636F7F /* ActiveShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 03E36FE628D9219000636F7F /* ActiveShell.swift */; };
5420395926135DC100FB00FA /* PrefsVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395826135DC100FB00FA /* PrefsVC.swift */; };
5420395F2613607600FB00FA /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5420395E2613607600FB00FA /* Preferences.swift */; };
5489625828312FAD004F647A /* CreatedFromFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5489625728312FAD004F647A /* CreatedFromFile.swift */; };
@ -101,8 +101,8 @@
C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1527DFDE7900862737 /* nginx-site.test */; };
C42CFB1827DFDFDC00862737 /* nginx-site-isolated.test in Resources */ = {isa = PBXBuildFile; fileRef = C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */; };
C42CFB1A27DFE8BD00862737 /* NginxConfigurationTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */; };
C42E3BF428A9BF5100AFECFC /* Shell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */; };
C42E3BF528A9BF5100AFECFC /* Shell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */; };
C42E3BF428A9BF5100AFECFC /* LegacyShell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* LegacyShell+PATH.swift */; };
C42E3BF528A9BF5100AFECFC /* LegacyShell+PATH.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42E3BF328A9BF5100AFECFC /* LegacyShell+PATH.swift */; };
C42F26732805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
C42F26742805B4B400938AC7 /* DomainListable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C42F26722805B4B400938AC7 /* DomainListable.swift */; };
C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */ = {isa = PBXBuildFile; fileRef = C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */; };
@ -216,8 +216,8 @@
C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */; };
C4B5853E2770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; };
C4B5853F2770FE3900DA4FBE /* Paths.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853B2770FE3900DA4FBE /* Paths.swift */; };
C4B585412770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; };
C4B585422770FE3900DA4FBE /* Shell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* Shell.swift */; };
C4B585412770FE3900DA4FBE /* LegacyShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* LegacyShell.swift */; };
C4B585422770FE3900DA4FBE /* LegacyShell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853C2770FE3900DA4FBE /* LegacyShell.swift */; };
C4B585442770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; };
C4B585452770FE3900DA4FBE /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B5853D2770FE3900DA4FBE /* Command.swift */; };
C4B6091A2853AAD300C95265 /* SectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4B609192853AAD300C95265 /* SectionHeaderView.swift */; };
@ -331,7 +331,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
03E36FE628D9219000636F7F /* NxtShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NxtShell.swift; sourceTree = "<group>"; };
03E36FE628D9219000636F7F /* ActiveShell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveShell.swift; sourceTree = "<group>"; };
5420395826135DC100FB00FA /* PrefsVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrefsVC.swift; sourceTree = "<group>"; };
5420395E2613607600FB00FA /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
5489625728312FAD004F647A /* CreatedFromFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatedFromFile.swift; sourceTree = "<group>"; };
@ -396,7 +396,7 @@
C42CFB1527DFDE7900862737 /* nginx-site.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site.test"; sourceTree = "<group>"; };
C42CFB1727DFDFDC00862737 /* nginx-site-isolated.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-site-isolated.test"; sourceTree = "<group>"; };
C42CFB1927DFE8BD00862737 /* NginxConfigurationTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NginxConfigurationTest.swift; sourceTree = "<group>"; };
C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Shell+PATH.swift"; sourceTree = "<group>"; };
C42E3BF328A9BF5100AFECFC /* LegacyShell+PATH.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "LegacyShell+PATH.swift"; sourceTree = "<group>"; };
C42F26722805B4B400938AC7 /* DomainListable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListable.swift; sourceTree = "<group>"; };
C42F26752805FEE200938AC7 /* nginx-secure-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-secure-proxy.test"; sourceTree = "<group>"; };
C436039F275E67610028EFC6 /* AppDelegate+Notifications.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Notifications.swift"; sourceTree = "<group>"; };
@ -458,7 +458,7 @@
C4B5635D276AB09000F12CCB /* VersionExtractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionExtractor.swift; sourceTree = "<group>"; };
C4B56360276AB0A500F12CCB /* VersionExtractorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VersionExtractorTest.swift; sourceTree = "<group>"; };
C4B5853B2770FE3900DA4FBE /* Paths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Paths.swift; sourceTree = "<group>"; };
C4B5853C2770FE3900DA4FBE /* Shell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shell.swift; sourceTree = "<group>"; };
C4B5853C2770FE3900DA4FBE /* LegacyShell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyShell.swift; sourceTree = "<group>"; };
C4B5853D2770FE3900DA4FBE /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = "<group>"; };
C4B609192853AAD300C95265 /* SectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderView.swift; sourceTree = "<group>"; };
C4B6091C2853AB9700C95265 /* ServicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServicesView.swift; sourceTree = "<group>"; };
@ -873,7 +873,7 @@
C46EBC3F28DB9550007ACC74 /* Next */ = {
isa = PBXGroup;
children = (
03E36FE628D9219000636F7F /* NxtShell.swift */,
03E36FE628D9219000636F7F /* ActiveShell.swift */,
C46EBC4628DB9644007ACC74 /* SystemShell.swift */,
C46EBC4928DB966A007ACC74 /* TestableShell.swift */,
C46EBC4328DB95F0007ACC74 /* Shellable.swift */,
@ -884,8 +884,8 @@
C46EBC4C28DB9F43007ACC74 /* Pending Removal */ = {
isa = PBXGroup;
children = (
C4B5853C2770FE3900DA4FBE /* Shell.swift */,
C42E3BF328A9BF5100AFECFC /* Shell+PATH.swift */,
C4B5853C2770FE3900DA4FBE /* LegacyShell.swift */,
C42E3BF328A9BF5100AFECFC /* LegacyShell+PATH.swift */,
);
path = "Pending Removal";
sourceTree = "<group>";
@ -1358,7 +1358,7 @@
C4D8016622B1584700C6DA1B /* Startup.swift in Sources */,
C42C49DB27C2806F0074ABAC /* MainMenu+FixMyValet.swift in Sources */,
C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */,
C4B585412770FE3900DA4FBE /* Shell.swift in Sources */,
C4B585412770FE3900DA4FBE /* LegacyShell.swift in Sources */,
C4998F0A2617633900B2526E /* PreferencesWindowController.swift in Sources */,
C46FA9882822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */,
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */,
@ -1432,7 +1432,7 @@
C41CA5ED2774F8EE00A2C80E /* DomainListVC+Actions.swift in Sources */,
C46E206D28299B3800D909D6 /* AppUpdateChecker.swift in Sources */,
C412E5FC25700D5300A1FB67 /* HomebrewPackage.swift in Sources */,
03E36FE728D9219000636F7F /* NxtShell.swift in Sources */,
03E36FE728D9219000636F7F /* ActiveShell.swift in Sources */,
C4D9ADBF277610E1007277F4 /* PhpSwitcher.swift in Sources */,
C45E76142854A65300B4FE0C /* ServicesManager.swift in Sources */,
C46EBC4728DB9644007ACC74 /* SystemShell.swift in Sources */,
@ -1481,7 +1481,7 @@
C40508AF28ADA23D008FAC1F /* NoDomainResultsView.swift in Sources */,
C4D89BC62783C99400A02B68 /* ComposerJson.swift in Sources */,
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */,
C42E3BF428A9BF5100AFECFC /* Shell+PATH.swift in Sources */,
C42E3BF428A9BF5100AFECFC /* LegacyShell+PATH.swift in Sources */,
C42337A3281F19F000459A48 /* Xdebug.swift in Sources */,
C4B97B75275CF08C003F3378 /* AppDelegate+MenuOutlets.swift in Sources */,
C41C02A627E60D7A009F26CB /* SiteScanner.swift in Sources */,
@ -1534,7 +1534,7 @@
C4FBFC532616485F00CDB8E1 /* PhpVersionDetectionTest.swift in Sources */,
C43A8A2425D9D20D00591B77 /* HomebrewPackageTest.swift in Sources */,
C485707928BF456C00539B36 /* ArrayExtension.swift in Sources */,
C42E3BF528A9BF5100AFECFC /* Shell+PATH.swift in Sources */,
C42E3BF528A9BF5100AFECFC /* LegacyShell+PATH.swift in Sources */,
C4F780CA25D80B75000DBC97 /* HomebrewPackage.swift in Sources */,
C4C8E81C276F54E5003AC782 /* PhpConfigWatcher.swift in Sources */,
C4F319C927B034A500AFF46F /* Stats.swift in Sources */,
@ -1586,7 +1586,7 @@
C4B97B7C275CF20A003F3378 /* App+GlobalHotkey.swift in Sources */,
5489625928313231004F647A /* CreatedFromFile.swift in Sources */,
54D9E0B327E4F51E003B9AD9 /* HotKeysController.swift in Sources */,
03E36FE828D9219000636F7F /* NxtShell.swift in Sources */,
03E36FE828D9219000636F7F /* ActiveShell.swift in Sources */,
C4B97B79275CF1B5003F3378 /* App+ActivationPolicy.swift in Sources */,
C4CE3BBB27B324230086CA49 /* MainMenu+Switcher.swift in Sources */,
C46E20702829D27F00D909D6 /* AppUpdaterCheckTest.swift in Sources */,
@ -1636,7 +1636,7 @@
C4A6957728D23EE300A14CF8 /* EnvironmentManager.swift in Sources */,
C4E0F7EE27BEBDA9007475F2 /* NSWindowExtension.swift in Sources */,
C4A81CA528C67101008DD9D1 /* PMTableView.swift in Sources */,
C4B585422770FE3900DA4FBE /* Shell.swift in Sources */,
C4B585422770FE3900DA4FBE /* LegacyShell.swift in Sources */,
C45E76152854A65300B4FE0C /* ServicesManager.swift in Sources */,
C464ADAD275A7A3F003FCD53 /* DomainListWindowController.swift in Sources */,
C40C7F1F2772136000DDDCDC /* PhpEnv.swift in Sources */,

View File

@ -10,14 +10,14 @@ import XCTest
class ShellTest: XCTestCase {
func test_default_shell_is_system_shell() {
XCTAssertTrue(NxtShell.shared is SystemShell)
XCTAssertTrue(Shell is SystemShell)
XCTAssertTrue(NxtShell.shared.syncPipe("php -v")
XCTAssertTrue(Shell.syncPipe("php -v")
.contains("Copyright (c) The PHP Group"))
}
func test_system_shell_has_path() {
let systemShell = NxtShell.shared as! SystemShell
let systemShell = Shell as! SystemShell
XCTAssertTrue(systemShell.PATH.contains(":/usr/local/bin"))
XCTAssertTrue(systemShell.PATH.contains(":/usr/bin"))
@ -38,15 +38,15 @@ class ShellTest: XCTestCase {
isError: false
)
NxtShell.useTestable([
ActiveShell.useTestable([
"php -v": expectedPhpOutput,
"php --version": slowVersionOutput
])
XCTAssertTrue(NxtShell.shared is TestableShell)
XCTAssertTrue(Shell is TestableShell)
XCTAssertEqual(expectedPhpOutput, NxtShell.shared.syncPipe("php -v"))
XCTAssertEqual(expectedPhpOutput, Shell.syncPipe("php -v"))
XCTAssertEqual(expectedPhpOutput, NxtShell.shared.syncPipe("php --version"))
XCTAssertEqual(expectedPhpOutput, Shell.syncPipe("php --version"))
}
}

View File

@ -56,7 +56,7 @@ class HomebrewPackageTest: XCTestCase {
func testCanParseServicesJsonFromCliOutput() throws {
let services = try! JSONDecoder().decode(
[HomebrewService].self,
from: Shell.pipe(
from: LegacyShell.pipe(
"sudo \(Paths.brew) services info --all --json",
requiresPath: true
).data(using: .utf8)!
@ -77,7 +77,7 @@ class HomebrewPackageTest: XCTestCase {
func testCanLoadExtensionJsonFromCliOutput() throws {
let package = try! JSONDecoder().decode(
[HomebrewPackage].self,
from: Shell.pipe("\(Paths.brew) info php --json", requiresPath: true).data(using: .utf8)!
from: LegacyShell.pipe("\(Paths.brew) info php --json", requiresPath: true).data(using: .utf8)!
).first!
XCTAssertTrue(package.name == "php")

View File

@ -124,7 +124,7 @@ class Actions {
try! "<?php phpinfo();".write(toFile: "/tmp/phpmon_phpinfo.php", atomically: true, encoding: .utf8)
// Tell php-cgi to run the PHP and output as an .html file
Shell.run("\(Paths.binPath)/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html")
LegacyShell.run("\(Paths.binPath)/php-cgi -q /tmp/phpmon_phpinfo.php > /tmp/phpmon_phpinfo.html")
return URL(string: "file:///private/tmp/phpmon_phpinfo.html")!
}

View File

@ -12,14 +12,14 @@
Runs a `valet` command. Defaults to running as superuser.
*/
func valet(_ command: String, sudo: Bool = true) -> String {
return Shell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true)
return LegacyShell.pipe("\(sudo ? "sudo " : "")" + "\(Paths.valet) \(command)", requiresPath: true)
}
/**
Runs a `brew` command. Can run as superuser.
*/
func brew(_ command: String, sudo: Bool = false) {
Shell.run("\(sudo ? "sudo " : "")" + "\(Paths.brew) \(command)")
LegacyShell.run("\(sudo ? "sudo " : "")" + "\(Paths.brew) \(command)")
}
/**
@ -33,9 +33,9 @@ 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 Filesystem.fileExists("\(Paths.binPath)/gsed") {
Shell.run("\(Paths.binPath)/gsed -i --follow-symlinks 's/\(e_original)/\(e_replacement)/g' \(file)")
LegacyShell.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)")
LegacyShell.run("sed -i '' 's/\(e_original)/\(e_replacement)/g' \(file)")
}
}
@ -43,7 +43,7 @@ func sed(file: String, original: String, replacement: String) {
Uses `grep` to determine whether a particular query string can be found in a particular file.
*/
func grepContains(file: String, query: String) -> Bool {
return Shell.pipe("""
return LegacyShell.pipe("""
grep -q '\(query)' \(file); [ $? -eq 0 ] && echo "YES" || echo "NO"
""")
.trimmingCharacters(in: .whitespacesAndNewlines)

View File

@ -21,7 +21,7 @@ public class Paths {
init() {
baseDir = App.architecture != "x86_64" ? .opt : .usr
userName = String(Shell.pipe("id -un").split(separator: "\n")[0])
userName = String(LegacyShell.pipe("id -un").split(separator: "\n")[0])
}
public func detectBinaryPaths() {

View File

@ -34,13 +34,13 @@ class Application {
(This will open the app if it isn't open yet.)
*/
@objc public func openDirectory(file: String) {
return Shell.run("/usr/bin/open -a \"\(name)\" \"\(file)\"")
return LegacyShell.run("/usr/bin/open -a \"\(name)\" \"\(file)\"")
}
/** Checks if the app is installed. */
func isInstalled() -> Bool {
// If this script does not complain, the app exists!
return Shell.user.executeSynchronously(
return LegacyShell.user.executeSynchronously(
"/usr/bin/open -Ra \"\(name)\"",
requiresPath: false
).task.terminationStatus == 0

View File

@ -129,7 +129,7 @@ class ActivePhpInstallation {
if self.version.short == "5.6" {
// The main PHP config file should contain `valet.sock` and then we're probably fine?
let fileName = "\(Paths.etcPath)/php/5.6/php-fpm.conf"
return Shell.pipe("cat \(fileName)").contains("valet.sock")
return LegacyShell.pipe("cat \(fileName)").contains("valet.sock")
}
// Make sure to check if valet-fpm.conf exists. If it does, we should be fine :)

View File

@ -15,7 +15,7 @@ class PhpEnv {
init() {
self.currentInstall = ActivePhpInstallation()
let brewPhpAlias = Shell.pipe("\(Paths.brew) info php --json")
let brewPhpAlias = LegacyShell.pipe("\(Paths.brew) info php --json")
self.homebrewPackage = try! JSONDecoder().decode(
[HomebrewPackage].self,
@ -84,7 +84,7 @@ class PhpEnv {
Detects which versions of PHP are installed.
*/
public func detectPhpVersions() -> [String] {
let files = Shell.pipe("ls \(Paths.optPath) | grep php@")
let files = LegacyShell.pipe("ls \(Paths.optPath) | grep php@")
var versionsOnly = extractPhpVersions(from: files.components(separatedBy: "\n"))

View File

@ -20,13 +20,13 @@ class PhpHelper {
let destination = "\(Paths.homePath)/.config/phpmon/bin/pm\(dotless)"
// Check if the ~/.config/phpmon/bin directory is in the PATH
let inPath = Shell.user.PATH.contains("\(Paths.homePath)/.config/phpmon/bin")
let inPath = LegacyShell.user.PATH.contains("\(Paths.homePath)/.config/phpmon/bin")
// Check if we can create symlinks (`/usr/local/bin` must be writable)
let canWriteSymlinks = FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
do {
Shell.run("mkdir -p ~/.config/phpmon/bin")
LegacyShell.run("mkdir -p ~/.config/phpmon/bin")
if FileManager.default.fileExists(atPath: destination) {
let contents = try String(contentsOfFile: destination)
@ -61,7 +61,7 @@ class PhpHelper {
)
// Make sure the file is executable
Shell.run("chmod +x \(destination)")
LegacyShell.run("chmod +x \(destination)")
// Create a symlink if the folder is not in the PATH
if !inPath {
@ -86,13 +86,13 @@ class PhpHelper {
if !Filesystem.fileExists(destination) {
Log.info("Creating new symlink: \(destination)")
Shell.run("ln -s \(source) \(destination)")
LegacyShell.run("ln -s \(source) \(destination)")
return
}
if !Filesystem.fileIsSymlink(destination) {
Log.info("Overwriting existing file with new symlink: \(destination)")
Shell.run("ln -fs \(source) \(destination)")
LegacyShell.run("ln -fs \(source) \(destination)")
return
}

View File

@ -115,7 +115,7 @@ class InternalSwitcher: PhpSwitcher {
if Valet.enabled(feature: .isolatedSites) && primary {
let socketVersion = version.replacingOccurrences(of: ".", with: "")
Shell.run("ln -sF ~/.config/valet/valet\(socketVersion).sock ~/.config/valet/valet.sock")
LegacyShell.run("ln -sF ~/.config/valet/valet\(socketVersion).sock ~/.config/valet/valet.sock")
Log.info("Symlinked new socket version (valet\(socketVersion).sock → valet.sock).")
}

View File

@ -8,7 +8,7 @@
import Foundation
extension Shell {
extension LegacyShell {
var PATH: String {
let task = Process()

View File

@ -8,8 +8,8 @@
import Cocoa
// TODO: Enable this to see where deprecations and replacements are needed.
// @available(*, deprecated, message: "Use the new replacement `NxtShell` instead")
public class Shell {
// @available(*, deprecated, message: "Use the new replacement `Shell` instead")
public class LegacyShell {
// MARK: - Invoke static functions
@ -17,14 +17,14 @@ public class Shell {
_ command: String,
requiresPath: Bool = false
) {
Shell.user.run(command, requiresPath: requiresPath)
LegacyShell.user.run(command, requiresPath: requiresPath)
}
public static func pipe(
_ command: String,
requiresPath: Bool = false
) -> String {
return Shell.user.pipe(command, requiresPath: requiresPath)
return LegacyShell.user.pipe(command, requiresPath: requiresPath)
}
// MARK: - Singleton
@ -40,7 +40,7 @@ public class Shell {
/**
Singleton to access a user shell (with --login)
*/
public static let user = Shell()
public static let user = LegacyShell()
/**
Runs a shell command without using the output.
@ -54,7 +54,7 @@ public class Shell {
requiresPath: Bool = false
) {
// Equivalent of piping to /dev/null; don't do anything with the string
_ = Shell.pipe(command, requiresPath: requiresPath)
_ = LegacyShell.pipe(command, requiresPath: requiresPath)
}
/**
@ -85,7 +85,7 @@ public class Shell {
public func executeSynchronously(
_ command: String,
requiresPath: Bool = false
) -> Shell.Output {
) -> LegacyShell.Output {
let outputPipe = Pipe()
let errorPipe = Pipe()
@ -96,7 +96,7 @@ public class Shell {
task.launch()
task.waitUntilExit()
let output = Shell.Output(
let output = LegacyShell.Output(
standardOutput: String(
data: outputPipe.fileHandleForReading.readDataToEndOfFile(),
encoding: .utf8

View File

@ -18,7 +18,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
(invoked by PHP Monitor) shell commands. It is used to
invoke all commands in this application.
*/
let sharedShell: Shell
let sharedShell: LegacyShell
/**
The App singleton contains information about the state of
@ -77,7 +77,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
Log.info("Version \(App.version)")
Log.separator(as: .info)
self.sharedShell = Shell.user
self.sharedShell = LegacyShell.user
self.state = App.shared
self.menu = MainMenu.shared
self.paths = Paths.shared

View File

@ -32,7 +32,7 @@ class AppUpdateChecker {
command = "curl -s --max-time 5"
}
return Shell.pipe(
return LegacyShell.pipe(
"\(command) '\(caskFile)' | grep version"
)
}

View File

@ -24,7 +24,7 @@ class ServicesManager: ObservableObject {
]
DispatchQueue.global(qos: .background).async {
let data = Shell
let data = LegacyShell
.pipe("sudo \(Paths.brew) services info --all --json", requiresPath: true)
.data(using: .utf8)!
@ -44,7 +44,7 @@ class ServicesManager: ObservableObject {
}
DispatchQueue.global(qos: .background).async {
let data = Shell
let data = LegacyShell
.pipe("\(Paths.brew) services info --all --json", requiresPath: true)
.data(using: .utf8)!

View File

@ -115,7 +115,7 @@ class Startup {
// Make sure we can detect one or more PHP installations.
// =================================================================================
EnvironmentCheck(
command: { return !Shell.pipe("ls \(Paths.optPath) | grep php").contains("php") },
command: { return !LegacyShell.pipe("ls \(Paths.optPath) | grep php").contains("php") },
name: "`ls \(Paths.optPath) | grep php` returned php result",
titleText: "startup.errors.php_opt.title".localized,
subtitleText: "startup.errors.php_opt.subtitle".localized(
@ -143,14 +143,14 @@ class Startup {
// functioning correctly. Let the user know that they need to run `valet trust`.
// =================================================================================
EnvironmentCheck(
command: { return !Shell.pipe("cat /private/etc/sudoers.d/brew").contains(Paths.brew) },
command: { return !LegacyShell.pipe("cat /private/etc/sudoers.d/brew").contains(Paths.brew) },
name: "`/private/etc/sudoers.d/brew` contains brew",
titleText: "startup.errors.sudoers_brew.title".localized,
subtitleText: "startup.errors.sudoers_brew.subtitle".localized,
descriptionText: "startup.errors.sudoers_brew.desc".localized
),
EnvironmentCheck(
command: { return !Shell.pipe("cat /private/etc/sudoers.d/valet").contains(Paths.valet) },
command: { return !LegacyShell.pipe("cat /private/etc/sudoers.d/valet").contains(Paths.valet) },
name: "`/private/etc/sudoers.d/valet` contains valet",
titleText: "startup.errors.sudoers_valet.title".localized,
subtitleText: "startup.errors.sudoers_valet.subtitle".localized,
@ -202,7 +202,7 @@ class Startup {
command: {
return App.architecture == "x86_64"
&& FileManager.default.fileExists(atPath: "/usr/local/bin/which")
&& Shell.pipe("which node", requiresPath: false)
&& LegacyShell.pipe("which node", requiresPath: false)
.contains("env: node: No such file or directory")
},
name: "`env: node` issue does not apply",

View File

@ -72,7 +72,7 @@ class AddProxyVC: NSViewController, NSTextFieldDelegate {
App.shared.domainListWindowController?.contentVC.setUIBusy()
DispatchQueue.global(qos: .userInitiated).async {
Shell.run("\(Paths.valet) proxy \(domain) \(proxyName)\(secure)", requiresPath: true)
LegacyShell.run("\(Paths.valet) proxy \(domain) \(proxyName)\(secure)", requiresPath: true)
Actions.restartNginx()
DispatchQueue.main.async {

View File

@ -71,7 +71,7 @@ class AddSiteVC: NSViewController, NSTextFieldDelegate {
// Adding `valet links` is a workaround for Valet malforming the config.json file
// TODO: I will have to investigate and report this behaviour if possible
Shell.run("cd '\(path)' && \(Paths.valet) link '\(name)' && valet links", requiresPath: true)
LegacyShell.run("cd '\(path)' && \(Paths.valet) link '\(name)' && valet links", requiresPath: true)
dismissView(outcome: .OK)

View File

@ -25,11 +25,11 @@ extension DomainListVC {
self.waitAndExecute {
// 1. Remove the original proxy
Shell.run("\(Paths.valet) unproxy \(selectedProxy.domain)", requiresPath: true)
LegacyShell.run("\(Paths.valet) unproxy \(selectedProxy.domain)", requiresPath: true)
// 2. Add a new proxy, which is either secured/unsecured
let secure = originalSecureStatus ? "" : " --secure"
Shell.run("\(Paths.valet) proxy \(selectedProxy.domain) \(selectedProxy.target)\(secure)",
LegacyShell.run("\(Paths.valet) proxy \(selectedProxy.domain) \(selectedProxy.target)\(secure)",
requiresPath: true)
// 3. Restart nginx
@ -50,7 +50,7 @@ extension DomainListVC {
let command = "cd '\(selectedSite.absolutePath)' && sudo \(Paths.valet) \(action) && exit;"
waitAndExecute {
Shell.run(command, requiresPath: true)
LegacyShell.run(command, requiresPath: true)
} completion: { [self] in
selectedSite.determineSecured()
if selectedSite.secured == originalSecureStatus {
@ -100,11 +100,11 @@ extension DomainListVC {
}
@objc func openInFinder() {
Shell.run("open '\(selectedSite!.absolutePath)'")
LegacyShell.run("open '\(selectedSite!.absolutePath)'")
}
@objc func openInTerminal() {
Shell.run("open -b com.apple.terminal '\(selectedSite!.absolutePath)'")
LegacyShell.run("open -b com.apple.terminal '\(selectedSite!.absolutePath)'")
}
@objc func openWithEditor(sender: EditorMenuItem) {
@ -157,7 +157,7 @@ extension DomainListVC {
style: .critical,
onFirstButtonPressed: {
self.waitAndExecute {
Shell.run("valet unlink '\(site.name)'", requiresPath: true)
LegacyShell.run("valet unlink '\(site.name)'", requiresPath: true)
} completion: {
self.reloadDomains()
}
@ -179,7 +179,7 @@ extension DomainListVC {
style: .critical,
onFirstButtonPressed: {
self.waitAndExecute {
Shell.run("valet unproxy '\(proxy.domain)'", requiresPath: true)
LegacyShell.run("valet unproxy '\(proxy.domain)'", requiresPath: true)
} completion: {
self.reloadDomains()
}
@ -191,7 +191,7 @@ extension DomainListVC {
let rowToReload = tableView.selectedRow
waitAndExecute {
Shell.run(command, requiresPath: true)
LegacyShell.run(command, requiresPath: true)
} completion: { [self] in
beforeCellReload()
tableView.reloadData(forRowIndexes: [rowToReload], columnIndexes: [0, 1, 2, 3, 4])

View File

@ -43,7 +43,7 @@ class ComposerWindow {
window?.setType(info: true)
DispatchQueue.global(qos: .userInitiated).async { [self] in
let task = Shell.user.createTask(
let task = LegacyShell.user.createTask(
for: "\(Paths.composer!) global update", requiresPath: true
)

View File

@ -14,7 +14,7 @@ class HomebrewDiagnostics {
Determines the Homebrew taps the user has installed.
*/
public static var installedTaps: [String] = {
return Shell
return LegacyShell
.pipe("\(Paths.brew) tap")
.split(separator: "\n")
.map { string in
@ -75,7 +75,7 @@ class HomebrewDiagnostics {
Check if the alias conflict as documented in `checkForCaskConflict` actually occurred.
*/
private static func hasAliasConflict() -> Bool {
let tapAlias = Shell.pipe("\(Paths.brew) info shivammathur/php/php --json")
let tapAlias = LegacyShell.pipe("\(Paths.brew) info shivammathur/php/php --json")
if tapAlias.contains("brew tap shivammathur/php") || tapAlias.contains("Error") {
Log.info("The user does not appear to have tapped: shivammathur/php")
@ -134,7 +134,7 @@ class HomebrewDiagnostics {
public static func cannotLoadService(_ name: String = "nginx") -> Bool {
let serviceInfo = try? JSONDecoder().decode(
[HomebrewService].self,
from: Shell.pipe(
from: LegacyShell.pipe(
"sudo \(Paths.brew) services info \(name) --json",
requiresPath: true
).data(using: .utf8)!

View File

@ -44,7 +44,7 @@ struct CustomPrefs: Decodable {
extension Preferences {
func loadCustomPreferences() {
// Ensure the configuration directory is created if missing
Shell.run("mkdir -p ~/.config/phpmon")
LegacyShell.run("mkdir -p ~/.config/phpmon")
// Move the legacy file
moveOutdatedConfigurationFile()
@ -63,7 +63,7 @@ extension Preferences {
func moveOutdatedConfigurationFile() {
if Filesystem.fileExists("~/.phpmon.conf.json") && !Filesystem.fileExists("~/.config/phpmon/config.json") {
Log.info("An outdated configuration file was found. Moving it...")
Shell.run("cp ~/.phpmon.conf.json ~/.config/phpmon/config.json")
LegacyShell.run("cp ~/.phpmon.conf.json ~/.config/phpmon/config.json")
Log.info("The configuration file was copied successfully!")
}
}
@ -87,7 +87,7 @@ extension Preferences {
if customPreferences.hasEnvironmentVariables() {
Log.info("Configuring the additional exports...")
Shell.user.exports = customPreferences.getEnvironmentVariables()
LegacyShell.user.exports = customPreferences.getEnvironmentVariables()
}
} catch {
Log.warn("The ~/.config/phpmon/config.json file seems to be missing or malformed.")

View File

@ -260,7 +260,7 @@ struct Preset: Codable, Equatable {
private func persistRevert() {
let data = try! JSONEncoder().encode(self.revertSnapshot)
Shell.run("mkdir -p ~/.config/phpmon")
LegacyShell.run("mkdir -p ~/.config/phpmon")
try! String(data: data, encoding: .utf8)!
.write(

View File

@ -22,7 +22,7 @@ class WarningManager {
public let evaluations: [Warning] = [
Warning(
command: {
return Shell.pipe("sysctl -n sysctl.proc_translated")
return LegacyShell.pipe("sysctl -n sysctl.proc_translated")
.trimmingCharacters(in: .whitespacesAndNewlines) == "1"
},
name: "Running PHP Monitor with Rosetta on M1",
@ -32,7 +32,7 @@ class WarningManager {
),
Warning(
command: {
return !Shell.user.PATH.contains("\(Paths.homePath)/.config/phpmon/bin") &&
return !LegacyShell.user.PATH.contains("\(Paths.homePath)/.config/phpmon/bin") &&
!FileManager.default.isWritableFile(atPath: "/usr/local/bin/")
},
name: "Helpers cannot be symlinked and not in PATH",

View File

@ -8,7 +8,11 @@
import Foundation
class NxtShell {
var Shell: Shellable {
return ActiveShell.shared
}
class ActiveShell {
static var shared: Shellable = SystemShell()
/// Uses a testable shell with predefined responses. You specify the terminal's output.

View File

@ -9,7 +9,9 @@
import Foundation
protocol Shellable {
// TODO: Rework this so it supports listening for updates (when piping) and
func syncPipe(_ command: String) -> String
func pipe(_ command: String) async -> String
typealias Output = String
func syncPipe(_ command: String) -> Output
func pipe(_ command: String) async -> Output
}