php8
[web.mtrack] / MTrackWeb / Changeset.php
1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
3
4 // Browse.php - only for rendering the body..
5 // Tree.php - the actually tree..
6
7 require_once 'MTrackWeb.php';
8
9 class MTrackWeb_Changeset extends MTrackWeb
10 {
11  
12     var $cs = '';  // the changeset.
13      
14     function getAuth() 
15     {
16         parent::getAuth();
17         
18         return true;
19   
20     }
21  
22     function get($pi)
23     {
24          $this->pi =  $pi . (strlen($pi) ? $this->bootLoader->ext : '');
25        
26         if (!isset($_REQUEST['ajax_body'])) {
27             $this->title = "Changeset: " . $this->pi;
28             return;
29         }
30         $this->masterTemplate = 'changeset.html';
31         $this->repo = DB_DataObject::factory('mtrack_repos');
32         $this->cs = $this->repo->loadFromPath($this->pi);
33      
34       
35        
36         if (!$this->repo->id) {
37             return HTML_FlexyFramework::run('Browse');  
38         };
39         
40         if (!$this->projectPerm($this->repo->project_id, 'MTrack.Repos', 'S')) {
41             return HTML_FlexyFramework::run('Noperm');  // noperm = loggedin -> need more perms / not.. try loggin in..
42         }
43         
44         //$data = mtrack_cache('get_change_data', array($path), 864000);
45         $this->data = $this->get_change_data($this->cs);
46         
47         if (!empty($_REQUEST['part'])) {
48             foreach($this->data->ent->files as $f) {
49                 if ($f->name != $_REQUEST['part']) {
50                     continue;
51                     
52                 }
53                 echo $this->diff($this->repo->diff($f, $this->data->ent->rev));
54                 exit;
55             }
56             die("can not find part?");
57         }
58         
59         
60         $this->ent = $this->data->ent;
61         if ($this->ent === null) {
62           throw new Exception("invalid parameters");
63         }
64
65         //$rdata = mtrack_cache('get_change_data_relatives', array($path, $ent->rev));
66         $rdata = $this->get_change_data_relatives($this->cs, $this->ent->rev);
67         
68        // print_R($rdata);exit;
69         if (isset($_GET['fmt']) && $_GET['fmt'] == 'diff') {
70             $this->downloadDiff();
71         }
72         $this->title = "Changeset " . $this->ent->rev;
73    
74  
75
76
77         
78     }
79     function downloadDiff()
80     {
81         $filename = "$this->repo->shortname.$this->ent->rev.diff";
82         header("Content-Type: text/plain; name=\"$filename\"");
83         header("Content-Disposition: attachment; filename=\"$filename\"");
84
85         echo "Changeset: $repo->shortname $ent->rev\n";
86         echo "By: $ent->changeby\n";
87         echo "When: $ent->ctime\n";
88         echo "\n";
89         echo $data->changelog . "\n\n";
90
91         if (is_array($ent->files) && count($ent->files)) {
92           foreach ($ent->files as $id => $file) {
93             echo "$file->status $file->name\n";
94           }
95           echo "\n";
96
97           foreach ($ent->files as $id => $file) {
98             $fpath = $file->name;
99             if ($fpath[0] != '/') $fpath = '/' . $fpath;
100             $diff = $repo->diff($file, $ent->rev);
101             if (is_resource($diff)) {
102               echo stream_get_contents($diff);
103             } elseif (is_array($diff)) {
104               echo join("\n", $diff);
105             } else {
106               echo $diff;
107             }
108           }
109         }
110         exit;
111     }
112
113     function get_change_data($pi)
114     {
115         $ents = $this->repo->history(null, 1, 'rev', $pi);
116         $data = new stdclass;
117         if (!count($ents)) {
118             $data->ent = null;
119         } else {
120             $ent = $ents[0];
121             $data->ent = $ent;
122
123         // Determine project from the file list
124         $changelog = $ent->changelog;
125         /*$the_proj = $this->repo->projectFromPath($ent->files);
126         if ($the_proj > 1) {
127             $proj = MTrackProject::loadById($the_proj);
128             $changelog = $proj->adjust_links($ent->changelog, true);
129         }
130         */
131         $data->changelog = $changelog;
132         $ent->files = is_array($ent->files) ? array_values($ent->files) : array();
133         
134         // we should not do this here..
135         // it's to slow on huge commits..
136         
137         //foreach ($ent->files as $file) {
138         //    $file->diff = $this->diff($this->repo->diff($file, $ent->rev));
139         //}
140       }
141
142       return $data;
143     }
144
145     function get_change_data_relatives($pi, $rev)
146     {
147       
148       $data = new stdclass;
149       list($data->parents, $data->kids) = $this->repo->getRelatedChanges($rev);
150       return $data;
151     }
152  
153
154
155     function diff($diffstr) // fixme... code should be in template..
156     {
157         $nlines = 0;
158     
159         if (is_resource($diffstr)) {
160             $lines = array();
161             while (($line = fgets($diffstr)) !== false) {
162                 $lines[] = rtrim($line, "\r\n");
163             }
164             $diffstr = $lines;
165         }
166
167         if (is_string($diffstr)) {
168             $abase = md5($diffstr);
169             $diffstr = preg_split("/\r?\n/", $diffstr);
170         } else {
171             $abase = md5(join("\n", $diffstr));
172         }
173         
174         // diffstr should now contain a string...
175
176         /* we could use toggle() below, but it is much faster to determine
177          * if we are hiding or showing based on a single variable than evaluating
178          * that for each possible cell */
179         $html = "
180             <button class='togglediffcopy' type='button'>Toggle Diff Line Numbers</button>
181             <table class='code diff'>
182         ";
183         //$html = "<pre class='code diff'>";
184
185         while (true) {
186             if (!count($diffstr)) {
187                 break;
188             }
189             $line = array_shift($diffstr);
190             $nlines++;
191             if (!strncmp($line, '@@ ', 3)) {
192                 /* done with preamble */
193                 break;
194             }
195             $line = htmlspecialchars($line, ENT_QUOTES, 'utf-8');
196             $line = "<tr class='meta'><td class='lineno'></td><td class='lineno'></td><td class='lineno'></td><td width='100%'>$line</tr>";
197             $html .= $line . "\n";
198         }
199
200         $lines = array(0, 0);
201         $first = false;
202         while (true) {
203             $class = 'unmod';
204
205             if (preg_match("/^@@\s+-(\pN+)(?:,\pN+)?\s+\+(\pN+)(?:,\pN+)?\s*@@/",
206                     $line, $M)) {
207                 $lines[0] = (int)$M[1] - 1;
208                 $lines[1] = (int)$M[2] - 1;
209                 $class = 'meta';
210                 $first = true;
211             } elseif (strlen($line)) {
212                 if ($line[0] == '-') {
213                     $lines[0]++;
214                     $class = 'removed';
215                 } elseif ($line[0] == '+') {
216                     $lines[1]++;
217                     $class = 'added';
218                 } else {
219                     $lines[0]++;
220                     $lines[1]++;
221                 }
222             } else {
223                 $lines[0]++;
224                 $lines[1]++;
225             }
226             $row = "<tr class='$class";
227             if ($first) {
228                 $row .= ' first';
229             }
230             if ($class != 'meta' && $first) {
231                 $first = false;
232             }
233             $row .= "'>";
234
235             switch ($class) {
236                 case 'meta':
237                     $line_info = '';
238                     $row .= "<td class='lineno'></td><td class='lineno'></td>";
239                     break;
240                 case 'added':
241                     $row .= "<td class='lineno'></td><td class='lineno'>" . $lines[1] . "</td>";
242                     break;
243                 case 'removed':
244                     $row .= "<td class='lineno'>" . $lines[0] . "</td><td class='lineno'></td>";
245                     break;
246                 default:
247                     $row .= "<td class='lineno'>" . $lines[0] . "</td><td class='lineno'>" . $lines[1] . "</td>";
248             }
249             $anchor = $abase . '.' . $nlines;
250             $row .= "<td class='linelink'><a name='$anchor'></a><a href='#$anchor' title='link to this line'>#</a></td>";
251
252             $line = htmlspecialchars($line, ENT_QUOTES, 'utf-8');
253             $row .= "<td class='line' width='100%'>$line</td></tr>\n";
254             $html .= $row;
255
256             if (!count($diffstr)) {
257                 break;
258             }
259             $line = array_shift($diffstr);
260             $nlines++;
261         }
262
263         if ($nlines == 0) {
264             return null;
265         }
266
267         $html .= "</table>";
268         return $html;
269     }
270 }