r55256 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r55255‎ | r55256 | r55257 >
Date:18:35, 18 August 2009
Author:brion
Status:ok
Tags:
Comment:
Update from dev trunk
Modified paths:
  • /branches/wmf-deployment/extensions/LocalisationUpdate (modified) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/KNOWN_ISSUES.txt (modified) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/LocalisationUpdate.class.php (modified) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/LocalisationUpdate.i18n.php (modified) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/LocalisationUpdate.php (modified) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/QuickArrayReader.php (added) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/patch-lfh_timestamp.sql (added) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/schema.sql (modified) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/tests (added) (history)
  • /branches/wmf-deployment/extensions/LocalisationUpdate/update.php (modified) (history)

Diff [purge]

Index: branches/wmf-deployment/extensions/LocalisationUpdate/tests/tokenTest.php
@@ -0,0 +1,91 @@
 2+<?php
 3+
 4+$IP = strval( getenv( 'MW_INSTALL_PATH' ) ) !== ''
 5+ ? getenv( 'MW_INSTALL_PATH' )
 6+ : realpath( dirname( __FILE__ ) . "/../../../" );
 7+
 8+require_once( "$IP/maintenance/commandLine.inc" );
 9+
 10+function evalExtractArray( $php, $varname ) {
 11+ eval( $php );
 12+ return @$$varname;
 13+}
 14+
 15+function confExtractArray( $php, $varname ) {
 16+ try {
 17+ $ce = new ConfEditor("<?php $php");
 18+ $vars = $ce->getVars();
 19+ $retval = @$vars[$varname];
 20+ } catch( Exception $e ) {
 21+ print $e . "\n";
 22+ $retval = null;
 23+ }
 24+ return $retval;
 25+}
 26+
 27+function quickTokenExtractArray( $php, $varname ) {
 28+ $reader = new QuickArrayReader("<?php $php");
 29+ return $reader->getVar( $varname );
 30+}
 31+
 32+
 33+if( count( $args ) ) {
 34+ $sources = $args;
 35+} else {
 36+ $sources =
 37+ array_merge(
 38+ glob("$IP/extensions/*/*.i18n.php"),
 39+ glob("$IP/languages/messages/Messages*.php") );
 40+}
 41+
 42+foreach( $sources as $sourceFile ) {
 43+ $rel = basename( $sourceFile );
 44+ $out = str_replace( '/', '-', $rel );
 45+
 46+ $sourceData = file_get_contents( $sourceFile );
 47+
 48+ if( preg_match( '!extensions/!', $sourceFile ) ) {
 49+ $sourceData = LocalisationUpdate::cleanupExtensionFile( $sourceData );
 50+ $items = 'langs';
 51+ } else {
 52+ $sourceData = LocalisationUpdate::cleanupFile( $sourceData );
 53+ $items = 'messages';
 54+ }
 55+
 56+ file_put_contents( "$out.txt", $sourceData );
 57+
 58+ $start = microtime(true);
 59+ $eval = evalExtractArray( $sourceData, 'messages' );
 60+ $deltaEval = microtime(true) - $start;
 61+
 62+ $start = microtime(true);
 63+ $quick = quickTokenExtractArray( $sourceData, 'messages' );
 64+ $deltaQuick = microtime(true) - $start;
 65+
 66+ $start = microtime(true);
 67+ $token = confExtractArray( $sourceData, 'messages' );
 68+ $deltaToken = microtime(true) - $start;
 69+
 70+ $hashEval = md5(serialize($eval));
 71+ $hashToken = md5(serialize($token));
 72+ $hashQuick = md5(serialize($quick));
 73+ $countEval = count( (array)$eval);
 74+ $countToken = count( (array)$token );
 75+ $countQuick = count( (array)$quick );
 76+
 77+ printf( "%s %s %d $items - %0.1fms - eval\n", $rel, $hashEval, $countEval, $deltaEval * 1000 );
 78+ printf( "%s %s %d $items - %0.1fms - QuickArrayReader\n", $rel, $hashQuick, $countQuick, $deltaQuick * 1000 );
 79+ printf( "%s %s %d $items - %0.1fms - ConfEditor\n", $rel, $hashToken, $countToken, $deltaToken * 1000 );
 80+
 81+ if( $hashEval !== $hashToken || $hashEval !== $hashQuick ) {
 82+ echo "FAILED on $rel\n";
 83+ file_put_contents( "$out-eval.txt", var_export( $eval, true ) );
 84+ file_put_contents( "$out-token.txt", var_export( $token, true ) );
 85+ file_put_contents( "$out-quick.txt", var_export( $quick, true ) );
 86+ #die("check eval.txt and token.txt\n");
 87+ }
 88+ echo "\n";
 89+}
 90+
 91+echo "ok\n";
 92+
