diff --git a/.agents/codebase-insights.txt b/.agents/codebase-insights.txt index cdc378018..1e1fc151f 100644 --- a/.agents/codebase-insights.txt +++ b/.agents/codebase-insights.txt @@ -25,3 +25,4 @@ - Interpreter overrides (e.g. `CODETRACER_PYTHON_INTERPRETER`) are now treated as authoritative; if the configured path cannot be resolved we error instead of silently falling back to PATH. - `ct record` verifies that `codetracer_python_recorder` is importable before launching the db backend and prints actionable guidance if the module is missing or broken. - Sudoku test-program datasets include intentionally invalid boards (e.g., examples #3 and #6) with duplicate digits inside a sub-grid; solvers should detect and report these gracefully. +- Default config templates live in `src/config/defaults.nim` and are embedded with `staticRead`; installers write from the embedded string rather than copying from `linksPath`. diff --git a/src/common/config.nim b/src/common/config.nim index 6783d15f5..4223edc22 100644 --- a/src/common/config.nim +++ b/src/common/config.nim @@ -4,6 +4,7 @@ import std / [ strutils, sequtils, streams, strformat, os ] import json_serialization/std/tables, yaml import .. / common / [paths, types] +import .. / config / defaults type RRBackendConfig* = object @@ -89,6 +90,10 @@ let configDir* = linksPath / "config" let userConfigDir* = getEnv("XDG_CONFIG_HOME", getHomeDir() / ".config") / "codetracer" let userLayoutDir* = getEnv("XDG_CONFIG_HOME", getHomeDir() / ".config") / "codetracer" +proc writeDefaultConfigFile(destPath: string) {.raises: [IOError, OSError].} = + ## Persist the embedded default configuration to `destPath`. + writeFile(destPath, defaults.defaultConfigContent) + func normalize(shortcut: string): string = # for now we expect to write editor-style monaco shortcuts shortcut @@ -140,7 +145,7 @@ proc loadConfig*(folder: string, inTest: bool): Config = if file.len == 0: file = userConfigDir / configPath createDir(userConfigDir) - copyFile(configDir / defaultConfigPath, file) + writeDefaultConfigFile(file) # if inTest: # file = codetracerTestDir / testConfigPath var raw = "" @@ -170,6 +175,9 @@ proc loadConfig*(folder: string, inTest: bool): Config = echo fmt" for now we now have directly copied your existing config file to {backupFilePath}" except Exception as copyError: echo "ERROR: couldn't backup your existing config file; error: ", copyError.msg - copyFile(configDir / defaultConfigPath, file) + try: + writeDefaultConfigFile(file) + except CatchableError as defaultWriteError: + echo "ERROR: failed to write default config: ", defaultWriteError.msg + quit(1) echo " REPLACED with new up to date default config file" - diff --git a/src/config/defaults.nim b/src/config/defaults.nim new file mode 100644 index 000000000..2de9c6418 --- /dev/null +++ b/src/config/defaults.nim @@ -0,0 +1,10 @@ +## Default configuration payloads embedded at compile time. +## +## Keeping the defaults in a dedicated module allows both CLI and frontend +## components to share the same embedded assets without relying on runtime +## filesystem access. + +const + defaultConfigFilename* = "default_config.yaml" + defaultConfigContent* = staticRead(defaultConfigFilename) + diff --git a/src/frontend/config.nim b/src/frontend/config.nim index 3535e5d1e..a3b8265dd 100644 --- a/src/frontend/config.nim +++ b/src/frontend/config.nim @@ -2,13 +2,15 @@ import std / [json, strutils, sequtils, jsffi], types, lib/jslib, - .. / common / ct_logging + .. / common / ct_logging, + .. / config / defaults let configPath* = ".config.yaml" testConfigPath* = ".config.yaml" defaultConfigPath* = "default_config.yaml" defaultLayoutPath* = "default_layout.json" + defaultConfigContent* = defaults.defaultConfigContent when not defined(ctRenderer): import @@ -56,4 +58,3 @@ proc initShortcutMap*(map: InputShortcutMap): ShortcutMap = result.conflictList.add((key, value)) return result - diff --git a/src/frontend/index/config.nim b/src/frontend/index/config.nim index 22471e131..3dee394e5 100644 --- a/src/frontend/index/config.nim +++ b/src/frontend/index/config.nim @@ -193,15 +193,16 @@ proc loadConfig*(main: js, startOptions: StartOptions, home: cstring = cstring"" errorPrint "mkdir for config folder error: exiting: ", errMkdir quit(1) - let errCopy = await fsCopyFileWithErr( - cstring(fmt"{configDir / defaultConfigPath}"), - cstring(fmt"{userConfigDir / configPath}") + # Persist the embedded default config when the user has no local file yet. + let errWrite = await fsWriteFileWithErr( + cstring(fmt"{userConfigDir / configPath}"), + cstring(defaultConfigContent) ) - if not errCopy.isNil: - errorPrint "can't copy .config.yaml to user config dir:" - errorPrint " tried to copy from: ", cstring(fmt"{configDir / defaultConfigPath}") - errorPrint " to: ", fmt"{userConfigDir / configPath}" + if not errWrite.isNil: + errorPrint "can't write default .config.yaml to user config dir:" + errorPrint " target: ", fmt"{userConfigDir / configPath}" + errorPrint " error: ", errWrite quit(1) infoPrint "index: load config ", file @@ -261,4 +262,4 @@ proc loadValues*(a: js, id: cstring): JsAssoc[cstring, cstring] = values[field] = cstring"undefined" else: values[field] = cstring"nil" - return values \ No newline at end of file + return values diff --git a/src/frontend/index_config.nim b/src/frontend/index_config.nim index fd68dbe81..88a598de9 100644 --- a/src/frontend/index_config.nim +++ b/src/frontend/index_config.nim @@ -1219,17 +1219,14 @@ proc loadConfig*(main: js, startOptions: StartOptions, home: cstring = j"", send if not errMkdir.isNil: errorPrint "mkdir for config folder error: exiting: ", errMkdir quit(1) - # thanks to Peter for the good advice to use copyFile instead of `cp` - # works around an issue i had with wrong libc version and nix - # and more clean - let errCopy = await fsCopyFileWithErr( - cstring(fmt"{configDir / defaultConfigPath}"), - cstring(fmt"{userConfigDir / configPath}")); - # cstring(&"cp {configDir}{defaultLayoutPath} {filename}")) - if not errCopy.isNil: - errorPrint "can't copy .config.yaml to user config dir:" - errorPrint " tried to copy from: ", cstring(fmt"{configDir / defaultConfigPath}") - errorPrint " to: ", fmt"{userConfigDir / configPath}" + # Persist the embedded default config when the user has no local file yet. + let errWrite = await fsWriteFileWithErr( + cstring(fmt"{userConfigDir / configPath}"), + cstring(defaultConfigContent)) + if not errWrite.isNil: + errorPrint "can't write default .config.yaml to user config dir:" + errorPrint " target: ", fmt"{userConfigDir / configPath}" + errorPrint " error: ", errWrite quit(1) # TODO: maybe remove config test logic?