Statistics
| Branch: | Tag: | Revision:

root / lib / utils / text.py @ 9c007da8

History | View | Annotate | Download (11.4 kB)

1 7fcffe27 Michael Hanselmann
#
2 7fcffe27 Michael Hanselmann
#
3 7fcffe27 Michael Hanselmann
4 7fcffe27 Michael Hanselmann
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 7fcffe27 Michael Hanselmann
#
6 7fcffe27 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 7fcffe27 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 7fcffe27 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 7fcffe27 Michael Hanselmann
# (at your option) any later version.
10 7fcffe27 Michael Hanselmann
#
11 7fcffe27 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 7fcffe27 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 7fcffe27 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 7fcffe27 Michael Hanselmann
# General Public License for more details.
15 7fcffe27 Michael Hanselmann
#
16 7fcffe27 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 7fcffe27 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 7fcffe27 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 7fcffe27 Michael Hanselmann
# 02110-1301, USA.
20 7fcffe27 Michael Hanselmann
21 7fcffe27 Michael Hanselmann
"""Utility functions for manipulating or working with text.
22 7fcffe27 Michael Hanselmann

23 7fcffe27 Michael Hanselmann
"""
24 7fcffe27 Michael Hanselmann
25 7fcffe27 Michael Hanselmann
26 7fcffe27 Michael Hanselmann
import re
27 7fcffe27 Michael Hanselmann
import os
28 7fcffe27 Michael Hanselmann
import time
29 7fcffe27 Michael Hanselmann
import collections
30 7fcffe27 Michael Hanselmann
31 7fcffe27 Michael Hanselmann
from ganeti import errors
32 7fcffe27 Michael Hanselmann
33 7fcffe27 Michael Hanselmann
34 7fcffe27 Michael Hanselmann
#: Unit checker regexp
35 7fcffe27 Michael Hanselmann
_PARSEUNIT_REGEX = re.compile(r"^([.\d]+)\s*([a-zA-Z]+)?$")
36 7fcffe27 Michael Hanselmann
37 7fcffe27 Michael Hanselmann
#: Characters which don't need to be quoted for shell commands
38 7fcffe27 Michael Hanselmann
_SHELL_UNQUOTED_RE = re.compile('^[-.,=:/_+@A-Za-z0-9]+$')
39 7fcffe27 Michael Hanselmann
40 7fcffe27 Michael Hanselmann
#: MAC checker regexp
41 7fcffe27 Michael Hanselmann
_MAC_CHECK_RE = re.compile("^([0-9a-f]{2}:){5}[0-9a-f]{2}$", re.I)
42 7fcffe27 Michael Hanselmann
43 7fcffe27 Michael Hanselmann
44 7fcffe27 Michael Hanselmann
def MatchNameComponent(key, name_list, case_sensitive=True):
45 7fcffe27 Michael Hanselmann
  """Try to match a name against a list.
46 7fcffe27 Michael Hanselmann

47 7fcffe27 Michael Hanselmann
  This function will try to match a name like test1 against a list
48 7fcffe27 Michael Hanselmann
  like C{['test1.example.com', 'test2.example.com', ...]}. Against
49 7fcffe27 Michael Hanselmann
  this list, I{'test1'} as well as I{'test1.example'} will match, but
50 7fcffe27 Michael Hanselmann
  not I{'test1.ex'}. A multiple match will be considered as no match
51 7fcffe27 Michael Hanselmann
  at all (e.g. I{'test1'} against C{['test1.example.com',
52 7fcffe27 Michael Hanselmann
  'test1.example.org']}), except when the key fully matches an entry
53 7fcffe27 Michael Hanselmann
  (e.g. I{'test1'} against C{['test1', 'test1.example.com']}).
54 7fcffe27 Michael Hanselmann

55 7fcffe27 Michael Hanselmann
  @type key: str
56 7fcffe27 Michael Hanselmann
  @param key: the name to be searched
57 7fcffe27 Michael Hanselmann
  @type name_list: list
58 7fcffe27 Michael Hanselmann
  @param name_list: the list of strings against which to search the key
59 7fcffe27 Michael Hanselmann
  @type case_sensitive: boolean
60 7fcffe27 Michael Hanselmann
  @param case_sensitive: whether to provide a case-sensitive match
61 7fcffe27 Michael Hanselmann

62 7fcffe27 Michael Hanselmann
  @rtype: None or str
63 7fcffe27 Michael Hanselmann
  @return: None if there is no match I{or} if there are multiple matches,
64 7fcffe27 Michael Hanselmann
      otherwise the element from the list which matches
65 7fcffe27 Michael Hanselmann

66 7fcffe27 Michael Hanselmann
  """
