if ( !is_array( $flags ) ) {
$flags = array( $flags );
}
- $this->basepath = realpath( $basepath );
+ $this->basepath = self::normalizePathSeparator( realpath( $basepath ) );
$this->collector = new ClassCollector;
if ( in_array( 'local', $flags ) ) {
$this->variableName = 'wgAutoloadLocalClasses';
*
* @param string $fqcn FQCN to force the location of
* @param string $inputPath Full path to the file containing the class
+ * @throws Exception
*/
public function forceClassPath( $fqcn, $inputPath ) {
- $path = realpath( $inputPath );
+ $path = self::normalizePathSeparator( realpath( $inputPath ) );
if ( !$path ) {
throw new \Exception( "Invalid path: $inputPath" );
}
}
/**
- * @var string $inputPath Path to a php file to find classes within
+ * @param string $inputPath Path to a php file to find classes within
+ * @throws Exception
*/
public function readFile( $inputPath ) {
+ // NOTE: do NOT expand $inputPath using realpath(). It is perfectly
+ // reasonable for LocalSettings.php and similiar files to be symlinks
+ // to files that are outside of $this->basepath.
+ $inputPath = self::normalizePathSeparator( $inputPath );
$len = strlen( $this->basepath );
if ( substr( $inputPath, 0, $len ) !== $this->basepath ) {
throw new \Exception( "Path is not within basepath: $inputPath" );
* for php files with either .php or .inc extensions
*/
public function readDir( $dir ) {
- $it = new RecursiveDirectoryIterator( realpath( $dir ) );
+ $it = new RecursiveDirectoryIterator(
+ self::normalizePathSeparator( realpath( $dir ) ) );
$it = new RecursiveIteratorIterator( $it );
foreach ( $it as $path => $file ) {
* developers towards the appropriate way to update the autoload.
*/
public function generateAutoload( $commandName = 'AutoloadGenerator' ) {
- $content = array();
- // We need to generate a line each rather than exporting the
- // full array so __DIR__ can be prepended to all the paths
- $format = "%s => __DIR__ . %s,";
- foreach ( $this->classes as $path => $contained ) {
- $exportedPath = var_export( $path, true );
- foreach ( $contained as $fqcn ) {
+ // We need to check whether an extenson.json exists or not, and
+ // incase it doesn't, update the autoload.php file.
+
+ if ( file_exists( $this->basepath . '/extension.json' ) ) {
+ require_once __DIR__ . '/../../includes/json/FormatJson.php';
+ $key = 'AutoloadClasses';
+ $json = FormatJson::decode( file_get_contents( $this->basepath
+ . '/extension.json' ), true );
+ unset( $json[$key] );
+ // Inverting the key-value pairs so that they become of the
+ // format class-name : path when they get converted into json.
+ foreach ( $this->classes as $path => $contained ) {
+ foreach ( $contained as $fqcn ) {
+
+ // Using substr to remove the leading '/'
+ $json[$key][$fqcn] = substr( $path, 1 );
+ }
+ }
+ foreach ( $this->overrides as $path => $fqcn ) {
+
+ // Using substr to remove the leading '/'
+ $json[$key][$fqcn] = substr( $path, 1 );
+ }
+
+ // Sorting the list of autoload classes.
+ ksort( $json[$key] );
+
+ // Update extension.json, using constants for the required
+ // formatting.
+ file_put_contents( $this->basepath . '/extension.json',
+ FormatJson::encode( $json, true ) . "\n" );
+ } else {
+ $content = array();
+
+ // We need to generate a line each rather than exporting the
+ // full array so __DIR__ can be prepended to all the paths
+ $format = "%s => __DIR__ . %s,";
+ foreach ( $this->classes as $path => $contained ) {
+ $exportedPath = var_export( $path, true );
+ foreach ( $contained as $fqcn ) {
+ $content[$fqcn] = sprintf(
+ $format,
+ var_export( $fqcn, true ),
+ $exportedPath
+ );
+ }
+ }
+
+ foreach ( $this->overrides as $fqcn => $path ) {
$content[$fqcn] = sprintf(
$format,
var_export( $fqcn, true ),
- $exportedPath
+ var_export( $path, true )
);
}
- }
-
- foreach ( $this->overrides as $fqcn => $path ) {
- $content[$fqcn] = sprintf(
- $format,
- var_export( $fqcn, true ),
- var_export( $path, true )
- );
- }
- // sort for stable output
- ksort( $content );
+ // sort for stable output
+ ksort( $content );
- // extensions using this generator are appending to the existing
- // autoload.
- if ( $this->variableName === 'wgAutoloadClasses' ) {
- $op = '+=';
- } else {
- $op = '=';
- }
+ // extensions using this generator are appending to the existing
+ // autoload.
+ if ( $this->variableName === 'wgAutoloadClasses' ) {
+ $op = '+=';
+ } else {
+ $op = '=';
+ }
- $output = implode( "\n\t", $content );
- file_put_contents(
- $this->basepath . '/autoload.php',
- <<<EOD
+ $output = implode( "\n\t", $content );
+ file_put_contents(
+ $this->basepath . '/autoload.php',
+ <<<EOD
<?php
// This file is generated by $commandName, do not adjust manually
-
+// @codingStandardsIgnoreFile
global \${$this->variableName};
\${$this->variableName} {$op} array(
);
EOD
- );
+ );
+ }
+ }
+ /**
+ * Ensure that Unix-style path separators ("/") are used in the path.
+ *
+ * @param string $path
+ * @return string
+ */
+ protected static function normalizePathSeparator( $path ) {
+ return str_replace( '\\', '/', $path );
}
}
if ( is_string( $token ) ) {
return;
}
- switch( $token[0] ) {
+ switch ( $token[0] ) {
case T_NAMESPACE:
case T_CLASS:
case T_INTERFACE:
* @param array
*/
protected function tryEndExpect( $token ) {
- switch( $this->startToken[0] ) {
+ switch ( $this->startToken[0] ) {
case T_NAMESPACE:
if ( $token === ';' || $token === '{' ) {
$this->namespace = $this->implodeTokens() . '\\';