gcmd.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778
  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
  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. args = map(EncodeString, args)
  125. # The Windows shell (cmd.exe) requires some special characters to
  126. # be escaped by preceding them with 3 carets (^^^). cmd.exe /?
  127. # mentions <space> and &()[]{}^=;!'+,`~. A quick test revealed that
  128. # only ^|&<> need to be escaped. A single quote can be escaped by
  129. # enclosing it with double quotes and vice versa.
  130. for i in range(2, len(args)):
  131. # "^" must be the first character in the list to avoid double
  132. # escaping.
  133. for c in ("^", "|", "&", "<", ">"):
  134. if c in args[i]:
  135. if "=" in args[i]:
  136. a = args[i].split("=")
  137. k = a[0] + "="
  138. v = "=".join(a[1:len(a)])
  139. else:
  140. k = ""
  141. v = args[i]
  142. # If there are spaces, the argument was already
  143. # esscaped with double quotes, so don't escape it
  144. # again.
  145. if c in v and not " " in v:
  146. # Here, we escape each ^ in ^^^ with ^^ and a
  147. # <special character> with ^ + <special character>,
  148. # so we need 7 carets.
  149. v = v.replace(c, "^^^^^^^" + c)
  150. args[i] = k + v
  151. subprocess.Popen.__init__(self, args, **kwargs)
  152. def recv(self, maxsize=None):
  153. return self._recv('stdout', maxsize)
  154. def recv_err(self, maxsize=None):
  155. return self._recv('stderr', maxsize)
  156. def send_recv(self, input='', maxsize=None):
  157. return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
  158. def get_conn_maxsize(self, which, maxsize):
  159. if maxsize is None:
  160. maxsize = 1024
  161. elif maxsize < 1:
  162. maxsize = 1
  163. return getattr(self, which), maxsize
  164. def _close(self, which):
  165. getattr(self, which).close()
  166. setattr(self, which, None)
  167. def kill(self):
  168. """Try to kill running process"""
  169. if is_mswindows:
  170. import win32api
  171. handle = win32api.OpenProcess(1, 0, self.pid)
  172. return (0 != win32api.TerminateProcess(handle, 0))
  173. else:
  174. try:
  175. os.kill(-self.pid, signal.SIGTERM) # kill whole group
  176. except OSError:
  177. pass
  178. if sys.platform == 'win32':
  179. def send(self, input):
  180. if not self.stdin:
  181. return None
  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 (subprocess.pywintypes.error, Exception) as why:
  188. if why[0] 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. try:
  197. x = msvcrt.get_osfhandle(conn.fileno())
  198. (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
  199. if maxsize < nAvail:
  200. nAvail = maxsize
  201. if nAvail > 0:
  202. (errCode, read) = ReadFile(x, nAvail, None)
  203. except ValueError:
  204. return self._close(which)
  205. except (subprocess.pywintypes.error, Exception) as why:
  206. if why[0] in (109, errno.ESHUTDOWN):
  207. return self._close(which)
  208. raise
  209. if self.universal_newlines:
  210. read = self._translate_newlines(read)
  211. return read
  212. else:
  213. def send(self, input):
  214. if not self.stdin:
  215. return None
  216. if not select.select([], [self.stdin], [], 0)[1]:
  217. return 0
  218. try:
  219. written = os.write(self.stdin.fileno(), input)
  220. except OSError as why:
  221. if why[0] == errno.EPIPE: # broken pipe
  222. return self._close('stdin')
  223. raise
  224. return written
  225. def _recv(self, which, maxsize):
  226. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  227. if conn is None:
  228. return None
  229. flags = fcntl.fcntl(conn, fcntl.F_GETFL)
  230. if not conn.closed:
  231. fcntl.fcntl(conn, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  232. try:
  233. if not select.select([conn], [], [], 0)[0]:
  234. return ''
  235. r = conn.read(maxsize)
  236. if not r:
  237. return self._close(which)
  238. if self.universal_newlines:
  239. r = self._translate_newlines(r)
  240. return r
  241. finally:
  242. if not conn.closed:
  243. fcntl.fcntl(conn, fcntl.F_SETFL, flags)
  244. message = "Other end disconnected!"
  245. def recv_some(p, t=.1, e=1, tr=5, stderr=0):
  246. if tr < 1:
  247. tr = 1
  248. x = time.time() + t
  249. y = []
  250. r = ''
  251. pr = p.recv
  252. if stderr:
  253. pr = p.recv_err
  254. while time.time() < x or r:
  255. r = pr()
  256. if r is None:
  257. if e:
  258. raise Exception(message)
  259. else:
  260. break
  261. elif r:
  262. y.append(decode(r))
  263. else:
  264. time.sleep(max((x - time.time()) / tr, 0))
  265. return ''.join(y)
  266. def send_all(p, data):
  267. while len(data):
  268. sent = p.send(data)
  269. if sent is None:
  270. raise Exception(message)
  271. data = buffer(data, sent)
  272. class Command:
  273. """Run command in separate thread. Used for commands launched
  274. on the background.
  275. If stdout/err is redirected, write() method is required for the
  276. given classes.
  277. cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
  278. if cmd.returncode == None:
  279. print 'RUNNING?'
  280. elif cmd.returncode == 0:
  281. print 'SUCCESS'
  282. else:
  283. print 'FAILURE (%d)' % cmd.returncode
  284. """
  285. def __init__(self, cmd, stdin=None,
  286. verbose=None, wait=True, rerr=False,
  287. stdout=None, stderr=None):
  288. """
  289. :param cmd: command given as list
  290. :param stdin: standard input stream
  291. :param verbose: verbose level [0, 3] (--q, --v)
  292. :param wait: wait for child execution terminated
  293. :param rerr: error handling (when GException raised).
  294. True for redirection to stderr, False for GUI
  295. dialog, None for no operation (quiet mode)
  296. :param stdout: redirect standard output or None
  297. :param stderr: redirect standard error output or None
  298. """
  299. Debug.msg(1, "gcmd.Command(): %s" % ' '.join(cmd))
  300. self.cmd = cmd
  301. self.stderr = stderr
  302. #
  303. # set verbosity level
  304. #
  305. verbose_orig = None
  306. if ('--q' not in self.cmd and '--quiet' not in self.cmd) and \
  307. ('--v' not in self.cmd and '--verbose' not in self.cmd):
  308. if verbose is not None:
  309. if verbose == 0:
  310. self.cmd.append('--quiet')
  311. elif verbose == 3:
  312. self.cmd.append('--verbose')
  313. else:
  314. verbose_orig = os.getenv("GRASS_VERBOSE")
  315. os.environ["GRASS_VERBOSE"] = str(verbose)
  316. #
  317. # create command thread
  318. #
  319. self.cmdThread = CommandThread(cmd, stdin,
  320. stdout, stderr)
  321. self.cmdThread.start()
  322. if wait:
  323. self.cmdThread.join()
  324. if self.cmdThread.module:
  325. self.cmdThread.module.wait()
  326. self.returncode = self.cmdThread.module.returncode
  327. else:
  328. self.returncode = 1
  329. else:
  330. self.cmdThread.join(0.5)
  331. self.returncode = None
  332. if self.returncode is not None:
  333. Debug.msg(
  334. 3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" %
  335. (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
  336. if rerr is not None and self.returncode != 0:
  337. if rerr is False: # GUI dialog
  338. raise GException("%s '%s'%s%s%s %s%s" %
  339. (_("Execution failed:"),
  340. ' '.join(self.cmd),
  341. os.linesep, os.linesep,
  342. _("Details:"),
  343. os.linesep,
  344. _("Error: ") + self.__GetError()))
  345. elif rerr == sys.stderr: # redirect message to sys
  346. stderr.write("Execution failed: '%s'" %
  347. (' '.join(self.cmd)))
  348. stderr.write(
  349. "%sDetails:%s%s" %
  350. (os.linesep,
  351. _("Error: ") +
  352. self.__GetError(),
  353. os.linesep))
  354. else:
  355. pass # nop
  356. else:
  357. Debug.msg(
  358. 3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" %
  359. (' '.join(cmd), wait, self.cmdThread.isAlive()))
  360. if verbose_orig:
  361. os.environ["GRASS_VERBOSE"] = verbose_orig
  362. elif "GRASS_VERBOSE" in os.environ:
  363. del os.environ["GRASS_VERBOSE"]
  364. def __ReadOutput(self, stream):
  365. """Read stream and return list of lines
  366. :param stream: stream to be read
  367. """
  368. lineList = []
  369. if stream is None:
  370. return lineList
  371. while True:
  372. line = stream.readline()
  373. if not line:
  374. break
  375. line = line.replace('%s' % os.linesep, '').strip()
  376. lineList.append(line)
  377. return lineList
  378. def __ReadErrOutput(self):
  379. """Read standard error output and return list of lines"""
  380. return self.__ReadOutput(self.cmdThread.module.stderr)
  381. def __ProcessStdErr(self):
  382. """
  383. Read messages/warnings/errors from stderr
  384. :return: list of (type, message)
  385. """
  386. if self.stderr is None:
  387. lines = self.__ReadErrOutput()
  388. else:
  389. lines = self.cmdThread.error.strip('%s' % os.linesep). \
  390. split('%s' % os.linesep)
  391. msg = []
  392. type = None
  393. content = ""
  394. for line in lines:
  395. if len(line) == 0:
  396. continue
  397. if 'GRASS_' in line: # error or warning
  398. if 'GRASS_INFO_WARNING' in line: # warning
  399. type = "WARNING"
  400. elif 'GRASS_INFO_ERROR' in line: # error
  401. type = "ERROR"
  402. elif 'GRASS_INFO_END': # end of message
  403. msg.append((type, content))
  404. type = None
  405. content = ""
  406. if type:
  407. content += line.split(':', 1)[1].strip()
  408. else: # stderr
  409. msg.append((None, line.strip()))
  410. return msg
  411. def __GetError(self):
  412. """Get error message or ''"""
  413. if not self.cmdThread.module:
  414. return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
  415. for type, msg in self.__ProcessStdErr():
  416. if type == 'ERROR':
  417. if _enc:
  418. return unicode(msg, _enc)
  419. return msg
  420. return ''
  421. class CommandThread(Thread):
  422. """Create separate thread for command. Used for commands launched
  423. on the background."""
  424. def __init__(self, cmd, env=None, stdin=None,
  425. stdout=sys.stdout, stderr=sys.stderr):
  426. """
  427. :param cmd: command (given as list)
  428. :param env: environmental variables
  429. :param stdin: standard input stream
  430. :param stdout: redirect standard output or None
  431. :param stderr: redirect standard error output or None
  432. """
  433. Thread.__init__(self)
  434. self.cmd = cmd
  435. self.stdin = stdin
  436. self.stdout = stdout
  437. self.stderr = stderr
  438. self.env = env
  439. self.module = None
  440. self.error = ''
  441. self._want_abort = False
  442. self.aborted = False
  443. self.setDaemon(True)
  444. # set message formatting
  445. self.message_format = os.getenv("GRASS_MESSAGE_FORMAT")
  446. os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
  447. def __del__(self):
  448. if self.message_format:
  449. os.environ["GRASS_MESSAGE_FORMAT"] = self.message_format
  450. else:
  451. del os.environ["GRASS_MESSAGE_FORMAT"]
  452. def run(self):
  453. """Run command"""
  454. if len(self.cmd) == 0:
  455. return
  456. Debug.msg(1, "gcmd.CommandThread(): %s" % ' '.join(self.cmd))
  457. self.startTime = time.time()
  458. # TODO: replace ugly hack below
  459. # this cannot be replaced it can be only improved
  460. # also unifying this with 3 other places in code would be nice
  461. # changing from one chdir to get_real_command function
  462. args = self.cmd
  463. if sys.platform == 'win32':
  464. if os.path.splitext(args[0])[1] == SCT_EXT:
  465. args[0] = args[0][:-3]
  466. # using Python executable to run the module if it is a script
  467. # expecting at least module name at first position
  468. # cannot use make_command for this now because it is used in GUI
  469. # The same code is in grass.script.core already twice.
  470. args[0] = grass.get_real_command(args[0])
  471. if args[0].endswith('.py'):
  472. args.insert(0, sys.executable)
  473. try:
  474. self.module = Popen(args,
  475. stdin=subprocess.PIPE,
  476. stdout=subprocess.PIPE,
  477. stderr=subprocess.PIPE,
  478. shell=sys.platform == "win32",
  479. env=self.env)
  480. except OSError as e:
  481. self.error = str(e)
  482. print(e, file=sys.stderr)
  483. return 1
  484. if self.stdin: # read stdin if requested ...
  485. self.module.stdin.write(self.stdin)
  486. self.module.stdin.close()
  487. # redirect standard outputs...
  488. self._redirect_stream()
  489. def _redirect_stream(self):
  490. """Redirect stream"""
  491. if self.stdout:
  492. # make module stdout/stderr non-blocking
  493. out_fileno = self.module.stdout.fileno()
  494. if not is_mswindows:
  495. flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
  496. fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  497. if self.stderr:
  498. # make module stdout/stderr non-blocking
  499. out_fileno = self.module.stderr.fileno()
  500. if not is_mswindows:
  501. flags = fcntl.fcntl(out_fileno, fcntl.F_GETFL)
  502. fcntl.fcntl(out_fileno, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  503. # wait for the process to end, sucking in stuff until it does end
  504. while self.module.poll() is None:
  505. if self._want_abort: # abort running process
  506. self.module.terminate()
  507. self.aborted = True
  508. return
  509. if self.stdout:
  510. line = recv_some(self.module, e=0, stderr=0)
  511. self.stdout.write(line)
  512. if self.stderr:
  513. line = recv_some(self.module, e=0, stderr=1)
  514. self.stderr.write(line)
  515. if len(line) > 0:
  516. self.error = line
  517. # get the last output
  518. if self.stdout:
  519. line = recv_some(self.module, e=0, stderr=0)
  520. self.stdout.write(line)
  521. if self.stderr:
  522. line = recv_some(self.module, e=0, stderr=1)
  523. self.stderr.write(line)
  524. if len(line) > 0:
  525. self.error = line
  526. def abort(self):
  527. """Abort running process, used by main thread to signal an abort"""
  528. self._want_abort = True
  529. def _formatMsg(text):
  530. """Format error messages for dialogs
  531. """
  532. message = ''
  533. for line in text.splitlines():
  534. if len(line) == 0:
  535. continue
  536. elif 'GRASS_INFO_MESSAGE' in line:
  537. message += line.split(':', 1)[1].strip() + '\n'
  538. elif 'GRASS_INFO_WARNING' in line:
  539. message += line.split(':', 1)[1].strip() + '\n'
  540. elif 'GRASS_INFO_ERROR' in line:
  541. message += line.split(':', 1)[1].strip() + '\n'
  542. elif 'GRASS_INFO_END' in line:
  543. return message
  544. else:
  545. message += line.strip() + '\n'
  546. return message
  547. def RunCommand(prog, flags="", overwrite=False, quiet=False,
  548. verbose=False, parent=None, read=False,
  549. parse=None, stdin=None, getErrorMsg=False, **kwargs):
  550. """Run GRASS command
  551. :param prog: program to run
  552. :param flags: flags given as a string
  553. :param overwrite, quiet, verbose: flags
  554. :param parent: parent window for error messages
  555. :param read: fetch stdout
  556. :param parse: fn to parse stdout (e.g. grass.parse_key_val) or None
  557. :param stdin: stdin or None
  558. :param getErrorMsg: get error messages on failure
  559. :param kwargs: program parameters
  560. :return: returncode (read == False and getErrorMsg == False)
  561. :return: returncode, messages (read == False and getErrorMsg == True)
  562. :return: stdout (read == True and getErrorMsg == False)
  563. :return: returncode, stdout, messages (read == True and getErrorMsg == True)
  564. :return: stdout, stderr
  565. """
  566. cmdString = b' '.join(grass.make_command(prog, flags, overwrite,
  567. quiet, verbose, **kwargs))
  568. Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString)
  569. kwargs['stderr'] = subprocess.PIPE
  570. if read:
  571. kwargs['stdout'] = subprocess.PIPE
  572. if stdin:
  573. kwargs['stdin'] = subprocess.PIPE
  574. if parent:
  575. messageFormat = os.getenv('GRASS_MESSAGE_FORMAT', 'gui')
  576. os.environ['GRASS_MESSAGE_FORMAT'] = 'standard'
  577. start = time.time()
  578. ps = grass.start_command(prog, flags, overwrite, quiet, verbose, **kwargs)
  579. if stdin:
  580. ps.stdin.write(stdin)
  581. ps.stdin.close()
  582. ps.stdin = None
  583. stdout, stderr = list(map(DecodeString, ps.communicate()))
  584. if parent: # restore previous settings
  585. os.environ['GRASS_MESSAGE_FORMAT'] = messageFormat
  586. ret = ps.returncode
  587. Debug.msg(1, "gcmd.RunCommand(): get return code %d (%.6f sec)" %
  588. (ret, (time.time() - start)))
  589. if ret != 0:
  590. if stderr:
  591. Debug.msg(2, "gcmd.RunCommand(): error %s" % stderr)
  592. else:
  593. Debug.msg(2, "gcmd.RunCommand(): nothing to print ???")
  594. if parent:
  595. GError(parent=parent,
  596. caption=_("Error in %s") % prog,
  597. message=stderr)
  598. if not read:
  599. if not getErrorMsg:
  600. return ret
  601. else:
  602. return ret, _formatMsg(stderr)
  603. if stdout:
  604. Debug.msg(3, "gcmd.RunCommand(): return stdout\n'%s'" % stdout)
  605. else:
  606. Debug.msg(3, "gcmd.RunCommand(): return stdout = None")
  607. if parse:
  608. stdout = parse(stdout)
  609. if not getErrorMsg:
  610. return stdout
  611. if read and getErrorMsg:
  612. return ret, stdout, _formatMsg(stderr)
  613. return stdout, _formatMsg(stderr)
  614. def GetDefaultEncoding(forceUTF8=False):
  615. """Get default system encoding
  616. :param bool forceUTF8: force 'UTF-8' if encoding is not defined
  617. :return: system encoding (can be None)
  618. """
  619. enc = locale.getdefaultlocale()[1]
  620. if forceUTF8 and (enc is None or enc == 'UTF8'):
  621. return 'UTF-8'
  622. Debug.msg(1, "GetSystemEncoding(): %s" % enc)
  623. return enc
  624. _enc = GetDefaultEncoding() # define as global variable