Updated exception handling to Python 2.6 syntax
[zeroinstall.git] / zeroinstall / support / __init__.py
blobe4f44f6ed31761737ee7d85f26146807189e5d37
1 """
2 Useful support routines (for internal use).
4 These functions aren't really Zero Install specific; they're things we might
5 wish were in the standard library.
7 @since: 0.27
8 """
10 # Copyright (C) 2009, Thomas Leonard
11 # See the README file for details, or visit http://0install.net.
13 from zeroinstall import _
14 import os, logging
16 def find_in_path(prog):
17 """Search $PATH for prog.
18 If prog is an absolute path, return it unmodified.
19 @param prog: name of executable to find
20 @return: the full path of prog, or None if not found
21 @since: 0.27
22 """
23 if os.path.isabs(prog): return prog
24 if os.name == "nt":
25 prog += '.exe'
26 for d in os.environ.get('PATH', '/bin:/usr/bin').split(os.pathsep):
27 path = os.path.join(d, prog)
28 if os.path.isfile(path):
29 return path
30 return None
32 def read_bytes(fd, nbytes, null_ok = False):
33 """Read exactly nbytes from fd.
34 @param fd: file descriptor to read from
35 @param nbytes: number of bytes to read
36 @param null_ok: if True, it's OK to receive EOF immediately (we then return None)
37 @return: the bytes read
38 @raise Exception: if we received less than nbytes of data
39 """
40 data = ''
41 while nbytes:
42 got = os.read(fd, nbytes)
43 if not got:
44 if null_ok and not data:
45 return None
46 raise Exception(_("Unexpected end-of-stream. Data so far %(data)s; expecting %(bytes)d bytes more.")
47 % {'data': repr(data), 'bytes': nbytes})
48 data += got
49 nbytes -= len(got)
50 logging.debug(_("Message received: %s") % repr(data))
51 return data
53 def pretty_size(size):
54 """Format a size for printing.
55 @param size: the size in bytes
56 @type size: int (or None)
57 @return: the formatted size
58 @rtype: str
59 @since: 0.27"""
60 if size is None:
61 return '?'
62 if size < 2048:
63 return _('%d bytes') % size
64 size = float(size)
65 for unit in (_('KB'), _('MB'), _('GB'), _('TB')):
66 size /= 1024
67 if size < 2048:
68 break
69 return _('%(size).1f %(unit)s') % {'size': size, 'unit': unit}
71 def ro_rmtree(root):
72 """Like shutil.rmtree, except that we also delete read-only items.
73 @param root: the root of the subtree to remove
74 @type root: str
75 @since: 0.28"""
76 import shutil
77 import platform
78 if platform.system() == 'Windows':
79 for main, dirs, files in os.walk(root):
80 for i in files + dirs:
81 os.chmod(os.path.join(main, i), 0o700)
82 os.chmod(root, 0o700)
83 else:
84 for main, dirs, files in os.walk(root):
85 os.chmod(main, 0o700)
86 shutil.rmtree(root)