r38864 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r38863‎ | r38864 | r38865 >
Date:09:00, 8 August 2008
Author:nikerabbit
Status:old
Tags:
Comment:
* 2008-08-08:1 experimental sync-group to import external changes and keep them in sync
Modified paths:
  • /trunk/extensions/Translate/README (modified) (history)
  • /trunk/extensions/Translate/Translate.php (modified) (history)
  • /trunk/extensions/Translate/scripts/sync-group.php (added) (history)

Diff [purge]

Index: trunk/extensions/Translate/Translate.php
@@ -11,7 +11,7 @@
1212 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
1313 */
1414
15 -define( 'TRANSLATE_VERSION', '9 (2008-08-04:1)' );
 15+define( 'TRANSLATE_VERSION', '9 (2008-08-08:1)' );
1616
1717 $wgExtensionCredits['specialpage'][] = array(
1818 'name' => 'Translate',
Index: trunk/extensions/Translate/scripts/sync-group.php
@@ -0,0 +1,294 @@
 2+<?php
 3+
 4+$optionsWithArgs = array( 'group', 'lang', 'start', 'end' );
 5+require( dirname(__FILE__) . '/cli.inc' );
 6+
 7+function showUsage() {
 8+ STDERR( <<<EOT
 9+Options:
 10+ --group comma separated list of group ids or *
 11+ --lang comma separated list of language codes or *
 12+ --norc do not add entries to recent changes table
 13+ --help this help
 14+ --noask skip all conflicts
 15+ --start start of the last export (changes in wiki after this will conflict)
 16+ --end end of the last export (changes in source before this wont conflict)
 17+ --nocolor without colours
 18+EOT
 19+);
 20+ exit( 1 );
 21+}
 22+
 23+if ( isset( $options['help'] ) ) showUsage();
 24+
 25+
 26+if (!isset($options['group'])) {
 27+ STDERR( "ESG1: Message group id must be supplied with group parameter." );
 28+ exit(1);
 29+}
 30+
 31+$group = MessageGroups::getGroup( $options['group'] );
 32+if ( $group === null ) {
 33+ if ( $options['group'] === '*' ) {
 34+ $mg = MessageGroups::singleton();
 35+ $groups = $mg->getGroups();
 36+ } else {
 37+ STDERR( "ESG2: Invalid message group was given." );
 38+ exit(1);
 39+ }
 40+} else {
 41+ $groups = array( $group );
 42+}
 43+
 44+if (!isset($options['lang'])) {
 45+ STDERR( "ESG3: List of language codes must be supplied with lang parameter." );
 46+ exit(1);
 47+}
 48+
 49+$start = isset($options['start']) ? strtotime($options['start']) : false;
 50+$end = isset($options['end']) ? strtotime($options['end']) : false;
 51+
 52+STDOUT( "Conflict times: " . wfTimestamp( TS_ISO_8601, $start ) . " - " . wfTimestamp( TS_ISO_8601, $end ) );
 53+
 54+$codes = array_filter( array_map( 'trim', explode( ',', $options['lang'] ) ) );
 55+
 56+if ( $codes[0] === '*' ) {
 57+ $langs = Language::getLanguageNames();
 58+ ksort( $langs );
 59+ $codes = array_keys($langs);
 60+}
 61+
 62+foreach ( $groups as &$group ) {
 63+ if ($group->isMeta()) continue;
 64+
 65+ STDOUT( "{$group->getLabel()} ", $group );
 66+
 67+ foreach ( $codes as $code ) {
 68+
 69+ $file = $group->getMessageFileWithPath( $code );
 70+ if ( !$file ) continue;
 71+
 72+ if ( !file_exists( $file ) ) continue;
 73+
 74+ $cs = new ChangeSyncer( $group );
 75+ if ( isset($options['norc']) ) $cs->norc = true;
 76+ if ( isset($options['noask']) ) $cs->interactive = false;
 77+ if ( isset($options['nocolor']) ) $cs->nocolor = true;
 78+
 79+ $ts = $cs->getTimestampsFromSvn( $file );
 80+ if ( !$ts ) $ts = $cs->getTimestampsFromFs( $file );
 81+
 82+ STDOUT( "Modify time for $code: " . wfTimestamp( TS_ISO_8601, $ts ) );
 83+
 84+ $count = $cs->checkConflicts( $code, $start, $end, $ts );
 85+
 86+ }
 87+ unset( $group );
 88+}
 89+
 90+class ChangeSyncer {
 91+ public $group;
 92+ public $norc = false;
 93+ public $interactive = true;
 94+ public $nocolor = false;
 95+
 96+ public function __construct( MessageGroup $group ) {
 97+ $this->group = $group;
 98+ }
 99+
 100+ // svn component from pecl doesn't seem to have this in quick sight
 101+ public function getTimestampsFromSvn( $file ) {
 102+ $file = escapeshellarg( $file );
 103+ $retval = 0;
 104+ $output = wfShellExec( "svn info $file", $retval );
 105+ if ( $retval ) return false;
 106+
 107+
 108+ $matches = array();
 109+ // PHP doesn't allow foo || return false;
 110+ // Thank
 111+ // you
 112+ // PHP (for being an ass)!
 113+ $regex = '^Last Changed Date: (.*) \(';
 114+ $ok = preg_match( "~$regex~m", $output, $matches );
 115+ if ($ok) return strtotime( $matches[1] );
 116+
 117+ return false;
 118+ }
 119+
 120+ public function getTimestampsFromFs( $file ) {
 121+ if ( !file_exists( $file ) ) return false;
 122+ $stat = stat($file);
 123+ return $stat['mtime'];
 124+ }
 125+
 126+ public function checkConflicts( $code, $startTs = false, $endTs = false, $changeTs = false ) {
 127+ $messages = $this->group->load( $code );
 128+ if ( !count($messages) ) return;
 129+
 130+ $collection = $this->group->initCollection( $code );
 131+ $this->group->fillCollection( $collection );
 132+
 133+ foreach ( $messages as $key => $translation ) {
 134+
 135+ if ( !isset($collection[$key]) ) {
 136+ //STDOUT( "Unknown key $key" );
 137+ continue;
 138+ }
 139+
 140+
 141+
 142+ $title = Title::makeTitleSafe( $this->group->namespaces[0], "$key/$code" );
 143+
 144+ $page = $title->getPrefixedText();
 145+
 146+ if ( $collection[$key]->database === null) {
 147+ STDOUT("Importing $page as a new translation");
 148+ $this->import( $title, $translation, 'Importing a new translation' );
 149+ continue;
 150+ }
 151+
 152+ $current = str_replace( TRANSLATE_FUZZY, '', $collection[$key]->translation );
 153+ $translation = str_replace( TRANSLATE_FUZZY, '', $translation );
 154+ if ( $translation === $current ) continue;
 155+
 156+ STDOUT("Conflict in " . $this->color('bold', $page). "!", $page);
 157+
 158+ global $wgLang;
 159+ $iso = 'xnY-xnm-xnd"T"xnH:xni:xns';
 160+
 161+ // Finally all is ok, now lets start comparing timestamps
 162+ // Make sure we are comparing timestamps in same format
 163+ $wikiTs = $this->getLastGoodChange( $title, $startTs );
 164+ if ( $wikiTs ) {
 165+ $wikiTs = wfTimestamp( TS_UNIX, $wikiTs );
 166+ $wikiDate = $wgLang->sprintfDate( $iso, wfTimestamp( TS_MW, $wikiTs ) );
 167+ } else {
 168+ $wikiDate = 'Unknown';
 169+ }
 170+
 171+ if ( $startTs ) {
 172+ $startTs = wfTimestamp( TS_UNIX, $startTs );
 173+ $startDate = $wgLang->sprintfDate( $iso, wfTimestamp( TS_MW, $startTs ) );
 174+ } else {
 175+ $startDate = 'Unknown';
 176+ }
 177+
 178+ if ( $endTs ) {
 179+ $endTs = wfTimestamp( TS_UNIX, $endTs );
 180+ $endDate = $wgLang->sprintfDate( $iso, wfTimestamp( TS_MW, $endTs ) );
 181+ } else {
 182+ $endDate = 'Unknown';
 183+ }
 184+
 185+ if ( $changeTs ) {
 186+ $changeTs = wfTimestamp( TS_UNIX, $changeTs );
 187+ $changeDate = $wgLang->sprintfDate( $iso, wfTimestamp( TS_MW, $changeTs ) );
 188+ } else {
 189+ $changeDate = 'Unknown';
 190+ }
 191+
 192+ if ( $changeTs ) {
 193+ if ( $wikiTs > $startTs && $changeTs <= $endTs ) {
 194+ STDOUT(" →Changed in wiki after export: IGNORE", $page);
 195+ continue;
 196+ } elseif ( !$wikiTs || ($changeTs > $endTs && $wikiTs < $startTs) ) {
 197+ STDOUT(" →Changed in source after export: IMPORT", $page);
 198+ $this->import( $title, $translation, 'Updating translation from external source' );
 199+ continue;
 200+ }
 201+
 202+ }
 203+
 204+ if ( !$this->interactive ) continue;
 205+ STDOUT(" →Needs manual resolution", $page);
 206+
 207+ STDOUT("Source translation at $changeDate:");
 208+ STDOUT($this->color('blue', $translation) . "\n");
 209+ STDOUT("Wiki translation at $wikiDate:");
 210+ STDOUT($this->color('green', $current) . "\n");
 211+
 212+ do {
 213+ STDOUT("Resolution: [S]kip [I]mport [C]onflict: ", 'foo' );
 214+ $action = fgets( STDIN );
 215+ $action = strtoupper( trim( $action ) );
 216+ if ( $action === 'S' ) break;
 217+ if ( $action === 'I' ) {
 218+ $this->import( $title, $translation, 'Updating translation from external source' );
 219+ break;
 220+ }
 221+ if ( $action === 'C' ) {
 222+ $this->import( $title, TRANSLATE_FUZZY . $translation, 'Edit conflict between wiki and source' );
 223+ break;
 224+ }
 225+ } while( true );
 226+
 227+ }
 228+ }
 229+
 230+ public function color( $color, $text ) {
 231+ switch ($color) {
 232+ case 'blue':
 233+ return "\033[1;34m$text\033[0m";
 234+ case 'green':
 235+ return "\033[1;32m$text\033[0m";
 236+ case 'bold':
 237+ return "\033[1m$text\033[0m";
 238+ default:
 239+ return $text;
 240+ }
 241+ }
 242+
 243+ public function getLastGoodChange( $title, $startTs = false ) {
 244+ global $wgTranslateFuzzyBotName;
 245+
 246+ $wikiTs = false;
 247+ $revision = Revision::newFromTitle( $title );
 248+ while ( $revision ) {
 249+ // No need to go back further
 250+ if ( $startTs && $wikiTs && ( $wikiTs < $startTs ) ) break;
 251+
 252+ if ( $revision->getRawUserText() === $wgTranslateFuzzyBotName ) {
 253+ $revision = $revision->getPrevious();
 254+ continue;
 255+ }
 256+
 257+ $wikiTs = wfTimestamp( TS_UNIX, $revision->getTimestamp());
 258+ break;
 259+ }
 260+
 261+ return $wikiTs;
 262+ }
 263+
 264+ public function getImportUser() {
 265+ static $user = null;
 266+ if ( $user === null ) {
 267+ global $wgTranslateFuzzyBotName;
 268+ $user = User::newFromName( $wgTranslateFuzzyBotName );
 269+
 270+ if ( !$user->isLoggedIn() ) {
 271+ STDOUT( "Creating user $wgTranslateFuzzyBotName" );
 272+ $user->addToDatabase();
 273+ }
 274+ }
 275+
 276+ return $user;
 277+ }
 278+
 279+ public function import( $title, $translation, $comment ) {
 280+ global $wgUser;
 281+ $old = $wgUser;
 282+ $wgUser = $this->getImportUser();
 283+
 284+ $flags = EDIT_FORCE_BOT;
 285+ if ( $this->norc ) $flags |= EDIT_SUPPRESS_RC;
 286+
 287+ $article = new Article( $title );
 288+ STDOUT( "Importing {$title->getPrefixedText()}: ", $title );
 289+ $success = $article->doEdit( $translation, $comment, $flags );
 290+ STDOUT( $success ? 'OK' : 'FAILED', $title );
 291+
 292+ $wgUser = $old;
 293+ }
 294+
 295+}
\ No newline at end of file
Property changes on: trunk/extensions/Translate/scripts/sync-group.php
___________________________________________________________________
Added: svn:eol-style
1296 + native
Index: trunk/extensions/Translate/README
@@ -33,7 +33,8 @@
3434 </code>
3535
3636 == Changes in version 10 ==
37 -* 2008-08-04:add "Other translations" link to Special:Prefexindex in sidebar toolbox
 37+* 2008-08-08:1 experimental sync-group to import external changes and keep them in sync
 38+* 2008-08-04:1 add "Other translations" link to Special:Prefexindex in sidebar toolbox
3839 * 2008-07-29:2 support for variables and purging and fallbacks in page translation
3940 * 2008-07-29:1 bug fixes and enhanced magic word support for AdvancedTranslate
4041 * 2008-07-26:2 proper parents for branched messages

Status & tagging log