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