gcmd.py 24 KB

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