From 66393094b0f49051ad9d44240fc1db6ce6f0b711 Mon Sep 17 00:00:00 2001 From: Nico Verbruggen Date: Tue, 24 Jan 2023 19:47:28 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Correctly=20parse=20.valetrc=20file?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PHP Monitor.xcodeproj/project.pbxproj | 34 +++++++++---- .../Domain/Integrations/Common/RCFile.swift | 48 +++++++++++++++++++ .../Integrations/Valet/Sites/ValetSite.swift | 28 +++++++---- tests/unit/Parsers/ValetRcTest.swift | 34 ++++++++++--- .../{valetrc_broken.rc => valetrc.broken} | 0 tests/unit/Test Files/valet/valetrc.rc | 3 -- tests/unit/Test Files/valet/valetrc.valid | 6 +++ 7 files changed, 127 insertions(+), 26 deletions(-) create mode 100644 phpmon/Domain/Integrations/Common/RCFile.swift rename tests/unit/Test Files/valet/{valetrc_broken.rc => valetrc.broken} (100%) delete mode 100644 tests/unit/Test Files/valet/valetrc.rc create mode 100644 tests/unit/Test Files/valet/valetrc.valid diff --git a/PHP Monitor.xcodeproj/project.pbxproj b/PHP Monitor.xcodeproj/project.pbxproj index ffd5963..583f332 100644 --- a/PHP Monitor.xcodeproj/project.pbxproj +++ b/PHP Monitor.xcodeproj/project.pbxproj @@ -118,6 +118,10 @@ C44067FB27E25FD70045BD4E /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; }; C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */; }; C44264C02850BD2A007400F1 /* VersionPopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */; }; + C4463FCC29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; }; + C4463FCD29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; }; + C4463FCE29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; }; + C4463FCF29804BCB007B93D5 /* RCFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4463FCB29804BCB007B93D5 /* RCFile.swift */; }; C449B4F027EE7FB800C47E8A /* DomainListTLSCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */; }; C449B4F127EE7FC200C47E8A /* DomainListNameCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F427E2582B0045BD4E /* DomainListNameCell.swift */; }; C449B4F227EE7FC400C47E8A /* DomainListPhpCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C44067F627E258410045BD4E /* DomainListPhpCell.swift */; }; @@ -144,8 +148,8 @@ C451AFF82969E40F0078E617 /* HelpButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C451AFF52969E40F0078E617 /* HelpButton.swift */; }; C451AFF92969E40F0078E617 /* HelpButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C451AFF52969E40F0078E617 /* HelpButton.swift */; }; C4551657297AED18009B8466 /* ValetRcTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C4551656297AED18009B8466 /* ValetRcTest.swift */; }; - C4551659297AED7D009B8466 /* valetrc.rc in Resources */ = {isa = PBXBuildFile; fileRef = C4551658297AED7D009B8466 /* valetrc.rc */; }; - C455165B297AEDB5009B8466 /* valetrc_broken.rc in Resources */ = {isa = PBXBuildFile; fileRef = C455165A297AEDB5009B8466 /* valetrc_broken.rc */; }; + C4551659297AED7D009B8466 /* valetrc.valid in Resources */ = {isa = PBXBuildFile; fileRef = C4551658297AED7D009B8466 /* valetrc.valid */; }; + C455165B297AEDB5009B8466 /* valetrc.broken in Resources */ = {isa = PBXBuildFile; fileRef = C455165A297AEDB5009B8466 /* valetrc.broken */; }; C4570C3A28FC355300D18420 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473319E2470923A009A0597 /* Localizable.strings */; }; C4570C3B28FC355300D18420 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473319E2470923A009A0597 /* Localizable.strings */; }; C4570C3C28FC355400D18420 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473319E2470923A009A0597 /* Localizable.strings */; }; @@ -799,6 +803,7 @@ C44067FA27E25FD70045BD4E /* DomainListTLSCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DomainListTLSCell.swift; sourceTree = ""; }; C44264BD2850B86C007400F1 /* SwiftUIHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIHelper.swift; sourceTree = ""; }; C44264BF2850BD2A007400F1 /* VersionPopoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionPopoverView.swift; sourceTree = ""; }; + C4463FCB29804BCB007B93D5 /* RCFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RCFile.swift; sourceTree = ""; }; C44A874728905BB000498BC4 /* ProgressVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressVC.swift; sourceTree = ""; }; C44AD3F62912EF7100997FF4 /* RealFileSystemTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealFileSystemTest.swift; sourceTree = ""; }; C44B3A4528E5C70100718CB1 /* TimeIntervalExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeIntervalExtension.swift; sourceTree = ""; }; @@ -810,8 +815,8 @@ C450C8C528C919EC002A2B4B /* PreferenceName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceName.swift; sourceTree = ""; }; C451AFF52969E40F0078E617 /* HelpButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpButton.swift; sourceTree = ""; }; C4551656297AED18009B8466 /* ValetRcTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetRcTest.swift; sourceTree = ""; }; - C4551658297AED7D009B8466 /* valetrc.rc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = valetrc.rc; sourceTree = ""; }; - C455165A297AEDB5009B8466 /* valetrc_broken.rc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = valetrc_broken.rc; sourceTree = ""; }; + C4551658297AED7D009B8466 /* valetrc.valid */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = valetrc.valid; sourceTree = ""; }; + C455165A297AEDB5009B8466 /* valetrc.broken */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = valetrc.broken; sourceTree = ""; }; C459B4BC27F6093700E9B4B4 /* nginx-proxy.test */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "nginx-proxy.test"; sourceTree = ""; }; C45B9148295607F400F4EC78 /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = ""; }; C45B914D295608E300F4EC78 /* ValetServicesManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValetServicesManager.swift; sourceTree = ""; }; @@ -1232,6 +1237,14 @@ path = Cells; sourceTree = ""; }; + C4463FD029804C13007B93D5 /* Common */ = { + isa = PBXGroup; + children = ( + C4463FCB29804BCB007B93D5 /* RCFile.swift */, + ); + path = Common; + sourceTree = ""; + }; C44A874628905B8500498BC4 /* Onboarding */ = { isa = PBXGroup; children = ( @@ -1293,8 +1306,8 @@ C459B4C027F6096300E9B4B4 /* valet */ = { isa = PBXGroup; children = ( - C455165A297AEDB5009B8466 /* valetrc_broken.rc */, - C4551658297AED7D009B8466 /* valetrc.rc */, + C455165A297AEDB5009B8466 /* valetrc.broken */, + C4551658297AED7D009B8466 /* valetrc.valid */, C4AF9F70275445FF00D44ED0 /* valet-config.json */, ); path = valet; @@ -1441,6 +1454,7 @@ C4AF9F6B275445D300D44ED0 /* Integrations */ = { isa = PBXGroup; children = ( + C4463FD029804C13007B93D5 /* Common */, C4C0E8DA27F887CC002D32A9 /* Nginx */, C4D89BC42783C98800A02B68 /* Composer */, C4AF9F6C275445D900D44ED0 /* Homebrew */, @@ -1929,7 +1943,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - C4551659297AED7D009B8466 /* valetrc.rc in Resources */, + C4551659297AED7D009B8466 /* valetrc.valid in Resources */, C4570C3C28FC355400D18420 /* Localizable.strings in Resources */, 54FCFD27276C883F004CE748 /* SelectPreferenceView.xib in Resources */, 54FCFD2E276C8D67004CE748 /* HotkeyPreferenceView.xib in Resources */, @@ -1943,7 +1957,7 @@ C44C1992276E44CB0072762D /* ProgressWindow.storyboard in Resources */, C42F26762805FEE200938AC7 /* nginx-secure-proxy.test in Resources */, C4F30B08278E195800755FCE /* brew-services.json in Resources */, - C455165B297AEDB5009B8466 /* valetrc_broken.rc in Resources */, + C455165B297AEDB5009B8466 /* valetrc.broken in Resources */, 54A18D40282A566E000A0D81 /* nginx-secure-proxy-custom-tld.test in Resources */, C42CFB1627DFDE7900862737 /* nginx-site.test in Resources */, C459B4BD27F6093700E9B4B4 /* nginx-proxy.test in Resources */, @@ -2020,6 +2034,7 @@ C4E2E85C28FC282B003B070C /* TestableConfiguration.swift in Sources */, C4C0E8DF27F88AEB002D32A9 /* FakeDomainScanner.swift in Sources */, C44B3A4628E5C70100718CB1 /* TimeIntervalExtension.swift in Sources */, + C4463FCC29804BCB007B93D5 /* RCFile.swift in Sources */, C44264BE2850B86C007400F1 /* SwiftUIHelper.swift in Sources */, C4E9D2C02878B336008FFDAD /* OnboardingView.swift in Sources */, C4F2E4372752F0870020E974 /* HomebrewDiagnostics.swift in Sources */, @@ -2201,6 +2216,7 @@ C471E86328F9BB650021E251 /* PMTableView.swift in Sources */, C471E86428F9BB650021E251 /* Warning.swift in Sources */, C40175BA2903108900763A68 /* ValetInteractor.swift in Sources */, + C4463FCE29804BCB007B93D5 /* RCFile.swift in Sources */, C45B9150295608E300F4EC78 /* ValetServicesManager.swift in Sources */, C471E86528F9BB650021E251 /* WarningManager.swift in Sources */, C471E86628F9BB650021E251 /* WarningsWindowController.swift in Sources */, @@ -2433,6 +2449,7 @@ C4D3660E29113F20006BD146 /* System.swift in Sources */, C471E80428F9BAD40021E251 /* PhpExtension.swift in Sources */, C471E7F728F9BACB0021E251 /* PhpSwitcher.swift in Sources */, + C4463FCF29804BCB007B93D5 /* RCFile.swift in Sources */, C471E82C28F9BB340021E251 /* ValetListable.swift in Sources */, C471E82828F9BB310021E251 /* HomebrewDiagnostics.swift in Sources */, C471E81E28F9BB260021E251 /* BetterAlert.swift in Sources */, @@ -2614,6 +2631,7 @@ C44AD3F72912EF7100997FF4 /* RealFileSystemTest.swift in Sources */, C4F30B0A278E1A1A00755FCE /* ComposerJson.swift in Sources */, C4C0E8E027F88AEB002D32A9 /* FakeDomainScanner.swift in Sources */, + C4463FCD29804BCB007B93D5 /* RCFile.swift in Sources */, C4AF9F7D275454A900D44ED0 /* ValetVersionExtractorTest.swift in Sources */, C4B56362276AB0A500F12CCB /* VersionExtractorTest.swift in Sources */, C4B585452770FE3900DA4FBE /* RealCommand.swift in Sources */, diff --git a/phpmon/Domain/Integrations/Common/RCFile.swift b/phpmon/Domain/Integrations/Common/RCFile.swift new file mode 100644 index 0000000..52a34e4 --- /dev/null +++ b/phpmon/Domain/Integrations/Common/RCFile.swift @@ -0,0 +1,48 @@ +// +// RCFile.swift +// PHP Monitor +// +// Created by Nico Verbruggen on 24/01/2023. +// Copyright © 2023 Nico Verbruggen. All rights reserved. +// + +import Foundation + +struct RCFile { + let path: String? + let fields: [String: String] + + static func fromPath(_ path: String) -> RCFile? { + do { + let text = try String(contentsOf: URL(fileURLWithPath: path), encoding: .utf8) + return RCFile(path: path, contents: text) + } catch { + return nil + } + } + + init(path: String? = nil, contents: String) { + var fields: [String: String] = [:] + + contents + .split(separator: "\n") + .forEach({ line in + if line.contains("=") { + let content = line.split(separator: "=") + let key = String(content[0]) + .trimmingCharacters(in: .whitespaces) + .replacingOccurrences(of: "\"", with: "") + if key.starts(with: "#") { + return + } + let value = String(content[1]) + .trimmingCharacters(in: .whitespaces) + .replacingOccurrences(of: "\"", with: "") + fields[key] = value + } + }) + + self.path = path + self.fields = fields + } +} diff --git a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift index d0742e7..3baa650 100644 --- a/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift +++ b/phpmon/Domain/Integrations/Valet/Sites/ValetSite.swift @@ -207,19 +207,20 @@ class ValetSite: ValetListable { } /** - Checks the contents of the .valetphprc file and determine the version, if possible. + Checks the contents of the .valetphprc file and determine the version. + The first file found takes precendence over all others. */ private func determineValetPhpFileInfo() { let files = [ - (".valetphprc", VersionSource.valetphprc), - (".valetrc", VersionSource.valetrc) + (".valetrc", VersionSource.valetrc), + (".valetphprc", VersionSource.valetphprc) ] for (suffix, source) in files { do { let path = "\(absolutePath)/\(suffix)" if FileSystem.fileExists(path) { - try self.handleValetFile(path, source) + return try self.handleValetFile(path, source) } } catch { Log.err("Something went wrong parsing the '\(suffix)' file") @@ -239,7 +240,7 @@ class ValetSite: ValetListable { self.composerPhpSource = source } case .valetrc: - self.parseValetRcFile(contents) + self.parseValetRcFile(path, contents) default: return } @@ -248,9 +249,20 @@ class ValetSite: ValetListable { /** Specifically extract PHP information from a .valetrc file. */ - private func parseValetRcFile(_ text: String) { - // TODO: Implement this - fatalError("A .valetrc file was found, needs to be parsed!") + private func parseValetRcFile(_ path: String, _ text: String) { + let valetRc = RCFile(path: path, contents: text) + + guard let versionString = valetRc.fields["PHP"] else { + if valetRc.path != nil { + Log.perf("\(self.name)'s .valetrc file at '\(valetRc.path!)' lacks a 'PHP' entry.") + } + return + } + + if let version = VersionExtractor.from(versionString) { + self.composerPhp = version + self.composerPhpSource = .valetrc + } } // MARK: - File Parsing diff --git a/tests/unit/Parsers/ValetRcTest.swift b/tests/unit/Parsers/ValetRcTest.swift index 222b91a..a89c028 100644 --- a/tests/unit/Parsers/ValetRcTest.swift +++ b/tests/unit/Parsers/ValetRcTest.swift @@ -12,19 +12,39 @@ class ValetRcTest: XCTestCase { // MARK: - Test Files - static var path: URL { + static var validPath: URL { return Bundle(for: Self.self) - .url(forResource: "valetrc", withExtension: "rc")! + .url(forResource: "valetrc", withExtension: "valid")! } + static var brokenPath: URL { + return Bundle(for: Self.self) + .url(forResource: "valetrc", withExtension: "broken")! + } + + // MARK: - Tests func test_can_extract_fields_from_valetrc_file() throws { - // TODO: Load the path and get the fields - } + let fakeFile = RCFile.fromPath("/Users/fake/file.rc") + XCTAssertNil(fakeFile) - func test_skip_invalid_fields_valetrc_file() throws { - // TODO: Load the path and throw error - } + // Can parse the file + let validFile = RCFile.fromPath(ValetRcTest.validPath.path) + XCTAssertNotNil(validFile) + let fields = validFile!.fields + + // Correctly parses and trims (and omits double quotes) per line + XCTAssertEqual(fields["PHP"], "php@8.2") + XCTAssertEqual(fields["OTHER"], "thing") + XCTAssertEqual(fields["PHPMON_WATCH"], "true") + XCTAssertEqual(fields["SYNTAX"], "variable") + + // Ignores entries prefixed with # + XCTAssertTrue(!fields.keys.contains("#PHP")) + + // Ignores invalid lines + XCTAssertTrue(!fields.keys.contains("OOF")) + } } diff --git a/tests/unit/Test Files/valet/valetrc_broken.rc b/tests/unit/Test Files/valet/valetrc.broken similarity index 100% rename from tests/unit/Test Files/valet/valetrc_broken.rc rename to tests/unit/Test Files/valet/valetrc.broken diff --git a/tests/unit/Test Files/valet/valetrc.rc b/tests/unit/Test Files/valet/valetrc.rc deleted file mode 100644 index 8e9c64b..0000000 --- a/tests/unit/Test Files/valet/valetrc.rc +++ /dev/null @@ -1,3 +0,0 @@ -PHP=php@8.2 -OTHER=thing -PHPMON_WATCH=true \ No newline at end of file diff --git a/tests/unit/Test Files/valet/valetrc.valid b/tests/unit/Test Files/valet/valetrc.valid new file mode 100644 index 0000000..1ac4bcd --- /dev/null +++ b/tests/unit/Test Files/valet/valetrc.valid @@ -0,0 +1,6 @@ +PHP=php@8.2 +#PHP=php +OTHER=thing +PHPMON_WATCH=true +SYNTAX = "variable" +OOF:NICE