]> git.mxchange.org Git - friendica.git/commitdiff
Add Console classes
authorHypolite Petovan <mrpetovan@gmail.com>
Sun, 18 Mar 2018 09:11:15 +0000 (05:11 -0400)
committerHypolite Petovan <mrpetovan@gmail.com>
Sun, 18 Mar 2018 09:11:48 +0000 (05:11 -0400)
src/Core/Console.php [new file with mode: 0644]
src/Core/Console/Config.php [new file with mode: 0644]
src/Core/Console/CreateDoxygen.php [new file with mode: 0644]
src/Core/Console/DocBloxErrorChecker.php [new file with mode: 0644]
src/Core/Console/GlobalCommunityBlock.php [new file with mode: 0644]

diff --git a/src/Core/Console.php b/src/Core/Console.php
new file mode 100644 (file)
index 0000000..f9c37dd
--- /dev/null
@@ -0,0 +1,111 @@
+<?php\r
+\r
+namespace Friendica\Core;\r
+\r
+/**\r
+ * Description of Console\r
+ *\r
+ * @author Hypolite Petovan <mrpetovan@gmail.com>\r
+ */\r
+class Console extends \Asika\SimpleConsole\Console\r
+{\r
+       // Disables the default help handling\r
+       protected $helpOptions = [];\r
+       protected $customHelpOptions = ['h', 'help', '?'];\r
+\r
+       protected function getHelp()\r
+       {\r
+\r
+\r
+               $help = <<<HELP\r
+Usage: bin/console [--version] [-h|--help|-?] <command> [<args>] [-v]\r
+\r
+Commands:\r
+       config               Edit site config\r
+       createdoxygen        Generate Doxygen headers\r
+       docbloxerrorchecker  Checks the file tree for DocBlox errors\r
+       globalcommunityblock Silence remote profile from global community page\r
+       help                 Show help about a command, e.g (bin/console help config)\r
+\r
+Options:\r
+       -h|--help|-? Show help information\r
+       -v           Show more debug information.\r
+HELP;\r
+               return $help;\r
+       }\r
+\r
+       protected function doExecute()\r
+       {\r
+               if ($this->getOption('v')) {\r
+                       $this->out('Executable: ' . $this->executable);\r
+                       $this->out('Arguments: ' . var_export($this->args, true));\r
+                       $this->out('Options: ' . var_export($this->options, true));\r
+               }\r
+\r
+               $showHelp = false;\r
+               $subHelp = false;\r
+               $command = null;\r
+\r
+               if ($this->getOption('version')) {\r
+                       $this->out('Friendica Console version ' . FRIENDICA_VERSION);\r
+\r
+                       return 0;\r
+               } elseif ((count($this->options) === 0 || $this->getOption($this->customHelpOptions) === true || $this->getOption($this->customHelpOptions) === 1) && count($this->args) === 0\r
+               ) {\r
+                       $showHelp = true;\r
+               } elseif (count($this->args) >= 2 && $this->getArgument(0) == 'help') {\r
+                       $command = $this->getArgument(1);\r
+                       $subHelp = true;\r
+                       array_shift($this->args);\r
+                       array_shift($this->args);\r
+               } elseif (count($this->args) >= 1) {\r
+                       $command = $this->getArgument(0);\r
+                       array_shift($this->args);\r
+               }\r
+\r
+               if (is_null($command)) {\r
+                       $this->out($this->getHelp());\r
+                       return 0;\r
+               }\r
+\r
+               $console = $this->getSubConsole($command);\r
+\r
+               if ($subHelp) {\r
+                       $console->setOption($this->customHelpOptions, true);\r
+               }\r
+\r
+               return $console->execute();\r
+       }\r
+\r
+       private function getSubConsole($command)\r
+       {\r
+               if ($this->getOption('v')) {\r
+                       $this->out('Command: ' . $command);\r
+               }\r
+\r
+               $subargs = $this->args;\r
+               array_unshift($subargs, $this->executable);\r
+\r
+               $subconsole = null;\r
+\r
+               switch ($command) {\r
+                       case 'config' : $subconsole = new Console\Config($subargs);\r
+                               break;\r
+                       case 'createdoxygen' : $subconsole = new Console\CreateDoxygen($subargs);\r
+                               break;\r
+                       case 'docbloxerrorchecker' : $subconsole = new Console\DocBloxErrorChecker($subargs);\r
+                               break;\r
+                       case 'globalcommunityblock': $subconsole = new Console\GlobalCommunityBlock($subargs);\r
+                               break;\r
+                       default:\r
+                               throw new \Asika\SimpleConsole\CommandArgsException('Command ' . $command . ' doesn\'t exist');\r
+               }\r
+\r
+               foreach ($this->options as $name => $value) {\r
+                       $subconsole->setOption($name, $value);\r
+               }\r
+\r
+               return $subconsole;\r
+       }\r
+\r
+}\r
diff --git a/src/Core/Console/Config.php b/src/Core/Console/Config.php
new file mode 100644 (file)
index 0000000..3b77d54
--- /dev/null
@@ -0,0 +1,131 @@
+<?php\r
+\r
+/*\r
+ * To change this license header, choose License Headers in Project Properties.\r
+ * To change this template file, choose Tools | Templates\r
+ * and open the template in the editor.\r
+ */\r
+\r
+namespace Friendica\Core\Console;\r
+\r
+use Asika\SimpleConsole\CommandArgsException;\r
+use dba;\r
+use Friendica\Core;\r
+\r
+require_once 'include/dba.php';\r
+require_once 'include/text.php';\r
+\r
+/**\r
+ * @brief tool to access the system config from the CLI\r
+ *\r
+ * With this script you can access the system configuration of your node from\r
+ * the CLI. You can do both, reading current values stored in the database and\r
+ * set new values to config variables.\r
+ *\r
+ * Usage:\r
+ *   If you specify no parameters at the CLI, the script will list all config\r
+ *   variables defined.\r
+ *\r
+ *   If you specify one parameter, the script will list all config variables\r
+ *   defined in this section of the configuration (e.g. "system").\r
+ *\r
+ *   If you specify two parameters, the script will show you the current value\r
+ *   of the named configuration setting. (e.g. "system loglevel")\r
+ *\r
+ *   If you specify three parameters, the named configuration setting will be\r
+ *   set to the value of the last parameter. (e.g. "system loglevel 0" will\r
+ *   disable logging)\r
+ *\r
+ * @author Tobias Diekershoff\r
+ * @author Hypolite Petovan <mrpetovan@gmail.com>\r
+ */\r
+class Config extends \Asika\SimpleConsole\Console\r
+{\r
+       protected $helpOptions = ['h', 'help', '?'];\r
+\r
+       protected function getHelp()\r
+       {\r
+               $help = <<<HELP\r
+console config - Manage site configuration\r
+Synopsis\r
+       bin/console config [-h|--help|-?] [-v]\r
+       bin/console config <category> [-h|--help|-?] [-v]\r
+       bin/console config <category> <key> [-h|--help|-?] [-v]\r
+       bin/console config <category> <key> <value> [-h|--help|-?] [-v]\r
+\r
+Description\r
+       bin/console config\r
+               Lists all config values\r
+\r
+       bin/console config <category>\r
+               Lists all config values in the provided category\r
+\r
+       bin/console config <category> <key>\r
+               Shows the value of the provided key in the category\r
+\r
+       bin/console config <category> <key> <value>\r
+               Set the value of the provided key in the category\r
+\r
+Options\r
+    -h|--help|-? Show help information\r
+    -v           Show more debug information.\r
+HELP;\r
+               return $help;\r
+       }\r
+\r
+       protected function doExecute()\r
+       {\r
+               if ($this->getOption('v')) {\r
+                       $this->out('Executable: ' . $this->executable);\r
+                       $this->out('Class: ' . __CLASS__);\r
+                       $this->out('Arguments: ' . var_export($this->args, true));\r
+                       $this->out('Options: ' . var_export($this->options, true));\r
+               }\r
+\r
+               if (count($this->args) > 3) {\r
+                       throw new CommandArgsException('Too many arguments');\r
+               }\r
+\r
+               require_once '.htconfig.php';\r
+               $result = dba::connect($db_host, $db_user, $db_pass, $db_data);\r
+               unset($db_host, $db_user, $db_pass, $db_data);\r
+\r
+               if (!$result) {\r
+                       throw new \RuntimeException('Unable to connect to database');\r
+               }\r
+\r
+               if (count($this->args) == 3) {\r
+                       Core\Config::set($this->getArgument(0), $this->getArgument(1), $this->getArgument(2));\r
+                       $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0),\r
+                                       $this->getArgument(1)));\r
+               }\r
+\r
+               if (count($this->args) == 2) {\r
+                       $this->out("config[{$this->getArgument(0)}][{$this->getArgument(1)}] = " . Core\Config::get($this->getArgument(0),\r
+                                       $this->getArgument(1)));\r
+               }\r
+\r
+               if (count($this->args) == 1) {\r
+                       Core\Config::load($this->getArgument(0));\r
+\r
+                       $a = get_app();\r
+                       if (!is_null($a->config[$this->getArgument(0)])) {\r
+                               foreach ($a->config[$this->getArgument(0)] as $k => $x) {\r
+                                       $this->out("config[{$this->getArgument(0)}][{$k}] = " . $x);\r
+                               }\r
+                       } else {\r
+                               $this->out('Config section ' . $this->getArgument(0) . ' returned nothing');\r
+                       }\r
+               }\r
+\r
+               if (count($this->args) == 0) {\r
+                       $configs = dba::select('config');\r
+                       foreach ($configs as $config) {\r
+                               $this->out("config[{$config['cat']}][{$config['k']}] = " . $config['v']);\r
+                       }\r
+               }\r
+\r
+               return 0;\r
+       }\r
+\r
+}\r
diff --git a/src/Core/Console/CreateDoxygen.php b/src/Core/Console/CreateDoxygen.php
new file mode 100644 (file)
index 0000000..17da992
--- /dev/null
@@ -0,0 +1,148 @@
+<?php\r
+\r
+namespace Friendica\Core\Console;\r
+\r
+/**\r
+ * Description of CreateDoxygen\r
+ *\r
+ * @author Hypolite Petovan <mrpetovan@gmail.com>\r
+ */\r
+class CreateDoxygen extends \Asika\SimpleConsole\Console\r
+{\r
+       protected $helpOptions = ['h', 'help', '?'];\r
+\r
+       protected function getHelp()\r
+       {\r
+               $help = <<<HELP\r
+console createdoxygen - Generate Doxygen headers\r
+Usage\r
+       bin/console createdoxygen <file> [-h|--help|-?] [-v]\r
+\r
+Description\r
+       Outputs the provided file with added Doxygen headers to functions\r
+\r
+Options\r
+    -h|--help|-? Show help information\r
+    -v           Show more debug information.\r
+HELP;\r
+               return $help;\r
+       }\r
+\r
+       protected function doExecute()\r
+       {\r
+               if ($this->getOption('v')) {\r
+                       $this->out('Class: ' . __CLASS__);\r
+                       $this->out('Arguments: ' . var_export($this->args, true));\r
+                       $this->out('Options: ' . var_export($this->options, true));\r
+               }\r
+\r
+               if (count($this->args) == 0) {\r
+                       $this->out($this->getHelp());\r
+                       return 0;\r
+               }\r
+\r
+               if (count($this->args) > 1) {\r
+                       throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');\r
+               }\r
+\r
+               $file = $this->getArgument(0);\r
+               if (!file_exists($file)) {\r
+                       throw new \RuntimeException('Unable to find specified file.');\r
+               }\r
+\r
+               $data = file_get_contents($file);\r
+\r
+               $lines = explode("\n", $data);\r
+\r
+               $previous = "";\r
+\r
+               foreach ($lines AS $line) {\r
+                       $line = rtrim(trim($line, "\r"));\r
+\r
+                       if (strstr(strtolower($line), "function")) {\r
+                               $detect = strtolower(trim($line));\r
+                               $detect = implode(" ", explode(" ", $detect));\r
+\r
+                               $found = false;\r
+\r
+                               if (substr($detect, 0, 9) == "function ") {\r
+                                       $found = true;\r
+                               }\r
+\r
+                               if (substr($detect, 0, 19) == "protected function ") {\r
+                                       $found = true;\r
+                               }\r
+\r
+                               if (substr($detect, 0, 17) == "private function ") {\r
+                                       $found = true;\r
+                               }\r
+\r
+                               if (substr($detect, 0, 23) == "public static function ") {\r
+                                       $found = true;\r
+                               }\r
+\r
+                               if (substr($detect, 0, 24) == "private static function ") {\r
+                                       $found = true;\r
+                               }\r
+\r
+                               if (substr($detect, 0, 10) == "function (") {\r
+                                       $found = false;\r
+                               }\r
+\r
+                               if ($found && ( trim($previous) == "*/")) {\r
+                                       $found = false;\r
+                               }\r
+\r
+                               if ($found) {\r
+                                       $this->out($this->addDocumentation($line));\r
+                               }\r
+                       }\r
+                       $this->out($line);\r
+                       $previous = $line;\r
+               }\r
+\r
+               return 0;\r
+       }\r
+\r
+       /**\r
+        * @brief Adds a doxygen header\r
+        *\r
+        * @param string $line The current line of the document\r
+        *\r
+        * @return string added doxygen header\r
+        */\r
+       private function addDocumentation($line)\r
+       {\r
+               $trimmed = ltrim($line);\r
+               $length = strlen($line) - strlen($trimmed);\r
+               $space = substr($line, 0, $length);\r
+\r
+               $block = $space . "/**\n" .\r
+                       $space . " * @brief \n" .\r
+                       $space . " *\n"; /**/\r
+\r
+\r
+               $left = strpos($line, "(");\r
+               $line = substr($line, $left + 1);\r
+\r
+               $right = strpos($line, ")");\r
+               $line = trim(substr($line, 0, $right));\r
+\r
+               if ($line != "") {\r
+                       $parameters = explode(",", $line);\r
+                       foreach ($parameters AS $parameter) {\r
+                               $parameter = trim($parameter);\r
+                               $splitted = explode("=", $parameter);\r
+\r
+                               $block .= $space . " * @param " . trim($splitted[0], "& ") . "\n";\r
+                       }\r
+                       if (count($parameters) > 0) $block .= $space . " *\n";\r
+               }\r
+\r
+               $block .= $space . " * @return \n" .\r
+                       $space . " */\n";\r
+\r
+               return $block;\r
+       }\r
+\r
+}\r
diff --git a/src/Core/Console/DocBloxErrorChecker.php b/src/Core/Console/DocBloxErrorChecker.php
new file mode 100644 (file)
index 0000000..2a9aa02
--- /dev/null
@@ -0,0 +1,192 @@
+<?php\r
+\r
+namespace Friendica\Core\Console;\r
+\r
+/**\r
+ * When I installed docblox, I had the experience that it does not generate any output at all.\r
+ * This script may be used to find that kind of problems with the documentation build process.\r
+ * If docblox generates output, use another approach for debugging.\r
+ *\r
+ * Basically, docblox takes a list of files to build documentation from. This script assumes there is a file or set of files\r
+ * breaking the build when it is included in that list. It tries to calculate the smallest list containing these files.\r
+ * Unfortunatly, the original problem is NP-complete, so what the script does is a best guess only.\r
+ *\r
+ * So it starts with a list of all files in the project.\r
+ * If that list can't be build, it cuts it in two parts and tries both parts independently. If only one of them breaks,\r
+ * it takes that one and tries the same independently. If both break, it assumes this is the smallest set. This assumption\r
+ * is not necessarily true. Maybe the smallest set consists of two files and both of them were in different parts when\r
+ * the list was divided, but by now it is my best guess. To make this assumption better, the list is shuffled after every step.\r
+ *\r
+ * After that, the script tries to remove a file from the list. It tests if the list breaks and if so, it\r
+ * assumes that the file it removed belongs to the set of erroneous files.\r
+ * This is done for all files, so, in the end removing one file leads to a working doc build.\r
+ *\r
+ * @author Alexander Kampmann\r
+ * @author Hypolite Petovan <mrpetovan@gmail.com>\r
+ */\r
+class DocBloxErrorChecker extends \Asika\SimpleConsole\Console\r
+{\r
+\r
+       protected $helpOptions = ['h', 'help', '?'];\r
+\r
+       protected function getHelp()\r
+       {\r
+               $help = <<<HELP\r
+console docbloxerrorchecker - Checks the file tree for docblox errors\r
+Usage\r
+       bin/console docbloxerrorchecker [-h|--help|-?] [-v]\r
+\r
+Options\r
+    -h|--help|-? Show help information\r
+    -v           Show more debug information.\r
+HELP;\r
+               return $help;\r
+       }\r
+\r
+       protected function doExecute()\r
+       {\r
+               if ($this->getOption('v')) {\r
+                       $this->out('Class: ' . __CLASS__);\r
+                       $this->out('Arguments: ' . var_export($this->args, true));\r
+                       $this->out('Options: ' . var_export($this->options, true));\r
+               }\r
+\r
+               if (count($this->args) > 0) {\r
+                       throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');\r
+               }\r
+\r
+               if (!$this->commandExists('docblox')) {\r
+                       throw new \RuntimeException('DocBlox isn\'t available.');\r
+               }\r
+\r
+               //return from util folder to frindica base dir\r
+               $dir = get_app()->get_basepath();\r
+\r
+               //stack for dirs to search\r
+               $dirstack = [];\r
+               //list of source files\r
+               $filelist = [];\r
+\r
+               //loop over all files in $dir\r
+               while ($dh = opendir($dir)) {\r
+                       while ($file = readdir($dh)) {\r
+                               if (is_dir($dir . "/" . $file)) {\r
+                                       //add to directory stack\r
+                                       if (strpos($file, '.') !== 0) {\r
+                                               array_push($dirstack, $dir . "/" . $file);\r
+                                               $this->out('dir ' . $dir . '/' . $file);\r
+                                       }\r
+                               } else {\r
+                                       //test if it is a source file and add to filelist\r
+                                       if (substr($file, strlen($file) - 4) == ".php") {\r
+                                               array_push($filelist, $dir . "/" . $file);\r
+                                               $this->out($dir . '/' . $file);\r
+                                       }\r
+                               }\r
+                       }\r
+                       //look at the next dir\r
+                       $dir = array_pop($dirstack);\r
+               }\r
+\r
+               //check the entire set\r
+               if ($this->runs($filelist)) {\r
+                       throw new \RuntimeException("I can not detect a problem.");\r
+               }\r
+\r
+               //check half of the set and discard if that half is okay\r
+               $res = $filelist;\r
+               $i = count($res);\r
+               do {\r
+                       $this->out($i . '/' . count($filelist) . ' elements remaining.');\r
+                       $res = $this->reduce($res, count($res) / 2);\r
+                       shuffle($res);\r
+                       $i = count($res);\r
+               } while (count($res) < $i);\r
+\r
+               //check one file after another\r
+               $needed = [];\r
+\r
+               while (count($res) != 0) {\r
+                       $file = array_pop($res);\r
+\r
+                       if ($this->runs(array_merge($res, $needed))) {\r
+                               $this->out('needs: ' . $file . ' and file count ' . count($needed));\r
+                               array_push($needed, $file);\r
+                       }\r
+               }\r
+\r
+               $this->out('Smallest Set is: ' . $this->namesList($needed) . ' with ' . count($needed) . ' files. ');\r
+\r
+               return 0;\r
+       }\r
+\r
+       private function commandExists($command)\r
+       {\r
+               $prefix = strpos(strtolower(PHP_OS),'win') > -1 ? 'where' : 'which';\r
+               exec("{$prefix} {$command}", $output = [], $returnVal = 0);\r
+               return $returnVal === 0;\r
+       }\r
+\r
+       /**\r
+        * This function generates a comma separated list of file names.\r
+        *\r
+        * @package util\r
+        *\r
+        * @param array $fileset Set of file names\r
+        *\r
+        * @return string comma-separated list of the file names\r
+        */\r
+       private function namesList($fileset)\r
+       {\r
+               return implode(',', $fileset);\r
+       }\r
+\r
+       /**\r
+        * This functions runs phpdoc on the provided list of files\r
+        * @package util\r
+        *\r
+        * @param array $fileset Set of filenames\r
+        *\r
+        * @return bool true, if that set can be built\r
+        */\r
+       private function runs($fileset)\r
+       {\r
+               $fsParam = $this->namesList($fileset);\r
+               $this->exec('docblox -t phpdoc_out -f ' . $fsParam);\r
+               if (file_exists("phpdoc_out/index.html")) {\r
+                       $this->out('Subset ' . $fsParam . ' is okay.');\r
+                       $this->exec('rm -r phpdoc_out');\r
+                       return true;\r
+               } else {\r
+                       $this->out('Subset ' . $fsParam . ' failed.');\r
+                       return false;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * This functions cuts down a fileset by removing files until it finally works.\r
+        * it was meant to be recursive, but php's maximum stack size is to small. So it just simulates recursion.\r
+        *\r
+        * In that version, it does not necessarily generate the smallest set, because it may not alter the elements order enough.\r
+        *\r
+        * @package util\r
+        *\r
+        * @param array $fileset set of filenames\r
+        * @param int $ps number of files in subsets\r
+        *\r
+        * @return array a part of $fileset, that crashes\r
+        */\r
+       private function reduce($fileset, $ps)\r
+       {\r
+               //split array...\r
+               $parts = array_chunk($fileset, $ps);\r
+               //filter working subsets...\r
+               $parts = array_filter($parts, [$this, 'runs']);\r
+               //melt remaining parts together\r
+               if (is_array($parts)) {\r
+                       return array_reduce($parts, "array_merge", []);\r
+               }\r
+               return [];\r
+       }\r
+\r
+}\r
diff --git a/src/Core/Console/GlobalCommunityBlock.php b/src/Core/Console/GlobalCommunityBlock.php
new file mode 100644 (file)
index 0000000..569bd78
--- /dev/null
@@ -0,0 +1,70 @@
+<?php\r
+\r
+namespace Friendica\Core\Console;\r
+\r
+use Friendica\Core\L10n;\r
+use Friendica\Model\Contact;\r
+\r
+/**\r
+ * Description of GlobalCommunityBlock\r
+ *\r
+ * @author Hypolite Petovan <mrpetovan@gmail.com>\r
+ */\r
+class GlobalCommunityBlock extends \Asika\SimpleConsole\Console\r
+{\r
+       protected $helpOptions = ['h', 'help', '?'];\r
+\r
+       protected function getHelp()\r
+       {\r
+               $help = <<<HELP\r
+console globalcommunityblock - Silence remote profile from global community page\r
+Usage\r
+       bin/console globalcommunityblock <profile_url> [-h|--help|-?] [-v]\r
+\r
+Description\r
+       bin/console globalcommunityblock <profile_url>\r
+               Silences the provided remote profile URL from the global community page\r
+\r
+Options\r
+    -h|--help|-? Show help information\r
+    -v           Show more debug information.\r
+HELP;\r
+               return $help;\r
+       }\r
+\r
+       protected function doExecute()\r
+       {\r
+               if ($this->getOption('v')) {\r
+                       $this->out('Class: ' . __CLASS__);\r
+                       $this->out('Arguments: ' . var_export($this->args, true));\r
+                       $this->out('Options: ' . var_export($this->options, true));\r
+               }\r
+\r
+               if (count($this->args) == 0) {\r
+                       $this->out($this->getHelp());\r
+                       return 0;\r
+               }\r
+\r
+               if (count($this->args) > 1) {\r
+                       throw new \Asika\SimpleConsole\CommandArgsException('Too many arguments');\r
+               }\r
+\r
+               require_once '.htconfig.php';\r
+               $result = \dba::connect($db_host, $db_user, $db_pass, $db_data);\r
+               unset($db_host, $db_user, $db_pass, $db_data);\r
+\r
+               if (!$result) {\r
+                       throw new \RuntimeException('Unable to connect to database');\r
+               }\r
+\r
+               $contact_id = Contact::getIdForURL($argv[1]);\r
+               if (!$contact_id) {\r
+                       throw new \RuntimeException(L10n::t('Could not find any contact entry for this URL (%s)', $nurl));\r
+               }\r
+               Contact::block($contact_id);\r
+               $this->out(L10n::t('The contact has been blocked from the node'));\r
+\r
+               return 0;\r
+       }\r
+\r
+}\r