66 $this->tmpParentDir =
"{$this->libDir}/.foreign/tmp";
68 $cacheHome =
getenv(
'XDG_CACHE_HOME' ) ? realpath(
getenv(
'XDG_CACHE_HOME' ) ) :
false;
69 $this->cacheDir = $cacheHome ?
"$cacheHome/mw-foreign" :
"{$this->libDir}/.foreign/cache";
77 $actions = [
'update',
'verify',
'make-sri' ];
79 $this->
error(
"Invalid action.\n\nMust be one of " . implode(
', ', $actions ) .
'.' );
85 if ( $module ===
'all' ) {
88 $modules = [ $module => $this->registry[ $module ] ];
90 $this->
error(
"Unknown module name.\n\nMust be one of:\n" .
97 foreach (
$modules as $moduleName => $info ) {
98 $this->
verbose(
"\n### {$moduleName}\n\n" );
99 $destDir =
"{$this->libDir}/$moduleName";
101 if ( $this->action ===
'update' ) {
102 $this->
output(
"... updating '{$moduleName}'\n" );
103 $this->
verbose(
"... emptying directory for $moduleName\n" );
105 }
elseif ( $this->action ===
'verify' ) {
106 $this->
output(
"... verifying '{$moduleName}'\n" );
108 $this->
output(
"... checking '{$moduleName}'\n" );
111 $this->
verbose(
"... preparing {$this->tmpParentDir}\n" );
114 throw new Exception(
"Unable to create {$this->tmpParentDir}" );
117 if ( !
isset( $info[
'type'] ) ) {
118 throw new Exception(
"Module '$moduleName' must have a 'type' key." );
120 switch ( $info[
'type'] ) {
131 throw new Exception(
"Unknown type '{$info['type']}' for '$moduleName'" );
135 $this->
output(
"\nDone!\n" );
137 if ( $this->hasErrors ) {
148 return rtrim( $key,
'_' );
161 private function fetch( $src, $integrity ) {
162 $key = $this->
cacheKey( $src, $integrity );
168 $req = MWHttpRequest::factory( $src, [
'method' =>
'GET',
'followRedirects' =>
false ] );
169 if ( !
$req->execute()->isOK() ) {
170 throw new Exception(
"Failed to download resource at {$src}" );
172 if (
$req->getStatus() !== 200 ) {
173 throw new Exception(
"Unexpected HTTP {$req->getStatus()} response from {$src}" );
176 $algo = $integrity ===
null ? $this->
defaultAlgo : explode(
'-', $integrity )[0];
178 if ( $integrity === $actualIntegrity ) {
179 $this->
verbose(
"... passed integrity check for {$src}\n" );
181 }
elseif ( $this->action ===
'make-sri' ) {
182 $this->
output(
"Integrity for {$src}\n\tintegrity: ${actualIntegrity}\n" );
184 throw new Exception(
"Integrity check failed for {$src}\n" .
185 "\tExpected: {$integrity}\n" .
186 "\tActual: {$actualIntegrity}"
193 if ( !
isset( $info[
'src'] ) ) {
194 throw new Exception(
"Module '$moduleName' must have a 'src' key." );
196 $data = $this->
fetch( $info[
'src'], $info[
'integrity'] ??
null );
197 $dest = $info[
'dest'] ??
basename( $info[
'src'] );
198 $path =
"$destDir/$dest";
200 throw new Exception(
"File for '$moduleName' is different." );
202 if ( $this->action ===
'update' ) {
209 if ( !
isset( $info[
'files'] ) ) {
210 throw new Exception(
"Module '$moduleName' must have a 'files' key." );
212 foreach ( $info[
'files'] as $dest => $file ) {
213 if ( !
isset( $file[
'src'] ) ) {
214 throw new Exception(
"Module '$moduleName' file '$dest' must have a 'src' key." );
216 $data = $this->
fetch( $file[
'src'], $file[
'integrity'] ??
null );
217 $path =
"$destDir/$dest";
219 throw new Exception(
"File '$dest' for '$moduleName' is different." );
220 }
elseif ( $this->action ===
'update' ) {
228 $info += [
'src' =>
null,
'integrity' =>
null,
'dest' =>
null ];
229 if ( $info[
'src'] ===
null ) {
230 throw new Exception(
"Module '$moduleName' must have a 'src' key." );
233 $data = $this->
fetch( $info[
'src'], $info[
'integrity' ] );
234 $tmpFile =
"{$this->tmpParentDir}/$moduleName.tar";
235 $this->
verbose(
"... writing '$moduleName' src to $tmpFile\n" );
238 $tmpDir =
"{$this->tmpParentDir}/$moduleName";
239 $p->extractTo( $tmpDir );
242 if ( $info[
'dest'] ===
null ) {
248 foreach ( $info[
'dest'] as $fromSubPath => $toSubPath ) {
250 $fromPaths =
glob(
"{$tmpDir}/{$fromSubPath}", GLOB_BRACE );
252 throw new Exception(
"Path '$fromSubPath' of '$moduleName' not found." );
254 foreach ( $fromPaths as $fromPath ) {
256 ?
"$destDir/" .
basename( $fromPath )
257 :
"$destDir/$toSubPath/" .
basename( $fromPath );
261 foreach ( $toCopy as $from => $to ) {
262 if ( $this->action ===
'verify' ) {
263 $this->
verbose(
"... verifying $to\n" );
267 RecursiveDirectoryIterator::SKIP_DOTS
270 foreach ( $rii as $file ) {
271 $remote = $file->getPathname();
272 $local =
strtr( $remote, [ $from => $to ] );
274 $this->
error(
"File '$local' is different." );
275 $this->hasErrors =
true;
279 $this->
error(
"File '$to' is different." );
280 $this->hasErrors =
true;
282 }
elseif ( $this->action ===
'update' ) {
283 $this->
verbose(
"... moving $from to $to\n" );
285 if ( !rename( $from, $to ) ) {
286 throw new Exception(
"Could not move $from to $to." );
309 foreach ( $this->registry as $info ) {
310 if ( $info[
'type'] ===
'file' || $info[
'type'] ===
'tar' ) {
311 $knownKeys[] = $this->
cacheKey( $info[
'src'], $info[
'integrity'] );
312 }
elseif ( $info[
'type'] ===
'multi-file' ) {
313 foreach ( $info[
'files'] as $file ) {
314 $knownKeys[] = $this->
cacheKey( $file[
'src'], $file[
'integrity'] );
318 foreach (
glob(
"{$this->cacheDir}/*" ) as $cacheFile ) {
339 foreach (
$lines as $i => $text ) {
341 $trimmed =
ltrim( $text,
' ' );
342 if ( $trimmed ===
'' || $trimmed[0] ===
'#' ) {
346 if ( $indent % 2 !== 0 ) {
347 throw new Exception( __METHOD__ .
": Odd indentation on line $line." );
349 $depth = $indent === 0 ? 0 : ( $indent / 2 );
350 if ( $depth < $prev ) {
355 throw new Exception( __METHOD__ .
": Too much indentation on line $line." );
357 if (
strpos( $trimmed,
':' ) ===
false ) {
358 throw new Exception( __METHOD__ .
": Missing colon on line $line." );
360 $dest =& $stack[ $depth ];
361 if ( $dest ===
null ) {
365 list( $key, $val ) = explode(
':', $trimmed, 2 );
366 $val =
ltrim( $val,
' ' );
369 $dest[ $key ] =
$val;
374 $dest[ $key ] = &
$val;
377 unset( $dest, $val );
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
wfRecursiveRemoveDir( $dir)
Remove a directory and all its content.
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
Manage foreign resources registered with ResourceLoader.
cacheKey( $src, $integrity)
parseBasicYaml( $input)
Basic YAML parser.
handleTypeTar( $moduleName, $destDir, array $info)
handleTypeMultiFile( $moduleName, $destDir, array $info)
__construct( $registryFile, $libDir, callable $infoPrinter=null, callable $errorPrinter=null, callable $verbosePrinter=null)
handleTypeFile( $moduleName, $destDir, array $info)
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
this hook is for auditing only $req
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults error
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
if(is_array($mode)) switch( $mode) $input