diff options
author | ahriman <ahriman@falte.red> | 2018-12-03 19:22:25 -0500 |
---|---|---|
committer | ahriman <ahriman@falte.red> | 2018-12-03 19:22:25 -0500 |
commit | 0ae8cbf5c0b1a198b963490985b7738392ebcb97 (patch) | |
tree | b2c77ae72c6b717e2b97492065196ac5ffb2d9e2 /wiki/bin | |
parent | f57f6cc5a2d159f90168d292437dc4bd8cd7f934 (diff) | |
download | site-0ae8cbf5c0b1a198b963490985b7738392ebcb97.tar.gz |
installed dokuwiki, added to navbar, updated news
Diffstat (limited to 'wiki/bin')
-rw-r--r-- | wiki/bin/.htaccess | 7 | ||||
-rwxr-xr-x | wiki/bin/dwpage.php | 322 | ||||
-rwxr-xr-x | wiki/bin/gittool.php | 340 | ||||
-rwxr-xr-x | wiki/bin/indexer.php | 107 | ||||
-rwxr-xr-x | wiki/bin/plugin.php | 103 | ||||
-rwxr-xr-x | wiki/bin/render.php | 64 | ||||
-rwxr-xr-x | wiki/bin/striplangs.php | 114 | ||||
-rwxr-xr-x | wiki/bin/wantedpages.php | 186 |
8 files changed, 1243 insertions, 0 deletions
diff --git a/wiki/bin/.htaccess b/wiki/bin/.htaccess new file mode 100644 index 0000000..5f279f1 --- /dev/null +++ b/wiki/bin/.htaccess @@ -0,0 +1,7 @@ +<IfModule mod_authz_host> + Require all denied +</IfModule> +<IfModule !mod_authz_host> + Order allow,deny + Deny from all +</IfModule> diff --git a/wiki/bin/dwpage.php b/wiki/bin/dwpage.php new file mode 100755 index 0000000..3124563 --- /dev/null +++ b/wiki/bin/dwpage.php @@ -0,0 +1,322 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Options; + +if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); +define('NOSESSION', 1); +require_once(DOKU_INC . 'inc/init.php'); + +/** + * Checkout and commit pages from the command line while maintaining the history + */ +class PageCLI extends CLI { + + protected $force = false; + protected $username = ''; + + /** + * Register options and arguments on the given $options object + * + * @param Options $options + * @return void + */ + protected function setup(Options $options) { + /* global */ + $options->registerOption( + 'force', + 'force obtaining a lock for the page (generally bad idea)', + 'f' + ); + $options->registerOption( + 'user', + 'work as this user. defaults to current CLI user', + 'u', + 'username' + ); + $options->setHelp( + 'Utility to help command line Dokuwiki page editing, allow ' . + 'pages to be checked out for editing then committed after changes' + ); + + /* checkout command */ + $options->registerCommand( + 'checkout', + 'Checks out a file from the repository, using the wiki id and obtaining ' . + 'a lock for the page. ' . "\n" . + 'If a working_file is specified, this is where the page is copied to. ' . + 'Otherwise defaults to the same as the wiki page in the current ' . + 'working directory.' + ); + $options->registerArgument( + 'wikipage', + 'The wiki page to checkout', + true, + 'checkout' + ); + $options->registerArgument( + 'workingfile', + 'How to name the local checkout', + false, + 'checkout' + ); + + /* commit command */ + $options->registerCommand( + 'commit', + 'Checks in the working_file into the repository using the specified ' . + 'wiki id, archiving the previous version.' + ); + $options->registerArgument( + 'workingfile', + 'The local file to commit', + true, + 'commit' + ); + $options->registerArgument( + 'wikipage', + 'The wiki page to create or update', + true, + 'commit' + ); + $options->registerOption( + 'message', + 'Summary describing the change (required)', + 'm', + 'summary', + 'commit' + ); + $options->registerOption( + 'trivial', + 'minor change', + 't', + false, + 'commit' + ); + + /* lock command */ + $options->registerCommand( + 'lock', + 'Obtains or updates a lock for a wiki page' + ); + $options->registerArgument( + 'wikipage', + 'The wiki page to lock', + true, + 'lock' + ); + + /* unlock command */ + $options->registerCommand( + 'unlock', + 'Removes a lock for a wiki page.' + ); + $options->registerArgument( + 'wikipage', + 'The wiki page to unlock', + true, + 'unlock' + ); + } + + /** + * Your main program + * + * Arguments and options have been parsed when this is run + * + * @param Options $options + * @return void + */ + protected function main(Options $options) { + $this->force = $options->getOpt('force', false); + $this->username = $options->getOpt('user', $this->getUser()); + + $command = $options->getCmd(); + $args = $options->getArgs(); + switch($command) { + case 'checkout': + $wiki_id = array_shift($args); + $localfile = array_shift($args); + $this->commandCheckout($wiki_id, $localfile); + break; + case 'commit': + $localfile = array_shift($args); + $wiki_id = array_shift($args); + $this->commandCommit( + $localfile, + $wiki_id, + $options->getOpt('message', ''), + $options->getOpt('trivial', false) + ); + break; + case 'lock': + $wiki_id = array_shift($args); + $this->obtainLock($wiki_id); + $this->success("$wiki_id locked"); + break; + case 'unlock': + $wiki_id = array_shift($args); + $this->clearLock($wiki_id); + $this->success("$wiki_id unlocked"); + break; + default: + echo $options->help(); + } + } + + /** + * Check out a file + * + * @param string $wiki_id + * @param string $localfile + */ + protected function commandCheckout($wiki_id, $localfile) { + global $conf; + + $wiki_id = cleanID($wiki_id); + $wiki_fn = wikiFN($wiki_id); + + if(!file_exists($wiki_fn)) { + $this->fatal("$wiki_id does not yet exist"); + } + + if(empty($localfile)) { + $localfile = getcwd() . '/' . utf8_basename($wiki_fn); + } + + if(!file_exists(dirname($localfile))) { + $this->fatal("Directory " . dirname($localfile) . " does not exist"); + } + + if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) { + $this->fatal("Attempt to check out file into data directory - not allowed"); + } + + $this->obtainLock($wiki_id); + + if(!copy($wiki_fn, $localfile)) { + $this->clearLock($wiki_id); + $this->fatal("Unable to copy $wiki_fn to $localfile"); + } + + $this->success("$wiki_id > $localfile"); + } + + /** + * Save a file as a new page revision + * + * @param string $localfile + * @param string $wiki_id + * @param string $message + * @param bool $minor + */ + protected function commandCommit($localfile, $wiki_id, $message, $minor) { + $wiki_id = cleanID($wiki_id); + $message = trim($message); + + if(!file_exists($localfile)) { + $this->fatal("$localfile does not exist"); + } + + if(!is_readable($localfile)) { + $this->fatal("Cannot read from $localfile"); + } + + if(!$message) { + $this->fatal("Summary message required"); + } + + $this->obtainLock($wiki_id); + + saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor); + + $this->clearLock($wiki_id); + + $this->success("$localfile > $wiki_id"); + } + + /** + * Lock the given page or exit + * + * @param string $wiki_id + */ + protected function obtainLock($wiki_id) { + if($this->force) $this->deleteLock($wiki_id); + + $_SERVER['REMOTE_USER'] = $this->username; + + if(checklock($wiki_id)) { + $this->error("Page $wiki_id is already locked by another user"); + exit(1); + } + + lock($wiki_id); + + if(checklock($wiki_id)) { + $this->error("Unable to obtain lock for $wiki_id "); + var_dump(checklock($wiki_id)); + exit(1); + } + } + + /** + * Clear the lock on the given page + * + * @param string $wiki_id + */ + protected function clearLock($wiki_id) { + if($this->force) $this->deleteLock($wiki_id); + + $_SERVER['REMOTE_USER'] = $this->username; + if(checklock($wiki_id)) { + $this->error("Page $wiki_id is locked by another user"); + exit(1); + } + + unlock($wiki_id); + + if(file_exists(wikiLockFN($wiki_id))) { + $this->error("Unable to clear lock for $wiki_id"); + exit(1); + } + } + + /** + * Forcefully remove a lock on the page given + * + * @param string $wiki_id + */ + protected function deleteLock($wiki_id) { + $wikiLockFN = wikiLockFN($wiki_id); + + if(file_exists($wikiLockFN)) { + if(!unlink($wikiLockFN)) { + $this->error("Unable to delete $wikiLockFN"); + exit(1); + } + } + } + + /** + * Get the current user's username from the environment + * + * @return string + */ + protected function getUser() { + $user = getenv('USER'); + if(empty ($user)) { + $user = getenv('USERNAME'); + } else { + return $user; + } + if(empty ($user)) { + $user = 'admin'; + } + return $user; + } +} + +// Main +$cli = new PageCLI(); +$cli->run(); diff --git a/wiki/bin/gittool.php b/wiki/bin/gittool.php new file mode 100755 index 0000000..63d5b44 --- /dev/null +++ b/wiki/bin/gittool.php @@ -0,0 +1,340 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Options; + +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 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->cmd_clone($args); + break; + case 'install': + $this->cmd_install($args); + break; + case 'repo': + case 'repos': + $this->cmd_repos(); + break; + default: + $this->cmd_git($command, $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; + } + + $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(); diff --git a/wiki/bin/indexer.php b/wiki/bin/indexer.php new file mode 100755 index 0000000..4d19a95 --- /dev/null +++ b/wiki/bin/indexer.php @@ -0,0 +1,107 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Options; + +if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); +define('NOSESSION', 1); +require_once(DOKU_INC . 'inc/init.php'); + +/** + * Update the Search Index from command line + */ +class IndexerCLI extends CLI { + + private $quiet = false; + private $clear = false; + + /** + * Register options and arguments on the given $options object + * + * @param Options $options + * @return void + */ + protected function setup(Options $options) { + $options->setHelp( + 'Updates the searchindex by indexing all new or changed pages. When the -c option is ' . + 'given the index is cleared first.' + ); + + $options->registerOption( + 'clear', + 'clear the index before updating', + 'c' + ); + $options->registerOption( + 'quiet', + 'don\'t produce any output', + 'q' + ); + } + + /** + * Your main program + * + * Arguments and options have been parsed when this is run + * + * @param Options $options + * @return void + */ + protected function main(Options $options) { + $this->clear = $options->getOpt('clear'); + $this->quiet = $options->getOpt('quiet'); + + if($this->clear) $this->clearindex(); + + $this->update(); + } + + /** + * Update the index + */ + function update() { + global $conf; + $data = array(); + $this->quietecho("Searching pages... "); + search($data, $conf['datadir'], 'search_allpages', array('skipacl' => true)); + $this->quietecho(count($data) . " pages found.\n"); + + foreach($data as $val) { + $this->index($val['id']); + } + } + + /** + * Index the given page + * + * @param string $id + */ + function index($id) { + $this->quietecho("$id... "); + idx_addPage($id, !$this->quiet, $this->clear); + $this->quietecho("done.\n"); + } + + /** + * Clear all index files + */ + function clearindex() { + $this->quietecho("Clearing index... "); + idx_get_indexer()->clear(); + $this->quietecho("done.\n"); + } + + /** + * Print message if not supressed + * + * @param string $msg + */ + function quietecho($msg) { + if(!$this->quiet) echo $msg; + } +} + +// Main +$cli = new IndexerCLI(); +$cli->run(); diff --git a/wiki/bin/plugin.php b/wiki/bin/plugin.php new file mode 100755 index 0000000..cbe0b1f --- /dev/null +++ b/wiki/bin/plugin.php @@ -0,0 +1,103 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Colors; +use splitbrain\phpcli\Options; + +if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); +define('NOSESSION', 1); +require_once(DOKU_INC . 'inc/init.php'); + +class PluginCLI extends CLI { + + /** + * Register options and arguments on the given $options object + * + * @param Options $options + * @return void + */ + protected function setup(Options $options) { + $options->setHelp('Excecutes Plugin command line tools'); + $options->registerArgument('plugin', 'The plugin CLI you want to run. Leave off to see list', false); + } + + /** + * Your main program + * + * Arguments and options have been parsed when this is run + * + * @param Options $options + * @return void + */ + protected function main(Options $options) { + global $argv; + $argv = $options->getArgs(); + + if($argv) { + $plugin = $this->loadPlugin($argv[0]); + if($plugin !== null) { + $plugin->run(); + } else { + $this->fatal('Command {cmd} not found.', ['cmd' => $argv[0]]); + } + } else { + echo $options->help(); + $this->listPlugins(); + } + } + + /** + * List available plugins + */ + protected function listPlugins() { + /** @var Doku_Plugin_Controller $plugin_controller */ + global $plugin_controller; + + echo "\n"; + echo "\n"; + echo $this->colors->wrap('AVAILABLE PLUGINS:', Colors::C_BROWN); + echo "\n"; + + $list = $plugin_controller->getList('cli'); + sort($list); + if(!count($list)) { + echo $this->colors->wrap(" No plugins providing CLI components available\n", Colors::C_RED); + } else { + $tf = new \splitbrain\phpcli\TableFormatter($this->colors); + + foreach($list as $name) { + $plugin = $this->loadPlugin($name); + if($plugin === null) continue; + $info = $plugin->getInfo(); + + echo $tf->format( + [2, '30%', '*'], + ['', $name, $info['desc']], + ['', Colors::C_CYAN, ''] + + ); + } + } + } + + /** + * Instantiate a CLI plugin + * + * @param string $name + * @return DokuWiki_CLI_Plugin|null + */ + protected + function loadPlugin($name) { + // execute the plugin CLI + $class = "cli_plugin_$name"; + if(class_exists($class)) { + return new $class(); + } + return null; + } +} + +// Main +$cli = new PluginCLI(); +$cli->run(); diff --git a/wiki/bin/render.php b/wiki/bin/render.php new file mode 100755 index 0000000..cc4a003 --- /dev/null +++ b/wiki/bin/render.php @@ -0,0 +1,64 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Options; + +if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); +define('NOSESSION', 1); +require_once(DOKU_INC . 'inc/init.php'); + +/** + * A simple commandline tool to render some DokuWiki syntax with a given + * renderer. + * + * This may not work for plugins that expect a certain environment to be + * set up before rendering, but should work for most or even all standard + * DokuWiki markup + * + * @license GPL2 + * @author Andreas Gohr <andi@splitbrain.org> + */ +class RenderCLI extends CLI { + + /** + * Register options and arguments on the given $options object + * + * @param Options $options + * @return void + */ + protected function setup(Options $options) { + $options->setHelp( + 'A simple commandline tool to render some DokuWiki syntax with a given renderer.' . + "\n\n" . + 'This may not work for plugins that expect a certain environment to be ' . + 'set up before rendering, but should work for most or even all standard ' . + 'DokuWiki markup' + ); + $options->registerOption('renderer', 'The renderer mode to use. Defaults to xhtml', 'r', 'mode'); + } + + /** + * Your main program + * + * Arguments and options have been parsed when this is run + * + * @param Options $options + * @throws DokuCLI_Exception + * @return void + */ + protected function main(Options $options) { + $renderer = $options->getOpt('renderer', 'xhtml'); + + // do the action + $source = stream_get_contents(STDIN); + $info = array(); + $result = p_render($renderer, p_get_instructions($source), $info); + if(is_null($result)) throw new DokuCLI_Exception("No such renderer $renderer"); + echo $result; + } +} + +// Main +$cli = new RenderCLI(); +$cli->run(); diff --git a/wiki/bin/striplangs.php b/wiki/bin/striplangs.php new file mode 100755 index 0000000..1800971 --- /dev/null +++ b/wiki/bin/striplangs.php @@ -0,0 +1,114 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Options; + +if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); +define('NOSESSION', 1); +require_once(DOKU_INC . 'inc/init.php'); + +/** + * Remove unwanted languages from a DokuWiki install + */ +class StripLangsCLI extends CLI { + + /** + * Register options and arguments on the given $options object + * + * @param Options $options + * @return void + */ + protected function setup(Options $options) { + + $options->setHelp( + 'Remove all languages from the installation, besides the ones specified. English language ' . + 'is never removed!' + ); + + $options->registerOption( + 'keep', + 'Comma separated list of languages to keep in addition to English.', + 'k', + 'langcodes' + ); + $options->registerOption( + 'english-only', + 'Remove all languages except English', + 'e' + ); + } + + /** + * Your main program + * + * Arguments and options have been parsed when this is run + * + * @param Options $options + * @return void + */ + protected function main(Options $options) { + if($options->getOpt('keep')) { + $keep = explode(',', $options->getOpt('keep')); + if(!in_array('en', $keep)) $keep[] = 'en'; + } elseif($options->getOpt('english-only')) { + $keep = array('en'); + } else { + echo $options->help(); + exit(0); + } + + // Kill all language directories in /inc/lang and /lib/plugins besides those in $langs array + $this->stripDirLangs(realpath(dirname(__FILE__) . '/../inc/lang'), $keep); + $this->processExtensions(realpath(dirname(__FILE__) . '/../lib/plugins'), $keep); + $this->processExtensions(realpath(dirname(__FILE__) . '/../lib/tpl'), $keep); + } + + /** + * Strip languages from extensions + * + * @param string $path path to plugin or template dir + * @param array $keep_langs languages to keep + */ + protected function processExtensions($path, $keep_langs) { + if(is_dir($path)) { + $entries = scandir($path); + + foreach($entries as $entry) { + if($entry != "." && $entry != "..") { + if(is_dir($path . '/' . $entry)) { + + $plugin_langs = $path . '/' . $entry . '/lang'; + + if(is_dir($plugin_langs)) { + $this->stripDirLangs($plugin_langs, $keep_langs); + } + } + } + } + } + } + + /** + * Strip languages from path + * + * @param string $path path to lang dir + * @param array $keep_langs languages to keep + */ + protected function stripDirLangs($path, $keep_langs) { + $dir = dir($path); + + while(($cur_dir = $dir->read()) !== false) { + if($cur_dir != '.' and $cur_dir != '..' and is_dir($path . '/' . $cur_dir)) { + + if(!in_array($cur_dir, $keep_langs, true)) { + io_rmdir($path . '/' . $cur_dir, true); + } + } + } + $dir->close(); + } +} + +$cli = new StripLangsCLI(); +$cli->run(); diff --git a/wiki/bin/wantedpages.php b/wiki/bin/wantedpages.php new file mode 100755 index 0000000..0240eb9 --- /dev/null +++ b/wiki/bin/wantedpages.php @@ -0,0 +1,186 @@ +#!/usr/bin/php +<?php + +use splitbrain\phpcli\CLI; +use splitbrain\phpcli\Options; + +if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/'); +define('NOSESSION', 1); +require_once(DOKU_INC . 'inc/init.php'); + +/** + * Find wanted pages + */ +class WantedPagesCLI extends CLI { + + const DIR_CONTINUE = 1; + const DIR_NS = 2; + const DIR_PAGE = 3; + + private $skip = false; + private $sort = 'wanted'; + + private $result = array(); + + /** + * Register options and arguments on the given $options object + * + * @param Options $options + * @return void + */ + protected function setup(Options $options) { + $options->setHelp( + 'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' . + ' (the pages that are linkin to these missing pages).' + ); + $options->registerArgument( + 'namespace', + 'The namespace to lookup. Defaults to root namespace', + false + ); + + $options->registerOption( + 'sort', + 'Sort by wanted or origin page', + 's', + '(wanted|origin)' + ); + + $options->registerOption( + 'skip', + 'Do not show the second dimension', + 'k' + ); + } + + /** + * Your main program + * + * Arguments and options have been parsed when this is run + * + * @param Options $options + * @return void + */ + protected function main(Options $options) { + $args = $options->getArgs(); + if($args) { + $startdir = dirname(wikiFN($args[0] . ':xxx')); + } else { + $startdir = dirname(wikiFN('xxx')); + } + + $this->skip = $options->getOpt('skip'); + $this->sort = $options->getOpt('sort'); + + $this->info("searching $startdir"); + + foreach($this->get_pages($startdir) as $page) { + $this->internal_links($page); + } + ksort($this->result); + foreach($this->result as $main => $subs) { + if($this->skip) { + print "$main\n"; + } else { + $subs = array_unique($subs); + sort($subs); + foreach($subs as $sub) { + printf("%-40s %s\n", $main, $sub); + } + } + } + } + + /** + * Determine directions of the search loop + * + * @param string $entry + * @param string $basepath + * @return int + */ + protected function dir_filter($entry, $basepath) { + if($entry == '.' || $entry == '..') { + return WantedPagesCLI::DIR_CONTINUE; + } + if(is_dir($basepath . '/' . $entry)) { + if(strpos($entry, '_') === 0) { + return WantedPagesCLI::DIR_CONTINUE; + } + return WantedPagesCLI::DIR_NS; + } + if(preg_match('/\.txt$/', $entry)) { + return WantedPagesCLI::DIR_PAGE; + } + return WantedPagesCLI::DIR_CONTINUE; + } + + /** + * Collects recursively the pages in a namespace + * + * @param string $dir + * @return array + * @throws DokuCLI_Exception + */ + protected function get_pages($dir) { + static $trunclen = null; + if(!$trunclen) { + global $conf; + $trunclen = strlen($conf['datadir'] . ':'); + } + + if(!is_dir($dir)) { + throw new DokuCLI_Exception("Unable to read directory $dir"); + } + + $pages = array(); + $dh = opendir($dir); + while(false !== ($entry = readdir($dh))) { + $status = $this->dir_filter($entry, $dir); + if($status == WantedPagesCLI::DIR_CONTINUE) { + continue; + } else if($status == WantedPagesCLI::DIR_NS) { + $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry)); + } else { + $page = array( + 'id' => pathID(substr($dir . '/' . $entry, $trunclen)), + 'file' => $dir . '/' . $entry, + ); + $pages[] = $page; + } + } + closedir($dh); + return $pages; + } + + /** + * Parse instructions and add the non-existing links to the result array + * + * @param array $page array with page id and file path + */ + function internal_links($page) { + global $conf; + $instructions = p_get_instructions(file_get_contents($page['file'])); + $cns = getNS($page['id']); + $exists = false; + $pid = $page['id']; + foreach($instructions as $ins) { + if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) { + $mid = $ins[1][0]; + resolve_pageid($cns, $mid, $exists); + if(!$exists) { + list($mid) = explode('#', $mid); //record pages without hashes + + if($this->sort == 'origin') { + $this->result[$pid][] = $mid; + } else { + $this->result[$mid][] = $pid; + } + } + } + } + } +} + +// Main +$cli = new WantedPagesCLI(); +$cli->run(); |