jenkins-bot has submitted this change and it was merged. Change subject: Maintenance script for exporting site definitions ......................................................................
Maintenance script for exporting site definitions Bug: T87178 Change-Id: I40fd6aaa8f47bad3d595d5c190036bf04d13c12a --- M autoload.php A includes/site/SiteExporter.php A maintenance/exportSites.php A tests/phpunit/includes/site/SiteExporterTest.php 4 files changed, 317 insertions(+), 0 deletions(-) Approvals: Hoo man: Looks good to me, approved jenkins-bot: Verified diff --git a/autoload.php b/autoload.php index 552566a..4b28966 100644 --- a/autoload.php +++ b/autoload.php @@ -1046,6 +1046,7 @@ 'Site' => __DIR__ . '/includes/site/Site.php', 'SiteArray' => __DIR__ . '/includes/site/SiteList.php', 'SiteConfiguration' => __DIR__ . '/includes/SiteConfiguration.php', + 'SiteExporter' => __DIR__ . '/includes/site/SiteExporter.php', 'SiteImporter' => __DIR__ . '/includes/site/SiteImporter.php', 'SiteList' => __DIR__ . '/includes/site/SiteList.php', 'SiteListFileCache' => __DIR__ . '/includes/site/SiteListFileCache.php', diff --git a/includes/site/SiteExporter.php b/includes/site/SiteExporter.php new file mode 100644 index 0000000..62f6ca3 --- /dev/null +++ b/includes/site/SiteExporter.php @@ -0,0 +1,114 @@ +<?php + +/** + * Utility for exporting site entries to XML. + * For the output file format, see docs/sitelist.txt and docs/sitelist-1.0.xsd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @since 1.25 + * + * @file + * @ingroup Site + * + * @license GNU GPL v2+ + * @author Daniel Kinzler + */ +class SiteExporter { + + /** + * @var resource + */ + private $sink; + + /** + * @param resource $sink A file handle open for writing + */ + public function __construct( $sink ) { + if ( !is_resource( $sink ) || get_resource_type( $sink ) !== 'stream' ) { + throw new InvalidArgumentException( '$sink must be a file handle' ); + } + + $this->sink = $sink; + } + + /** + * Writes a <site> tag for each Site object in $sites, and encloses the entire list + * between <sites> tags. + * + * @param Site[]|SiteList $sites + */ + public function exportSites( $sites ) { + $attributes = array( + 'version' => '1.0', + 'xmlns' => 'http://www.mediawiki.org/xml/sitelist-1.0/', + ); + + fwrite( $this->sink, XML::openElement( 'sites', $attributes ) . "\n" ); + + foreach ( $sites as $site ) { + $this->exportSite( $site ); + } + + fwrite( $this->sink, XML::closeElement( 'sites' ) . "\n" ); + fflush( $this->sink ); + } + + /** + * Writes a <site> tag representing the given Site object. + * + * @param Site $site + */ + private function exportSite( Site $site ) { + if ( $site->getType() !== Site::TYPE_UNKNOWN ) { + $siteAttr = array( 'type' => $site->getType() ); + } else { + $siteAttr = null; + } + + fwrite( $this->sink, "\t" . XML::openElement( 'site', $siteAttr ) . "\n" ); + + fwrite( $this->sink, "\t\t" . XML::element( 'globalid', null, $site->getGlobalId() ) . "\n" ); + + if ( $site->getGroup() !== Site::GROUP_NONE ) { + fwrite( $this->sink, "\t\t" . XML::element( 'group', null, $site->getGroup() ) . "\n" ); + } + + if ( $site->getSource() !== Site::SOURCE_LOCAL ) { + fwrite( $this->sink, "\t\t" . XML::element( 'source', null, $site->getSource() ) . "\n" ); + } + + if ( $site->shouldForward() ) { + fwrite( $this->sink, "\t\t" . XML::element( 'forward', null, '' ) . "\n" ); + } + + foreach ( $site->getAllPaths() as $type => $path ) { + fwrite( $this->sink, "\t\t" . XML::element( 'path', array( 'type' => $type ), $path ) . "\n" ); + } + + foreach ( $site->getLocalIds() as $type => $ids ) { + foreach ( $ids as $id ) { + fwrite( $this->sink, "\t\t" . XML::element( 'localid', array( 'type' => $type ), $id ) . "\n" ); + } + } + + //@todo: export <data> + //@todo: export <config> + + fwrite( $this->sink, "\t" . XML::closeElement( 'site' ) . "\n" ); + } + +} diff --git a/maintenance/exportSites.php b/maintenance/exportSites.php new file mode 100644 index 0000000..1c71dc0 --- /dev/null +++ b/maintenance/exportSites.php @@ -0,0 +1,54 @@ +<?php + +$basePath = getenv( 'MW_INSTALL_PATH' ) !== false ? getenv( 'MW_INSTALL_PATH' ) : __DIR__ . '/..'; + +require_once $basePath . '/maintenance/Maintenance.php'; + +/** + * Maintenance script for exporting site definitions from XML into the sites table. + * + * @since 1.25 + * + * @licence GNU GPL v2+ + * @author Daniel Kinzler + */ +class ExportSites extends Maintenance { + + public function __construct() { + $this->mDescription = 'Exports site definitions the sites table to XML file'; + + $this->addArg( 'file', 'A file to write the XML to (see docs/sitelist.txt). Use "php://stdout" to write to stdout.', true ); + + parent::__construct(); + } + + /** + * Do the actual work. All child classes will need to implement this + */ + public function execute() { + $file = $this->getArg( 0 ); + + if ( $file === 'php://output' || $file === 'php://stdout' ) { + $this->mQuiet = true; + } + + $handle = fopen( $file, 'w' ); + + if ( !$handle ) { + $this->error( "Failed to open $file for writing.\n", 1 ); + } + + $exporter = new SiteExporter( $handle ); + + $sites = SiteSQLStore::newInstance()->getSites( 'recache' ); + $exporter->exportSites( $sites ); + + fclose( $handle ); + + $this->output( "Exported sites to " . realpath( $file ) . ".\n" ); + } + +} + +$maintClass = 'ExportSites'; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/tests/phpunit/includes/site/SiteExporterTest.php b/tests/phpunit/includes/site/SiteExporterTest.php new file mode 100644 index 0000000..a3ef4be --- /dev/null +++ b/tests/phpunit/includes/site/SiteExporterTest.php @@ -0,0 +1,148 @@ +<?php + +/** + * Tests for the SiteExporter class. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * + * @ingroup Site + * @ingroup Test + * + * @group Site + * + * @covers SiteExporter + * + * @licence GNU GPL v2+ + * @author Daniel Kinzler + */ +class SiteExporterTest extends PHPUnit_Framework_TestCase { + + public function testConstructor_InvalidArgument() { + $this->setExpectedException( 'InvalidArgumentException' ); + + new SiteExporter( 'Foo' ); + } + + public function testExportSites() { + $foo = Site::newForType( Site::TYPE_UNKNOWN ); + $foo->setGlobalId( 'Foo' ); + + $acme = Site::newForType( Site::TYPE_UNKNOWN ); + $acme->setGlobalId( 'acme.com' ); + $acme->setGroup( 'Test' ); + $acme->addLocalId( Site::ID_INTERWIKI, 'acme' ); + $acme->setPath( Site::PATH_LINK, 'http://acme.com/' ); + + $tmp = tmpfile(); + $exporter = new SiteExporter( $tmp ); + + $exporter->exportSites( array( $foo, $acme ) ); + + fseek( $tmp, 0 ); + $xml = fread( $tmp, 16*1024 ); + + $this->assertContains( '<sites ', $xml ); + $this->assertContains( '<site>', $xml ); + $this->assertContains( '<globalid>Foo</globalid>', $xml ); + $this->assertContains( '</site>', $xml ); + $this->assertContains( '<globalid>acme.com</globalid>', $xml ); + $this->assertContains( '<group>Test</group>', $xml ); + $this->assertContains( '<localid type="interwiki">acme</localid>', $xml ); + $this->assertContains( '<path type="link">http://acme.com/</path>', $xml ); + $this->assertContains( '</sites>', $xml ); + + // NOTE: HHVM (at least on wmf Jenkins) doesn't like file URLs. + $xsdFile = __DIR__ . '/../../../../docs/sitelist-1.0.xsd'; + $xsdData = file_get_contents( $xsdFile ); + + $document = new DOMDocument(); + $document->loadXML( $xml, LIBXML_NONET ); + $document->schemaValidateSource( $xsdData ); + } + + private function newSiteStore( SiteList $sites ) { + $store = $this->getMock( 'SiteStore' ); + + $store->expects( $this->once() ) + ->method( 'saveSites' ) + ->will( $this->returnCallback( function ( $moreSites ) use ( $sites ) { + foreach ( $moreSites as $site ) { + $sites->setSite( $site ); + } + } ) ); + + $store->expects( $this->any() ) + ->method( 'getSites' ) + ->will( $this->returnValue( new SiteList() ) ); + + return $store; + } + + public function provideRoundTrip() { + $foo = Site::newForType( Site::TYPE_UNKNOWN ); + $foo->setGlobalId( 'Foo' ); + + $acme = Site::newForType( Site::TYPE_UNKNOWN ); + $acme->setGlobalId( 'acme.com' ); + $acme->setGroup( 'Test' ); + $acme->addLocalId( Site::ID_INTERWIKI, 'acme' ); + $acme->setPath( Site::PATH_LINK, 'http://acme.com/' ); + + $dewiki = Site::newForType( Site::TYPE_MEDIAWIKI ); + $dewiki->setGlobalId( 'dewiki' ); + $dewiki->setGroup( 'wikipedia' ); + $dewiki->setForward( true ); + $dewiki->addLocalId( Site::ID_INTERWIKI, 'wikipedia' ); + $dewiki->addLocalId( Site::ID_EQUIVALENT, 'de' ); + $dewiki->setPath( Site::PATH_LINK, 'http://de.wikipedia.org/w/' ); + $dewiki->setPath( MediaWikiSite::PATH_PAGE, 'http://de.wikipedia.org/wiki/' ); + $dewiki->setSource( 'meta.wikimedia.org' ); + + return array( + 'empty' => array( + new SiteList() + ), + + 'some' => array( + new SiteList( array( $foo, $acme, $dewiki ) ), + ), + ); + } + + /** + * @dataProvider provideRoundTrip() + */ + public function testRoundTrip( SiteList $sites ) { + $tmp = tmpfile(); + $exporter = new SiteExporter( $tmp ); + + $exporter->exportSites( $sites ); + + fseek( $tmp, 0 ); + $xml = fread( $tmp, 16*1024 ); + + $actualSites = new SiteList(); + $store = $this->newSiteStore( $actualSites ); + + $importer = new SiteImporter( $store ); + $importer->importFromXML( $xml ); + + $this->assertEquals( $sites, $actualSites ); + } + +} -- To view, visit https://gerrit.wikimedia.org/r/188060 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I40fd6aaa8f47bad3d595d5c190036bf04d13c12a Gerrit-PatchSet: 12 Gerrit-Project: mediawiki/core Gerrit-Branch: master Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Addshore <addshorew...@gmail.com> Gerrit-Reviewer: Aude <aude.w...@gmail.com> Gerrit-Reviewer: Daniel Kinzler <daniel.kinz...@wikimedia.de> Gerrit-Reviewer: Hoo man <h...@online.de> Gerrit-Reviewer: Jeroen De Dauw <jeroended...@gmail.com> Gerrit-Reviewer: Reedy <re...@wikimedia.org> Gerrit-Reviewer: Thiemo Mättig (WMDE) <thiemo.maet...@wikimedia.de> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits