1 """Utility functions for Cheesecake project.
2 """
3
4 import os
5 import shutil
6 import sys
7 import tarfile
8 import time
9 import zipfile
10
11 from subprocess import call, ProcessError, Popen, PIPE, STDOUT
12
13 PAD_TEXT = 40
14 PAD_VALUE = 4
15
17 """Run command and return its return code and its output.
18
19 >>> run_cmd('/bin/true')
20 (0, '')
21 """
22 arglist = cmd.split()
23 try:
24 p = Popen(arglist, stdout=PIPE, stderr=STDOUT, env=env)
25 except ProcessError, e:
26 return 1, e
27 output = p.communicate()[0]
28 return p.returncode, output
29
31 """Returns True if command exited normally, False otherwise.
32
33 >>> command_successful('/bin/true')
34 True
35 >>> command_successful('this-command-doesnt-exist')
36 False
37 """
38 rc, output = run_cmd(cmd)
39 if rc:
40 return False
41 return True
42
44 """Redirect stdout to a temporary file.
45 """
47 if filename:
48 self.fh = open(filename, 'w')
49 else:
50 self.fh = os.tmpfile()
51
54
57
59 """Return contents of the temporary file.
60 """
61 self.fh.seek(0)
62 return self.fh.read()
63
65 """Pad text with dots up to given length.
66
67 >>> pad_with_dots("Hello world", 20)
68 'Hello world ........'
69 >>> pad_with_dots("Exceeding length", 10)
70 'Exceeding length'
71 """
72 msg_length = len(msg)
73
74 if msg_length >= length:
75 return msg
76
77 msg = msg + " "
78 for i in range(msg_length+1, length):
79 msg += "."
80 return msg
81
83 """Pad value with spaces at left up to given length.
84
85 >>> pad_left_spaces(15, 4)
86 ' 15'
87 >>> pad_left_spaces(123456, 2)
88 '123456'
89 >>> len(pad_left_spaces("")) == PAD_VALUE
90 True
91 """
92 if not isinstance(value, basestring):
93 value = str(value)
94 diff = length - len(value)
95 return " " * diff + value
96
98 """Pad value with spaces at left up to given length.
99
100 >>> pad_right_spaces(123, 5)
101 '123 '
102 >>> pad_right_spaces(12.1, 5)
103 '12.1 '
104 """
105 if not isinstance(value, basestring):
106 value = str(value)
107 diff = length - len(value)
108 return value + " " * diff
109
111 """Pad message with dots and pad value with spaces.
112
113 >>> pad_msg("123456", 77, msg_length=10, value_length=4)
114 '123456 ... 77'
115 >>> pad_msg("123", u"45", msg_length=5, value_length=3)
116 u'123 . 45'
117 """
118 return msg + " " +"." * (msg_length-len(msg)-1) + pad_left_spaces(value, value_length)
119
121 """Return line consisting of 'char' characters.
122
123 >>> pad_line('*', 3)
124 '***'
125 >>> pad_line(length=10)
126 '=========='
127 """
128 return char * length
129
131 """Unzip given `package` to the `destination` directory.
132
133 Return name of unpacked directory or None on error.
134 """
135 try:
136 z = zipfile.ZipFile(package)
137 except zipfile.error:
138 return None
139
140
141 for name in z.namelist():
142 (dir, file) = os.path.split(name)
143 unpack_dir = dir
144 target_dir = os.path.join(destination, dir)
145 if not os.path.exists(target_dir):
146 os.makedirs(target_dir)
147
148
149 for i, name in enumerate(z.namelist()):
150 if not name.endswith('/'):
151 outfile = open(os.path.join(destination, name), 'wb')
152 outfile.write(z.read(name))
153 outfile.flush()
154 outfile.close()
155
156 return unpack_dir.split(os.sep)[0]
157
159 """Untar given `package` to the `destination` directory.
160
161 Return name of unpacked directory or None on error.
162 """
163 try:
164 t = tarfile.open(package)
165 except tarfile.ReadError, e:
166 return None
167
168 for member in t.getmembers():
169 t.extract(member, destination)
170
171 tarinfo = t.members[0]
172 return tarinfo.name.split(os.sep)[0]
173
175 """Unpack given egg to the `destination` directory.
176
177 Return name of unpacked directory or None on error.
178 """
179 if os.path.isdir(package):
180 package_name = os.path.basename(package)
181 destination = os.path.join(destination, package_name)
182 shutil.copytree(package, destination, symlinks=True)
183 return package_name
184 else:
185 return unzip_package(package, destination)
186
188 """Make directory with parent directories as needed.
189
190 Don't throw an exception if directory exists.
191 """
192 parts = dir.split(os.path.sep)
193 for length in xrange(1, len(parts)+1):
194 path = os.path.sep.join([''] + parts[:length])
195 if not os.path.exists(path):
196 os.mkdir(path)
197
199 """Measure function execution time.
200
201 Return (return value, time taken) tuple.
202
203 >>> def fun(x):
204 ... return x*2
205 >>> ret, time_taken = time_function(lambda: fun(5))
206 >>> ret
207 10
208 """
209 start = time.time()
210 ret = function()
211 end = time.time()
212 return ret, end-start
213