Files
rspade_system/app/RSpade/Commands/Rsx/Clean_Command.php
root 29c657f7a7 Exclude tests directory from framework publish
Add 100+ automated unit tests from .expect file specifications
Add session system test
Add rsx:constants:regenerate command test
Add rsx:logrotate command test
Add rsx:clean command test
Add rsx:manifest:stats command test
Add model enum system test
Add model mass assignment prevention test
Add rsx:check command test
Add migrate:status command test

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-25 03:59:58 +00:00

202 lines
6.5 KiB
PHP

<?php
/**
* CODING CONVENTION:
* This file follows the coding convention where variable_names and function_names
* use snake_case (underscore_wherever_possible).
*/
namespace App\RSpade\Commands\Rsx;
use Exception;
use Illuminate\Console\Command;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
class Clean_Command extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'rsx:clean {--silent : Suppress all output except errors}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Clean RSX caches, build artifacts, and temp files';
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
// Prevent being called via $this->call() - must use passthru for fresh process
$this->prevent_call_from_another_command();
$silent = $this->option('silent');
// Show warning if not in framework developer mode
$is_framework_dev = config('rsx.code_quality.is_framework_developer', false);
if (!$is_framework_dev && !$silent) {
$this->warn('⚠️ Running rsx:clean is rarely necessary');
$this->line('');
$this->line(' The manifest system automatically detects and rebuilds when files change.');
$this->line(' Manual cache clearing only adds 30-60 seconds to the next request.');
$this->line('');
$this->line(' Only run this command if:');
$this->line(' • Catastrophic errors require a fresh start');
$this->line(' • Framework code itself was updated outside normal workflows');
$this->line(' • Explicitly instructed by framework documentation');
$this->line('');
$this->line(' Consider removing rsx:clean from your development workflow.');
$this->newLine();
}
if (!$silent) {
$this->info('🧹 Cleaning RSX caches...');
$this->newLine();
}
$cleaned_items = [];
// 1. Clear rsx-build directory recursively - EVERYTHING
$build_path = storage_path('rsx-build');
if (is_dir($build_path)) {
$this->clear_directory($build_path);
$cleaned_items[] = '✓ Build storage cleaned';
}
// 2. Clear rsx-tmp directory recursively - EVERYTHING
$tmp_path = storage_path('rsx-tmp');
if (is_dir($tmp_path)) {
$this->clear_directory($tmp_path);
$cleaned_items[] = '✓ Temp storage cleaned';
}
// 3. Clear Redis cache directly without loading framework
try {
$redis = \Illuminate\Support\Facades\Redis::connection();
$redis->flushdb();
$cleaned_items[] = '✓ Redis cache cleared';
} catch (Exception $e) {
$cleaned_items[] = '⊘ Redis cache skipped (not configured or unreachable)';
}
// Note: We never clear rsx-locks directory as it contains active lock files
// Display results
if (!$silent) {
if (empty($cleaned_items)) {
$this->info('Nothing to clean - all caches already empty');
} else {
foreach ($cleaned_items as $item) {
$this->line(" $item");
}
$this->newLine();
$this->info('✅ RSX caches cleaned successfully');
}
}
return 0;
}
/**
* Clean a directory recursively
*
* @param string $path
* @return void
*/
protected function clear_directory($path)
{
if (!is_dir($path)) {
return;
}
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($files as $file) {
if ($file->isDir()) {
rmdir($file->getRealPath());
} else {
unlink($file->getRealPath());
}
}
}
/**
* Count files in a directory recursively
*
* @param string $path
* @return int
*/
protected function count_files_in_directory($path)
{
if (!is_dir($path)) {
return 0;
}
$count = 0;
$files = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($files as $file) {
if ($file->isFile()) {
$count++;
}
}
return $count;
}
/**
* Prevent this command from being called via $this->call() from another command
*
* This command MUST run in a fresh process to ensure in-memory caches are cleared.
* Use passthru() instead of $this->call() when calling from other commands.
*
* @return void
*/
protected function prevent_call_from_another_command()
{
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 20);
foreach ($trace as $frame) {
// Check if we're being called from Artisan::call() or Command::call()
if (isset($frame['class']) && isset($frame['function'])) {
$class = $frame['class'];
$function = $frame['function'];
// Detect $this->call() from another command
if ($function === 'call' && str_contains($class, 'Command')) {
$this->error('');
$this->error('❌ FATAL ERROR: rsx:clean cannot be called via $this->call()');
$this->error('');
$this->error('This command MUST run in a fresh process to properly clear in-memory caches.');
$this->error('');
$this->error('FIX: Use passthru() instead of $this->call():');
$this->error('');
$this->line(' // ❌ WRONG - runs in same process, caches remain in memory');
$this->line(' $this->call(\'rsx:clean\');');
$this->error('');
$this->line(' // ✅ CORRECT - fresh process, all caches cleared');
$this->line(' passthru(\'php artisan rsx:clean\');');
$this->error('');
exit(1);
}
}
}
}
}