67 7fcffe27 Michael Hanselmann
  if key in name_list:
68 7fcffe27 Michael Hanselmann
    return key
69 7fcffe27 Michael Hanselmann
70 7fcffe27 Michael Hanselmann
  re_flags = 0
71 7fcffe27 Michael Hanselmann
  if not case_sensitive:
72 7fcffe27 Michael Hanselmann
    re_flags |= re.IGNORECASE
73 7fcffe27 Michael Hanselmann
    key = key.upper()
74 7fcffe27 Michael Hanselmann
  mo = re.compile("^%s(\..*)?$" % re.escape(key), re_flags)
75 7fcffe27 Michael Hanselmann
  names_filtered = []
76 7fcffe27 Michael Hanselmann
  string_matches = []
77 7fcffe27 Michael Hanselmann
  for name in name_list:
78 7fcffe27 Michael Hanselmann
    if mo.match(name) is not None:
79 7fcffe27 Michael Hanselmann
      names_filtered.append(name)
80 7fcffe27 Michael Hanselmann
      if not case_sensitive and key == name.upper():
81 7fcffe27 Michael Hanselmann
        string_matches.append(name)
82 7fcffe27 Michael Hanselmann
83 7fcffe27 Michael Hanselmann
  if len(string_matches) == 1:
84 7fcffe27 Michael Hanselmann
    return string_matches[0]
85 7fcffe27 Michael Hanselmann
  if len(names_filtered) == 1:
86 7fcffe27 Michael Hanselmann
    return names_filtered[0]
87 7fcffe27 Michael Hanselmann
  return None
88 7fcffe27 Michael Hanselmann
89 7fcffe27 Michael Hanselmann
90 7fcffe27 Michael Hanselmann
def FormatUnit(value, units):
91 7fcffe27 Michael Hanselmann
  """Formats an incoming number of MiB with the appropriate unit.
92 7fcffe27 Michael Hanselmann

93 7fcffe27 Michael Hanselmann
  @type value: int
94 7fcffe27 Michael Hanselmann
  @param value: integer representing the value in MiB (1048576)
95 7fcffe27 Michael Hanselmann
  @type units: char
96 7fcffe27 Michael Hanselmann
  @param units: the type of formatting we should do:
97 7fcffe27 Michael Hanselmann
      - 'h' for automatic scaling
98 7fcffe27 Michael Hanselmann
      - 'm' for MiBs
99 7fcffe27 Michael Hanselmann
      - 'g' for GiBs
100 7fcffe27 Michael Hanselmann
      - 't' for TiBs
101 7fcffe27 Michael Hanselmann
  @rtype: str
102 7fcffe27 Michael Hanselmann
  @return: the formatted value (with suffix)
103 7fcffe27 Michael Hanselmann

104 7fcffe27 Michael Hanselmann
  """
105 7fcffe27 Michael Hanselmann
  if units not in ('m', 'g', 't', 'h'):
106 7fcffe27 Michael Hanselmann
    raise errors.ProgrammerError("Invalid unit specified '%s'" % str(units))
107 7fcffe27 Michael Hanselmann
108 7fcffe27 Michael Hanselmann
  suffix = ''
109 7fcffe27 Michael Hanselmann
110 7fcffe27 Michael Hanselmann
  if units == 'm' or (units == 'h' and value < 1024):
111 7fcffe27 Michael Hanselmann
    if units == 'h':
112 7fcffe27 Michael Hanselmann
      suffix = 'M'
