mirror of
https://github.com/nicoverbruggen/phpmon.git
synced 2025-08-07 12:00:09 +02:00
✨ Allow replacing of config values
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
//
|
||||
// PhpIniTest.swift
|
||||
// PhpConfigurationTest.swift
|
||||
// PHP Monitor
|
||||
//
|
||||
// Created by Nico Verbruggen on 04/05/2022.
|
||||
@ -40,12 +40,45 @@ class PhpConfigurationTest: XCTestCase {
|
||||
XCTAssert(iniFile.get(for: "display_errors") == "On")
|
||||
}
|
||||
|
||||
func testCanSwapConfigurationValue() throws {
|
||||
let destination = Utility.copyToTemporaryFile(resourceName: "php", fileExtension: "ini")!
|
||||
func testCanCustomizeConfigurationValue() throws {
|
||||
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
|
||||
//
|
||||
// Created by Nico Verbruggen on 04/05/2022.
|
||||
@ -10,18 +10,26 @@ import Foundation
|
||||
|
||||
class PhpConfigurationFile: CreatedFromFile {
|
||||
|
||||
typealias Section = [String: String]
|
||||
struct ConfigValue {
|
||||
let lineIndex: Int
|
||||
let value: String
|
||||
}
|
||||
|
||||
typealias Section = [String: ConfigValue]
|
||||
typealias Config = [String: Section]
|
||||
|
||||
/// The file where this configuration file was located.
|
||||
let file: String
|
||||
let filePath: String
|
||||
|
||||
/// 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
|
||||
|
||||
/// The original lines of the file.
|
||||
var lines: [String]
|
||||
|
||||
/** Resolves a PHP configuration file (.ini) */
|
||||
static func from(filePath: String) -> Self? {
|
||||
let path = filePath.replacingOccurrences(
|
||||
@ -43,10 +51,8 @@ class PhpConfigurationFile: CreatedFromFile {
|
||||
}
|
||||
|
||||
required init(path: String, contents: String) {
|
||||
self.file = path
|
||||
|
||||
let lines = contents.components(separatedBy: "\n")
|
||||
|
||||
self.filePath = path
|
||||
self.lines = contents.components(separatedBy: "\n")
|
||||
self.extensions = PhpExtension.from(lines, filePath: path)
|
||||
self.content = Self.parseConfig(lines: lines)
|
||||
}
|
||||
@ -60,16 +66,57 @@ class PhpConfigurationFile: CreatedFromFile {
|
||||
}
|
||||
|
||||
public func get(for key: String) -> String? {
|
||||
return getConfig(for: key)?.value
|
||||
}
|
||||
|
||||
public func getConfig(for key: String) -> ConfigValue? {
|
||||
for (_, section) in self.content {
|
||||
if section.keys.contains(key) {
|
||||
return section[key]
|
||||
return section[key]!
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
public func replace(key: String, value: String) {
|
||||
// TODO
|
||||
enum ReplacementErrors: Error {
|
||||
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
|
||||
@ -84,14 +131,17 @@ class PhpConfigurationFile: CreatedFromFile {
|
||||
|
||||
var currentSectionName = "main"
|
||||
|
||||
for line in lines {
|
||||
for (index, line) in lines.enumerated() {
|
||||
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
|
||||
section[key] = ConfigValue(
|
||||
lineIndex: index,
|
||||
value: value
|
||||
)
|
||||
config[currentSectionName] = section
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user