Property changes on: branches/wmf-deployment/extensions/LocalisationUpdate/tests/tokenTest.php
___________________________________________________________________
Name: svn:eol-style
193 + native
Index: branches/wmf-deployment/extensions/LocalisationUpdate/QuickArrayReader.php
@@ -0,0 +1,172 @@
 2+<?php
 3+
 4+/**
 5+ * Quickie parser class that can happily read the subset of PHP we need
 6+ * for our localization arrays safely.
 7+ *
 8+ * About an order of magnitude faster than ConfEditor(), but still an
 9+ * order of magnitude slower than eval().
 10+ */
 11+class QuickArrayReader {
 12+ var $vars = array();
 13+
 14+ function __construct( $string ) {
 15+ $scalarTypes = array(
 16+ T_LNUMBER => true,
 17+ T_DNUMBER => true,
 18+ T_STRING => true,
 19+ T_CONSTANT_ENCAPSED_STRING => true,
 20+ );
 21+ $skipTypes = array(
 22+ T_WHITESPACE => true,
 23+ T_COMMENT => true,
 24+ T_DOC_COMMENT => true,
 25+ );
 26+ $tokens = token_get_all( $string );
 27+ $count = count( $tokens );
 28+ for( $i = 0; $i < $count; ) {
 29+ while( isset($skipTypes[$tokens[$i][0]] ) ) {
 30+ $i++;
 31+ }
 32+ switch( $tokens[$i][0] ) {
 33+ case T_OPEN_TAG:
 34+ $i++;
 35+ continue;
 36+ case T_VARIABLE:
 37+ // '$messages' -> 'messages'
 38+ $varname = trim( substr( $tokens[$i][1], 1 ) );
 39+ $varindex = null;
 40+
 41+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 42+
 43+ if( $tokens[$i] === '[' ) {
 44+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 45+
 46+ if( isset($scalarTypes[$tokens[$i][0]] ) ) {
 47+ $varindex = $this->parseScalar( $tokens[$i] );
 48+ } else {
 49+ throw $this->except( $tokens[$i], 'scalar index' );
 50+ }
 51+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 52+
 53+ if( $tokens[$i] !== ']' ) {
 54+ throw $this->except( $tokens[$i], ']' );
 55+ }
 56+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 57+ }
 58+
 59+ if( $tokens[$i] !== '=' ) {
 60+ throw $this->except( $tokens[$i], '=' );
 61+ }
 62+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 63+
 64+ if( isset($scalarTypes[$tokens[$i][0]] ) ) {
 65+ $buildval = $this->parseScalar( $tokens[$i] );
 66+ } elseif( $tokens[$i][0] === T_ARRAY ) {
 67+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 68+ if( $tokens[$i] !== '(' ) {
 69+ throw $this->except( $tokens[$i], '(' );
 70+ }
 71+ $buildval = array();
 72+ do {
 73+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 74+
 75+ if( $tokens[$i] === ')' ) {
 76+ break;
 77+ }
 78+ if( isset($scalarTypes[$tokens[$i][0]] ) ) {
 79+ $key = $this->parseScalar( $tokens[$i] );
 80+ }
 81+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 82+
 83+ if( $tokens[$i][0] !== T_DOUBLE_ARROW ) {
 84+ throw $this->except( $tokens[$i], '=>' );
 85+ }
 86+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 87+
 88+ if( isset($scalarTypes[$tokens[$i][0]] ) ) {
 89+ $val = $this->parseScalar( $tokens[$i] );
 90+ }
 91+ @$buildval[$key] = $val;
 92+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 93+
 94+ if( $tokens[$i] === ',' ) {
 95+ continue;
 96+ } elseif( $tokens[$i] === ')' ) {
 97+ break;
 98+ } else {
 99+ throw $this->except( $tokens[$i], ', or )' );
 100+ }
 101+ } while(true);
 102+ } else {
 103+ throw $this->except( $tokens[$i], 'scalar or array' );
 104+ }
 105+ if( is_null( $varindex ) ) {
 106+ $this->vars[$varname] = $buildval;
 107+ } else {
 108+ @$this->vars[$varname][$varindex] = $buildval;
 109+ }
 110+ while( isset($skipTypes[$tokens[++$i][0]] ) );
 111+ if( $tokens[$i] !== ';' ) {
 112+ throw $this->except($tokens[$i], ';');
 113+ }
 114+ $i++;
 115+ break;
 116+ default:
 117+ throw $this->except($tokens[$i], 'open tag, whitespace, or variable.');
 118+ }
 119+ }
 120+ }
 121+
 122+ private function except( $got, $expected ) {
 123+ if( is_array( $got ) ) {
 124+ $got = token_name( $got[0] ) . " ('" . $got[1] . "')";
 125+ } else {
 126+ $got = "'" . $got . "'";
 127+ }
 128+ return new Exception( "Expected $expected, got $got" );
 129+ }
 130+
 131+ /**
 132+ * Parse a scalar value in PHP
 133+ * @return mixed Parsed value
 134+ */
 135+ function parseScalar( $token ) {
 136+ if( is_array( $token ) ) {
 137+ $str = $token[1];
 138+ } else {
 139+ $str = $token;
 140+ }
 141+ if ( $str !== '' && $str[0] == '\'' )
 142+ // Single-quoted string
 143+ // @fixme trim() call is due to mystery bug where whitespace gets
 144+ // appended to the token; without it we ended up reading in the
 145+ // extra quote on the end!
 146+ return strtr( substr( trim( $str ), 1, -1 ),
 147+ array( '\\\'' => '\'', '\\\\' => '\\' ) );
 148+ if ( $str !== '' && @$str[0] == '"' )
 149+ // Double-quoted string
 150+ // @fixme trim() call is due to mystery bug where whitespace gets
 151+ // appended to the token; without it we ended up reading in the
 152+ // extra quote on the end!
 153+ return stripcslashes( substr( trim( $str ), 1, -1 ) );
 154+ if ( substr( $str, 0, 4 ) === 'true' )
 155+ return true;
 156+ if ( substr( $str, 0, 5 ) === 'false' )
 157+ return false;
 158+ if ( substr( $str, 0, 4 ) === 'null' )
 159+ return null;
 160+ // Must be some kind of numeric value, so let PHP's weak typing
 161+ // be useful for a change
 162+ return $str;
 163+ }
 164+
 165+ function getVar( $varname ) {
 166+ if( isset( $this->vars[$varname] ) ) {
 167+ return $this->vars[$varname];
 168+ } else {
 169+ return null;
 170+ }
 171+ }
 172+}
 173+
