gcmd.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. """
  2. @package core.gcmd
  3. @brief wxGUI command interface
  4. Classes:
  5. - gcmd::GError
  6. - gcmd::GWarning
  7. - gcmd::GMessage
  8. - gcmd::GException
  9. - gcmd::Popen (from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440554)
  10. - gcmd::Command
  11. - gcmd::CommandThread
  12. Functions:
  13. - RunCommand
  14. - GetDefaultEncoding
  15. (C) 2007-2008, 2010-2011 by the GRASS Development Team
  16. This program is free software under the GNU General Public License
  17. (>=v2). Read the file COPYING that comes with GRASS for details.
  18. @author Jachym Cepicky
  19. @author Martin Landa <landa.martin gmail.com>
  20. """
  21. from __future__ import print_function
  22. import os
  23. import sys
  24. import time
  25. import errno
  26. import signal
  27. import traceback
  28. import locale
  29. import subprocess
  30. from threading import Thread
  31. import wx
  32. is_mswindows = sys.platform == 'win32'
  33. if is_mswindows:
  34. from win32file import ReadFile, WriteFile
  35. from win32pipe import PeekNamedPipe
  36. import msvcrt
  37. else:
  38. import select
  39. import fcntl
  40. from core.debug import Debug
  41. from core.globalvar import SCT_EXT
  42. from grass.script import core as grass
  43. from grass.script.utils import decode, encode
  44. if sys.version_info.major == 2:
  45. bytes = str
  46. def DecodeString(string):
  47. """Decode string using system encoding
  48. :param string: string to be decoded
  49. :return: decoded string
  50. """
  51. if not string:
  52. return string
  53. if _enc and isinstance(string, bytes):
  54. Debug.msg(5, "DecodeString(): enc=%s" % _enc)
  55. return string.decode(_enc)
  56. return string
  57. def EncodeString(string):
  58. """Return encoded string using system locales
  59. :param string: string to be encoded
  60. :return: encoded string
  61. """
  62. if not string:
  63. return string
  64. if _enc:
  65. Debug.msg(5, "EncodeString(): enc=%s" % _enc)
  66. return string.encode(_enc)
  67. return string
  68. class GError:
  69. def __init__(self, message, parent=None, caption=None, showTraceback=True):
  70. """Show error message window
  71. :param message: error message
  72. :param parent: centre window on parent if given
  73. :param caption: window caption (if not given "Error")
  74. :param showTraceback: True to show also Python traceback
  75. """
  76. if not caption:
  77. caption = _('Error')
  78. style = wx.OK | wx.ICON_ERROR | wx.CENTRE
  79. exc_type, exc_value, exc_traceback = sys.exc_info()
  80. if exc_traceback:
  81. exception = traceback.format_exc()
  82. reason = exception.splitlines()[-1].split(':', 1)[-1].strip()
  83. if Debug.GetLevel() > 0 and exc_traceback:
  84. sys.stderr.write(exception)
  85. if showTraceback and exc_traceback:
  86. wx.MessageBox(parent=parent,
  87. message=message + '\n\n%s: %s\n\n%s' %
  88. (_('Reason'),
  89. reason, exception),
  90. caption=caption,
  91. style=style)
  92. else:
  93. wx.MessageBox(parent=parent,
  94. message=message,
  95. caption=caption,
  96. style=style)
  97. class GWarning:
  98. def __init__(self, message, parent=None):
  99. caption = _('Warning')
  100. style = wx.OK | wx.ICON_WARNING | wx.CENTRE
  101. wx.MessageBox(parent=parent,
  102. message=message,
  103. caption=caption,
  104. style=style)
  105. class GMessage:
  106. def __init__(self, message, parent=None):
  107. caption = _('Message')
  108. style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE
  109. wx.MessageBox(parent=parent,
  110. message=message,
  111. caption=caption,
  112. style=style)
  113. class GException(Exception):
  114. def __init__(self, value=''):
  115. self.value = value
  116. def __str__(self):
  117. return self.value
  118. def __unicode__(self):
  119. return self.value
  120. class Popen(subprocess.Popen):
  121. """Subclass subprocess.Popen"""
  122. def __init__(self, args, **kwargs):
  123. if is_mswindows:
  124. # The Windows shell (cmd.exe) requires some special characters to
  125. # be escaped by preceding them with 3 carets (^^^). cmd.exe /?
  126. # mentions <space> and &()[]{}^=;!'+,`~. A quick test revealed that
  127. # only ^|&<> need to be escaped. A single quote can be escaped by
  128. # enclosing it with double quotes and vice versa.
  129. for i in range(2, len(args)):
  130. # "^" must be the first character in the list to avoid double
  131. # escaping.
  132. for c in ("^", "|", "&", "<", ">"):
  133. if c in args[i]:
  134. if "=" in args[i]:
  135. a = args[i].split("=")
  136. k = a[0] + "="
  137. v = "=".join(a[1:len(a)])
  138. else:
  139. k = ""
  140. v = args[i]
  141. # If there are spaces, the argument was already
  142. # esscaped with double quotes, so don't escape it
  143. # again.
  144. if c in v and " " not in v:
  145. # Here, we escape each ^ in ^^^ with ^^ and a
  146. # <special character> with ^ + <special character>,
  147. # so we need 7 carets.
  148. v = v.replace(c, "^^^^^^^" + c)
  149. args[i] = k + v
  150. subprocess.Popen.__init__(self, args, **kwargs)
  151. def recv(self, maxsize=None):
  152. return self._recv('stdout', maxsize)
  153. def recv_err(self, maxsize=None):
  154. return self._recv('stderr', maxsize)
  155. def send_recv(self, input='', maxsize=None):
  156. return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
  157. def get_conn_maxsize(self, which, maxsize):
  158. if maxsize is None:
  159. maxsize = 1024
  160. elif maxsize < 1:
  161. maxsize = 1
  162. return getattr(self, which), maxsize
  163. def _close(self, which):
  164. getattr(self, which).close()
  165. setattr(self, which, None)
  166. def kill(self):
  167. """Try to kill running process"""
  168. if is_mswindows:
  169. import win32api
  170. handle = win32api.OpenProcess(1, 0, self.pid)
  171. return (0 != win32api.TerminateProcess(handle, 0))
  172. else:
  173. try:
  174. os.kill(-self.pid, signal.SIGTERM) # kill whole group
  175. except OSError:
  176. pass
  177. if sys.platform == 'win32':
  178. def send(self, input):
  179. if not self.stdin:
  180. return None
  181. import pywintypes
  182. try:
  183. x = msvcrt.get_osfhandle(self.stdin.fileno())
  184. (errCode, written) = WriteFile(x, input)
  185. except ValueError:
  186. return self._close('stdin')
  187. except (pywintypes.error, Exception) as why:
  188. if why.winerror in (109, errno.ESHUTDOWN):
  189. return self._close('stdin')
  190. raise
  191. return written
  192. def _recv(self, which, maxsize):
  193. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  194. if conn is None:
  195. return None
  196. import pywintypes
  197. try:
  198. x = msvcrt.get_osfhandle(conn.fileno())
  199. (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
  200. if maxsize < nAvail:
  201. nAvail = maxsize
  202. if nAvail > 0:
  203. (errCode, read) = ReadFile(x, nAvail, None)
  204. except ValueError:
  205. return self._close(which)
  206. except (pywintypes.error, Exception) as why:
  207. if why.winerror in (109, errno.ESHUTDOWN):
  208. return self._close(which)
  209. raise
  210. if self.universal_newlines:
  211. read = self._translate_newlines(read)
  212. return read
  213. else:
  214. def send(self, input):
  215. if not self.stdin:
  216. return None
  217. if not select.select([], [self.stdin], [], 0)[1]:
  218. return 0
  219. try:
  220. written = os.write(self.stdin.fileno(), input)
  221. except OSError as why:
  222. if why[0] == errno.EPIPE: # broken pipe
  223. return self._close('stdin')
  224. raise
  225. return written
  226. def _recv(self, which, maxsize):
  227. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  228. if conn is None:
  229. return None
  230. flags = fcntl.fcntl(conn, fcntl.F_GETFL)
  231. if not conn.closed:
  232. fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  233. try:
  234. if not select.select([conn], [], [], 0)[0]:
  235. return ''
  236. r = conn.read(maxsize)
  237. if not r:
  238. return self._close(which)
  239. if self.universal_newlines:
  240. r = self._translate_newlines(r)
  241. return r
  242. finally:
  243. if not conn.closed:
  244. fcntl.fcntl(conn, fcntl.F_SETFL, flags)
  245. message = "Other end disconnected!"
  246. def recv_some(p, t=.1, e=1, tr=5, stderr=0):
  247. if tr < 1:
  248. tr = 1
  249. x = time.time() + t
  250. y = []
  251. r = ''
  252. pr = p.recv
  253. if stderr:
  254. pr = p.recv_err
  255. while time.time() < x or r:
  256. r = pr()
  257. if r is None:
  258. if e:
  259. raise Exception(message)
  260. else:
  261. break
  262. elif r:
  263. y.append(decode(r))
  264. else:
  265. time.sleep(max((x - time.time()) / tr, 0))
  266. return ''.join(y)
  267. class Command:
  268. """Run command in separate thread. Used for commands launched
  269. on the background.
  270. If stdout/err is redirected, write() method is required for the
  271. given classes.
  272. cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
  273. if cmd.returncode == None:
  274. print 'RUNNING?'
  275. elif cmd.returncode == 0:
  276. print 'SUCCESS'
  277. else:
  278. print 'FAILURE (%d)' % cmd.returncode
  279. """
  280. def __init__(self, cmd, stdin=None,
  281. verbose=None, wait=True, rerr=False,
  282. stdout=None, stderr=None):
  283. """
  284. :param cmd: command given as list
  285. :param stdin: standard input stream
  286. :param verbose: verbose level [0, 3] (--q, --v)
  287. :param wait: wait for child execution terminated
  288. :param rerr: error handling (when GException raised).
  289. True for redirection to stderr, False for GUI
  290. dialog, None for no operation (quiet mode)
  291. :param stdout: redirect standard output or None
  292. :param stderr: redirect standard error output or None
  293. """
  294. Debug.msg(1, "gcmd.Command(): %s" % ' '.join(cmd))
  295. self.cmd = cmd
  296. self.stderr = stderr
  297. #
  298. # set verbosity level
  299. #
  300. verbose_orig = None
  301. if ('--q' not in self.cmd and '--quiet' not in self.cmd) and \
  302. ('--v' not in self.cmd and '--verbose' not in self.cmd):
  303. if verbose is not None:
  304. if verbose == 0:
  305. self.cmd.append('--quiet')
  306. elif verbose == 3:
  307. self.cmd.append('--verbose')
  308. else:
  309. verbose_orig = os.getenv("GRASS_VERBOSE")
  310. os.environ["GRASS_VERBOSE"] = str(verbose)
  311. #
  312. # create command thread
  313. #
  314. self.cmdThread = CommandThread(cmd, stdin,
  315. stdout, stderr)
  316. self.cmdThread.start()
  317. if wait:
  318. self.cmdThread.join()
  319. if self.cmdThread.module:
  320. self.cmdThread.module.wait()
  321. self.returncode = self.cmdThread.module.returncode
  322. else:
  323. self.returncode = 1
  324. else:
  325. self.cmdThread.join(0.5)
  326. self.returncode = None
  327. if self.returncode is not None:
  328. Debug.msg(
  329. 3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" %
  330. (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
  331. if rerr is not None and self.returncode != 0:
  332. if rerr is False: # GUI dialog
  333. raise GException("%s '%s'%s%s%s %s%s" %
  334. (_("Execution failed:"),
  335. ' '.join(self.cmd),
  336. os.linesep, os.linesep,
  337. _("Details:"),
  338. os.linesep,
  339. _("Error: ") + self.__GetError()))
  340. elif rerr == sys.stderr: # redirect message to sys
  341. stderr.write("Execution failed: '%s'" %
  342. (' '.join(self.cmd)))
  343. stderr.write(
  344. "%sDetails:%s%s" %
  345. (os.linesep,
  346. _("Error: ") +
  347. self.__GetError(),
  348. os.linesep))
  349. else:
  350. pass # nop
  351. else:
  352. Debug.msg(
  353. 3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" %
  354. (' '.join(cmd), wait, self.cmdThread.isAlive()))
  355. if verbose_orig:
  356. os.environ["GRASS_VERBOSE"] = verbose_orig
  357. elif "GRASS_VERBOSE" in os.environ:
  358. del os.environ["GRASS_VERBOSE"]
  359. def __ReadOutput(self, stream):
  360. """Read stream and return list of lines
  361. :param stream: stream to be read
  362. """
  363. lineList = []
  364. if stream is None:
  365. return lineList
  366. while True:
  367. line = stream.readline()
  368. if not line:
  369. break
  370. line = line.replace('%s' % os.linesep, '').strip()
  371. lineList.append(line)
  372. return lineList
  373. def __ReadErrOutput(self):
  374. """Read standard error output and return list of lines"""
  375. return self.__ReadOutput(self.cmdThread.module.stderr)
  376. def __ProcessStdErr(self):
  377. """
  378. Read messages/warnings/errors from stderr
  379. :return: list of (type, message)
  380. """
  381. if self.stderr is None:
  382. lines = self.__ReadErrOutput()
  383. else:
  384. lines = self.cmdThread.error.strip('%s' % os.linesep). \
  385. split('%s' % os.linesep)
  386. msg = []
  387. type = None
  388. content = ""
  389. for line in lines:
  390. if len(line) == 0:
  391. continue
  392. if 'GRASS_' in line: # error or warning
  393. if 'GRASS_INFO_WARNING' in line: # warning
  394. type = "WARNING"
  395. elif 'GRASS_INFO_ERROR' in line: # error
  396. type = "ERROR"
  397. elif 'GRASS_INFO_END': # end of message
  398. msg.append((type, content))
  399. type = None
  400. content = ""
  401. if type:
  402. content += line.split(':', 1)[1].strip()
  403. else: # stderr
  404. msg.append((None, line.strip()))
  405. return msg
  406. def __GetError(self):
  407. """Get error message or ''"""
  408. if not self.cmdThread.module:
  409. return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
  410. for type, msg in self.__ProcessStdErr():
  411. if type == 'ERROR':
  412. return msg
  413. return ''
  414. class CommandThread(Thread):
  415. """Create separate thread for command. Used for commands launched
  416. on the background."""
  417. def __init__(self, cmd, env=None, stdin=None,
  418. stdout=sys.stdout, stderr=sys.stderr):
  419. """
  420. :param cmd: command (given as list)
  421. :param env: environmental variables
  422. :param stdin: standard input stream
  423. :param stdout: redirect standard output or None
  424. :param stderr: redirect standard error output or None
  425. """
  426. Thread.__init__(self)
  427. self.cmd = cmd
  428. self.stdin = stdin
  429. self.stdout = stdout
  430. self.stderr = stderr
  431. self.env = env
  432. self.module = None
  433. self.error = ''
  434. self._want_abort = False
  435. self.aborted = False
  436. self.setDaemon(True)
  437. # set message formatting
  438. self.message_format = os.getenv("GRASS_MESSAGE_FORMAT")
  439. os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
  440. def __del__(self):
  441. if self.message_format:
  442. os.environ["GRASS_MESSAGE_FORMAT"] = self.message_format
  443. else:
  444. del os.environ["GRASS_MESSAGE_FORMAT"]
  445. def run(self):
  446. """Run command"""
  447. if len(self.cmd) == 0:
  448. return
  449. Debug.msg(1, "gcmd.CommandThread(): %s" % ' '.join(self.cmd))
  450. self.startTime = time.time()
  451. # TODO: replace ugly hack below
  452. # this cannot be replaced it can be only improved
  453. # also unifying this with 3 other places in code would be nice
  454. # changing from one chdir to get_real_command function
  455. args = self.cmd
  456. if sys.platform == 'win32':
  457. if os.path.splitext(args[0])[1] == SCT_EXT:
  458. args[0] = args[0][:-3]
  459. # using Python executable to run the module if it is a script
  460. # expecting at least module name at first position
  461. # cannot use make_command for this now because it is used in GUI
  462. # The same code is in grass.script.core already twice.
  463. args[0] = grass.get_real_command(args[0])
  464. if args[0].endswith('.py'):
  465. args.insert(0, sys.executable)
  466. try:
  467. self.module = Popen(args,
  468. stdin=subprocess.PIPE,
  469. stdout=subprocess.PIPE,
  470. stderr=subprocess.PIPE,
  471. shell=sys.platform == "win32",
  472. env=self.env)
  473. except OSError as e:
  474. self.error = str(e)
  475. print(e, file=sys.stderr)
  476. return 1
  477. if self.stdin: # read stdin if requested ...
  478. self.module.stdin.write(self.stdin)
  479. self.module.stdin.close()
  480. # redirect standard outputs...
  481. self._redirect_stream()
  482. def _redirect_stream(self):
  483. """Redirect stream"""
  484. if self.stdout:
  485. # make module stdout/stderr non-blocking
  486. out_fileno = self.module.stdout.fileno()
  487. if not is_mswindows:
  488. flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
  489. fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  490. if self.stderr:
  491. # make module stdout/stderr non-blocking
  492. out_fileno = self.module.stderr.fileno()
  493. if not is_mswindows:
  494. flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
  495. fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  496. # wait for the process to end, sucking in stuff until it does end
  497. while self.module.poll() is None:
  498. if self._want_abort: # abort running process
  499. self.module.terminate()
  500. self.aborted = True
  501. return
  502. if self.stdout:
  503. line = recv_some(self.module, e=0, stderr=0)
  504. self.stdout.write(line)
  505. if self.stderr:
  506. line = recv_some(self.module, e=0, stderr=1)
  507. self.stderr.write(line)
  508. if len(line) > 0:
  509. self.error = line
  510. # get the last output
  511. if self.stdout:
  512. line = recv_some(self.module, e=0, stderr=0)
  513. self.stdout.write(line)
  514. if self.stderr:
  515. line = recv_some(self.module, e=0, stderr=1)
  516. self.stderr.write(line)
  517. if len(line) > 0:
  518. self.error = line
  519. def abort(self):
  520. """Abort running process, used by main thread to signal an abort"""
  521. self._want_abort = True
  522. def _formatMsg(text):
  523. """Format error messages for dialogs
  524. """
  525. message = ''
  526. for line in text.splitlines():
  527. if len(line) == 0:
  528. continue
  529. elif 'GRASS_INFO_MESSAGE' in line:
  530. message += line.split(':', 1)[1].strip() + '\n'
  531. elif 'GRASS_INFO_WARNING' in line:
  532. message += line.split(':', 1)[1].strip() + '\n'
  533. elif 'GRASS_INFO_ERROR' in line:
  534. message += line.split(':', 1)[1].strip() + '\n'
  535. elif 'GRASS_INFO_END' in line:
  536. return message
  537. else:
  538. message += line.strip() + '\n'
  539. return message
  540. def RunCommand(prog, flags="", overwrite=False, quiet=False,
  541. verbose=False, parent=None, read=False,
  542. parse=None, stdin=None, getErrorMsg=False, env=None, **kwargs):
  543. """Run GRASS command
  544. :param prog: program to run
  545. :param flags: flags given as a string
  546. :param overwrite, quiet, verbose: flags
  547. :param parent: parent window for error messages
  548. :param read: fetch stdout
  549. :param parse: fn to parse stdout (e.g. grass.parse_key_val) or None
  550. :param stdin: stdin or None
  551. :param getErrorMsg: get error messages on failure
  552. :param env: environment (optional, uses os.environ if not provided)
  553. :param kwargs: program parameters
  554. The environment passed to the function (env or os.environ) is not modified (a copy is used internally).
  555. :return: returncode (read == False and getErrorMsg == False)
  556. :return: returncode, messages (read == False and getErrorMsg == True)
  557. :return: stdout (read == True and getErrorMsg == False)
  558. :return: returncode, stdout, messages (read == True and getErrorMsg == True)
  559. :return: stdout, stderr
  560. """
  561. cmdString = ' '.join(grass.make_command(prog, flags, overwrite,
  562. quiet, verbose, **kwargs))
  563. Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString)
  564. kwargs['stderr'] = subprocess.PIPE
  565. if read:
  566. kwargs['stdout'] = subprocess.PIPE
  567. if stdin:
  568. kwargs['stdin'] = subprocess.PIPE
  569. # Do not change the environment, only a local copy.
  570. if env:
  571. env = env.copy()
  572. else:
  573. env = os.environ.copy()
  574. if parent:
  575. env['GRASS_MESSAGE_FORMAT'] = 'standard'
  576. start = time.time()
  577. ps = grass.start_command(prog, flags, overwrite, quiet, verbose, env=env, **kwargs)
  578. if stdin:
  579. ps.stdin.write(encode(stdin))
  580. ps.stdin.close()
  581. ps.stdin = None
  582. stdout, stderr = ps.communicate()
  583. stderr = decode(stderr)
  584. stdout = decode(stdout) if read else stdout
  585. ret = ps.returncode
  586. Debug.msg(1, "gcmd.RunCommand(): get return code %d (%.6f sec)" %
  587. (ret, (time.time() - start)))
  588. if ret != 0:
  589. if stderr:
  590. Debug.msg(2, "gcmd.RunCommand(): error %s" % stderr)
  591. else:
  592. Debug.msg(2, "gcmd.RunCommand(): nothing to print ???")
  593. if parent:
  594. GError(parent=parent,
  595. caption=_("Error in %s") % prog,
  596. message=stderr)
  597. if not read:
  598. if not getErrorMsg:
  599. return ret
  600. else:
  601. return ret, _formatMsg(stderr)
  602. if stdout:
  603. Debug.msg(3, "gcmd.RunCommand(): return stdout\n'%s'" % stdout)
  604. else:
  605. Debug.msg(3, "gcmd.RunCommand(): return stdout = None")
  606. if parse:
  607. stdout = parse(stdout)
  608. if not getErrorMsg:
  609. return stdout
  610. if read and getErrorMsg:
  611. return ret, stdout, _formatMsg(stderr)
  612. return stdout, _formatMsg(stderr)
  613. def GetDefaultEncoding(forceUTF8=False):
  614. """Get default system encoding
  615. :param bool forceUTF8: force 'UTF-8' if encoding is not defined
  616. :return: system encoding (can be None)
  617. """
  618. enc = locale.getdefaultlocale()[1]
  619. if forceUTF8 and (enc is None or enc == 'UTF8'):
  620. return 'UTF-8'
  621. if enc is None:
  622. enc = locale.getpreferredencoding()
  623. Debug.msg(1, "GetSystemEncoding(): %s" % enc)
  624. return enc
  625. _enc = GetDefaultEncoding() # define as global variable