113 7fcffe27 Michael Hanselmann
    return "%d%s" % (round(value, 0), suffix)
114 7fcffe27 Michael Hanselmann
115 7fcffe27 Michael Hanselmann
  elif units == 'g' or (units == 'h' and value < (1024 * 1024)):
116 7fcffe27 Michael Hanselmann
    if units == 'h':
117 7fcffe27 Michael Hanselmann
      suffix = 'G'
118 7fcffe27 Michael Hanselmann
    return "%0.1f%s" % (round(float(value) / 1024, 1), suffix)
119 7fcffe27 Michael Hanselmann
120 7fcffe27 Michael Hanselmann
  else:
121 7fcffe27 Michael Hanselmann
    if units == 'h':
122 7fcffe27 Michael Hanselmann
      suffix = 'T'
123 7fcffe27 Michael Hanselmann
    return "%0.1f%s" % (round(float(value) / 1024 / 1024, 1), suffix)
124 7fcffe27 Michael Hanselmann
125 7fcffe27 Michael Hanselmann
126 7fcffe27 Michael Hanselmann
def ParseUnit(input_string):
127 7fcffe27 Michael Hanselmann
  """Tries to extract number and scale from the given string.
128 7fcffe27 Michael Hanselmann

129 7fcffe27 Michael Hanselmann
  Input must be in the format C{NUMBER+ [DOT NUMBER+] SPACE*
130 7fcffe27 Michael Hanselmann
  [UNIT]}. If no unit is specified, it defaults to MiB. Return value
131 7fcffe27 Michael Hanselmann
  is always an int in MiB.
132 7fcffe27 Michael Hanselmann

133 7fcffe27 Michael Hanselmann
  """
134 7fcffe27 Michael Hanselmann
  m = _PARSEUNIT_REGEX.match(str(input_string))
135 7fcffe27 Michael Hanselmann
  if not m:
136 7fcffe27 Michael Hanselmann
    raise errors.UnitParseError("Invalid format")
137 7fcffe27 Michael Hanselmann
138 7fcffe27 Michael Hanselmann
  value = float(m.groups()[0])
139 7fcffe27 Michael Hanselmann
140 7fcffe27 Michael Hanselmann
  unit = m.groups()[1]
141 7fcffe27 Michael Hanselmann
  if unit:
142 7fcffe27 Michael Hanselmann
    lcunit = unit.lower()
143 7fcffe27 Michael Hanselmann
  else:
144 7fcffe27 Michael Hanselmann
    lcunit = 'm'
145 7fcffe27 Michael Hanselmann
146 7fcffe27 Michael Hanselmann
  if lcunit in ('m', 'mb', 'mib'):
147 7fcffe27 Michael Hanselmann
    # Value already in MiB
148 7fcffe27 Michael Hanselmann
    pass
149 7fcffe27 Michael Hanselmann
150 7fcffe27 Michael Hanselmann
  elif lcunit in ('g', 'gb', 'gib'):
151 7fcffe27 Michael Hanselmann
    value *= 1024
152 7fcffe27 Michael Hanselmann
153 7fcffe27 Michael Hanselmann
  elif lcunit in ('t', 'tb', 'tib'):
154 7fcffe27 Michael Hanselmann
    value *= 1024 * 1024
155 7fcffe27 Michael Hanselmann
156 7fcffe27 Michael Hanselmann
  else:
157 7fcffe27 Michael Hanselmann
    raise errors.UnitParseError("Unknown unit: %s" % unit)
158 7fcffe27 Michael Hanselmann
159 7fcffe27 Michael Hanselmann
  # Make sure we round up
160 7fcffe27 Michael Hanselmann
  if int(value) < value:
161 7fcffe27 Michael Hanselmann
    value += 1
162 7fcffe27 Michael Hanselmann
163 7fcffe27 Michael Hanselmann
  # Round up to the next multiple of 4
164 7fcffe27 Michael Hanselmann
  value = int(value)
165 7fcffe27 Michael Hanselmann
  if value % 4:
166 7fcffe27 Michael Hanselmann
    value += 4 - value % 4
