From 7544b1c4977ca9cb37f2e028a2899843f2fda362 Mon Sep 17 00:00:00 2001 From: Roan Kattouw Date: Tue, 27 Nov 2007 16:41:13 +0000 Subject: [PATCH] API: Adding diff generation to prop=revisions. This implementation outputs normal diff output (with < and >) rather than unified, and always uses native PHP diff (i.e. ignores $wgExternalDiffEngine). An implementation that honors $wgExternalDiffEngine and outputs a unified diff will follow later. --- RELEASE-NOTES | 1 + includes/api/ApiQueryRevisions.php | 103 +++++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 5751c2d97f..4252f7de7e 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -297,6 +297,7 @@ Full API documentation is available at http://www.mediawiki.org/wiki/API * Outputting list of all user preferences rather than having to request them by name * (bug 11206) api.php should honor maxlag +* Added diff generation to prop=revisions === Languages updated in 1.12 === diff --git a/includes/api/ApiQueryRevisions.php b/includes/api/ApiQueryRevisions.php index 5b4e236c8c..70747c6621 100644 --- a/includes/api/ApiQueryRevisions.php +++ b/includes/api/ApiQueryRevisions.php @@ -45,14 +45,14 @@ class ApiQueryRevisions extends ApiQueryBase { $fld_comment = false, $fld_user = false, $fld_content = false; public function execute() { - $limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = null; + $limit = $startid = $endid = $start = $end = $dir = $prop = $user = $excludeuser = $diffto = $difftoprev = null; extract($this->extractRequestParams()); // If any of those parameters are used, work in 'enumeration' mode. // Enum mode can only be used when exactly one page is provided. - // Enumerating revisions on multiple pages make it extremelly - // difficult to manage continuations and require additional sql indexes - $enumRevMode = (!is_null($user) || !is_null($excludeuser) || !is_null($limit) || !is_null($startid) || !is_null($endid) || $dir === 'newer' || !is_null($start) || !is_null($end)); + // Enumerating revisions on multiple pages make it extremely + // difficult to manage continuations and require additional SQL indexes + $enumRevMode = (!is_null($user) || !is_null($excludeuser) || !is_null($limit) || !is_null($startid) || !is_null($endid) || $dir === 'newer' || !is_null($start) || !is_null($end) | !$difftoprev); $pageSet = $this->getPageSet(); @@ -67,7 +67,7 @@ class ApiQueryRevisions extends ApiQueryBase { $this->dieUsage('The revids= parameter may not be used with the list options (limit, startid, endid, dirNewer, start, end).', 'revids'); if ($pageCount > 1 && $enumRevMode) - $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start, and end parameters may only be used on a single page.', 'multpages'); + $this->dieUsage('titles, pageids or a generator was used to supply multiple pages, but the limit, startid, endid, dirNewer, user, excludeuser, start, end and difftoprev parameters may only be used on a single page.', 'multpages'); $this->addTables('revision'); $this->addWhere('rev_deleted=0'); @@ -86,12 +86,36 @@ class ApiQueryRevisions extends ApiQueryBase { $this->fld_comment = $this->addFieldsIf('rev_comment', isset ($prop['comment'])); $this->fld_size = $this->addFieldsIf('rev_len', isset ($prop['size'])); + if($diffto || $difftoprev) + $this->formatter = new DiffFormatter; + if($diffto) + { + global $wgContLang; + $difftoRev = Revision::newFromID($diffto); + if(!($difftoRev instanceof Revision)) + $this->dieUsage("There is no revision with ID $diffto", 'nosuchrev'); + $this->diffOldText = $difftoRev->revText(); + if($this->diffOldText == '') // deleted revision + $this->dieUsage("There is no revision with ID $diffto", 'nosuchrev'); // fake non-existence + $this->diffOldText = explode("\n", $wgContLang->segmentForDiff($this->diffOldText)); + $this->diffto = $diffto; + } + else + $this->diffto = false; + if($difftoprev) + { + $this->revCache = array(); + $this->difftoprev = true; + } + else + $this->difftoprev = false; + if (isset ($prop['user'])) { $this->addFields('rev_user'); $this->addFields('rev_user_text'); $this->fld_user = true; } - if (isset ($prop['content'])) { + if (isset ($prop['content']) || !is_null($diffto) || $difftoprev) { // For each page we will request, the user must have read rights for that page foreach ($pageSet->getGoodTitles() as $title) { @@ -107,17 +131,17 @@ class ApiQueryRevisions extends ApiQueryBase { $this->addFields('old_text'); $this->addFields('old_flags'); - $this->fld_content = true; + $this->fld_content = isset($prop['content']); $this->expandTemplates = $expandtemplates; } - $userMax = ($this->fld_content ? 50 : 500); - $botMax = ($this->fld_content ? 200 : 10000); + $userMax = ($this->fld_content || $diffto || $difftoprev ? 50 : 500); + $botMax = ($this->fld_content || $diffto || $difftoprev ? 200 : 10000); if ($enumRevMode) { - // This is mostly to prevent parameter errors (and optimize sql?) + // This is mostly to prevent parameter errors (and optimize SQL?) if (!is_null($startid) && !is_null($start)) $this->dieUsage('start and startid cannot be used together', 'badparams'); @@ -205,7 +229,41 @@ class ApiQueryRevisions extends ApiQueryBase { $this->extractRowInfo($row)); } $db->freeResult($res); - + + if($this->difftoprev) + { + global $wgContLang; + ksort($this->revCache, SORT_NUMERIC); + $previousRevID = null; + $oldText = null; + $data =& $this->getResult()->getData(); + $pageID = current(array_keys($pageSet->getGoodTitles())); + $this->diffArr = array(); + foreach($this->revCache as $revid => $revtext) + { + $r = array(); + if(is_null($previousRevID)) + { + // First run + $previousRevID = $revid; + $oldText = explode("\n", $wgContLang->segmentForDiff($revtext)); + continue; + } + $newText = explode("\n", $wgContLang->segmentForDiff($revtext)); + $diff = new Diff($oldText, $newText); + $r['from'] = $previousRevID; + ApiResult::setContent($r, $wgContLang->unsegmentForDiff($this->formatter->format($diff))); + $diffArr[$revid] = $r; + + $previousRevID = $revid; + $oldText = $newText; + } + // Now that $this->diffArr is filled with diffprev elements, add them to the result + foreach($data['query']['pages'][$pageID]['revisions'] as &$rev) + if(isset($diffArr[$rev['revid']])) + $rev['difftoprev'] = $diffArr[$rev['revid']]; + } + // Ensure that all revisions are shown as '' elements $result = $this->getResult(); if ($result->getIsRawMode()) { @@ -248,8 +306,9 @@ class ApiQueryRevisions extends ApiQueryBase { $vals['comment'] = $row->rev_comment; } - if ($this->fld_content) { + if ($this->fld_content || $this->diffto || $this->difftoprev) $text = Revision :: getRevisionText($row); + if ($this->fld_content) { if ($this->expandTemplates) { global $wgParser; $text = $wgParser->preprocess( $text, Title::newFromID($row->rev_page), new ParserOptions() ); @@ -257,6 +316,18 @@ class ApiQueryRevisions extends ApiQueryBase { ApiResult :: setContent($vals, $text); } + if($this->diffto) + { + global $wgContLang; + $newText = explode("\n", $wgContLang->segmentForDiff($text)); + $diff = new Diff($this->diffOldText, $newText); + $vals['diffto']['from'] = $this->diffto; + ApiResult::setContent($vals['diffto'], $wgContLang->unsegmentForDiff($this->formatter->format($diff))); + } + if($this->difftoprev) + // Cache the revision's content for later use + $this->revCache[$row->rev_id] = $text; + return $vals; } @@ -308,6 +379,10 @@ class ApiQueryRevisions extends ApiQueryBase { ), 'expandtemplates' => false, + 'diffto' => array( + ApiBase :: PARAM_TYPE => 'integer' + ), + 'difftoprev' => false, ); } @@ -322,7 +397,9 @@ class ApiQueryRevisions extends ApiQueryBase { 'dir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)', 'user' => 'only include revisions made by user', 'excludeuser' => 'exclude revisions made by user', - 'expandtemplates' => 'expand templates in revision content' + 'expandtemplates' => 'expand templates in revision content', + 'diffto' => 'Revision number to compare all revisions with', + 'difftoprev' => 'Diff each revision to the previous one (enum)', ); } -- 2.20.1