gcmd.py 23 KB

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