167 7fcffe27 Michael Hanselmann
168 7fcffe27 Michael Hanselmann
  return value
169 7fcffe27 Michael Hanselmann
170 7fcffe27 Michael Hanselmann
171 7fcffe27 Michael Hanselmann
def ShellQuote(value):
172 7fcffe27 Michael Hanselmann
  """Quotes shell argument according to POSIX.
173 7fcffe27 Michael Hanselmann

174 7fcffe27 Michael Hanselmann
  @type value: str
175 7fcffe27 Michael Hanselmann
  @param value: the argument to be quoted
176 7fcffe27 Michael Hanselmann
  @rtype: str
177 7fcffe27 Michael Hanselmann
  @return: the quoted value
178 7fcffe27 Michael Hanselmann

179 7fcffe27 Michael Hanselmann
  """
180 7fcffe27 Michael Hanselmann
  if _SHELL_UNQUOTED_RE.match(value):
181 7fcffe27 Michael Hanselmann
    return value
182 7fcffe27 Michael Hanselmann
  else:
183 7fcffe27 Michael Hanselmann
    return "'%s'" % value.replace("'", "'\\''")
184 7fcffe27 Michael Hanselmann
185 7fcffe27 Michael Hanselmann
186 7fcffe27 Michael Hanselmann
def ShellQuoteArgs(args):
187 7fcffe27 Michael Hanselmann
  """Quotes a list of shell arguments.
188 7fcffe27 Michael Hanselmann

189 7fcffe27 Michael Hanselmann
  @type args: list
190 7fcffe27 Michael Hanselmann
  @param args: list of arguments to be quoted
191 7fcffe27 Michael Hanselmann
  @rtype: str
192 7fcffe27 Michael Hanselmann
  @return: the quoted arguments concatenated with spaces
193 7fcffe27 Michael Hanselmann

194 7fcffe27 Michael Hanselmann
  """
195 7fcffe27 Michael Hanselmann
  return " ".join([ShellQuote(i) for i in args])
196 7fcffe27 Michael Hanselmann
197 7fcffe27 Michael Hanselmann
198 7fcffe27 Michael Hanselmann
class ShellWriter:
199 7fcffe27 Michael Hanselmann
  """Helper class to write scripts with indentation.
200 7fcffe27 Michael Hanselmann

201 7fcffe27 Michael Hanselmann
  """
202 7fcffe27 Michael Hanselmann
  INDENT_STR = "  "
203 7fcffe27 Michael Hanselmann
204 7fcffe27 Michael Hanselmann
  def __init__(self, fh):
205 7fcffe27 Michael Hanselmann
    """Initializes this class.
206 7fcffe27 Michael Hanselmann

207 7fcffe27 Michael Hanselmann
    """
208 7fcffe27 Michael Hanselmann
    self._fh = fh
209 7fcffe27 Michael Hanselmann
    self._indent = 0
210 7fcffe27 Michael Hanselmann
211 7fcffe27 Michael Hanselmann
  def IncIndent(self):
212 7fcffe27 Michael Hanselmann
    """Increase indentation level by 1.
213 7fcffe27 Michael Hanselmann

214 7fcffe27 Michael Hanselmann
    """
215 7fcffe27 Michael Hanselmann
    self._indent += 1
216 7fcffe27 Michael Hanselmann
217 7fcffe27 Michael Hanselmann
  def DecIndent(self):
218 7fcffe27 Michael Hanselmann
    """Decrease indentation level by 1.
219 7fcffe27 Michael Hanselmann

220 7fcffe27 Michael Hanselmann
    """
221 7fcffe27 Michael Hanselmann
    assert self._indent > 0
222 7fcffe27 Michael Hanselmann
    self._indent -= 1
223 7fcffe27 Michael Hanselmann
224 7fcffe27 Michael Hanselmann
  def Write(self, txt, *args):
225 7fcffe27 Michael Hanselmann
    """Write line to output file.
226 7fcffe27 Michael Hanselmann

227 7fcffe27 Michael Hanselmann
    """
