[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/bin/ -> gittool.php (source)

   1  #!/usr/bin/env php
   2  <?php
   3  
   4  use splitbrain\phpcli\CLI;
   5  use splitbrain\phpcli\Options;
   6  
   7  if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
   8  define('NOSESSION', 1);
   9  require_once (DOKU_INC . 'inc/init.php');
  10  
  11  /**
  12   * Easily manage DokuWiki git repositories
  13   *
  14   * @author Andreas Gohr <andi@splitbrain.org>
  15   */
  16  class GitToolCLI extends CLI
  17  {
  18      /**
  19       * Register options and arguments on the given $options object
  20       *
  21       * @param Options $options
  22       * @return void
  23       */
  24      protected function setup(Options $options)
  25      {
  26          $options->setHelp(
  27              "Manage git repositories for DokuWiki and its plugins and templates.\n\n" .
  28              "$> ./bin/gittool.php clone gallery template:ach\n" .
  29              "$> ./bin/gittool.php repos\n" .
  30              "$> ./bin/gittool.php origin -v"
  31          );
  32  
  33          $options->registerArgument(
  34              'command',
  35              'Command to execute. See below',
  36              true
  37          );
  38  
  39          $options->registerCommand(
  40              'clone',
  41              'Tries to install a known plugin or template (prefix with template:) via git. Uses the DokuWiki.org ' .
  42              'plugin repository to find the proper git repository. Multiple extensions can be given as parameters'
  43          );
  44          $options->registerArgument(
  45              'extension',
  46              'name of the extension to install, prefix with \'template:\' for templates',
  47              true,
  48              'clone'
  49          );
  50  
  51          $options->registerCommand(
  52              'install',
  53              'The same as clone, but when no git source repository can be found, the extension is installed via ' .
  54              'download'
  55          );
  56          $options->registerArgument(
  57              'extension',
  58              'name of the extension to install, prefix with \'template:\' for templates',
  59              true,
  60              'install'
  61          );
  62  
  63          $options->registerCommand(
  64              'repos',
  65              'Lists all git repositories found in this DokuWiki installation'
  66          );
  67  
  68          $options->registerCommand(
  69              '*',
  70              'Any unknown commands are assumed to be arguments to git and will be executed in all repositories ' .
  71              'found within this DokuWiki installation'
  72          );
  73      }
  74  
  75      /**
  76       * Your main program
  77       *
  78       * Arguments and options have been parsed when this is run
  79       *
  80       * @param Options $options
  81       * @return void
  82       */
  83      protected function main(Options $options)
  84      {
  85          $command = $options->getCmd();
  86          $args = $options->getArgs();
  87          if (!$command) $command = array_shift($args);
  88  
  89          switch ($command) {
  90              case '':
  91                  echo $options->help();
  92                  break;
  93              case 'clone':
  94                  $this->cmdClone($args);
  95                  break;
  96              case 'install':
  97                  $this->cmdInstall($args);
  98                  break;
  99              case 'repo':
 100              case 'repos':
 101                  $this->cmdRepos();
 102                  break;
 103              default:
 104                  $this->cmdGit($command, $args);
 105          }
 106      }
 107  
 108      /**
 109       * Tries to install the given extensions using git clone
 110       *
 111       * @param array $extensions
 112       */
 113      public function cmdClone($extensions)
 114      {
 115          $errors = [];
 116          $succeeded = [];
 117  
 118          foreach ($extensions as $ext) {
 119              $repo = $this->getSourceRepo($ext);
 120  
 121              if (!$repo) {
 122                  $this->error("could not find a repository for $ext");
 123                  $errors[] = $ext;
 124              } elseif ($this->cloneExtension($ext, $repo)) {
 125                  $succeeded[] = $ext;
 126              } else {
 127                  $errors[] = $ext;
 128              }
 129          }
 130  
 131          echo "\n";
 132          if ($succeeded) $this->success('successfully cloned the following extensions: ' . implode(', ', $succeeded));
 133          if ($errors) $this->error('failed to clone the following extensions: ' . implode(', ', $errors));
 134      }
 135  
 136      /**
 137       * Tries to install the given extensions using git clone with fallback to install
 138       *
 139       * @param array $extensions
 140       */
 141      public function cmdInstall($extensions)
 142      {
 143          $errors = [];
 144          $succeeded = [];
 145  
 146          foreach ($extensions as $ext) {
 147              $repo = $this->getSourceRepo($ext);
 148  
 149              if (!$repo) {
 150                  $this->info("could not find a repository for $ext");
 151                  if ($this->downloadExtension($ext)) {
 152                      $succeeded[] = $ext;
 153                  } else {
 154                      $errors[] = $ext;
 155                  }
 156              } elseif ($this->cloneExtension($ext, $repo)) {
 157                  $succeeded[] = $ext;
 158              } else {
 159                  $errors[] = $ext;
 160              }
 161          }
 162  
 163          echo "\n";
 164          if ($succeeded) $this->success('successfully installed the following extensions: ' . implode(', ', $succeeded));
 165          if ($errors) $this->error('failed to install the following extensions: ' . implode(', ', $errors));
 166      }
 167  
 168      /**
 169       * Executes the given git command in every repository
 170       *
 171       * @param $cmd
 172       * @param $arg
 173       */
 174      public function cmdGit($cmd, $arg)
 175      {
 176          $repos = $this->findRepos();
 177  
 178          $shell = array_merge(['git', $cmd], $arg);
 179          $shell = array_map('escapeshellarg', $shell);
 180          $shell = implode(' ', $shell);
 181  
 182          foreach ($repos as $repo) {
 183              if (!@chdir($repo)) {
 184                  $this->error("Could not change into $repo");
 185                  continue;
 186              }
 187  
 188              $this->info("executing $shell in $repo");
 189              $ret = 0;
 190              system($shell, $ret);
 191  
 192              if ($ret == 0) {
 193                  $this->success("git succeeded in $repo");
 194              } else {
 195                  $this->error("git failed in $repo");
 196              }
 197          }
 198      }
 199  
 200      /**
 201       * Simply lists the repositories
 202       */
 203      public function cmdRepos()
 204      {
 205          $repos = $this->findRepos();
 206          foreach ($repos as $repo) {
 207              echo "$repo\n";
 208          }
 209      }
 210  
 211      /**
 212       * Install extension from the given download URL
 213       *
 214       * @param string $ext
 215       * @return bool|null
 216       */
 217      private function downloadExtension($ext)
 218      {
 219          /** @var helper_plugin_extension_extension $plugin */
 220          $plugin = plugin_load('helper', 'extension_extension');
 221          if (!$ext) die("extension plugin not available, can't continue");
 222  
 223          $plugin->setExtension($ext);
 224  
 225          $url = $plugin->getDownloadURL();
 226          if (!$url) {
 227              $this->error("no download URL for $ext");
 228              return false;
 229          }
 230  
 231          $ok = false;
 232          try {
 233              $this->info("installing $ext via download from $url");
 234              $ok = $plugin->installFromURL($url);
 235          } catch (Exception $e) {
 236              $this->error($e->getMessage());
 237          }
 238  
 239          if ($ok) {
 240              $this->success("installed $ext via download");
 241              return true;
 242          } else {
 243              $this->success("failed to install $ext via download");
 244              return false;
 245          }
 246      }
 247  
 248      /**
 249       * Clones the extension from the given repository
 250       *
 251       * @param string $ext
 252       * @param string $repo
 253       * @return bool
 254       */
 255      private function cloneExtension($ext, $repo)
 256      {
 257          if (str_starts_with($ext, 'template:')) {
 258              $target = fullpath(tpl_incdir() . '../' . substr($ext, 9));
 259          } else {
 260              $target = DOKU_PLUGIN . $ext;
 261          }
 262  
 263          $this->info("cloning $ext from $repo to $target");
 264          $ret = 0;
 265          system("git clone $repo $target", $ret);
 266          if ($ret === 0) {
 267              $this->success("cloning of $ext succeeded");
 268              return true;
 269          } else {
 270              $this->error("cloning of $ext failed");
 271              return false;
 272          }
 273      }
 274  
 275      /**
 276       * Returns all git repositories in this DokuWiki install
 277       *
 278       * Looks in root, template and plugin directories only.
 279       *
 280       * @return array
 281       */
 282      private function findRepos()
 283      {
 284          $this->info('Looking for .git directories');
 285          $data = array_merge(
 286              glob(DOKU_INC . '.git', GLOB_ONLYDIR),
 287              glob(DOKU_PLUGIN . '*/.git', GLOB_ONLYDIR),
 288              glob(fullpath(tpl_incdir() . '../') . '/*/.git', GLOB_ONLYDIR)
 289          );
 290  
 291          if (!$data) {
 292              $this->error('Found no .git directories');
 293          } else {
 294              $this->success('Found ' . count($data) . ' .git directories');
 295          }
 296          $data = array_map('fullpath', array_map('dirname', $data));
 297          return $data;
 298      }
 299  
 300      /**
 301       * Returns the repository for the given extension
 302       *
 303       * @param $extension
 304       * @return false|string
 305       */
 306      private function getSourceRepo($extension)
 307      {
 308          /** @var helper_plugin_extension_extension $ext */
 309          $ext = plugin_load('helper', 'extension_extension');
 310          if (!$ext) die("extension plugin not available, can't continue");
 311  
 312          $ext->setExtension($extension);
 313  
 314          $repourl = $ext->getSourcerepoURL();
 315          if (!$repourl) return false;
 316  
 317          // match github repos
 318          if (preg_match('/github\.com\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
 319              $user = $m[1];
 320              $repo = $m[2];
 321              return 'https://github.com/' . $user . '/' . $repo . '.git';
 322          }
 323  
 324          // match gitorious repos
 325          if (preg_match('/gitorious.org\/([^\/]+)\/([^\/]+)?/i', $repourl, $m)) {
 326              $user = $m[1];
 327              $repo = $m[2];
 328              if (!$repo) $repo = $user;
 329  
 330              return 'https://git.gitorious.org/' . $user . '/' . $repo . '.git';
 331          }
 332  
 333          // match bitbucket repos - most people seem to use mercurial there though
 334          if (preg_match('/bitbucket\.org\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
 335              $user = $m[1];
 336              $repo = $m[2];
 337              return 'https://bitbucket.org/' . $user . '/' . $repo . '.git';
 338          }
 339  
 340          return false;
 341      }
 342  }
 343  
 344  // Main
 345  $cli = new GitToolCLI();
 346  $cli->run();