gcmd.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758
  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. import os
  22. import sys
  23. import time
  24. import errno
  25. import signal
  26. import traceback
  27. import locale
  28. import subprocess
  29. if subprocess.mswindows:
  30. from win32file import ReadFile, WriteFile
  31. from win32pipe import PeekNamedPipe
  32. import msvcrt
  33. else:
  34. import select
  35. import fcntl
  36. from threading import Thread
  37. import wx
  38. from grass.script import core as grass
  39. from core import globalvar
  40. from core.debug import Debug
  41. # cannot import from the core.utils module to avoid cross dependencies
  42. try:
  43. # intended to be used also outside this module
  44. import gettext
  45. _ = gettext.translation('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale')).ugettext
  46. except IOError:
  47. # using no translation silently
  48. def null_gettext(string):
  49. return string
  50. _ = null_gettext
  51. def DecodeString(string):
  52. """Decode string using system encoding
  53. :param string: string to be decoded
  54. :return: decoded string
  55. """
  56. if not string:
  57. return string
  58. if _enc:
  59. Debug.msg(5, "DecodeString(): enc=%s" % _enc)
  60. return string.decode(_enc)
  61. return string
  62. def EncodeString(string):
  63. """Return encoded string using system locales
  64. :param string: string to be encoded
  65. :return: encoded string
  66. """
  67. if not string:
  68. return string
  69. if _enc:
  70. Debug.msg(5, "EncodeString(): enc=%s" % _enc)
  71. return string.encode(_enc)
  72. return string
  73. class GError:
  74. def __init__(self, message, parent = None, caption = None, showTraceback = True):
  75. """Show error message window
  76. :param message: error message
  77. :param parent: centre window on parent if given
  78. :param caption: window caption (if not given "Error")
  79. :param showTraceback: True to show also Python traceback
  80. """
  81. if not caption:
  82. caption = _('Error')
  83. style = wx.OK | wx.ICON_ERROR | wx.CENTRE
  84. exc_type, exc_value, exc_traceback = sys.exc_info()
  85. if exc_traceback:
  86. exception = traceback.format_exc()
  87. reason = exception.splitlines()[-1].split(':', 1)[-1].strip()
  88. if Debug.GetLevel() > 0 and exc_traceback:
  89. sys.stderr.write(exception)
  90. if showTraceback and exc_traceback:
  91. wx.MessageBox(parent = parent,
  92. message = message + '\n\n%s: %s\n\n%s' % \
  93. (_('Reason'),
  94. reason, exception),
  95. caption = caption,
  96. style = style)
  97. else:
  98. wx.MessageBox(parent = parent,
  99. message = message,
  100. caption = caption,
  101. style = style)
  102. class GWarning:
  103. def __init__(self, message, parent = None):
  104. caption = _('Warning')
  105. style = wx.OK | wx.ICON_WARNING | wx.CENTRE
  106. wx.MessageBox(parent = parent,
  107. message = message,
  108. caption = caption,
  109. style = style)
  110. class GMessage:
  111. def __init__(self, message, parent = None):
  112. caption = _('Message')
  113. style = wx.OK | wx.ICON_INFORMATION | wx.CENTRE
  114. wx.MessageBox(parent = parent,
  115. message = message,
  116. caption = caption,
  117. style = style)
  118. class GException(Exception):
  119. def __init__(self, value = ''):
  120. self.value = value
  121. def __str__(self):
  122. return self.value
  123. def __unicode__(self):
  124. return self.value
  125. class Popen(subprocess.Popen):
  126. """Subclass subprocess.Popen"""
  127. def __init__(self, args, **kwargs):
  128. if subprocess.mswindows:
  129. args = map(EncodeString, args)
  130. # The Windows shell (cmd.exe) requires some special characters to
  131. # be escaped by preceding them with 3 carets (^^^). cmd.exe /?
  132. # mentions <space> and &()[]{}^=;!'+,`~. A quick test revealed that
  133. # only ^|&<> need to be escaped. A single quote can be escaped by
  134. # enclosing it with double quotes and vice versa.
  135. for i in range(2, len(args)):
  136. # "^" must be the first character in the list to avoid double
  137. # escaping.
  138. for c in ("^", "|", "&", "<", ">"):
  139. if c in args[i]:
  140. if "=" in args[i]:
  141. a = args[i].split("=")
  142. k = a[0] + "="
  143. v = "=".join(a[1:len(a)])
  144. else:
  145. k = ""
  146. v = args[i]
  147. # If there are spaces, the argument was already
  148. # esscaped with double quotes, so don't escape it
  149. # again.
  150. if c in v and not " " in v:
  151. # Here, we escape each ^ in ^^^ with ^^ and a
  152. # <special character> with ^ + <special character>,
  153. # so we need 7 carets.
  154. v = v.replace(c, "^^^^^^^" + c)
  155. args[i] = k + v
  156. subprocess.Popen.__init__(self, args, **kwargs)
  157. def recv(self, maxsize = None):
  158. return self._recv('stdout', maxsize)
  159. def recv_err(self, maxsize = None):
  160. return self._recv('stderr', maxsize)
  161. def send_recv(self, input = '', maxsize = None):
  162. return self.send(input), self.recv(maxsize), self.recv_err(maxsize)
  163. def get_conn_maxsize(self, which, maxsize):
  164. if maxsize is None:
  165. maxsize = 1024
  166. elif maxsize < 1:
  167. maxsize = 1
  168. return getattr(self, which), maxsize
  169. def _close(self, which):
  170. getattr(self, which).close()
  171. setattr(self, which, None)
  172. def kill(self):
  173. """Try to kill running process"""
  174. if subprocess.mswindows:
  175. import win32api
  176. handle = win32api.OpenProcess(1, 0, self.pid)
  177. return (0 != win32api.TerminateProcess(handle, 0))
  178. else:
  179. try:
  180. os.kill(-self.pid, signal.SIGTERM) # kill whole group
  181. except OSError:
  182. pass
  183. if subprocess.mswindows:
  184. def send(self, input):
  185. if not self.stdin:
  186. return None
  187. try:
  188. x = msvcrt.get_osfhandle(self.stdin.fileno())
  189. (errCode, written) = WriteFile(x, input)
  190. except ValueError:
  191. return self._close('stdin')
  192. except (subprocess.pywintypes.error, Exception) as why:
  193. if why[0] in (109, errno.ESHUTDOWN):
  194. return self._close('stdin')
  195. raise
  196. return written
  197. def _recv(self, which, maxsize):
  198. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  199. if conn is None:
  200. return None
  201. try:
  202. x = msvcrt.get_osfhandle(conn.fileno())
  203. (read, nAvail, nMessage) = PeekNamedPipe(x, 0)
  204. if maxsize < nAvail:
  205. nAvail = maxsize
  206. if nAvail > 0:
  207. (errCode, read) = ReadFile(x, nAvail, None)
  208. except ValueError:
  209. return self._close(which)
  210. except (subprocess.pywintypes.error, Exception) as why:
  211. if why[0] in (109, errno.ESHUTDOWN):
  212. return self._close(which)
  213. raise
  214. if self.universal_newlines:
  215. read = self._translate_newlines(read)
  216. return read
  217. else:
  218. def send(self, input):
  219. if not self.stdin:
  220. return None
  221. if not select.select([], [self.stdin], [], 0)[1]:
  222. return 0
  223. try:
  224. written = os.write(self.stdin.fileno(), input)
  225. except OSError as why:
  226. if why[0] == errno.EPIPE: #broken pipe
  227. return self._close('stdin')
  228. raise
  229. return written
  230. def _recv(self, which, maxsize):
  231. conn, maxsize = self.get_conn_maxsize(which, maxsize)
  232. if conn is None:
  233. return None
  234. flags = fcntl.fcntl(conn, fcntl.F_GETFL)
  235. if not conn.closed:
  236. fcntl.fcntl(conn, fcntl.F_SETFL, flags| os.O_NONBLOCK)
  237. try:
  238. if not select.select([conn], [], [], 0)[0]:
  239. return ''
  240. r = conn.read(maxsize)
  241. if not r:
  242. return self._close(which)
  243. if self.universal_newlines:
  244. r = self._translate_newlines(r)
  245. return r
  246. finally:
  247. if not conn.closed:
  248. fcntl.fcntl(conn, fcntl.F_SETFL, flags)
  249. message = "Other end disconnected!"
  250. def recv_some(p, t = .1, e = 1, tr = 5, stderr = 0):
  251. if tr < 1:
  252. tr = 1
  253. x = time.time()+t
  254. y = []
  255. r = ''
  256. pr = p.recv
  257. if stderr:
  258. pr = p.recv_err
  259. while time.time() < x or r:
  260. r = pr()
  261. if r is None:
  262. if e:
  263. raise Exception(message)
  264. else:
  265. break
  266. elif r:
  267. y.append(r)
  268. else:
  269. time.sleep(max((x-time.time())/tr, 0))
  270. return ''.join(y)
  271. def send_all(p, data):
  272. while len(data):
  273. sent = p.send(data)
  274. if sent is None:
  275. raise Exception(message)
  276. data = buffer(data, sent)
  277. class Command:
  278. """Run command in separate thread. Used for commands launched
  279. on the background.
  280. If stdout/err is redirected, write() method is required for the
  281. given classes.
  282. cmd = Command(cmd=['d.rast', 'elevation.dem'], verbose=3, wait=True)
  283. if cmd.returncode == None:
  284. print 'RUNNING?'
  285. elif cmd.returncode == 0:
  286. print 'SUCCESS'
  287. else:
  288. print 'FAILURE (%d)' % cmd.returncode
  289. """
  290. def __init__ (self, cmd, stdin = None,
  291. verbose = None, wait = True, rerr = False,
  292. stdout = None, stderr = None):
  293. """
  294. :param cmd: command given as list
  295. :param stdin: standard input stream
  296. :param verbose: verbose level [0, 3] (--q, --v)
  297. :param wait: wait for child execution terminated
  298. :param rerr: error handling (when GException raised).
  299. True for redirection to stderr, False for GUI
  300. dialog, None for no operation (quiet mode)
  301. :param stdout: redirect standard output or None
  302. :param stderr: redirect standard error output or None
  303. """
  304. Debug.msg(1, "gcmd.Command(): %s" % ' '.join(cmd))
  305. self.cmd = cmd
  306. self.stderr = stderr
  307. #
  308. # set verbosity level
  309. #
  310. verbose_orig = None
  311. if ('--q' not in self.cmd and '--quiet' not in self.cmd) and \
  312. ('--v' not in self.cmd and '--verbose' not in self.cmd):
  313. if verbose is not None:
  314. if verbose == 0:
  315. self.cmd.append('--quiet')
  316. elif verbose == 3:
  317. self.cmd.append('--verbose')
  318. else:
  319. verbose_orig = os.getenv("GRASS_VERBOSE")
  320. os.environ["GRASS_VERBOSE"] = str(verbose)
  321. #
  322. # create command thread
  323. #
  324. self.cmdThread = CommandThread(cmd, stdin,
  325. stdout, stderr)
  326. self.cmdThread.start()
  327. if wait:
  328. self.cmdThread.join()
  329. if self.cmdThread.module:
  330. self.cmdThread.module.wait()
  331. self.returncode = self.cmdThread.module.returncode
  332. else:
  333. self.returncode = 1
  334. else:
  335. self.cmdThread.join(0.5)
  336. self.returncode = None
  337. if self.returncode is not None:
  338. Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=%d, alive=%s" % \
  339. (' '.join(cmd), wait, self.returncode, self.cmdThread.isAlive()))
  340. if rerr is not None and self.returncode != 0:
  341. if rerr is False: # GUI dialog
  342. raise GException("%s '%s'%s%s%s %s%s" % \
  343. (_("Execution failed:"),
  344. ' '.join(self.cmd),
  345. os.linesep, os.linesep,
  346. _("Details:"),
  347. os.linesep,
  348. _("Error: ") + self.__GetError()))
  349. elif rerr == sys.stderr: # redirect message to sys
  350. stderr.write("Execution failed: '%s'" % (' '.join(self.cmd)))
  351. stderr.write("%sDetails:%s%s" % (os.linesep,
  352. _("Error: ") + self.__GetError(),
  353. os.linesep))
  354. else:
  355. pass # nop
  356. else:
  357. Debug.msg (3, "Command(): cmd='%s', wait=%s, returncode=?, alive=%s" % \
  358. (' '.join(cmd), wait, self.cmdThread.isAlive()))
  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). \
  389. split('%s' % os.linesep)
  390. msg = []
  391. type = None
  392. content = ""
  393. for line in lines:
  394. if len(line) == 0:
  395. continue
  396. if 'GRASS_' in line: # error or warning
  397. if 'GRASS_INFO_WARNING' in line: # warning
  398. type = "WARNING"
  399. elif 'GRASS_INFO_ERROR' in line: # error
  400. type = "ERROR"
  401. elif 'GRASS_INFO_END': # end of message
  402. msg.append((type, content))
  403. type = None
  404. content = ""
  405. if type:
  406. content += line.split(':', 1)[1].strip()
  407. else: # stderr
  408. msg.append((None, line.strip()))
  409. return msg
  410. def __GetError(self):
  411. """Get error message or ''"""
  412. if not self.cmdThread.module:
  413. return _("Unable to exectute command: '%s'") % ' '.join(self.cmd)
  414. for type, msg in self.__ProcessStdErr():
  415. if type == 'ERROR':
  416. if _enc:
  417. return unicode(msg, _enc)
  418. return msg
  419. return ''
  420. class CommandThread(Thread):
  421. """Create separate thread for command. Used for commands launched
  422. on the background."""
  423. def __init__ (self, cmd, env = None, stdin = None,
  424. stdout = sys.stdout, stderr = sys.stderr):
  425. """
  426. :param cmd: command (given as list)
  427. :param env: environmental variables
  428. :param stdin: standard input stream
  429. :param stdout: redirect standard output or None
  430. :param stderr: redirect standard error output or None
  431. """
  432. Thread.__init__(self)
  433. self.cmd = cmd
  434. self.stdin = stdin
  435. self.stdout = stdout
  436. self.stderr = stderr
  437. self.env = env
  438. self.module = None
  439. self.error = ''
  440. self._want_abort = False
  441. self.aborted = False
  442. self.setDaemon(True)
  443. # set message formatting
  444. self.message_format = os.getenv("GRASS_MESSAGE_FORMAT")
  445. os.environ["GRASS_MESSAGE_FORMAT"] = "gui"
  446. def __del__(self):
  447. if self.message_format:
  448. os.environ["GRASS_MESSAGE_FORMAT"] = self.message_format
  449. else:
  450. del os.environ["GRASS_MESSAGE_FORMAT"]
  451. def run(self):
  452. """Run command"""
  453. if len(self.cmd) == 0:
  454. return
  455. Debug.msg(1, "gcmd.CommandThread(): %s" % ' '.join(self.cmd))
  456. self.startTime = time.time()
  457. # TODO: replace ugly hack below
  458. # this cannot be replaced it can be only improved
  459. # also unifying this with 3 other places in code would be nice
  460. # changing from one chdir to get_real_command function
  461. args = self.cmd
  462. if sys.platform == 'win32':
  463. if os.path.splitext(args[0])[1] == globalvar.SCT_EXT:
  464. args[0] = args[0][:-3]
  465. # using Python executable to run the module if it is a script
  466. # expecting at least module name at first position
  467. # cannot use make_command for this now because it is used in GUI
  468. # The same code is in grass.script.core already twice.
  469. args[0] = grass.get_real_command(args[0])
  470. if args[0].endswith('.py'):
  471. args.insert(0, sys.executable)
  472. try:
  473. self.module = Popen(args,
  474. stdin = subprocess.PIPE,
  475. stdout = subprocess.PIPE,
  476. stderr = subprocess.PIPE,
  477. shell = sys.platform == "win32",
  478. env = self.env)
  479. except OSError as e:
  480. self.error = str(e)
  481. print >> sys.stderr, e
  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 subprocess.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 subprocess.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. """
  531. message = ''
  532. for line in text.splitlines():
  533. if len(line) == 0:
  534. continue
  535. elif 'GRASS_INFO_MESSAGE' in line:
  536. message += line.split(':', 1)[1].strip() + '\n'
  537. elif 'GRASS_INFO_WARNING' in line:
  538. message += line.split(':', 1)[1].strip() + '\n'
  539. elif 'GRASS_INFO_ERROR' in line:
  540. message += line.split(':', 1)[1].strip() + '\n'
  541. elif 'GRASS_INFO_END' in line:
  542. return message
  543. else:
  544. message += line.strip() + '\n'
  545. return message
  546. def RunCommand(prog, flags = "", overwrite = False, quiet = False,
  547. verbose = False, parent = None, read = False,
  548. parse = None, stdin = None, getErrorMsg = False, **kwargs):
  549. """Run GRASS command
  550. :param prog: program to run
  551. :param flags: flags given as a string
  552. :param overwrite, quiet, verbose: flags
  553. :param parent: parent window for error messages
  554. :param read: fetch stdout
  555. :param parse: fn to parse stdout (e.g. grass.parse_key_val) or None
  556. :param stdin: stdin or None
  557. :param getErrorMsg: get error messages on failure
  558. :param kwargs: program parameters
  559. :return: returncode (read == False and getErrorMsg == False)
  560. :return: returncode, messages (read == False and getErrorMsg == True)
  561. :return: stdout (read == True and getErrorMsg == False)
  562. :return: returncode, stdout, messages (read == True and getErrorMsg == True)
  563. :return: stdout, stderr
  564. """
  565. cmdString = ' '.join(grass.make_command(prog, flags, overwrite,
  566. quiet, verbose, **kwargs))
  567. Debug.msg(1, "gcmd.RunCommand(): %s" % cmdString)
  568. kwargs['stderr'] = subprocess.PIPE
  569. if read:
  570. kwargs['stdout'] = subprocess.PIPE
  571. if stdin:
  572. kwargs['stdin'] = subprocess.PIPE
  573. if parent:
  574. messageFormat = os.getenv('GRASS_MESSAGE_FORMAT', 'gui')
  575. os.environ['GRASS_MESSAGE_FORMAT'] = 'standard'
  576. start = time.time()
  577. ps = grass.start_command(prog, flags, overwrite, quiet, verbose, **kwargs)
  578. if stdin:
  579. ps.stdin.write(stdin)
  580. ps.stdin.close()
  581. ps.stdin = None
  582. stdout, stderr = map(DecodeString, ps.communicate())
  583. if parent: # restore previous settings
  584. os.environ['GRASS_MESSAGE_FORMAT'] = messageFormat
  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. Debug.msg(1, "GetSystemEncoding(): %s" % enc)
  622. return enc
  623. _enc = GetDefaultEncoding() # define as global variable