228 7fcffe27 Michael Hanselmann
    assert self._indent >= 0
229 7fcffe27 Michael Hanselmann
230 7fcffe27 Michael Hanselmann
    self._fh.write(self._indent * self.INDENT_STR)
231 7fcffe27 Michael Hanselmann
232 7fcffe27 Michael Hanselmann
    if args:
233 7fcffe27 Michael Hanselmann
      self._fh.write(txt % args)
234 7fcffe27 Michael Hanselmann
    else:
235 7fcffe27 Michael Hanselmann
      self._fh.write(txt)
236 7fcffe27 Michael Hanselmann
237 7fcffe27 Michael Hanselmann
    self._fh.write("\n")
238 7fcffe27 Michael Hanselmann
239 7fcffe27 Michael Hanselmann
240 7fcffe27 Michael Hanselmann
def GenerateSecret(numbytes=20):
241 7fcffe27 Michael Hanselmann
  """Generates a random secret.
242 7fcffe27 Michael Hanselmann

243 7fcffe27 Michael Hanselmann
  This will generate a pseudo-random secret returning an hex string
244 7fcffe27 Michael Hanselmann
  (so that it can be used where an ASCII string is needed).
245 7fcffe27 Michael Hanselmann

246 7fcffe27 Michael Hanselmann
  @param numbytes: the number of bytes which will be represented by the returned
247 7fcffe27 Michael Hanselmann
      string (defaulting to 20, the length of a SHA1 hash)
248 7fcffe27 Michael Hanselmann
  @rtype: str
249 7fcffe27 Michael Hanselmann
  @return: an hex representation of the pseudo-random sequence
250 7fcffe27 Michael Hanselmann

251 7fcffe27 Michael Hanselmann
  """
252 7fcffe27 Michael Hanselmann
  return os.urandom(numbytes).encode("hex")
253 7fcffe27 Michael Hanselmann
254 7fcffe27 Michael Hanselmann
255 7fcffe27 Michael Hanselmann
def NormalizeAndValidateMac(mac):
256 7fcffe27 Michael Hanselmann
  """Normalizes and check if a MAC address is valid.
257 7fcffe27 Michael Hanselmann

258 7fcffe27 Michael Hanselmann
  Checks whether the supplied MAC address is formally correct, only
259 7fcffe27 Michael Hanselmann
  accepts colon separated format. Normalize it to all lower.
260 7fcffe27 Michael Hanselmann

261 7fcffe27 Michael Hanselmann
  @type mac: str
262 7fcffe27 Michael Hanselmann
  @param mac: the MAC to be validated
263 7fcffe27 Michael Hanselmann
  @rtype: str
264 7fcffe27 Michael Hanselmann
  @return: returns the normalized and validated MAC.
265 7fcffe27 Michael Hanselmann

266 7fcffe27 Michael Hanselmann
  @raise errors.OpPrereqError: If the MAC isn't valid
267 7fcffe27 Michael Hanselmann

268 7fcffe27 Michael Hanselmann
  """
269 7fcffe27 Michael Hanselmann
  if not _MAC_CHECK_RE.match(mac):
270 7fcffe27 Michael Hanselmann
    raise errors.OpPrereqError("Invalid MAC address '%s'" % mac,
271 7fcffe27 Michael Hanselmann
                               errors.ECODE_INVAL)
272 7fcffe27 Michael Hanselmann
273 7fcffe27 Michael Hanselmann
  return mac.lower()
