website_jukni/dokuwiki/bin/gittool.php
2017-12-29 15:51:59 +01:00

336 lines
No EOL
9.8 KiB
PHP
Executable file

#!/usr/bin/php
<?php
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
define('NOSESSION', 1);
require_once(DOKU_INC.'inc/init.php');
/**
* Easily manage DokuWiki git repositories
*
* @author Andreas Gohr <andi@splitbrain.org>
*/
class GitToolCLI extends DokuCLI {
/**
* Register options and arguments on the given $options object
*
* @param DokuCLI_Options $options
* @return void
*/
protected function setup(DokuCLI_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 DokuCLI_Options $options
* @return void
*/
protected function main(DokuCLI_Options $options) {
$command = $options->getCmd();
if(!$command) $command = array_shift($options->args);
switch($command) {
case '':
echo $options->help();
break;
case 'clone':
$this->cmd_clone($options->args);
break;
case 'install':
$this->cmd_install($options->args);
break;
case 'repo':
case 'repos':
$this->cmd_repos();
break;
default:
$this->cmd_git($command, $options->args);
}
}
/**
* Tries to install the given extensions using git clone
*
* @param array $extensions
*/
public function cmd_clone($extensions) {
$errors = array();
$succeeded = array();
foreach($extensions as $ext) {
$repo = $this->getSourceRepo($ext);
if(!$repo) {
$this->error("could not find a repository for $ext");
$errors[] = $ext;
} else {
if($this->cloneExtension($ext, $repo)) {
$succeeded[] = $ext;
} else {
$errors[] = $ext;
}
}
}
echo "\n";
if($succeeded) $this->success('successfully cloned the following extensions: '.join(', ', $succeeded));
if($errors) $this->error('failed to clone the following extensions: '.join(', ', $errors));
}
/**
* Tries to install the given extensions using git clone with fallback to install
*
* @param array $extensions
*/
public function cmd_install($extensions) {
$errors = array();
$succeeded = array();
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;
}
} else {
if($this->cloneExtension($ext, $repo)) {
$succeeded[] = $ext;
} else {
$errors[] = $ext;
}
}
}
echo "\n";
if($succeeded) $this->success('successfully installed the following extensions: '.join(', ', $succeeded));
if($errors) $this->error('failed to install the following extensions: '.join(', ', $errors));
}
/**
* Executes the given git command in every repository
*
* @param $cmd
* @param $arg
*/
public function cmd_git($cmd, $arg) {
$repos = $this->findRepos();
$shell = array_merge(array('git', $cmd), $arg);
$shell = array_map('escapeshellarg', $shell);
$shell = join(' ', $shell);
foreach($repos as $repo) {
if(!@chdir($repo)) {
$this->error("Could not change into $repo");
continue;
}
echo "\n";
$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 cmd_repos() {
$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(substr($ext, 0, 9) == '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();