unwanted commit
[oweals/gnunet.git] / contrib / buildslave-0.8.6p1-gnunet-w32.patch
1 diff -urN /src/buildbot-slave-0.8.6p1.orig/buildslave/runprocess.py /src/buildbot-slave-0.8.6p1/buildslave/runprocess.py
2 --- buildbot-slave-0.8.6p1.orig/buildslave/runprocess.py        2012-03-26 04:09:10 +0400
3 +++ buildbot-slave-0.8.6p1/buildslave/runprocess.py     2013-03-31 05:18:55 +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,89 @@
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 +    import win32event
20 +    import pywintypes
21 +
22 +def safe_terminate_process (proc, code):
23 +    if os.name == 'nt':
24 +        log.msg ("Obtaining current process handle")
25 +        cp = win32api.GetCurrentProcess ()
26 +        result = False
27 +        log.msg ("Expanding target process handle permissions")
28 +        dupproc = win32api.DuplicateHandle (cp, proc._handle, cp, 2 | 1024 | 8 | 32 | 16 | 0x100000, 0, 0)
29 +        log.msg ("Expanded.")
30 +        try:
31 +            log.msg ("Checking exit code of target process")
32 +            exitcode = win32process.GetExitCodeProcess (dupproc)
33 +            log.msg ("Exit code is %d" % exitcode)
34 +            if exitcode == 0x103:
35 +                log.msg ("Opening kernel32.dll")
36 +                kernel32 = win32api.GetModuleHandle ("kernel32")
37 +                log.msg ("Getting ExitProcess() address")
38 +                exitprocess = win32api.GetProcAddress (kernel32, "ExitProcess")
39 +                try:
40 +                    log.msg ("Creating remote thread")
41 +                    th = 0
42 +                    tid = 0
43 +                    failed = False
44 +                    th, tid = win32process.CreateRemoteThread (dupproc, None, 0, exitprocess, code, 0)
45 +                    log.msg ("Created remote thread %d" % tid)
46 +                except pywintypes.error as e:
47 +                    if e[0] == 5:
48 +                      log.msg ("Access denied. It still might die, so don't fail yet")
49 +                      pass
50 +                    else:
51 +                      log.msg("exception %s - %s" % (sys.exc_info()[0], sys.exc_info()[1]))
52 +                      failed = True
53 +                except Exception as e:
54 +                    log.msg("exception %s - %s" % (sys.exc_info()[0], sys.exc_info()[1]))
55 +                    failed = True
56 +                if not failed:
57 +                    log.msg ("Wait for 5 seconds or until it dies (usually takes around 1 microsecond)")
58 +                    waitresult = win32event.WaitForSingleObject (dupproc, 5)
59 +                    log.msg ("Result of waiting: %d" % waitresult)
60 +                    win32api.CloseHandle (th)
61 +                    if waitresult == 0:
62 +                        result = True
63 +            else:
64 +                result = True
65 +        except:
66 +            log.msg("exception %s - %s" % (sys.exc_info()[0], sys.exc_info()[1]))
67 +        finally:
68 +            win32api.CloseHandle (dupproc)
69 +        return result
70 +    else:
71 +        return proc.kill ()
72 +
73 +class Dummy(object):
74 +    def SetHandle (self, h):
75 +        self._handle = h
76 +
77 +def safe_terminate_process_by_pid (proc, code):
78 +    if os.name == 'nt':
79 +        try:
80 +            log.msg("Opening process %d" % proc)
81 +            openproc = win32api.OpenProcess (2 | 1024 | 8 | 32 | 16 | 0x100000, 0, proc)
82 +            log.msg("Opened process %d" % proc)
83 +            try:
84 +                d = Dummy ()
85 +                d.SetHandle (openproc)
86 +                log.msg("Terminating it safely")
87 +                safe_terminate_process (d, code)
88 +                log.msg("Finished terminating")
89 +            finally:
90 +                log.msg("Closing process handle")
91 +                win32api.CloseHandle (openproc)
92 +        except:
93 +            log.msg("exception %s - %s" % (sys.exc_info()[0], sys.exc_info()[1]))
94 +            pass
95 +    else:
96 +        return os.kill (proc, code)
97 +
98 +       
99  def shell_quote(cmd_list):
100      # attempt to quote cmd_list such that a shell will properly re-interpret
101      # it.  The pipes module is only available on UNIX, and Windows "shell"
102 @@ -148,6 +232,7 @@
103          self.pending_stdin = ""
104          self.stdin_finished = False
105          self.killed = False
106 +        self.scriptfile = ""
107  
108      def setStdin(self, data):
109          assert not self.connected
110 @@ -198,6 +283,11 @@
111                  rc = 1
112              else:
113                  rc = -1
114 +        if self.scriptfile:
115 +            try:
116 +                os.remove (self.scriptfile) 
117 +            except:
118 +                pass
119          self.command.finished(sig, rc)
120  
121  
122 @@ -408,9 +498,14 @@
123  
124          if type(self.command) in types.StringTypes:
125              if runtime.platformType  == 'win32':
126 -                argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args
127 -                if '/c' not in argv: argv += ['/c']
128 -                argv += [self.command]
129 +                if os.environ['BUILDSLAVE_SHELL']:
130 +                    argv = os.environ['BUILDSLAVE_SHELL'].split() # allow %COMSPEC% to have args
131 +                    argv += [self.command]
132 +                else:
133 +                    argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args
134 +                    if '/c' not in argv:
135 +                        argv += ['/c']
136 +                    argv += [self.command]
137              else:
138                  # for posix, use /bin/sh. for other non-posix, well, doesn't
139                  # hurt to try
140 @@ -424,9 +519,26 @@
141              # handle path searching, etc.
142              if runtime.platformType == 'win32' and not \
143                      (self.command[0].lower().endswith(".exe") and os.path.isabs(self.command[0])):
144 -                argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args
145 -                if '/c' not in argv: argv += ['/c']
146 -                argv += list(self.command)
147 +                if os.environ['BUILDSLAVE_SHELL']:
148 +                    argv = os.environ['BUILDSLAVE_SHELL'].split()
149 +                    # Create a temporary script file that changes current directory
150 +                    # and runs the command we want
151 +                    # It will be deleted after command is finished running (see RunProcessPP)
152 +                    tf, tf_name = tempfile.mkstemp ()
153 +                    f = os.fdopen (tf, 'wb')
154 +                    fcontents = '#!/bin/sh\ncd {}\n{}'.format (
155 +                        re.sub(r'(?<!\\) ','\\ ', self.workdir.replace('\\','/')),
156 +                        ' '.join (self.command))
157 +                    f.write (fcontents)
158 +                    log.msg("Script: {}".format (fcontents))
159 +                    f.close ()
160 +                    self.pp.scriptfile = tf_name
161 +                    argv += [tf_name.replace('\\','/')]
162 +                else:
163 +                    argv = os.environ['COMSPEC'].split() # allow %COMSPEC% to have args
164 +                    if '/c' not in argv:
165 +                      argv += ['/c']
166 +                    argv += list(self.command)
167              else:
168                  argv = self.command
169              # Attempt to format this for use by a shell, although the process isn't perfect
170 @@ -439,7 +551,7 @@
171              self.environ['PWD'] = os.path.abspath(self.workdir)
172  
173          # self.stdin is handled in RunProcessPP.connectionMade
174 -
175 +        log.msg("Running {}".format (argv))
176          log.msg(" " + display)
177          self._addToBuffers('header', display+"\n")
178  
179 @@ -770,9 +882,7 @@
180              if self.interruptSignal == None:
181                  log.msg("self.interruptSignal==None, only pretending to kill child")
182              else:
183 -                log.msg("using TASKKILL /F PID /T to kill pid %s" % self.process.pid)
184 -                subprocess.check_call("TASKKILL /F /PID %s /T" % self.process.pid)
185 -                log.msg("taskkill'd pid %s" % self.process.pid)
186 +                safe_terminate_process_by_pid (self.process.pid, 1)
187                  hit = 1
188  
189          # try signalling the process itself (works on Windows too, sorta)
190 @@ -795,10 +905,11 @@
191          if not hit:
192              log.msg("signalProcess/os.kill failed both times")
193  
194 -        if runtime.platformType == "posix":
195 +        if runtime.platformType == "posix" or runtime.platformType == "win32":
196              # we only do this under posix because the win32eventreactor
197              # blocks here until the process has terminated, while closing
198              # stderr. This is weird.
199 +            # LRN: Turns out, things don't work without this on W32. At all.
200              self.pp.transport.loseConnection()
201  
202          if self.deferred: