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