274 7fcffe27 Michael Hanselmann
275 7fcffe27 Michael Hanselmann
276 7fcffe27 Michael Hanselmann
def SafeEncode(text):
277 7fcffe27 Michael Hanselmann
  """Return a 'safe' version of a source string.
278 7fcffe27 Michael Hanselmann

279 7fcffe27 Michael Hanselmann
  This function mangles the input string and returns a version that
280 7fcffe27 Michael Hanselmann
  should be safe to display/encode as ASCII. To this end, we first
281 7fcffe27 Michael Hanselmann
  convert it to ASCII using the 'backslashreplace' encoding which
282 7fcffe27 Michael Hanselmann
  should get rid of any non-ASCII chars, and then we process it
283 7fcffe27 Michael Hanselmann
  through a loop copied from the string repr sources in the python; we
284 7fcffe27 Michael Hanselmann
  don't use string_escape anymore since that escape single quotes and
285 7fcffe27 Michael Hanselmann
  backslashes too, and that is too much; and that escaping is not
286 7fcffe27 Michael Hanselmann
  stable, i.e. string_escape(string_escape(x)) != string_escape(x).
287 7fcffe27 Michael Hanselmann

288 7fcffe27 Michael Hanselmann
  @type text: str or unicode
289 7fcffe27 Michael Hanselmann
  @param text: input data
290 7fcffe27 Michael Hanselmann
  @rtype: str
291 7fcffe27 Michael Hanselmann
  @return: a safe version of text
292 7fcffe27 Michael Hanselmann

293 7fcffe27 Michael Hanselmann
  """
294 7fcffe27 Michael Hanselmann
  if isinstance(text, unicode):
295 7fcffe27 Michael Hanselmann
    # only if unicode; if str already, we handle it below
296 7fcffe27 Michael Hanselmann
    text = text.encode('ascii', 'backslashreplace')
297 7fcffe27 Michael Hanselmann
  resu = ""
298 7fcffe27 Michael Hanselmann
  for char in text:
299 7fcffe27 Michael Hanselmann
    c = ord(char)
300 7fcffe27 Michael Hanselmann
    if char  == '\t':
301 7fcffe27 Michael Hanselmann
      resu += r'\t'
302 7fcffe27 Michael Hanselmann
    elif char == '\n':
303 7fcffe27 Michael Hanselmann
      resu += r'\n'
304 7fcffe27 Michael Hanselmann
    elif char == '\r':
305 7fcffe27 Michael Hanselmann
      resu += r'\'r'
306 7fcffe27 Michael Hanselmann
    elif c < 32 or c >= 127: # non-printable
307 7fcffe27 Michael Hanselmann
      resu += "\\x%02x" % (c & 0xff)
308 7fcffe27 Michael Hanselmann
    else:
309 7fcffe27 Michael Hanselmann
      resu += char
310 7fcffe27 Michael Hanselmann
  return resu
311 7fcffe27 Michael Hanselmann
312 7fcffe27 Michael Hanselmann
313 7fcffe27 Michael Hanselmann
def UnescapeAndSplit(text, sep=","):
314 7fcffe27 Michael Hanselmann
  """Split and unescape a string based on a given separator.
315 7fcffe27 Michael Hanselmann

316 7fcffe27 Michael Hanselmann
  This function splits a string based on a separator where the
317 7fcffe27 Michael Hanselmann
  separator itself can be escape in order to be an element of the
318 7fcffe27 Michael Hanselmann
  elements. The escaping rules are (assuming coma being the
319 7fcffe27 Michael Hanselmann
  separator):
320 7fcffe27 Michael Hanselmann
    - a plain , separates the elements
321 7fcffe27 Michael Hanselmann
    - a sequence \\\\, (double backslash plus comma) is handled as a
322 7fcffe27 Michael Hanselmann
      backslash plus a separator comma
323 7fcffe27 Michael Hanselmann
    - a sequence \, (backslash plus comma) is handled as a
324 7fcffe27 Michael Hanselmann
      non-separator comma
325 7fcffe27 Michael Hanselmann

326 7fcffe27 Michael Hanselmann
  @type text: string
327 7fcffe27 Michael Hanselmann
  @param text: the string to split
328 7fcffe27 Michael Hanselmann
  @type sep: string
329 7fcffe27 Michael Hanselmann
  @param text: the separator
330 7fcffe27 Michael Hanselmann
  @rtype: string
331 7fcffe27 Michael Hanselmann
  @return: a list of strings
332 7fcffe27 Michael Hanselmann

333 7fcffe27 Michael Hanselmann
  """
334 7fcffe27 Michael Hanselmann
  # we split the list by sep (with no escaping at this stage)
335 7fcffe27 Michael Hanselmann
  slist = text.split(sep)
