136c0b2b4SAndreas Gohr#!/usr/bin/env php 236c0b2b4SAndreas Gohr<?php 336c0b2b4SAndreas Gohr 436c0b2b4SAndreas Gohruse dokuwiki\Extension\CLIPlugin; 536c0b2b4SAndreas Gohruse dokuwiki\Extension\PluginController; 6*5586e97bSAndreas Gohruse dokuwiki\plugin\dev\LangProcessor; 71a23d1dbSAndreas Gohruse dokuwiki\plugin\dev\SVGIcon; 836c0b2b4SAndreas Gohruse splitbrain\phpcli\Exception as CliException; 936c0b2b4SAndreas Gohruse splitbrain\phpcli\Options; 1036c0b2b4SAndreas Gohr 1136c0b2b4SAndreas Gohr/** 1236c0b2b4SAndreas Gohr * @license GPL2 1336c0b2b4SAndreas Gohr * @author Andreas Gohr <andi@splitbrain.org> 1436c0b2b4SAndreas Gohr */ 1536c0b2b4SAndreas Gohrclass cli_plugin_dev extends CLIPlugin 1636c0b2b4SAndreas Gohr{ 1736c0b2b4SAndreas Gohr /** 1836c0b2b4SAndreas Gohr * Register options and arguments on the given $options object 1936c0b2b4SAndreas Gohr * 2036c0b2b4SAndreas Gohr * @param Options $options 2136c0b2b4SAndreas Gohr * @return void 2236c0b2b4SAndreas Gohr */ 2336c0b2b4SAndreas Gohr protected function setup(Options $options) 2436c0b2b4SAndreas Gohr { 25f2576912SAndreas Gohr $options->useCompactHelp(); 2636c0b2b4SAndreas Gohr $options->setHelp( 27f2576912SAndreas Gohr "CLI to help with DokuWiki plugin and template development.\n\n" . 2836c0b2b4SAndreas Gohr "Run this script from within the extension's directory." 2936c0b2b4SAndreas Gohr ); 3036c0b2b4SAndreas Gohr 31f2576912SAndreas Gohr $options->registerCommand('init', 'Initialize a new plugin or template in the current (empty) directory.'); 32f2576912SAndreas Gohr $options->registerCommand('addTest', 'Add the testing framework files and a test. (_test/)'); 33f2576912SAndreas Gohr $options->registerArgument('test', 'Optional name of the new test. Defaults to the general test.', false, 34f2576912SAndreas Gohr 'addTest'); 35f2576912SAndreas Gohr $options->registerCommand('addConf', 'Add the configuration files. (conf/)'); 36f2576912SAndreas Gohr $options->registerCommand('addLang', 'Add the language files. (lang/)'); 3736c0b2b4SAndreas Gohr 38f2576912SAndreas Gohr $types = PluginController::PLUGIN_TYPES; 39f2576912SAndreas Gohr array_walk( 40f2576912SAndreas Gohr $types, 41f2576912SAndreas Gohr function (&$item) { 42f2576912SAndreas Gohr $item = $this->colors->wrap($item, $this->colors::C_BROWN); 43f2576912SAndreas Gohr } 4436c0b2b4SAndreas Gohr ); 4536c0b2b4SAndreas Gohr 46f2576912SAndreas Gohr $options->registerCommand('addComponent', 'Add a new plugin component.'); 47f2576912SAndreas Gohr $options->registerArgument('type', 'Type of the component. Needs to be one of ' . join(', ', $types), true, 48f2576912SAndreas Gohr 'addComponent'); 49f2576912SAndreas Gohr $options->registerArgument('name', 'Optional name of the component. Defaults to a base component.', false, 50f2576912SAndreas Gohr 'addComponent'); 51f2576912SAndreas Gohr 52f2576912SAndreas Gohr $options->registerCommand('deletedFiles', 'Create the list of deleted files based on the git history.'); 53f2576912SAndreas Gohr $options->registerCommand('rmObsolete', 'Delete obsolete files.'); 541a23d1dbSAndreas Gohr 551a23d1dbSAndreas Gohr $prefixes = array_keys(SVGIcon::SOURCES); 561a23d1dbSAndreas Gohr array_walk( 571a23d1dbSAndreas Gohr $prefixes, 581a23d1dbSAndreas Gohr function (&$item) { 591a23d1dbSAndreas Gohr $item = $this->colors->wrap($item, $this->colors::C_BROWN); 601a23d1dbSAndreas Gohr } 611a23d1dbSAndreas Gohr ); 621a23d1dbSAndreas Gohr 631a23d1dbSAndreas Gohr $options->registerCommand('downloadSvg', 'Download an SVG file from a known icon repository.'); 641a23d1dbSAndreas Gohr $options->registerArgument('prefix:name', 651a23d1dbSAndreas Gohr 'Colon-prefixed name of the icon. Available prefixes: ' . join(', ', $prefixes), true, 'downloadSvg'); 661a23d1dbSAndreas Gohr $options->registerArgument('output', 'File to save, defaults to <name>.svg in current dir', false, 671a23d1dbSAndreas Gohr 'downloadSvg'); 6892738407SAndreas Gohr $options->registerOption('keep-ns', 'Keep the SVG namespace. Use when the file is not inlined into HTML.', 'k', 6992738407SAndreas Gohr false, 'downloadSvg'); 701a23d1dbSAndreas Gohr 718f82d673SAndreas Gohr $options->registerCommand('cleanSvg', 'Clean a existing SVG files to reduce their file size.'); 728f82d673SAndreas Gohr $options->registerArgument('files...', 'The files to clean (will be overwritten)', true, 'cleanSvg'); 7392738407SAndreas Gohr $options->registerOption('keep-ns', 'Keep the SVG namespace. Use when the file is not inlined into HTML.', 'k', 7492738407SAndreas Gohr false, 'cleanSvg'); 75*5586e97bSAndreas Gohr 76*5586e97bSAndreas Gohr $options->registerCommand('cleanLang', 77*5586e97bSAndreas Gohr 'Clean language files from unused language strings. Detecting which strings are truly in use may '. 78*5586e97bSAndreas Gohr 'not always correctly work. Use with caution.'); 7936c0b2b4SAndreas Gohr } 8036c0b2b4SAndreas Gohr 8136c0b2b4SAndreas Gohr /** @inheritDoc */ 8236c0b2b4SAndreas Gohr protected function main(Options $options) 8336c0b2b4SAndreas Gohr { 841a23d1dbSAndreas Gohr $args = $options->getArgs(); 851a23d1dbSAndreas Gohr 8636c0b2b4SAndreas Gohr switch ($options->getCmd()) { 8736c0b2b4SAndreas Gohr case 'init': 8836c0b2b4SAndreas Gohr return $this->cmdInit(); 8936c0b2b4SAndreas Gohr case 'addTest': 9036c0b2b4SAndreas Gohr $test = array_shift($args); 9136c0b2b4SAndreas Gohr return $this->cmdAddTest($test); 9236c0b2b4SAndreas Gohr case 'addConf': 9336c0b2b4SAndreas Gohr return $this->cmdAddConf(); 9436c0b2b4SAndreas Gohr case 'addLang': 9536c0b2b4SAndreas Gohr return $this->cmdAddLang(); 9636c0b2b4SAndreas Gohr case 'addComponent': 9736c0b2b4SAndreas Gohr $type = array_shift($args); 9836c0b2b4SAndreas Gohr $component = array_shift($args); 9936c0b2b4SAndreas Gohr return $this->cmdAddComponent($type, $component); 10036c0b2b4SAndreas Gohr case 'deletedFiles': 10136c0b2b4SAndreas Gohr return $this->cmdDeletedFiles(); 102c5c85a97SAndreas Gohr case 'rmObsolete': 1031a23d1dbSAndreas Gohr return $this->cmdRmObsolete(); 1041a23d1dbSAndreas Gohr case 'downloadSvg': 1051a23d1dbSAndreas Gohr $ident = array_shift($args); 1061a23d1dbSAndreas Gohr $save = array_shift($args); 10792738407SAndreas Gohr $keep = $options->getOpt('keep-ns', false); 10892738407SAndreas Gohr return $this->cmdDownloadSVG($ident, $save, $keep); 1091a23d1dbSAndreas Gohr case 'cleanSvg': 11092738407SAndreas Gohr $keep = $options->getOpt('keep-ns', false); 1118f82d673SAndreas Gohr return $this->cmdCleanSVG($args, $keep); 112*5586e97bSAndreas Gohr case 'cleanLang': 113*5586e97bSAndreas Gohr return $this->cmdCleanLang(); 11436c0b2b4SAndreas Gohr default: 1151a23d1dbSAndreas Gohr $this->error('Unknown command'); 11636c0b2b4SAndreas Gohr echo $options->help(); 11736c0b2b4SAndreas Gohr return 0; 11836c0b2b4SAndreas Gohr } 11936c0b2b4SAndreas Gohr } 12036c0b2b4SAndreas Gohr 12136c0b2b4SAndreas Gohr /** 12236c0b2b4SAndreas Gohr * Get the extension name from the current working directory 12336c0b2b4SAndreas Gohr * 12436c0b2b4SAndreas Gohr * @throws CliException if something's wrong 12536c0b2b4SAndreas Gohr * @param string $dir 12636c0b2b4SAndreas Gohr * @return string[] name, type 12736c0b2b4SAndreas Gohr */ 12836c0b2b4SAndreas Gohr protected function getTypedNameFromDir($dir) 12936c0b2b4SAndreas Gohr { 13036c0b2b4SAndreas Gohr $pdir = fullpath(DOKU_PLUGIN); 13136c0b2b4SAndreas Gohr $tdir = fullpath(tpl_incdir() . '../'); 13236c0b2b4SAndreas Gohr 13336c0b2b4SAndreas Gohr if (strpos($dir, $pdir) === 0) { 13436c0b2b4SAndreas Gohr $ldir = substr($dir, strlen($pdir)); 13536c0b2b4SAndreas Gohr $type = 'plugin'; 13636c0b2b4SAndreas Gohr } elseif (strpos($dir, $tdir) === 0) { 13736c0b2b4SAndreas Gohr $ldir = substr($dir, strlen($tdir)); 13836c0b2b4SAndreas Gohr $type = 'template'; 13936c0b2b4SAndreas Gohr } else { 14036c0b2b4SAndreas Gohr throw new CliException('Current directory needs to be in plugin or template directory'); 14136c0b2b4SAndreas Gohr } 14236c0b2b4SAndreas Gohr 14336c0b2b4SAndreas Gohr $ldir = trim($ldir, '/'); 14436c0b2b4SAndreas Gohr 14536c0b2b4SAndreas Gohr if (strpos($ldir, '/') !== false) { 14636c0b2b4SAndreas Gohr throw new CliException('Current directory has to be main extension directory'); 14736c0b2b4SAndreas Gohr } 14836c0b2b4SAndreas Gohr 14936c0b2b4SAndreas Gohr return [$ldir, $type]; 15036c0b2b4SAndreas Gohr } 15136c0b2b4SAndreas Gohr 15236c0b2b4SAndreas Gohr /** 15336c0b2b4SAndreas Gohr * Interactively ask for a value from the user 15436c0b2b4SAndreas Gohr * 15536c0b2b4SAndreas Gohr * @param string $prompt 15636c0b2b4SAndreas Gohr * @param bool $cache cache given value for next time? 15736c0b2b4SAndreas Gohr * @return string 15836c0b2b4SAndreas Gohr */ 15936c0b2b4SAndreas Gohr protected function readLine($prompt, $cache = false) 16036c0b2b4SAndreas Gohr { 16136c0b2b4SAndreas Gohr $value = ''; 16236c0b2b4SAndreas Gohr $default = ''; 16336c0b2b4SAndreas Gohr $cachename = getCacheName($prompt, '.readline'); 16436c0b2b4SAndreas Gohr if ($cache && file_exists($cachename)) { 16536c0b2b4SAndreas Gohr $default = file_get_contents($cachename); 16636c0b2b4SAndreas Gohr } 16736c0b2b4SAndreas Gohr 16836c0b2b4SAndreas Gohr while ($value === '') { 16936c0b2b4SAndreas Gohr echo $prompt; 17036c0b2b4SAndreas Gohr if ($default) echo ' [' . $default . ']'; 17136c0b2b4SAndreas Gohr echo ': '; 17236c0b2b4SAndreas Gohr 17336c0b2b4SAndreas Gohr $fh = fopen('php://stdin', 'r'); 17436c0b2b4SAndreas Gohr $value = trim(fgets($fh)); 17536c0b2b4SAndreas Gohr fclose($fh); 17636c0b2b4SAndreas Gohr 17736c0b2b4SAndreas Gohr if ($value === '') $value = $default; 17836c0b2b4SAndreas Gohr } 17936c0b2b4SAndreas Gohr 18036c0b2b4SAndreas Gohr if ($cache) { 18136c0b2b4SAndreas Gohr file_put_contents($cachename, $value); 18236c0b2b4SAndreas Gohr } 18336c0b2b4SAndreas Gohr 18436c0b2b4SAndreas Gohr return $value; 18536c0b2b4SAndreas Gohr } 18636c0b2b4SAndreas Gohr 18736c0b2b4SAndreas Gohr /** 18836c0b2b4SAndreas Gohr * Download a skeleton file and do the replacements 18936c0b2b4SAndreas Gohr * 19036c0b2b4SAndreas Gohr * @param string $skel Skeleton relative to the skel dir in the repo 19136c0b2b4SAndreas Gohr * @param string $target Target file relative to the main directory 19236c0b2b4SAndreas Gohr * @param array $replacements 19336c0b2b4SAndreas Gohr */ 19436c0b2b4SAndreas Gohr protected function loadSkeleton($skel, $target, $replacements) 19536c0b2b4SAndreas Gohr { 19636c0b2b4SAndreas Gohr if (file_exists($target)) { 19736c0b2b4SAndreas Gohr $this->error($target . ' already exists'); 19836c0b2b4SAndreas Gohr return; 19936c0b2b4SAndreas Gohr } 20036c0b2b4SAndreas Gohr 20136c0b2b4SAndreas Gohr $base = 'https://raw.githubusercontent.com/dokufreaks/dokuwiki-plugin-wizard/master/skel/'; 20236c0b2b4SAndreas Gohr $http = new \dokuwiki\HTTP\DokuHTTPClient(); 20336c0b2b4SAndreas Gohr $content = $http->get($base . $skel); 20436c0b2b4SAndreas Gohr 20536c0b2b4SAndreas Gohr $content = str_replace( 20636c0b2b4SAndreas Gohr array_keys($replacements), 20736c0b2b4SAndreas Gohr array_values($replacements), 20836c0b2b4SAndreas Gohr $content 20936c0b2b4SAndreas Gohr ); 21036c0b2b4SAndreas Gohr 21136c0b2b4SAndreas Gohr io_makeFileDir($target); 21236c0b2b4SAndreas Gohr file_put_contents($target, $content); 21336c0b2b4SAndreas Gohr $this->success('Added ' . $target); 21436c0b2b4SAndreas Gohr } 21536c0b2b4SAndreas Gohr 21636c0b2b4SAndreas Gohr /** 21736c0b2b4SAndreas Gohr * Prepare the string replacements 21836c0b2b4SAndreas Gohr * 21936c0b2b4SAndreas Gohr * @param array $replacements override defaults 22036c0b2b4SAndreas Gohr * @return array 22136c0b2b4SAndreas Gohr */ 22236c0b2b4SAndreas Gohr protected function prepareReplacements($replacements = []) 22336c0b2b4SAndreas Gohr { 22436c0b2b4SAndreas Gohr // defaults 22536c0b2b4SAndreas Gohr $data = [ 22636c0b2b4SAndreas Gohr '@@AUTHOR_NAME@@' => '', 22736c0b2b4SAndreas Gohr '@@AUTHOR_MAIL@@' => '', 22836c0b2b4SAndreas Gohr '@@PLUGIN_NAME@@' => '', 22936c0b2b4SAndreas Gohr '@@PLUGIN_DESC@@' => '', 23036c0b2b4SAndreas Gohr '@@PLUGIN_URL@@' => '', 23136c0b2b4SAndreas Gohr '@@PLUGIN_TYPE@@' => '', 23236c0b2b4SAndreas Gohr '@@INSTALL_DIR@@' => 'plugins', 23336c0b2b4SAndreas Gohr '@@DATE@@' => date('Y-m-d'), 23436c0b2b4SAndreas Gohr ]; 23536c0b2b4SAndreas Gohr 23636c0b2b4SAndreas Gohr // load from existing plugin.info 23736c0b2b4SAndreas Gohr $dir = fullpath(getcwd()); 23836c0b2b4SAndreas Gohr [$name, $type] = $this->getTypedNameFromDir($dir); 23936c0b2b4SAndreas Gohr if (file_exists("$type.info.txt")) { 24036c0b2b4SAndreas Gohr $info = confToHash("$type.info.txt"); 24136c0b2b4SAndreas Gohr $data['@@AUTHOR_NAME@@'] = $info['author']; 24236c0b2b4SAndreas Gohr $data['@@AUTHOR_MAIL@@'] = $info['email']; 24336c0b2b4SAndreas Gohr $data['@@PLUGIN_DESC@@'] = $info['desc']; 24436c0b2b4SAndreas Gohr $data['@@PLUGIN_URL@@'] = $info['url']; 24536c0b2b4SAndreas Gohr } 24636c0b2b4SAndreas Gohr $data['@@PLUGIN_NAME@@'] = $name; 24736c0b2b4SAndreas Gohr $data['@@PLUGIN_TYPE@@'] = $type; 24836c0b2b4SAndreas Gohr 24936c0b2b4SAndreas Gohr if ($type == 'template') { 25036c0b2b4SAndreas Gohr $data['@@INSTALL_DIR@@'] = 'tpl'; 25136c0b2b4SAndreas Gohr } 25236c0b2b4SAndreas Gohr 25336c0b2b4SAndreas Gohr // merge given overrides 25436c0b2b4SAndreas Gohr $data = array_merge($data, $replacements); 25536c0b2b4SAndreas Gohr 25636c0b2b4SAndreas Gohr // set inherited defaults 25736c0b2b4SAndreas Gohr if (empty($data['@@PLUGIN_URL@@'])) { 25836c0b2b4SAndreas Gohr $data['@@PLUGIN_URL@@'] = 25936c0b2b4SAndreas Gohr 'https://www.dokuwiki.org/' . 26036c0b2b4SAndreas Gohr $data['@@PLUGIN_TYPE@@'] . ':' . 26136c0b2b4SAndreas Gohr $data['@@PLUGIN_NAME@@']; 26236c0b2b4SAndreas Gohr } 26336c0b2b4SAndreas Gohr 26436c0b2b4SAndreas Gohr return $data; 26536c0b2b4SAndreas Gohr } 26636c0b2b4SAndreas Gohr 26736c0b2b4SAndreas Gohr /** 26836c0b2b4SAndreas Gohr * Replacements needed for action components. 26936c0b2b4SAndreas Gohr * 27036c0b2b4SAndreas Gohr * Not cool but that' what we need currently 27136c0b2b4SAndreas Gohr * 27236c0b2b4SAndreas Gohr * @return string[] 27336c0b2b4SAndreas Gohr */ 27436c0b2b4SAndreas Gohr protected function actionReplacements() 27536c0b2b4SAndreas Gohr { 27636c0b2b4SAndreas Gohr $fn = 'handleEventName'; 27736c0b2b4SAndreas Gohr $register = ' $controller->register_hook(\'EVENT_NAME\', \'AFTER|BEFORE\', $this, \'' . $fn . '\');'; 27836c0b2b4SAndreas Gohr $handler = ' public function ' . $fn . '(Doku_Event $event, $param)' . "\n" 27936c0b2b4SAndreas Gohr . " {\n" 28036c0b2b4SAndreas Gohr . " }\n"; 28136c0b2b4SAndreas Gohr 28236c0b2b4SAndreas Gohr return [ 28336c0b2b4SAndreas Gohr '@@REGISTER@@' => $register . "\n ", 28436c0b2b4SAndreas Gohr '@@HANDLERS@@' => $handler, 28536c0b2b4SAndreas Gohr ]; 28636c0b2b4SAndreas Gohr } 28736c0b2b4SAndreas Gohr 28836c0b2b4SAndreas Gohr /** 289c5c85a97SAndreas Gohr * Delete the given file if it exists 290c5c85a97SAndreas Gohr * 291c5c85a97SAndreas Gohr * @param string $file 292c5c85a97SAndreas Gohr */ 293c5c85a97SAndreas Gohr protected function deleteFile($file) 294c5c85a97SAndreas Gohr { 295c5c85a97SAndreas Gohr if (!file_exists($file)) return; 296c5c85a97SAndreas Gohr if (@unlink($file)) { 297c5c85a97SAndreas Gohr $this->success('Delete ' . $file); 298c5c85a97SAndreas Gohr } 299c5c85a97SAndreas Gohr } 300c5c85a97SAndreas Gohr 301c5c85a97SAndreas Gohr /** 302c5c85a97SAndreas Gohr * Run git with the given arguments and return the output 303c5c85a97SAndreas Gohr * 304c5c85a97SAndreas Gohr * @throws CliException when the command can't be run 305c5c85a97SAndreas Gohr * @param string ...$args 306c5c85a97SAndreas Gohr * @return string[] 307c5c85a97SAndreas Gohr */ 308c5c85a97SAndreas Gohr protected function git(...$args) 309c5c85a97SAndreas Gohr { 310c5c85a97SAndreas Gohr $args = array_map('escapeshellarg', $args); 311c5c85a97SAndreas Gohr $cmd = 'git ' . join(' ', $args); 312c5c85a97SAndreas Gohr $output = []; 313c5c85a97SAndreas Gohr $result = 0; 314c5c85a97SAndreas Gohr 315c5c85a97SAndreas Gohr $this->info($cmd); 316c5c85a97SAndreas Gohr $last = exec($cmd, $output, $result); 317c5c85a97SAndreas Gohr if ($last === false || $result !== 0) { 318c5c85a97SAndreas Gohr throw new CliException('Running git failed'); 319c5c85a97SAndreas Gohr } 320c5c85a97SAndreas Gohr 321c5c85a97SAndreas Gohr return $output; 322c5c85a97SAndreas Gohr } 323c5c85a97SAndreas Gohr 324c5c85a97SAndreas Gohr // region Commands 325c5c85a97SAndreas Gohr 326c5c85a97SAndreas Gohr /** 32736c0b2b4SAndreas Gohr * Intialize the current directory as a plugin or template 32836c0b2b4SAndreas Gohr * 32936c0b2b4SAndreas Gohr * @return int 33036c0b2b4SAndreas Gohr */ 33136c0b2b4SAndreas Gohr protected function cmdInit() 33236c0b2b4SAndreas Gohr { 33336c0b2b4SAndreas Gohr $dir = fullpath(getcwd()); 33436c0b2b4SAndreas Gohr if ((new FilesystemIterator($dir))->valid()) { 33536c0b2b4SAndreas Gohr throw new CliException('Current directory needs to be empty'); 33636c0b2b4SAndreas Gohr } 33736c0b2b4SAndreas Gohr 33836c0b2b4SAndreas Gohr [$name, $type] = $this->getTypedNameFromDir($dir); 33936c0b2b4SAndreas Gohr $user = $this->readLine('Your Name', true); 34036c0b2b4SAndreas Gohr $mail = $this->readLine('Your E-Mail', true); 34136c0b2b4SAndreas Gohr $desc = $this->readLine('Short description'); 34236c0b2b4SAndreas Gohr 34336c0b2b4SAndreas Gohr $replacements = [ 34436c0b2b4SAndreas Gohr '@@AUTHOR_NAME@@' => $user, 34536c0b2b4SAndreas Gohr '@@AUTHOR_MAIL@@' => $mail, 34636c0b2b4SAndreas Gohr '@@PLUGIN_NAME@@' => $name, 34736c0b2b4SAndreas Gohr '@@PLUGIN_DESC@@' => $desc, 34836c0b2b4SAndreas Gohr '@@PLUGIN_TYPE@@' => $type, 34936c0b2b4SAndreas Gohr ]; 35036c0b2b4SAndreas Gohr $replacements = $this->prepareReplacements($replacements); 35136c0b2b4SAndreas Gohr 35236c0b2b4SAndreas Gohr $this->loadSkeleton('info.skel', $type . '.info.txt', $replacements); 35336c0b2b4SAndreas Gohr $this->loadSkeleton('README.skel', 'README', $replacements); // fixme needs to be type specific 35436c0b2b4SAndreas Gohr $this->loadSkeleton('LICENSE.skel', 'LICENSE', $replacements); 35536c0b2b4SAndreas Gohr 3568b06c9ddSAndreas Gohr try { 3578b06c9ddSAndreas Gohr $this->git('init'); 3588b06c9ddSAndreas Gohr } catch (CliException $e) { 3598b06c9ddSAndreas Gohr $this->error($e->getMessage()); 3608b06c9ddSAndreas Gohr } 3618b06c9ddSAndreas Gohr 36236c0b2b4SAndreas Gohr return 0; 36336c0b2b4SAndreas Gohr } 36436c0b2b4SAndreas Gohr 36536c0b2b4SAndreas Gohr /** 36636c0b2b4SAndreas Gohr * Add test framework 36736c0b2b4SAndreas Gohr * 36836c0b2b4SAndreas Gohr * @param string $test Name of the Test to add 36936c0b2b4SAndreas Gohr * @return int 37036c0b2b4SAndreas Gohr */ 37136c0b2b4SAndreas Gohr protected function cmdAddTest($test = '') 37236c0b2b4SAndreas Gohr { 37336c0b2b4SAndreas Gohr $test = ucfirst(strtolower($test)); 37436c0b2b4SAndreas Gohr 37536c0b2b4SAndreas Gohr $replacements = $this->prepareReplacements(['@@TEST@@' => $test]); 37636c0b2b4SAndreas Gohr $this->loadSkeleton('.github/workflows/phpTestLinux.skel', '.github/workflows/phpTestLinux.yml', $replacements); 37736c0b2b4SAndreas Gohr if ($test) { 37836c0b2b4SAndreas Gohr $this->loadSkeleton('_test/StandardTest.skel', '_test/' . $test . 'Test.php', $replacements); 37936c0b2b4SAndreas Gohr } else { 38036c0b2b4SAndreas Gohr $this->loadSkeleton('_test/GeneralTest.skel', '_test/GeneralTest.php', $replacements); 38136c0b2b4SAndreas Gohr } 38236c0b2b4SAndreas Gohr 38336c0b2b4SAndreas Gohr return 0; 38436c0b2b4SAndreas Gohr } 38536c0b2b4SAndreas Gohr 38636c0b2b4SAndreas Gohr /** 38736c0b2b4SAndreas Gohr * Add configuration 38836c0b2b4SAndreas Gohr * 38936c0b2b4SAndreas Gohr * @return int 39036c0b2b4SAndreas Gohr */ 39136c0b2b4SAndreas Gohr protected function cmdAddConf() 39236c0b2b4SAndreas Gohr { 39336c0b2b4SAndreas Gohr $replacements = $this->prepareReplacements(); 39436c0b2b4SAndreas Gohr $this->loadSkeleton('conf/default.skel', 'conf/default.php', $replacements); 39536c0b2b4SAndreas Gohr $this->loadSkeleton('conf/metadata.skel', 'conf/metadata.php', $replacements); 39636c0b2b4SAndreas Gohr if (is_dir('lang')) { 39736c0b2b4SAndreas Gohr $this->loadSkeleton('lang/settings.skel', 'lang/en/settings.php', $replacements); 39836c0b2b4SAndreas Gohr } 39936c0b2b4SAndreas Gohr 40036c0b2b4SAndreas Gohr return 0; 40136c0b2b4SAndreas Gohr } 40236c0b2b4SAndreas Gohr 40336c0b2b4SAndreas Gohr /** 40436c0b2b4SAndreas Gohr * Add language 40536c0b2b4SAndreas Gohr * 40636c0b2b4SAndreas Gohr * @return int 40736c0b2b4SAndreas Gohr */ 40836c0b2b4SAndreas Gohr protected function cmdAddLang() 40936c0b2b4SAndreas Gohr { 41036c0b2b4SAndreas Gohr $replacements = $this->prepareReplacements(); 41136c0b2b4SAndreas Gohr $this->loadSkeleton('lang/lang.skel', 'lang/en/lang.php', $replacements); 41236c0b2b4SAndreas Gohr if (is_dir('conf')) { 41336c0b2b4SAndreas Gohr $this->loadSkeleton('lang/settings.skel', 'lang/en/settings.php', $replacements); 41436c0b2b4SAndreas Gohr } 41536c0b2b4SAndreas Gohr 41636c0b2b4SAndreas Gohr return 0; 41736c0b2b4SAndreas Gohr } 41836c0b2b4SAndreas Gohr 41936c0b2b4SAndreas Gohr /** 42036c0b2b4SAndreas Gohr * Add another component to the plugin 42136c0b2b4SAndreas Gohr * 42236c0b2b4SAndreas Gohr * @param string $type 42336c0b2b4SAndreas Gohr * @param string $component 42436c0b2b4SAndreas Gohr */ 42536c0b2b4SAndreas Gohr protected function cmdAddComponent($type, $component = '') 42636c0b2b4SAndreas Gohr { 42736c0b2b4SAndreas Gohr $dir = fullpath(getcwd()); 42836c0b2b4SAndreas Gohr list($plugin, $extension) = $this->getTypedNameFromDir($dir); 42936c0b2b4SAndreas Gohr if ($extension != 'plugin') throw new CliException('Components can only be added to plugins'); 43036c0b2b4SAndreas Gohr if (!in_array($type, PluginController::PLUGIN_TYPES)) { 43136c0b2b4SAndreas Gohr throw new CliException('Invalid type ' . $type); 43236c0b2b4SAndreas Gohr } 43336c0b2b4SAndreas Gohr 43436c0b2b4SAndreas Gohr if ($component) { 43536c0b2b4SAndreas Gohr $path = $type . '/' . $component . '.php'; 43636c0b2b4SAndreas Gohr $class = $type . '_plugin_' . $plugin . '_' . $component; 43736c0b2b4SAndreas Gohr $self = $plugin . '_' . $component; 43836c0b2b4SAndreas Gohr } else { 43936c0b2b4SAndreas Gohr $path = $type . '.php'; 44036c0b2b4SAndreas Gohr $class = $type . '_plugin_' . $plugin; 44136c0b2b4SAndreas Gohr $self = $plugin; 44236c0b2b4SAndreas Gohr } 44336c0b2b4SAndreas Gohr 44436c0b2b4SAndreas Gohr $replacements = $this->actionReplacements(); 44536c0b2b4SAndreas Gohr $replacements['@@PLUGIN_COMPONENT_NAME@@'] = $class; 44636c0b2b4SAndreas Gohr $replacements['@@SYNTAX_COMPONENT_NAME@@'] = $self; 44736c0b2b4SAndreas Gohr $replacements = $this->prepareReplacements($replacements); 44836c0b2b4SAndreas Gohr $this->loadSkeleton($type . '.skel', $path, $replacements); 44936c0b2b4SAndreas Gohr 45036c0b2b4SAndreas Gohr return 0; 45136c0b2b4SAndreas Gohr } 45236c0b2b4SAndreas Gohr 45336c0b2b4SAndreas Gohr /** 45436c0b2b4SAndreas Gohr * Generate a list of deleted files from git 45536c0b2b4SAndreas Gohr * 45636c0b2b4SAndreas Gohr * @link https://stackoverflow.com/a/6018049/172068 45736c0b2b4SAndreas Gohr */ 45836c0b2b4SAndreas Gohr protected function cmdDeletedFiles() 45936c0b2b4SAndreas Gohr { 4608b06c9ddSAndreas Gohr if (!is_dir('.git')) throw new CliException('This extension seems not to be managed by git'); 46136c0b2b4SAndreas Gohr 4628b06c9ddSAndreas Gohr $output = $this->git('log', '--no-renames', '--pretty=format:', '--name-only', '--diff-filter=D'); 46336c0b2b4SAndreas Gohr $output = array_map('trim', $output); 46436c0b2b4SAndreas Gohr $output = array_filter($output); 46536c0b2b4SAndreas Gohr $output = array_unique($output); 46636c0b2b4SAndreas Gohr $output = array_filter($output, function ($item) { 46736c0b2b4SAndreas Gohr return !file_exists($item); 46836c0b2b4SAndreas Gohr }); 46936c0b2b4SAndreas Gohr sort($output); 47036c0b2b4SAndreas Gohr 47136c0b2b4SAndreas Gohr if (!count($output)) { 47236c0b2b4SAndreas Gohr $this->info('No deleted files found'); 47336c0b2b4SAndreas Gohr return 0; 47436c0b2b4SAndreas Gohr } 47536c0b2b4SAndreas Gohr 47636c0b2b4SAndreas Gohr $content = "# This is a list of files that were present in previous releases\n" . 47736c0b2b4SAndreas Gohr "# but were removed later. They should not exist in your installation.\n" . 47836c0b2b4SAndreas Gohr join("\n", $output) . "\n"; 47936c0b2b4SAndreas Gohr 48036c0b2b4SAndreas Gohr file_put_contents('deleted.files', $content); 48136c0b2b4SAndreas Gohr $this->success('written deleted.files'); 48236c0b2b4SAndreas Gohr return 0; 48336c0b2b4SAndreas Gohr } 4848b06c9ddSAndreas Gohr 4858b06c9ddSAndreas Gohr /** 486c5c85a97SAndreas Gohr * Remove files that shouldn't be here anymore 4878b06c9ddSAndreas Gohr */ 4881a23d1dbSAndreas Gohr protected function cmdRmObsolete() 4898b06c9ddSAndreas Gohr { 490c5c85a97SAndreas Gohr $this->deleteFile('_test/general.test.php'); 491c5c85a97SAndreas Gohr $this->deleteFile('.travis.yml'); 4928b06c9ddSAndreas Gohr 493c5c85a97SAndreas Gohr return 0; 4948b06c9ddSAndreas Gohr } 4958b06c9ddSAndreas Gohr 4961a23d1dbSAndreas Gohr /** 4971a23d1dbSAndreas Gohr * Download a remote icon 4981a23d1dbSAndreas Gohr * 4991a23d1dbSAndreas Gohr * @param string $ident 5001a23d1dbSAndreas Gohr * @param string $save 50192738407SAndreas Gohr * @param bool $keep 5021a23d1dbSAndreas Gohr * @return int 5031a23d1dbSAndreas Gohr * @throws Exception 5041a23d1dbSAndreas Gohr */ 50592738407SAndreas Gohr protected function cmdDownloadSVG($ident, $save = '', $keep = false) 5061a23d1dbSAndreas Gohr { 5071a23d1dbSAndreas Gohr $svg = new SVGIcon($this); 50892738407SAndreas Gohr $svg->keepNamespace($keep); 5091a23d1dbSAndreas Gohr return (int)$svg->downloadRemoteIcon($ident, $save); 5101a23d1dbSAndreas Gohr } 5111a23d1dbSAndreas Gohr 5121a23d1dbSAndreas Gohr /** 5138f82d673SAndreas Gohr * @param string[] $files 51492738407SAndreas Gohr * @param bool $keep 5151a23d1dbSAndreas Gohr * @return int 5161a23d1dbSAndreas Gohr * @throws Exception 5171a23d1dbSAndreas Gohr */ 5188f82d673SAndreas Gohr protected function cmdCleanSVG($files, $keep = false) 5191a23d1dbSAndreas Gohr { 5201a23d1dbSAndreas Gohr $svg = new SVGIcon($this); 52192738407SAndreas Gohr $svg->keepNamespace($keep); 5228f82d673SAndreas Gohr 5238f82d673SAndreas Gohr $ok = true; 5248f82d673SAndreas Gohr foreach ($files as $file) { 5258f82d673SAndreas Gohr $ok = $ok && $svg->cleanSVGFile($file); 5268f82d673SAndreas Gohr } 5278f82d673SAndreas Gohr return (int)$ok; 5281a23d1dbSAndreas Gohr } 5291a23d1dbSAndreas Gohr 530*5586e97bSAndreas Gohr /** 531*5586e97bSAndreas Gohr * @return int 532*5586e97bSAndreas Gohr */ 533*5586e97bSAndreas Gohr protected function cmdCleanLang() 534*5586e97bSAndreas Gohr { 535*5586e97bSAndreas Gohr $lp = new LangProcessor($this); 536*5586e97bSAndreas Gohr 537*5586e97bSAndreas Gohr $files = glob('./lang/*/lang.php'); 538*5586e97bSAndreas Gohr foreach ($files as $file) { 539*5586e97bSAndreas Gohr $lp->processLangFile($file); 540*5586e97bSAndreas Gohr } 541*5586e97bSAndreas Gohr 542*5586e97bSAndreas Gohr return 0; 543*5586e97bSAndreas Gohr } 544*5586e97bSAndreas Gohr 545c5c85a97SAndreas Gohr //endregion 54636c0b2b4SAndreas Gohr} 547