#!/usr/bin/php
<?php

/******************************************************************************
*
* LFS-Updates createrepo
* Part of LFS-Ryco
*
* Copyright (c) 2020-2025 Ryan Coe <bluemrp9@gmail.com>
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
******************************************************************************/

declare(strict_types=1);

if (@file_exists('./vendor/_autoload.php')) {
    require_once('./vendor/_autoload.php');
} else {
    $_SERVER['LFS_ROOTFS'] = (isset($_SERVER['LFS_ROOTFS']) ? $_SERVER['LFS_ROOTFS'] : '');
    require_once($_SERVER['LFS_ROOTFS'].'/usr/share/php/vendor/_autoload.php');
}

use LFS\LFS;
use LFS\Repo;
use Ryco\Error\Exception;
use Ryco\Log;
use Ryco\Package\RPM;
use Ryco\Utils\ArrayHelper;
use Ryco\Utils\FindFiles;
use Ryco\Utils\HashTable;
use Ryco\Utils\System;

LFS::_init();
LFS::timer_start();

$prefix = LFS::get_prefix();
$repo_file = $prefix.'/rpmbuild/REPO/'.LFS::REPO_FILE;
$rpm_dir = $prefix.'/rpmbuild/RPMS';
$srpm_dir = $prefix.'/rpmbuild/SRPMS';
$hash_file = $prefix.'/rpmbuild/TOOLS/hashfile.json';
$alias_dir = $prefix.'/rpmbuild/TOOLS/collections';
$eol_dir = $prefix.'/rpmbuild/TOOLS/eol';
$update_initrd_dir = $prefix.'/rpmbuild/TOOLS/update-initrd';
$repo_ini_file = $prefix.'/rpmbuild/TOOLS/repo.ini';

// Print program name and version
Log::info(LFS::DISTRO.' createrepo 2025.08.23');

// Overrides from command line
$opts = getopt('', ['name:', 'serial:', 'age:']);
$opts = ($opts === false ? [] : $opts);

try {
    $repo = Repo::createFromArray(ArrayHelper::jsonDecode(System::readFile($repo_file, true)));
    $old_serial_num = $repo->getSerial();
    unset($repo);
} catch (Exception $e) {
    Log::warning($e->getMessage());
    $old_serial_num = 0;
}
if (isset($opts['serial']) && strlen($opts['serial']) > 0) {
    $old_serial_num = intval($opts['serial']);
}

$srpm_files = FindFiles::newInstance()->setPath($srpm_dir)->setExt('rpm')->findFiles();
if ($srpm_files->getCount() === 0) {
    Log::error("No RPM packages found in '{$srpm_dir}'");
    exit(1);
}
$rpm_files = FindFiles::newInstance()->setPath($rpm_dir)->setExt('rpm')->findFiles();
if ($rpm_files->getCount() === 0) {
    Log::error("No RPM packages found in '{$rpm_dir}'");
    exit(1);
}
$all_files = FindFiles::combine($srpm_files, $rpm_files);
try {
    HashTable::jsonDecode(System::readFile($hash_file));
} catch (Exception $e) {
    Log::warning($e->getMessage());
    HashTable::clearInternalState();
}
$config = Repo::getConfig($repo_ini_file);
$repo = Repo::createFromFiles(
    $all_files,
    $config->getBool('repo.enforce_signing'),
    $config->getString('repo.signing_key'),
    $config->getString('repo.gnupg_dir'),
);
$age = (isset($opts['age']) ? intval($opts['age']) : $config->getInt('repo.age'));
$repo->setSourceNames()->checkPkgUpdateInitrd()->buildVersionTable()->cleanOldPackages($age)->refCount();
// Clean files
$hash_keys = HashTable::getKeys();
foreach ($hash_keys as $key) {
    $file = HashTable::getInstance($key);
    if ($file->refcount === 0 && System::fileExists($file->filename)) {
        Log::debug('Removing file \''.$file->filename.'\'');
        System::unlinkFile($file->filename);
    }
}
HashTable::cleanHashTable();
// Write hash file
System::writeFile($hash_file, HashTable::jsonEncode(true)."\n");

$pkg_eol = [];
if ($config->keyExists('eol.package')) {
    ArrayHelper::noDupAddArr($pkg_eol, $config->getArray('eol.package'));
}
if (System::fileExists($eol_dir)) {
    ArrayHelper::noDupAddArr($pkg_eol, LFS::dir2arr($eol_dir));
}
sort($pkg_eol);
$repo->setPkgEOL($pkg_eol);
unset($pkg_eol);

if (System::fileExists($alias_dir)) {
    $repo->setPkgAlias(LFS::dir2arr($alias_dir));
}

if (System::fileExists($update_initrd_dir)) {
    $arr = $repo->getPkgUpdateInitrd();
    Log::varDump($arr);
    ArrayHelper::noDupAddArr($arr, LFS::dir2arr($update_initrd_dir));
    sort($arr);
    Log::varDump($arr);
    $repo->setPkgUpdateInitrd($arr);
    unset($arr);
}

// Set name from config
if (isset($opts['name']) && strlen($opts['name']) > 0) {
    $repo->setName($opts['name']);
} else {
    $repo->setName($config->getString('repo.name'));
}
// Update serial and generated stamp
$repo->setSerial($old_serial_num+1)->setGenerated();

$pkg_counts = $repo->getPackageCounts();
$len1 = ArrayHelper::arrayMaxStrLength(RPM::getSupportedArch())+5;
$len2 = ArrayHelper::arrayMaxStrLength($pkg_counts);

Log::info(sprintf('%s : %s', str_pad('Repo Name', $len1), $repo->getName()));
Log::info(sprintf('%s : %d', str_pad('Serial', $len1), $repo->getSerial()));
Log::info(sprintf('%s : %s', str_pad('Generated', $len1), date('Y-m-d H:i:s', $repo->getGenerated())));

foreach ($pkg_counts as $arch => $count) {
    $str = sprintf(
        '%s : %s package%s',
        str_pad('Arch '.$arch, $len1),
        str_pad(strval($count), $len2),
        ($count !== 1 ? 's' : '')
    );
    Log::info($str);
}

// Write file
System::writeFile($repo_file, ArrayHelper::jsonEncode($repo->toArray(), true)."\n", true);

exit(0);
