#!/usr/bin/env php
<?php

/**
 * @file
 * Writes the Gutenberg JS version and Git commit hash to the gutenberg.module file.
 *
 * Usage:
 *  write-gutenberg-version.php [gutenberg repo] [--version=] [--hash=] [--mode=development]
 */

$_GUTENBERG_HELP = <<<EOL

Writes the Gutenberg JS version and Git commit hash to the gutenberg.module file.

If a valid Gutenberg repo folder isn't declared, then the version and hash arguments must be specified.

  Usage:

      {$GLOBALS['argv'][0]} [gutenberg repo] [--version=] [--hash=] [--mode=development]

EOL;
require_once __DIR__ . '/_cli_include.inc.php';

$gutenberg_version = NULL;
$gutenberg_commit_hash = NULL;
$gutenberg_build_mode = NULL;

if (!empty($_CLI_OPTIONS['mode']) && $_CLI_OPTIONS['mode'] !== 'production') {
  // Write the current build mode.
  $gutenberg_build_mode = $_CLI_OPTIONS['mode'];
}
if (!empty($_CLI_OPTIONS['version'])) {
  $gutenberg_version = $_CLI_OPTIONS['version'];
}
if (!empty($_CLI_OPTIONS['hash'])) {
  $gutenberg_commit_hash = $_CLI_OPTIONS['hash'];
}

if (!$gutenberg_version || !$gutenberg_commit_hash) {
  // Default to .gutenberg folder if the repo argument wasn't specified.
  $gutenberg_repo = $_POSITIONAL_ARGS[0] ?? (dirname(__DIR__) . DIRECTORY_SEPARATOR . '.gutenberg');

  // Try reading version from the npm @wordpress/blocks package first.
  $npm_package_file = dirname(__DIR__) . '/node_modules/@wordpress/blocks/package.json';
  if (!$gutenberg_version && file_exists($npm_package_file)) {
    $gutenberg_version = json_decode(file_get_contents($npm_package_file), TRUE)['version'];
  }

  if (!$gutenberg_commit_hash && file_exists($npm_package_file)) {
    // No git hash available from npm packages, use 'npm' as placeholder.
    $gutenberg_commit_hash = 'npm';
  }

  // Fall back to git repo if npm package not available.
  if (!$gutenberg_version || !$gutenberg_commit_hash) {
    if (!file_exists($gutenberg_repo . DIRECTORY_SEPARATOR . '.git')) {
      fwrite(STDERR, "'$gutenberg_repo' is not a valid git repo and @wordpress/blocks npm package not found.");
      exit(1);
    }

    if (!$gutenberg_version) {
      // Fetch the version number.
      $package_file = $gutenberg_repo . DIRECTORY_SEPARATOR . 'package.json';
      if (!file_exists($package_file)) {
        fwrite(STDERR, "'$package_file' does not exist.");
        exit(2);
      }

      $gutenberg_version = json_decode(file_get_contents($package_file), TRUE)['version'];
    }

    if (!$gutenberg_commit_hash) {
      // Fetch the commit hash.
      $cwd = getcwd();
      chdir($gutenberg_repo);
      $gutenberg_commit_hash = trim(shell_exec('git rev-parse HEAD'));
      chdir($cwd);
    }
  }
}

$_module_filename = dirname(__DIR__) . DIRECTORY_SEPARATOR . 'gutenberg.module';
$_module_handle = fopen($_module_filename, 'r+b');
// Temp file to write to as we need to avoid writing to the file as we are reading it.
$_temp_filename = tempnam(sys_get_temp_dir(), 'gutenberg-module');
$_temp_handle = fopen($_temp_filename, 'wb+');

/**
 * Write a line.
 *
 * @param string $line
 *   Line to write to the file.
 */
function write_file($line) {
  global $_temp_handle;
  if (fwrite($_temp_handle, $line) === FALSE) {
    fwrite(STDERR, 'Could not write to temp module file..');
    exit(2);
  }
}

$inside_editor_fold = FALSE;
while (TRUE) {
  $line = fgets($_module_handle);
  if (FALSE === $line) {
    break;
  }

  switch (trim($line)) {
    case '// <editor-fold desc="Gutenberg autogenerated code.">':
      $inside_editor_fold = TRUE;
      write_file($line);
      write_file("define('GUTENBERG_JS_VERSION', '$gutenberg_version');\n");
      if ($gutenberg_commit_hash) {
        write_file("define('GUTENBERG_JS_GIT_COMMIT', '$gutenberg_commit_hash');\n");
      }
      if ($gutenberg_build_mode) {
        write_file("define('GUTENBERG_JS_BUILD', '$gutenberg_build_mode');\n");
      }
      break;

    case '// </editor-fold>':
      $inside_editor_fold = FALSE;
      write_file($line);
      break;

    default:
      // Don't write anything while processing the editor-fold.
      if (!$inside_editor_fold) {
        write_file($line);
      }
      break;
  }
}

// Stop reading/writing the files, and prepare for a move.
if (fclose($_module_handle) && fclose($_temp_handle)) {
  // Attempt to move the temp file over.
  if (rename($_temp_filename, $_module_filename)) {
    echo "Updated $_module_filename.\n";
    exit(0);
  }
}

fwrite(STDERR, "Could not update $_module_filename.");
exit(1);
