1<?php
2/**
3 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Myron Turner <turnermm02@shaw.ca>
5 */
6// must be run within Dokuwiki
7if(!defined('DOKU_INC')) die();
8
9if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
10if(!defined('DW_COMMITS')) define('DW_COMMITS',DOKU_INC.'lib/plugins/dwcommits/');
11global $dwc_dbg_log;
12
13class helper_plugin_dwcommits extends DokuWiki_Plugin {
14
15  private $path;
16  private $status_message;
17  private $branches;
18  private $selected_branch ='master';
19  private $sqlite;
20  private $git = '/usr/bin/git';
21  private $repros;
22  private $default_repro;
23  private $db_name;
24  private $remote_url;
25  private $commit_url;
26
27    function __construct() {
28        global $dwc_dbg_log;
29        if(isset($_REQUEST['dwc__repro']) && $_REQUEST['dwc__repro']) {
30             $this->path = $_REQUEST['dwc__repro'];
31        }
32        else {
33           $this->path = $this->get_conf_repro();
34        }
35        $this->default_repro = $this->path;
36        $this->status_message = array();
37        $this->selected_branch="";
38        $this->sqlite = 0;
39        $binary = $this->getConf('git_binary');
40        if(isset($binary)) $this->git=$binary;
41        $fname_hash = md5($this->path);
42        $names_fname = dirname(__FILE__).'/db/dbnames.ser';
43
44        if(file_exists($names_fname)) {
45            $inf_str = file_get_contents ($names_fname);
46            $inf = unserialize($inf_str);
47            if($inf[$fname_hash]) {
48                 $this->db_name=$inf[$fname_hash];
49                 $this->remote_url=$this->set_githubURL();
50            }
51            else {
52               $this->db_name=$this->new_dbname($fname_hash,$names_fname,$inf);
53            }
54        }
55        else {
56          $this->db_name=$this->new_dbname($fname_hash,$names_fname, false);
57        }
58        $dwc_dbg_log  =  DW_COMMITS . 'dwc_debug.log';
59
60    }
61
62    function new_dbname($fname_hash,$names_fname,$inf_array) {
63
64       if($inf_array && $inf_array['count']) {
65          $count =  $inf_array['count'] + 1;
66       }
67       else {
68         $count = 1;
69         $inf_array=array();
70       }
71       $inf_array['count'] = $count;
72       $new_fname = 'dwcommits_' . $count;
73       $inf_array[$fname_hash] = $new_fname;
74       $inf_array['git' . $count] = $this->path;
75       file_put_contents($names_fname, serialize($inf_array));
76       return $new_fname ;
77
78    }
79
80    function save_dbnames_ser($fname,$content) {
81       if(function_exists(io_saveFile)){
82          return io_saveFile($fname,$content);
83       }
84       else {
85         return file_put_contents($names_fname, $content);
86       }
87    }
88
89    function set_githubURL($remote_url="") {
90        $names_fname = dirname(__FILE__).'/db/dbnames.ser';
91        $inf_str = file_get_contents ($names_fname);
92        $inf = unserialize($inf_str);
93        if(!$inf) return;
94        $fname_hash = md5($this->path);
95        if(!$inf[$fname_hash]) return;
96        $db = $inf[$fname_hash];
97        list($base,$count) = explode('_',$db);
98        $slot = 'url'.$count;
99        if($remote_url) {
100           $inf[$slot] = $remote_url;
101           if($this->save_dbnames_ser($names_fname,serialize($inf))) {
102                  return "$remote_url saved";
103           }
104           else $this->error(5);
105        }
106        else {
107           if($inf[$slot]) return $inf[$slot];
108        }
109
110        return "";
111
112    }
113
114    function current_dbname() {
115      return $this->db_name;
116    }
117
118   /* must be called from syntax.php before _getDB() */
119    function setup_syntax($name) {
120        $this->db_name = $name;
121        $names_fname = dirname(__FILE__).'/db/dbnames.ser';
122        $inf_str = file_get_contents ($names_fname);
123        $inf = unserialize($inf_str);
124        if(!$inf) return;
125
126        list($base,$count) = explode('_',$this->db_name);
127        $slot = 'url'.$count;
128        if($inf[$slot]) {
129             $this->remote_url = $inf[$slot];
130       }
131       else $this->remote_url = "";
132       return $this->remote_url . " slot=$slot";
133    }
134
135
136    function get_conf_repro(){
137            $repro = $this->getConf('default_git');
138            if(isset($repro) && $repro) {
139                  return $repro;
140            }
141            else {
142                return DW_COMMITS . 'db/dokuwiki';
143            }
144    }
145
146    /**
147     * load the sqlite helper
148     */
149    function _getDB(){
150        static $db = null;
151        if ($db === null) {
152            $db =& plugin_load('helper', 'sqlite');
153            if ($db === null) {
154                msg('The data plugin needs the sqlite plugin', -1);
155                return false;
156            }
157
158            if(!$db->init($this->db_name,dirname(__FILE__).'/db/')){
159                return false;
160            }
161            if(defined('DOKU_SQLITE_ASSOC'))
162                $db->fetchmode = DOKU_SQLITE_ASSOC;
163            else $db->fetchmode = 'DOKU_SQLITE_ASSOC';
164        }
165        $this->sqlite = $db;
166        return $db;
167    }
168    function wearehere() {
169        echo 'wearehere';
170    }
171
172   function chdir() {
173      if(!chdir($this->path)) {
174         if(file_exists($this->path)) {
175               $this->error(1);
176         }
177         else $this->error(0);
178         return false;
179     }
180      return true;
181    }
182
183   function update_commits($which) {
184        $this->status_message = array();
185        if(!$this->chdir()) return false;
186
187        if($which == 'fetch') {
188            exec("$this->git fetch origin",$retv,$exit_code);
189            $status = "exit code: " . $exit_code . " ";
190            $this->status_message = array_merge(array(getcwd(),"$this->git fetch origin", $status),$this->status_message,$retv);
191        }
192        elseif($which == 'merge') {
193            exec("$this->git merge origin",$retv, $exit_code);
194            $status = "exit code: " . $exit_code;
195            $this->status_message = array_merge(array(getcwd(),"$this->git merge origin", $status),$this->status_message,$retv);
196        }
197        elseif($which == 'commit') {
198            exec("git commit -mdbupgrade",$retv, $exit_code);
199            $status = "exit code: " . $exit_code;
200            $this->status_message = array_merge(array(getcwd(),"git commit", $status),$this->status_message,$retv);
201            if($exit_code <=1 ) return true;
202        }
203        elseif($which == 'add') {
204            exec("$this->git add .",$retv_add, $exit_code);
205            $status = "exit code: " . $exit_code;
206            $this->status_message = array_merge(array(getcwd(),"git add . ", $status),$this->status_message,$retv_add);
207        }
208        elseif($which == 'pull') {
209            exec("$this->git pull",$retv, $exit_code);
210            $status = "exit code: " . $exit_code;
211            $this->status_message = array_merge(array(getcwd(),"git pull", $status),$this->status_message,$retv);
212        }
213       elseif($which == 'branch') {
214            $branch = $_REQUEST['dwc__branch'];
215            exec("$this->git checkout $branch",$retv, $exit_code);
216            $status = "exit code: " . $exit_code;
217            $this->status_message = array_merge(array(getcwd(),"git checkout $branch", $status),$this->status_message,$retv);
218            $this->set_branches();
219        }
220       elseif($which == 'remote_url') {
221             exec("$this->git  config --get remote.origin.url",$retv, $exit_code);
222             $this->remote_url = $retv[0];
223             $this->remote_url = preg_replace('/:(?!\/)/',"/",$this->remote_url);
224             $this->remote_url = preg_replace('/^\s*.*?@/',"",$this->remote_url);
225             if(!preg_match('/http/',$this->remote_url)) {
226                   if(preg_match('/github/',$this->remote_url)) {
227                     $this->remote_url = 'https://'. $this->remote_url;
228                   }
229                   else $this->remote_url = 'http://'. $this->remote_url;
230             }
231
232             $this->status_message = array_merge(array(getcwd(),"git checkout $branch", $status),$this->status_message,$retv);
233             if($this->remote_url) {
234                $this->status_message[] = "Remote URL: $this->remote_url";
235             }
236       }
237            if($exit_code > 0) return false;
238            return true;
239
240   }
241
242    function set_commit_url() {
243       if(!$this->remote_url) return false;
244       if($this->commit_url) return $this->commit_url;
245       $url = preg_replace('/\.git$/',"", $this->remote_url) . '/commit/';
246       $this->commit_url=$url;
247       return $url;
248    }
249
250    function get_remote_url() {
251      return $this->remote_url;
252    }
253
254   function set_repros() {
255      $this->repros = array();
256      $this->repros[] = $this->html_option($this->path,true);
257      $conf_repro = $this->get_conf_repro();
258      if($this->path != $conf_repro) {
259             $this->repros[] = $this->html_option($conf_repro);
260      }
261      if(file_exists(DOKU_PLUGIN . 'dwcommits/conf/default.local.ini')) {
262         $ini_array = parse_ini_file(DOKU_PLUGIN . 'dwcommits/conf/default.local.ini', true);
263            foreach ($ini_array as $name=>$a) {
264                if($name == 'other_gits') {
265                    foreach($a as $git_dir) {
266                        $this->repros[] = $this->html_option($git_dir);
267                   }
268                }
269                if($name == 'dwc_gits') {
270                    foreach($a as $git_dir) {
271                        $this->repros[] = $this->html_option(DW_COMMITS_DB . $git_dir);
272                   }
273               }
274           }
275        }
276   }
277
278   function get_repros() {
279      echo implode("\n",$this->repros);
280   }
281
282   function set_branches() {
283       if(!$this->chdir()) return false;
284       $this->branches = array();
285       exec("$this->git branch",$retv, $exit_code);
286       if($exit_code) return false;
287       foreach ($retv as $branch) {
288        if(preg_match('/\*(.*)/',$branch,$matches)) {
289           $this->selected_branch = $matches[1];
290             $this->branches[] = $this->html_option($matches[1],true);
291        }
292        else {
293            $this->branches[] = $this->html_option($branch);
294        }
295       }
296   }
297
298   function html_option($val, $selected=false) {
299      $val = trim($val);
300      if(!$selected) {
301        return '<option value="'. $val .'">' . $val .'</option>';
302      }
303      return '<option value="' .$val . '" selected>' . $val . '</option>';
304   }
305
306   function get_branches() {
307      echo implode("\n",$this->branches);
308   }
309
310   function selected_branch() {
311          if($this->selected_branch) return $this->selected_branch;
312          $this->selected_branch = 'master'; //needed for db column if and when implemented
313          return 'master';
314   }
315
316  function selected_repro() {
317          if(isset($_REQUEST['dwc__repro']) && $_REQUEST['dwc__repro']) return $_REQUEST['dwc__repro'];
318          return $this->default_repro;
319   }
320
321  /*  Seems git status sometimes returns exit code of 1 even when 0 is expected
322      So exit code > 0 can't be trusted to report genuine error. Confirmed via Google
323  */
324   function get_status() {
325      $this->status_message = array();
326      if(!$this->chdir()) return false;
327         exec("$this->git status",$retv, $exit_code);
328         $this->status_message =
329              array_merge(array(getcwd(),"git status"),$this->status_message,$retv);
330        return true;
331
332   }
333
334   function error($which, $type=-1) {
335      $path = $this->path;
336      $msgs = array(
337           "Cannot find cloned git at $path",  // 0
338           "Cannot access $path. The entire directory and all its contents must be read/write for the web server.", // 1
339           "Cannot fetch from github",  // 2
340           "Unable to merge",  // 3
341           "Bad Query Construct. Please notify the plugin author.",  // 4
342           "Unable to write to dbnames.ser file.",  // 5
343           "Please check your query. You seem not to have entered any search terms.", // 6
344           "Unable to restore backup; you may not have a backup saved." // 7
345      );
346
347      msg($msgs[$which],$type);
348
349   }
350   function get_status_msg() {
351       $status = $this->status_message;
352       $this->status_message = array();
353
354       $current_git = "<b>Git:</b> $this->path<br/>";
355       if(!is_array($status)) return $current_git;
356       return $current_git . implode('<br />',$status);
357
358   }
359
360function populate($timestamp_start=0,$table='git_commits') {
361
362     if(!$this->chdir()) return false;
363
364     $months = array('Jan'=>1,'Feb'=>2,'Mar'=>3,'Apr'=>4,'May'=>5,'Jun'=>6,'Jul'=>7,
365              'Aug'=>8,'Sep'=>9,'Oct'=>10,'Nov'=>11,'Dec'=>12);
366
367    $count = 0;
368    $start_number = 0;
369    if(!$timestamp_start) {
370       $timestamp_start = mktime(0,0,0,11,11,2010);
371    }
372
373     $results = $this->sqlite->query("select count(*) from git_commits");
374
375   $start_number = $this->res2single($results);
376     $since =  date('Y-m-d',$timestamp_start);
377     if(!preg_match('/^\d\d\d\d-\d\d-\d\d$/',$since)) {
378          $since = '2010-11-11';
379     }
380    $handle = popen("$this->git log --since=$since", "r");
381    $msg = "";
382    $author="";
383    $timestamp=0;
384    $gitid="";
385    $record_done = false;
386    $done = false;
387    if (!$handle) {
388      echo "can't open git\n";
389      exit;
390    }
391
392        while (($buffer = fgets($handle, 4096)) !== false) {
393
394
395           if(preg_match('/^([A-Z]\w+):(.*)/',$buffer, $matches)) {
396
397               switch($matches[1]){
398
399                 case 'Date':
400                     preg_match('/(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)/',$matches[2],$date_matches);
401                     list($dstr,$mon,$day,$hour,$min,$sec,$year) = $date_matches;
402                     $timestamp = mktime ($hour,$min,$sec, $months[$mon], $day, $year);
403                     $count++ ;
404                     if($timestamp < $timestamp_start) {
405                       $done = true;
406                    }
407                    break;
408
409                 case 'Merge':
410                   break;
411
412                 case 'Author':
413                    $author = $matches[2];
414                    break;
415
416                 default:
417                    break;
418               }
419
420           }
421           elseif (preg_match('/^commit\s(.*)/',$buffer,$commit)) {
422               if($msg) {
423                     $this->insert($author,$timestamp,$gitid,$msg,$table);
424               }
425               $msg = "";
426               $gitid=$commit[1];
427
428           }
429           else {
430            $msg .= $buffer;
431           }
432          if($done) break;
433        }
434
435     pclose($handle);
436     $results = $this->sqlite->query("select count(*) from git_commits");
437     $end_number = $this->res2single($results);
438
439     return array($end_number-$start_number, $end_number);
440
441}
442
443    function insert($author,$timestamp,$gitid,$msg,$table) {
444
445        $prefix =  substr( $gitid , 0, 15 );
446
447        if($this->sqlite->query("INSERT OR IGNORE INTO $table (author,timestamp,gitid,msg,prefix,gitbranch) VALUES (?,?,?,?,?,?)",
448                     $author,$timestamp,$gitid,$msg,$prefix,$this->selected_branch)){
449              return true;
450        }
451        else {
452          return false;
453        }
454
455    }
456
457
458  function select_all($q=array()) {
459        $temp_str = "";
460        $query = count($q) ? $q: $_REQUEST['dwc_query'];
461        $msg = "";
462        $author = "";
463        $branch = "";
464        $term1 = "";
465        $term2 = "";
466        $date_1 = "";
467        $date_2 = "";
468
469        foreach($query as $col=>$val) {
470             switch ($col) {
471                case 'author':
472                   $author = $this->construct_term('author',$val);
473                   break;
474                case 'branch':
475                   if($val != 'any') {
476                     $branch = $this->construct_term('gitbranch',$val);
477                   }
478                   break;
479               case 'terms_1':
480                  $term1 = $this->construct_term('msg',$val);
481                  break;
482               case 'terms_2':
483                 $term2 = $this->construct_term('msg',$val);
484                 break;
485               case 'd1':
486                 $date_1 =  $this->get_timestamp($val);
487                 break;
488               case 'd2':
489                 $date_2 =  $this->get_timestamp($val);
490                 break;
491
492             }
493        }
494
495        $msg = $this->construct_msg_clause($term1,$term2,$query['OP_1']);
496        $ab_clause = $this->construct_ab_clause($author,$branch,$query['OP_2'],$msg);
497        $attach = ($ab_clause || $msg) ? true : false;
498        $date_clause = $this->construct_date_clause($date_1,$date_2,$attach);
499        $q = $msg . $ab_clause . $date_clause;
500        if(!$q) {
501         $this->error(6,1);
502         return array();
503        }
504        $res = $this->sqlite->query("SELECT timestamp,author,msg,gitid,gitbranch FROM git_commits WHERE $q ORDER BY timestamp DESC");
505        if(!$res) {
506          $this->error(4);
507          return false;
508        }
509
510        $arr = $this->sqlite->res2arr($res);
511        if($arr) $q .= " [Rows:  " . count($arr) . "] ";
512        return array($arr,  $q);
513
514  }
515
516  function format_result_table($arr, $q=false) {
517
518        $this->set_commit_url();
519        $query = $q ? $q: $_REQUEST['dwc_query'];
520
521        $regex = $this->get_hilite_regex($query);
522
523        $output = "";
524        foreach($arr as $row) {
525           $output .= $this->format_tablerow($row,$regex);
526           $output .= "<tr><td colspan='3' style='border-bottom: 1px solid black;'>\n";
527        }
528        return '<table width="85%" cellspacing="4">' . $output . '</table>';
529  }
530
531 function format_tablerow($row,$regex) {
532        $result = "";
533
534        $msg = "";
535        $date = "";
536        $commit = "";
537        $branch = "";
538        $author = "";
539        global $conf;
540        foreach ($row as $col=>$val) {
541
542
543            if($col == 'msg'){
544                $msg = hsc($val);
545                if($regex) {
546                    $msg = preg_replace($regex,"<span class='dwc_hilite'>$1</span>",$val);
547                }
548
549            }
550            elseif($col == 'timestamp') {
551                $date = date("D M d H:i:s Y" ,$val);
552            }
553            elseif($col == 'gitid') {
554                if($this->commit_url) {
555                  $commit = $this->format_commit_url($val);
556                }
557                else $commit = $val;
558            }
559            elseif($col == 'gitbranch') {
560                $branch = $val;
561            }
562           elseif($col == 'author') {
563                list($name,$email) = explode('<',$val);
564                $email = trim($email,'>');
565                $author = "<a href ='mailto: $email' title='$email'>$name</a>";
566            }
567
568
569        }
570
571        return "<tr><td rowspan='2'><td nowrap style='padding-right:2px;'>$date</td><td><b>Commit:&nbsp;&nbsp;</b> $commit</td>" .
572              "<tr><td rowspan = '2' valign='top' style='padding-right:2px;'><b>Author:&nbsp;&nbsp;</b>$author<br /><b>Branch:&nbsp;&nbsp;</b>$branch</td>" .
573               "<td style='padding:2px;'>$msg</td>";
574
575
576  }
577
578
579 function get_hilite_regex($query) {
580        $term1 = $query['terms_1'];
581        $term2 = $query['terms_2'];
582
583        $regex = "";
584
585        if($term1 && $term2) {
586              $regex = "/($term1|$term2)/ims";
587        }
588        elseif($term1) {
589             $regex = "/($term1)/ims";
590        }
591       return $regex;
592 }
593  function format_result_plain($arr, $q=false) {
594        $this->set_commit_url();
595        $query = $q ? $q: $_REQUEST['dwc_query'];
596
597        $regex = $this->get_hilite_regex($query);
598
599        $output = "";
600        foreach($arr as $row) {
601           $output .= $this->format_row($row,$regex);
602           $output .= "\n---------\n";
603        }
604
605        return '<pre>' . $output . '</pre>';
606  }
607
608  function format_row($row,$regex) {
609        $result = "";
610
611        foreach ($row as $col=>$val) {
612
613
614            if($col == 'msg'){
615                $val = wordwrap($val, 80,"\n");
616                $val = hsc($val);
617                if($regex) {
618                    $val = preg_replace($regex,"<span class='dwc_hilite'>$1</span>",$val);
619                }
620            }
621            elseif($col == 'timestamp') {
622                $result .= "<b>Date: </b>";
623                $val = date("D M d H:i:s Y" ,$val);
624            }
625            elseif($col == 'gitid') {
626                if($this->commit_url) {
627                  $result .= 'Commit (URL): ';
628                  $result .= $this->format_commit_url($val);
629                  continue;
630                }
631                else $result .= '<b>Commit: </b>';
632            }
633            elseif($col == 'gitbranch') {
634                $result .= '<b>Branch: </b>';
635            }
636           elseif($col == 'author') {
637                $result .= '<b>Author: </b>';
638            }
639            else {
640               $result .= "<b>$col: </b>";
641            }
642
643            $result .= "$val\n";
644        }
645        return $result;
646  }
647
648
649  function format_commit_url($val) {
650     $url = $this->commit_url . $val;
651     return "<a href='$url' target='commitwin'>$val</a>\n";
652  }
653
654  function construct_term($col,$val) {
655         if($val) return " $col LIKE '%$val%' ";
656         return "";
657  }
658
659  function construct_date_clause($d1,$d2, $attach) {
660     $q = "";
661     $op  = $attach ? 'AND' : "";
662     if($d1 && $d2) {
663       $q = " $op ( timestamp > $d1 AND timestamp < $d2 )";
664     }
665     elseif($d1) {
666        $q = " $op timestamp > $d1 ";
667     }
668     elseif($d2) {
669       $q = " $op timestamp < $d2 ";
670     }
671     return $q;
672
673  }
674  function construct_ab_clause($author,$branch,$op,$msg){
675
676        $q = "";
677        if($author) {
678            if($msg) {
679              $OP = ($op == 'AND') ? ' AND ' : ' OR ';
680              $q = " $OP $author ";
681            }
682            else $q = " $author ";
683        }
684        if($branch) {
685            if($author || $msg){
686                 $q .= " AND $branch ";
687            }
688            else
689               $q = " $branch ";
690
691        }
692        return $q;
693
694  }
695
696  function construct_msg_clause($phrase1,$phrase2,$op) {
697        if(!$phrase1) return "";
698        if(!$phrase2) return $phrase1;
699        $OP = ($op == 'AND') ? ' AND ' : ' OR ';
700        return " (($phrase1) $OP ($phrase2)) ";
701  }
702
703  function get_timestamp($dstr) {
704      if(!$dstr) return "";
705      if(preg_match('/[a-zA-Z]/',$dstr)){
706         msg('Date wasn\'t set:' . $dstr , -1);
707         return false;
708      }
709
710      list($month,$day,$year) = explode('-',$dstr);
711      if((strlen($month) < 2) || (strlen($year) < 4)||(strlen($day) < 2)  ) {
712                msg('Incorrect date format: ' . $dstr  , -1);
713      }
714
715      if((strlen($month) + strlen($year) + strlen($day) > 8 )  ) {
716                msg('Incorrect date format: ' . $dstr , -1);
717      }
718
719      return mktime (0,0,0, $month, $day, $year);
720   }
721
722   function res2single($res) {
723        if(method_exists($this->sqlite,res2single)){
724            return $this->sqlite->res2single($res);
725        }
726        $arr = $this->sqlite->res2row($res);
727        list($key,$val) = each($arr);
728        return($val);
729}
730
731function restore_backup() {
732   $names_fname = dirname(__FILE__).'/db/dbnames.ser';
733   $backup = $names_fname . '.prev';
734   if(!file_exists($names_fname)) {
735      return "backup file not found";
736   }
737   if(file_exists($names_fname) && file_exists($backup)) {
738          @unlink($names_fname);
739  }
740  else {
741         $this->error(7);
742         return;
743  }
744  if(rename($backup,$names_fname)) {
745       return "Backup restored";
746   }
747
748  $this->error(7);
749   return "";
750}
751
752function prune($del) {
753   $names_fname = dirname(__FILE__).'/db/dbnames.ser';
754   $msg = "";
755   $meta = DOKU_INC . 'data/meta/';
756   if(file_exists($names_fname)) {
757        $inf_str = file_get_contents ($names_fname);
758        $inf = unserialize($inf_str);
759        if(!$inf) return;
760        foreach($_REQUEST[prune] as $db=>$key) {
761           unset($inf[$key]);
762           list($prefix,$index) = explode('_',$db);
763           $url = 'url' . $index;
764           $git = 'git' . $index;
765           if(isset($inf[$url])) {
766              unset($inf[$url]);
767           }
768           if(isset($inf[$git])) {
769              unset($inf[$git]);
770           }
771
772           $sql = $meta . $db . '.sqlite';
773           if($del && file_exists($sql)) {
774             if(!unlink($sql)) {
775                $msg .= "Could not delete $sql<br />";
776
777             }
778           }
779        }
780
781       $backup = $names_fname . '.prev';
782       if(file_exists($backup)) {
783           @unlink($backup);
784       }
785       if(rename($names_fname, $backup)) {
786          $msg .= "Old data saved in backup $backup";
787          if($del) {
788            $msg .= "<br />This backup may contain references to deleted sqlite dbase files<br />";
789          }
790       }
791       $this->save_dbnames_ser($names_fname,serialize($inf));
792   }
793
794  return $msg;
795}
796
797/* Read dbnames.ser and return data found there */
798function db_data($inf = false) {
799     $output = "";
800     $filename = DW_COMMITS . 'db/dbnames.ser';
801     if(!$inf) {
802        $inf_str = file_get_contents ($filename);
803        $inf = unserialize($inf_str);
804     }
805
806    foreach($inf as $val=>$entry) {
807       if(preg_match('/dwcommits_(\d+)/',$entry, $matches)) {
808           $output .= "<b>" . $this->getLang('db_file'). "</b> $entry";
809           $output .= '&nbsp;&nbsp;&nbsp;<input type = "checkbox" value = "'. $val. '" name="prune[' .$entry. ']">';
810           $output .= "<br />";
811           if(($url = $this->dwc_element('url', $matches[1], $inf))!== false) {
812               $output .= "<b>" . $this->getLang('remote_url'). "</b> $url<br />";
813           }
814
815           $git = $this->dwc_element('git', $matches[1], $inf);
816           if($git !== false) {
817             if(!file_exists($git)) {
818                $output .= "<b>". $this->getLang('git_missing'). "</b>  $git<br />";
819             }
820             else $output .= "<b>". $this->getLang('git_local'). "</b> $git<br />";
821           }
822          $output .= "<br />";
823       }
824    }
825    return $output;
826 }
827
828 function dwc_element($prefix, $suffix, $ar) {
829    $inx = $prefix . $suffix;
830    if(isset($ar[$inx])) {
831         return $ar[$inx];
832    }
833    return false;
834
835 }
836
837  function recreate_table($timestamp_start) {
838
839     $this->sqlite->query("DROP TABLE git_commits");
840     $this->sqlite->query('CREATE TABLE git_commits(author TEXT,timestamp INTEGER,gitid TEXT,msg TEXT, prefix TEXT, gitbranch TEXT, PRIMARY KEY(prefix,timestamp))');
841     $this->populate($timestamp_start);
842     $results = $this->sqlite->query("select count(*) from git_commits");
843     $res = $this->res2single($results);
844     return $res;
845
846  }
847
848    function write_debug($data) {
849      return;
850      global $dwc_dbg_log;
851      static $handle;
852      if(!$handle) {
853      if(!$handle = fopen($dwc_dbg_log, 'a')) {
854        return;
855        }
856      }
857       if(is_array($data)) $data = print_r($data,true);
858       fwrite($handle, "$data\n");
859    }
860}
861
862
863