|
- #!/usr/bin/env php
- <?php
-
- use splitbrain\phpcli\CLI;
- use splitbrain\phpcli\Options;
-
- if (!defined('DOKU_INC')) define('DOKU_INC', realpath(__DIR__ . '/../') . '/');
- define('NOSESSION', 1);
- require_once(DOKU_INC . 'inc/init.php');
-
- /**
- * Easily manage DokuWiki git repositories
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- */
- class GitToolCLI extends CLI
- {
- /**
- * Register options and arguments on the given $options object
- *
- * @param Options $options
- * @return void
- */
- protected function setup(Options $options)
- {
- $options->setHelp(
- "Manage git repositories for DokuWiki and its plugins and templates.\n\n" .
- "$> ./bin/gittool.php clone gallery template:ach\n" .
- "$> ./bin/gittool.php repos\n" .
- "$> ./bin/gittool.php origin -v"
- );
-
- $options->registerArgument(
- 'command',
- 'Command to execute. See below',
- true
- );
-
- $options->registerCommand(
- 'clone',
- 'Tries to install a known plugin or template (prefix with template:) via git. Uses the DokuWiki.org ' .
- 'plugin repository to find the proper git repository. Multiple extensions can be given as parameters'
- );
- $options->registerArgument(
- 'extension',
- 'name of the extension to install, prefix with \'template:\' for templates',
- true,
- 'clone'
- );
-
- $options->registerCommand(
- 'install',
- 'The same as clone, but when no git source repository can be found, the extension is installed via ' .
- 'download'
- );
- $options->registerArgument(
- 'extension',
- 'name of the extension to install, prefix with \'template:\' for templates',
- true,
- 'install'
- );
-
- $options->registerCommand(
- 'repos',
- 'Lists all git repositories found in this DokuWiki installation'
- );
-
- $options->registerCommand(
- '*',
- 'Any unknown commands are assumed to be arguments to git and will be executed in all repositories ' .
- 'found within this DokuWiki installation'
- );
- }
-
- /**
- * Your main program
- *
- * Arguments and options have been parsed when this is run
- *
- * @param Options $options
- * @return void
- */
- protected function main(Options $options)
- {
- $command = $options->getCmd();
- $args = $options->getArgs();
- if (!$command) $command = array_shift($args);
-
- switch ($command) {
- case '':
- echo $options->help();
- break;
- case 'clone':
- $this->cmdClone($args);
- break;
- case 'install':
- $this->cmdInstall($args);
- break;
- case 'repo':
- case 'repos':
- $this->cmdRepos();
- break;
- default:
- $this->cmdGit($command, $args);
- }
- }
-
- /**
- * Tries to install the given extensions using git clone
- *
- * @param array $extensions
- */
- public function cmdClone($extensions)
- {
- $errors = [];
- $succeeded = [];
-
- foreach ($extensions as $ext) {
- $repo = $this->getSourceRepo($ext);
-
- if (!$repo) {
- $this->error("could not find a repository for $ext");
- $errors[] = $ext;
- } elseif ($this->cloneExtension($ext, $repo)) {
- $succeeded[] = $ext;
- } else {
- $errors[] = $ext;
- }
- }
-
- echo "\n";
- if ($succeeded) $this->success('successfully cloned the following extensions: ' . implode(', ', $succeeded));
- if ($errors) $this->error('failed to clone the following extensions: ' . implode(', ', $errors));
- }
-
- /**
- * Tries to install the given extensions using git clone with fallback to install
- *
- * @param array $extensions
- */
- public function cmdInstall($extensions)
- {
- $errors = [];
- $succeeded = [];
-
- foreach ($extensions as $ext) {
- $repo = $this->getSourceRepo($ext);
-
- if (!$repo) {
- $this->info("could not find a repository for $ext");
- if ($this->downloadExtension($ext)) {
- $succeeded[] = $ext;
- } else {
- $errors[] = $ext;
- }
- } elseif ($this->cloneExtension($ext, $repo)) {
- $succeeded[] = $ext;
- } else {
- $errors[] = $ext;
- }
- }
-
- echo "\n";
- if ($succeeded) $this->success('successfully installed the following extensions: ' . implode(', ', $succeeded));
- if ($errors) $this->error('failed to install the following extensions: ' . implode(', ', $errors));
- }
-
- /**
- * Executes the given git command in every repository
- *
- * @param $cmd
- * @param $arg
- */
- public function cmdGit($cmd, $arg)
- {
- $repos = $this->findRepos();
-
- $shell = array_merge(['git', $cmd], $arg);
- $shell = array_map('escapeshellarg', $shell);
- $shell = implode(' ', $shell);
-
- foreach ($repos as $repo) {
- if (!@chdir($repo)) {
- $this->error("Could not change into $repo");
- continue;
- }
-
- $this->info("executing $shell in $repo");
- $ret = 0;
- system($shell, $ret);
-
- if ($ret == 0) {
- $this->success("git succeeded in $repo");
- } else {
- $this->error("git failed in $repo");
- }
- }
- }
-
- /**
- * Simply lists the repositories
- */
- public function cmdRepos()
- {
- $repos = $this->findRepos();
- foreach ($repos as $repo) {
- echo "$repo\n";
- }
- }
-
- /**
- * Install extension from the given download URL
- *
- * @param string $ext
- * @return bool|null
- */
- private function downloadExtension($ext)
- {
- /** @var helper_plugin_extension_extension $plugin */
- $plugin = plugin_load('helper', 'extension_extension');
- if (!$ext) die("extension plugin not available, can't continue");
-
- $plugin->setExtension($ext);
-
- $url = $plugin->getDownloadURL();
- if (!$url) {
- $this->error("no download URL for $ext");
- return false;
- }
-
- $ok = false;
- try {
- $this->info("installing $ext via download from $url");
- $ok = $plugin->installFromURL($url);
- } catch (Exception $e) {
- $this->error($e->getMessage());
- }
-
- if ($ok) {
- $this->success("installed $ext via download");
- return true;
- } else {
- $this->success("failed to install $ext via download");
- return false;
- }
- }
-
- /**
- * Clones the extension from the given repository
- *
- * @param string $ext
- * @param string $repo
- * @return bool
- */
- private function cloneExtension($ext, $repo)
- {
- if (str_starts_with($ext, 'template:')) {
- $target = fullpath(tpl_incdir() . '../' . substr($ext, 9));
- } else {
- $target = DOKU_PLUGIN . $ext;
- }
-
- $this->info("cloning $ext from $repo to $target");
- $ret = 0;
- system("git clone $repo $target", $ret);
- if ($ret === 0) {
- $this->success("cloning of $ext succeeded");
- return true;
- } else {
- $this->error("cloning of $ext failed");
- return false;
- }
- }
-
- /**
- * Returns all git repositories in this DokuWiki install
- *
- * Looks in root, template and plugin directories only.
- *
- * @return array
- */
- private function findRepos()
- {
- $this->info('Looking for .git directories');
- $data = array_merge(
- glob(DOKU_INC . '.git', GLOB_ONLYDIR),
- glob(DOKU_PLUGIN . '*/.git', GLOB_ONLYDIR),
- glob(fullpath(tpl_incdir() . '../') . '/*/.git', GLOB_ONLYDIR)
- );
-
- if (!$data) {
- $this->error('Found no .git directories');
- } else {
- $this->success('Found ' . count($data) . ' .git directories');
- }
- $data = array_map('fullpath', array_map('dirname', $data));
- return $data;
- }
-
- /**
- * Returns the repository for the given extension
- *
- * @param $extension
- * @return false|string
- */
- private function getSourceRepo($extension)
- {
- /** @var helper_plugin_extension_extension $ext */
- $ext = plugin_load('helper', 'extension_extension');
- if (!$ext) die("extension plugin not available, can't continue");
-
- $ext->setExtension($extension);
-
- $repourl = $ext->getSourcerepoURL();
- if (!$repourl) return false;
-
- // match github repos
- if (preg_match('/github\.com\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
- $user = $m[1];
- $repo = $m[2];
- return 'https://github.com/' . $user . '/' . $repo . '.git';
- }
-
- // match gitorious repos
- if (preg_match('/gitorious.org\/([^\/]+)\/([^\/]+)?/i', $repourl, $m)) {
- $user = $m[1];
- $repo = $m[2];
- if (!$repo) $repo = $user;
-
- return 'https://git.gitorious.org/' . $user . '/' . $repo . '.git';
- }
-
- // match bitbucket repos - most people seem to use mercurial there though
- if (preg_match('/bitbucket\.org\/([^\/]+)\/([^\/]+)/i', $repourl, $m)) {
- $user = $m[1];
- $repo = $m[2];
- return 'https://bitbucket.org/' . $user . '/' . $repo . '.git';
- }
-
- return false;
- }
- }
-
- // Main
- $cli = new GitToolCLI();
- $cli->run();
|