Add new config keys to existing files at startup - #52
Merged
Merged
Conversation
LoadModConfig fills a missing key from the class default in memory and leaves the file alone, so an admin upgrading from 0.1.0 never saw the Attribution block appear in pulse.json, nor ServiceName in pulse-otlp.json, and had to learn about them from the README and type them in. ConfigUpgrade compares the file on disk against the config object the loader handed back, recursively and by key name only, and reports both what the file is missing and what it carries that the config knows nothing about. When something is missing the file is rewritten from that object, which already holds every value the admin set, so the write only ever adds; the log then names the keys that were added. An unknown key does not survive that rewrite, so it gets a warning of its own rather than disappearing quietly. A file that is already complete is not written at all, which keeps a read-only or version-tracked ModConfig untouched. The comparison is against JsonUtil.ToPrettyString, which is the same JsonConvert.SerializeObject(obj, Formatting.Indented) call StoreModConfig writes with, so the keys weighed here are exactly the keys a rewrite produces. Pulse.Otlp compiles the helper from the same source file rather than referencing Pulse.dll, since the two mods still meet at nothing but a meter name.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A hosting provider running Pulse in production asked for this. Their admins upgrade the mod, read the changelog, and then find the new keys nowhere in the
pulse.jsonthey already have.LoadModConfigfills a missing key from the class default in memory and never writes it back, so theAttributionblock added in this cycle only ever appears in a file created from scratch. Same story forServiceNameinpulse-otlp.json.Both mods now compare their file against the config object the loader handed back, right after loading it, and rewrite the file when a key is missing. That object already carries every value the admin set, so the rewrite adds the missing defaults and changes nothing else. One notification names what was added.
The comparison runs the other way too. A key in the file that the config class knows nothing about, a typo or a key some release retired, does not survive the rewrite, so it gets a warning of its own rather than vanishing without a word. When the file is already complete, nothing is written at all: no rewrite, no modification time change, which matters on a host that mounts
ModConfigread-only or keeps it under version control. Text that does not parse as a JSON object is left alone for the same reason.What an admin upgrading from 0.1.0 sees, lifted off a scenario's own server log:
Pulse.Otlpstill does not referencePulse.dll. The two mods meet at a meter name and nothing else, on purpose, so the comparison is shared as a linked source file and each assembly compiles its own internal copy of it. What it compares against isJsonUtil.ToPrettyString, which is the exactJsonConvert.SerializeObject(obj, Formatting.Indented)callStoreModConfigwrites with, so the keys weighed are the keys a rewrite produces. No new package reference anywhere:System.Text.Json.Nodesout of the runtime does the key walk, and the base mod stays a single dependency-free dll.Tests go from 183 to 195, all green locally. Ten unit tests cover the comparison itself, including key order, formatting, differing values, nesting, unknown keys at both depths, comments and trailing commas, and text that is not JSON at all. Two scenarios boot a real server on a seeded partial file and read the result back off the ModConfig data path: the base one checks that the admin's port survived into both the file and the bound socket, that
Attributionarrived with its defaults, and that the unknown key is gone; the OTLP one checks thatServiceNamewas filled in. The mutation check gains three mutations for the new code and reports 41/41 killed.