mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 12:00:09 +02:00
♻️ WIP: Parsing logic for configuration file
This commit is contained in:
@ -118,8 +118,8 @@
|
||||
C464ADB0275A7A6A003FCD53 /* DomainListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADAE275A7A69003FCD53 /* DomainListVC.swift */; };
|
||||
C464ADB2275A87CA003FCD53 /* DomainListCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */; };
|
||||
C46FA23F246C358E00944F05 /* StringExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA23E246C358E00944F05 /* StringExtension.swift */; };
|
||||
C46FA9882822EFDC00D78807 /* PhpInitializationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA9872822EFDC00D78807 /* PhpInitializationFile.swift */; };
|
||||
C46FA9892822EFDC00D78807 /* PhpInitializationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA9872822EFDC00D78807 /* PhpInitializationFile.swift */; };
|
||||
C46FA9882822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */; };
|
||||
C46FA9892822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */; };
|
||||
C46FA98C2822F08F00D78807 /* PhpIniTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C46FA98A2822F08F00D78807 /* PhpIniTest.swift */; };
|
||||
C473319F2470923A009A0597 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = C473319E2470923A009A0597 /* Localizable.strings */; };
|
||||
C47331A2247093B7009A0597 /* StatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = C47331A1247093B7009A0597 /* StatusMenu.swift */; };
|
||||
@ -341,7 +341,7 @@
|
||||
C464ADAE275A7A69003FCD53 /* DomainListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListVC.swift; sourceTree = "<group>"; };
|
||||
C464ADB1275A87CA003FCD53 /* DomainListCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DomainListCellProtocol.swift; sourceTree = "<group>"; };
|
||||
C46FA23E246C358E00944F05 /* StringExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtension.swift; sourceTree = "<group>"; };
|
||||
C46FA9872822EFDC00D78807 /* PhpInitializationFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpInitializationFile.swift; sourceTree = "<group>"; };
|
||||
C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpConfigurationFile.swift; sourceTree = "<group>"; };
|
||||
C46FA98A2822F08F00D78807 /* PhpIniTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhpIniTest.swift; sourceTree = "<group>"; };
|
||||
C473319E2470923A009A0597 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
C47331A1247093B7009A0597 /* StatusMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusMenu.swift; sourceTree = "<group>"; };
|
||||
@ -466,7 +466,7 @@
|
||||
C41C1B4A22B019FF00E7CF16 /* ActivePhpInstallation.swift */,
|
||||
C4F2E4392752F7D00020E974 /* PhpInstallation.swift */,
|
||||
C4ACA38E25C754C100060C66 /* PhpExtension.swift */,
|
||||
C46FA9872822EFDC00D78807 /* PhpInitializationFile.swift */,
|
||||
C46FA9872822EFDC00D78807 /* PhpConfigurationFile.swift */,
|
||||
);
|
||||
path = PHP;
|
||||
sourceTree = "<group>";
|
||||
@ -1132,7 +1132,7 @@
|
||||
C48D6C70279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */,
|
||||
C4B585412770FE3900DA4FBE /* Shell.swift in Sources */,
|
||||
C4998F0A2617633900B2526E /* PrefsWC.swift in Sources */,
|
||||
C46FA9882822EFDC00D78807 /* PhpInitializationFile.swift in Sources */,
|
||||
C46FA9882822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */,
|
||||
C4F8C0A422D4F12C002EFE61 /* DateExtension.swift in Sources */,
|
||||
C4AF9F7A2754499000D44ED0 /* Valet.swift in Sources */,
|
||||
C4C0E8EA27F88B80002D32A9 /* ValetProxy+Fake.swift in Sources */,
|
||||
@ -1340,7 +1340,7 @@
|
||||
C44CCD4A27AFF3BC00CE40E5 /* MainMenu+Async.swift in Sources */,
|
||||
C449B4F327EE7FC600C47E8A /* DomainListTypeCell.swift in Sources */,
|
||||
C48D6C71279CD2AC00F26D7E /* PhpVersionNumber.swift in Sources */,
|
||||
C46FA9892822EFDC00D78807 /* PhpInitializationFile.swift in Sources */,
|
||||
C46FA9892822EFDC00D78807 /* PhpConfigurationFile.swift in Sources */,
|
||||
C41C02AB27E61CB3009F26CB /* ValetSite+Fake.swift in Sources */,
|
||||
C4F780C925D80B75000DBC97 /* StringExtension.swift in Sources */,
|
||||
C4D9F24C280B69E100DCD39A /* AddProxyVC.swift in Sources */,
|
||||
|
@ -20,7 +20,7 @@ class ActivePhpInstallation {
|
||||
|
||||
var version: Version!
|
||||
var limits: Limits!
|
||||
var iniFiles: [PhpInitializationFile] = []
|
||||
var iniFiles: [PhpConfigurationFile] = []
|
||||
|
||||
var extensions: [PhpExtension] {
|
||||
return iniFiles.flatMap { initFile in
|
||||
@ -53,7 +53,7 @@ class ActivePhpInstallation {
|
||||
let mainConfigurationFileUrl = URL(fileURLWithPath: "\(Paths.etcPath)/php/\(version.short)/php.ini")
|
||||
|
||||
iniFiles.append(
|
||||
PhpInitializationFile(fileUrl: mainConfigurationFileUrl)
|
||||
PhpConfigurationFile(fileUrl: mainConfigurationFileUrl)
|
||||
)
|
||||
|
||||
// extensions.append(contentsOf: PhpExtension.load(from: mainConfigurationFileUrl))
|
||||
@ -76,7 +76,7 @@ class ActivePhpInstallation {
|
||||
let fileUrl = URL(fileURLWithPath: iniFilePath)
|
||||
|
||||
iniFiles.append(
|
||||
PhpInitializationFile(fileUrl: fileUrl)
|
||||
PhpConfigurationFile(fileUrl: fileUrl)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
128
phpmon/Common/PHP/PhpConfigurationFile.swift
Normal file
128
phpmon/Common/PHP/PhpConfigurationFile.swift
Normal file
@ -0,0 +1,128 @@
|
||||
//
|
||||
// PhpInitFile.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 04/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PhpConfigurationFile {
|
||||
|
||||
typealias Section = [String: String]
|
||||
typealias Config = [String: Section]
|
||||
|
||||
/// The file where this configuration file was located.
|
||||
let file: String
|
||||
|
||||
/// The extensions found in this .ini file.
|
||||
let extensions: [PhpExtension]
|
||||
|
||||
/// The actual content of the configuration file.
|
||||
var content: Config
|
||||
|
||||
init(fileUrl: URL) {
|
||||
self.file = fileUrl.path
|
||||
|
||||
let rawString = (try? String(contentsOf: fileUrl, encoding: .utf8)) ?? ""
|
||||
|
||||
self.extensions = PhpExtension.load(from: fileUrl)
|
||||
|
||||
self.content = Self.parseConfig(from: rawString.components(separatedBy: "\n"))
|
||||
|
||||
dump(self)
|
||||
}
|
||||
|
||||
// MARK: Parsing Logic
|
||||
// Slightly modified from: https://gist.github.com/jetmind/f776c0d223e4ac6aec1ff9389e874553
|
||||
|
||||
/**
|
||||
Attempts to parse the configuration file, based on an array of strings.
|
||||
Each string is a line from the configuration file.
|
||||
*/
|
||||
private static func parseConfig(from lines: [String]) -> Config {
|
||||
var config = Config()
|
||||
var currentSectionName = "main"
|
||||
for line in lines {
|
||||
let line = trim(line)
|
||||
if line.hasPrefix("[") && line.hasSuffix("]") {
|
||||
currentSectionName = parseSectionHeader(line)
|
||||
} else if let (key, value) = parseLine(line) {
|
||||
var section = config[currentSectionName] ?? [:]
|
||||
section[key] = value
|
||||
config[currentSectionName] = section
|
||||
}
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
/**
|
||||
Remove all whitespace and additional characters from individual lines.
|
||||
*/
|
||||
private static func trim(_ s: String) -> String {
|
||||
let whitespaces = CharacterSet(charactersIn: " \n\r\t")
|
||||
return s.trimmingCharacters(in: whitespaces)
|
||||
}
|
||||
|
||||
/**
|
||||
It may prove beneficial to strip all comments, which can start with # or ;.
|
||||
In this case, strip both.
|
||||
*/
|
||||
private static func stripComment(_ line: String) -> String {
|
||||
var line = line
|
||||
|
||||
let characters: [String.Element] = ["#", ";"]
|
||||
|
||||
for character in characters {
|
||||
// Only keep checking for comments as long as the line isn't empty
|
||||
if line.isEmpty {
|
||||
return line
|
||||
}
|
||||
|
||||
// Check for the next comment character
|
||||
line = strip(character: character, line)
|
||||
}
|
||||
|
||||
return line
|
||||
}
|
||||
|
||||
/**
|
||||
Empties a line if it happens to be commented out, causing it to be ignored.
|
||||
*/
|
||||
private static func strip(character: String.Element, _ line: String) -> String {
|
||||
let parts = line.split(
|
||||
separator: character,
|
||||
maxSplits: 1,
|
||||
omittingEmptySubsequences: false
|
||||
)
|
||||
if !parts.isEmpty {
|
||||
return String(parts[0])
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to parse a section header. Requires the line to start with [ and end with ].
|
||||
*/
|
||||
private static func parseSectionHeader(_ line: String) -> String {
|
||||
let from = line.index(after: line.startIndex)
|
||||
let to = line.index(before: line.endIndex)
|
||||
return line[from..<to]
|
||||
}
|
||||
|
||||
/**
|
||||
Attempts to parse a regular line, which may contain a configuration value that is being set.
|
||||
*/
|
||||
private static func parseLine(_ line: String) -> (String, String)? {
|
||||
let parts = stripComment(line)
|
||||
.split(separator: "=", maxSplits: 1)
|
||||
if parts.count == 2 {
|
||||
let k = trim(String(parts[0]))
|
||||
let v = trim(String(parts[1]))
|
||||
return (k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
//
|
||||
// PhpInitFile.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 04/05/2022.
|
||||
// Copyright © 2022 Nico Verbruggen. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class PhpInitializationFile {
|
||||
|
||||
/// The file where this extension was located.
|
||||
let file: String
|
||||
|
||||
/// The original string contained within the file when scanned.
|
||||
let raw: [String]
|
||||
|
||||
/// The extensions found in this .ini file.
|
||||
let extensions: [PhpExtension]
|
||||
|
||||
init(fileUrl: URL) {
|
||||
self.file = fileUrl.path
|
||||
|
||||
let rawString = (try? String(contentsOf: fileUrl, encoding: .utf8)) ?? ""
|
||||
|
||||
self.raw = rawString.components(separatedBy: "\n")
|
||||
|
||||
self.extensions = PhpExtension.load(from: fileUrl)
|
||||
|
||||
dump(self)
|
||||
|
||||
// TODO: Actually parse the .ini file
|
||||
// Parsing the file could be done like this gist:
|
||||
// https://gist.github.com/jetmind/f776c0d223e4ac6aec1ff9389e874553
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user