https://www.mediawiki.org/wiki/Special:Code/MediaWiki/114548
Revision: 114548
Author: tstarling
Date: 2012-03-28 05:47:11 +0000 (Wed, 28 Mar 2012)
Log Message:
-----------
Gerrit changeset differ
Added Paths:
-----------
trunk/tools/gerrit-differ/
trunk/tools/gerrit-differ/gerrit-differ.php
Added: trunk/tools/gerrit-differ/gerrit-differ.php
===================================================================
--- trunk/tools/gerrit-differ/gerrit-differ.php (rev 0)
+++ trunk/tools/gerrit-differ/gerrit-differ.php 2012-03-28 05:47:11 UTC (rev
114548)
@@ -0,0 +1,325 @@
+<?php
+
+$differ = new GerritDifferUI;
+$differ->execute();
+
+class GerritDifferUI {
+ var $writer;
+ var $engine;
+ var $errorsShown;
+
+ function execute() {
+ $this->errorsShown = false;
+ $xw = $this->writer = new XMLWriter;
+ $this->engine = new GerritDifferEngine;
+ $xw->openMemory();
+ $xw->setIndent( true );
+ $this->showHeader();
+ if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
+ $this->showForm();
+ $this->showDiff();
+ } else {
+ $this->showForm();
+ }
+ $this->showFooter();
+ echo $xw->outputMemory();
+ }
+
+ function textBox( $name, $label, $size, $default = false ) {
+ $xw = $this->writer;
+ $xw->startElement( 'label' );
+ $xw->text( $label . ': ' );
+ $xw->startElement( 'input' );
+ $xw->writeAttribute( 'type', 'text' );
+ $xw->writeAttribute( 'name', $name );
+ $xw->writeAttribute( 'size', $size );
+
+ if ( isset( $_POST[$name] ) ) {
+ $value = $_POST[$name];
+ } else {
+ $value = $default;
+ }
+ if ( $value !== false ) {
+ $xw->writeAttribute( 'value', $value );
+ }
+
+ $xw->endElement(); // input
+ $xw->endElement(); // label
+ $xw->writeElement( 'br' );
+ }
+
+ function showHeader() {
+ $xw = $this->writer;
+ $xw->writeDTD( 'html' );
+ $xw->startElement( 'html' );
+ $xw->startElement( 'head' );
+ $xw->writeElement( 'title', 'Gerrit changeset diff' );
+ $xw->writeComment( 'TODO: put some styles in here' );
+ $xw->endElement(); // head
+ $xw->startElement( 'body' );
+ }
+
+ function showFooter() {
+ $xw = $this->writer;
+ $xw->endElement(); // body
+ $xw->endElement(); // html
+ }
+
+ function showForm() {
+ $xw = $this->writer;
+ $xw->startElement( 'form' );
+ $xw->writeAttribute( 'action', $_SERVER['PHP_SELF'] );
+ $xw->writeAttribute( 'method', 'POST' );
+
+ $this->textBox( 'url', 'Gerrit change URL', 80 );
+ $this->textBox( 'old', 'Old patchset index', 10 );
+ $this->textBox( 'new', 'New patchset index', 10 );
+ $this->textBox( 'base', 'Rebase branch', 30, 'master' );
+
+ $xw->startElement( 'input' );
+ $xw->writeAttribute( 'type', 'submit' );
+ $xw->writeAttribute( 'name', 'submit' );
+ $xw->writeAttribute( 'value', 'OK' );
+
+ $xw->endElement(); // form
+ }
+
+ function getPostVal( $name ) {
+ if ( !isset( $_POST[$name] ) ) {
+ return false;
+ } else {
+ return trim( strval( $_POST[$name] ) );
+ }
+ }
+
+ function validateInteger( $value, $description ) {
+ if ( !preg_match( '/^\d+$/', $value ) ) {
+ $this->showError( "$description must be an integer" );
+ return false;
+ } else {
+ return intval( $value );
+ }
+ }
+
+ function showError( $text ) {
+ $xw = $this->writer;
+ $xw->startElement( 'div' );
+ $xw->writeAttribute( 'class', 'gd-error' );
+ $xw->text( "Error: $text" );
+ $xw->endElement();
+ $this->errorsShown = true;
+ }
+
+ function showDiff() {
+ $xw = $this->writer;
+ $xw->writeElement( 'hr' );
+
+ $url = $this->getPostVal( 'url' );
+ $old = $this->getPostVal( 'old' );
+ $new = $this->getPostVal( 'new' );
+ $base = $this->getPostVal( 'base' );
+
+ if ( !strlen( $url ) ) {
+ $this->showError( 'Please specify a gerrit URL' );
+ }
+ if ( !strlen( $old ) ) {
+ $this->showError( 'Please specify an old patchset
index' );
+ }
+ if ( !strlen( $new ) ) {
+ $this->showError( 'Please specify a new patchset index'
);
+ }
+ if ( !strlen( $base ) ) {
+ $this->showError( 'Please specify a rebase branch' );
+ }
+ if ( $this->errorsShown ) {
+ return;
+ }
+
+ $fragment = @parse_url( $url, PHP_URL_FRAGMENT );
+ if ( $fragment === false ) {
+ $this->showError( 'Malformed Gerrit URL: no fragment' );
+ return;
+ }
+
+ $host = @parse_url( $url, PHP_URL_HOST );
+ if ( $host !== 'gerrit.wikimedia.org' ) {
+ $this->showError( 'Sorry, only Wikimedia changes are
supported at the moment' );
+ return;
+ }
+
+ if ( !preg_match( '/^change,(\d+(\d\d))$/', $fragment, $m ) ) {
+ $this->showError( 'Malformed Gerrit URL: fragment
should be of the form "change,NNNN"' );
+ } else {
+ $change = $m[1];
+ $changeRef = "refs/changes/{$m[2]}/{$m[1]}";
+ }
+
+ $old = $this->validateInteger( $old, 'Old patchset index' );
+ $new = $this->validateInteger( $new, 'New patchset index' );
+
+ if ( $this->errorsShown ) {
+ return;
+ }
+
+ try {
+ $this->engine->updateMirror();
+
+ $baseRef = "refs/heads/$base";
+ if ( $old === 0 ) {
+ $oldRef = $baseRef;
+ } else {
+ $oldRef = "$changeRef/$old";
+ }
+ $newRef = "$changeRef/$new";
+
+ if ( !$this->engine->refExists( $baseRef ) ) {
+ $this->showError( "Branch \"$base\" does not
exist" );
+ }
+ if ( !$this->engine->refExists( $oldRef ) ) {
+ $this->showError( "Old patchset $oldRef does
not exist" );
+ }
+ if ( !$this->engine->refExists( $newRef ) ) {
+ $this->showError( "New patchset $newRef does
not exist" );
+ }
+ if ( $this->errorsShown ) {
+ return;
+ }
+
+ $oldBranch = $this->engine->newBranch( $oldRef );
+ $newBranch = $this->engine->newBranch( $newRef );
+ $this->engine->updateNormal();
+ $oldBranch->rebase( $base );
+ $newBranch->rebase( $base );
+ $diff = $this->engine->diff( $oldBranch, $newBranch );
+ } catch ( GerritDifferException $e ) {
+ $this->showError( $e->getMessage() );
+ return;
+ }
+
+ $xw->startElement( 'pre' );
+ $xw->text( $diff );
+ $xw->endElement();
+ }
+}
+
+class GerritDifferEngine {
+ var $mirrorDir = '/var/local/gerrit-differ/core.git';
+ var $normalDir = '/var/local/gerrit-differ/core';
+
+ var $refCache;
+
+ function updateMirror() {
+ $this->runMirrorGit( array( 'fetch' ) );
+ }
+
+ function updateNormal() {
+ $this->runNormalGit( array( 'fetch' ) );
+ }
+
+ function runGit( $dir, $args ) {
+ $cmd = 'git';
+ foreach ( $args as $arg ) {
+ $cmd .= ' ';
+ $cmd .= escapeshellarg( $arg );
+ }
+ $cmd .= ' 2>&1';
+
+ $oldCwd = getcwd();
+ chdir( $dir );
+
+ $pipe = popen( $cmd, 'r' );
+ if ( !$pipe ) {
+ chdir( $oldCwd );
+ throw new GerritDifferException( "Unable to run git" );
+ }
+ $result = stream_get_contents( $pipe );
+ $status = pclose( $pipe );
+ chdir( $oldCwd );
+ if ( $status ) {
+ throw new GerritDifferException( "Git exited with
status \"$status\":\n$result\n" );
+ }
+ return $result;
+ }
+
+ function runMirrorGit( $args ) {
+ return $this->runGit( $this->mirrorDir, $args );
+ }
+
+ function runNormalGit( $args ) {
+ return $this->runGit( $this->normalDir, $args );
+ }
+
+ function refExists( $ref ) {
+ try {
+ $this->runMirrorGit( array(
+ 'show-ref',
+ '--verify',
+ $ref ) );
+ $found = true;
+ } catch ( GerritDifferException $e ) {
+ $found = false;
+ }
+ return $found;
+ }
+
+ function newBranch( $ref ) {
+ return new GerritDifferBranch( $this, $ref );
+ }
+
+ function diff( $oldBranch, $newBranch ) {
+ return $this->runNormalGit( array(
+ 'diff',
+ $oldBranch->getName(),
+ $newBranch->getName() ) );
+ }
+}
+
+class GerritDifferBranch {
+ var $valid = false;
+ var $name;
+
+ function __construct( $engine, $ref ) {
+ $this->engine = $engine;
+ $this->ref = $ref;
+ $this->name = 'gerrit-differ/' . $ref;
+ $this->engine->runNormalGit( array(
+ 'fetch',
+ 'origin',
+ $this->ref ) );
+ $this->engine->runNormalGit( array(
+ 'branch',
+ '--force',
+ $this->name,
+ 'FETCH_HEAD' ) );
+ $this->valid = true;
+ }
+
+ function __destruct() {
+ if ( !$this->valid ) {
+ return;
+ }
+ $this->engine->runNormalGit( array(
+ 'checkout',
+ 'master' ) );
+
+ $this->engine->runNormalGit( array(
+ 'branch',
+ '-D',
+ $this->name ) );
+ }
+
+ function getName() {
+ return $this->name;
+ }
+
+ function rebase( $newBase ) {
+ $this->engine->runNormalGit( array(
+ 'rebase',
+ $newBase,
+ $this->name,
+ ) );
+ }
+}
+
+class GerritDifferException extends Exception {}
+
Property changes on: trunk/tools/gerrit-differ/gerrit-differ.php
___________________________________________________________________
Added: svn:eol-style
+ native
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs