blob: 6e6f53cc93dd7f3f5899a5b49506c5e83ebf8827 [file] [log] [blame]
mbligh56f1fbb2006-10-01 15:10:56 +00001__author__ = """Copyright Martin J. Bligh, Andy Whitcroft, 2005, 2006"""
2
3import sys, os
4
5class fd_stack:
6 """a stack of fd redirects
7
8 Redirects cause existing fd's to be pushed on the stack; restore()
9 causes the current set of redirects to be popped, restoring the previous
10 filehandle destinations.
11
12 Note that we need to redirect both the sys.stdout type descriptor
13 (which print, etc use) and the low level OS numbered descriptor
14 which os.system() etc use.
15 """
16
17 def __init__(self, fd, filehandle):
18 self.fd = fd # eg 1
19 self.filehandle = filehandle # eg sys.stdout
20 self.stack = [(fd, filehandle)]
21
22
23 def update_handle(self, new):
24 if (self.filehandle == sys.stdout):
25 sys.stdout = new
26 if (self.filehandle == sys.stderr):
27 sys.stderr = new
28 self.filehandle = new
29
30 def redirect(self, filename):
31 """Redirect output to the specified file
32
33 Overwrites the previous contents, if any.
34 """
35 self.filehandle.flush()
36 fdcopy = os.dup(self.fd)
37 self.stack.append( (fdcopy, self.filehandle, 0) )
38 # self.filehandle = file(filename, 'w')
39 if (os.path.isfile(filename)):
40 newfd = os.open(filename, os.O_WRONLY)
41 else:
42 newfd = os.open(filename, os.O_WRONLY | os.O_CREAT)
43 os.dup2(newfd, self.fd)
44 os.close(newfd)
45 self.update_handle(os.fdopen(self.fd, 'w'))
46
47
48 def tee_redirect(self, filename):
49 """Tee output to the specified file
50
51 Overwrites the previous contents, if any.
52 """
53 self.filehandle.flush()
54 #print_to_tty("tee_redirect to " + filename)
55 #where_art_thy_filehandles()
56 fdcopy = os.dup(self.fd)
57 r, w = os.pipe()
58 pid = os.fork()
59 if pid: # parent
60 os.close(r)
61 os.dup2(w, self.fd)
62 os.close(w)
63 else: # child
64 os.close(w)
65 os.dup2(r, 0)
66 os.dup2(fdcopy, 1)
67 os.close(r)
68 os.close(fdcopy)
69 os.execlp('tee', 'tee', filename)
70 self.stack.append( (fdcopy, self.filehandle, pid) )
71 self.update_handle(os.fdopen(self.fd, 'w'))
72 #where_art_thy_filehandles()
73 #print_to_tty("done tee_redirect to " + filename)
74
75
76 def restore(self):
77 """unredirect one level"""
78 self.filehandle.flush()
79 # print_to_tty("ENTERING RESTORE %d" % self.fd)
80 # where_art_thy_filehandles()
81 (old_fd, old_filehandle, pid) = self.stack.pop()
82 # print_to_tty("old_fd %d" % old_fd)
83 # print_to_tty("self.fd %d" % self.fd)
84 self.filehandle.close() # seems to close old_fd as well.
85 if pid:
86 os.waitpid(pid, 0)
87 # where_art_thy_filehandles()
88 os.dup2(old_fd, self.fd)
89 # print_to_tty("CLOSING FD %d" % old_fd)
90 os.close(old_fd)
91 # where_art_thy_filehandles()
92 self.update_handle(old_filehandle)
93 # where_art_thy_filehandles()
94 # print_to_tty("EXIT RESTORE %d" % self.fd)