$id, 'enabled' => $enabled, 'cron' => $cron, 'updated' => date('c'), ]; if (!vv_schedule_save($schedule)) return false; return vv_cron_rebuild($schedule); } define('LOG_DIR', '/var/log/varaverk'); function vv_cron_rebuild(array $schedule): bool { if (!is_dir(LOG_DIR)) mkdir(LOG_DIR, 0755, true); $lines = ["# Varaverk — managed by plugin, do not edit manually"]; $lines[] = "# Regenerated: " . date('Y-m-d H:i:s'); $lines[] = ""; $scriptsDir = SCRIPTS_DIR; foreach ($schedule as $entry) { if (empty($entry['enabled']) || empty($entry['cron']) || empty($entry['id'])) continue; $script = "$scriptsDir/{$entry['id']}"; $cron = $entry['cron']; $lines[] = "$cron " . CRON_USER . " bash \"$script\" >> " . LOG_DIR . "/jobs.log 2>&1"; } $lines[] = ""; return file_put_contents(CRON_FILE, implode("\n", $lines)) !== false; } // Walk the scripts repo and return the job tree: // orchestrators as top-level, individual scripts as children function vv_job_tree(): array { $scriptsDir = SCRIPTS_DIR; $schedule = vv_schedule_load(); // Orchestrators are in Orchestrators/ and their children are all scripts they call // For now: walk top-level folders, treat *_management.sh or *_maintenance.sh as orchs $orchPattern = "$scriptsDir/Orchestrators/*.sh"; $orchs = []; foreach (glob($orchPattern) ?: [] as $path) { $id = 'Orchestrators/' . basename($path); $entry = $schedule[$id] ?? ['enabled' => false, 'cron' => '']; $orchs[] = [ 'id' => $id, 'label' => basename($path, '.sh'), 'type' => 'orchestrator', 'enabled' => (bool)($entry['enabled'] ?? false), 'cron' => $entry['cron'] ?? '', 'children' => vv_script_children($path, $schedule), ]; } return $orchs; } // Parse an orchestrator script to find which child scripts it calls. // Handles two common patterns: // $SCRIPT_DIR/../Category/script.sh (relative via variable) // $SCRIPTS_ROOT/Category/script.sh (absolute root via variable) // Root-level files (load_config.sh, etc.) are excluded — must be in a subdirectory. // Validates each candidate against the filesystem to filter false positives. function vv_script_children(string $orchPath, array $schedule): array { $scriptsDir = SCRIPTS_DIR; $content = file_get_contents($orchPath) ?: ''; $children = []; $seen = []; // Match $ANY_VAR/../Category/script.sh or $ANY_VAR/Category/script.sh // Capture only the Category/script.sh portion (requires at least one subdirectory) preg_match_all( '/\$[A-Z_]+\/(?:\.\.\/)?([A-Za-z][A-Za-z0-9_.\-]*\/[A-Za-z0-9_.\-]+\.sh)/', $content, $m ); foreach ($m[1] as $rel) { if (isset($seen[$rel])) continue; if (!file_exists("$scriptsDir/$rel")) continue; $seen[$rel] = true; $entry = $schedule[$rel] ?? ['enabled' => false, 'cron' => '']; $children[] = [ 'id' => $rel, 'label' => basename($rel, '.sh'), 'type' => 'script', 'enabled' => (bool)($entry['enabled'] ?? false), 'cron' => $entry['cron'] ?? '', ]; } return $children; }