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

Reply via email to