Property changes on: branches/wmf-deployment/extensions/LocalisationUpdate/QuickArrayReader.php
___________________________________________________________________
Name: svn:eol-style
1174 + native
Index: branches/wmf-deployment/extensions/LocalisationUpdate/KNOWN_ISSUES.txt
@@ -1,2 +1,11 @@
22 - Only works with SVN revision 50605 or later of the
33 MediaWiki core
 4+
 5+
 6+
 7+Key issues at the moment:
 8+* Seems to want to store a copy of the localization updates in each local database.
 9+We've got hundreds of wikis run from the same installation set; we don't want to multiply our effort by 1000.
 10+
 11+* It doesn't seem to be using available memcached stuff; unsure yet whether this is taken care of
 12+by the general message caching or if we're going to end up making extra hits we don't need.
Index: branches/wmf-deployment/extensions/LocalisationUpdate/patch-lfh_timestamp.sql
@@ -0,0 +1,4 @@
 2+-- Patch that adds lfh_timestamp field and index
 3+
 4+ALTER TABLE /*_*/localisation_file_hash ADD lfh_timestamp varchar(14) NOT NULL;
 5+CREATE INDEX /*i*/lfh_timestamp ON /*_*/localisation_file_hash (lfh_timestamp);
Property changes on: branches/wmf-deployment/extensions/LocalisationUpdate/patch-lfh_timestamp.sql
___________________________________________________________________
Name: svn:eol-style
16 + native
Index: branches/wmf-deployment/extensions/LocalisationUpdate/LocalisationUpdate.i18n.php
@@ -5,7 +5,7 @@
66 * @file
77 * @ingroup Extensions
88 */
9 -
 9+
1010 $messages = array();
1111
1212 /** English
@@ -31,6 +31,13 @@
3232 'localisationupdate-desc' => 'يبقي الرسائل المترجمة محدثة كأفضل ما يكون',
3333 );
3434
 35+/** Bavarian (Boarisch)
 36+ * @author Man77
 37+ */
 38+$messages['bar'] = array(
 39+ 'localisationupdate-desc' => "Lokalisiade Texte und Nåchrichtn so aktuell håidn wia's gråd gehd",
 40+);
 41+
3542 /** Belarusian (Taraškievica orthography) (Беларуская (тарашкевіца))
3643 * @author EugeneZelenko
3744 */
@@ -45,6 +52,13 @@
4653 'localisationupdate-desc' => 'Zadržavanje lokaliziranih poruka ažurnim koliko je god moguće',
4754 );
4855
 56+/** Catalan (Català)
 57+ * @author Paucabot
 58+ */
 59+$messages['ca'] = array(
 60+ 'localisationupdate-desc' => 'Manté els missatges localitzats tan actualitzats com sigui possible',
 61+);
 62+
4963 /** German (Deutsch)
5064 * @author Purodha
5165 */
@@ -59,6 +73,20 @@
6074 'localisationupdate-desc' => 'Źaržy lokalizěrowane powěźeńki tak aktualne ako móžno',
6175 );
6276
 77+/** Spanish (Español)
 78+ * @author Crazymadlover
 79+ */
 80+$messages['es'] = array(
 81+ 'localisationupdate-desc' => 'Mantener los mensajes localizados tan actualizados como sean posibles',
 82+);
 83+
 84+/** Finnish (Suomi)
 85+ * @author Nike
 86+ */
 87+$messages['fi'] = array(
 88+ 'localisationupdate-desc' => 'Pitää käännetyt viestit niin ajantasaisina kuin mahdollista',
 89+);
 90+
6391 /** French (Français)
6492 * @author Crochet.david
6593 */
@@ -94,6 +122,13 @@
95123 'localisationupdate-desc' => 'Dźerži lokalizowane zdźělenki tak aktualne kaž móžno',
96124 );
97125
 126+/** Hungarian (Magyar)
 127+ * @author Glanthor Reviol
 128+ */
 129+$messages['hu'] = array(
 130+ 'localisationupdate-desc' => 'Frissíti a lefordított üzeneteket',
 131+);
 132+
98133 /** Interlingua (Interlingua)
99134 * @author McDutchie
100135 */
@@ -101,6 +136,20 @@
102137 'localisationupdate-desc' => 'Mantene le messages localisate tanto actual como possibile',
103138 );
104139
 140+/** Indonesian (Bahasa Indonesia)
 141+ * @author Bennylin
 142+ */
 143+$messages['id'] = array(
 144+ 'localisationupdate-desc' => 'Mengusahakan agar pesan-pesan yang telah diterjemahkan tetap semutakhir mungkin',
 145+);
 146+
 147+/** Italian (Italiano)
 148+ * @author Darth Kule
 149+ */
 150+$messages['it'] = array(
 151+ 'localisationupdate-desc' => 'Mantiene i messaggi localizzati quanto più aggiornati è possibile',
 152+);
 153+
105154 /** Japanese (日本語)
106155 * @author Fryed-peach
107156 */
@@ -122,6 +171,13 @@
123172 'localisationupdate-desc' => 'hält déi lokaliséiert Messagen esou aktuell wéi méiglech.',
124173 );
125174
 175+/** Macedonian (Македонски)
 176+ * @author Bjankuloski06
 177+ */
 178+$messages['mk'] = array(
 179+ 'localisationupdate-desc' => 'Ги одржува локализираните пораки колку што е можно пообновени и повеќе во тек со настаните',
 180+);
 181+
126182 /** Dutch (Nederlands)
127183 * @author Siebrand
128184 */
@@ -129,6 +185,13 @@
130186 'localisationupdate-desc' => 'Houdt de gelokaliseerde berichten zo actueel mogelijk',
131187 );
132188
 189+/** Norwegian Nynorsk (‪Norsk (nynorsk)‬)
 190+ * @author Gunnernett
 191+ */
 192+$messages['nn'] = array(
 193+ 'localisationupdate-desc' => 'Held dei lokaliserte meldingane så oppdaterte som mogleg',
 194+);
 195+
133196 /** Norwegian (bokmål)‬ (‪Norsk (bokmål)‬)
134197 * @author Nghtwlkr
135198 */
@@ -150,6 +213,34 @@
151214 'localisationupdate-desc' => 'Uaktualnia lokalne komunikaty w miarę możliwości na bieżąco',
152215 );
153216
 217+/** Piedmontese (Piemontèis)
 218+ * @author Dragonòt
 219+ */
 220+$messages['pms'] = array(
 221+ 'localisationupdate-desc' => 'A manten i messagi localisà ël pì agiornà possìbil',
 222+);
 223+
 224+/** Portuguese (Português)
 225+ * @author Malafaya
 226+ */
 227+$messages['pt'] = array(
 228+ 'localisationupdate-desc' => 'Mantém as mensagens localizadas tão atualizadas quanto possível',
 229+);
 230+
 231+/** Brazilian Portuguese (Português do Brasil)
 232+ * @author Eduardo.mps
 233+ */
 234+$messages['pt-br'] = array(
 235+ 'localisationupdate-desc' => 'Mantém as mensagens localizadas tão atualizadas quanto possível',
 236+);
 237+
 238+/** Romanian (Română)
 239+ * @author KlaudiuMihaila
 240+ */
 241+$messages['ro'] = array(
 242+ 'localisationupdate-desc' => 'Menţine mesajele localizate cât mai actualizate',
 243+);
 244+
154245 /** Tarandíne (Tarandíne)
155246 * @author Joetaras
156247 */
@@ -157,6 +248,13 @@
158249 'localisationupdate-desc' => "Mandine le messagge localizzate 'u cchiù aggiornate possibbile",
159250 );
160251
 252+/** Russian (Русский)
 253+ * @author Александр Сигачёв
 254+ */
 255+$messages['ru'] = array(
 256+ 'localisationupdate-desc' => 'Поддерживает актуальность локализованных сообщений, насколько это возможно',
 257+);
 258+
161259 /** Slovak (Slovenčina)
162260 * @author Helix84
163261 */
@@ -164,6 +262,13 @@
165263 'localisationupdate-desc' => 'Udržiava lokalizované správy čo najaktuálnejšie',
166264 );
167265
 266+/** Vietnamese (Tiếng Việt)
 267+ * @author Vinhtantran
 268+ */
 269+$messages['vi'] = array(
 270+ 'localisationupdate-desc' => 'Giữ các thông điệp bản địa hóa được cập nhật nhất có thể',
 271+);
 272+
168273 /** Yue (粵語)
169274 * @author Tom Maaswinkel
170275 */
Index: branches/wmf-deployment/extensions/LocalisationUpdate/update.php
@@ -6,25 +6,30 @@
77
88 require_once( "$IP/maintenance/commandLine.inc" );
99
10 -$verbose = false;
 10+if( isset( $options['help'] ) ) {
 11+ print "Fetches updated localisation files from MediaWiki development SVN\n";
 12+ print "and saves into local database to merge with release defaults.\n";
 13+ print "\n";
 14+ print "Usage: php extensions/LocalisationUpdate/update.php\n";
 15+ print "Options:\n";
 16+ print " --quiet Suppress progress output\n";
 17+ print " --all Fetch all present extensions, not just those enabled\n";
 18+ print "\n";
 19+ exit( 0 );
 20+}
1121
12 -if ( $argc > 1 && $argv[0] == "verbose" )
13 - $verbose = true;
1422
15 -$mtime = microtime();
16 -$mtime = explode( " ", $mtime );
17 -$mtime = $mtime[1] + $mtime[0];
18 -$starttime = $mtime;
 23+$verbose = !isset( $options['quiet'] );
 24+$all = isset( $options['all'] );
1925
 26+$starttime = microtime( true );
 27+
2028 // Prevent the script from timing out
2129 set_time_limit( 0 );
2230 ini_set( "max_execution_time", 0 );
2331
24 -LocalisationUpdate::updateMessages( $verbose );
 32+LocalisationUpdate::updateMessages( $verbose, $all );
2533
26 -$mtime = microtime();
27 -$mtime = explode( " ", $mtime );
28 -$mtime = $mtime[1] + $mtime[0];
29 -$endtime = $mtime;
 34+$endtime = microtime( true );
