Files
pilot/gnome-pilot-extension/yamlConfig.js
2026-01-10 20:24:11 +01:00

281 lines
8.5 KiB
JavaScript

// yamlConfig.js - Module pour lire/écrire le fichier config.yaml de Pilot V2
// Version simple sans dépendances externes
import GLib from 'gi://GLib';
import Gio from 'gi://Gio';
/**
* Parser YAML simple - ne gère que les structures basiques nécessaires pour config.yaml
* Format attendu: clés avec indentation de 2 espaces
*/
export class YamlConfig {
constructor(configPath = null) {
// Chemins par défaut où chercher le config.yaml
this.configPath = configPath || this._findConfigPath();
this.config = null;
}
/**
* Trouve le fichier de configuration dans les emplacements standards
*/
_findConfigPath() {
const possiblePaths = [
GLib.build_filenamev([GLib.get_home_dir(), 'app/pilot/pilot-v2/config.yaml']),
GLib.build_filenamev([GLib.get_home_dir(), '.config/pilot/config.yaml']),
'/etc/pilot/config.yaml',
'./pilot-v2/config.yaml'
];
for (const path of possiblePaths) {
if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
return path;
}
}
// Par défaut
return GLib.build_filenamev([GLib.get_home_dir(), 'app/pilot/pilot-v2/config.yaml']);
}
/**
* Lit le fichier YAML et retourne un objet JavaScript
*/
load() {
try {
const file = Gio.File.new_for_path(this.configPath);
const [success, contents] = file.load_contents(null);
if (!success) {
throw new Error(`Cannot read file: ${this.configPath}`);
}
const decoder = new TextDecoder('utf-8');
const text = decoder.decode(contents);
this.config = this._parseYaml(text);
return this.config;
} catch (error) {
console.error(`Error loading config: ${error.message}`);
return null;
}
}
/**
* Parse simple de YAML (gère uniquement la structure de config.yaml)
* Convertit YAML en objet JavaScript
*/
_parseYaml(text) {
const lines = text.split('\n');
const result = {};
const stack = [{obj: result, indent: -1}];
for (let line of lines) {
// Ignorer les commentaires et lignes vides
if (line.trim().startsWith('#') || line.trim() === '') {
continue;
}
const indent = line.search(/\S/);
const trimmed = line.trim();
// Calculer le niveau d'indentation (2 espaces = 1 niveau)
const level = Math.floor(indent / 2);
// Remonter dans la pile si nécessaire
while (stack.length > 0 && stack[stack.length - 1].indent >= level) {
stack.pop();
}
const parent = stack[stack.length - 1].obj;
// Traiter la ligne
if (trimmed.includes(':')) {
const colonIndex = trimmed.indexOf(':');
const key = trimmed.substring(0, colonIndex).trim();
let value = trimmed.substring(colonIndex + 1).trim();
if (value === '') {
// C'est un objet (nouvelle section)
parent[key] = {};
stack.push({obj: parent[key], indent: level});
} else if (value === 'true' || value === 'false') {
// Boolean
parent[key] = value === 'true';
} else if (!isNaN(value) && value !== '') {
// Number
parent[key] = Number(value);
} else {
// String (enlever les quotes si présentes)
parent[key] = value.replace(/^["']|["']$/g, '');
}
} else if (trimmed.startsWith('- ')) {
// Liste
if (!Array.isArray(parent)) {
// Convertir le parent en tableau si ce n'est pas déjà le cas
const lastKey = Object.keys(stack[stack.length - 2].obj).pop();
stack[stack.length - 2].obj[lastKey] = [];
stack[stack.length - 1].obj = stack[stack.length - 2].obj[lastKey];
}
const value = trimmed.substring(2).trim();
parent.push(value.replace(/^["']|["']$/g, ''));
}
}
return result;
}
/**
* Sauvegarde l'objet JavaScript en YAML
*/
save(config = null) {
const dataToSave = config || this.config;
if (!dataToSave) {
throw new Error('No config data to save');
}
try {
const yamlText = this._toYaml(dataToSave);
const file = Gio.File.new_for_path(this.configPath);
// Créer une sauvegarde
this._createBackup();
// Écrire le nouveau fichier
file.replace_contents(
new TextEncoder().encode(yamlText),
null,
false,
Gio.FileCreateFlags.REPLACE_DESTINATION,
null
);
console.log(`Config saved to: ${this.configPath}`);
return true;
} catch (error) {
console.error(`Error saving config: ${error.message}`);
return false;
}
}
/**
* Convertit un objet JavaScript en YAML
*/
_toYaml(obj, indent = 0) {
let yaml = '';
const spaces = ' '.repeat(indent);
for (const [key, value] of Object.entries(obj)) {
if (value === null || value === undefined) {
continue;
}
if (typeof value === 'object' && !Array.isArray(value)) {
// Objet imbriqué
yaml += `${spaces}${key}:\n`;
yaml += this._toYaml(value, indent + 1);
} else if (Array.isArray(value)) {
// Tableau
yaml += `${spaces}${key}:\n`;
for (const item of value) {
yaml += `${spaces} - ${item}\n`;
}
} else {
// Valeur simple
const valueStr = typeof value === 'string' ? value : String(value);
yaml += `${spaces}${key}: ${valueStr}\n`;
}
}
return yaml;
}
/**
* Crée une sauvegarde du fichier de config actuel
*/
_createBackup() {
try {
const timestamp = GLib.DateTime.new_now_local().format('%Y%m%d_%H%M%S');
const backupPath = `${this.configPath}.backup_${timestamp}`;
const source = Gio.File.new_for_path(this.configPath);
const dest = Gio.File.new_for_path(backupPath);
if (source.query_exists(null)) {
source.copy(dest, Gio.FileCopyFlags.OVERWRITE, null, null);
console.log(`Backup created: ${backupPath}`);
}
} catch (error) {
console.warn(`Could not create backup: ${error.message}`);
}
}
/**
* Obtient les métriques de télémétrie configurées
*/
getTelemetryMetrics() {
if (!this.config?.features?.telemetry?.metrics) {
return {};
}
return this.config.features.telemetry.metrics;
}
/**
* Obtient la liste des commandes autorisées
*/
getCommandsAllowlist() {
if (!this.config?.features?.commands?.allowlist) {
return [];
}
return this.config.features.commands.allowlist;
}
/**
* Met à jour une métrique de télémétrie
*/
updateTelemetryMetric(metricName, updates) {
if (!this.config?.features?.telemetry?.metrics?.[metricName]) {
return false;
}
Object.assign(this.config.features.telemetry.metrics[metricName], updates);
return true;
}
/**
* Active/désactive la télémétrie globale
*/
setTelemetryEnabled(enabled) {
if (!this.config?.features?.telemetry) {
return false;
}
this.config.features.telemetry.enabled = enabled;
return true;
}
/**
* Active/désactive les commandes globales
*/
setCommandsEnabled(enabled) {
if (!this.config?.features?.commands) {
return false;
}
this.config.features.commands.enabled = enabled;
return true;
}
/**
* Met à jour la liste des commandes autorisées
*/
updateCommandsAllowlist(newAllowlist) {
if (!this.config?.features?.commands) {
return false;
}
this.config.features.commands.allowlist = newAllowlist;
return true;
}
}