diff options
author | LRN <lrn1986@gmail.com> | 2013-03-19 14:06:10 +0000 |
---|---|---|
committer | LRN <lrn1986@gmail.com> | 2013-03-19 14:06:10 +0000 |
commit | a15a0d82708f6d021dbd974aba3d712fe722d20f (patch) | |
tree | e447c7bf1ffb6a1b52abb0f6b73107fd6a508e1f /contrib | |
parent | 583e1cc42de7a8b1d846fca7e592d88599b77ebc (diff) | |
download | gnunet-a15a0d82708f6d021dbd974aba3d712fe722d20f.tar.gz gnunet-a15a0d82708f6d021dbd974aba3d712fe722d20f.zip |
A buildslave patch for our W32 slaves
* Safe process termination
* Use BUILDSLAVE_SHELL, if defined, to run commands
(Define it to something like
%SLAVEDIR%/dir-where-msys-is/bin/sh.exe --login -c
to be able to configure buildmaster with POSIX shell commands for all
platforms)
* Use temporary script files to change current directory when running MSYS
Diffstat (limited to 'contrib')
-rw-r--r-- | contrib/buildslave-0.8.5-gnunet-w32.patch | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/contrib/buildslave-0.8.5-gnunet-w32.patch b/contrib/buildslave-0.8.5-gnunet-w32.patch new file mode 100644 index 000000000..291efc47a --- /dev/null +++ b/contrib/buildslave-0.8.5-gnunet-w32.patch | |||
@@ -0,0 +1,183 @@ | |||
1 | diff -urN buildbot-slave-0.8.5.orig/buildslave/runprocess.py buildbot-slave-0.8.5/buildslave/runprocess.py | ||
2 | --- buildbot-slave-0.8.5.orig/buildslave/runprocess.py 2011-09-03 23:59:10 +0400 | ||
3 | +++ buildbot-slave-0.8.5/buildslave/runprocess.py 2012-11-02 03:08:05 +0400 | ||
4 | @@ -24,6 +24,7 @@ | ||
5 | import re | ||
6 | import subprocess | ||
7 | import traceback | ||
8 | +import tempfile | ||
9 | import stat | ||
10 | from collections import deque | ||
11 | |||
12 | @@ -36,6 +37,54 @@ | ||
13 | if runtime.platformType == 'posix': | ||
14 | from twisted.internet.process import Process | ||
15 | |||
16 | +if os.name == 'nt': | ||
17 | + import win32api | ||
18 | + import win32process | ||
19 | + | ||
20 | +def safe_terminate_process (proc, code): | ||
21 | + if os.name == 'nt': | ||
22 | + cp = win32api.GetCurrentProcess () | ||
23 | + result = False | ||
24 | + dupproc = win32api.DuplicateHandle (cp, proc._handle, cp, 2 | 1024 | 8 | 32 | 16, 0, 0) | ||
25 | + try: | ||
26 | + exitcode = win32process.GetExitCodeProcess (dupproc) | ||
27 | + if exitcode == 0x103: | ||
28 | + kernel32 = win32api.GetModuleHandle ("kernel32") | ||
29 | + exitprocess = win32api.GetProcAddress (kernel32, "ExitProcess") | ||
30 | + try: | ||
31 | + th, tid = win32process.CreateRemoteThread (dupproc, None, 0, exitprocess, code, 0) | ||
32 | + win32api.CloseHandle (th) | ||
33 | + except: | ||
34 | + pass | ||
35 | + result = True | ||
36 | + else: | ||
37 | + result = True | ||
38 | + # except failed to get exit code? failed to get module handle? | ||
39 | + finally: | ||
40 | + win32api.CloseHandle (dupproc) | ||
41 | + return result | ||
42 | + else: | ||
43 | + return proc.kill () | ||
44 | + | ||
45 | +class Dummy(object): | ||
46 | + def SetHandle (self, h): | ||
47 | + self._handle = h | ||
48 | + | ||
49 | +def safe_terminate_process_by_pid (proc, code): | ||
50 | + if os.name == 'nt': | ||
51 | + try: | ||
52 | + openproc = win32process.OpenProcess (2 | 1024 | 8 | 32 | 16, 0, proc) | ||
53 | + try: | ||
54 | + d = Dummy () | ||
55 | + d.SetHandle (openproc) | ||
56 | + safe_termiate_process (d, code) | ||
57 | + finally: | ||
58 | + win32api.CloseHandle (openproc) | ||
59 | + except: | ||
60 | + pass | ||
61 | + else: | ||
62 | + return os.kill (proc, code) | ||
63 | + | ||
64 | def shell_quote(cmd_list): | ||
65 | # attempt to quote cmd_list such that a shell will properly re-interpret | ||
66 | # it. The pipes module is only available on UNIX, and Windows "shell" | ||
67 | @@ -148,6 +197,7 @@ | ||
68 | self.pending_stdin = "" | ||
69 | self.stdin_finished = False | ||
70 | self.killed = False | ||
71 | + self.scriptfile = "" | ||
72 | |||
73 | def setStdin(self, data): | ||
74 | assert not self.connected | ||
75 | @@ -198,6 +248,11 @@ | ||
76 | rc = 1 | ||
77 | else: | ||
78 | rc = -1 | ||
79 | + if self.scriptfile: | ||
80 | + try: | ||
81 | + os.remove (self.scriptfile) | ||
82 | + except: | ||
83 | + pass | ||
84 | self.command.finished(sig, rc) | ||
85 | |||
86 | |||
87 | @@ -400,30 +455,52 @@ | ||
88 | |||
89 | self.pp = RunProcessPP(self) | ||
90 | |||
91 | - if type(self.command) in types.StringTypes: | ||
92 | - if runtime.platformType == 'win32': | ||
93 | - argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args | ||
94 | - if '/c' not in argv: argv += ['/c'] | ||
95 | - argv += [self.command] | ||
96 | - else: | ||
97 | - # for posix, use /bin/sh. for other non-posix, well, doesn't | ||
98 | - # hurt to try | ||
99 | - argv = ['/bin/sh', '-c', self.command] | ||
100 | - display = self.fake_command | ||
101 | - else: | ||
102 | - # On windows, CreateProcess requires an absolute path to the executable. | ||
103 | - # When we call spawnProcess below, we pass argv[0] as the executable. | ||
104 | - # So, for .exe's that we have absolute paths to, we can call directly | ||
105 | - # Otherwise, we should run under COMSPEC (usually cmd.exe) to | ||
106 | - # handle path searching, etc. | ||
107 | - if runtime.platformType == 'win32' and not \ | ||
108 | - (self.command[0].lower().endswith(".exe") and os.path.isabs(self.command[0])): | ||
109 | - argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args | ||
110 | - if '/c' not in argv: argv += ['/c'] | ||
111 | - argv += list(self.command) | ||
112 | - else: | ||
113 | - argv = self.command | ||
114 | - # Attempt to format this for use by a shell, although the process isn't perfect | ||
115 | + if type(self.command) in types.StringTypes: | ||
116 | + if runtime.platformType == 'win32': | ||
117 | + if os.environ['BUILDSLAVE_SHELL']: | ||
118 | + argv = os.environ['BUILDSLAVE_SHELL'].split() # allow %COMSPEC% to have args | ||
119 | + argv += [self.command] | ||
120 | + else: | ||
121 | + argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args | ||
122 | + if '/c' not in argv: | ||
123 | + argv += ['/c'] | ||
124 | + argv += [self.command] | ||
125 | + else: | ||
126 | + # for posix, use /bin/sh. for other non-posix, well, doesn't | ||
127 | + # hurt to try | ||
128 | + argv = ['/bin/sh', '-c', self.command] | ||
129 | + display = self.fake_command | ||
130 | + else: | ||
131 | + # On windows, CreateProcess requires an absolute path to the executable. | ||
132 | + # When we call spawnProcess below, we pass argv[0] as the executable. | ||
133 | + # So, for .exe's that we have absolute paths to, we can call directly | ||
134 | + # Otherwise, we should run under COMSPEC (usually cmd.exe) to | ||
135 | + # handle path searching, etc. | ||
136 | + if runtime.platformType == 'win32' and not \ | ||
137 | + (self.command[0].lower().endswith(".exe") and os.path.isabs(self.command[0])): | ||
138 | + if os.environ['BUILDSLAVE_SHELL']: | ||
139 | + argv = os.environ['BUILDSLAVE_SHELL'].split() | ||
140 | + # Create a temporary script file that changes current directory | ||
141 | + # and runs the command we want | ||
142 | + # It will be deleted after command is finished running (see RunProcessPP) | ||
143 | + tf, tf_name = tempfile.mkstemp () | ||
144 | + f = os.fdopen (tf, 'wb') | ||
145 | + fcontents = '#!/bin/sh\ncd {}\n{}'.format ( | ||
146 | + re.sub(r'(?<!\\) ','\\ ', self.workdir.replace('\\','/')), | ||
147 | + ' '.join (self.command)) | ||
148 | + f.write (fcontents) | ||
149 | + log.msg("Script: {}".format (fcontents)) | ||
150 | + f.close () | ||
151 | + self.pp.scriptfile = tf_name | ||
152 | + argv += [tf_name.replace('\\','/')] | ||
153 | + else: | ||
154 | + argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args | ||
155 | + if '/c' not in argv: | ||
156 | + argv += ['/c'] | ||
157 | + argv += list(self.command) | ||
158 | + else: | ||
159 | + argv = self.command | ||
160 | + # Attempt to format this for use by a shell, although the process isn't perfect | ||
161 | display = shell_quote(self.fake_command) | ||
162 | |||
163 | # $PWD usually indicates the current directory; spawnProcess may not | ||
164 | @@ -433,7 +510,7 @@ | ||
165 | self.environ['PWD'] = os.path.abspath(self.workdir) | ||
166 | |||
167 | # self.stdin is handled in RunProcessPP.connectionMade | ||
168 | - | ||
169 | + log.msg("Running {}".format (argv)) | ||
170 | log.msg(" " + display) | ||
171 | self._addToBuffers('header', display+"\n") | ||
172 | |||
173 | @@ -764,9 +841,7 @@ | ||
174 | if self.KILL == None: | ||
175 | log.msg("self.KILL==None, only pretending to kill child") | ||
176 | else: | ||
177 | - log.msg("using TASKKILL /F PID /T to kill pid %s" % self.process.pid) | ||
178 | - subprocess.check_call("TASKKILL /F /PID %s /T" % self.process.pid) | ||
179 | - log.msg("taskkill'd pid %s" % self.process.pid) | ||
180 | + safe_terminate_process_by_pid (self.process.pid, 1) | ||
181 | hit = 1 | ||
182 | |||
183 | # try signalling the process itself (works on Windows too, sorta) | ||