source: trunk/htdocs/coverager/coverager.php @ 1053

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

refactor: move htdocs, bin, lib for easier installation

  • Property svn:eol-style set to native
File size: 7.7 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                $todos   += $info['todos'];
154                unset($info['subdirs']);
155                $subdirs[$srcfile] = $info;
156            }
157            else if (substr($outfile, -5) == ".pcov") {
158                // pass
159                $info = $this->loadFile($outfile);
160                $total += $info['total'];
161                $hits  += $info['hits'];
162                $srcfile = substr($outfile, $this->datadir_len, -5);
163                $files[$srcfile] = $info;
164            }
165            else {
166                continue;
167            }
168        }
169        if ($addtodo === true) {
170            foreach (glob($srcdir . "/*") as $srcfile) {
171                if (!isset($files[$srcfile]) && is_file($srcfile)) {
172                    $files[$srcfile] = array('total' => 0, 'hits' => 0);
173                    $todos ++;
174                }
175                else if (!isset($subdirs[$srcfile]) && is_dir($srcfile)) {
176                    $subdirs[$srcfile] = array('total' => 0, 'hits' => 0, 'todos' => 1, 'files' => 0, 'subdirs' => array());
177                    $todos ++;
178                }
179            }
180        }
181
182        if ($this->use_cache) {
183            ksort($subdirs);
184            ksort($files);
185        }
186
187        $info = array(
188                'total'   => $total,
189                'hits'    => $hits,
190                'todos'   => $todos,
191                'files'   => $files,
192                'subdirs' => $subdirs,
193                );
194
195        if ($this->use_cache) {
196            $fp = fopen($cachefile, "wb");
197            fwrite($fp, serialize($info));
198            fclose($fp);
199        }
200        return $info;
201    }
202
203    function loadFile($file)
204    {
205        if ($this->use_cache) {
206            $cachefile = $file . "cache";
207            if (file_exists($cachefile)) {
208                return unserialize(file_get_contents($cachefile));
209            }
210        }
211
212        $info = $this->loadCov($file); //, $lines);
213        unset($info['cov']);
214
215        if ($this->use_cache) {
216            $fp = fopen($cachefile, "wb");
217            fwrite($fp, serialize($info));
218            fclose($fp);
219        }
220        return $info;
221    }
222
223    function loadCov($file)//, $lines)
224    {
225        $total = $hits = 0;
226
227        $cov = xcache_coverager_decode(file_get_contents($file));
228
229        return array('total' => count($cov) - 1, 'hits' => $cov[0], 'cov' => $cov);
230    }
231
232    function loadTplCov($cov, $ctpl)
233    {
234        $tplinfofile = $ctpl . '.phpinfo';
235
236        if (!file_exists($tplinfofile)) {
237            return;
238        }
239
240        $tplinfo = unserialize(file_get_contents($tplinfofile));
241
242        if (!isset($tplinfo['sourceFile'])) {
243            return;
244        }
245        $tplfile = $tplinfo['sourceFile'];
246        if (!isset($tplinfo['lineMap']) || !count($tplinfo['lineMap'])) {
247            return;
248        }
249
250        $tpllines = file($tplfile);
251
252        $dline = 0;
253        $sline = 0;
254        $tplcov = array();
255        foreach ($cov as $line => $times) {
256            // find nearest line
257            while ($dline < $line) {
258                if ((list($dline, $sline) = each($tplinfo['lineMap'])) === false) {
259                    break 2;
260                }
261            }
262
263            $tplcov[$sline] = $times;
264        }
265        return array($tplfile, $tpllines, $tplcov);
266    }
267}
268
269function sprint_cov($cov, $lines, $encode = true)
270{
271    $lastattr = null;
272    foreach ($lines as $l => $line) {
273        $offs = $l + 1;
274        if ($encode) {
275            $line = str_replace("\n", "", htmlspecialchars($line));
276        }
277        else if ($line !== "") {
278            if (substr($line, 0, 7) == '</span>') {
279                $lastattr = null;
280                $line = substr($line, 7);
281            }
282            else if (isset($lastattr)) {
283                $line = $lastattr . $line;
284            }
285
286            if (preg_match('!(<span[^>]+>|</span>)[^<>]*$!', $line, $m)) {
287                if ($m[1] == '</span>') {
288                    $lastattr = null;
289                }
290                else {
291                    $line .= '</span>';
292                    $lastattr = $m[1];
293                }
294            }
295        }
296        if (isset($cov[$offs])) {
297            $lines[$l] = sprintf("<li class=\"line%sCov\"><pre class=\"code\"> %s\t%s\n</pre></li>"
298                    , $cov[$offs] ? '' : 'No'
299                    , $cov[$offs]
300                    , $line);
301        }
302        else {
303            $lines[$l] = "<li><pre class=\"code\">\t$line\n</pre></li>";
304        }
305    }
306    return implode('', $lines);
307}
308
309if (!function_exists('xcache_coverager_decode')) {
310    function xcache_coverager_decode($bytes)
311    {
312        $bytes = unpack('l*', $bytes);
313        $i = 1;
314        if ($bytes[$i ++] != 0x564f4350) {
315            return null;
316        }
317        $end = count($bytes);
318        $cov = array();
319        for (/* empty*/; $i <= $end; $i += 2) {
320            $hits = $bytes[$i + 1];
321            $cov[$bytes[$i]] = $hits <= 0 ? 0 : $hits;
322        }
323        return $cov;
324    }
325}
326
327$app = new XcacheCoverageViewer();
328$app->main();
329
330?>
Note: See TracBrowser for help on using the repository browser.