3035 $totaltime = ( $endtime - $starttime );
3136 print "All done in " . $totaltime . " seconds\n";
Index: branches/wmf-deployment/extensions/LocalisationUpdate/LocalisationUpdate.php
@@ -7,7 +7,18 @@
88
99 // Configuration
1010
11 -$wgLocalisationUpdateSVNURL = "svn.wikimedia.org/svnroot/mediawiki/";
 11+/**
 12+ * This should point to either an HTTP-accessible Subversion repository containing
 13+ * MediaWiki's 'phase3' and 'extensions' directory, *or* a local directory containing
 14+ * checkouts of them:
 15+ *
 16+ * cd /path/to/mediawiki-trunk
 17+ * svn co http://svn.wikimedia.org/svnroot/mediawiki/trunk/phase3
 18+ * svn co http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions
 19+ * $wgLocalisationUpdateSVNURL = '/path/to/mediawiki-trunk';
 20+ */
 21+$wgLocalisationUpdateSVNURL = "http://svn.wikimedia.org/svnroot/mediawiki/trunk";
 22+
1223 $wgLocalisationUpdateRetryAttempts = 5;
1324
1425 // Info about me!
@@ -22,9 +33,13 @@
2334 );
2435
2536 // Use the right hook
26 -$wgHooks['MessageNotInMwNs'][] = "LocalisationUpdate::FindUpdatedMessage";
 37+$wgHooks['LocalisationCacheRecache'][] = 'LocalisationUpdate::onRecache'; // MW 1.16+
2738
2839 $dir = dirname( __FILE__ ) . '/';
2940 $wgExtensionMessagesFiles['LocalisationUpdate'] = $dir . 'LocalisationUpdate.i18n.php';
3041 $wgAutoloadClasses['LocalisationUpdate'] = $dir . 'LocalisationUpdate.class.php';
 42+$wgAutoloadClasses['LUDependency'] = $dir . 'LocalisationUpdate.class.php';
 43+$wgAutoloadClasses['QuickArrayReader'] = $dir . 'QuickArrayReader.php';
 44+
3145 $wgHooks['LoadExtensionSchemaUpdates'][] = 'LocalisationUpdate::schemaUpdates';
 46+
