diff options
author | Özgür Kesim <oec-taler@kesim.org> | 2023-08-25 13:24:30 +0200 |
---|---|---|
committer | Özgür Kesim <oec-taler@kesim.org> | 2023-08-25 13:24:30 +0200 |
commit | a58f73ecdb995e02a770338aa8a8aa529ccfdfaa (patch) | |
tree | e1f329bb59ffd1fa4419241cf3bc849738103b54 /packages/taler-util/src | |
parent | 5ab3070b3a63c2e8fed0e413dea06cf03fb48f1e (diff) | |
parent | 896841aec5dc3594d83cc300349d20ec2270f88e (diff) |
Merge branch 'master' into age-withdraw
Diffstat (limited to 'packages/taler-util/src')
-rw-r--r-- | packages/taler-util/src/logging.ts | 10 | ||||
-rw-r--r-- | packages/taler-util/src/talerconfig.ts | 193 |
2 files changed, 166 insertions, 37 deletions
diff --git a/packages/taler-util/src/logging.ts b/packages/taler-util/src/logging.ts index c4b2a3da0..79fc49cdd 100644 --- a/packages/taler-util/src/logging.ts +++ b/packages/taler-util/src/logging.ts @@ -32,13 +32,17 @@ export enum LogLevel { None = "none", } -export let globalLogLevel = LogLevel.Info; +let globalLogLevel = LogLevel.Info; +const byTagLogLevel: Record<string, LogLevel> = {}; + +export function getGlobalLogLevel(): string { + return globalLogLevel; +} export function setGlobalLogLevelFromString(logLevelStr: string): void { globalLogLevel = getLevelForString(logLevelStr); } -export const byTagLogLevel: Record<string, LogLevel> = {}; export function setLogLevelFromString(tag: string, logLevelStr: string): void { byTagLogLevel[tag] = getLevelForString(logLevelStr); } @@ -98,7 +102,7 @@ function writeNodeLog( * and uses the corresponding console.* method to log in the browser. */ export class Logger { - constructor(private tag: string) {} + constructor(private tag: string) { } shouldLogTrace(): boolean { const level = byTagLogLevel[this.tag] ?? globalLogLevel; diff --git a/packages/taler-util/src/talerconfig.ts b/packages/taler-util/src/talerconfig.ts index 59c789cae..d86c58678 100644 --- a/packages/taler-util/src/talerconfig.ts +++ b/packages/taler-util/src/talerconfig.ts @@ -1,6 +1,6 @@ /* This file is part of GNU Taler - (C) 2020 Taler Systems S.A. + (C) 2020-2023 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -39,10 +39,30 @@ export class ConfigError extends Error { } } +enum EntryOrigin { + /** + * From a default file. + */ + DefaultFile = 1, + /** + * From a system/installation specific default value. + */ + DefaultSystem = 2, + /** + * Loaded from file or string + */ + Loaded = 3, + /** + * Changed after loading + */ + Changed = 4, +} + interface Entry { value: string; sourceLine: number; sourceFile: string; + origin: EntryOrigin; } interface Section { @@ -159,12 +179,12 @@ export function pathsub( const r = lookup(inner, depth + 1); if (r !== undefined) { - s = s.substr(0, start) + r + s.substr(p + 1); + s = s.substring(0, start) + r + s.substring(p + 1); l = start + r.length; continue; } else if (defaultValue !== undefined) { const resolvedDefault = pathsub(defaultValue, lookup, depth + 1); - s = s.substr(0, start) + resolvedDefault + s.substr(p + 1); + s = s.substring(0, start) + resolvedDefault + s.substring(p + 1); l = start + resolvedDefault.length; continue; } @@ -176,7 +196,7 @@ export function pathsub( if (m && m[0]) { const r = lookup(m[0], depth + 1); if (r !== undefined) { - s = s.substr(0, l) + r + s.substr(l + 1 + m[0].length); + s = s.substring(0, l) + r + s.substring(l + 1 + m[0].length); l = l + r.length; continue; } @@ -195,6 +215,7 @@ export interface LoadOptions { export interface StringifyOptions { diagnostics?: boolean; + excludeDefaults?: boolean; } export interface LoadedFile { @@ -282,7 +303,11 @@ export class Configuration { private nestLevel = 0; - private loadFromFilename(filename: string, opts: LoadOptions = {}): void { + private loadFromFilename( + filename: string, + isDefaultSource: boolean, + opts: LoadOptions = {}, + ): void { filename = expandPath(filename); const checkCycle = () => { @@ -309,7 +334,7 @@ export class Configuration { const oldNestLevel = this.nestLevel; this.nestLevel += 1; try { - this.loadFromString(s, { + this.internalLoadFromString(s, isDefaultSource, { ...opts, filename: filename, }); @@ -318,7 +343,11 @@ export class Configuration { } } - private loadGlob(parentFilename: string, fileglob: string): void { + private loadGlob( + parentFilename: string, + isDefaultSource: boolean, + fileglob: string, + ): void { const resolvedParent = nodejs_fs.realpathSync(parentFilename); const parentDir = nodejs_path.dirname(resolvedParent); @@ -339,12 +368,16 @@ export class Configuration { for (const f of files) { if (globMatch(tail, f)) { const fullPath = nodejs_path.join(head, f); - this.loadFromFilename(fullPath); + this.loadFromFilename(fullPath, isDefaultSource); } } } - private loadSecret(sectionName: string, filename: string): void { + private loadSecret( + sectionName: string, + filename: string, + isDefaultSource: boolean, + ): void { const sec = this.provideSection(sectionName); sec.secretFilename = filename; const otherCfg = new Configuration(); @@ -354,7 +387,7 @@ export class Configuration { sec.inaccessible = true; return; } - otherCfg.loadFromFilename(filename, { + otherCfg.loadFromFilename(filename, isDefaultSource, { banDirectives: true, }); const otherSec = otherCfg.provideSection(sectionName); @@ -363,7 +396,11 @@ export class Configuration { } } - loadFromString(s: string, opts: LoadOptions = {}): void { + private internalLoadFromString( + s: string, + isDefaultSource: boolean, + opts: LoadOptions = {}, + ): void { let lineNo = 0; const fn = opts.filename ?? "<input>"; const reComment = /^\s*#.*$/; @@ -399,7 +436,10 @@ export class Configuration { ); } const arg = directiveMatch[2].trim(); - this.loadFromFilename(normalizeInlineFilename(opts.filename, arg)); + this.loadFromFilename( + normalizeInlineFilename(opts.filename, arg), + isDefaultSource, + ); break; } case "inline-secret": { @@ -419,7 +459,7 @@ export class Configuration { opts.filename, sp[1], ); - this.loadSecret(sp[0], secretFilename); + this.loadSecret(sp[0], secretFilename, isDefaultSource); break; } case "inline-matching": { @@ -429,7 +469,7 @@ export class Configuration { `invalid configuration, @inline-matching@ directive in ${fn}:${lineNo} can only be used from a file`, ); } - this.loadGlob(opts.filename, arg); + this.loadGlob(opts.filename, isDefaultSource, arg); break; } default: @@ -462,6 +502,9 @@ export class Configuration { value: val, sourceFile: opts.filename ?? "<unknown>", sourceLine: lineNo, + origin: isDefaultSource + ? EntryOrigin.DefaultFile + : EntryOrigin.Loaded, }; continue; } @@ -471,6 +514,10 @@ export class Configuration { } } + loadFromString(s: string, opts: LoadOptions = {}): void { + return this.internalLoadFromString(s, false, opts); + } + private provideSection(section: string): Section { const secNorm = section.toUpperCase(); if (this.sectionMap[secNorm]) { @@ -496,6 +543,24 @@ export class Configuration { value, sourceLine: 0, sourceFile: "<unknown>", + origin: EntryOrigin.Changed, + }; + } + + /** + * Set a string value to a value from default locations. + */ + private setStringSystemDefault( + section: string, + option: string, + value: string, + ): void { + const sec = this.provideSection(section); + sec.entries[option.toUpperCase()] = { + value, + sourceLine: 0, + sourceFile: "<unknown>", + origin: EntryOrigin.DefaultSystem, }; } @@ -559,7 +624,7 @@ export class Configuration { lookupVariable(x: string, depth: number = 0): string | undefined { // We loop up options in PATHS in upper case, as option names // are case insensitive - const val = this.findEntry("PATHS", x)?.value; + let val = this.findEntry("PATHS", x)?.value; if (val !== undefined) { return pathsub(val, (v, d) => this.lookupVariable(v, d), depth); } @@ -578,30 +643,63 @@ export class Configuration { ); } - loadFrom(dirname: string): void { + loadDefaultsFromDir(dirname: string): void { const files = nodejs_fs.readdirSync(dirname); for (const f of files) { const fn = nodejs_path.join(dirname, f); - this.loadFromFilename(fn); + this.loadFromFilename(fn, true); } } private loadDefaults(): void { - let bc = process.env["TALER_BASE_CONFIG"]; - if (!bc) { + let baseConfigDir = process.env["TALER_BASE_CONFIG"]; + if (!baseConfigDir) { /* Try to locate the configuration based on the location * of the taler-config binary. */ const path = which("taler-config"); if (path) { - bc = nodejs_fs.realpathSync( + baseConfigDir = nodejs_fs.realpathSync( nodejs_path.dirname(path) + "/../share/taler/config.d", ); } } - if (!bc) { - bc = "/usr/share/taler/config.d"; + if (!baseConfigDir) { + baseConfigDir = "/usr/share/taler/config.d"; } - this.loadFrom(bc); + + let installPrefix = process.env["TALER_PREFIX"]; + if (!installPrefix) { + /* Try to locate install path based on the location + * of the taler-config binary. */ + const path = which("taler-config"); + if (path) { + installPrefix = nodejs_fs.realpathSync( + nodejs_path.dirname(path) + "/..", + ); + } + } + if (!installPrefix) { + installPrefix = "/usr"; + } + + this.setStringSystemDefault( + "PATHS", + "LIBEXECDIR", + `${installPrefix}/taler/libexec/`, + ); + this.setStringSystemDefault( + "PATHS", + "DOCDIR", + `${installPrefix}/share/doc/taler/`, + ); + this.setStringSystemDefault("PATHS", "ICONDIR", `${installPrefix}/share/icons/`); + this.setStringSystemDefault("PATHS", "LOCALEDIR", `${installPrefix}/share/locale/`); + this.setStringSystemDefault("PATHS", "PREFIX", `${installPrefix}/`); + this.setStringSystemDefault("PATHS", "BINDIR", `${installPrefix}/bin`); + this.setStringSystemDefault("PATHS", "LIBDIR", `${installPrefix}/lib/taler/`); + this.setStringSystemDefault("PATHS", "DATADIR", `${installPrefix}/share/taler/`); + + this.loadDefaultsFromDir(baseConfigDir); } getDefaultConfigFilename(): string | undefined { @@ -631,11 +729,13 @@ export class Configuration { const cfg = new Configuration(); cfg.loadDefaults(); if (filename) { - cfg.loadFromFilename(filename); + cfg.loadFromFilename(filename, false); } else { const fn = cfg.getDefaultConfigFilename(); if (fn) { - cfg.loadFromFilename(fn); + // It's the default filename for the main config file, + // but we don't consider the values default values. + cfg.loadFromFilename(fn, false); } } cfg.hintEntrypoint = filename; @@ -657,26 +757,51 @@ export class Configuration { } for (const sectionName of Object.keys(this.sectionMap)) { const sec = this.sectionMap[sectionName]; - if (opts.diagnostics && sec.secretFilename) { - s += `# Secret section from ${sec.secretFilename}\n`; - s += `# Secret accessible: ${!sec.inaccessible}\n`; - } - s += `[${sectionName}]\n`; + let headerWritten = false; for (const optionName of Object.keys(sec.entries)) { const entry = this.sectionMap[sectionName].entries[optionName]; + if ( + opts.excludeDefaults && + (entry.origin === EntryOrigin.DefaultSystem || + entry.origin === EntryOrigin.DefaultFile) + ) { + continue; + } + if (!headerWritten) { + if (opts.diagnostics && sec.secretFilename) { + s += `# Secret section from ${sec.secretFilename}\n`; + s += `# Secret accessible: ${!sec.inaccessible}\n`; + } + s += `[${sectionName}]\n`; + headerWritten = true; + } if (entry !== undefined) { if (opts.diagnostics) { - s += `# ${entry.sourceFile}:${entry.sourceLine}\n`; + switch (entry.origin) { + case EntryOrigin.DefaultFile: + case EntryOrigin.Changed: + case EntryOrigin.Loaded: + s += `# ${entry.sourceFile}:${entry.sourceLine}\n`; + break; + case EntryOrigin.DefaultSystem: + s += `# (system/installation default)\n`; + break; + } } s += `${optionName} = ${entry.value}\n`; } } - s += "\n"; + if (headerWritten) { + s += "\n"; + } } return s; } - write(filename: string): void { - nodejs_fs.writeFileSync(filename, this.stringify()); + write(filename: string, opts: { excludeDefaults?: boolean } = {}): void { + nodejs_fs.writeFileSync( + filename, + this.stringify({ excludeDefaults: opts.excludeDefaults }), + ); } } |