1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 import bdb
16 import bz2
17 import debugger
18 import fcntl
19 import errno
20 import itertools
21 import log
22 import misc
23 import os
24 import re
25 import select
26 import shutil
27 import signal
28 import stat
29 import string
30 import StringIO
31 import subprocess
32 import struct
33 import sys
34 import tempfile
35 import time
36 import types
37 import urllib
38 import urlparse
39 import weakref
40 import xmlrpclib
41 import zlib
42
43 from conary.lib import fixedglob, graph, log, api
44
45
46 from conary.lib.formattrace import formatTrace
47
48
49
50
52 s = os.path.normpath(path)
53 if s.startswith(os.sep + os.sep):
54 return s[1:]
55 return s
56
65
67 return stat.S_ISREG(os.lstat(path)[stat.ST_MODE])
68
69
80
81
82 @api.developerApi
84 """
85 Make one or more directories if they do not already exist, including any
86 needed parent directories. Similar to L{os.makedirs} except that it does
87 not error if the requested directory already exists, and it is more
88 resilient to race conditions.
89 """
90 for path in paths:
91 path = normpath(os.path.abspath(path))
92 if not os.path.exists(path):
93 _mkdirs(path)
94
95
97 file = arg[0]
98 path = arg[1]
99 testname = '%s%s%s' %(dirname, os.sep, file)
100 if file in names:
101 path[0] = testname
102 del names
103
109
111 for dir in searchdirs:
112 s = "%s%s%s" %(dir, os.sep, file)
113 if os.path.exists(s):
114 return s
115 if error:
116 raise OSError, (errno.ENOENT, os.strerror(errno.ENOENT))
117 return None
118
121
123 if not os.environ.has_key('PATH') or os.environ['PATH'] == '':
124 p = os.defpath
125 else:
126 p = os.environ['PATH']
127
128 pathlist = p.split (os.pathsep)
129
130 for path in pathlist:
131 f = os.path.join(path, filename)
132 if os.access(f, os.X_OK):
133 return f
134 return None
135
137 """Recursively list all files in the directory"""
138 items = [topdir]
139 while items:
140 item = items.pop()
141 if os.path.islink(item) or os.path.isfile(item):
142 yield item
143 continue
144
145 listdir = os.listdir(item)
146
147
148 listdir.sort()
149 listdir.reverse()
150 listdir = [ os.path.join(item, x) for x in listdir ]
151 items.extend(listdir)
152
153 if withDirs:
154
155 yield item
156
158 surl = list(urlparse.urlsplit(url))
159 if surl[2] == '':
160 surl[2] = '/'
161 elif surl[2] != '/':
162 tail = ''
163 if surl[2].endswith('/'):
164 tail = '/'
165 surl[2] = normpath(surl[2]) + tail
166 return urlparse.urlunsplit(surl)
167
168 errorMessage = '''
169 ERROR: An unexpected condition has occurred in Conary. This is
170 most likely due to insufficient handling of erroneous input, but
171 may be some other bug. In either case, please report the error at
172 http://issues.rpath.com/ and attach to the issue the file
173 %(stackfile)s
174
175 Then, for more complete information, please run the following script:
176 conary-debug "%(command)s"
177 You can attach the resulting archive to your issue report at
178 http://issues.rpath.com/ For more information, or if you have
179 trouble with the conary-debug command, go to:
180 http://wiki.rpath.com/wiki/Conary:How_To_File_An_Effective_Bug_Report
181
182 To get a debug prompt, rerun the command with --debug-all
183
184 Error details follow:
185
186 %(filename)s:%(lineno)s
187 %(errtype)s: %(errmsg)s
188
189 The complete related traceback has been saved as %(stackfile)s
190 '''
191 _debugAll = False
192
193 @api.developerApi
197 def SIGUSR1Handler(signum, frame):
198 global _debugAll
199 _debugAll = True
200 print >>sys.stderr, '<Turning on KeyboardInterrupt catching>'
201
202 def excepthook(typ, value, tb):
203 if typ is bdb.BdbQuit:
204 sys.exit(1)
205
206 sys.excepthook = sys.__excepthook__
207 if not _debugAll and (typ == KeyboardInterrupt and not debugCtrlC):
208 sys.exit(1)
209
210 out = BoundedStringIO()
211 formatTrace(typ, value, tb, stream = out, withLocals = False)
212 out.write("\nFull stack:\n")
213 formatTrace(typ, value, tb, stream = out, withLocals = True)
214 out.seek(0)
215 tbString = out.read()
216 del out
217 if log.syslog is not None:
218 log.syslog("command failed\n%s", tbString)
219
220 if debug or _debugAll:
221 formatTrace(typ, value, tb, stream = sys.stderr,
222 withLocals = False)
223 if sys.stdout.isatty() and sys.stdin.isatty():
224 debugger.post_mortem(tb, typ, value)
225 else:
226 sys.exit(1)
227 elif log.getVerbosity() is log.DEBUG:
228 log.debug(tbString)
229 else:
230 cmd = sys.argv[0]
231 if cmd.endswith('/commands/conary'):
232 cmd = cmd[:len('/commands/conary')] + '/bin/conary'
233 elif cmd.endswith('/commands/cvc'):
234 cmd = cmd[:len('/commands/cvc')] + '/bin/cvc'
235
236 origTb = tb
237 cmd = normpath(cmd)
238 sys.argv[0] = cmd
239 while tb.tb_next: tb = tb.tb_next
240 lineno = tb.tb_frame.f_lineno
241 filename = tb.tb_frame.f_code.co_filename
242 tmpfd, stackfile = tempfile.mkstemp('.txt', prefix)
243 os.write(tmpfd, tbString)
244 os.close(tmpfd)
245
246 sys.stderr.write(error % dict(command=' '.join(sys.argv),
247 filename=filename,
248 lineno=lineno,
249 errtype=typ.__name__,
250 errmsg=value,
251 stackfile=stackfile))
252
253
254
255 return excepthook
256
257
258
260 if rc:
261 if not os.WIFEXITED(rc):
262 info = 'Shell command "%s" killed with signal %d' \
263 %(cmd, os.WTERMSIG(rc))
264 if os.WEXITSTATUS(rc):
265 info = 'Shell command "%s" exited with exit code %d' \
266 %(cmd, os.WEXITSTATUS(rc))
267 log.error(info)
268 raise RuntimeError, info
269
270 -def execute(cmd, destDir=None, verbose=True):
271 """
272 similar to os.system, but raises errors if exit code != 0 and closes stdin
273 so processes can never block on user input
274 """
275 if verbose:
276 log.info(cmd)
277 rc = subprocess.call(cmd, shell=True, cwd=destDir, stdin=open(os.devnull))
278
279 if rc < 0:
280
281 rc = rc * -1
282 else:
283
284 rc = rc << 8
285 _handle_rc(rc, cmd)
286
288 """
289 Version of popen() that throws errors on close(), unlike os.popen()
290 """
291
299
304
305
306
307 -def find(s, subs, start=0):
308 ret = -1
309 found = None
310 for sub in subs:
311 this = string.find(s, sub, start)
312 if this > -1 and ( ret < 0 or this < ret):
313 ret = this
314 found = s[this:this+1]
315 return (ret, found)
316
319
320
321
323 """Class encapsulating the logic required by the brace expander parser"""
333 "Concatenation operator"
334
335 @classmethod
353
354 @classmethod
364
365 @classmethod
367 haveComma = False
368 haveText = False
369
370 listObj.append(None)
371 outputQ = []
372 operators = []
373 lastWasLiteral = False
374 for item in listObj:
375 if isinstance(item, basestring):
376 if not haveText:
377 text = []
378 outputQ.append(text)
379 haveText = True
380 else:
381 text = outputQ[-1]
382 text.append(item)
383 continue
384 if haveText:
385 topNode = outputQ.pop()
386 topNode = ''.join(topNode)
387 haveText = False
388 outputQ.append(topNode)
389 lastWasLiteral = True
390
391 if item is None:
392
393 break
394 if item is cls.Comma:
395 haveComma = True
396 lastWasLiteral = False
397 while operators:
398 op = operators.pop()
399 outputQ.append(op)
400 operators.append(item)
401 continue
402 outputQ.append(item)
403 if not lastWasLiteral:
404 lastWasLiteral = True
405 continue
406
407 while operators and operators[-1] is not cls.Comma:
408 op = operators.pop()
409 outputQ.append(op)
410 operators.append(cls.Concat)
411 while operators:
412 op = operators.pop()
413 outputQ.append(op)
414
415 stack = []
416 opMap = {
417 cls.Comma: cls.Alternative,
418 cls.Concat: cls.Product,
419 }
420 for item in outputQ:
421 if not (item is cls.Comma or item is cls.Concat):
422 stack.append(item)
423 continue
424 op2 = stack.pop()
425 op1 = stack.pop()
426 ncls = opMap[item]
427 if isinstance(op1, ncls):
428 op1.append(op2)
429 stack.append(op1)
430 elif isinstance(op2, ncls):
431 op2[0:0] = [op1]
432 stack.append(op2)
433 else:
434 nobj = ncls()
435 nobj.extend([op1, op2])
436 stack.append(nobj)
437 ret = stack[0]
438 if not haveComma:
439 ret = cls.Alternative([ret])
440 return ret
441
442 @classmethod
444 for item in l:
445 if item is cls.Comma:
446 yield ','
447 else:
448 yield item
449
450 @classmethod
498
501
502 @api.publicApi
504 """
505 @raises ValueError: raised if paths has unbalanced braces
506 @raises OSError: raised in some cases where lstat on a path fails
507 """
508 pathlist = []
509 for path in braceExpand(paths):
510 pathlist.extend(fixedglob.glob(path))
511 return pathlist
512
513 @api.developerApi
514 -def rmtree(paths, ignore_errors=False, onerror=None):
524
534
535 -def remove(paths, quiet=False):
545
546 -def copyfile(sources, dest, verbose=True):
551
552 -def copyfileobj(source, dest, callback = None, digest = None,
553 abortCheck = None, bufSize = 128*1024, rateLimit = None,
554 sizeLimit = None, total=0):
555 if hasattr(dest, 'send'):
556 write = dest.send
557 else:
558 write = dest.write
559
560 if rateLimit is None:
561 rateLimit = 0
562
563 if not rateLimit == 0:
564 if rateLimit < 8 * 1024:
565 bufSize = 4 * 1024
566 else:
567 bufSize = 8 * 1024
568
569 rateLimit = float(rateLimit)
570
571 starttime = time.time()
572
573 copied = 0
574
575 if abortCheck:
576 pollObj = select.poll()
577 pollObj.register(source.fileno(), select.POLLIN)
578 else:
579 pollObj = None
580
581 while True:
582 if sizeLimit and (sizeLimit - copied < bufSize):
583 bufSize = sizeLimit - copied
584
585 if abortCheck:
586
587
588 l = []
589 while not l:
590 if abortCheck():
591 return None
592 l = pollObj.poll(5000)
593
594 buf = source.read(bufSize)
595 if not buf:
596 break
597
598 total += len(buf)
599 copied += len(buf)
600 write(buf)
601
602 if digest:
603 digest.update(buf)
604
605 now = time.time()
606 if now == starttime:
607 rate = 0
608 else:
609 rate = copied / ((now - starttime))
610
611 if callback:
612 callback(total, rate)
613
614 if copied == sizeLimit:
615 break
616
617 if rateLimit > 0 and rate > rateLimit:
618 time.sleep((copied / rateLimit) - (copied / rate))
619
620 return copied
621
626
628 sourcelist = arg[0]
629 sourcelen = arg[1]
630 dest = arg[2]
631 filemode = arg[3]
632 dirmode = arg[4]
633 if dirmode:
634 os.chmod(dirname, dirmode)
635 for name in names:
636 if filemode:
637 os.chmod(dirname+os.sep+name, filemode)
638 sourcelist.append(os.path.normpath(
639 dest + os.sep + dirname[sourcelen:] + os.sep + name))
640
641 -def copytree(sources, dest, symlinks=False, filemode=None, dirmode=None):
642 """
643 Copies tree(s) from sources to dest, returning a list of
644 the filenames that it has written.
645 """
646 sourcelist = []
647 for source in braceGlob(sources):
648 if os.path.isdir(source):
649 if source[-1] == '/':
650 source = source[:-1]
651 thisdest = '%s%s%s' %(dest, os.sep, os.path.basename(source))
652 log.debug('copying [tree] %s to %s', source, thisdest)
653 shutil.copytree(source, thisdest, symlinks)
654 if dirmode:
655 os.chmod(thisdest, dirmode)
656 os.path.walk(source, _copyVisit,
657 (sourcelist, len(source), thisdest, filemode, dirmode))
658 else:
659 log.debug('copying [file] %s to %s', source, dest)
660 shutil.copy2(source, dest)
661 if dest.endswith(os.sep):
662 thisdest = dest + os.sep + os.path.basename(source)
663 else:
664 thisdest = dest
665 if filemode:
666 os.chmod(thisdest, filemode)
667 sourcelist.append(thisdest)
668 return sourcelist
669
696
699
701 """Split the path at the operating system's separators.
702 Returns a list with the path components in reverse order.
703 Empty path components are stripped out.
704 Example: 'a//b//c/d' -> ['d', 'c', 'b', 'a']
705 """
706 while 1:
707 path, tail = os.path.split(path)
708 if not tail:
709 break
710 yield tail
711
713 """Split the path at the operating system's separators
714 Empty path components are stripped out
715 Example: 'a//b//c/d' -> ['a', 'b', 'c', 'd']
716 """
717 ret = list(splitPathReverse(path))
718 ret.reverse()
719 return ret
720
722 try:
723 iter.next()
724 raise AssertionError
725 except StopIteration:
726 return True
727
728 ref = weakref.ref
730 """
731 Implements a cache of arbitrary (hashable) objects where an object
732 can be looked up and have its cached value retrieved. This allows
733 a single copy of immutable objects to be kept in memory.
734 """
736 dict.__init__(self, *args)
737
738 def remove(k, selfref=ref(self)):
739 self = selfref()
740 if self is not None:
741 return dict.__delitem__(self, k)
742 self._remove = remove
743
746
749
752
755
758
761
764
766 """Get the memory usage.
767 @param pid: Process to analyze (None for current process)
768 """
769 if pid is None:
770 pfn = "/proc/self/statm"
771 else:
772 pfn = "/proc/%d/statm" % pid
773 line = open(pfn).readline()
774
775
776 arr = [ 4 * int(x) for x in line.split()[:6] ]
777 vmsize, vmrss, vmshared, text, lib, data = arr
778
779
780
781
782 return vmsize, vmrss, vmshared, text, lib, data
783
793
795 """
796 Inserts newItem into haystack, maintaining the sorted order. The
797 cmpIdx is the item number in the list of tuples to base comparisons on.
798 Duplicates items aren't added. Returns True if the item was added,
799 False if it was already present.
800
801 @param haystack: list of tuples.
802 @type haystack: list
803 @param newItem: The item to be inserted
804 @type newItem: tuple
805 @param cmpFn: Comparison function
806 @type cmpFn: function
807 @rtype: bool
808 """
809 start = 0
810 finish = len(haystack) - 1
811 while start < finish:
812 i = (start + finish) / 2
813
814 rc = cmpFn(haystack[i], newItem)
815 if rc == 0:
816 start = i
817 finish = i
818 break
819 elif rc < 0:
820 start = i + 1
821 else:
822 finish = i - 1
823
824 if start >= len(haystack):
825 haystack.append(newItem)
826 else:
827 rc = cmpFn(haystack[start], newItem)
828 if rc < 0:
829 haystack.insert(start + 1, newItem)
830 elif rc > 0:
831 haystack.insert(start, newItem)
832 else:
833 return False
834
835 return True
836
837 _tempdir = tempfile.gettempdir()
842
844 """
845 a wrapper for tempfile.mkstemp that uses a common prefix which
846 is set through settempdir()
847 """
848 if dir is None:
849 global _tempdir
850 dir = _tempdir
851 return tempfile.mkstemp(suffix=suffix, prefix=prefix, dir=dir, text=text)
852
854
855 tags = {}
856 ptrSize = len(struct.pack("@P", 0))
857
858 @staticmethod
861
864
865 @staticmethod