first commit.

This commit is contained in:
kj
2026-10-05 15:08:39 -03:00
commit b7799f9fff
93 changed files with 8966 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
<?php
use Toolbox\Commands\AddCommand;
use Toolbox\Commands\InstallCommand;
use Toolbox\Commands\ListCommand;
use Toolbox\Commands\RemoveCommand;
use Toolbox\Commands\UpdateCommand;
use Toolbox\Console;
use Toolbox\Lock;
Harness::suite('group7');
function g7_toolbox(bool $compreFaceInDefault = true): string
{
$dir = tmpdir('tool');
write_file($dir . '/packages/http/duckbrain.json', json_encode([
'name' => 'http',
'version' => '1.0.0',
'description' => 'Utilidades HTTP',
'components' => [
'curlRequest' => ['files' => ['src/Libs/CurlRequest.php']],
'aria2' => ['files' => ['src/Libs/Aria2.php']],
'compreFace' => [
'files' => ['src/Libs/CompreFace.php'],
'require' => ['http:curlRequest' => '>=1.0'],
],
],
'default' => $compreFaceInDefault ? ['curlRequest', 'aria2', 'compreFace'] : ['aria2'],
], JSON_PRETTY_PRINT));
write_file($dir . '/packages/http/src/Libs/CurlRequest.php', "<?php\n// curl\n");
write_file($dir . '/packages/http/src/Libs/Aria2.php', "<?php\n// aria2\n");
write_file($dir . '/packages/http/src/Libs/CompreFace.php', "<?php\n// compreface\n");
return $dir;
}
function g7_core(string $version = '0.1.0', string $router = 'router-v1'): string
{
$dir = tmpdir('core');
write_file($dir . '/autoload.php', <<<'PHP'
<?php
define('ROOT_DIR', __DIR__);
define('ROOT_CORE', ROOT_DIR . '/src');
spl_autoload_register(function (string $class): void {
$fp = str_replace('\\', '/', $class);
$file = ROOT_CORE . '/' . dirname($fp) . '/' . basename($fp) . '.php';
if (file_exists($file)) {
require_once $file;
}
});
PHP);
write_file($dir . '/config.php', "<?php\n");
write_file($dir . '/src/Libs/Router.php', "<?php\n// " . $router . "\n");
// Documentación del repo (rastreada, pero excluida del core distribuible).
write_file($dir . '/readme.org', "* core readme\n");
git_init($dir);
git_commit($dir, 'core ' . $router);
if ($version !== '') {
git_tag($dir, 'v' . $version);
}
return $dir;
}
function g7_console(&$stream): Console
{
$stream = fopen('php://memory', 'r+');
return new Console($stream, $stream);
}
Harness::it('install descarga el core en un directorio vacío', function () {
$proj = tmpdir('proj');
$core = g7_core('0.1.0');
$tool = g7_toolbox();
$cmd = new InstallCommand(new Console());
$code = $cmd->run([$proj, '--toolbox=' . $tool, '--core-dir=' . $core, '--yes']);
eq(0, $code);
ok(is_file($proj . '/autoload.php'));
ok(is_file($proj . '/src/Libs/Router.php'));
ok(!is_file($proj . '/readme.org'), 'no copia la documentación del core');
eq('0.1.0', Lock::load($proj)->core()['version'], 'versión resuelta por tag v0.1.0');
rrmdir($proj);
rrmdir($core);
rrmdir($tool);
});
Harness::it('add copia componente, registra lock y manifest', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox();
$cmd = new AddCommand(new Console());
$code = $cmd->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
eq(0, $code);
ok(is_file($proj . '/src/Libs/Aria2.php'), 'archivo copiado');
$lock = Lock::load($proj);
ok($lock->has('http:aria2'), 'lock registra el componente');
rrmdir($proj);
rrmdir($tool);
});
Harness::it('add de paquete expande default; require trae dependencia', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox(false); // default sólo aria2
$cmd = new AddCommand(new Console());
$cmd->run(['http:compreFace', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
ok(is_file($proj . '/src/Libs/CompreFace.php'));
ok(is_file($proj . '/src/Libs/CurlRequest.php'), 'dependencia require instalada');
$proj2 = tmpdir('proj2');
$cmd->run(['http', '--root=' . $proj2, '--toolbox=' . $tool, '--yes']);
ok(is_file($proj2 . '/src/Libs/Aria2.php'));
ok(!is_file($proj2 . '/src/Libs/CompreFace.php'), 'default sólo trae lo declarado');
rrmdir($proj);
rrmdir($proj2);
rrmdir($tool);
});
Harness::it('remove sólo quita archivos del componente', function () {
$proj = tmpdir('proj');
$core = g7_core();
$tool = g7_toolbox();
(new InstallCommand(new Console()))->run([$proj, '--toolbox=' . $tool, '--core-dir=' . $core, '--yes']);
(new AddCommand(new Console()))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
(new RemoveCommand(new Console()))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
ok(!is_file($proj . '/src/Libs/Aria2.php'), 'archivo del componente eliminado');
ok(is_file($proj . '/src/Libs/Router.php'), 'archivo del core intacto');
rrmdir($proj);
rrmdir($core);
rrmdir($tool);
});
Harness::it('update core sólo toca rutas del core', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox();
$core = g7_core('1.0.0', 'router-v1');
(new InstallCommand(new Console()))->run([$proj, '--toolbox=' . $tool, '--core-dir=' . $core, '--yes']);
(new AddCommand(new Console()))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
$core2 = g7_core('2.0.0', 'router-v2');
(new UpdateCommand(new Console()))->run(['core', '--root=' . $proj, '--toolbox=' . $tool, '--core-dir=' . $core2, '--yes']);
ok(str_contains((string) file_get_contents($proj . '/src/Libs/Router.php'), 'router-v2'), 'core actualizado');
ok(is_file($proj . '/src/Libs/Aria2.php'), 'componente intacto');
eq('2.0.0', Lock::load($proj)->core()['version']);
rrmdir($proj);
rrmdir($tool);
rrmdir($core);
rrmdir($core2);
});
Harness::it('list muestra instalados con versión y modo', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox();
(new AddCommand(new Console()))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
$console = g7_console($stream);
(new ListCommand($console))->run(['--root=' . $proj, '--toolbox=' . $tool]);
rewind($stream);
$output = stream_get_contents($stream);
ok(str_contains($output, 'http:aria2'), 'id en la salida');
ok(str_contains($output, 'copy'), 'modo en la salida');
rrmdir($proj);
rrmdir($tool);
});
Harness::it('--dry-run no escribe archivos ni lock', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox();
(new AddCommand(new Console()))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes', '--dry-run']);
ok(!is_file($proj . '/src/Libs/Aria2.php'), 'no copia en dry-run');
ok(!is_file(Lock::path($proj)), 'no crea lock en dry-run');
rrmdir($proj);
rrmdir($tool);
});
Harness::it('core sin tags: versión desconocida y commit pineado', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox();
$core = g7_core(''); // repo git sin tags
(new InstallCommand(new Console()))->run([$proj, '--toolbox=' . $tool, '--core-dir=' . $core, '--yes']);
$lock = Lock::load($proj);
eq(null, $lock->core()['version'], 'sin tags la versión es desconocida');
ok($lock->core()['commit'] !== null, 'commit pineado sin depender de tags');
rrmdir($proj);
rrmdir($tool);
rrmdir($core);
});
Harness::it('--force resuelve drift pero no salta avisos de compatibilidad', function () {
$proj = tmpdir('proj');
$tool = g7_toolbox();
// add once and edit locally
(new AddCommand(new Console()))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes']);
write_file($proj . '/src/Libs/Aria2.php', "<?php\n// editado\n");
// package declares tested core 0.9 -> warning against core 0.0.0 (unknown) is OK;
// set a tested value to force a warning
$json = json_decode((string) file_get_contents($tool . '/packages/http/duckbrain.json'), true);
$json['core'] = ['requires' => '>=1.0'];
write_file($tool . '/packages/http/duckbrain.json', json_encode($json));
$stream = fopen('php://memory', 'r+');
$console = new Console($stream, $stream);
$code = (new AddCommand($console))->run(['http:aria2', '--root=' . $proj, '--toolbox=' . $tool, '--yes', '--force']);
eq(0, $code, 'force resuelve el drift');
rewind($stream);
$output = stream_get_contents($stream);
ok(str_contains($output, 'WARN'), 'sigue avisando de compatibilidad');
ok(str_contains((string) file_get_contents($proj . '/src/Libs/Aria2.php'), 'aria2'), 'sobreescribe con --force');
rrmdir($proj);
rrmdir($tool);
});