[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/bin/ -> gittool.php (source)

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