Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git
<?php
class GitRefs {
  private string $repoPath;

  public function __construct( string $repoPath ) {
    $this->repoPath = $repoPath;
  }

  public function resolve( string $input ): string {
    if( preg_match( '/^[0-9a-f]{40}$/', $input ) ) {
      return $input;
    }

    $headFile = "{$this->repoPath}/HEAD";

    if( $input === 'HEAD' && file_exists( $headFile ) ) {
      $head = trim( file_get_contents( $headFile ) );

      return strpos( $head, 'ref: ' ) === 0
        ? $this->resolve( substr( $head, 5 ) )
        : $head;
    }

    return $this->resolveRef( $input );
  }

  public function getMainBranch(): array {
    $branches = [];

    $this->scanRefs(
      'refs/heads',
      function( string $name, string $sha ) use ( &$branches ) {
        $branches[$name] = $sha;
      }
    );

    foreach( ['main', 'master', 'trunk', 'develop'] as $try ) {
      if( isset( $branches[$try] ) ) {
        return ['name' => $try, 'hash' => $branches[$try]];
      }
    }

    $firstKey = array_key_first( $branches );

    return $firstKey
      ? ['name' => $firstKey, 'hash' => $branches[$firstKey]]
      : ['name' => '', 'hash' => ''];
  }

  public function scanRefs( string $prefix, callable $callback ): void {
    $dir = "{$this->repoPath}/$prefix";

    if( is_dir( $dir ) ) {
      $files = array_diff( scandir( $dir ), ['.', '..'] );

      foreach( $files as $file ) {
        $callback( $file, trim( file_get_contents( "$dir/$file" ) ) );
      }
    }
  }

  private function resolveRef( string $input ): string {
    $paths = [$input, "refs/heads/$input", "refs/tags/$input"];

    foreach( $paths as $ref ) {
      $path = "{$this->repoPath}/$ref";

      if( file_exists( $path ) ) {
        return trim( file_get_contents( $path ) );
      }
    }

    $packedPath = "{$this->repoPath}/packed-refs";

    return file_exists( $packedPath )
      ? $this->findInPackedRefs( $packedPath, $input )
      : '';
  }

  private function findInPackedRefs( string $path, string $input ): string {
    $targets = [$input, "refs/heads/$input", "refs/tags/$input"];

    foreach( file( $path ) as $line ) {
      if( $line[0] === '#' || $line[0] === '^' ) {
        continue;
      }

      $parts = explode( ' ', trim( $line ) );

      if( count( $parts ) >= 2 && in_array( $parts[1], $targets ) ) {
        return $parts[0];
      }
    }

    return '';
  }
}