336 7fcffe27 Michael Hanselmann
  # next, we revisit the elements and if any of them ended with an odd
337 7fcffe27 Michael Hanselmann
  # number of backslashes, then we join it with the next
338 7fcffe27 Michael Hanselmann
  rlist = []
339 7fcffe27 Michael Hanselmann
  while slist:
340 7fcffe27 Michael Hanselmann
    e1 = slist.pop(0)
341 7fcffe27 Michael Hanselmann
    if e1.endswith("\\"):
342 7fcffe27 Michael Hanselmann
      num_b = len(e1) - len(e1.rstrip("\\"))
343 7fcffe27 Michael Hanselmann
      if num_b % 2 == 1:
344 7fcffe27 Michael Hanselmann
        e2 = slist.pop(0)
345 7fcffe27 Michael Hanselmann
        # here the backslashes remain (all), and will be reduced in
346 7fcffe27 Michael Hanselmann
        # the next step
347 7fcffe27 Michael Hanselmann
        rlist.append(e1 + sep + e2)
348 7fcffe27 Michael Hanselmann
        continue
349 7fcffe27 Michael Hanselmann
    rlist.append(e1)
350 7fcffe27 Michael Hanselmann
  # finally, replace backslash-something with something
351 7fcffe27 Michael Hanselmann
  rlist = [re.sub(r"\\(.)", r"\1", v) for v in rlist]
352 7fcffe27 Michael Hanselmann
  return rlist
353 7fcffe27 Michael Hanselmann
354 7fcffe27 Michael Hanselmann
355 7fcffe27 Michael Hanselmann
def CommaJoin(names):
356 7fcffe27 Michael Hanselmann
  """Nicely join a set of identifiers.
357 7fcffe27 Michael Hanselmann

358 7fcffe27 Michael Hanselmann
  @param names: set, list or tuple
359 7fcffe27 Michael Hanselmann
  @return: a string with the formatted results
360 7fcffe27 Michael Hanselmann

361 7fcffe27 Michael Hanselmann
  """
362 7fcffe27 Michael Hanselmann
  return ", ".join([str(val) for val in names])
363 7fcffe27 Michael Hanselmann
364 7fcffe27 Michael Hanselmann
365 7fcffe27 Michael Hanselmann
def FormatTime(val):
366 7fcffe27 Michael Hanselmann
  """Formats a time value.
367 7fcffe27 Michael Hanselmann

368 7fcffe27 Michael Hanselmann
  @type val: float or None
369 7fcffe27 Michael Hanselmann
  @param val: Timestamp as returned by time.time() (seconds since Epoch,
370 7fcffe27 Michael Hanselmann
    1970-01-01 00:00:00 UTC)
371 7fcffe27 Michael Hanselmann
  @return: a string value or N/A if we don't have a valid timestamp
372 7fcffe27 Michael Hanselmann

373 7fcffe27 Michael Hanselmann
  """
374 7fcffe27 Michael Hanselmann
  if val is None or not isinstance(val, (int, float)):
375 7fcffe27 Michael Hanselmann
    return "N/A"
376 7fcffe27 Michael Hanselmann
  # these two codes works on Linux, but they are not guaranteed on all
377 7fcffe27 Michael Hanselmann
  # platforms
378 7fcffe27 Michael Hanselmann
  return time.strftime("%F %T", time.localtime(val))
379 7fcffe27 Michael Hanselmann
380 7fcffe27 Michael Hanselmann
381 7fcffe27 Michael Hanselmann
def FormatSeconds(secs):
382 7fcffe27 Michael Hanselmann
  """Formats seconds for easier reading.
383 7fcffe27 Michael Hanselmann

384 7fcffe27 Michael Hanselmann
  @type secs: number
385 7fcffe27 Michael Hanselmann
  @param secs: Number of seconds
386 7fcffe27 Michael Hanselmann
  @rtype: string
387 7fcffe27 Michael Hanselmann
  @return: Formatted seconds (e.g. "2d 9h 19m 49s")
388 7fcffe27 Michael Hanselmann

389 7fcffe27 Michael Hanselmann
  """
