1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
# util.py - utility functions from Mercurial
#
# Copyright 2006, 2015 Matt Mackall <mpm@selenic.com>
# Copyright 2007 Eric St-Jean <esj@wwd.ca>
# Copyright 2009, 2011 Mads Kiilerich <mads@kiilerich.com>
# Copyright 2015 Pierre-Yves David <pierre-yves.david@fb.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version
from __future__ import unicode_literals
from gettext import gettext as _
import os
import subprocess
import shutil
import sys
from . import encoding
closefds = os.name == 'posix'
def explainexit(code):
"""return a 2-tuple (desc, code) describing a subprocess status
(codes from kill are negative - not os.system/wait encoding)"""
if (code < 0) and (os.name == 'posix'):
return _("killed by signal %d") % -code, -code
else:
return _("exited with status %d") % code, code
class Abort(Exception):
pass
def system(cmd, cwd=None, onerr=None, errprefix=None):
try:
sys.stdout.flush()
except Exception:
pass
if isinstance(cmd, list):
shell = False
prog = os.path.basename(cmd[0])
else:
shell = True
prog = os.path.basename(cmd.split(None, 1)[0])
rc = subprocess.call(cmd, shell=shell, close_fds=closefds,
cwd=cwd)
if rc and onerr:
errmsg = '%s %s' % (prog,
explainexit(rc)[0])
if errprefix:
errmsg = '%s: %s' % (errprefix, errmsg)
raise onerr(errmsg)
return rc
def systemcall(cmd, onerr=None, errprefix=None):
try:
sys.stdout.flush()
except Exception:
pass
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, close_fds=closefds)
out = ''
for line in iter(p.stdout.readline, b''):
out = out + line.decode(encoding.encoding)
p.wait()
rc = p.returncode
if rc and onerr:
errmsg = '%s %s' % (os.path.basename(cmd[0]),
explainexit(rc)[0])
if errprefix:
errmsg = '%s: %s' % (errprefix, errmsg)
raise onerr(errmsg)
return out
def copyfile(src, dest, hardlink=False, copystat=False):
'''copy a file, preserving mode and optionally other stat info like
atime/mtime'''
if os.path.lexists(dest):
os.unlink(dest)
# hardlinks are problematic on CIFS, quietly ignore this flag
# until we find a way to work around it cleanly (issue4546)
if False and hardlink:
try:
os.link(src, dest)
return
except (IOError, OSError):
pass # fall back to normal copy
if os.path.islink(src):
os.symlink(os.readlink(src), dest)
# copytime is ignored for symlinks, but in general copytime isn't needed
# for them anyway
else:
try:
shutil.copyfile(src, dest)
if copystat:
# copystat also copies mode
shutil.copystat(src, dest)
else:
shutil.copymode(src, dest)
except shutil.Error as inst:
raise Abort(str(inst))
def ellipsis(text, maxlength=400):
"""Trim string to at most maxlength (default: 400) columns in display."""
return encoding.trim(text, maxlength, ellipsis='...')
_notset = object()
def safehasattr(thing, attr):
return getattr(thing, attr, _notset) is not _notset
|