1a3092f6cSAndreas Gohr<?php 2a3092f6cSAndreas Gohr 3a3092f6cSAndreas Gohruse dokuwiki\plugin\cachestats\FileStatistics; 4a3092f6cSAndreas Gohruse splitbrain\phpcli\Options; 5a3092f6cSAndreas Gohruse splitbrain\phpcli\TableFormatter; 6a3092f6cSAndreas Gohr 7a3092f6cSAndreas Gohr/** 8a3092f6cSAndreas Gohr * DokuWiki Plugin cachestats (CLI Component) 9a3092f6cSAndreas Gohr * 10a3092f6cSAndreas Gohr * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html 11a3092f6cSAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 12a3092f6cSAndreas Gohr */ 13a3092f6cSAndreas Gohrclass cli_plugin_cachestats extends \dokuwiki\Extension\CLIPlugin 14a3092f6cSAndreas Gohr{ 15*9cff4bafSAndreas Gohr /** @var string[] */ 16*9cff4bafSAndreas Gohr private array $buckets = ['<1d', '<1w', '<1m', '<3m', '<6m', '<1y', '>1y']; 17*9cff4bafSAndreas Gohr 18a3092f6cSAndreas Gohr /** @inheritDoc */ 19a3092f6cSAndreas Gohr protected function setup(Options $options) 20a3092f6cSAndreas Gohr { 21a3092f6cSAndreas Gohr $options->setHelp('Collect statistics about the cache directory.'); 22a3092f6cSAndreas Gohr 23*9cff4bafSAndreas Gohr $options->registerOption('format', 'Output format: table|json|csv', 'f', 'table'); 24a3092f6cSAndreas Gohr $options->registerOption('sort', 'Sort by count|size|dups', 's', false); 25a3092f6cSAndreas Gohr } 26a3092f6cSAndreas Gohr 27a3092f6cSAndreas Gohr /** @inheritDoc */ 28a3092f6cSAndreas Gohr protected function main(Options $options) 29a3092f6cSAndreas Gohr { 30a3092f6cSAndreas Gohr global $conf; 31a3092f6cSAndreas Gohr 32a3092f6cSAndreas Gohr $sort = $options->getOpt('sort', 'size'); 33a3092f6cSAndreas Gohr if (!in_array($sort, ['count', 'size', 'dups'])) { 34a3092f6cSAndreas Gohr $this->error("Invalid sort option '$sort'. Allowed are: count, size, dups."); 35a3092f6cSAndreas Gohr return 1; 36a3092f6cSAndreas Gohr } 37a3092f6cSAndreas Gohr 38*9cff4bafSAndreas Gohr $format = $options->getOpt('format', 'table'); 39*9cff4bafSAndreas Gohr if (!in_array($format, ['table', 'json', 'csv'])) { 40*9cff4bafSAndreas Gohr $this->error("Invalid format option '$format'. Allowed are: table, json, csv."); 41*9cff4bafSAndreas Gohr return 1; 42*9cff4bafSAndreas Gohr } 43*9cff4bafSAndreas Gohr 44*9cff4bafSAndreas Gohr if ($format === 'json') { 45a3092f6cSAndreas Gohr fprintf(STDERR, 'Collecting cache statistics from ' . $conf['cachedir'] . "…\n"); 46a3092f6cSAndreas Gohr } else { 47a3092f6cSAndreas Gohr $this->info('Collecting cache statistics from ' . $conf['cachedir'] . '…'); 48a3092f6cSAndreas Gohr } 49a3092f6cSAndreas Gohr 50a3092f6cSAndreas Gohr $stats = (new FileStatistics($conf['cachedir']))->collect(); 51a3092f6cSAndreas Gohr 52a3092f6cSAndreas Gohr // for debugging 53a3092f6cSAndreas Gohr print_r($stats); 54a3092f6cSAndreas Gohr 55a3092f6cSAndreas Gohr $keys = array_unique( 56a3092f6cSAndreas Gohr array_merge( 57a3092f6cSAndreas Gohr array_keys($stats['extensions']), 58a3092f6cSAndreas Gohr array_keys($stats['sizes']), 59a3092f6cSAndreas Gohr array_keys($stats['duplicates']) 60a3092f6cSAndreas Gohr ) 61a3092f6cSAndreas Gohr ); 62a3092f6cSAndreas Gohr $result = []; 63a3092f6cSAndreas Gohr foreach ($keys as $key) { 64*9cff4bafSAndreas Gohr $modified = []; 65*9cff4bafSAndreas Gohr foreach ($this->buckets as $bucket) { 66*9cff4bafSAndreas Gohr $modified[$bucket] = $stats['modified_groups'][$key][$bucket] ?? 0; 67*9cff4bafSAndreas Gohr } 68a3092f6cSAndreas Gohr $result[$key] = [ 69a3092f6cSAndreas Gohr 'count' => $stats['extensions'][$key] ?? 0, 70a3092f6cSAndreas Gohr 'size' => $stats['sizes'][$key] ?? 0, 71a3092f6cSAndreas Gohr 'dups' => $stats['duplicates'][$key] ?? 0, 72*9cff4bafSAndreas Gohr 'modified' => $modified, 73a3092f6cSAndreas Gohr ]; 74a3092f6cSAndreas Gohr } 75a3092f6cSAndreas Gohr 76a3092f6cSAndreas Gohr // sort with preserved keys 77a3092f6cSAndreas Gohr uasort($result, function ($a, $b) use ($sort) { 78a3092f6cSAndreas Gohr return $b[$sort] <=> $a[$sort]; 79a3092f6cSAndreas Gohr }); 80a3092f6cSAndreas Gohr 81*9cff4bafSAndreas Gohr match ($format) { 82*9cff4bafSAndreas Gohr 'json' => $this->print_json($result), 83*9cff4bafSAndreas Gohr 'csv' => $this->print_csv($result), 84*9cff4bafSAndreas Gohr default => $this->print_table($result), 85*9cff4bafSAndreas Gohr }; 86a3092f6cSAndreas Gohr return 0; 87a3092f6cSAndreas Gohr } 88a3092f6cSAndreas Gohr 89*9cff4bafSAndreas Gohr /** 90*9cff4bafSAndreas Gohr * Output statistics as JSON 91*9cff4bafSAndreas Gohr */ 92*9cff4bafSAndreas Gohr private function print_json(array $result): void 93*9cff4bafSAndreas Gohr { 94*9cff4bafSAndreas Gohr echo json_encode($result, JSON_PRETTY_PRINT); 95*9cff4bafSAndreas Gohr } 96*9cff4bafSAndreas Gohr 97*9cff4bafSAndreas Gohr /** 98*9cff4bafSAndreas Gohr * Output statistics as CSV 99*9cff4bafSAndreas Gohr */ 100*9cff4bafSAndreas Gohr private function print_csv(array $result): void 101*9cff4bafSAndreas Gohr { 102*9cff4bafSAndreas Gohr $handle = fopen('php://output', 'w'); 103*9cff4bafSAndreas Gohr if ($handle === false) { 104*9cff4bafSAndreas Gohr $this->error('Could not open output for CSV.'); 105*9cff4bafSAndreas Gohr return; 106*9cff4bafSAndreas Gohr } 107*9cff4bafSAndreas Gohr 108*9cff4bafSAndreas Gohr $header = array_merge( 109*9cff4bafSAndreas Gohr ['extension', 'count', 'total_size_bytes', 'duplicate_files'], 110*9cff4bafSAndreas Gohr $this->buckets 111*9cff4bafSAndreas Gohr ); 112*9cff4bafSAndreas Gohr fputcsv($handle, $header); 113*9cff4bafSAndreas Gohr 114*9cff4bafSAndreas Gohr foreach ($result as $ext => $data) { 115*9cff4bafSAndreas Gohr $row = [ 116*9cff4bafSAndreas Gohr $ext, 117*9cff4bafSAndreas Gohr $data['count'], 118*9cff4bafSAndreas Gohr $data['size'], 119*9cff4bafSAndreas Gohr $data['dups'] 120*9cff4bafSAndreas Gohr ]; 121*9cff4bafSAndreas Gohr foreach ($this->buckets as $bucket) { 122*9cff4bafSAndreas Gohr $row[] = $data['modified'][$bucket]; 123*9cff4bafSAndreas Gohr } 124*9cff4bafSAndreas Gohr fputcsv($handle, $row); 125*9cff4bafSAndreas Gohr } 126*9cff4bafSAndreas Gohr } 127*9cff4bafSAndreas Gohr 128*9cff4bafSAndreas Gohr /** 129*9cff4bafSAndreas Gohr * Output statistics as table 130*9cff4bafSAndreas Gohr */ 131*9cff4bafSAndreas Gohr private function print_table(array $result): void 132*9cff4bafSAndreas Gohr { 133a3092f6cSAndreas Gohr $tr = new TableFormatter($this->colors); 134*9cff4bafSAndreas Gohr $columns = array_merge(['*', 7, 10, 7], array_fill(0, count($this->buckets), 5)); 135*9cff4bafSAndreas Gohr $headers = array_merge( 136a3092f6cSAndreas Gohr ['Extension', 'File Count', 'Total Size (bytes)', 'Duplicate Files'], 137*9cff4bafSAndreas Gohr $this->buckets 138*9cff4bafSAndreas Gohr ); 139*9cff4bafSAndreas Gohr echo $tr->format( 140*9cff4bafSAndreas Gohr $columns, 141*9cff4bafSAndreas Gohr $headers, 142a3092f6cSAndreas Gohr ['', '', '', ''] 143a3092f6cSAndreas Gohr ); 144a3092f6cSAndreas Gohr 145a3092f6cSAndreas Gohr foreach ($result as $ext => $data) { 146*9cff4bafSAndreas Gohr $row = [ 147a3092f6cSAndreas Gohr $ext, 148*9cff4bafSAndreas Gohr sprintf("% 7s", number_format($data['count'])), 149a3092f6cSAndreas Gohr sprintf("% 10s", filesize_h($data['size'])), 150*9cff4bafSAndreas Gohr sprintf("% 7s", number_format($data['dups'])) 151*9cff4bafSAndreas Gohr ]; 152*9cff4bafSAndreas Gohr foreach ($this->buckets as $bucket) { 153*9cff4bafSAndreas Gohr $row[] = sprintf("% 5s", number_format($data['modified'][$bucket])); 154*9cff4bafSAndreas Gohr } 155*9cff4bafSAndreas Gohr echo $tr->format( 156*9cff4bafSAndreas Gohr $columns, 157*9cff4bafSAndreas Gohr $row, 158a3092f6cSAndreas Gohr ['', '', '', ''] 159a3092f6cSAndreas Gohr ); 160a3092f6cSAndreas Gohr } 161a3092f6cSAndreas Gohr } 162a3092f6cSAndreas Gohr} 163