From 9b8fb1d550e3902d3b69e7a3477c4a22a5fe0386 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Sun, 18 Mar 2018 05:11:15 -0400 Subject: [PATCH] Add Console classes --- src/Core/Console.php | 111 +++++++++++++ src/Core/Console/Config.php | 131 +++++++++++++++ src/Core/Console/CreateDoxygen.php | 148 +++++++++++++++++ src/Core/Console/DocBloxErrorChecker.php | 192 ++++++++++++++++++++++ src/Core/Console/GlobalCommunityBlock.php | 70 ++++++++ 5 files changed, 652 insertions(+) create mode 100644 src/Core/Console.php create mode 100644 src/Core/Console/Config.php create mode 100644 src/Core/Console/CreateDoxygen.php create mode 100644 src/Core/Console/DocBloxErrorChecker.php create mode 100644 src/Core/Console/GlobalCommunityBlock.php diff --git a/src/Core/Console.php b/src/Core/Console.php new file mode 100644 index 0000000000..f9c37dde1e --- /dev/null +++ b/src/Core/Console.php @@ -0,0 +1,111 @@ + + */ +class Console extends \Asika\SimpleConsole\Console +{ + // Disables the default help handling + protected $helpOptions = []; + protected $customHelpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + + + $help = << [] [-v] + +Commands: + config Edit site config + createdoxygen Generate Doxygen headers + docbloxerrorchecker Checks the file tree for DocBlox errors + globalcommunityblock Silence remote profile from global community page + help Show help about a command, e.g (bin/console help config) + +Options: + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Executable: ' . $this->executable); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + $showHelp = false; + $subHelp = false; + $command = null; + + if ($this->getOption('version')) { + $this->out('Friendica Console version ' . FRIENDICA_VERSION); + + return 0; + } elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0 + ) { + $showHelp = true; + } elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') { + $command = $this->getArgument(1); + $subHelp = true; + array_shift($this->args); + array_shift($this->args); + } elseif (count($this->args) >= 1) { + $command = $this->getArgument(0); + array_shift($this->args); + } + + if (is_null($command)) { + $this->out($this->getHelp()); + return 0; + } + + $console = $this->getSubConsole($command); + + if ($subHelp) { + $console->setOption($this->customHelpOptions, true); + } + + return $console->execute(); + } + + private function getSubConsole($command) + { + if ($this->getOption('v')) { + $this->out('Command: ' . $command); + } + + $subargs = $this->args; + array_unshift($subargs, $this->executable); + + $subconsole = null; + + switch ($command) { + case 'config' : $subconsole = new Console\Config($subargs); + break; + case 'createdoxygen' : $subconsole = new Console\CreateDoxygen($subargs); + break; + case 'docbloxerrorchecker' : $subconsole = new Console\DocBloxErrorChecker($subargs); + break; + case 'globalcommunityblock': $subconsole = new Console\GlobalCommunityBlock($subargs); + break; + default: + throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist'); + } + + foreach ($this->options as $name => $value) { + $subconsole->setOption($name, $value); + } + + return $subconsole; + } + +} diff --git a/src/Core/Console/Config.php b/src/Core/Console/Config.php new file mode 100644 index 0000000000..3b77d54009 --- /dev/null +++ b/src/Core/Console/Config.php @@ -0,0 +1,131 @@ + + */ +class Config extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + bin/console config [-h|--help|-?] [-v] + bin/console config [-h|--help|-?] [-v] + +Description + bin/console config + Lists all config values + + bin/console config + Lists all config values in the provided category + + bin/console config + Shows the value of the provided key in the category + + bin/console config + Set the value of the provided key in the category + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Executable: ' . $this->executable); + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) > 3) { + throw new CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + if (count($this->args) == 3) { + Core\Config::set($this->getArgument(0), $this->getArgument(1), $this->getArgument(2)); + $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0), + $this->getArgument(1))); + } + + if (count($this->args) == 2) { + $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0), + $this->getArgument(1))); + } + + if (count($this->args) == 1) { + Core\Config::load($this->getArgument(0)); + + $a = get_app(); + if (!is_null($a->config[$this->getArgument(0)])) { + foreach ($a->config[$this->getArgument(0)] as $k => $x) { + $this->out("config[{$this->getArgument(0)}][{$k}] = " . $x); + } + } else { + $this->out('Config section ' . $this->getArgument(0) . ' returned nothing'); + } + } + + if (count($this->args) == 0) { + $configs = dba::select('config'); + foreach ($configs as $config) { + $this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']); + } + } + + return 0; + } + +} diff --git a/src/Core/Console/CreateDoxygen.php b/src/Core/Console/CreateDoxygen.php new file mode 100644 index 0000000000..17da9922ee --- /dev/null +++ b/src/Core/Console/CreateDoxygen.php @@ -0,0 +1,148 @@ + + */ +class CreateDoxygen extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Description + Outputs the provided file with added Doxygen headers to functions + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + $file = $this->getArgument(0); + if (!file_exists($file)) { + throw new \RuntimeException('Unable to find specified file.'); + } + + $data = file_get_contents($file); + + $lines = explode("\n", $data); + + $previous = ""; + + foreach ($lines AS $line) { + $line = rtrim(trim($line, "\r")); + + if (strstr(strtolower($line), "function")) { + $detect = strtolower(trim($line)); + $detect = implode(" ", explode(" ", $detect)); + + $found = false; + + if (substr($detect, 0, 9) == "function ") { + $found = true; + } + + if (substr($detect, 0, 19) == "protected function ") { + $found = true; + } + + if (substr($detect, 0, 17) == "private function ") { + $found = true; + } + + if (substr($detect, 0, 23) == "public static function ") { + $found = true; + } + + if (substr($detect, 0, 24) == "private static function ") { + $found = true; + } + + if (substr($detect, 0, 10) == "function (") { + $found = false; + } + + if ($found && ( trim($previous) == "*/")) { + $found = false; + } + + if ($found) { + $this->out($this->addDocumentation($line)); + } + } + $this->out($line); + $previous = $line; + } + + return 0; + } + + /** + * @brief Adds a doxygen header + * + * @param string $line The current line of the document + * + * @return string added doxygen header + */ + private function addDocumentation($line) + { + $trimmed = ltrim($line); + $length = strlen($line) - strlen($trimmed); + $space = substr($line, 0, $length); + + $block = $space . "/**\n" . + $space . " * @brief \n" . + $space . " *\n"; /**/ + + + $left = strpos($line, "("); + $line = substr($line, $left + 1); + + $right = strpos($line, ")"); + $line = trim(substr($line, 0, $right)); + + if ($line != "") { + $parameters = explode(",", $line); + foreach ($parameters AS $parameter) { + $parameter = trim($parameter); + $splitted = explode("=", $parameter); + + $block .= $space . " * @param " . trim($splitted[0], "& ") . "\n"; + } + if (count($parameters) > 0) $block .= $space . " *\n"; + } + + $block .= $space . " * @return \n" . + $space . " */\n"; + + return $block; + } + +} diff --git a/src/Core/Console/DocBloxErrorChecker.php b/src/Core/Console/DocBloxErrorChecker.php new file mode 100644 index 0000000000..2a9aa024f9 --- /dev/null +++ b/src/Core/Console/DocBloxErrorChecker.php @@ -0,0 +1,192 @@ + + */ +class DocBloxErrorChecker extends \Asika\SimpleConsole\Console +{ + + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = <<getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) > 0) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + if (!$this->commandExists('docblox')) { + throw new \RuntimeException('DocBlox isn\'t available.'); + } + + //return from util folder to frindica base dir + $dir = get_app()->get_basepath(); + + //stack for dirs to search + $dirstack = []; + //list of source files + $filelist = []; + + //loop over all files in $dir + while ($dh = opendir($dir)) { + while ($file = readdir($dh)) { + if (is_dir($dir . "/" . $file)) { + //add to directory stack + if (strpos($file, '.') !== 0) { + array_push($dirstack, $dir . "/" . $file); + $this->out('dir ' . $dir . '/' . $file); + } + } else { + //test if it is a source file and add to filelist + if (substr($file, strlen($file) - 4) == ".php") { + array_push($filelist, $dir . "/" . $file); + $this->out($dir . '/' . $file); + } + } + } + //look at the next dir + $dir = array_pop($dirstack); + } + + //check the entire set + if ($this->runs($filelist)) { + throw new \RuntimeException("I can not detect a problem."); + } + + //check half of the set and discard if that half is okay + $res = $filelist; + $i = count($res); + do { + $this->out($i . '/' . count($filelist) . ' elements remaining.'); + $res = $this->reduce($res, count($res) / 2); + shuffle($res); + $i = count($res); + } while (count($res) < $i); + + //check one file after another + $needed = []; + + while (count($res) != 0) { + $file = array_pop($res); + + if ($this->runs(array_merge($res, $needed))) { + $this->out('needs: ' . $file . ' and file count ' . count($needed)); + array_push($needed, $file); + } + } + + $this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. '); + + return 0; + } + + private function commandExists($command) + { + $prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which'; + exec("{$prefix} {$command}", $output = [], $returnVal = 0); + return $returnVal === 0; + } + + /** + * This function generates a comma separated list of file names. + * + * @package util + * + * @param array $fileset Set of file names + * + * @return string comma-separated list of the file names + */ + private function namesList($fileset) + { + return implode(',', $fileset); + } + + /** + * This functions runs phpdoc on the provided list of files + * @package util + * + * @param array $fileset Set of filenames + * + * @return bool true, if that set can be built + */ + private function runs($fileset) + { + $fsParam = $this->namesList($fileset); + $this->exec('docblox -t phpdoc_out -f ' . $fsParam); + if (file_exists("phpdoc_out/index.html")) { + $this->out('Subset ' . $fsParam . ' is okay.'); + $this->exec('rm -r phpdoc_out'); + return true; + } else { + $this->out('Subset ' . $fsParam . ' failed.'); + return false; + } + } + + /** + * This functions cuts down a fileset by removing files until it finally works. + * it was meant to be recursive, but php's maximum stack size is to small. So it just simulates recursion. + * + * In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough. + * + * @package util + * + * @param array $fileset set of filenames + * @param int $ps number of files in subsets + * + * @return array a part of $fileset, that crashes + */ + private function reduce($fileset, $ps) + { + //split array... + $parts = array_chunk($fileset, $ps); + //filter working subsets... + $parts = array_filter($parts, [$this, 'runs']); + //melt remaining parts together + if (is_array($parts)) { + return array_reduce($parts, "array_merge", []); + } + return []; + } + +} diff --git a/src/Core/Console/GlobalCommunityBlock.php b/src/Core/Console/GlobalCommunityBlock.php new file mode 100644 index 0000000000..569bd78162 --- /dev/null +++ b/src/Core/Console/GlobalCommunityBlock.php @@ -0,0 +1,70 @@ + + */ +class GlobalCommunityBlock extends \Asika\SimpleConsole\Console +{ + protected $helpOptions = ['h', 'help', '?']; + + protected function getHelp() + { + $help = << [-h|--help|-?] [-v] + +Description + bin/console globalcommunityblock + Silences the provided remote profile URL from the global community page + +Options + -h|--help|-? Show help information + -v Show more debug information. +HELP; + return $help; + } + + protected function doExecute() + { + if ($this->getOption('v')) { + $this->out('Class: ' . __CLASS__); + $this->out('Arguments: ' . var_export($this->args, true)); + $this->out('Options: ' . var_export($this->options, true)); + } + + if (count($this->args) == 0) { + $this->out($this->getHelp()); + return 0; + } + + if (count($this->args) > 1) { + throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments'); + } + + require_once '.htconfig.php'; + $result = \dba::connect($db_host, $db_user, $db_pass, $db_data); + unset($db_host, $db_user, $db_pass, $db_data); + + if (!$result) { + throw new \RuntimeException('Unable to connect to database'); + } + + $contact_id = Contact::getIdForURL($argv[1]); + if (!$contact_id) { + throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl)); + } + Contact::block($contact_id); + $this->out(L10n::t('The contact has been blocked from the node')); + + return 0; + } + +}