fixup! fixup! fixup! Pritup pres PHP a docker

This commit is contained in:
lachtan obecny
2026-08-18 05:37:33 +02:00
parent 3126173f82
commit b075ed11c8
5 changed files with 204 additions and 132 deletions

View File

@@ -2,143 +2,22 @@
declare(strict_types=1);
const MANIFEST_PATH = 'manifest.yaml';
const TEMPLATES_DIRECTORY = __DIR__ . '/../templates';
const FETCH_TIMEOUT_SECONDS = 5;
require __DIR__ . '/../src/functions.php';
function sendPlainTextError(int $statusCode, string $message): never
{
http_response_code($statusCode);
header('Content-Type: text/plain; charset=utf-8');
echo $message . "\n";
exit;
}
define('PUBLIC_BASE_URL', resolvePublicBaseUrl());
function fetchRaw(string $relativePath): string|false
{
$url = REPO_RAW_BASE_URL . ltrim($relativePath, '/');
$curl = curl_init($url);
curl_setopt_array($curl, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FAILONERROR => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3,
CURLOPT_TIMEOUT => FETCH_TIMEOUT_SECONDS,
]);
$content = curl_exec($curl);
return is_string($content) ? $content : false;
}
function escapeForDoubleQuotedShellString(string $value): string
{
return str_replace(['\\', '"', '$', '`'], ['\\\\', '\\"', '\\$', '\\`'], $value);
}
function resolveHomePath(string $path): string
{
if ($path === '~' || str_starts_with($path, '~/')) {
return '$HOME' . escapeForDoubleQuotedShellString(substr($path, 1));
}
return escapeForDoubleQuotedShellString($path);
}
function renderScriptTemplate(string $templateName, array $placeholders): string|false
{
$path = TEMPLATES_DIRECTORY . '/' . $templateName . '.sh.tpl';
if (!is_file($path)) {
return false;
}
$script = file_get_contents($path);
foreach ($placeholders as $key => $value) {
$script = str_replace('{{' . $key . '}}', $value, $script);
}
return $script;
}
$repoRawBaseUrl = getenv('REPO_RAW_BASE_URL');
if ($repoRawBaseUrl === false || $repoRawBaseUrl === '') {
sendPlainTextError(500, 'REPO_RAW_BASE_URL is not configured');
}
define('REPO_RAW_BASE_URL', $repoRawBaseUrl);
$publicBaseUrl = getenv('PUBLIC_BASE_URL');
if ($publicBaseUrl === false || $publicBaseUrl === '') {
sendPlainTextError(500, 'PUBLIC_BASE_URL is not configured');
}
define('PUBLIC_BASE_URL', $publicBaseUrl);
$requestPath = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '/';
$name = trim(rawurldecode($requestPath), '/');
$name = resolveRequestedName();
if ($name === '') {
sendPlainTextError(400, 'Missing name of the installable item');
handleIndexRequest();
}
$isRawRequest = str_starts_with($name, 'raw/');
if ($isRawRequest) {
$name = substr($name, strlen('raw/'));
if ($name === 'list') {
handleListRequest();
}
$repoHost = parse_url(REPO_RAW_BASE_URL, PHP_URL_HOST);
$manifestYaml = fetchRaw(MANIFEST_PATH);
if ($manifestYaml === false) {
sendPlainTextError(502, "Failed to fetch the manifest from $repoHost");
if (str_starts_with($name, 'raw/')) {
handleRawRequest(substr($name, strlen('raw/')));
}
$manifest = yaml_parse($manifestYaml);
if ($manifest === false) {
sendPlainTextError(502, "Failed to parse the manifest from $repoHost");
}
$entry = $manifest[$name] ?? null;
if ($entry === null) {
sendPlainTextError(404, "Unknown item '$name'");
}
if (!is_string($entry['source'] ?? null) || !is_string($entry['target'] ?? null) || !is_string($entry['template'] ?? null)) {
sendPlainTextError(500, "Malformed manifest entry for item '$name'");
}
if ($isRawRequest) {
$content = fetchRaw($entry['source']);
if ($content === false) {
sendPlainTextError(502, "Failed to fetch the file from $repoHost");
}
header('Content-Type: application/octet-stream');
echo $content;
exit;
}
$variables = [
'SOURCE_URL' => rtrim(PUBLIC_BASE_URL, '/') . '/raw/' . rawurlencode($name),
'TARGET_PATH' => resolveHomePath($entry['target']),
'POST_INSTALL' => $entry['post_install'] ?? '',
];
$script = renderScriptTemplate($entry['template'], $variables);
if ($script === false) {
sendPlainTextError(500, 'Template for this item is missing');
}
header('Content-Type: text/x-shellscript; charset=utf-8');
echo $script;
handleInstallRequest($name);