PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/clilib.php

https://github.com/mackensen/moodle
PHP | 320 lines | 207 code | 20 blank | 93 comment | 39 complexity | 07283e1734302119609a3a4900ce3a01 MD5 | raw file
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Command line utility functions and classes
  18. *
  19. * @package core
  20. * @subpackage cli
  21. * @copyright 2009 Petr Skoda (http://skodak.org)
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23. */
  24. // NOTE: no MOODLE_INTERNAL test here, sometimes we use this before requiring Moodle libs!
  25. /**
  26. * Write a text to the given stream
  27. *
  28. * @param string $text text to be written
  29. * @param resource $stream output stream to be written to, defaults to STDOUT
  30. */
  31. function cli_write($text, $stream=STDOUT) {
  32. fwrite($stream, $text);
  33. }
  34. /**
  35. * Write a text followed by an end of line symbol to the given stream
  36. *
  37. * @param string $text text to be written
  38. * @param resource $stream output stream to be written to, defaults to STDOUT
  39. */
  40. function cli_writeln($text, $stream=STDOUT) {
  41. cli_write($text.PHP_EOL, $stream);
  42. }
  43. /**
  44. * Get input from user
  45. * @param string $prompt text prompt, should include possible options
  46. * @param string $default default value when enter pressed
  47. * @param array $options list of allowed options, empty means any text
  48. * @param bool $casesensitive true if options are case sensitive
  49. * @return string entered text
  50. */
  51. function cli_input($prompt, $default='', array $options=null, $casesensitiveoptions=false) {
  52. cli_writeln($prompt);
  53. cli_write(': ');
  54. $input = fread(STDIN, 2048);
  55. $input = trim($input);
  56. if ($input === '') {
  57. $input = $default;
  58. }
  59. if ($options) {
  60. if (!$casesensitiveoptions) {
  61. $input = strtolower($input);
  62. }
  63. if (!in_array($input, $options)) {
  64. cli_writeln(get_string('cliincorrectvalueretry', 'admin'));
  65. return cli_input($prompt, $default, $options, $casesensitiveoptions);
  66. }
  67. }
  68. return $input;
  69. }
  70. /**
  71. * Returns cli script parameters.
  72. * @param array $longoptions array of --style options ex:('verbose'=>false)
  73. * @param array $shortmapping array describing mapping of short to long style options ex:('h'=>'help', 'v'=>'verbose')
  74. * @return array array of arrays, options, unrecognised as optionlongname=>value
  75. */
  76. function cli_get_params(array $longoptions, array $shortmapping=null) {
  77. $shortmapping = (array)$shortmapping;
  78. $options = array();
  79. $unrecognized = array();
  80. if (empty($_SERVER['argv'])) {
  81. // bad luck, we can continue in interactive mode ;-)
  82. return array($options, $unrecognized);
  83. }
  84. $rawoptions = $_SERVER['argv'];
  85. //remove anything after '--', options can not be there
  86. if (($key = array_search('--', $rawoptions)) !== false) {
  87. $rawoptions = array_slice($rawoptions, 0, $key);
  88. }
  89. //remove script
  90. unset($rawoptions[0]);
  91. foreach ($rawoptions as $raw) {
  92. if (substr($raw, 0, 2) === '--') {
  93. $value = substr($raw, 2);
  94. $parts = explode('=', $value);
  95. if (count($parts) == 1) {
  96. $key = reset($parts);
  97. $value = true;
  98. if (substr($key, 0, 3) === 'no-' && !array_key_exists($key, $longoptions)
  99. && array_key_exists(substr($key, 3), $longoptions)) {
  100. // Support flipping the boolean value.
  101. $value = !$value;
  102. $key = substr($key, 3);
  103. }
  104. } else {
  105. $key = array_shift($parts);
  106. $value = implode('=', $parts);
  107. }
  108. if (array_key_exists($key, $longoptions)) {
  109. $options[$key] = $value;
  110. } else {
  111. $unrecognized[] = $raw;
  112. }
  113. } else if (substr($raw, 0, 1) === '-') {
  114. $value = substr($raw, 1);
  115. $parts = explode('=', $value);
  116. if (count($parts) == 1) {
  117. $key = reset($parts);
  118. $value = true;
  119. } else {
  120. $key = array_shift($parts);
  121. $value = implode('=', $parts);
  122. }
  123. if (array_key_exists($key, $shortmapping)) {
  124. $options[$shortmapping[$key]] = $value;
  125. } else {
  126. $unrecognized[] = $raw;
  127. }
  128. } else {
  129. $unrecognized[] = $raw;
  130. continue;
  131. }
  132. }
  133. //apply defaults
  134. foreach ($longoptions as $key=>$default) {
  135. if (!array_key_exists($key, $options)) {
  136. $options[$key] = $default;
  137. }
  138. }
  139. // finished
  140. return array($options, $unrecognized);
  141. }
  142. /**
  143. * This sets the cli process title suffix
  144. *
  145. * An example is appending current Task API info so a sysadmin can immediately
  146. * see what task a cron process is running at any given moment.
  147. *
  148. * @param string $suffix process suffix
  149. */
  150. function cli_set_process_title_suffix(string $suffix) {
  151. if (CLI_SCRIPT && function_exists('cli_set_process_title') && isset($_SERVER['argv'])) {
  152. $command = join(' ', $_SERVER['argv']);
  153. @cli_set_process_title("php $command ($suffix)");
  154. }
  155. }
  156. /**
  157. * Print or return section separator string
  158. * @param bool $return false means print, true return as string
  159. * @return mixed void or string
  160. */
  161. function cli_separator($return=false) {
  162. $separator = str_repeat('-', 79).PHP_EOL;
  163. if ($return) {
  164. return $separator;
  165. } else {
  166. cli_write($separator);
  167. }
  168. }
  169. /**
  170. * Print or return section heading string
  171. * @param string $string text
  172. * @param bool $return false means print, true return as string
  173. * @return mixed void or string
  174. */
  175. function cli_heading($string, $return=false) {
  176. $string = "== $string ==".PHP_EOL;
  177. if ($return) {
  178. return $string;
  179. } else {
  180. cli_write($string);
  181. }
  182. }
  183. /**
  184. * Write error notification
  185. * @param $text
  186. * @return void
  187. */
  188. function cli_problem($text) {
  189. cli_writeln($text, STDERR);
  190. }
  191. /**
  192. * Write to standard error output and exit with the given code
  193. *
  194. * @param string $text
  195. * @param int $errorcode
  196. * @return void (does not return)
  197. */
  198. function cli_error($text, $errorcode=1) {
  199. cli_writeln($text.PHP_EOL, STDERR);
  200. die($errorcode);
  201. }
  202. /**
  203. * Print an ASCII version of the Moodle logo.
  204. *
  205. * @param int $padding left padding of the logo
  206. * @param bool $return should we print directly (false) or return the string (true)
  207. * @return mixed void or string
  208. */
  209. function cli_logo($padding=2, $return=false) {
  210. $lines = array(
  211. ' .-..-. ',
  212. ' _____ | || | ',
  213. '/____/-.---_ .---. .---. .-.| || | .---. ',
  214. '| | _ _ |/ _ \\/ _ \\/ _ || |/ __ \\',
  215. '* | | | | | || |_| || |_| || |_| || || |___/',
  216. ' |_| |_| |_|\\_____/\\_____/\\_____||_|\\_____)',
  217. );
  218. $logo = '';
  219. foreach ($lines as $line) {
  220. $logo .= str_repeat(' ', $padding);
  221. $logo .= $line;
  222. $logo .= PHP_EOL;
  223. }
  224. if ($return) {
  225. return $logo;
  226. } else {
  227. cli_write($logo);
  228. }
  229. }
  230. /**
  231. * Substitute cursor, colour, and bell placeholders in a CLI output to ANSI escape characters when ANSI is available.
  232. *
  233. * @param string $message
  234. * @return string
  235. */
  236. function cli_ansi_format(string $message): string {
  237. global $CFG;
  238. $replacements = [
  239. "<newline>" => "\n",
  240. "<bell>" => "\007",
  241. // Cursor movement: https://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html.
  242. "<cursor:save>" => "\033[s",
  243. "<cursor:restore>" => "\033[u",
  244. "<cursor:up>" => "\033[1A",
  245. "<cursor:down>" => "\033[1B",
  246. "<cursor:forward>" => "\033[1C",
  247. "<cursor:back>" => "\033[1D",
  248. ];
  249. $colours = [
  250. 'normal' => '0;0',
  251. 'black' => '0;30',
  252. 'darkGray' => '1;30',
  253. 'red' => '0;31',
  254. 'lightRed' => '1;31',
  255. 'green' => '0;32',
  256. 'lightGreen' => '1;32',
  257. 'brown' => '0;33',
  258. 'yellow' => '1;33',
  259. 'lightYellow' => '0;93',
  260. 'blue' => '0;34',
  261. 'lightBlue' => '1;34',
  262. 'purple' => '0;35',
  263. 'lightPurple' => '1;35',
  264. 'cyan' => '0;36',
  265. 'lightCyan' => '1;36',
  266. 'lightGray' => '0;37',
  267. 'white' => '1;37',
  268. ];
  269. $bgcolours = [
  270. 'black' => '40',
  271. 'red' => '41',
  272. 'green' => '42',
  273. 'yellow' => '43',
  274. 'blue' => '44',
  275. 'magenta' => '45',
  276. 'cyan' => '46',
  277. 'white' => '47',
  278. ];
  279. foreach ($colours as $colour => $code) {
  280. $replacements["<colour:{$colour}>"] = "\033[{$code}m";
  281. }
  282. foreach ($bgcolours as $colour => $code) {
  283. $replacements["<bgcolour:{$colour}>"] = "\033[{$code}m";
  284. }
  285. // Windows don't support ANSI code by default, but does if ANSICON is available.
  286. $isansicon = getenv('ANSICON');
  287. if (($CFG->ostype === 'WINDOWS') && empty($isansicon)) {
  288. return str_replace(array_keys($replacements), '', $message);
  289. }
  290. return str_replace(array_keys($replacements), array_values($replacements), $message);
  291. }