source: branches/1.3/coverager/coverager.php @ 614

Last change on this file since 614 was 614, checked in by moo, 5 years ago

merged r460,r613 from trunk

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