mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 20:10:08 +02:00
✨ Allow replacing of config values
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// PhpIniTest.swift
|
// PhpConfigurationTest.swift
|
||||||
// PHP Monitor
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 04/05/2022.
|
// Created by Nico Verbruggen on 04/05/2022.
|
||||||
@ -40,12 +40,45 @@ class PhpConfigurationTest: XCTestCase {
|
|||||||
XCTAssert(iniFile.get(for: "display_errors") == "On")
|
XCTAssert(iniFile.get(for: "display_errors") == "On")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCanSwapConfigurationValue() throws {
|
func testCanCustomizeConfigurationValue() throws {
|
||||||
let destination = Utility.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
let destination = Utility
|
||||||
|
.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
||||||
|
|
||||||
let configurationFile = PhpConfigurationFile.from(filePath: destination.path)
|
let configurationFile = PhpConfigurationFile
|
||||||
|
.from(filePath: destination.path)!
|
||||||
|
|
||||||
XCTAssertNotNil(configurationFile)
|
// 0. Verify the original value
|
||||||
|
XCTAssertEqual(configurationFile.get(for: "error_reporting"), "E_ALL")
|
||||||
|
|
||||||
|
// 1. Change the value
|
||||||
|
try! configurationFile.replace(
|
||||||
|
key: "error_reporting",
|
||||||
|
value: "E_ALL & ~E_DEPRECATED & ~E_STRICT"
|
||||||
|
)
|
||||||
|
XCTAssertEqual(
|
||||||
|
configurationFile.get(for: "error_reporting"),
|
||||||
|
"E_ALL & ~E_DEPRECATED & ~E_STRICT"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 2. Ensure that same key and value doesn't break subsequent saves
|
||||||
|
try! configurationFile.replace(
|
||||||
|
key: "error_reporting",
|
||||||
|
value: "error_reporting"
|
||||||
|
)
|
||||||
|
XCTAssertEqual(
|
||||||
|
configurationFile.get(for: "error_reporting"),
|
||||||
|
"error_reporting"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 3. Verify subsequent saves weren't broken
|
||||||
|
try! configurationFile.replace(
|
||||||
|
key: "error_reporting",
|
||||||
|
value: "E_ALL"
|
||||||
|
)
|
||||||
|
XCTAssertEqual(
|
||||||
|
configurationFile.get(for: "error_reporting"),
|
||||||
|
"E_ALL"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//
|
//
|
||||||
// PhpInitFile.swift
|
// PhpConfigurationFile.swift
|
||||||
// PHP Monitor
|
// PHP Monitor
|
||||||
//
|
//
|
||||||
// Created by Nico Verbruggen on 04/05/2022.
|
// Created by Nico Verbruggen on 04/05/2022.
|
||||||
@ -10,18 +10,26 @@ import Foundation
|
|||||||
|
|
||||||
class PhpConfigurationFile: CreatedFromFile {
|
class PhpConfigurationFile: CreatedFromFile {
|
||||||
|
|
||||||
typealias Section = [String: String]
|
struct ConfigValue {
|
||||||
|
let lineIndex: Int
|
||||||
|
let value: String
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias Section = [String: ConfigValue]
|
||||||
typealias Config = [String: Section]
|
typealias Config = [String: Section]
|
||||||
|
|
||||||
/// The file where this configuration file was located.
|
/// The file where this configuration file was located.
|
||||||
let file: String
|
let filePath: String
|
||||||
|
|
||||||
/// The extensions found in this .ini file.
|
/// The extensions found in this .ini file.
|
||||||
let extensions: [PhpExtension]
|
var extensions: [PhpExtension]
|
||||||
|
|
||||||
/// The actual content of the configuration file.
|
/// The actual, structured content of the configuration file.
|
||||||
var content: Config
|
var content: Config
|
||||||
|
|
||||||
|
/// The original lines of the file.
|
||||||
|
var lines: [String]
|
||||||
|
|
||||||
/** Resolves a PHP configuration file (.ini) */
|
/** Resolves a PHP configuration file (.ini) */
|
||||||
static func from(filePath: String) -> Self? {
|
static func from(filePath: String) -> Self? {
|
||||||
let path = filePath.replacingOccurrences(
|
let path = filePath.replacingOccurrences(
|
||||||
@ -43,10 +51,8 @@ class PhpConfigurationFile: CreatedFromFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
required init(path: String, contents: String) {
|
required init(path: String, contents: String) {
|
||||||
self.file = path
|
self.filePath = path
|
||||||
|
self.lines = contents.components(separatedBy: "\n")
|
||||||
let lines = contents.components(separatedBy: "\n")
|
|
||||||
|
|
||||||
self.extensions = PhpExtension.from(lines, filePath: path)
|
self.extensions = PhpExtension.from(lines, filePath: path)
|
||||||
self.content = Self.parseConfig(lines: lines)
|
self.content = Self.parseConfig(lines: lines)
|
||||||
}
|
}
|
||||||
@ -60,16 +66,57 @@ class PhpConfigurationFile: CreatedFromFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func get(for key: String) -> String? {
|
public func get(for key: String) -> String? {
|
||||||
|
return getConfig(for: key)?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getConfig(for key: String) -> ConfigValue? {
|
||||||
for (_, section) in self.content {
|
for (_, section) in self.content {
|
||||||
if section.keys.contains(key) {
|
if section.keys.contains(key) {
|
||||||
return section[key]
|
return section[key]!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func replace(key: String, value: String) {
|
enum ReplacementErrors: Error {
|
||||||
// TODO
|
case missingKey
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Replaces the value for a specific (existing) key with a new value.
|
||||||
|
The key must exist for this to work.
|
||||||
|
*/
|
||||||
|
public func replace(key: String, value: String) throws {
|
||||||
|
// Ensure that the key exists
|
||||||
|
guard let item = getConfig(for: key) else {
|
||||||
|
throw ReplacementErrors.missingKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out what comes after the assignment
|
||||||
|
var components = self
|
||||||
|
.lines[item.lineIndex]
|
||||||
|
.components(separatedBy: "=")
|
||||||
|
|
||||||
|
// Replace the value with the new one
|
||||||
|
components[1] = components[1]
|
||||||
|
.replacingOccurrences(of: item.value, with: value)
|
||||||
|
|
||||||
|
// Replace the specific line
|
||||||
|
self.lines[item.lineIndex] = components.joined(separator: "=")
|
||||||
|
|
||||||
|
// Finally, join the string and save the file atomatically again
|
||||||
|
try self.lines.joined(separator: "\n")
|
||||||
|
.write(toFile: self.filePath, atomically: true, encoding: .utf8)
|
||||||
|
|
||||||
|
// Reload the original file
|
||||||
|
self.reload()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func reload() {
|
||||||
|
self.lines = try! String(contentsOfFile: self.filePath)
|
||||||
|
.components(separatedBy: "\n")
|
||||||
|
self.extensions = PhpExtension.from(lines, filePath: self.filePath)
|
||||||
|
self.content = Self.parseConfig(lines: lines)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Parsing Logic
|
// MARK: Parsing Logic
|
||||||
@ -84,14 +131,17 @@ class PhpConfigurationFile: CreatedFromFile {
|
|||||||
|
|
||||||
var currentSectionName = "main"
|
var currentSectionName = "main"
|
||||||
|
|
||||||
for line in lines {
|
for (index, line) in lines.enumerated() {
|
||||||
let line = trim(line)
|
let line = trim(line)
|
||||||
|
|
||||||
if line.hasPrefix("[") && line.hasSuffix("]") {
|
if line.hasPrefix("[") && line.hasSuffix("]") {
|
||||||
currentSectionName = parseSectionHeader(line)
|
currentSectionName = parseSectionHeader(line)
|
||||||
} else if let (key, value) = parseLine(line) {
|
} else if let (key, value) = parseLine(line) {
|
||||||
var section = config[currentSectionName] ?? [:]
|
var section = config[currentSectionName] ?? [:]
|
||||||
section[key] = value
|
section[key] = ConfigValue(
|
||||||
|
lineIndex: index,
|
||||||
|
value: value
|
||||||
|
)
|
||||||
config[currentSectionName] = section
|
config[currentSectionName] = section
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user