3 // This file is part of Moodle - http://moodle.org/
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.
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/>.
19 * Command line utility functions and classes
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!
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);
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);
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) {
60 $input = fread(STDIN
, 2048);
61 $input = trim($input);
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);
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;
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);
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);
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.
113 $key = substr($key, 3);
116 $key = array_shift($parts);
117 $value = implode('=', $parts);
119 if (array_key_exists($key, $longoptions)) {
120 $options[$key] = $value;
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);
132 $key = array_shift($parts);
133 $value = implode('=', $parts);
135 if (array_key_exists($key, $shortmapping)) {
136 $options[$shortmapping[$key]] = $value;
138 $unrecognized[] = $raw;
141 $unrecognized[] = $raw;
146 foreach ($longoptions as $key=>$default) {
147 if (!array_key_exists($key, $options)) {
148 $options[$key] = $default;
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
;
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
;
200 * Write error notification
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
);
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) {
232 '/____/-.---_ .---. .---. .-.| || | .---. ',
233 '| | _ _ |/ _ \\/ _ \\/ _ || |/ __ \\',
234 '* | | | | | || |_| || |_| || |_| || || |___/',
235 ' |_| |_| |_|\\_____/\\_____/\\_____||_|\\_____)',
240 foreach ($lines as $line) {
241 $logo .= str_repeat(' ', $padding);
254 * Substitute cursor, colour, and bell placeholders in a CLI output to ANSI escape characters when ANSI is available.
256 * @param string $message
259 function cli_ansi_format(string $message): string {
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",
278 'darkGray' => '1;30',
280 'lightRed' => '1;31',
282 'lightGreen' => '1;32',
285 'lightYellow' => '0;93',
287 'lightBlue' => '1;34',
289 'lightPurple' => '1;35',
291 'lightCyan' => '1;36',
292 'lightGray' => '0;37',
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);