Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] portage r15480 - in main/branches/prefix/pym/portage: . dbapi package/ebuild util
Date: Sat, 27 Feb 2010 19:01:32
Message-Id: E1NlRup-0008Hz-AY@stork.gentoo.org
1 Author: grobian
2 Date: 2010-02-27 19:01:26 +0000 (Sat, 27 Feb 2010)
3 New Revision: 15480
4
5 Added:
6 main/branches/prefix/pym/portage/util/listdir.py
7 Modified:
8 main/branches/prefix/pym/portage/__init__.py
9 main/branches/prefix/pym/portage/dbapi/bintree.py
10 main/branches/prefix/pym/portage/dbapi/porttree.py
11 main/branches/prefix/pym/portage/dbapi/vartree.py
12 main/branches/prefix/pym/portage/package/ebuild/doebuild.py
13 main/branches/prefix/pym/portage/util/digraph.py
14 Log:
15 Merged from trunk -r15449:15451
16
17 | 15450 | Move cacheddir and listdir to portage.util.listdir. |
18 | zmedico | |
19
20 | 15451 | Fix broken references to |
21 | zmedico | portage._doebuild_manifest_exempt_depend. |
22
23
24 Modified: main/branches/prefix/pym/portage/__init__.py
25 ===================================================================
26 --- main/branches/prefix/pym/portage/__init__.py 2010-02-27 18:53:28 UTC (rev 15479)
27 +++ main/branches/prefix/pym/portage/__init__.py 2010-02-27 19:01:26 UTC (rev 15480)
28 @@ -122,6 +122,7 @@
29 'stack_lists,unique_array,varexpand,writedict,writemsg,' + \
30 'writemsg_stdout,write_atomic',
31 'portage.util.digraph:digraph',
32 + 'portage.util.listdir:cacheddir,listdir',
33 'portage.versions',
34 'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,' + \
35 'cpv_getkey@getCPFromCPV,endversion_keys,' + \
36 @@ -534,145 +535,6 @@
37 mylink=mydir+"/"+mylink
38 return os.path.normpath(mylink)
39
40 -dircache = {}
41 -cacheHit=0
42 -cacheMiss=0
43 -cacheStale=0
44 -def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True):
45 - global cacheHit,cacheMiss,cacheStale
46 - mypath = normalize_path(my_original_path)
47 - if mypath in dircache:
48 - cacheHit += 1
49 - cached_mtime, list, ftype = dircache[mypath]
50 - else:
51 - cacheMiss += 1
52 - cached_mtime, list, ftype = -1, [], []
53 - try:
54 - pathstat = os.stat(mypath)
55 - if stat.S_ISDIR(pathstat[stat.ST_MODE]):
56 - mtime = pathstat.st_mtime
57 - else:
58 - raise portage.exception.DirectoryNotFound(mypath)
59 - except EnvironmentError as e:
60 - if e.errno == portage.exception.PermissionDenied.errno:
61 - raise portage.exception.PermissionDenied(mypath)
62 - del e
63 - return [], []
64 - except portage.exception.PortageException:
65 - return [], []
66 - # Python retuns mtime in seconds, so if it was changed in the last few seconds, it could be invalid
67 - if mtime != cached_mtime or time.time() - mtime < 4:
68 - if mypath in dircache:
69 - cacheStale += 1
70 - try:
71 - list = os.listdir(mypath)
72 - except EnvironmentError as e:
73 - if e.errno != errno.EACCES:
74 - raise
75 - del e
76 - raise portage.exception.PermissionDenied(mypath)
77 - ftype = []
78 - for x in list:
79 - try:
80 - if followSymlinks:
81 - pathstat = os.stat(mypath+"/"+x)
82 - else:
83 - pathstat = os.lstat(mypath+"/"+x)
84 -
85 - if stat.S_ISREG(pathstat[stat.ST_MODE]):
86 - ftype.append(0)
87 - elif stat.S_ISDIR(pathstat[stat.ST_MODE]):
88 - ftype.append(1)
89 - elif stat.S_ISLNK(pathstat[stat.ST_MODE]):
90 - ftype.append(2)
91 - else:
92 - ftype.append(3)
93 - except (IOError, OSError):
94 - ftype.append(3)
95 - dircache[mypath] = mtime, list, ftype
96 -
97 - ret_list = []
98 - ret_ftype = []
99 - for x in range(0, len(list)):
100 - if list[x] in ignorelist:
101 - pass
102 - elif ignorecvs:
103 - if list[x][:2] != ".#":
104 - ret_list.append(list[x])
105 - ret_ftype.append(ftype[x])
106 - else:
107 - ret_list.append(list[x])
108 - ret_ftype.append(ftype[x])
109 -
110 - writemsg("cacheddirStats: H:%d/M:%d/S:%d\n" % (cacheHit, cacheMiss, cacheStale),10)
111 - return ret_list, ret_ftype
112 -
113 -_ignorecvs_dirs = ('CVS', 'SCCS', '.svn', '.git')
114 -
115 -def listdir(mypath, recursive=False, filesonly=False, ignorecvs=False, ignorelist=[], followSymlinks=True,
116 - EmptyOnError=False, dirsonly=False):
117 - """
118 - Portage-specific implementation of os.listdir
119 -
120 - @param mypath: Path whose contents you wish to list
121 - @type mypath: String
122 - @param recursive: Recursively scan directories contained within mypath
123 - @type recursive: Boolean
124 - @param filesonly; Only return files, not more directories
125 - @type filesonly: Boolean
126 - @param ignorecvs: Ignore CVS directories ('CVS','SCCS','.svn','.git')
127 - @type ignorecvs: Boolean
128 - @param ignorelist: List of filenames/directories to exclude
129 - @type ignorelist: List
130 - @param followSymlinks: Follow Symlink'd files and directories
131 - @type followSymlinks: Boolean
132 - @param EmptyOnError: Return [] if an error occurs (deprecated, always True)
133 - @type EmptyOnError: Boolean
134 - @param dirsonly: Only return directories.
135 - @type dirsonly: Boolean
136 - @rtype: List
137 - @returns: A list of files and directories (or just files or just directories) or an empty list.
138 - """
139 -
140 - list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks)
141 -
142 - if list is None:
143 - list=[]
144 - if ftype is None:
145 - ftype=[]
146 -
147 - if not (filesonly or dirsonly or recursive):
148 - return list
149 -
150 - if recursive:
151 - x=0
152 - while x<len(ftype):
153 - if ftype[x] == 1 and not \
154 - (ignorecvs and os.path.basename(list[x]) in _ignorecvs_dirs):
155 - l,f = cacheddir(mypath+"/"+list[x], ignorecvs, ignorelist, EmptyOnError,
156 - followSymlinks)
157 -
158 - l=l[:]
159 - for y in range(0,len(l)):
160 - l[y]=list[x]+"/"+l[y]
161 - list=list+l
162 - ftype=ftype+f
163 - x+=1
164 - if filesonly:
165 - rlist=[]
166 - for x in range(0,len(ftype)):
167 - if ftype[x]==0:
168 - rlist=rlist+[list[x]]
169 - elif dirsonly:
170 - rlist = []
171 - for x in range(0, len(ftype)):
172 - if ftype[x] == 1:
173 - rlist = rlist + [list[x]]
174 - else:
175 - rlist=list
176 -
177 - return rlist
178 -
179 #parse /etc/env.d and generate /etc/profile.env
180
181 def env_update(makelinks=1, target_root=None, prev_mtimes=None, contents=None,
182 @@ -1017,209 +879,6 @@
183
184 return (version,None)
185
186 -# XXX This would be to replace getstatusoutput completely.
187 -# XXX Issue: cannot block execution. Deadlock condition.
188 -def spawn(mystring, mysettings, debug=0, free=0, droppriv=0, sesandbox=0, fakeroot=0, **keywords):
189 - """
190 - Spawn a subprocess with extra portage-specific options.
191 - Optiosn include:
192 -
193 - Sandbox: Sandbox means the spawned process will be limited in its ability t
194 - read and write files (normally this means it is restricted to ${D}/)
195 - SElinux Sandbox: Enables sandboxing on SElinux
196 - Reduced Privileges: Drops privilages such that the process runs as portage:portage
197 - instead of as root.
198 -
199 - Notes: os.system cannot be used because it messes with signal handling. Instead we
200 - use the portage.process spawn* family of functions.
201 -
202 - This function waits for the process to terminate.
203 -
204 - @param mystring: Command to run
205 - @type mystring: String
206 - @param mysettings: Either a Dict of Key,Value pairs or an instance of portage.config
207 - @type mysettings: Dictionary or config instance
208 - @param debug: Ignored
209 - @type debug: Boolean
210 - @param free: Enable sandboxing for this process
211 - @type free: Boolean
212 - @param droppriv: Drop to portage:portage when running this command
213 - @type droppriv: Boolean
214 - @param sesandbox: Enable SELinux Sandboxing (toggles a context switch)
215 - @type sesandbox: Boolean
216 - @param fakeroot: Run this command with faked root privileges
217 - @type fakeroot: Boolean
218 - @param keywords: Extra options encoded as a dict, to be passed to spawn
219 - @type keywords: Dictionary
220 - @rtype: Integer
221 - @returns:
222 - 1. The return code of the spawned process.
223 - """
224 -
225 - if isinstance(mysettings, dict):
226 - env=mysettings
227 - keywords["opt_name"]="[ %s ]" % "portage"
228 - else:
229 - check_config_instance(mysettings)
230 - env=mysettings.environ()
231 - if mysettings.mycpv is not None:
232 - keywords["opt_name"] = "[%s]" % mysettings.mycpv
233 - else:
234 - keywords["opt_name"] = "[%s/%s]" % \
235 - (mysettings.get("CATEGORY",""), mysettings.get("PF",""))
236 -
237 - fd_pipes = keywords.get("fd_pipes")
238 - if fd_pipes is None:
239 - fd_pipes = {
240 - 0:sys.stdin.fileno(),
241 - 1:sys.stdout.fileno(),
242 - 2:sys.stderr.fileno(),
243 - }
244 - # In some cases the above print statements don't flush stdout, so
245 - # it needs to be flushed before allowing a child process to use it
246 - # so that output always shows in the correct order.
247 - stdout_filenos = (sys.stdout.fileno(), sys.stderr.fileno())
248 - for fd in fd_pipes.values():
249 - if fd in stdout_filenos:
250 - sys.stdout.flush()
251 - sys.stderr.flush()
252 - break
253 -
254 - # The default policy for the sesandbox domain only allows entry (via exec)
255 - # from shells and from binaries that belong to portage (the number of entry
256 - # points is minimized). The "tee" binary is not among the allowed entry
257 - # points, so it is spawned outside of the sesandbox domain and reads from a
258 - # pseudo-terminal that connects two domains.
259 - logfile = keywords.get("logfile")
260 - mypids = []
261 - master_fd = None
262 - slave_fd = None
263 - fd_pipes_orig = None
264 - got_pty = False
265 - if logfile:
266 - del keywords["logfile"]
267 - if 1 not in fd_pipes or 2 not in fd_pipes:
268 - raise ValueError(fd_pipes)
269 -
270 - got_pty, master_fd, slave_fd = \
271 - _create_pty_or_pipe(copy_term_size=fd_pipes[1])
272 -
273 - if not got_pty and 'sesandbox' in mysettings.features \
274 - and mysettings.selinux_enabled():
275 - # With sesandbox, logging works through a pty but not through a
276 - # normal pipe. So, disable logging if ptys are broken.
277 - # See Bug #162404.
278 - logfile = None
279 - os.close(master_fd)
280 - master_fd = None
281 - os.close(slave_fd)
282 - slave_fd = None
283 -
284 - if logfile:
285 -
286 - fd_pipes.setdefault(0, sys.stdin.fileno())
287 - fd_pipes_orig = fd_pipes.copy()
288 -
289 - # We must set non-blocking mode before we close the slave_fd
290 - # since otherwise the fcntl call can fail on FreeBSD (the child
291 - # process might have already exited and closed slave_fd so we
292 - # have to keep it open in order to avoid FreeBSD potentially
293 - # generating an EAGAIN exception).
294 - import fcntl
295 - fcntl.fcntl(master_fd, fcntl.F_SETFL,
296 - fcntl.fcntl(master_fd, fcntl.F_GETFL) | os.O_NONBLOCK)
297 -
298 - fd_pipes[0] = fd_pipes_orig[0]
299 - fd_pipes[1] = slave_fd
300 - fd_pipes[2] = slave_fd
301 - keywords["fd_pipes"] = fd_pipes
302 -
303 - features = mysettings.features
304 - # TODO: Enable fakeroot to be used together with droppriv. The
305 - # fake ownership/permissions will have to be converted to real
306 - # permissions in the merge phase.
307 - fakeroot = fakeroot and uid != 0 and portage.process.fakeroot_capable
308 - if droppriv and not uid and portage_gid and portage_uid:
309 - keywords.update({"uid":portage_uid,"gid":portage_gid,
310 - "groups":userpriv_groups,"umask":0o02})
311 - if not free:
312 - free=((droppriv and "usersandbox" not in features) or \
313 - (not droppriv and "sandbox" not in features and \
314 - "usersandbox" not in features and not fakeroot))
315 -
316 - if not free and not (fakeroot or process.sandbox_capable):
317 - free = True
318 -
319 - if free or "SANDBOX_ACTIVE" in os.environ:
320 - keywords["opt_name"] += " bash"
321 - spawn_func = portage.process.spawn_bash
322 - elif fakeroot:
323 - keywords["opt_name"] += " fakeroot"
324 - keywords["fakeroot_state"] = os.path.join(mysettings["T"], "fakeroot.state")
325 - spawn_func = portage.process.spawn_fakeroot
326 - else:
327 - keywords["opt_name"] += " sandbox"
328 - spawn_func = portage.process.spawn_sandbox
329 -
330 - if sesandbox:
331 - spawn_func = selinux.spawn_wrapper(spawn_func,
332 - mysettings["PORTAGE_SANDBOX_T"])
333 -
334 - returnpid = keywords.get("returnpid")
335 - keywords["returnpid"] = True
336 - try:
337 - mypids.extend(spawn_func(mystring, env=env, **keywords))
338 - finally:
339 - if logfile:
340 - os.close(slave_fd)
341 -
342 - if returnpid:
343 - return mypids
344 -
345 - if logfile:
346 - log_file = open(_unicode_encode(logfile), mode='ab')
347 - apply_secpass_permissions(logfile,
348 - uid=portage_uid, gid=portage_gid, mode=0o664)
349 - stdout_file = os.fdopen(os.dup(fd_pipes_orig[1]), 'wb')
350 - master_file = os.fdopen(master_fd, 'rb')
351 - iwtd = [master_file]
352 - owtd = []
353 - ewtd = []
354 - import array, select
355 - buffsize = 65536
356 - eof = False
357 - while not eof:
358 - events = select.select(iwtd, owtd, ewtd)
359 - for f in events[0]:
360 - # Use non-blocking mode to prevent read
361 - # calls from blocking indefinitely.
362 - buf = array.array('B')
363 - try:
364 - buf.fromfile(f, buffsize)
365 - except EOFError:
366 - pass
367 - if not buf:
368 - eof = True
369 - break
370 - if f is master_file:
371 - buf.tofile(stdout_file)
372 - stdout_file.flush()
373 - buf.tofile(log_file)
374 - log_file.flush()
375 - log_file.close()
376 - stdout_file.close()
377 - master_file.close()
378 - pid = mypids[-1]
379 - retval = os.waitpid(pid, 0)[1]
380 - portage.process.spawned_pids.remove(pid)
381 - if retval != os.EX_OK:
382 - if retval & 0xff:
383 - return (retval & 0xff) << 8
384 - return retval >> 8
385 - return retval
386 -
387 -=======
388 ->>>>>>> .merge-right.r15449
389 def digestgen(myarchives=None, mysettings=None,
390 overwrite=None, manifestonly=None, myportdb=None):
391 """
392
393 Modified: main/branches/prefix/pym/portage/dbapi/bintree.py
394 ===================================================================
395 --- main/branches/prefix/pym/portage/dbapi/bintree.py 2010-02-27 18:53:28 UTC (rev 15479)
396 +++ main/branches/prefix/pym/portage/dbapi/bintree.py 2010-02-27 19:01:26 UTC (rev 15480)
397 @@ -13,6 +13,7 @@
398 'portage.package.ebuild.doebuild:_vdb_use_conditional_atoms',
399 'portage.update:update_dbentries',
400 'portage.util:ensure_dirs,normalize_path,writemsg,writemsg_stdout',
401 + 'portage.util.listdir:listdir',
402 'portage.versions:best,catpkgsplit,catsplit',
403 )
404
405 @@ -23,7 +24,7 @@
406 from portage.const import EAPI
407 from portage.localization import _
408
409 -from portage import dep_expand, listdir, _movefile
410 +from portage import dep_expand, _movefile
411 from portage import os
412 from portage import _encodings
413 from portage import _unicode_decode
414
415 Modified: main/branches/prefix/pym/portage/dbapi/porttree.py
416 ===================================================================
417 --- main/branches/prefix/pym/portage/dbapi/porttree.py 2010-02-27 18:53:28 UTC (rev 15479)
418 +++ main/branches/prefix/pym/portage/dbapi/porttree.py 2010-02-27 19:01:26 UTC (rev 15480)
419 @@ -11,9 +11,11 @@
420 import portage
421 portage.proxy.lazyimport.lazyimport(globals(),
422 'portage.checksum',
423 - 'portage.dep:dep_getkey,match_from_list,paren_reduce,use_reduce',
424 + 'portage.dep:dep_getkey,flatten,match_from_list,paren_reduce,use_reduce',
425 'portage.env.loaders:KeyValuePairFileLoader',
426 + 'portage.package.ebuild.doebuild:doebuild',
427 'portage.util:ensure_dirs,writemsg,writemsg_level',
428 + 'portage.util.listdir:listdir',
429 'portage.versions:best,catpkgsplit,_pkgsplit@pkgsplit,ver_regexp',
430 )
431
432 @@ -27,8 +29,8 @@
433 from portage.localization import _
434 from portage.manifest import Manifest
435
436 -from portage import eclass_cache, auxdbkeys, doebuild, flatten, \
437 - listdir, dep_expand, eapi_is_supported, dep_check, \
438 +from portage import eclass_cache, auxdbkeys, \
439 + dep_expand, eapi_is_supported, dep_check, \
440 _eapi_is_deprecated
441 from portage import os
442 from portage import _encodings
443
444 Modified: main/branches/prefix/pym/portage/dbapi/vartree.py
445 ===================================================================
446 --- main/branches/prefix/pym/portage/dbapi/vartree.py 2010-02-27 18:53:28 UTC (rev 15479)
447 +++ main/branches/prefix/pym/portage/dbapi/vartree.py 2010-02-27 19:01:26 UTC (rev 15480)
448 @@ -12,7 +12,7 @@
449 import portage
450 portage.proxy.lazyimport.lazyimport(globals(),
451 'portage.checksum:_perform_md5_merge@perform_md5',
452 - 'portage.dep:dep_getkey,isjustname,match_from_list,' + \
453 + 'portage.dep:dep_getkey,isjustname,flatten,match_from_list,' + \
454 'use_reduce,paren_reduce,_slot_re',
455 'portage.elog:elog_process',
456 'portage.locks:lockdir,unlockdir',
457 @@ -24,7 +24,10 @@
458 'portage.util:apply_secpass_permissions,ConfigProtect,ensure_dirs,' + \
459 'writemsg,writemsg_level,write_atomic,atomic_ofstream,writedict,' + \
460 'grabfile,grabdict,normalize_path,new_protect_filename,getlibpaths',
461 - 'portage.versions:best,catpkgsplit,catsplit,pkgcmp,_pkgsplit@pkgsplit',
462 + 'portage.util.digraph:digraph',
463 + 'portage.util.listdir:dircache,listdir',
464 + 'portage.versions:best,catpkgsplit,catsplit,cpv_getkey,pkgcmp,' + \
465 + '_pkgsplit@pkgsplit',
466 )
467
468 from portage.const import CACHE_PATH, CONFIG_MEMORY_FILE, \
469 @@ -36,9 +39,8 @@
470 FileNotFound, PermissionDenied, UnsupportedAPIException
471 from portage.localization import _
472
473 -from portage import listdir, dep_expand, digraph, flatten, \
474 - env_update, \
475 - abssymlink, movefile, _movefile, bsd_chflags, cpv_getkey
476 +from portage import dep_expand, env_update, \
477 + abssymlink, movefile, _movefile, bsd_chflags
478
479 # This is a special version of the os module, wrapped for unicode support.
480 from portage import os
481 @@ -2077,7 +2079,6 @@
482 self.mtdircache.pop(pkg_dblink.cat, None)
483 self.matchcache.pop(pkg_dblink.cat, None)
484 self.cpcache.pop(pkg_dblink.mysplit[0], None)
485 - from portage import dircache
486 dircache.pop(pkg_dblink.dbcatdir, None)
487
488 def match(self, origdep, use_cache=1):
489
490 Modified: main/branches/prefix/pym/portage/package/ebuild/doebuild.py
491 ===================================================================
492 --- main/branches/prefix/pym/portage/package/ebuild/doebuild.py 2010-02-27 18:53:28 UTC (rev 15479)
493 +++ main/branches/prefix/pym/portage/package/ebuild/doebuild.py 2010-02-27 19:01:26 UTC (rev 15480)
494 @@ -280,7 +280,7 @@
495 if os.path.exists(exit_status_file):
496 os.unlink(exit_status_file)
497
498 -_doebuild_manifest_exempt_depend = 0
499 +
500 _doebuild_manifest_cache = None
501 _doebuild_broken_ebuilds = set()
502 _doebuild_broken_manifests = set()
503 @@ -401,16 +401,13 @@
504 noiselevel=-1)
505 return 1
506
507 - global _doebuild_manifest_exempt_depend
508 -
509 if "strict" in features and \
510 "digest" not in features and \
511 tree == "porttree" and \
512 mydo not in ("digest", "manifest", "help") and \
513 - not _doebuild_manifest_exempt_depend:
514 + not portage._doebuild_manifest_exempt_depend:
515 # Always verify the ebuild checksums before executing it.
516 - global _doebuild_manifest_cache, _doebuild_broken_ebuilds, \
517 - _doebuild_broken_ebuilds
518 + global _doebuild_manifest_cache, _doebuild_broken_ebuilds
519
520 if myebuild in _doebuild_broken_ebuilds:
521 return 1
522 @@ -508,7 +505,7 @@
523 if mydo in ("digest", "manifest", "help"):
524 # Temporarily exempt the depend phase from manifest checks, in case
525 # aux_get calls trigger cache generation.
526 - _doebuild_manifest_exempt_depend += 1
527 + portage._doebuild_manifest_exempt_depend += 1
528
529 # If we don't need much space and we don't need a constant location,
530 # we can temporarily override PORTAGE_TMPDIR with a random temp dir
531 @@ -1023,7 +1020,7 @@
532 if mydo in ("digest", "manifest", "help"):
533 # If necessary, depend phase has been triggered by aux_get calls
534 # and the exemption is no longer needed.
535 - _doebuild_manifest_exempt_depend -= 1
536 + portage._doebuild_manifest_exempt_depend -= 1
537
538 def _validate_deps(mysettings, myroot, mydo, mydbapi):
539
540
541 Modified: main/branches/prefix/pym/portage/util/digraph.py
542 ===================================================================
543 --- main/branches/prefix/pym/portage/util/digraph.py 2010-02-27 18:53:28 UTC (rev 15479)
544 +++ main/branches/prefix/pym/portage/util/digraph.py 2010-02-27 19:01:26 UTC (rev 15480)
545 @@ -2,6 +2,8 @@
546 # Distributed under the terms of the GNU General Public License v2
547 # $Id$
548
549 +__all__ = ['digraph']
550 +
551 from portage.util import writemsg
552
553 class digraph(object):
554
555 Copied: main/branches/prefix/pym/portage/util/listdir.py (from rev 15451, main/trunk/pym/portage/util/listdir.py)
556 ===================================================================
557 --- main/branches/prefix/pym/portage/util/listdir.py (rev 0)
558 +++ main/branches/prefix/pym/portage/util/listdir.py 2010-02-27 19:01:26 UTC (rev 15480)
559 @@ -0,0 +1,153 @@
560 +# Copyright 2010 Gentoo Foundation
561 +# Distributed under the terms of the GNU General Public License v2
562 +# $Id$
563 +
564 +__all__ = ['cacheddir', 'listdir']
565 +
566 +import errno
567 +import stat
568 +import time
569 +
570 +from portage import os
571 +from portage.exception import DirectoryNotFound, PermissionDenied, PortageException
572 +from portage.util import normalize_path, writemsg
573 +
574 +dircache = {}
575 +cacheHit = 0
576 +cacheMiss = 0
577 +cacheStale = 0
578 +
579 +def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True):
580 + global cacheHit,cacheMiss,cacheStale
581 + mypath = normalize_path(my_original_path)
582 + if mypath in dircache:
583 + cacheHit += 1
584 + cached_mtime, list, ftype = dircache[mypath]
585 + else:
586 + cacheMiss += 1
587 + cached_mtime, list, ftype = -1, [], []
588 + try:
589 + pathstat = os.stat(mypath)
590 + if stat.S_ISDIR(pathstat[stat.ST_MODE]):
591 + mtime = pathstat.st_mtime
592 + else:
593 + raise DirectoryNotFound(mypath)
594 + except EnvironmentError as e:
595 + if e.errno == PermissionDenied.errno:
596 + raise PermissionDenied(mypath)
597 + del e
598 + return [], []
599 + except PortageException:
600 + return [], []
601 + # Python retuns mtime in seconds, so if it was changed in the last few seconds, it could be invalid
602 + if mtime != cached_mtime or time.time() - mtime < 4:
603 + if mypath in dircache:
604 + cacheStale += 1
605 + try:
606 + list = os.listdir(mypath)
607 + except EnvironmentError as e:
608 + if e.errno != errno.EACCES:
609 + raise
610 + del e
611 + raise PermissionDenied(mypath)
612 + ftype = []
613 + for x in list:
614 + try:
615 + if followSymlinks:
616 + pathstat = os.stat(mypath+"/"+x)
617 + else:
618 + pathstat = os.lstat(mypath+"/"+x)
619 +
620 + if stat.S_ISREG(pathstat[stat.ST_MODE]):
621 + ftype.append(0)
622 + elif stat.S_ISDIR(pathstat[stat.ST_MODE]):
623 + ftype.append(1)
624 + elif stat.S_ISLNK(pathstat[stat.ST_MODE]):
625 + ftype.append(2)
626 + else:
627 + ftype.append(3)
628 + except (IOError, OSError):
629 + ftype.append(3)
630 + dircache[mypath] = mtime, list, ftype
631 +
632 + ret_list = []
633 + ret_ftype = []
634 + for x in range(0, len(list)):
635 + if list[x] in ignorelist:
636 + pass
637 + elif ignorecvs:
638 + if list[x][:2] != ".#":
639 + ret_list.append(list[x])
640 + ret_ftype.append(ftype[x])
641 + else:
642 + ret_list.append(list[x])
643 + ret_ftype.append(ftype[x])
644 +
645 + writemsg("cacheddirStats: H:%d/M:%d/S:%d\n" % (cacheHit, cacheMiss, cacheStale),10)
646 + return ret_list, ret_ftype
647 +
648 +_ignorecvs_dirs = ('CVS', 'SCCS', '.svn', '.git')
649 +
650 +def listdir(mypath, recursive=False, filesonly=False, ignorecvs=False, ignorelist=[], followSymlinks=True,
651 + EmptyOnError=False, dirsonly=False):
652 + """
653 + Portage-specific implementation of os.listdir
654 +
655 + @param mypath: Path whose contents you wish to list
656 + @type mypath: String
657 + @param recursive: Recursively scan directories contained within mypath
658 + @type recursive: Boolean
659 + @param filesonly; Only return files, not more directories
660 + @type filesonly: Boolean
661 + @param ignorecvs: Ignore CVS directories ('CVS','SCCS','.svn','.git')
662 + @type ignorecvs: Boolean
663 + @param ignorelist: List of filenames/directories to exclude
664 + @type ignorelist: List
665 + @param followSymlinks: Follow Symlink'd files and directories
666 + @type followSymlinks: Boolean
667 + @param EmptyOnError: Return [] if an error occurs (deprecated, always True)
668 + @type EmptyOnError: Boolean
669 + @param dirsonly: Only return directories.
670 + @type dirsonly: Boolean
671 + @rtype: List
672 + @returns: A list of files and directories (or just files or just directories) or an empty list.
673 + """
674 +
675 + list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks)
676 +
677 + if list is None:
678 + list=[]
679 + if ftype is None:
680 + ftype=[]
681 +
682 + if not (filesonly or dirsonly or recursive):
683 + return list
684 +
685 + if recursive:
686 + x=0
687 + while x<len(ftype):
688 + if ftype[x] == 1 and not \
689 + (ignorecvs and os.path.basename(list[x]) in _ignorecvs_dirs):
690 + l,f = cacheddir(mypath+"/"+list[x], ignorecvs, ignorelist, EmptyOnError,
691 + followSymlinks)
692 +
693 + l=l[:]
694 + for y in range(0,len(l)):
695 + l[y]=list[x]+"/"+l[y]
696 + list=list+l
697 + ftype=ftype+f
698 + x+=1
699 + if filesonly:
700 + rlist=[]
701 + for x in range(0,len(ftype)):
702 + if ftype[x]==0:
703 + rlist=rlist+[list[x]]
704 + elif dirsonly:
705 + rlist = []
706 + for x in range(0, len(ftype)):
707 + if ftype[x] == 1:
708 + rlist = rlist + [list[x]]
709 + else:
710 + rlist=list
711 +
712 + return rlist