[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
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(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();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body