gcmd.py 25 KB

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