|
1 # Copyright (C) 2003-2007 John Goerzen |
|
2 # <jgoerzen@complete.org> |
|
3 # |
|
4 # This program is free software; you can redistribute it and/or modify |
|
5 # it under the terms of the GNU General Public License as published by |
|
6 # the Free Software Foundation; either version 2 of the License, or |
|
7 # (at your option) any later version. |
|
8 # |
|
9 # This program is distributed in the hope that it will be useful, |
|
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 # GNU General Public License for more details. |
|
13 # |
|
14 # You should have received a copy of the GNU General Public License |
|
15 # along with this program; if not, write to the Free Software |
|
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
17 |
|
18 import os, sys, re |
|
19 |
|
20 nulldev = None |
|
21 verbose = 0 |
|
22 |
|
23 class ExecProblem(Exception): |
|
24 pass |
|
25 |
|
26 def mainexec(program, args = [], child_stdout = None, |
|
27 child_stdin = None, child_stderr = None, wait = 1, closefds = []): |
|
28 """Runs the program as a sub-process, passing to it args if specified. |
|
29 The sub-process has its file descriptors adjusted as per the arguments. |
|
30 |
|
31 If wait is 1, wait until the child exits, then return the result code from |
|
32 os.waitpid(). |
|
33 |
|
34 If wait is 0, return the PID immediately.""" |
|
35 global verbose |
|
36 def setfds(source, dest): |
|
37 if source != None: |
|
38 if hasattr(source, 'fileno'): |
|
39 source = source.fileno() |
|
40 os.dup2(source, dest) |
|
41 |
|
42 pid = os.fork() |
|
43 if not pid: |
|
44 if verbose: |
|
45 print "Running: ", program, args |
|
46 setfds(child_stdin, 0) |
|
47 setfds(child_stdout, 1) |
|
48 setfds(child_stderr, 2) |
|
49 for fd in closefds: |
|
50 os.close(fd) |
|
51 os.execvp(program, (program,) + tuple(args)) |
|
52 sys.exit(255) |
|
53 else: |
|
54 if wait: |
|
55 return os.waitpid(pid, 0)[1] |
|
56 else: |
|
57 return pid |
|
58 |
|
59 def safeexec(program, args = [], child_stdout = None, |
|
60 child_stdin = None, child_stderr = None, |
|
61 expected = 0): |
|
62 """Calls mainexec() with the appropriate arguments, and raises |
|
63 an exception if the program died with a signal or returned an |
|
64 error code other than expected. This function will always wait.""" |
|
65 result = mainexec(program, args, child_stdout, child_stdin, child_stderr) |
|
66 return checkresult(result, expected) |
|
67 |
|
68 def getstdoutsafeexec(program, args, expected = 0): |
|
69 pipes = os.pipe() |
|
70 pid = mainexec(program, args, child_stdout = pipes[1], wait = 0) |
|
71 os.close(pipes[1]) |
|
72 fd = os.fdopen(pipes[0], 'r') |
|
73 retval = fd.readlines() |
|
74 checkpid(pid, expected) |
|
75 os.close(pipes[0]) |
|
76 return retval |
|
77 |
|
78 def silentsafeexec(program, args, expected = 0): |
|
79 """Silently runs the specified program.""" |
|
80 null = getnull() |
|
81 result = mainexec(program, args, null, null, null) |
|
82 return checkresult(result, expected) |
|
83 |
|
84 def checkresult(result, expected): |
|
85 info = [] |
|
86 if os.WIFSIGNALED(result): |
|
87 info.append("got signal %d" % os.WTERMSIG(result)) |
|
88 if os.WIFEXITED(result): |
|
89 info.append("exited with code %d" % os.WEXITSTATUS(result)) |
|
90 info = ",".join(info) |
|
91 if not os.WIFEXITED(result): |
|
92 raise ExecProblem, info |
|
93 if os.WEXITSTATUS(result) != expected: |
|
94 raise ExecProblem, info + " (expected exit code %d)" % expected |
|
95 return result |
|
96 |
|
97 def checkpid(pid, expected): |
|
98 return checkresult(os.waitpid(pid, 0)[1], expected) |
|
99 |
|
100 def getnull(): |
|
101 global nulldev |
|
102 if not nulldev: |
|
103 nulldev = open("/dev/null", "w+") |
|
104 return nulldev |
|
105 |
|
106 def chdircmd(newdir, func, *args, **kwargs): |
|
107 cwd = os.getcwd() |
|
108 os.chdir(newdir) |
|
109 try: |
|
110 return apply(func, args, kwargs) |
|
111 finally: |
|
112 os.chdir(cwd) |
|
113 |
|
114 def maketree(path, addpath = None, ignore = [], res = None): |
|
115 thisdir = os.listdir(path) |
|
116 retval = [] |
|
117 others = [] |
|
118 if res == None: |
|
119 res = [re.compile(x) for x in ignore] |
|
120 for item in thisdir: |
|
121 skip = 0 |
|
122 for retest in res: |
|
123 if retest.search(item): |
|
124 skip = 1 |
|
125 break |
|
126 if skip: |
|
127 continue |
|
128 dirname = os.path.join(path, item) |
|
129 if os.path.isdir(dirname) and not os.path.islink(dirname): |
|
130 if addpath: |
|
131 retval.append(os.path.join(addpath, item) + '/') |
|
132 else: |
|
133 retval.append(item + '/') |
|
134 if addpath: |
|
135 newaddpath = os.path.join(addpath, item) |
|
136 else: |
|
137 newaddpath = item |
|
138 others.extend(maketree(dirname, newaddpath, res = res)) |
|
139 else: |
|
140 if addpath: |
|
141 retval.append(os.path.join(addpath, item)) |
|
142 else: |
|
143 retval.append(item) |
|
144 return sorttree(retval + others) |
|
145 |
|
146 def sorttree(srctree, filesfirst = False): |
|
147 retval = [] |
|
148 dirs = [x for x in srctree if x.endswith('/')] |
|
149 files = [x for x in srctree if not x.endswith('/')] |
|
150 dirs.sort() |
|
151 files.sort() |
|
152 if filesfirst: |
|
153 return files + dirs |
|
154 else: |
|
155 return dirs + files |
|
156 |
|
157 |
|
158 def copyfrom(srcdir, destdir): |
|
159 pipes = os.pipe() |
|
160 verbargs = [] |
|
161 #if verbose: |
|
162 # verbargs.append('-v') |
|
163 readerpid = chdircmd(srcdir, mainexec, "tar", ["-cSpf", "-", "."], |
|
164 child_stdout = pipes[1], wait = 0, |
|
165 closefds = [pipes[0]]) |
|
166 writerpid = chdircmd(destdir, mainexec, "tar", ["-xSpf", "-"] + verbargs, |
|
167 child_stdin = pipes[0], wait = 0, closefds = [pipes[1]]) |
|
168 os.close(pipes[0]) |
|
169 os.close(pipes[1]) |
|
170 checkpid(readerpid, 0) |
|
171 checkpid(writerpid, 0) |
|
172 |