source: trunk/htdocs/coverager/index.php @ 1126

Last change on this file since 1126 was 1126, checked in by moo, 2 years ago

dont show empty todo for directory out of include_dir

  • Property svn:eol-style set to native
File size: 7.8 KB
Line 
1<?php
2
3include "./common.php";
4
5class XcacheCoverageViewer
6{
7    var $syntax_higlight = true;
8    var $use_cache = false;
9    var $include_paths = array();
10    var $exclude_paths = array();
11    var $charset = 'UTF-8';
12    var $lang = 'en-us';
13    var $datadir = null;
14    var $datadir_len = null;
15    var $path = null;
16    var $outpath = null;
17
18    function XcacheCoverageViewer()
19    {
20        $this->datadir = ini_get('xcache.coveragedump_directory');
21
22        global $config;
23        foreach (array('charset', 'include_paths', 'exclude_paths', 'syntax_higlight', 'use_cache', 'datadir', 'lang') as $k) {
24            if (isset($config[$k])) {
25                $this->{$k} = $config[$k];
26            }
27        }
28
29        $this->datadir = preg_replace('!/$!', '', $this->datadir);
30        $this->datadir_len = strlen($this->datadir);
31
32        $this->path = isset($_GET['path']) ? $_GET['path'] : '';
33        $this->path = preg_replace('!\.{2,}!', '.', $this->path);
34        $qsep = preg_quote(DIRECTORY_SEPARATOR, '!');
35        $this->path = preg_replace("![\\\\$qsep]{2,}!", DIRECTORY_SEPARATOR, $this->path);
36        $this->path = preg_replace("!$qsep$!", '', $this->path);
37        if ($this->path == '/') {
38            $this->path = '';
39        }
40        $this->outpath = $this->datadir . $this->path;
41    }
42
43    function main()
44    {
45        $path = $this->path;
46
47        if (is_dir($this->outpath)) {
48            $action = 'dir';
49            $prefix_len = strlen($path) + 1;
50            $dirinfo = $this->loadDir($this->outpath);
51            if (!$this->use_cache) {
52                ksort($dirinfo['subdirs']);
53                ksort($dirinfo['files']);
54            }
55        }
56        else if (is_file($this->outpath . ".pcov")) {
57            $action = 'file';
58
59            $dir = dirname($path);
60            $filename = basename($path);
61
62            $fileinfo = $this->loadCov($this->outpath . ".pcov");
63
64            $lines = file($path);
65            // fix the tabs not in the middle
66            foreach ($lines as $l => $line) {
67                if (preg_match('!^(\\t*)([^\\t]+\\t.*)$!s', $line, $m)) {
68                    $lines[$l] = $m[1];
69                    $chunks = explode("\t", $m[2]);
70                    for ($i = 0, $c = count($chunks) - 1; $i < $c; $i ++) {
71                        $lines[$l] .= $chunks[$i] . str_repeat(" ", 4 - (strlen($chunks[$i]) % 4));
72                    }
73                    $lines[$l] .= $chunks[$c];
74                }
75            }
76            if ($this->syntax_higlight) {
77                $source = implode('', $lines);
78                ob_start();
79                highlight_string($source);
80                $lines = str_replace("\n", "", ob_get_clean());
81                $lines = str_replace('<code>', '', $lines);
82                $lines = str_replace('</code>', '', $lines);
83                $lines = preg_replace('(^<span[^>]*>|</span>$)', '', $lines);
84                $lines = explode('<br />', $lines);
85                $last = array_pop($lines);
86                $lines[count($lines) - 1] .= $last;
87                $filecov = sprint_cov($fileinfo['cov'], $lines, false);
88                unset($source);
89            }
90            else {
91                $filecov = sprint_cov($fileinfo['cov'], $lines);
92            }
93
94            list($tplfile, $tpllines, $tplcov) = $this->loadTplCov($fileinfo['cov'], substr($this->outpath, $this->datadir_len));
95            if ($tplfile) {
96                $tplcov = sprint_cov($tplcov, $tpllines);
97                unset($tpllines);
98            }
99        }
100        else if (!$this->datadir) {
101            $action = 'error';
102            $error  = 'require `xcache.coveragedump_directory` in ini or `$datadir` in config to be set';
103        }
104        else {
105            $action = 'error';
106            $error  = "no data";
107        }
108
109        global $config;
110        include "coverager.tpl.php";
111    }
112
113    function loadDir($outdir, $addtodo = null)
114    {
115        if ($this->use_cache) {
116            $cachefile = $outdir . "/.pcovcache";
117            if (file_exists($cachefile)) {
118                return unserialize(file_get_contents($cachefile));
119            }
120        }
121        $srcdir = substr($outdir, $this->datadir_len);
122
123        $total = $hits = $todos = 0;
124        $files = array();
125        $subdirs = array();
126        if (!isset($addtodo)) {
127            if ($this->include_paths) {
128                foreach ($this->include_paths as $p) {
129                    if (strncmp($p, $srcdir, strlen($p)) == 0) {
130                        $addtodo = true;
131                        break;
132                    }
133                }
134            }
135        }
136        if ($addtodo) {
137            if ($this->exclude_paths) {
138                foreach ($this->exclude_paths as $p) {
139                    if (strncmp($p, $srcdir, strlen($p)) == 0) {
140                        $addtodo = false;
141                        break;
142                    }
143                }
144            }
145        }
146        foreach (glob($outdir . "/*") as $outfile) {
147            if (is_dir($outfile)) {
148                $info = $this->loadDir($outfile, $addtodo);
149                $srcfile = substr($outfile, $this->datadir_len);
150                $subdirs += $info['subdirs'];
151                $total   += $info['total'];
152                $hits    += $info['hits'];
153                if ($addtodo === true) {
154                    $todos += $info['todos'];
155                }
156                unset($info['subdirs']);
157                $subdirs[$srcfile] = $info;
158            }
159            else if (substr($outfile, -5) == ".pcov") {
160                // pass
161                $info = $this->loadFile($outfile);
162                $total += $info['total'];
163                $hits  += $info['hits'];
164                $srcfile = substr($outfile, $this->datadir_len, -5);
165                $files[$srcfile] = $info;
166            }
167            else {
168                continue;
169            }
170        }
171        if ($addtodo === true) {
172            foreach (glob($srcdir . "/*") as $srcfile) {
173                if (!isset($files[$srcfile]) && is_file($srcfile)) {
174                    $files[$srcfile] = array('total' => 0, 'hits' => 0);
175                    $todos ++;
176                }
177                else if (!isset($subdirs[$srcfile]) && is_dir($srcfile)) {
178                    $subdirs[$srcfile] = array('total' => 0, 'hits' => 0, 'todos' => 1, 'files' => 0, 'subdirs' => array());
179                    $todos ++;
180                }
181            }
182        }
183
184        if ($this->use_cache) {
185            ksort($subdirs);
186            ksort($files);
187        }
188
189        $info = array(
190                'total'   => $total,
191                'hits'    => $hits,
192                'todos'   => $todos,
193                'files'   => $files,
194                'subdirs' => $subdirs,
195                );
196
197        if ($this->use_cache) {
198            $fp = fopen($cachefile, "wb");
199            fwrite($fp, serialize($info));
200            fclose($fp);
201        }
202        return $info;
203    }
204
205    function loadFile($file)
206    {
207        if ($this->use_cache) {
208            $cachefile = $file . "cache";
209            if (file_exists($cachefile)) {
210                return unserialize(file_get_contents($cachefile));
211            }
212        }
213
214        $info = $this->loadCov($file); //, $lines);
215        unset($info['cov']);
216
217        if ($this->use_cache) {
218            $fp = fopen($cachefile, "wb");
219            fwrite($fp, serialize($info));
220            fclose($fp);
221        }
222        return $info;
223    }
224
225    function loadCov($file)//, $lines)
226    {
227        $total = $hits = 0;
228
229        $cov = xcache_coverager_decode(file_get_contents($file));
230
231        return array('total' => count($cov) - 1, 'hits' => $cov[0], 'cov' => $cov);
232    }
233
234    function loadTplCov($cov, $ctpl)
235    {
236        $tplinfofile = $ctpl . '.phpinfo';
237
238        if (!file_exists($tplinfofile)) {
239            return;
240        }
241
242        $tplinfo = unserialize(file_get_contents($tplinfofile));
243
244        if (!isset($tplinfo['sourceFile'])) {
245            return;
246        }
247        $tplfile = $tplinfo['sourceFile'];
248        if (!isset($tplinfo['lineMap']) || !count($tplinfo['lineMap'])) {
249            return;
250        }
251
252        $tpllines = file($tplfile);
253
254        $dline = 0;
255        $sline = 0;
256        $tplcov = array();
257        foreach ($cov as $line => $times) {
258            // find nearest line
259            while ($dline < $line) {
260                if ((list($dline, $sline) = each($tplinfo['lineMap'])) === false) {
261                    break 2;
262                }
263            }
264
265            $tplcov[$sline] = $times;
266        }
267        return array($tplfile, $tpllines, $tplcov);
268    }
269}
270
271function sprint_cov($cov, $lines, $encode = true)
272{
273    $lastattr = null;
274    foreach ($lines as $l => $line) {
275        $offs = $l + 1;
276        if ($encode) {
277            $line = str_replace("\n", "", htmlspecialchars($line));
278        }
279        else if ($line !== "") {
280            if (substr($line, 0, 7) == '</span>') {
281                $lastattr = null;
282                $line = substr($line, 7);
283            }
284            else if (isset($lastattr)) {
285                $line = $lastattr . $line;
286            }
287
288            if (preg_match('!(<span[^>]+>|</span>)[^<>]*$!', $line, $m)) {
289                if ($m[1] == '</span>') {
290                    $lastattr = null;
291                }
292                else {
293                    $line .= '</span>';
294                    $lastattr = $m[1];
295                }
296            }
297        }
298        if (isset($cov[$offs])) {
299            $lines[$l] = sprintf("<li class=\"line%sCov\"><pre class=\"code\"> %s\t%s\n</pre></li>"
300                    , $cov[$offs] ? '' : 'No'
301                    , $cov[$offs]
302                    , $line);
303        }
304        else {
305            $lines[$l] = "<li><pre class=\"code\">\t$line\n</pre></li>";
306        }
307    }
308    return implode('', $lines);
309}
310
311if (!function_exists('xcache_coverager_decode')) {
312    function xcache_coverager_decode($bytes)
313    {
314        $bytes = unpack('l*', $bytes);
315        $i = 1;
316        if ($bytes[$i ++] != 0x564f4350) {
317            return null;
318        }
319        $end = count($bytes);
320        $cov = array();
321        for (/* empty*/; $i <= $end; $i += 2) {
322            $hits = $bytes[$i + 1];
323            $cov[$bytes[$i]] = $hits <= 0 ? 0 : $hits;
324        }
325        return $cov;
326    }
327}
328
329$app = new XcacheCoverageViewer();
330$app->main();
331
332?>
Note: See TracBrowser for help on using the repository browser.