source: trunk/coverager/coverager.php @ 464

Last change on this file since 464 was 464, checked in by moo, 7 years ago

fix lastattr

  • Property svn:eol-style set to native
File size: 8.1 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);
[463]110                $lines = str_replace("\n", "", ob_get_clean());
111                $lines = str_replace('<code>', '', $lines);
112                $lines = str_replace('</code>', '', $lines);
113                $lines = preg_replace('(^<span[^>]*>|</span>$)', '', $lines);
114                $lines = explode('<br />', $lines);
[33]115                $last = array_pop($lines);
116                $filecov = sprint_cov($fileinfo['cov'], $lines, false);
117                $filecov .= $last;
118                unset($source);
119            }
120            else {
121                $filecov = sprint_cov($fileinfo['cov'], $lines);
122            }
123
124            list($tplfile, $tpllines, $tplcov) = $this->loadTplCov($fileinfo['cov'], substr($this->outpath, $this->datadir_len));
125            if ($tplfile) {
[184]126                $tplcov = sprint_cov($tplcov, $tpllines);
[33]127                unset($tpllines);
128            }
129        }
130        else if (!$this->datadir) {
[185]131            $action = 'error';
132            $error  = 'require `ini:xcache.coveragedump_directory` or `config:$datadir` to be set';
[33]133        }
134        else {
[185]135            $action = 'error';
136            $error  = "no data";
[33]137        }
138
[183]139        $xcache_version = defined('XCACHE_VERSION') ? XCACHE_VERSION : '';
[33]140        include("coverager.tpl.php");
141    }
142
143    function loadDir($outdir, $addtodo = null)
144    {
145        if ($this->usecache) {
146            $cachefile = $outdir . "/.pcovcache";
147            if (file_exists($cachefile)) {
148                return unserialize(file_get_contents($cachefile));
149            }
150        }
151        $srcdir = substr($outdir, $this->datadir_len);
152
153        $total = $hits = $todos = 0;
154        $files = array();
155        $subdirs = array();
156        if (!isset($addtodo)) {
157            if ($this->include_paths) {
158                foreach ($this->include_paths as $p) {
159                    if (strncmp($p, $srcdir, strlen($p)) == 0) {
160                        $addtodo = true;
161                        break;
162                    }
163                }
164            }
165        }
166        if ($addtodo) {
167            if ($this->exclude_paths) {
168                foreach ($this->exclude_paths as $p) {
169                    if (strncmp($p, $srcdir, strlen($p)) == 0) {
170                        $addtodo = false;
171                        break;
172                    }
173                }
174            }
175        }
176        foreach (glob($outdir . "/*") as $outfile) {
177            if (is_dir($outfile)) {
178                $info = $this->loadDir($outfile, $addtodo);
179                $srcfile = substr($outfile, $this->datadir_len);
180                $subdirs += $info['subdirs'];
181                $total   += $info['total'];
182                $hits    += $info['hits'];
183                $todos   += $info['todos'];
184                unset($info['subdirs']);
185                $subdirs[$srcfile] = $info;
186            }
187            else if (substr($outfile, -5) == ".pcov") {
188                // pass
189                $info = $this->loadFile($outfile);
190                $total += $info['total'];
191                $hits  += $info['hits'];
192                $srcfile = substr($outfile, $this->datadir_len, -5);
193                $files[$srcfile] = $info;
194            }
195            else {
196                continue;
197            }
198        }
199        if ($addtodo === true) {
200            foreach (glob($srcdir . "/*") as $srcfile) {
201                if (!isset($files[$srcfile]) && is_file($srcfile)) {
202                    $files[$srcfile] = array('total' => 0, 'hits' => 0);
203                    $todos ++;
204                }
205                else if (!isset($subdirs[$srcfile]) && is_dir($srcfile)) {
206                    $subdirs[$srcfile] = array('total' => 0, 'hits' => 0, 'todos' => 1, 'files' => 0, 'subdirs' => array());
207                    $todos ++;
208                }
209            }
210        }
211
212        if ($this->usecache) {
213            ksort($subdirs);
214            ksort($files);
215        }
216
217        $info = array(
218                'total'   => $total,
219                'hits'    => $hits,
220                'todos'   => $todos,
221                'files'   => $files,
222                'subdirs' => $subdirs,
223                );
224
225        if ($this->usecache) {
226            $fp = fopen($cachefile, "wb");
227            fwrite($fp, serialize($info));
228            fclose($fp);
229        }
230        return $info;
231    }
232
233    function loadFile($file)
234    {
235        if ($this->usecache) {
236            $cachefile = $file . "cache";
237            if (file_exists($cachefile)) {
238                return unserialize(file_get_contents($cachefile));
239            }
240        }
241
242        $info = $this->loadCov($file); //, $lines);
243        unset($info['cov']);
244
245        if ($this->usecache) {
246            $fp = fopen($cachefile, "wb");
247            fwrite($fp, serialize($info));
248            fclose($fp);
249        }
250        return $info;
251    }
252
253    function loadCov($file)//, $lines)
254    {
255        $total = $hits = 0;
256
257        $cov = xcache_coverager_decode(file_get_contents($file));
258
259        return array('total' => count($cov) - 1, 'hits' => $cov[0], 'cov' => $cov);
260    }
261
262    function loadTplCov($cov, $ctpl)
263    {
264        $tplinfofile = $ctpl . '.phpinfo';
265
266        if (!file_exists($tplinfofile)) {
267            return;
268        }
269
270        $tplinfo = unserialize(file_get_contents($tplinfofile));
271
272        if (!isset($tplinfo['sourceFile'])) {
273            return;
274        }
275        $tplfile = $tplinfo['sourceFile'];
276        if (!isset($tplinfo['lineMap']) || !count($tplinfo['lineMap'])) {
277            return;
278        }
279
280        $tpllines = file($tplfile);
281
282        $dline = 0;
283        $sline = 0;
284        $tplcov = array();
285        foreach ($cov as $line => $times) {
286            // find nearest line
287            while ($dline < $line) {
288                if ((list($dline, $sline) = each($tplinfo['lineMap'])) === false) {
289                    break 2;
290                }
291            }
292
293            $tplcov[$sline] = $times;
294        }
295        return array($tplfile, $tpllines, $tplcov);
296    }
297}
298
299function sprint_cov($cov, $lines, $encode = true)
300{
[463]301    $lastattr = null;
[33]302    foreach ($lines as $l => $line) {
303        $offs = $l + 1;
304        if ($encode) {
305            $line = str_replace("\n", "", htmlspecialchars($line));
306        }
[463]307        else if ($line !== "") {
308            if (substr($line, 0, 7) == '</span>') {
309                $lastattr = null;
310                $line = substr($line, 7);
311            }
312            else if (isset($lastattr)) {
313                $line = $lastattr . $line;
314            }
315
[464]316            if (preg_match('!(<span[^>]+>|</span>)[^<>]*$!', $line, $m)) {
[463]317                if ($m[1] == '</span>') {
318                    $lastattr = null;
319                }
320                else {
321                    $line .= '</span>';
322                    $lastattr = $m[1];
323                }
324            }
325        }
[33]326        if (isset($cov[$offs])) {
[460]327            $lines[$l] = sprintf("<li class=\"line%sCov\"> %s\t%s\n</li>"
[33]328                    , $cov[$offs] ? '' : 'No'
329                    , $cov[$offs]
330                    , $line);
331        }
332        else {
[460]333            $lines[$l] = "<li>\t$line\n</li>";
[33]334        }
335    }
336    return implode('', $lines);
337}
[463]338
[183]339if (!function_exists('xcache_coverager_decode')) {
340    function xcache_coverager_decode($bytes)
341    {
342        $bytes = unpack('l*', $bytes);
343        $i = 1;
344        if ($bytes[$i ++] != 0x564f4350) {
345            return null;
346        }
347        $end = count($bytes);
348        $cov = array();
349        for (/* empty*/; $i <= $end; $i += 2) {
[257]350            $hits = $bytes[$i + 1];
351            $cov[$bytes[$i]] = $hits <= 0 ? 0 : $hits;
[183]352        }
353        return $cov;
354    }
355}
[33]356
357$app = new XcacheCoverageViewer();
358$app->main();
359
360?>
Note: See TracBrowser for help on using the repository browser.