Index: branches/wmf-deployment/extensions/LocalisationUpdate/LocalisationUpdate.class.php
@@ -1,44 +1,44 @@
22 <?php
33 class LocalisationUpdate {
44 // DB Search funtion
5 - public static function FindUpdatedMessage( &$message, $lckey, $langcode, $isFullKey ) {
6 - // Define a cache
7 - static $cache = array();
8 - $db = wfGetDB ( DB_SLAVE );
 5+ public static function onRecache( $lc, $langcode, &$cache ) {
 6+ $dbr = wfGetDB ( DB_SLAVE );
97
10 - // If the key also contains the language code remove the language code from the key
11 - if ( $isFullKey ) {
12 - $lckey = preg_replace( "/\/" . $langcode . "/", "", $lckey );
13 - }
 8+ // Get the messages from the database
 9+ $res = $dbr->select( 'localisation',
 10+ array( 'lo_key', 'lo_value' ),
 11+ array( 'lo_language' => $langcode ),
 12+ __METHOD__ );
1413
15 - // If message is in the cache, don't get an update!
16 - if ( array_key_exists( $lckey . "/" . $langcode, $cache ) ) {
17 - $message = $cache[$lckey . "/" . $langcode];
18 - return true;
 14+ foreach ( $res as $row ) {
 15+ $cache['messages'][$row->lo_key] = $row->lo_value;
1916 }
20 -
21 - // Get the message from the database
22 - $conds = array( 'lo_key' => $lckey, 'lo_language' => $langcode );
23 - $result = $db->selectField( 'localisation', 'lo_value', $conds, __METHOD__ ); // Check if the database has any updated message
24 - if ( $result === false ) { // If no results found, exit here
25 - return true;
26 - }
27 -
28 - $message = $result;
29 - $cache[$lckey . "/" . $langcode] = $result; // Update the cache
 17+ $cache['deps'][] = new LUDependency;
3018 return true;
3119 }
3220
3321 // Called from the cronjob to fetch new messages from SVN
34 - public static function updateMessages( $verbose = false ) {
35 - // Need this later
36 - global $wgExtensionMessagesFiles;
37 -
 22+ public static function updateMessages( $verbose = false, $all = false ) {
3823 // Update all MW core messages
3924 $result = self::updateMediawikiMessages( $verbose );
4025
4126 // Update all Extension messages
42 - foreach ( $wgExtensionMessagesFiles as $extension => $locFile ) {
 27+ if( $all ) {
 28+ global $IP;
 29+ $extFiles = array();
 30+ $messageFiles = glob( "$IP/extensions/*/*.i18n.php" );
 31+ foreach( $messageFiles as $pathname ) {
 32+ $filename = basename( $pathname );
 33+ if( preg_match( '/^(.*)\.i18n\.php$/', $filename, $matches ) ) {
 34+ $group = $matches[1];
 35+ $extFiles[$group] = $pathname;
 36+ }
 37+ }
 38+ } else {
 39+ global $wgExtensionMessagesFiles;
 40+ $extFiles = $wgExtensionMessagesFiles;
 41+ }
 42+ foreach ( $extFiles as $extension => $locFile ) {
4343 $result += self::updateExtensionMessages( $locFile, $extension, $verbose );
4444 }
4545
@@ -51,18 +51,21 @@
5252 // Update Extension Messages
5353 public static function updateExtensionMessages( $file, $extension, $verbose ) {
5454 global $IP, $wgLocalisationUpdateSVNURL;
55 -
56 - // Find the right SVN folder
57 - $svnFolder = SpecialVersion::getSvnRevision( dirname( $file ), false, false, true );
58 -
 55+
 56+ $relfile = wfRelativePath( $file, "$IP/extensions" );
 57+ if( substr( $relfile, 0, 2 ) == ".." ) {
 58+ self::myLog( "Skipping $file; not in $IP/extensions\n" );
 59+ return false;
 60+ }
 61+
5962 // Create a full path
60 - $localfile = $IP . "/" . $file;
 63+ $localfile = "$IP/extensions/$relfile";
6164
6265 // Get the full SVN directory path
63 - $svndir = "http://" . $wgLocalisationUpdateSVNURL . $svnFolder;
 66+ $svnfile = "$wgLocalisationUpdateSVNURL/extensions/$relfile";
6467
6568 // Compare the 2 files
66 - $result = self::compareExtensionFiles( $extension, $svndir . "/" . basename( $file ), $file, $verbose, false, true );
 69+ $result = self::compareExtensionFiles( $extension, $svnfile, $file, $verbose, false, true );
6770 return $result;
6871 }
6972
@@ -77,22 +80,13 @@
7881 $dirname = "languages/messages";
7982
8083 // Get the full path to the directory
81 - $dirname = $IP . "/" . $dirname;
 84+ $localdir = $IP . "/" . $dirname;
8285
83 - // Get the SVN folder used for the checkout
84 - $svnFolder = SpecialVersion::getSvnRevision( $dirname, false, false, true );
85 -
86 - // Do not update if not from SVN
87 - if ( empty( $svnFolder ) ) {
88 - self::myLog( 'Cannot update localisation as the files are not retrieved from SVN' );
89 - return 0;
90 - }
91 -
9286 // Get the full SVN Path
93 - $svndir = "http://" . $wgLocalisationUpdateSVNURL . $svnFolder;
 87+ $svndir = "$wgLocalisationUpdateSVNURL/phase3/$dirname";
9488
9589 // Open the directory
96 - $dir = opendir( $dirname );
 90+ $dir = opendir( $localdir );
9791 while ( false !== ( $file = readdir( $dir ) ) ) {
9892 $m = array();
9993
@@ -106,7 +100,7 @@
107101 closedir( $dir );
108102
109103 // Find the changed English strings (as these messages won't be updated in ANY language)
110 - $changedEnglishStrings = self::compareFiles( $dirname . "/MessagesEn.php", $svndir . "/MessagesEn.php", $verbose );
 104+ $changedEnglishStrings = self::compareFiles( $localdir . "/MessagesEn.php", $svndir . "/MessagesEn.php", $verbose, true );
111105
112106 // Count the changes
113107 $changedCount = 0;
@@ -115,7 +109,7 @@
116110 sort($files);
117111 foreach ( $files as $file ) {
118112 $svnfile = $svndir . "/" . $file;
119 - $localfile = $dirname . "/" . $file;
 113+ $localfile = $localdir . "/" . $file;
120114
121115 // Compare the files
122116 $result = self::compareFiles( $svnfile, $localfile, $verbose, $changedEnglishStrings, false, true );
@@ -133,7 +127,7 @@
134128 public static function cleanupFile( $contents ) {
135129 // We don't need any PHP tags
136130 $contents = preg_replace( "/<\\?php/", "", $contents );
137 - $contents = preg_replace( "/\?>/", "", $contents );
 131+ $contents = preg_replace( "/\?" . ">/", "", $contents );
138132 $results = array();
139133 // And we only want the messages array
140134 preg_match( "/\\\$messages(.*\s)*?\);/", $contents, $results );
@@ -159,8 +153,11 @@
160154 // use cURL to get the SVN contents
161155 if ( preg_match( "/^http/", $basefile ) ) {
162156 while( !$basefilecontents && $attempts <= $wgLocalisationUpdateRetryAttempts) {
163 - if($attempts > 0)
164 - sleep(1);
 157+ if($attempts > 0) {
 158+ $delay = 1;
 159+ self::myLog( "Failed to download " . $basefile . "; retrying in ${delay}s..." );
 160+ sleep( $delay );
 161+ }
165162 $basefilecontents = Http::get( $basefile );
166163 $attempts++;
167164 }
@@ -199,8 +196,8 @@
200197 $basefilecontents = preg_replace( "/\\\$messages/", "\$base_messages", $basefilecontents );
201198
202199 $basehash = md5( $basefilecontents );
203 - // If this is the remote file check if the file has changed since our last update
204 - if ( preg_match( "/^http/", $basefile ) && !$alwaysGetResult ) {
 200+ // Check if the file has changed since our last update
 201+ if ( !$alwaysGetResult ) {
205202 if ( !self::checkHash( $basefile, $basehash ) ) {
206203 self::myLog( "Skipping {$langcode} since the remote file hasn't changed since our last update" );
207204 return array();
@@ -208,9 +205,7 @@
209206 }
210207
211208 // Get the array with messages
212 - $fileEditor = new ConfEditor( $basefilecontents );
213 - $vars = $fileEditor->getVars();
214 - $base_messages = $vars['base_messages'];
 209+ $base_messages = self::parsePHP( $basefilecontents, 'base_messages' );
215210
216211 $comparefilecontents = self::getFileContents( $comparefile );
217212 if ( $comparefilecontents === false || $comparefilecontents === "" ) return array(); // Failed
@@ -230,9 +225,7 @@
231226 }
232227 }
233228 // Get the array
234 - $fileEditor = new ConfEditor( $comparefilecontents );
235 - $vars = $fileEditor->getVars();
236 - $compare_messages = $vars['compare_messages'];
 229+ $compare_messages = self::parsePHP( $comparefilecontents, 'compare_messages' );
237230
238231 // if the localfile and the remote file are the same, skip them!
239232 if ( $basehash == $comparehash && !$alwaysGetResult ) {
@@ -252,27 +245,30 @@
253246 $changedStrings = array_diff_assoc( $base_messages, $compare_messages );
254247
255248 // If we want to save the differences
256 - if ( $saveResults === true && !empty($changedStrings) && is_array($changedStrings)) {
 249+ if ( $saveResults && !empty($changedStrings) && is_array($changedStrings)) {
257250 self::myLog( "--Checking languagecode {$langcode}--" );
258251 // The save them
259 - $updates = self::saveChanges( $changedStrings, $forbiddenKeys, $base_messages, $langcode, $verbose );
 252+ $updates = self::saveChanges( $changedStrings, $forbiddenKeys, $compare_messages, $base_messages, $langcode, $verbose );
260253 self::myLog( "{$updates} messages updated for {$langcode}." );
261 - } elseif($saveResults === true) {
 254+ } elseif ( $saveResults ) {
262255 self::myLog( "--{$langcode} hasn't changed--" );
263256 }
264257
265258
266 - if ( preg_match( "/^http/", $basefile )) {
267 - self::saveHash( $basefile, $basehash );
268 - }
 259+ self::saveHash( $basefile, $basehash );
269260
270 - if ( preg_match( "/^http/", $comparefile )) {
271 - self::saveHash( $comparefile, $comparehash );
272 - }
 261+ self::saveHash( $comparefile, $comparehash );
273262
274263 return $changedStrings;
275264 }
276265
 266+ /**
 267+ * Checks whether a messages file has a certain hash
 268+ * TODO: Swap return values, this is insane
 269+ * @param $file string Filename
 270+ * @param $hash string Hash
 271+ * @return bool True if $file does NOT have hash $hash, false if it does
 272+ */
277273 public static function checkHash( $file, $hash ) {
278274 $db = wfGetDB( DB_MASTER );
279275
@@ -287,13 +283,18 @@
288284
289285 public static function saveHash ($file, $hash) {
290286 $db = wfGetDB ( DB_MASTER );
291 - $hashConds = array( 'lfh_file' => $file, 'lfh_hash' => $hash );
292 - $conds = array( 'lfh_file' => $file );
293 - $db->delete( 'localisation_file_hash', $conds , __METHOD__ );
294 - $db->insert( 'localisation_file_hash', $hashConds, __METHOD__ );
 287+ // Double query sucks but we wanna make sure we don't update
 288+ // the timestamp when the hash hasn't changed
 289+ if ( self::checkHash( $file, $hash ) )
 290+ $db->replace( 'localisation_file_hash', array( 'lfh_file' ), array(
 291+ 'lfh_file' => $file,
 292+ 'lfh_hash' => $hash,
 293+ 'lfh_timestamp' => $db->timestamp( wfTimestamp() )
 294+ ), __METHOD__
 295+ );
295296 }
296297
297 - public static function saveChanges( $changedStrings, $forbiddenKeys, $base_messages, $langcode, $verbose ) {
 298+ public static function saveChanges( $changedStrings, $forbiddenKeys, $compare_messages, $base_messages, $langcode, $verbose ) {
298299 // Gonna write to the DB again
299300 $db = wfGetDB ( DB_MASTER );
300301
@@ -305,8 +306,8 @@
306307 }
307308
308309 foreach ( $changedStrings as $key => $value ) {
309 - // If this message wasn't changed in English
310 - if ( !array_key_exists( $key , $forbiddenKeys ) ) {
 310+ // If this message wasn't changed in English, and is in fact set
 311+ if ( !array_key_exists( $key , $forbiddenKeys ) && isset( $compare_messages[$key] ) ) {
311312 // See if we can update the database
312313
313314 $values = array(
@@ -320,7 +321,7 @@
321322
322323 // Output extra logmessages when needed
323324 if ( $verbose ) {
324 - self::myLog( "Updated message {$key} from {$compare_messages[$key]} to {$base_messages[$key]}" );
 325+ self::myLog( "Updated message {$key} from '{$compare_messages[$key]}' to '{$base_messages[$key]}'" );
325326 }
326327
327328 // Update the counter
@@ -333,7 +334,7 @@
334335 public static function cleanupExtensionFile( $contents ) {
335336 // We don't want PHP tags
336337 $contents = preg_replace( "/<\?php/", "", $contents );
337 - $contents = preg_replace( "/\?>/", "", $contents );
 338+ $contents = preg_replace( "/\?" . ">/", "", $contents );
338339 $results = array();
339340 // And we only want message arrays
340341 preg_match_all( "/\\\$messages(.*\s)*?\);/", $contents, $results );
@@ -377,10 +378,8 @@
378379 }
379380
380381 // And get the real contents
381 - $fileEditor = new ConfEditor( $basefilecontents );
382 - $vars = $fileEditor->getVars();
383 - $base_messages = $vars['base_messages'];
384 -
 382+ $base_messages = self::parsePHP( $basefilecontents, 'base_messages' );
 383+
385384 $comparefilecontents = self::getFileContents( $comparefile );
386385 if ( $comparefilecontents === false || $comparefilecontents === "" ) return 0; // Failed
387386
@@ -398,9 +397,7 @@
399398 }
400399 }
401400 // Get the real array
402 - $fileEditor = new ConfEditor( $comparefilecontents );
403 - $vars = $fileEditor->getVars();
404 - $compare_messages = $vars['compare_messages'];
 401+ $compare_messages = self::parsePHP( $comparefilecontents, 'compare_messages' );
405402
406403 // If both files are the same, they can be skipped
407404 if ( $basehash == $comparehash && !$alwaysGetResult ) {
@@ -456,7 +453,7 @@
457454 if ( $saveResults === true && !empty($changedStrings) && is_array($changedStrings)) {
458455 self::myLog( "--Checking languagecode {$language}--" );
459456 // The save them
460 - $updates = self::saveChanges( $changedStrings, $forbiddenKeys, $messages, $language, $verbose );
 457+ $updates = self::saveChanges( $changedStrings, $forbiddenKeys, $compare_messages, $messages, $language, $verbose );
461458 self::myLog( "{$updates} messages updated for {$language}." );
462459 } elseif($saveResults === true) {
463460 self::myLog( "--{$language} hasn't changed--" );
@@ -466,21 +463,18 @@
467464 // And log some stuff
468465 self::myLog( "Updated " . $updates . " messages for the '{$extension}' extension" );
469466
470 - if ( preg_match( "/^http/", $basefile )) {
471 - self::saveHash( $basefile, $basehash );
472 - }
 467+ self::saveHash( $basefile, $basehash );
473468
474 - if ( preg_match( "/^http/", $comparefile )) {
475 - self::saveHash( $comparefile, $comparehash );
476 - }
 469+ self::saveHash( $comparefile, $comparehash );
477470
478471 return $updates;
479472 }
480473
481474 public static function schemaUpdates() {
482 - global $wgExtNewTables;
 475+ global $wgExtNewTables, $wgExtNewFields;
483476 $dir = dirname( __FILE__ );
484477 $wgExtNewTables[] = array( 'localisation', "$dir/schema.sql" );
 478+ $wgExtNewFields[] = array( 'localisation_file_hash', 'lfh_timestamp', "$dir/patch-lfh_timestamp.sql" );
485479 return true;
486480 }
487481
@@ -491,5 +485,39 @@
492486 print( $log . "\n" );
493487 }
494488 }
 489+
 490+ public static function parsePHP( $php, $varname ) {
 491+ try {
 492+ $reader = new QuickArrayReader("<?php $php");
 493+ return $reader->getVar( $varname );
 494+ } catch( Exception $e ) {
 495+ self::myLog( "Failed to read file: " . $e );
 496+ return false;
 497+ }
 498+ }
 499+}
495500
496 -}
\ No newline at end of file
 501+class LUDependency extends CacheDependency {
 502+ var $timestamp;
 503+
 504+ function isExpired() {
 505+ $timestamp = $this->getTimestamp();
 506+ return $timestamp !== $this->timestamp;
 507+ }
 508+
 509+ function loadDependencyValues() {
 510+ $this->timestamp = $this->getTimestamp();
 511+ }
 512+
 513+ function getTimestamp() {
 514+ $dbr = wfGetDB( DB_SLAVE );
 515+ return $dbr->selectField(
 516+ 'localisation_file_hash', 'MAX(lfh_timestamp)', '',
 517+ __METHOD__ );
 518+ }
 519+
 520+ function __sleep() {
 521+ $this->loadDependencyValues();
 522+ return array( 'timestamp' );
 523+ }
 524+}
Index: branches/wmf-deployment/extensions/LocalisationUpdate/schema.sql
@@ -9,10 +9,13 @@
1010
1111 CREATE TABLE /*$wgDBprefix*/localisation_file_hash (
1212 lfh_file varchar(250) NOT NULL,
13 - lfh_hash varchar(50) NOT NULL
 13+ lfh_hash varchar(50) NOT NULL,
 14+ lfh_timestamp varchar(14) NOT NULL
1415 ) /*$wgDBTableOptions*/;
1516
1617 CREATE UNIQUE INDEX /*i*/lfh_file ON
1718 /*$wgDBprefix*/localisation_file_hash (lfh_file);
1819 CREATE INDEX /*i*/lfh_file_hash ON
19 - /*$wgDBprefix*/localisation_file_hash (lfh_file, lfh_hash);
\ No newline at end of file
 20+ /*$wgDBprefix*/localisation_file_hash (lfh_file, lfh_hash);
 21+CREATE INDEX /*i*/lfh_timestamp ON
 22+ /*$wgDBprefix*/localisation_file_hash (lfh_timestamp);
\ No newline at end of file
Property changes on: branches/wmf-deployment/extensions/LocalisationUpdate
___________________________________________________________________
Name: svn:mergeinfo
2023 + /branches/REL1_15/phase3/extensions/LocalisationUpdate:51646
/trunk/extensions/LocalisationUpdate:52089-55252
/trunk/phase3/LocalisationUpdate:52859,53272
/trunk/phase3/extensions/LocalisationUpdate:52290,52402,52404,52718,52737,52759,52776,52791,52800,52808,52812-52813,52815-52819,52822,52846,52850,52852-52853,52855-52857,52859,52924,52986,53128-53129,53190,53197,53199,53203-53204,53210-53211,53247,53249,53252,53267,53270,53293,53305,53344,53369,53427,53502-53504,53506,53777,54384,54494,54592,54599-54602,54604,54613,54764,54793,54806,55178

Status & tagging log