Package zeroinstall :: Package support
[frames] | no frames]

Source Code for Package zeroinstall.support

  1  """ 
  2  Useful support routines (for internal use). 
  3   
  4  These functions aren't really Zero Install specific; they're things we might 
  5  wish were in the standard library. 
  6   
  7  @since: 0.27 
  8  """ 
  9   
 10  # Copyright (C) 2009, Thomas Leonard 
 11  # See the README file for details, or visit http://0install.net. 
 12   
 13  from zeroinstall import _, logger 
 14  import sys, os 
 15   
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 @type prog: str 21 @return: the full path of prog, or None if not found 22 @rtype: str 23 @since: 0.27""" 24 if os.path.isabs(prog): return prog 25 if os.name == "nt": 26 prog += '.exe' 27 for d in os.environ.get('PATH', '/bin:/usr/bin').split(os.pathsep): 28 path = os.path.join(d, prog) 29 if os.path.isfile(path): 30 return path 31 return None
32
33 -def read_bytes(fd, nbytes, null_ok = False):
34 """Read exactly nbytes from fd. 35 @param fd: file descriptor to read from 36 @type fd: int 37 @param nbytes: number of bytes to read 38 @type nbytes: int 39 @param null_ok: if True, it's OK to receive EOF immediately (we then return None) 40 @type null_ok: bool 41 @return: the bytes read 42 @rtype: bytes 43 @raise Exception: if we received less than nbytes of data""" 44 data = b'' 45 while nbytes: 46 got = os.read(fd, nbytes) 47 if not got: 48 if null_ok and not data: 49 return None 50 raise Exception(_("Unexpected end-of-stream. Data so far %(data)s; expecting %(bytes)d bytes more.") 51 % {'data': repr(data), 'bytes': nbytes}) 52 data += got 53 nbytes -= len(got) 54 logger.debug(_("Message received: %r"), data) 55 return data
56
57 -def pretty_size(size):
58 """Format a size for printing. 59 @param size: the size in bytes 60 @type size: int (or None) 61 @return: the formatted size 62 @rtype: str 63 @since: 0.27""" 64 if size is None: 65 return '?' 66 if size < 2048: 67 return _('%d bytes') % size 68 size = float(size) 69 for unit in (_('KB'), _('MB'), _('GB'), _('TB')): 70 size /= 1024 71 if size < 2048: 72 break 73 return _('%(size).1f %(unit)s') % {'size': size, 'unit': unit}
74
75 -def ro_rmtree(root):
76 """Like shutil.rmtree, except that we also delete read-only items. 77 @param root: the root of the subtree to remove 78 @type root: str 79 @since: 0.28""" 80 import shutil 81 import platform 82 if (os.getcwd() + os.path.sep).startswith(root + os.path.sep): 83 import warnings 84 warnings.warn("Removing tree ({tree}) containing the current directory ({cwd}) - this will not work on Windows".format(cwd = os.getcwd(), tree = root), stacklevel = 2) 85 86 if os.path.isfile(root): 87 os.chmod(root, 0o700) 88 os.remove(root) 89 else: 90 if platform.system() == 'Windows': 91 for main, dirs, files in os.walk(root): 92 for i in files + dirs: 93 os.chmod(os.path.join(main, i), 0o700) 94 os.chmod(root, 0o700) 95 else: 96 for main, dirs, files in os.walk(root): 97 os.chmod(main, 0o700) 98 shutil.rmtree(root)
99
100 -def raise_with_traceback(ex, tb):
101 """Raise an exception in a way that works on Python 2 and Python 3 102 @type ex: BaseException""" 103 if hasattr(ex, 'with_traceback'): 104 raise ex # Python 3 105 exec("raise ex, None, tb", {'ex': ex, 'tb': tb}) # Python 2 106 assert 0
107
108 -def portable_rename(src, dst):
109 """Rename 'src' to 'dst', which must be on the same filesystem. 110 On POSIX systems, this operation is atomic. 111 On Windows, do the best we can by deleting dst and then renaming. 112 @type src: str 113 @type dst: str 114 @since: 1.9""" 115 if os.name == "nt" and os.path.exists(dst): 116 os.unlink(dst) 117 os.rename(src, dst)
118
119 -def windows_args_escape(args):
120 """Combines multiple strings into one for use as a Windows command-line argument. 121 This coressponds to Windows' handling of command-line arguments as specified in: http://msdn.microsoft.com/library/17w5ykft. 122 @type args: [str] 123 @rtype: str 124 @since: 1.11""" 125 def _escape(arg): 126 # Add leading quotation mark if there are whitespaces 127 import string 128 contains_whitespace = any(whitespace in arg for whitespace in string.whitespace) 129 result = '"' if contains_whitespace else '' 130 131 # Split by quotation marks 132 parts = arg.split('"') 133 for i, part in enumerate(parts): 134 # Count slashes preceeding the quotation mark 135 slashes_count = len(part) - len(part.rstrip('\\')) 136 137 result = result + part 138 if i < len(parts) - 1: 139 # Not last part 140 result = result + ("\\" * slashes_count) # Double number of slashes 141 result = result + "\\" + '"' # Escaped quotation mark 142 elif contains_whitespace: 143 # Last part if there are whitespaces 144 result = result + ("\\" * slashes_count) # Double number of slashes 145 result = result + '"' # Non-escaped quotation mark 146 147 return result
148 149 return ' '.join(map(_escape, args)) 150 151 if sys.version_info[0] > 2: 152 # Python 3 153 unicode = str 154 basestring = str 155 intern = sys.intern 156 raw_input = input 157
158 - def urlparse(url):
159 """@type url: str 160 @rtype: ParseResult""" 161 from urllib import parse 162 return parse.urlparse(url)
163 else: 164 # Python 2 165 unicode = unicode # (otherwise it can't be imported) 166 basestring = basestring 167 intern = intern 168 raw_input = raw_input 169
170 - def urlparse(url):
171 """@type url: str 172 @rtype: ParseResult""" 173 import urlparse 174 return urlparse.urlparse(url)
175