Improve GitInfo for reading packed refs
authorSeb35 <seb35@seb35.fr>
Fri, 15 Sep 2017 08:29:13 +0000 (10:29 +0200)
committerBryanDavis <bdavis@wikimedia.org>
Mon, 2 Oct 2017 03:47:33 +0000 (03:47 +0000)
GitInfo only reads branches in files /refs/heads/*; it should also
read those in /.git/packed-refs.

There are 4 tests in this commit to test this new "feature" and add some
code coverage to other methods. Given this class tests Git behaviour and
MediaWiki itself is versioned with Git, the test data are created during
the tests and removed at the end to avoid interference with Git as CVS.

Bug: T155747
Change-Id: Icccdf3ec797788582f836e2d8e267a1d714d50dc

includes/GitInfo.php
tests/phpunit/includes/GitInfoTest.php

index 4351acc..3c600ed 100644 (file)
@@ -191,8 +191,14 @@ class GitInfo {
                        } else {
                                // If not a SHA1 it may be a ref:
                                $refFile = "{$this->basedir}/{$head}";
+                               $packedRefs = "{$this->basedir}/packed-refs";
+                               $headRegex = preg_quote( $head, '/' );
                                if ( is_readable( $refFile ) ) {
                                        $sha1 = rtrim( file_get_contents( $refFile ) );
+                               } elseif ( is_readable( $packedRefs ) &&
+                                       preg_match( "/^([0-9A-Fa-f]{40}) $headRegex$/m", file_get_contents( $packedRefs ), $matches )
+                               ) {
+                                       $sha1 = $matches[1];
                                }
                        }
                        $this->cache['headSHA1'] = $sha1;
index ae858f5..1037b37 100644 (file)
@@ -4,6 +4,30 @@
  */
 class GitInfoTest extends MediaWikiTestCase {
 
+       public static function setUpBeforeClass() {
+               mkdir( __DIR__ . '/../data/gitrepo' );
+               mkdir( __DIR__ . '/../data/gitrepo/1' );
+               mkdir( __DIR__ . '/../data/gitrepo/2' );
+               mkdir( __DIR__ . '/../data/gitrepo/3' );
+               mkdir( __DIR__ . '/../data/gitrepo/1/.git' );
+               mkdir( __DIR__ . '/../data/gitrepo/1/.git/refs' );
+               mkdir( __DIR__ . '/../data/gitrepo/1/.git/refs/heads' );
+               file_put_contents( __DIR__ . '/../data/gitrepo/1/.git/HEAD',
+                       "ref: refs/heads/master\n" );
+               file_put_contents( __DIR__ . '/../data/gitrepo/1/.git/refs/heads/master',
+                       "0123456789012345678901234567890123abcdef\n" );
+               file_put_contents( __DIR__ . '/../data/gitrepo/1/.git/packed-refs',
+                       "abcdef6789012345678901234567890123456789 refs/heads/master\n" );
+               file_put_contents( __DIR__ . '/../data/gitrepo/2/.git',
+                       "gitdir: ../1/.git\n" );
+               file_put_contents( __DIR__ . '/../data/gitrepo/3/.git',
+                       'gitdir: ' . __DIR__ . "/../data/gitrepo/1/.git\n" );
+       }
+
+       public static function tearDownAfterClass() {
+               wfRecursiveRemoveDir( __DIR__ . '/../data/gitrepo' );
+       }
+
        protected function setUp() {
                parent::setUp();
                $this->setMwGlobals( 'wgGitInfoCacheDirectory', __DIR__ . '/../data/gitinfo' );
@@ -43,4 +67,36 @@ class GitInfoTest extends MediaWikiTestCase {
                $this->assertTrue( $fixture->cacheIsComplete() );
        }
 
+       public function testReadingHead() {
+               $dir = __DIR__ . '/../data/gitrepo/1';
+               $fixture = new GitInfo( $dir );
+
+               $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
+               $this->assertEquals( '0123456789012345678901234567890123abcdef', $fixture->getHeadSHA1() );
+       }
+
+       public function testIndirection() {
+               $dir = __DIR__ . '/../data/gitrepo/2';
+               $fixture = new GitInfo( $dir );
+
+               $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
+               $this->assertEquals( '0123456789012345678901234567890123abcdef', $fixture->getHeadSHA1() );
+       }
+
+       public function testIndirection2() {
+               $dir = __DIR__ . '/../data/gitrepo/3';
+               $fixture = new GitInfo( $dir );
+
+               $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
+               $this->assertEquals( '0123456789012345678901234567890123abcdef', $fixture->getHeadSHA1() );
+       }
+
+       public function testReadingPackedRefs() {
+               $dir = __DIR__ . '/../data/gitrepo/1';
+               unlink( __DIR__ . '/../data/gitrepo/1/.git/refs/heads/master' );
+               $fixture = new GitInfo( $dir );
+
+               $this->assertEquals( 'refs/heads/master', $fixture->getHead() );
+               $this->assertEquals( 'abcdef6789012345678901234567890123456789', $fixture->getHeadSHA1() );
+       }
 }