xref: /plugin/cachestats/cli.php (revision bd0f08c8d70aba669d14442513a922fd0f205c71)
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{
159cff4bafSAndreas Gohr    /** @var string[] */
169cff4bafSAndreas Gohr    private array $buckets = ['<1d', '<1w', '<1m', '<3m', '<6m', '<1y', '>1y'];
179cff4bafSAndreas 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
239cff4bafSAndreas 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
389cff4bafSAndreas Gohr        $format = $options->getOpt('format', 'table');
399cff4bafSAndreas Gohr        if (!in_array($format, ['table', 'json', 'csv'])) {
409cff4bafSAndreas Gohr            $this->error("Invalid format option '$format'. Allowed are: table, json, csv.");
419cff4bafSAndreas Gohr            return 1;
429cff4bafSAndreas Gohr        }
439cff4bafSAndreas Gohr
449cff4bafSAndreas 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) {
64a3092f6cSAndreas Gohr            $result[$key] = [
65a3092f6cSAndreas Gohr                'count' => $stats['extensions'][$key] ?? 0,
66a3092f6cSAndreas Gohr                'size' => $stats['sizes'][$key] ?? 0,
67a3092f6cSAndreas Gohr                'dups' => $stats['duplicates'][$key] ?? 0,
68a3092f6cSAndreas Gohr            ];
69*bd0f08c8SAndreas Gohr            foreach ($this->buckets as $bucket) {
70*bd0f08c8SAndreas Gohr                $result[$key][$bucket] = $stats['modified_groups'][$key][$bucket] ?? 0;
71*bd0f08c8SAndreas Gohr            }
72a3092f6cSAndreas Gohr        }
73a3092f6cSAndreas Gohr
74a3092f6cSAndreas Gohr        // sort with preserved keys
75a3092f6cSAndreas Gohr        uasort($result, function ($a, $b) use ($sort) {
76a3092f6cSAndreas Gohr            return $b[$sort] <=> $a[$sort];
77a3092f6cSAndreas Gohr        });
78a3092f6cSAndreas Gohr
799cff4bafSAndreas Gohr        match ($format) {
809cff4bafSAndreas Gohr            'json' => $this->print_json($result),
819cff4bafSAndreas Gohr            'csv' => $this->print_csv($result),
829cff4bafSAndreas Gohr            default => $this->print_table($result),
839cff4bafSAndreas Gohr        };
84a3092f6cSAndreas Gohr        return 0;
85a3092f6cSAndreas Gohr    }
86a3092f6cSAndreas Gohr
879cff4bafSAndreas Gohr    /**
889cff4bafSAndreas Gohr     * Output statistics as JSON
899cff4bafSAndreas Gohr     */
909cff4bafSAndreas Gohr    private function print_json(array $result): void
919cff4bafSAndreas Gohr    {
929cff4bafSAndreas Gohr        echo json_encode($result, JSON_PRETTY_PRINT);
939cff4bafSAndreas Gohr    }
949cff4bafSAndreas Gohr
959cff4bafSAndreas Gohr    /**
969cff4bafSAndreas Gohr     * Output statistics as CSV
979cff4bafSAndreas Gohr     */
989cff4bafSAndreas Gohr    private function print_csv(array $result): void
999cff4bafSAndreas Gohr    {
1009cff4bafSAndreas Gohr        $handle = fopen('php://output', 'w');
1019cff4bafSAndreas Gohr        if ($handle === false) {
1029cff4bafSAndreas Gohr            $this->error('Could not open output for CSV.');
1039cff4bafSAndreas Gohr            return;
1049cff4bafSAndreas Gohr        }
1059cff4bafSAndreas Gohr
106*bd0f08c8SAndreas Gohr        $header = array_merge(['extension'], array_keys(reset($result)));
1079cff4bafSAndreas Gohr        fputcsv($handle, $header);
1089cff4bafSAndreas Gohr
1099cff4bafSAndreas Gohr        foreach ($result as $ext => $data) {
110*bd0f08c8SAndreas Gohr            fputcsv($handle, array_merge([$ext], $data));
1119cff4bafSAndreas Gohr        }
1129cff4bafSAndreas Gohr    }
1139cff4bafSAndreas Gohr
1149cff4bafSAndreas Gohr    /**
1159cff4bafSAndreas Gohr     * Output statistics as table
1169cff4bafSAndreas Gohr     */
1179cff4bafSAndreas Gohr    private function print_table(array $result): void
1189cff4bafSAndreas Gohr    {
119*bd0f08c8SAndreas Gohr        $colWidth = 9;
120*bd0f08c8SAndreas Gohr
121*bd0f08c8SAndreas Gohr        $headers = array_merge(['ext'], array_keys(reset($result)));
122*bd0f08c8SAndreas Gohr        $widths = array_merge(['*'], array_fill(0, count($headers) -1, $colWidth));
123*bd0f08c8SAndreas Gohr        $colors = array_fill(0, count($headers), '');
124*bd0f08c8SAndreas Gohr
125*bd0f08c8SAndreas Gohr        // ensure terminal is wide enough, otherwise break ugly
126a3092f6cSAndreas Gohr        $tr = new TableFormatter($this->colors);
127*bd0f08c8SAndreas Gohr        if($tr->getMaxWidth() < $colWidth * count($headers)){;
128*bd0f08c8SAndreas Gohr            $tr->setMaxWidth($colWidth * count($headers) + 10);
129*bd0f08c8SAndreas Gohr        }
130*bd0f08c8SAndreas Gohr
131*bd0f08c8SAndreas Gohr        echo $tr->format($widths, $headers, $colors);
132a3092f6cSAndreas Gohr
133a3092f6cSAndreas Gohr        foreach ($result as $ext => $data) {
134*bd0f08c8SAndreas Gohr            array_walk(
135*bd0f08c8SAndreas Gohr                $data,
136*bd0f08c8SAndreas Gohr                fn (&$v, $k) => $v = sprintf(
137*bd0f08c8SAndreas Gohr                    "% ${colWidth}s",
138*bd0f08c8SAndreas Gohr                    ($k == 'size') ? filesize_h($v) : number_format($v)
139*bd0f08c8SAndreas Gohr                )
140*bd0f08c8SAndreas Gohr            );
141*bd0f08c8SAndreas Gohr
1429cff4bafSAndreas Gohr            echo $tr->format(
143*bd0f08c8SAndreas Gohr                $widths,
144*bd0f08c8SAndreas Gohr                array_merge([$ext], array_values($data)),
145*bd0f08c8SAndreas Gohr                $colors
146a3092f6cSAndreas Gohr            );
147a3092f6cSAndreas Gohr        }
148a3092f6cSAndreas Gohr    }
149a3092f6cSAndreas Gohr}
150