1
2
3
4 """
5 This file is part of the web2py Web Framework
6 Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
7 License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
8 """
9
10 import storage
11 import os
12 import re
13 import tarfile
14 import glob
15 from http import HTTP
16 from gzip import open as gzopen
17 from settings import global_settings
18
19
20 __all__ = [
21 'up',
22 'abspath',
23 'mktree',
24 'listdir',
25 'recursive_unlink',
26 'cleanpath',
27 'tar',
28 'untar',
29 'tar_compiled',
30 'get_session',
31 'check_credentials',
32 'w2p_pack',
33 'w2p_unpack',
34 'w2p_pack_plugin',
35 'w2p_unpack_plugin',
36 'fix_newlines',
37 ]
38
39
41 "convert relative path to absolute path based (by default) on applications_parent"
42 path = os.path.join(*relpath)
43 gluon = base.get('gluon', False)
44 if os.path.isabs(path):
45 return path
46 if gluon:
47 return os.path.join(global_settings.gluon_parent, path)
48 return os.path.join(global_settings.applications_parent, path)
49
50
52 head,tail =os.path.split(path)
53 if head:
54 if tail: mktree(head)
55 if not os.path.exists(head):
56 os.mkdir(head)
57
58 -def listdir(
59 path,
60 expression='^.+$',
61 drop=True,
62 add_dirs=False,
63 sort=True,
64 ):
65 """
66 like os.listdir() but you can specify a regex pattern to filter files.
67 if add_dirs is True, the returned items will have the full path.
68 """
69 if path[-1:] != '/':
70 path = path + '/'
71 if drop:
72 n = len(path)
73 else:
74 n = 0
75 regex = re.compile(expression)
76 items = []
77 for (root, dirs, files) in os.walk(path, topdown=True):
78 for dir in dirs[:]:
79 if dir.startswith('.'):
80 dirs.remove(dir)
81 if add_dirs:
82 items.append(root[n:])
83 for file in sorted(files):
84 if regex.match(file) and not file.startswith('.'):
85 items.append(os.path.join(root, file)[n:])
86 if sort:
87 return sorted(items)
88 else:
89 return items
90
91
93 if os.path.isdir(f):
94 for s in os.listdir(f):
95 recursive_unlink(os.path.join(f,s))
96 os.rmdir(f)
97 elif os.path.isfile(f):
98 os.unlink(f)
99
100
102 """
103 turns any expression/path into a valid filename. replaces / with _ and
104 removes special characters.
105 """
106
107 items = path.split('.')
108 if len(items) > 1:
109 path = re.sub('[^\w\.]+', '_', '_'.join(items[:-1]) + '.'
110 + ''.join(items[-1:]))
111 else:
112 path = re.sub('[^\w\.]+', '_', ''.join(items[-1:]))
113 return path
114
115
117 if not hasattr(tarfile.TarFile, 'extractall'):
118 from tarfile import ExtractError
119
120 class TarFile(tarfile.TarFile):
121
122 def extractall(self, path='.', members=None):
123 """Extract all members from the archive to the current working
124 directory and set owner, modification time and permissions on
125 directories afterwards. `path' specifies a different directory
126 to extract to. `members' is optional and must be a subset of the
127 list returned by getmembers().
128 """
129
130 directories = []
131 if members is None:
132 members = self
133 for tarinfo in members:
134 if tarinfo.isdir():
135
136
137
138
139 try:
140 os.makedirs(os.path.join(path,
141 tarinfo.name), 0777)
142 except EnvironmentError:
143 pass
144 directories.append(tarinfo)
145 else:
146 self.extract(tarinfo, path)
147
148
149
150 directories.sort(lambda a, b: cmp(a.name, b.name))
151 directories.reverse()
152
153
154
155 for tarinfo in directories:
156 path = os.path.join(path, tarinfo.name)
157 try:
158 self.chown(tarinfo, path)
159 self.utime(tarinfo, path)
160 self.chmod(tarinfo, path)
161 except ExtractError, e:
162 if self.errorlevel > 1:
163 raise
164 else:
165 self._dbg(1, 'tarfile: %s' % e)
166
167
168 _cls = TarFile
169 else:
170 _cls = tarfile.TarFile
171
172 tar = _cls(filename, 'r')
173 ret = tar.extractall(path, members)
174 tar.close()
175 return ret
176
177 -def tar(file, dir, expression='^.+$'):
178 """
179 tars dir into file, only tars file that match expression
180 """
181
182 tar = tarfile.TarFile(file, 'w')
183 for file in listdir(dir, expression, add_dirs=True):
184 tar.add(os.path.join(dir, file), file, False)
185 tar.close()
186
188 """
189 untar file into dir
190 """
191
192 _extractall(file, dir)
193
194
195 -def w2p_pack(filename, path, compiled=False):
196 filename = abspath(filename)
197 path = abspath(path)
198 tarname = filename + '.tar'
199 if compiled:
200 tar_compiled(tarname, path, '^[\w\.\-]+$')
201 else:
202 tar(tarname, path, '^[\w\.\-]+$')
203 w2pfp = gzopen(filename, 'wb')
204 tarfp = open(tarname, 'rb')
205 w2pfp.write(tarfp.read())
206 w2pfp.close()
207 tarfp.close()
208 os.unlink(tarname)
209
211 filename = abspath(filename)
212 path = abspath(path)
213 if filename[-4:] == '.w2p' or filename[-3:] == '.gz':
214 if filename[-4:] == '.w2p':
215 tarname = filename[:-4] + '.tar'
216 else:
217 tarname = filename[:-3] + '.tar'
218 fgzipped = gzopen(filename, 'rb')
219 tarfile = open(tarname, 'wb')
220 tarfile.write(fgzipped.read())
221 tarfile.close()
222 fgzipped.close()
223 else:
224 tarname = filename
225 untar(tarname, path)
226 if delete_tar:
227 os.unlink(tarname)
228
229
231 """Pack the given plugin into a w2p file.
232 Will match files at:
233 <path>/*/plugin_[name].*
234 <path>/*/plugin_[name]/*
235 """
236 filename = abspath(filename)
237 path = abspath(path)
238 if not filename.endswith('web2py.plugin.%s.w2p' % plugin_name):
239 raise Exception, "Not a web2py plugin name"
240 plugin_tarball = tarfile.open(filename, 'w:gz')
241 app_dir = path
242 while app_dir[-1]=='/':
243 app_dir = app_dir[:-1]
244 files1=glob.glob(os.path.join(app_dir,'*/plugin_%s.*' % plugin_name))
245 files2=glob.glob(os.path.join(app_dir,'*/plugin_%s/*' % plugin_name))
246 for file in files1+files2:
247 plugin_tarball.add(file, arcname=file[len(app_dir)+1:])
248 plugin_tarball.close()
249
250
257
258
260 """
261 used to tar a compiled application.
262 the content of models, views, controllers is not stored in the tar file.
263 """
264
265 tar = tarfile.TarFile(file, 'w')
266 for file in listdir(dir, expression, add_dirs=True):
267 filename = os.path.join(dir, file)
268 if os.path.islink(filename):
269 continue
270 if os.path.isfile(filename) and file[-4:] != '.pyc':
271 if file[:6] == 'models':
272 continue
273 if file[:5] == 'views':
274 continue
275 if file[:11] == 'controllers':
276 continue
277 if file[:7] == 'modules':
278 continue
279 tar.add(filename, file, False)
280 tar.close()
281
283 return os.path.dirname(os.path.normpath(path))
284
285
287 """ checks that user is authorized to access other_application"""
288
289 if request.application == other_application:
290 raise KeyError
291 try:
292 session_id = request.cookies['session_id_' + other_application].value
293 osession = storage.load_storage(os.path.join(
294 up(request.folder), other_application, 'sessions', session_id))
295 except:
296 osession = storage.Storage()
297 return osession
298
299
301 """ checks that user is authorized to access other_application"""
302
303 if request.env.web2py_runtime_gae:
304 from google.appengine.api import users
305 if users.is_current_user_admin():
306 return True
307 else:
308 login_html = '<a href="%s">Sign in with your google account</a>.' \
309 % users.create_login_url(request.env.path_info)
310 raise HTTP(200, '<html><body>%s</body></html>' % login_html)
311 else:
312 return get_session(request, other_application).authorized
313
314
316 regex = re.compile(r'''(\r
317 |\r|
318 )''')
319 for filename in listdir(path, '.*\.(py|html)$', drop=False):
320 fp = open(filename, 'rb')
321 rdata = fp.read()
322 fp.close()
323 wdata = regex.sub('\n', rdata)
324 if wdata != rdata:
325 fp = open(filename, 'wb')
326 fp.write(wdata)
327 fp.close()
328
329
330 -def copystream(
331 src,
332 dest,
333 size,
334 chunk_size=10 ** 5,
335 ):
336 """
337 this is here because I think there is a bug in shutil.copyfileobj
338 """
339 while size > 0:
340 if size < chunk_size:
341 data = src.read(size)
342 else:
343 data = src.read(chunk_size)
344 length = len(data)
345 if length > size:
346 (data, length) = (data[:size], size)
347 size -= length
348 if length == 0:
349 break
350 dest.write(data)
351 if length < chunk_size:
352 break
353 dest.seek(0)
354 return
355