Personal tools




Extension:Packages.php

From OrganicDesign Wiki

Jump to: navigation, search
<?php
# Extension:Workflow
# - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html)
# - Author: [http://www.organicdesign.co.nz/nad User:Nad]
# - Started: 2007-11-04
 
define('PACKAGES_VERSION','0.0.6, 2007-11-13');
$wgExtensionCredits['parserhook'][] = $wgExtensionCredits['specialpage'][] = array(
	'name'        => 'Packages',
	'author'      => '[http://www.organicdesign.co.nz/nad User:Nad]',
	'description' => 'Create packages of templates and other articles from remote wiki\'s. The resulting packages are PHP files which can be added or removed like a normal extension without affecting the database.',
	'url'         => 'http://www.mediawiki.org/wiki/Extension:Packages',
	'version'     => PACKAGES_VERSION
	);
 
$wgPackageList = array();
$wgPackagesDir = dirname(__FILE__);
 
# Special page for managing list of packages
if (defined('MEDIAWIKI')) {
	require_once "$IP/includes/SpecialPage.php";
	class SpecialPackages extends SpecialPage {
 
		function SpecialPackages() {
			SpecialPage::SpecialPage('Packages','',true,false,false,false);
			}
 
		# Render list
		function execute($param) {
			global $wgParser,$wgOut,$wgScriptPath,$wgPackagesDir;
			$wgParser->disableCache();
			$this->setHeaders();
			$wgOut->addWikiText("== Packages available ==\nThese packages of templates are defined in [[MediaWiki:Packages]],
				and can be built by running this extension from the command line.\n\n",true);
			$wgOut->addWikiText("== Installed packages ==\nThe following packages have been included from LocalSettings.php\n\n",true);
			$wgOut->addWikiText("== Download packages ==\nThe following packages have been built and are available for download.\n\n",true);
			foreach (glob("$wgPackagesDir/pkg_*") as $package) $wgOut->addWikiText("*[http://www.organicdesign.co.nz/$wgScriptPath/extensions/$package $package]\n");
			}
		}
	}
 
# Not called from index.php, include commandLine.inc or die if called from web directly
else {
	if (isset($_SERVER) && array_key_exists('REQUEST_METHOD',$_SERVER)) die("Not an entry point");
	$IP = ereg_replace('.extensions.?','',$argv[1]);
	$cli = "$IP/maintenance/commandLine.inc";
	if (!file_exists($cli)) die("Couldn't find \"$cli\"! Syntax: php Packages.php path/to/extensions\n");
	include($cli);
	}
 
# Define main Packages class which expands the included magic words
class Packages {
 
	# Constructor
	function Packages() {
		global $wgHooks,$wgExtensionFunctions,$wgPackageList,$wgCommandLineMode;
 
		if ($wgCommandLineMode) $this->build();
 
		# Reserve the magic word for use as a parser-function
		$wgHooks['LanguageGetMagic'][] = array($this,'languageGetMagic');
 
		# Add the extension's setup function to the list to be called after the environment is up and running
		$wgExtensionFunctions[] = array($this,'setup');
		}
 
	# Setup
	function setup() {
		global $wgParser,$wgLanguageCode,$wgMessageCache,$wgContLang,$wgPackageList;
 
		# Add the messages used (todo: move into i18n)
		if ($wgLanguageCode == 'en') {
			$wgMessageCache->addMessages(array(
				));
			}
 
		# Add the specialpage to the environment
		SpecialPage::addPage(new SpecialPackages());
 
		# Add a parser-function hook for each package which returns the package content with variables replaced
		foreach (array_keys($wgPackageList) as $package) {
			$wgParser->setFunctionHook($package,create_function('','
				global $wgPackageList;
				$args   = func_get_args();
				$parser = array_shift($args);
				$text   = $wgPackageList["'.$package.'"][$args[0]];
				# todo: if package item doesn\'t exist, try falling back to article
				return $parser->replaceVariables($text,$args,true);
				'),SFH_NO_HASH);
			}
 
		}
 
	# Needed in some versions to prevent Special:Version from breaking
	function __toString() { return 'Packages'; }
 
	# Reserve a magic word for each package
	function languageGetMagic(&$magicWords,$langCode = 0) {
		global $wgPackageList;
		foreach (array_keys($wgPackageList) as $package) $magicWords[$package] = array(0,$package);
		return true;
		}
 
	# Used to find dependencies within template content	
	function examineBraces(&$content) {
		$braces = array();
		$depths = array();
		$depth = 1;
		$index = 0;
		while (preg_match('/\\{\\{\\s*([#a-z0-9_]*)|\\}\\}/is',$content,$match,PREG_OFFSET_CAPTURE,$index)) {
			$index = $match[0][1]+2;
			if ($match[0][0] == '}}') {
				$brace =& $braces[$depths[$depth-1]];
				$brace['LENGTH'] = $match[0][1]-$brace['OFFSET']+2;
				$brace['DEPTH']  = $depth--;
				}
			else {
				$depths[$depth++] = count($braces);
				$braces[] = array(
					'NAME'   => $match[1][0],
					'OFFSET' => $match[0][1]
					);
				}
			}
		return $braces;
		}
 
	# Build the packages defined in the MediaWiki:Packages article
	function build() {
		global $wgEnableScaryTranscluding,$wgPackagesDir;
		$wgEnableScaryTranscluding = true;
		$parser = new Parser;
 
		# Read in the package definitions from MediaWiki:Packages
		$packages = 'Packages';
		$title = Title::newFromText($packages,NS_MEDIAWIKI);
		if (!is_object($title) || !$title->exists()) die("No MediaWiki:$packages article!\n");
		$article = new Article($title);
		$text = $article->getContent();
 
		# Extract the package sections in the definitions article and loop through them building a file for each
		# NOTE: there is an existing function to do with this that we should checkout and/or test called extractSections() in Parser.php
		#       Extension:Selenium is using preg_match_all |^={2,}\s*(.+?)\s*={2,}(.+?</selenium>)|ms
		preg_match_all('/=+\\s*(.+?)\\s*=+([^=]+)/',$text,$m1);
		while (count($m1[1])) {
 
			# Initialise current package data
			$package = array_shift($m1[1]);
			$content = "<?\n# $package built by Extension:Packages.php\n";
 
			# Extract the articles listed for this package and loop through them (as a reducing stack)
			preg_match_all('/\\[{2}(.+?)(\\|(.+?))?\\]{2}/',array_shift($m1[2]),$m2);
			$links = array();
			while (count($m2[1])) {
 
				# Get the content of the current article (local or interwiki)
				$anchor   = array_shift($m2[3]);
				$title    = array_shift($m2[1]);
				if ($anchor == '') $anchor = $title;
				$title    = Title::newFromText($title);
				$article  = new Article($title);
				$text     = $title->isLocal() ? $article->getContent() : $parser->interwikiTransclude($title,'raw');
 
				# Push any valid dependency templates found in this article's content onto the end of the currently reducing stack
				if (0) foreach ($this->examineBraces($text) as $template) {
					$anchor = 'foo'; # todo: rename the dependency according to the package and namespace etc
					if ($anchor) {
						$m2[1][] = $template;
						$m2[3][] = $anchor;
						# todo: must change references in content to transformed name
						}
					}
 
				# Append content to the current package data
				$text     = str_replace("'","\\'",$text);
				$content .= "\$wgPackageList['$package']['$anchor']='$text';\n";
				}
 
			# Write the built package data to file in same dir as script
			file_put_contents("$wgPackagesDir/pkg_$package.php",$content);
			print "pkg_$package.php built\n";
			}
		}
	}
 
$wgPackages = new Packages();

The GNU Project Debian Linux Ubuntu Linux Wikipedia Affiliate Button MediaWiki