Index: trunk/extensions/CodeReview/CodeReview.php |
— | — | @@ -39,6 +39,7 @@ |
40 | 40 | $dir = dirname(__FILE__) . '/'; |
41 | 41 | |
42 | 42 | $wgAutoloadClasses['ApiCodeUpdate'] = $dir . 'ApiCodeUpdate.php'; |
| 43 | +$wgAutoloadClasses['ApiCodeDiff'] = $dir . 'ApiCodeDiff.php'; |
43 | 44 | $wgAutoloadClasses['CodeDiffHighlighter'] = $dir . 'DiffHighlighter.php'; |
44 | 45 | $wgAutoloadClasses['CodeRepository'] = $dir . 'CodeRepository.php'; |
45 | 46 | $wgAutoloadClasses['CodeRepoListView'] = $dir . 'CodeRepoListView.php'; |
— | — | @@ -67,6 +68,7 @@ |
68 | 69 | $wgSpecialPageGroups['RepoAdmin'] = 'developer'; |
69 | 70 | |
70 | 71 | $wgAPIModules['codeupdate'] = 'ApiCodeUpdate'; |
| 72 | +$wgAPIModules['codediff'] = 'ApiCodeDiff'; |
71 | 73 | |
72 | 74 | $wgExtensionMessagesFiles['CodeReview'] = $dir . 'CodeReview.i18n.php'; |
73 | 75 | $wgExtensionAliasesFiles['CodeReview'] = $dir . 'CodeReview.alias.php'; |
— | — | @@ -78,11 +80,11 @@ |
79 | 81 | $wgAvailableRights[] = 'codereview-set-status'; |
80 | 82 | $wgAvailableRights[] = 'codereview-link-user'; |
81 | 83 | |
82 | | -$wgGroupPermissions['*']['codereview-add-tag'] = true; |
83 | | -$wgGroupPermissions['*']['codereview-remove-tag'] = true; |
84 | | -$wgGroupPermissions['*']['codereview-post-comment'] = true; |
85 | | -$wgGroupPermissions['*']['codereview-set-status'] = true; |
86 | | -$wgGroupPermissions['*']['codereview-link-user'] = true; |
| 84 | +$wgGroupPermissions['user']['codereview-add-tag'] = true; |
| 85 | +$wgGroupPermissions['user']['codereview-remove-tag'] = true; |
| 86 | +$wgGroupPermissions['user']['codereview-post-comment'] = true; |
| 87 | +$wgGroupPermissions['user']['codereview-set-status'] = true; |
| 88 | +$wgGroupPermissions['user']['codereview-link-user'] = true; |
87 | 89 | |
88 | 90 | $wgGroupPermissions['steward']['repoadmin'] = true; // temp |
89 | 91 | |
Index: trunk/extensions/CodeReview/ApiCodeDiff.php |
— | — | @@ -0,0 +1,69 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +// Please don't use this interface publicly yet. |
| 5 | +// I don't really know what I'm doing in the API and it might explode. ;) |
| 6 | +// -- brion |
| 7 | + |
| 8 | +class ApiCodeDiff extends ApiBase { |
| 9 | + |
| 10 | + public function execute() { |
| 11 | + $params = $this->extractRequestParams(); |
| 12 | + |
| 13 | + if( !isset( $params['repo'] ) ) { |
| 14 | + $this->dieUsageMsg( array( 'missingparam', 'repo' ) ); |
| 15 | + } |
| 16 | + if( !isset( $params['rev'] ) ) { |
| 17 | + $this->dieUsageMsg( array( 'missingparam', 'rev' ) ); |
| 18 | + } |
| 19 | + |
| 20 | + $repo = CodeRepository::newFromName( $params['repo'] ); |
| 21 | + if( !$repo ){ |
| 22 | + throw new MWException( "Invalid repo {$args[0]}" ); |
| 23 | + } |
| 24 | + |
| 25 | + $svn = SubversionAdaptor::newFromRepo( $repo->getPath() ); |
| 26 | + $lastStoredRev = $repo->getLastStoredRev(); |
| 27 | + |
| 28 | + $rev = intval( $params['rev'] ); |
| 29 | + if( $rev <= 0 || $rev > $lastStoredRev ) { |
| 30 | + /// @fixme more sensible error |
| 31 | + throw new MWException( 'Invalid input revision' ); |
| 32 | + } |
| 33 | + |
| 34 | + $diff = $repo->getDiff( $rev ); |
| 35 | + |
| 36 | + if( $diff ) { |
| 37 | + $hilite = new CodeDiffHighlighter(); |
| 38 | + $html = $hilite->render( $diff ); |
| 39 | + } else { |
| 40 | + $html = 'Failed to load diff.'; |
| 41 | + } |
| 42 | + |
| 43 | + $data = array(); |
| 44 | + $data['repo'] = $params['repo']; |
| 45 | + $data['id'] = $rev; |
| 46 | + $data['diff'] = $html; |
| 47 | + $this->getResult()->addValue( 'code', 'rev', $data ); |
| 48 | + } |
| 49 | + |
| 50 | + public function getAllowedParams() { |
| 51 | + return array( |
| 52 | + 'repo' => null, |
| 53 | + 'rev' => null ); |
| 54 | + } |
| 55 | + |
| 56 | + public function getParamDescription() { |
| 57 | + return array( |
| 58 | + 'repo' => 'Name of repository to look at', |
| 59 | + 'rev' => 'Revision ID to fetch diff of' ); |
| 60 | + } |
| 61 | + |
| 62 | + public function getDescription() { |
| 63 | + return array( |
| 64 | + 'Fetch formatted diff from CodeReview\'s backing revision control system.' ); |
| 65 | + } |
| 66 | + |
| 67 | + public function getVersion() { |
| 68 | + return __CLASS__ . ': $Id$'; |
| 69 | + } |
| 70 | +} |
Property changes on: trunk/extensions/CodeReview/ApiCodeDiff.php |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 71 | + native |
Index: trunk/extensions/CodeReview/CodeRepository.php |
— | — | @@ -147,6 +147,11 @@ |
148 | 148 | return CodeRevision::newFromRow( $row ); |
149 | 149 | } |
150 | 150 | |
| 151 | + /** |
| 152 | + * @param int $rev Revision ID |
| 153 | + * @param $skipCache 'skipcache' to avoid caching |
| 154 | + * 'cached' to *only* fetch if cached |
| 155 | + */ |
151 | 156 | function getDiff( $rev, $skipCache = '' ) { |
152 | 157 | global $wgMemc; |
153 | 158 | |
— | — | @@ -165,7 +170,7 @@ |
166 | 171 | $data = $wgMemc->get( $key ); |
167 | 172 | } |
168 | 173 | |
169 | | - if( !$data ) { |
| 174 | + if( !$data && $skipCache != 'cached' ) { |
170 | 175 | $svn = SubversionAdaptor::newFromRepo( $this->mPath ); |
171 | 176 | $data = $svn->getDiff( '', $rev1, $rev2 ); |
172 | 177 | $wgMemc->set( $key, $data, 3600*24*3 ); |
Index: trunk/extensions/CodeReview/codereview.js |
— | — | @@ -0,0 +1,62 @@ |
| 2 | +var CodeReview = new Object; |
| 3 | +CodeReview.loadDiff = function(repo, rev) { |
| 4 | + var path = wgScriptPath + |
| 5 | + "/api.php" + |
| 6 | + "?action=codediff" + |
| 7 | + "&format=json" + |
| 8 | + "&repo=" + encodeURIComponent(repo) + |
| 9 | + "&rev=" + encodeURIComponent(rev); |
| 10 | + var xmlhttp = sajax_init_object(); |
| 11 | + if(xmlhttp){ |
| 12 | + try { |
| 13 | + injectSpinner(CodeReview.diffTarget(), 'codereview-diff'); |
| 14 | + xmlhttp.open("GET", path, true); |
| 15 | + xmlhttp.onreadystatechange=function(){ |
| 16 | + if (xmlhttp.readyState==4 && typeof os_updateIfRelevant == 'function') { |
| 17 | + CodeReview.decodeAndShowDiff(xmlhttp.responseText); |
| 18 | + removeSpinner('codereview-diff'); |
| 19 | + } |
| 20 | + }; |
| 21 | + xmlhttp.send(null); |
| 22 | + } catch (e) { |
| 23 | + if (window.location.hostname == "localhost") { |
| 24 | + alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing."); |
| 25 | + } |
| 26 | + throw e; |
| 27 | + } |
| 28 | + } |
| 29 | +}; |
| 30 | +CodeReview.decodeAndShowDiff = function(jsonText) { |
| 31 | + // bleah |
| 32 | + eval("var data=" + jsonText); |
| 33 | + if (typeof data.code != 'undefined' && |
| 34 | + typeof data.code.rev != 'undefined' && |
| 35 | + typeof data.code.rev.diff != 'undefined') { |
| 36 | + CodeReview.showDiff(data.code.rev.diff); |
| 37 | + } else { |
| 38 | + CodeReview.showDiff('Diff load failed. :('); |
| 39 | + //alert(dumpWtf(data)); |
| 40 | + } |
| 41 | +}; |
| 42 | +CodeReview.diffTarget = function() { |
| 43 | + return document.getElementById('mw-codereview-diff'); |
| 44 | +}; |
| 45 | +CodeReview.showDiff = function(diffHtml) { |
| 46 | + CodeReview.diffTarget().innerHTML = diffHtml; |
| 47 | +}; |
| 48 | + |
| 49 | + |
| 50 | +function dumpWtf(obj) { |
| 51 | + var out = typeof(obj) + ' '; |
| 52 | + if (typeof(obj) == 'object' || typeof(obj) == 'array' ) { |
| 53 | + out += '('; |
| 54 | + for (var i in obj) { |
| 55 | + out += i + ': ' + |
| 56 | + dumpWtf(obj[i]) + "\n"; |
| 57 | + } |
| 58 | + out += ')'; |
| 59 | + } else { |
| 60 | + out += obj; |
| 61 | + } |
| 62 | + return out; |
| 63 | +} |
Property changes on: trunk/extensions/CodeReview/codereview.js |
___________________________________________________________________ |
Name: svn:eol-style |
1 | 64 | + native |
Index: trunk/extensions/CodeReview/CodeRevisionView.php |
— | — | @@ -60,13 +60,13 @@ |
61 | 61 | |
62 | 62 | $html .= $this->formatMetaData( $fields ); |
63 | 63 | |
64 | | - $diffHtml = $this->formatDiff(); |
65 | | - if( $diffHtml ) { |
| 64 | + if( $this->mRev->isDiffable() ) { |
| 65 | + $diffHtml = $this->formatDiff(); |
66 | 66 | $html .= |
67 | 67 | "<h2>" . wfMsgHtml( 'code-rev-diff' ) . |
68 | 68 | ' <small>[' . $wgUser->getSkin()->makeLinkObj( $special, |
69 | 69 | wfMsg('code-rev-purge-link'), 'action=purge' ) . ']</small></h2>' . |
70 | | - "<div class='mw-codereview-diff'>" . $diffHtml . "</div>\n"; |
| 70 | + "<div class='mw-codereview-diff' id='mw-codereview-diff'>" . $diffHtml . "</div>\n"; |
71 | 71 | } |
72 | 72 | $comments = $this->formatComments(); |
73 | 73 | if( $comments ) { |
— | — | @@ -228,13 +228,41 @@ |
229 | 229 | } |
230 | 230 | |
231 | 231 | function formatDiff() { |
232 | | - $diff = $this->mRepo->getDiff( $this->mRev->getId(), $this->mSkipCache ? 'skipcache' : '' ); |
| 232 | + $diff = $this->mRepo->getDiff( $this->mRev->getId(), $this->mSkipCache ? 'skipcache' : 'cached' ); |
233 | 233 | if( !$diff ) { |
234 | | - return false; |
| 234 | + // We'll try loading it by AJAX... |
| 235 | + return $this->stubDiffLoader(); |
235 | 236 | } |
236 | 237 | $hilite = new CodeDiffHighlighter(); |
237 | 238 | return $hilite->render( $diff ); |
238 | 239 | } |
| 240 | + |
| 241 | + function stubDiffLoader() { |
| 242 | + global $wgOut, $wgScriptPath; |
| 243 | + $encRepo = Xml::encodeJsVar( $this->mRepo->getName() ); |
| 244 | + $encRev = Xml::encodeJsVar( $this->mRev->getId() ); |
| 245 | + $wgOut->addScriptFile( "$wgScriptPath/extensions/CodeReview/codereview.js" ); |
| 246 | + $wgOut->addInlineScript( |
| 247 | + "addOnloadHook( |
| 248 | + function() { |
| 249 | + CodeReview.loadDiff($encRepo,$encRev); |
| 250 | + } |
| 251 | + );" ); |
| 252 | + return "Loading diff..."; |
| 253 | + /* |
| 254 | + return |
| 255 | + Xml::openElement( 'script', |
| 256 | + array( |
| 257 | + 'src' => $wgServer . $wgScriptPath . '/api.php?' . |
| 258 | + wfArrayToCgi( array( |
| 259 | + 'action' => 'codediff', |
| 260 | + 'repo' => $this->mRepo->getName(), |
| 261 | + 'rev' => $this->mRev->getId(), |
| 262 | + 'format' => 'json', |
| 263 | + 'callback' => 'alert' ) ) ) ) . |
| 264 | + "</script>"; |
| 265 | + */ |
| 266 | + } |
239 | 267 | |
240 | 268 | function formatComments() { |
241 | 269 | return "<div class='mw-codereview-comments'>" . |