MDL-68714 clilib: Check set_process_title exists
[moodle.git] / lib / clilib.php
CommitLineData
5d995668 1<?php
3b596dbf 2
3// This file is part of Moodle - http://moodle.org/
4//
5d995668 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.
3b596dbf 14//
5d995668 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/>.
17
9d068cd6 18/**
3b596dbf 19 * Command line utility functions and classes
9d068cd6 20 *
78bfb562 21 * @package core
3b596dbf 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
9d068cd6 25 */
9d068cd6 26
3604563c 27// NOTE: no MOODLE_INTERNAL test here, sometimes we use this before requiring Moodle libs!
78bfb562 28
028bbc5b
DM
29/**
30 * Write a text to the given stream
31 *
32 * @param string $text text to be written
33 * @param resource $stream output stream to be written to, defaults to STDOUT
34 */
35function cli_write($text, $stream=STDOUT) {
36 fwrite($stream, $text);
37}
38
39/**
40 * Write a text followed by an end of line symbol to the given stream
41 *
42 * @param string $text text to be written
43 * @param resource $stream output stream to be written to, defaults to STDOUT
44 */
45function cli_writeln($text, $stream=STDOUT) {
46 cli_write($text.PHP_EOL, $stream);
47}
48
9d068cd6 49/**
3b596dbf 50 * Get input from user
1275723f 51 * @param string $prompt text prompt, should include possible options
3b596dbf 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
9d068cd6 56 */
3b596dbf 57function cli_input($prompt, $default='', array $options=null, $casesensitiveoptions=false) {
028bbc5b
DM
58 cli_writeln($prompt);
59 cli_write(': ');
3b596dbf 60 $input = fread(STDIN, 2048);
61 $input = trim($input);
62 if ($input === '') {
63 $input = $default;
9d068cd6 64 }
3b596dbf 65 if ($options) {
66 if (!$casesensitiveoptions) {
67 $input = strtolower($input);
9d068cd6 68 }
3b596dbf 69 if (!in_array($input, $options)) {
c0e8a8a5 70 cli_writeln(get_string('cliincorrectvalueretry', 'admin'));
3b596dbf 71 return cli_input($prompt, $default, $options, $casesensitiveoptions);
9d068cd6 72 }
73 }
3b596dbf 74 return $input;
9d068cd6 75}
76
77/**
3b596dbf 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
9d068cd6 82 */
3b596dbf 83function cli_get_params(array $longoptions, array $shortmapping=null) {
84 $shortmapping = (array)$shortmapping;
85 $options = array();
86 $unrecognized = array();
9d068cd6 87
3b596dbf 88 if (empty($_SERVER['argv'])) {
89 // bad luck, we can continue in interactive mode ;-)
90 return array($options, $unrecognized);
9d068cd6 91 }
3b596dbf 92 $rawoptions = $_SERVER['argv'];
9d068cd6 93
3b596dbf 94 //remove anything after '--', options can not be there
95 if (($key = array_search('--', $rawoptions)) !== false) {
96 $rawoptions = array_slice($rawoptions, 0, $key);
9d068cd6 97 }
9d068cd6 98
3b596dbf 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;
108 } else {
109 $key = array_shift($parts);
110 $value = implode('=', $parts);
9d068cd6 111 }
3b596dbf 112 if (array_key_exists($key, $longoptions)) {
113 $options[$key] = $value;
114 } else {
115 $unrecognized[] = $raw;
9d068cd6 116 }
9d068cd6 117
3b596dbf 118 } else if (substr($raw, 0, 1) === '-') {
119 $value = substr($raw, 1);
120 $parts = explode('=', $value);
121 if (count($parts) == 1) {
122 $key = reset($parts);
123 $value = true;
124 } else {
125 $key = array_shift($parts);
126 $value = implode('=', $parts);
127 }
128 if (array_key_exists($key, $shortmapping)) {
129 $options[$shortmapping[$key]] = $value;
130 } else {
131 $unrecognized[] = $raw;
9d068cd6 132 }
133 } else {
3b596dbf 134 $unrecognized[] = $raw;
135 continue;
9d068cd6 136 }
137 }
3b596dbf 138 //apply defaults
139 foreach ($longoptions as $key=>$default) {
140 if (!array_key_exists($key, $options)) {
141 $options[$key] = $default;
9d068cd6 142 }
9d068cd6 143 }
3b596dbf 144 // finished
145 return array($options, $unrecognized);
9d068cd6 146}
147
73a5ba92
BH
148/**
149 * This sets the cli process title suffix
150 *
151 * An example is appending current Task API info so a sysadmin can immediately
152 * see what task a cron process is running at any given moment.
153 *
154 * @param string $suffix process suffix
155 */
156function cli_set_process_title_suffix(string $suffix) {
9eaf7a4c 157 if (CLI_SCRIPT && function_exists('cli_set_process_title') && isset($_SERVER['argv'])) {
73a5ba92
BH
158 $command = join(' ', $_SERVER['argv']);
159 @cli_set_process_title("php $command ($suffix)");
160 }
161}
162
c31d94e8 163/**
164 * Print or return section separator string
165 * @param bool $return false means print, true return as string
166 * @return mixed void or string
167 */
168function cli_separator($return=false) {
028bbc5b 169 $separator = str_repeat('-', 79).PHP_EOL;
c31d94e8 170 if ($return) {
171 return $separator;
172 } else {
028bbc5b 173 cli_write($separator);
c31d94e8 174 }
175}
176
177/**
178 * Print or return section heading string
179 * @param string $string text
180 * @param bool $return false means print, true return as string
181 * @return mixed void or string
182 */
183function cli_heading($string, $return=false) {
028bbc5b 184 $string = "== $string ==".PHP_EOL;
c31d94e8 185 if ($return) {
186 return $string;
187 } else {
028bbc5b 188 cli_write($string);
c31d94e8 189 }
190}
191
9d068cd6 192/**
3b596dbf 193 * Write error notification
194 * @param $text
195 * @return void
9d068cd6 196 */
3b596dbf 197function cli_problem($text) {
028bbc5b 198 cli_writeln($text, STDERR);
9d068cd6 199}
3b596dbf 200
9d068cd6 201/**
028bbc5b 202 * Write to standard error output and exit with the given code
9d068cd6 203 *
3b596dbf 204 * @param string $text
205 * @param int $errorcode
206 * @return void (does not return)
9d068cd6 207 */
3b596dbf 208function cli_error($text, $errorcode=1) {
028bbc5b 209 cli_writeln($text.PHP_EOL, STDERR);
3b596dbf 210 die($errorcode);
9d068cd6 211}
08e7f97e 212
85f8fe5e
DM
213/**
214 * Print an ASCII version of the Moodle logo.
215 *
216 * @param int $padding left padding of the logo
217 * @param bool $return should we print directly (false) or return the string (true)
218 * @return mixed void or string
219 */
220function cli_logo($padding=2, $return=false) {
221
222 $lines = array(
223 ' .-..-. ',
224 ' _____ | || | ',
225 '/____/-.---_ .---. .---. .-.| || | .---. ',
226 '| | _ _ |/ _ \\/ _ \\/ _ || |/ __ \\',
227 '* | | | | | || |_| || |_| || |_| || || |___/',
228 ' |_| |_| |_|\\_____/\\_____/\\_____||_|\\_____)',
229 );
230
231 $logo = '';
232
233 foreach ($lines as $line) {
234 $logo .= str_repeat(' ', $padding);
235 $logo .= $line;
236 $logo .= PHP_EOL;
237 }
238
239 if ($return) {
240 return $logo;
241 } else {
028bbc5b 242 cli_write($logo);
85f8fe5e
DM
243 }
244}
3b4717ea
AN
245
246/**
247 * Substitute cursor, colour, and bell placeholders in a CLI output to ANSI escape characters when ANSI is available.
248 *
249 * @param string $message
250 * @return string
251 */
252function cli_ansi_format(string $message): string {
253 global $CFG;
254
255 $replacements = [
256 "<newline>" => "\n",
257 "<bell>" => "\007",
258
259 // Cursor movement: https://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x361.html.
c1f7368e
BH
260 "<cursor:save>" => "\033[s",
261 "<cursor:restore>" => "\033[u",
262 "<cursor:up>" => "\033[1A",
263 "<cursor:down>" => "\033[1B",
264 "<cursor:forward>" => "\033[1C",
265 "<cursor:back>" => "\033[1D",
3b4717ea
AN
266 ];
267
268 $colours = [
c1f7368e
BH
269 'normal' => '0;0',
270 'black' => '0;30',
271 'darkGray' => '1;30',
272 'red' => '0;31',
273 'lightRed' => '1;31',
274 'green' => '0;32',
275 'lightGreen' => '1;32',
276 'brown' => '0;33',
277 'yellow' => '1;33',
278 'lightYellow' => '0;93',
279 'blue' => '0;34',
280 'lightBlue' => '1;34',
281 'purple' => '0;35',
282 'lightPurple' => '1;35',
283 'cyan' => '0;36',
284 'lightCyan' => '1;36',
285 'lightGray' => '0;37',
286 'white' => '1;37',
287 ];
288 $bgcolours = [
289 'black' => '40',
290 'red' => '41',
291 'green' => '42',
292 'yellow' => '43',
293 'blue' => '44',
294 'magenta' => '45',
295 'cyan' => '46',
296 'white' => '47',
3b4717ea
AN
297 ];
298
299 foreach ($colours as $colour => $code) {
300 $replacements["<colour:{$colour}>"] = "\033[{$code}m";
301 }
c1f7368e
BH
302 foreach ($bgcolours as $colour => $code) {
303 $replacements["<bgcolour:{$colour}>"] = "\033[{$code}m";
304 }
3b4717ea
AN
305
306 // Windows don't support ANSI code by default, but does if ANSICON is available.
307 $isansicon = getenv('ANSICON');
308 if (($CFG->ostype === 'WINDOWS') && empty($isansicon)) {
309 return str_replace(array_keys($replacements), '', $message);
310 }
311
312 return str_replace(array_keys($replacements), array_values($replacements), $message);
313}