390 7fcffe27 Michael Hanselmann
  parts = []
391 7fcffe27 Michael Hanselmann
392 7fcffe27 Michael Hanselmann
  secs = round(secs, 0)
393 7fcffe27 Michael Hanselmann
394 7fcffe27 Michael Hanselmann
  if secs > 0:
395 7fcffe27 Michael Hanselmann
    # Negative values would be a bit tricky
396 7fcffe27 Michael Hanselmann
    for unit, one in [("d", 24 * 60 * 60), ("h", 60 * 60), ("m", 60)]:
397 7fcffe27 Michael Hanselmann
      (complete, secs) = divmod(secs, one)
398 7fcffe27 Michael Hanselmann
      if complete or parts:
399 7fcffe27 Michael Hanselmann
        parts.append("%d%s" % (complete, unit))
400 7fcffe27 Michael Hanselmann
401 7fcffe27 Michael Hanselmann
  parts.append("%ds" % secs)
402 7fcffe27 Michael Hanselmann
403 7fcffe27 Michael Hanselmann
  return " ".join(parts)
404 7fcffe27 Michael Hanselmann
405 7fcffe27 Michael Hanselmann
406 7fcffe27 Michael Hanselmann
class LineSplitter:
407 7fcffe27 Michael Hanselmann
  """Splits data chunks into lines separated by newline.
408 7fcffe27 Michael Hanselmann

409 7fcffe27 Michael Hanselmann
  Instances provide a file-like interface.
410 7fcffe27 Michael Hanselmann

411 7fcffe27 Michael Hanselmann
  """
412 7fcffe27 Michael Hanselmann
  def __init__(self, line_fn, *args):
413 7fcffe27 Michael Hanselmann
    """Initializes this class.
414 7fcffe27 Michael Hanselmann

415 7fcffe27 Michael Hanselmann
    @type line_fn: callable
416 7fcffe27 Michael Hanselmann
    @param line_fn: Function called for each line, first parameter is line
417 7fcffe27 Michael Hanselmann
    @param args: Extra arguments for L{line_fn}
418 7fcffe27 Michael Hanselmann

419 7fcffe27 Michael Hanselmann
    """
420 7fcffe27 Michael Hanselmann
    assert callable(line_fn)
421 7fcffe27 Michael Hanselmann
422 7fcffe27 Michael Hanselmann
    if args:
423 7fcffe27 Michael Hanselmann
      # Python 2.4 doesn't have functools.partial yet
424 7fcffe27 Michael Hanselmann
      self._line_fn = \
425 7fcffe27 Michael Hanselmann
        lambda line: line_fn(line, *args) # pylint: disable-msg=W0142
426 7fcffe27 Michael Hanselmann
    else:
427 7fcffe27 Michael Hanselmann
      self._line_fn = line_fn
428 7fcffe27 Michael Hanselmann
429 7fcffe27 Michael Hanselmann
    self._lines = collections.deque()
430 7fcffe27 Michael Hanselmann
    self._buffer = ""
431 7fcffe27 Michael Hanselmann
432 7fcffe27 Michael Hanselmann
  def write(self, data):
433 7fcffe27 Michael Hanselmann
    parts = (self._buffer + data).split("\n")
434 7fcffe27 Michael Hanselmann
    self._buffer = parts.pop()
435 7fcffe27 Michael Hanselmann
    self._lines.extend(parts)
436 7fcffe27 Michael Hanselmann
437 7fcffe27 Michael Hanselmann
  def flush(self):
438 7fcffe27 Michael Hanselmann
    while self._lines:
439 7fcffe27 Michael Hanselmann
      self._line_fn(self._lines.popleft().rstrip("\r\n"))
440 7fcffe27 Michael Hanselmann
441 7fcffe27 Michael Hanselmann
  def close(self):
442 7fcffe27 Michael Hanselmann
    self.flush()
443 7fcffe27 Michael Hanselmann
    if self._buffer:
444 7fcffe27 Michael Hanselmann
      self._line_fn(self._buffer)