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