builtin.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. # builtin.py - builtins and utilities definitions for pysh.
  2. #
  3. # Copyright 2007 Patrick Mezard
  4. #
  5. # This software may be used and distributed according to the terms
  6. # of the GNU General Public License, incorporated herein by reference.
  7. """Builtin and internal utilities implementations.
  8. - Beware not to use python interpreter environment as if it were the shell
  9. environment. For instance, commands working directory must be explicitely handled
  10. through env['PWD'] instead of relying on python working directory.
  11. """
  12. import errno
  13. import optparse
  14. import os
  15. import re
  16. import subprocess
  17. import sys
  18. import time
  19. def has_subprocess_bug():
  20. return getattr(subprocess, 'list2cmdline') and \
  21. ( subprocess.list2cmdline(['']) == '' or \
  22. subprocess.list2cmdline(['foo|bar']) == 'foo|bar')
  23. # Detect python bug 1634343: "subprocess swallows empty arguments under win32"
  24. # <http://sourceforge.net/tracker/index.php?func=detail&aid=1634343&group_id=5470&atid=105470>
  25. # Also detect: "[ 1710802 ] subprocess must escape redirection characters under win32"
  26. # <http://sourceforge.net/tracker/index.php?func=detail&aid=1710802&group_id=5470&atid=105470>
  27. if has_subprocess_bug():
  28. import subprocess_fix
  29. subprocess.list2cmdline = subprocess_fix.list2cmdline
  30. from sherrors import *
  31. class NonExitingParser(optparse.OptionParser):
  32. """OptionParser default behaviour upon error is to print the error message and
  33. exit. Raise a utility error instead.
  34. """
  35. def error(self, msg):
  36. raise UtilityError(msg)
  37. #-------------------------------------------------------------------------------
  38. # set special builtin
  39. #-------------------------------------------------------------------------------
  40. OPT_SET = NonExitingParser(usage="set - set or unset options and positional parameters")
  41. OPT_SET.add_option( '-f', action='store_true', dest='has_f', default=False,
  42. help='The shell shall disable pathname expansion.')
  43. OPT_SET.add_option('-e', action='store_true', dest='has_e', default=False,
  44. help="""When this option is on, if a simple command fails for any of the \
  45. reasons listed in Consequences of Shell Errors or returns an exit status \
  46. value >0, and is not part of the compound list following a while, until, \
  47. or if keyword, and is not a part of an AND or OR list, and is not a \
  48. pipeline preceded by the ! reserved word, then the shell shall immediately \
  49. exit.""")
  50. OPT_SET.add_option('-x', action='store_true', dest='has_x', default=False,
  51. help="""The shell shall write to standard error a trace for each command \
  52. after it expands the command and before it executes it. It is unspecified \
  53. whether the command that turns tracing off is traced.""")
  54. def builtin_set(name, args, interp, env, stdin, stdout, stderr, debugflags):
  55. if 'debug-utility' in debugflags:
  56. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  57. option, args = OPT_SET.parse_args(args)
  58. env = interp.get_env()
  59. if option.has_f:
  60. env.set_opt('-f')
  61. if option.has_e:
  62. env.set_opt('-e')
  63. if option.has_x:
  64. env.set_opt('-x')
  65. return 0
  66. #-------------------------------------------------------------------------------
  67. # shift special builtin
  68. #-------------------------------------------------------------------------------
  69. def builtin_shift(name, args, interp, env, stdin, stdout, stderr, debugflags):
  70. if 'debug-utility' in debugflags:
  71. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  72. params = interp.get_env().get_positional_args()
  73. if args:
  74. try:
  75. n = int(args[0])
  76. if n > len(params):
  77. raise ValueError()
  78. except ValueError:
  79. return 1
  80. else:
  81. n = 1
  82. params[:n] = []
  83. interp.get_env().set_positional_args(params)
  84. return 0
  85. #-------------------------------------------------------------------------------
  86. # export special builtin
  87. #-------------------------------------------------------------------------------
  88. OPT_EXPORT = NonExitingParser(usage="set - set or unset options and positional parameters")
  89. OPT_EXPORT.add_option('-p', action='store_true', dest='has_p', default=False)
  90. def builtin_export(name, args, interp, env, stdin, stdout, stderr, debugflags):
  91. if 'debug-utility' in debugflags:
  92. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  93. option, args = OPT_EXPORT.parse_args(args)
  94. if option.has_p:
  95. raise NotImplementedError()
  96. for arg in args:
  97. try:
  98. name, value = arg.split('=', 1)
  99. except ValueError:
  100. name, value = arg, None
  101. env = interp.get_env().export(name, value)
  102. return 0
  103. #-------------------------------------------------------------------------------
  104. # return special builtin
  105. #-------------------------------------------------------------------------------
  106. def builtin_return(name, args, interp, env, stdin, stdout, stderr, debugflags):
  107. if 'debug-utility' in debugflags:
  108. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  109. res = 0
  110. if args:
  111. try:
  112. res = int(args[0])
  113. except ValueError:
  114. res = 0
  115. if not 0<=res<=255:
  116. res = 0
  117. # BUG: should be last executed command exit code
  118. raise ReturnSignal(res)
  119. #-------------------------------------------------------------------------------
  120. # trap special builtin
  121. #-------------------------------------------------------------------------------
  122. def builtin_trap(name, args, interp, env, stdin, stdout, stderr, debugflags):
  123. if 'debug-utility' in debugflags:
  124. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  125. if len(args) < 2:
  126. stderr.write('trap: usage: trap [[arg] signal_spec ...]\n')
  127. return 2
  128. action = args[0]
  129. for sig in args[1:]:
  130. try:
  131. env.traps[sig] = action
  132. except Exception, e:
  133. stderr.write('trap: %s\n' % str(e))
  134. return 0
  135. #-------------------------------------------------------------------------------
  136. # unset special builtin
  137. #-------------------------------------------------------------------------------
  138. OPT_UNSET = NonExitingParser("unset - unset values and attributes of variables and functions")
  139. OPT_UNSET.add_option( '-f', action='store_true', dest='has_f', default=False)
  140. OPT_UNSET.add_option( '-v', action='store_true', dest='has_v', default=False)
  141. def builtin_unset(name, args, interp, env, stdin, stdout, stderr, debugflags):
  142. if 'debug-utility' in debugflags:
  143. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  144. option, args = OPT_UNSET.parse_args(args)
  145. status = 0
  146. env = interp.get_env()
  147. for arg in args:
  148. try:
  149. if option.has_f:
  150. env.remove_function(arg)
  151. else:
  152. del env[arg]
  153. except KeyError:
  154. pass
  155. except VarAssignmentError:
  156. status = 1
  157. return status
  158. #-------------------------------------------------------------------------------
  159. # wait special builtin
  160. #-------------------------------------------------------------------------------
  161. def builtin_wait(name, args, interp, env, stdin, stdout, stderr, debugflags):
  162. if 'debug-utility' in debugflags:
  163. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  164. return interp.wait([int(arg) for arg in args])
  165. #-------------------------------------------------------------------------------
  166. # cat utility
  167. #-------------------------------------------------------------------------------
  168. def utility_cat(name, args, interp, env, stdin, stdout, stderr, debugflags):
  169. if 'debug-utility' in debugflags:
  170. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  171. if not args:
  172. args = ['-']
  173. status = 0
  174. for arg in args:
  175. if arg == '-':
  176. data = stdin.read()
  177. else:
  178. path = os.path.join(env['PWD'], arg)
  179. try:
  180. f = file(path, 'rb')
  181. try:
  182. data = f.read()
  183. finally:
  184. f.close()
  185. except IOError, e:
  186. if e.errno != errno.ENOENT:
  187. raise
  188. status = 1
  189. continue
  190. stdout.write(data)
  191. stdout.flush()
  192. return status
  193. #-------------------------------------------------------------------------------
  194. # cd utility
  195. #-------------------------------------------------------------------------------
  196. OPT_CD = NonExitingParser("cd - change the working directory")
  197. def utility_cd(name, args, interp, env, stdin, stdout, stderr, debugflags):
  198. if 'debug-utility' in debugflags:
  199. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  200. option, args = OPT_CD.parse_args(args)
  201. env = interp.get_env()
  202. directory = None
  203. printdir = False
  204. if not args:
  205. home = env.get('HOME')
  206. if home:
  207. # Unspecified, do nothing
  208. return 0
  209. else:
  210. directory = home
  211. elif len(args)==1:
  212. directory = args[0]
  213. if directory=='-':
  214. if 'OLDPWD' not in env:
  215. raise UtilityError("OLDPWD not set")
  216. printdir = True
  217. directory = env['OLDPWD']
  218. else:
  219. raise UtilityError("too many arguments")
  220. curpath = None
  221. # Absolute directories will be handled correctly by the os.path.join call.
  222. if not directory.startswith('.') and not directory.startswith('..'):
  223. cdpaths = env.get('CDPATH', '.').split(';')
  224. for cdpath in cdpaths:
  225. p = os.path.join(cdpath, directory)
  226. if os.path.isdir(p):
  227. curpath = p
  228. break
  229. if curpath is None:
  230. curpath = directory
  231. curpath = os.path.join(env['PWD'], directory)
  232. env['OLDPWD'] = env['PWD']
  233. env['PWD'] = curpath
  234. if printdir:
  235. stdout.write('%s\n' % curpath)
  236. return 0
  237. #-------------------------------------------------------------------------------
  238. # colon utility
  239. #-------------------------------------------------------------------------------
  240. def utility_colon(name, args, interp, env, stdin, stdout, stderr, debugflags):
  241. if 'debug-utility' in debugflags:
  242. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  243. return 0
  244. #-------------------------------------------------------------------------------
  245. # echo utility
  246. #-------------------------------------------------------------------------------
  247. def utility_echo(name, args, interp, env, stdin, stdout, stderr, debugflags):
  248. if 'debug-utility' in debugflags:
  249. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  250. # Echo only takes arguments, no options. Use printf if you need fancy stuff.
  251. output = ' '.join(args) + '\n'
  252. stdout.write(output)
  253. stdout.flush()
  254. return 0
  255. #-------------------------------------------------------------------------------
  256. # egrep utility
  257. #-------------------------------------------------------------------------------
  258. # egrep is usually a shell script.
  259. # Unfortunately, pysh does not support shell scripts *with arguments* right now,
  260. # so the redirection is implemented here, assuming grep is available.
  261. def utility_egrep(name, args, interp, env, stdin, stdout, stderr, debugflags):
  262. if 'debug-utility' in debugflags:
  263. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  264. return run_command('grep', ['-E'] + args, interp, env, stdin, stdout,
  265. stderr, debugflags)
  266. #-------------------------------------------------------------------------------
  267. # env utility
  268. #-------------------------------------------------------------------------------
  269. def utility_env(name, args, interp, env, stdin, stdout, stderr, debugflags):
  270. if 'debug-utility' in debugflags:
  271. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  272. if args and args[0]=='-i':
  273. raise NotImplementedError('env: -i option is not implemented')
  274. i = 0
  275. for arg in args:
  276. if '=' not in arg:
  277. break
  278. # Update the current environment
  279. name, value = arg.split('=', 1)
  280. env[name] = value
  281. i += 1
  282. if args[i:]:
  283. # Find then execute the specified interpreter
  284. utility = env.find_in_path(args[i])
  285. if not utility:
  286. return 127
  287. args[i:i+1] = utility
  288. name = args[i]
  289. args = args[i+1:]
  290. try:
  291. return run_command(name, args, interp, env, stdin, stdout, stderr,
  292. debugflags)
  293. except UtilityError:
  294. stderr.write('env: failed to execute %s' % ' '.join([name]+args))
  295. return 126
  296. else:
  297. for pair in env.get_variables().iteritems():
  298. stdout.write('%s=%s\n' % pair)
  299. return 0
  300. #-------------------------------------------------------------------------------
  301. # exit utility
  302. #-------------------------------------------------------------------------------
  303. def utility_exit(name, args, interp, env, stdin, stdout, stderr, debugflags):
  304. if 'debug-utility' in debugflags:
  305. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  306. res = None
  307. if args:
  308. try:
  309. res = int(args[0])
  310. except ValueError:
  311. res = None
  312. if not 0<=res<=255:
  313. res = None
  314. if res is None:
  315. # BUG: should be last executed command exit code
  316. res = 0
  317. raise ExitSignal(res)
  318. #-------------------------------------------------------------------------------
  319. # fgrep utility
  320. #-------------------------------------------------------------------------------
  321. # see egrep
  322. def utility_fgrep(name, args, interp, env, stdin, stdout, stderr, debugflags):
  323. if 'debug-utility' in debugflags:
  324. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  325. return run_command('grep', ['-F'] + args, interp, env, stdin, stdout,
  326. stderr, debugflags)
  327. #-------------------------------------------------------------------------------
  328. # gunzip utility
  329. #-------------------------------------------------------------------------------
  330. # see egrep
  331. def utility_gunzip(name, args, interp, env, stdin, stdout, stderr, debugflags):
  332. if 'debug-utility' in debugflags:
  333. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  334. return run_command('gzip', ['-d'] + args, interp, env, stdin, stdout,
  335. stderr, debugflags)
  336. #-------------------------------------------------------------------------------
  337. # kill utility
  338. #-------------------------------------------------------------------------------
  339. def utility_kill(name, args, interp, env, stdin, stdout, stderr, debugflags):
  340. if 'debug-utility' in debugflags:
  341. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  342. for arg in args:
  343. pid = int(arg)
  344. status = subprocess.call(['pskill', '/T', str(pid)],
  345. shell=True,
  346. stdout=subprocess.PIPE,
  347. stderr=subprocess.PIPE)
  348. # pskill is asynchronous, hence the stupid polling loop
  349. while 1:
  350. p = subprocess.Popen(['pslist', str(pid)],
  351. shell=True,
  352. stdout=subprocess.PIPE,
  353. stderr=subprocess.STDOUT)
  354. output = p.communicate()[0]
  355. if ('process %d was not' % pid) in output:
  356. break
  357. time.sleep(1)
  358. return status
  359. #-------------------------------------------------------------------------------
  360. # mkdir utility
  361. #-------------------------------------------------------------------------------
  362. OPT_MKDIR = NonExitingParser("mkdir - make directories.")
  363. OPT_MKDIR.add_option('-p', action='store_true', dest='has_p', default=False)
  364. def utility_mkdir(name, args, interp, env, stdin, stdout, stderr, debugflags):
  365. if 'debug-utility' in debugflags:
  366. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  367. # TODO: implement umask
  368. # TODO: implement proper utility error report
  369. option, args = OPT_MKDIR.parse_args(args)
  370. for arg in args:
  371. path = os.path.join(env['PWD'], arg)
  372. if option.has_p:
  373. try:
  374. os.makedirs(path)
  375. except IOError, e:
  376. if e.errno != errno.EEXIST:
  377. raise
  378. else:
  379. os.mkdir(path)
  380. return 0
  381. #-------------------------------------------------------------------------------
  382. # netstat utility
  383. #-------------------------------------------------------------------------------
  384. def utility_netstat(name, args, interp, env, stdin, stdout, stderr, debugflags):
  385. # Do you really expect me to implement netstat ?
  386. # This empty form is enough for Mercurial tests since it's
  387. # supposed to generate nothing upon success. Faking this test
  388. # is not a big deal either.
  389. if 'debug-utility' in debugflags:
  390. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  391. return 0
  392. #-------------------------------------------------------------------------------
  393. # pwd utility
  394. #-------------------------------------------------------------------------------
  395. OPT_PWD = NonExitingParser("pwd - return working directory name")
  396. OPT_PWD.add_option('-L', action='store_true', dest='has_L', default=True,
  397. help="""If the PWD environment variable contains an absolute pathname of \
  398. the current directory that does not contain the filenames dot or dot-dot, \
  399. pwd shall write this pathname to standard output. Otherwise, the -L option \
  400. shall behave as the -P option.""")
  401. OPT_PWD.add_option('-P', action='store_true', dest='has_L', default=False,
  402. help="""The absolute pathname written shall not contain filenames that, in \
  403. the context of the pathname, refer to files of type symbolic link.""")
  404. def utility_pwd(name, args, interp, env, stdin, stdout, stderr, debugflags):
  405. if 'debug-utility' in debugflags:
  406. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  407. option, args = OPT_PWD.parse_args(args)
  408. stdout.write('%s\n' % env['PWD'])
  409. return 0
  410. #-------------------------------------------------------------------------------
  411. # printf utility
  412. #-------------------------------------------------------------------------------
  413. RE_UNESCAPE = re.compile(r'(\\x[a-zA-Z0-9]{2}|\\[0-7]{1,3}|\\.)')
  414. def utility_printf(name, args, interp, env, stdin, stdout, stderr, debugflags):
  415. if 'debug-utility' in debugflags:
  416. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  417. def replace(m):
  418. assert m.group()
  419. g = m.group()[1:]
  420. if g.startswith('x'):
  421. return chr(int(g[1:], 16))
  422. if len(g) <= 3 and len([c for c in g if c in '01234567']) == len(g):
  423. # Yay, an octal number
  424. return chr(int(g, 8))
  425. return {
  426. 'a': '\a',
  427. 'b': '\b',
  428. 'f': '\f',
  429. 'n': '\n',
  430. 'r': '\r',
  431. 't': '\t',
  432. 'v': '\v',
  433. '\\': '\\',
  434. }.get(g)
  435. # Convert escape sequences
  436. format = re.sub(RE_UNESCAPE, replace, args[0])
  437. stdout.write(format % tuple(args[1:]))
  438. return 0
  439. #-------------------------------------------------------------------------------
  440. # true utility
  441. #-------------------------------------------------------------------------------
  442. def utility_true(name, args, interp, env, stdin, stdout, stderr, debugflags):
  443. if 'debug-utility' in debugflags:
  444. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  445. return 0
  446. #-------------------------------------------------------------------------------
  447. # sed utility
  448. #-------------------------------------------------------------------------------
  449. RE_SED = re.compile(r'^s(.).*\1[a-zA-Z]*$')
  450. # cygwin sed fails with some expressions when they do not end with a single space.
  451. # see unit tests for details. Interestingly, the same expressions works perfectly
  452. # in cygwin shell.
  453. def utility_sed(name, args, interp, env, stdin, stdout, stderr, debugflags):
  454. if 'debug-utility' in debugflags:
  455. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  456. # Scan pattern arguments and append a space if necessary
  457. for i in xrange(len(args)):
  458. if not RE_SED.search(args[i]):
  459. continue
  460. args[i] = args[i] + ' '
  461. return run_command(name, args, interp, env, stdin, stdout,
  462. stderr, debugflags)
  463. #-------------------------------------------------------------------------------
  464. # sleep utility
  465. #-------------------------------------------------------------------------------
  466. def utility_sleep(name, args, interp, env, stdin, stdout, stderr, debugflags):
  467. if 'debug-utility' in debugflags:
  468. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  469. time.sleep(int(args[0]))
  470. return 0
  471. #-------------------------------------------------------------------------------
  472. # sort utility
  473. #-------------------------------------------------------------------------------
  474. OPT_SORT = NonExitingParser("sort - sort, merge, or sequence check text files")
  475. def utility_sort(name, args, interp, env, stdin, stdout, stderr, debugflags):
  476. def sort(path):
  477. if path == '-':
  478. lines = stdin.readlines()
  479. else:
  480. try:
  481. f = file(path)
  482. try:
  483. lines = f.readlines()
  484. finally:
  485. f.close()
  486. except IOError, e:
  487. stderr.write(str(e) + '\n')
  488. return 1
  489. if lines and lines[-1][-1]!='\n':
  490. lines[-1] = lines[-1] + '\n'
  491. return lines
  492. if 'debug-utility' in debugflags:
  493. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  494. option, args = OPT_SORT.parse_args(args)
  495. alllines = []
  496. if len(args)<=0:
  497. args += ['-']
  498. # Load all files lines
  499. curdir = os.getcwd()
  500. try:
  501. os.chdir(env['PWD'])
  502. for path in args:
  503. alllines += sort(path)
  504. finally:
  505. os.chdir(curdir)
  506. alllines.sort()
  507. for line in alllines:
  508. stdout.write(line)
  509. return 0
  510. #-------------------------------------------------------------------------------
  511. # hg utility
  512. #-------------------------------------------------------------------------------
  513. hgcommands = [
  514. 'add',
  515. 'addremove',
  516. 'commit', 'ci',
  517. 'debugrename',
  518. 'debugwalk',
  519. 'falabala', # Dummy command used in a mercurial test
  520. 'incoming',
  521. 'locate',
  522. 'pull',
  523. 'push',
  524. 'qinit',
  525. 'remove', 'rm',
  526. 'rename', 'mv',
  527. 'revert',
  528. 'showconfig',
  529. 'status', 'st',
  530. 'strip',
  531. ]
  532. def rewriteslashes(name, args):
  533. # Several hg commands output file paths, rewrite the separators
  534. if len(args) > 1 and name.lower().endswith('python') \
  535. and args[0].endswith('hg'):
  536. for cmd in hgcommands:
  537. if cmd in args[1:]:
  538. return True
  539. # svn output contains many paths with OS specific separators.
  540. # Normalize these to unix paths.
  541. base = os.path.basename(name)
  542. if base.startswith('svn'):
  543. return True
  544. return False
  545. def rewritehg(output):
  546. if not output:
  547. return output
  548. # Rewrite os specific messages
  549. output = output.replace(': The system cannot find the file specified',
  550. ': No such file or directory')
  551. output = re.sub(': Access is denied.*$', ': Permission denied', output)
  552. output = output.replace(': No connection could be made because the target machine actively refused it',
  553. ': Connection refused')
  554. return output
  555. def run_command(name, args, interp, env, stdin, stdout,
  556. stderr, debugflags):
  557. # Execute the command
  558. if 'debug-utility' in debugflags:
  559. print interp.log(' '.join([name, str(args), interp['PWD']]) + '\n')
  560. hgbin = interp.options().hgbinary
  561. ishg = hgbin and ('hg' in name or args and 'hg' in args[0])
  562. unixoutput = 'cygwin' in name or ishg
  563. exec_env = env.get_variables()
  564. try:
  565. # BUG: comparing file descriptor is clearly not a reliable way to tell
  566. # whether they point on the same underlying object. But in pysh limited
  567. # scope this is usually right, we do not expect complicated redirections
  568. # besides usual 2>&1.
  569. # Still there is one case we have but cannot deal with is when stdout
  570. # and stderr are redirected *by pysh caller*. This the reason for the
  571. # --redirect pysh() option.
  572. # Now, we want to know they are the same because we sometimes need to
  573. # transform the command output, mostly remove CR-LF to ensure that
  574. # command output is unix-like. Cygwin utilies are a special case because
  575. # they explicitely set their output streams to binary mode, so we have
  576. # nothing to do. For all others commands, we have to guess whether they
  577. # are sending text data, in which case the transformation must be done.
  578. # Again, the NUL character test is unreliable but should be enough for
  579. # hg tests.
  580. redirected = stdout.fileno()==stderr.fileno()
  581. if not redirected:
  582. p = subprocess.Popen([name] + args, cwd=env['PWD'], env=exec_env,
  583. stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  584. else:
  585. p = subprocess.Popen([name] + args, cwd=env['PWD'], env=exec_env,
  586. stdin=stdin, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
  587. out, err = p.communicate()
  588. except WindowsError, e:
  589. raise UtilityError(str(e))
  590. if not unixoutput:
  591. def encode(s):
  592. if '\0' in s:
  593. return s
  594. return s.replace('\r\n', '\n')
  595. else:
  596. encode = lambda s: s
  597. if rewriteslashes(name, args):
  598. encode1_ = encode
  599. def encode(s):
  600. s = encode1_(s)
  601. s = s.replace('\\\\', '\\')
  602. s = s.replace('\\', '/')
  603. return s
  604. if ishg:
  605. encode2_ = encode
  606. def encode(s):
  607. return rewritehg(encode2_(s))
  608. stdout.write(encode(out))
  609. if not redirected:
  610. stderr.write(encode(err))
  611. return p.returncode