1#!/usr/bin/env python2 2# 3# Copyright (c) 2016 ARM Limited 4# All rights reserved 5# 6# The license below extends only to copyright in the software and shall 7# not be construed as granting a license to any other intellectual 8# property including but not limited to intellectual property relating 9# to a hardware implementation of the functionality of the software 10# licensed hereunder. You may use the software subject to the license 11# terms below provided that you ensure that this notice is replicated 12# unmodified and in its entirety in all distributions of the software, 13# modified or unmodified, in source code or in binary form. 14# 15# Redistribution and use in source and binary forms, with or without 16# modification, are permitted provided that the following conditions are 17# met: redistributions of source code must retain the above copyright 18# notice, this list of conditions and the following disclaimer; 19# redistributions in binary form must reproduce the above copyright 20# notice, this list of conditions and the following disclaimer in the 21# documentation and/or other materials provided with the distribution; 22# neither the name of the copyright holders nor the names of its 23# contributors may be used to endorse or promote products derived from 24# this software without specific prior written permission. 25# 26# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37# 38# Authors: Andreas Sandberg 39
| 1#!/usr/bin/env python2 2# 3# Copyright (c) 2016 ARM Limited 4# All rights reserved 5# 6# The license below extends only to copyright in the software and shall 7# not be construed as granting a license to any other intellectual 8# property including but not limited to intellectual property relating 9# to a hardware implementation of the functionality of the software 10# licensed hereunder. You may use the software subject to the license 11# terms below provided that you ensure that this notice is replicated 12# unmodified and in its entirety in all distributions of the software, 13# modified or unmodified, in source code or in binary form. 14# 15# Redistribution and use in source and binary forms, with or without 16# modification, are permitted provided that the following conditions are 17# met: redistributions of source code must retain the above copyright 18# notice, this list of conditions and the following disclaimer; 19# redistributions in binary form must reproduce the above copyright 20# notice, this list of conditions and the following disclaimer in the 21# documentation and/or other materials provided with the distribution; 22# neither the name of the copyright holders nor the names of its 23# contributors may be used to endorse or promote products derived from 24# this software without specific prior written permission. 25# 26# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37# 38# Authors: Andreas Sandberg 39
|
40import subprocess 41from threading import Timer 42import time 43import re 44 45class CallTimeoutException(Exception): 46 """Exception that indicates that a process call timed out""" 47 48 def __init__(self, status, stdout, stderr): 49 self.status = status 50 self.stdout = stdout 51 self.stderr = stderr 52 53class ProcessHelper(subprocess.Popen): 54 """Helper class to run child processes. 55 56 This class wraps a subprocess.Popen class and adds support for 57 using it in a with block. When the process goes out of scope, it's 58 automatically terminated. 59 60 with ProcessHelper(["/bin/ls"], stdout=subprocess.PIPE) as p: 61 return p.call() 62 """ 63 def __init__(self, *args, **kwargs): 64 super(ProcessHelper, self).__init__(*args, **kwargs) 65 66 def _terminate_nicely(self, timeout=5): 67 def on_timeout(): 68 self.kill() 69 70 if self.returncode is not None: 71 return self.returncode 72 73 timer = Timer(timeout, on_timeout) 74 self.terminate() 75 status = self.wait() 76 timer.cancel() 77 78 return status 79 80 def __enter__(self): 81 return self 82 83 def __exit__(self, exc_type, exc_value, traceback): 84 if self.returncode is None: 85 self._terminate_nicely() 86 87 def call(self, timeout=0): 88 self._timeout = False 89 def on_timeout(): 90 self._timeout = True 91 self._terminate_nicely() 92 93 status, stdout, stderr = None, None, None 94 timer = Timer(timeout, on_timeout) 95 if timeout: 96 timer.start() 97 98 stdout, stderr = self.communicate() 99 status = self.wait() 100 101 timer.cancel() 102 103 if self._timeout: 104 self._terminate_nicely() 105 raise CallTimeoutException(self.returncode, stdout, stderr) 106 else: 107 return status, stdout, stderr 108 109class FileIgnoreList(object): 110 """Helper class to implement file ignore lists. 111 112 This class implements ignore lists using plain string matching and 113 regular expressions. In the simplest use case, rules are created 114 statically upon initialization: 115 116 ignore_list = FileIgnoreList(name=("ignore_me.txt", ), rex=(r".*~", ) 117 118 Ignores can be queried using in the same ways as normal Python 119 containers: 120 121 if file_name in ignore_list: 122 print "Ignoring %s" % file_name 123 124 125 New rules can be added at runtime by extending the list in the 126 rules attribute: 127 128 ignore_list.rules.append(FileIgnoreList.simple("bar.txt")) 129 """ 130 131 @staticmethod 132 def simple(r): 133 return lambda f: f == r 134 135 @staticmethod 136 def rex(r): 137 re_obj = r if hasattr(r, "search") else re.compile(r) 138 return lambda name: re_obj.search(name) 139 140 def __init__(self, names=(), rex=()): 141 self.rules = [ FileIgnoreList.simple(n) for n in names ] + \ 142 [ FileIgnoreList.rex(r) for r in rex ] 143 144 def __contains__(self, name): 145 for rule in self.rules: 146 if rule(name): 147 return True 148 return False 149 150if __name__ == "__main__": 151 # Run internal self tests to ensure that the helpers are working 152 # properly. The expected output when running this script is 153 # "SUCCESS!". 154 155 cmd_foo = [ "/bin/echo", "-n", "foo" ] 156 cmd_sleep = [ "/bin/sleep", "10" ] 157 158 # Test that things don't break if the process hasn't been started 159 with ProcessHelper(cmd_foo) as p: 160 pass 161 162 with ProcessHelper(cmd_foo, stdout=subprocess.PIPE) as p: 163 status, stdout, stderr = p.call() 164 assert stdout == "foo" 165 assert status == 0 166 167 try: 168 with ProcessHelper(cmd_sleep) as p: 169 status, stdout, stderr = p.call(timeout=1) 170 assert False, "Timeout not triggered" 171 except CallTimeoutException: 172 pass 173 174 ignore_list = FileIgnoreList( 175 names=("ignore.txt", "foo/test.txt"), 176 rex=(r"~$", re.compile("^#"))) 177 178 assert "ignore.txt" in ignore_list 179 assert "bar.txt" not in ignore_list 180 assert "foo/test.txt" in ignore_list 181 assert "test.txt" not in ignore_list 182 assert "file1.c~" in ignore_list 183 assert "file1.c" not in ignore_list 184 assert "#foo" in ignore_list 185 assert "foo#" not in ignore_list 186 187 ignore_list.rules.append(FileIgnoreList.simple("bar.txt")) 188 assert "bar.txt" in ignore_list 189
| 42import subprocess 43from threading import Timer 44import time 45import re 46 47class CallTimeoutException(Exception): 48 """Exception that indicates that a process call timed out""" 49 50 def __init__(self, status, stdout, stderr): 51 self.status = status 52 self.stdout = stdout 53 self.stderr = stderr 54 55class ProcessHelper(subprocess.Popen): 56 """Helper class to run child processes. 57 58 This class wraps a subprocess.Popen class and adds support for 59 using it in a with block. When the process goes out of scope, it's 60 automatically terminated. 61 62 with ProcessHelper(["/bin/ls"], stdout=subprocess.PIPE) as p: 63 return p.call() 64 """ 65 def __init__(self, *args, **kwargs): 66 super(ProcessHelper, self).__init__(*args, **kwargs) 67 68 def _terminate_nicely(self, timeout=5): 69 def on_timeout(): 70 self.kill() 71 72 if self.returncode is not None: 73 return self.returncode 74 75 timer = Timer(timeout, on_timeout) 76 self.terminate() 77 status = self.wait() 78 timer.cancel() 79 80 return status 81 82 def __enter__(self): 83 return self 84 85 def __exit__(self, exc_type, exc_value, traceback): 86 if self.returncode is None: 87 self._terminate_nicely() 88 89 def call(self, timeout=0): 90 self._timeout = False 91 def on_timeout(): 92 self._timeout = True 93 self._terminate_nicely() 94 95 status, stdout, stderr = None, None, None 96 timer = Timer(timeout, on_timeout) 97 if timeout: 98 timer.start() 99 100 stdout, stderr = self.communicate() 101 status = self.wait() 102 103 timer.cancel() 104 105 if self._timeout: 106 self._terminate_nicely() 107 raise CallTimeoutException(self.returncode, stdout, stderr) 108 else: 109 return status, stdout, stderr 110 111class FileIgnoreList(object): 112 """Helper class to implement file ignore lists. 113 114 This class implements ignore lists using plain string matching and 115 regular expressions. In the simplest use case, rules are created 116 statically upon initialization: 117 118 ignore_list = FileIgnoreList(name=("ignore_me.txt", ), rex=(r".*~", ) 119 120 Ignores can be queried using in the same ways as normal Python 121 containers: 122 123 if file_name in ignore_list: 124 print "Ignoring %s" % file_name 125 126 127 New rules can be added at runtime by extending the list in the 128 rules attribute: 129 130 ignore_list.rules.append(FileIgnoreList.simple("bar.txt")) 131 """ 132 133 @staticmethod 134 def simple(r): 135 return lambda f: f == r 136 137 @staticmethod 138 def rex(r): 139 re_obj = r if hasattr(r, "search") else re.compile(r) 140 return lambda name: re_obj.search(name) 141 142 def __init__(self, names=(), rex=()): 143 self.rules = [ FileIgnoreList.simple(n) for n in names ] + \ 144 [ FileIgnoreList.rex(r) for r in rex ] 145 146 def __contains__(self, name): 147 for rule in self.rules: 148 if rule(name): 149 return True 150 return False 151 152if __name__ == "__main__": 153 # Run internal self tests to ensure that the helpers are working 154 # properly. The expected output when running this script is 155 # "SUCCESS!". 156 157 cmd_foo = [ "/bin/echo", "-n", "foo" ] 158 cmd_sleep = [ "/bin/sleep", "10" ] 159 160 # Test that things don't break if the process hasn't been started 161 with ProcessHelper(cmd_foo) as p: 162 pass 163 164 with ProcessHelper(cmd_foo, stdout=subprocess.PIPE) as p: 165 status, stdout, stderr = p.call() 166 assert stdout == "foo" 167 assert status == 0 168 169 try: 170 with ProcessHelper(cmd_sleep) as p: 171 status, stdout, stderr = p.call(timeout=1) 172 assert False, "Timeout not triggered" 173 except CallTimeoutException: 174 pass 175 176 ignore_list = FileIgnoreList( 177 names=("ignore.txt", "foo/test.txt"), 178 rex=(r"~$", re.compile("^#"))) 179 180 assert "ignore.txt" in ignore_list 181 assert "bar.txt" not in ignore_list 182 assert "foo/test.txt" in ignore_list 183 assert "test.txt" not in ignore_list 184 assert "file1.c~" in ignore_list 185 assert "file1.c" not in ignore_list 186 assert "#foo" in ignore_list 187 assert "foo#" not in ignore_list 188 189 ignore_list.rules.append(FileIgnoreList.simple("bar.txt")) 190 assert "bar.txt" in ignore_list 191
|