1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """Basic useful utilities: file copying, removal, permissions,
22 path-name manipulation, and command execution."""
23
24 import os
25 import re
26 import glob
27 import sys
28 import shutil
29 import stat
30 import types
31 import time
32 import subprocess
33 import tempfile
34 import shlex
35 import mbuild
36 import traceback
37 try:
38 import cPickle as apickle
39 except:
40 import pickle as apickle
41
42 from base import *
43
45 """return path to NON cygwin"""
46 pycmd = sys.executable
47 if env.on_windows() and env.on_cygwin():
48
49 if pycmd in ['/usr/bin/python', '/bin/python']:
50 python_commands = [ 'c:/python27/python.exe',
51 'c:/python26/python.exe',
52 'c:/python25/python.exe' ]
53 pycmd = None
54 for p in python_commands:
55 if os.path.exists(p):
56 return p
57 if not pycmd:
58 mbuild.die("Could not find win32 python at these locations: %s" %
59 "\n\t" + "\n\t".join(python_commands))
60
61 return pycmd
63 """Copy src to tgt."""
64 if verbose(1):
65 msgb("COPY", tgt + " <- " + src)
66 shutil.copy(src,tgt)
68 """Move/Rename src to tgt."""
69 if verbose(1):
70 msgb("MOVE", src + " -> " + tgt)
71 shutil.move(src,tgt)
73 """Make a symlink from src to target. Not available on windows."""
74 if env.on_windows():
75 die("symlink() not available on windows")
76 if verbose(1):
77 msgb("SYMLINK", src + " -> " + tgt)
78 os.symlink(src,tgt)
79
80 -def copy_tree(src,tgt, ignore_patterns=None, symlinks=False):
81 """Copy the tree at src to tgt. This will first remove tgt if it
82 already exists."""
83 if verbose(1):
84 msgb("COPYTREE", tgt + " <- " + src)
85 if not os.path.exists(src):
86 error_msg("SRC TREE DOES NOT EXIST", src)
87 raise Exception
88 if os.path.exists(tgt):
89 if verbose(1):
90 msgb("Removing existing target tree", tgt)
91 shutil.rmtree(tgt, ignore_errors=True)
92 if verbose(1):
93 msgb("Copying to tree", tgt)
94 if ignore_patterns:
95 sp = shutil.ignore_patterns(ignore_patterns)
96 else:
97 sp = None
98 shutil.copytree(src,tgt,ignore=sp, symlinks=symlinks)
99 if verbose(1):
100 msgb("Done copying tree", tgt)
101
103 """Make a directory if it does not exist"""
104 if not os.path.exists(path_to_dir):
105 if verbose(1):
106 msgb("MKDIR", path_to_dir)
107 os.makedirs(path_to_dir)
109 """Print a list as a string"""
110 s = " ".join(ls)
111 return s
112
114 """Remove a file or link if it exists. env parameter is not used."""
115 if os.path.exists(fn):
116 make_writable(fn)
117 if os.path.exists(fn) or os.path.lexists(fn):
118 if not quiet:
119 if verbose(1):
120 msgb("REMOVING", fn)
121 os.unlink(fn)
122 return (0, [])
124 """Remove a directory if it exists. env parameter is not
125 used. This will not remove a directory that has a .svn
126 subdirectory indicating it is a source directory. Warning: It does
127 not look recursively for .svn subdirectories.
128 @type dir_name: string
129 @param dir_name: a directory name
130 @type env: L{env_t}
131 @param env: optional. Not currently used.
132 @type dangerous: bool
133 @param dangerous: optional. If True,will delete anything including svn trees!! BE CAREFUL! default False.
134 """
135 if verbose(1):
136 msgb("CHECKING", dir_name)
137 if os.path.exists(dir_name):
138 if not dangerous and os.path.exists(os.path.join(dir_name, ".svn")):
139 s = 'Did not remove directory %s because of a .svn subdirectory' % \
140 dir_name
141 warn(s)
142 return (1, [ s ])
143 if verbose(1):
144 msgb("REMOVING", dir_name)
145 make_writable(dir_name)
146 shutil.rmtree(dir_name, ignore_errors = True)
147 return (0, [])
149 """Remove all the files in the list of files, lst. The env
150 parameter is not used"""
151 for fn in lst:
152 remove_file(fn)
153 return (0, [])
154
156 """Remove all files in the list of wild card expressions. The env
157 parameter is not used"""
158 for fn_glob in lst:
159
160 for file_name in glob(fn_glob):
161 remove_file(file_name)
162 return (0, [])
163
165 """Remove files that match the re object compiled pattern provided"""
166 for (dir, subdirs, subfiles) in os.walk(dir):
167 for file_name in subfiles:
168 fn = os.path.join(dir,file_name)
169 if file_patterns.search(fn):
170 remove_file(fn)
171
172
173 _readable_by_all = stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH
174 _readable_by_ug = stat.S_IRUSR|stat.S_IRGRP
175 _executable_by_all = stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH
176 _executable_by_ug = stat.S_IXUSR|stat.S_IXGRP
177 _writeable_by_me = stat.S_IWUSR
178 _rwx_by_me = stat.S_IWUSR| stat.S_IRUSR|stat.S_IXUSR
179 _writeable_by_ug = stat.S_IWUSR|stat.S_IWGRP
180
182 """Make the file or directory readable/writable/executable by me"""
183 global _rwx_by_me
184 os.chmod(fn, _rwx_by_me)
185
192
194 """Walk the tree rooted at path and apply the function dir_fn to
195 directories and file_fn to files. This is intended for doing
196 recursive chmods, etc."""
197 if dir_fn:
198 dir_fn(path)
199 for (dir, subdirs, subfiles) in os.walk(path):
200 if dir_fn:
201 for subdir in subdirs:
202 dir_fn(os.path.join(dir,subdir))
203 if file_fn:
204 for file_name in subfiles:
205 file_fn(os.path.join(dir,file_name))
206
207
212
229
236
237
238
240 """Add dir on to the front of the input file or files. Works with
241 strings or lists of strings.
242 @type dir: string
243 @param dir: prefix directory
244
245 @type input_files: string or list of strings
246 @param input_files: name(s) of files
247
248 @rtype: string or list of strings
249 @return: input file(s) prefixed with dir sp
250 """
251 if isinstance(input_files,types.ListType):
252 new_files = map(lambda(x): join(dir, x), input_files)
253 return new_files
254 elif isinstance(input_files,types.StringType):
255 new_file = join(dir, input_files)
256 return new_file
257 die("Unhandled type in prefix_files: "+ str(type(input_files)))
258
260 """Add quotes around the file nameed fn. Return a string"""
261 return "\"%s\"" % fn
262
264 """Add quotes to a string if there are spaces in the name"""
265 if re.search(' ',fn):
266 return '"%s"' % fn
267 return fn
268
269
271 """Open a file for append. Write nothing to it"""
272 if verbose():
273 msgb("TOUCH", fn)
274 f=open(fn,"a")
275 f.close()
276
277
278 if on_native_windows():
279 _mysep = "\\"
280 else:
281 _mysep = "/"
282
284 """join all the args supplied as arguments using _mysep as the
285 separator. _mysep is a backslash on native windows and a forward
286 slash everywhere else.
287 @type args: strings
288 @param args: path component strings
289
290 @rtype: string
291 @return: string with _mysep slashes
292 """
293 s = ''
294 first = True
295 for a in args:
296 if first:
297 first = False
298 else:
299 s = s + _mysep
300 s = s + a
301 return s
302
304 """Conditionally remove leading/trailing quotes from a string
305 @type a: string
306 @param a: a string potentially with quotes
307
308 @rtype: string
309 @return: same string without the leading and trailing quotes
310 """
311 ln = len(a)
312 if ln >= 2:
313 strip_quotes = False
314 if a[0] == '"' and a[-1] == '"':
315 strip_quotes=True
316 elif a[0] == "'" and a[-1] == "'":
317 strip_quotes=True
318 if strip_quotes:
319 b = a[1:ln-1]
320 return b
321 return a
322
324 """join all the args supplied as arguments using a forward slash as
325 the separator
326
327 @type args: strings
328 @param args: path component strings
329
330 @rtype: string
331 @return: string with forward-slashes
332 """
333 s = ''
334 first = True
335 for a in args:
336 ln = len(s)
337 if first:
338 first = False
339 elif ln == 0 or s[-1] != '/':
340
341 s = s + '/'
342 a = strip_quotes(a)
343 s = s + a
344 return s
345
346
348 """convert to backslashes to _mysep slashes. _mysep slashes are
349 defined to be backslashes on native windows and forward slashes
350 everywhere else.
351 @type s: string or list of strings
352 @param s: path name(s)
353
354 @rtype: string or list of strings
355 @return: string(s) with _mysep slashes
356 """
357
358 if on_native_windows():
359 return s
360 if type(s) == types.ListType:
361 return map(flip_slashes, s)
362 t = re.sub(r'\\',_mysep,s,0)
363 return t
364
366 """convert to posix slashes. Do not flip slashes immediately before spaces
367 @type s: string or list of strings
368 @param s: path name(s)
369
370 @rtype: string or list of strings
371 @return: string(s) with forward slashes
372 """
373 if type(s) == types.ListType:
374 return map(posix_slashes, s)
375
376 last = len(s)-1
377 t=[]
378 for i,a in enumerate(s):
379 x=a
380 if a == '\\':
381 if i == last:
382 x = '/'
383 elif s[i+1] != ' ':
384 x = '/'
385 t.append(x)
386 return ''.join(t)
387
389 """Run the normal glob.glob() on s but make sure all the slashes
390 are flipped forward afterwards. This is shorthand for
391 mbuild.posix_slashes(glob.glob(s))"""
392 import glob
393 return posix_slashes(glob.glob(s))
394
396 """If there are spaces in the input string s, put quotes around the
397 string and return it... if there are not already quotes in the
398 string.
399
400 @type s: string
401 @param s: path name
402
403 @rtype: string
404 @return: string with quotes, if necessary
405 """
406 if re.search(r'[ ]',s) and not ( re.search(r'["].*["]',s) or
407 re.search(r"['].*[']",s) ):
408 return '\"' + s + '\"'
409 return s
410
411
413 """Add a backslash before characters that have special meanings in
414 regular expressions. Python does not handle backslashes in regular
415 expressions or substitution text so they must be escaped before
416 processing."""
417
418 special_chars = r'\\'
419 new_string = ''
420 for c in s:
421 if c in special_chars:
422 new_string += '\\'
423 new_string += c
424 return new_string
425
426
427
428 if check_python_version(2,5):
429 import hashlib
430 else:
431 import sha
432
434 """Compute a sha1 hash of a list of strings and return the hex digest"""
435 if check_python_version(2,5):
436 m = hashlib.sha1()
437 else:
438 m = sha.new()
439 map(lambda (x): m.update(x), list_of_strings)
440 d = m.hexdigest()
441 return d
442
443
445 if os.path.exists(fn):
446 try:
447 lines = file(fn).readlines()
448 except:
449 die("COULD NOT READ: %s" % (fn))
450 signature = hash_list(lines)
451 return signature
452 return None
453
454
456 """Write a dictionary of d[file]=hash to the specified file"""
457
458 f = open(fn,"wb")
459 apickle.dump(d,f)
460 f.close()
461
463 """Return a dictionary of d[file]=hash from the specified file"""
464 try:
465 f = open(fn,"r")
466 d = apickle.load(f)
467 f.close()
468 return d
469 except:
470 return None
471
472
474 """Compute a sha1 hash of a string and return the hex digest"""
475 if check_python_version(2,5):
476 m = hashlib.sha1()
477 else:
478 m = sha.new()
479 m.update(s)
480 d = m.hexdigest()
481 return d
482
483
485 """Hash the files in the list of files and write the hashes to fn"""
486 d = {}
487 for f in list_of_files:
488 d[f] = hash_file(f)
489 write_signatures(fn,d)
490
492 """Return true iff the old hashes in the file fn are valid for all
493 of the specified list of files."""
494 if not os.path.exists(fn):
495 return False
496 d = read_signatures(fn)
497 if d == None:
498 return False
499 for f in list_of_files:
500 if os.path.exists(f):
501 nhash = hash_file(f)
502 else:
503 return False
504 if nhash == None:
505 return False
506 if f not in d:
507 return False
508 elif d[f] != nhash:
509 return False;
510 return True
511
512
513
515 """@rtype: string
516 @returns: current time as string
517 """
518
519 return time.strftime('%Y-%m-%d %H:%M:%S %Z')
520
522 """@rtype: float
523 @returns: current time as float
524 """
525 return time.time()
526
528 """compute the elapsed time in seconds or minutes
529 @type start_time: float
530 @param start_time: starting time.
531 @type end_time: float
532 @param end_time: ending time.
533 @rtype: string
534 """
535 if end_time == None:
536 end_time = get_time()
537 seconds = end_time - start_time
538 negative_prefix = ''
539 if seconds < 0:
540 negative_prefix = '-'
541 seconds = -seconds
542 if seconds < 120:
543 if int(seconds) == 0:
544 milli_seconds = seconds * 1000
545 timestr = "%d" % int(milli_seconds)
546 suffix = " msecs"
547 else:
548 timestr = "%d" % int(seconds)
549 suffix = " secs"
550 else:
551 minutes = int(seconds/60.0)
552 remainder_seconds = int(seconds - (minutes*60))
553 timestr = "%.d:%02d" % (minutes,remainder_seconds)
554 suffix = " min:sec"
555 return "".join([negative_prefix, timestr, suffix])
556
558 """print the elapsed time in seconds or minutes.
559
560 @type start_time: float
561 @param start_time: the starting time
562 @type end_time: float
563 @param end_time: the ending time (optional)
564 @type prefix: string
565 @param prefix: a string to print at the start of the line (optional)
566 """
567 if end_time == None:
568 end_time = get_time()
569 ets = "ELAPSED TIME"
570 if prefix:
571 s = "%s %s" % (prefix, ets)
572 else:
573 s = ets
574
575 t = get_elapsed_time(start_time, end_time)
576 if current:
577 t = t + " / NOW: " + get_time_str()
578 msgb(s,t)
579
580
581
583 """Tokenize the cmd string input. Return as list on non-windows
584 platforms. On windows, it returns the raw command string."""
585
586 if on_native_windows():
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601 args = cmd
602
603 else:
604 args = shlex.split(cmd)
605 return args
606
616
617 -def run_command(cmd,
618 separate_stderr=False,
619 shell_executable=None,
620 directory=None,
621 osenv=None,
622 input_file_name=None,
623 **kwargs):
624 """
625 Run a command string using the subprocess module.
626
627 @type cmd: string
628 @param cmd: command line to execut with all args.
629 @type separate_stderr: bool
630 @param separate_stderr: If True, the return tuple has a list of stderr lines as the 3rd element
631 @type shell_executable: string
632 @param shell_executable: the shell executable
633 @type directory: string
634 @param directory: a directory to change to before running the command.
635 @type osenv: dictionary
636 @param osenv: dict of environment vars to be passed to the new process
637 @type input_file_name: string
638 @param input_file_name: file name to read stdin from. Default none
639
640 @rtype: tuple
641 @return: (return code, list of stdout lines, list of lines of stderr)
642 """
643 use_shell = False
644 if verbose(99):
645 msgb("RUN COMMAND", cmd)
646 msgb("RUN COMMAND repr", repr(cmd))
647 stdout = None
648 stderr = None
649 cmd_args = _prepare_cmd(cmd)
650 try:
651 input_file_obj = _cond_open_input_file(directory, input_file_name)
652
653 if separate_stderr:
654 sub = subprocess.Popen(cmd_args,
655 shell=use_shell,
656 executable=shell_executable,
657 stdin = input_file_obj,
658 stdout = subprocess.PIPE,
659 stderr = subprocess.PIPE,
660 cwd=directory,
661 env=osenv,
662 **kwargs)
663 (stdout, stderr ) = sub.communicate()
664 if not isinstance(stderr,types.ListType):
665 stderr = [stderr]
666 if not isinstance(stdout,types.ListType):
667 stdout = [stdout]
668 return (sub.returncode, stdout, stderr)
669 else:
670 sub = subprocess.Popen(cmd_args,
671 shell=use_shell,
672 executable=shell_executable,
673 stdin = input_file_obj,
674 stdout = subprocess.PIPE,
675 stderr = subprocess.STDOUT,
676 cwd=directory,
677 env=osenv,
678 **kwargs)
679 stdout = sub.stdout.readlines()
680 sub.wait()
681 if not isinstance(stdout,types.ListType):
682 stdout = [stdout]
683 return (sub.returncode, stdout, None)
684 except OSError, e:
685 s= ["Execution failed for: %s\n" % (cmd) ]
686 s.append("Result is %s\n" % (str(e)))
687
688
689 if separate_stderr:
690 if stderr == None:
691 stderr = []
692 elif not isinstance(stderr,types.ListType):
693 stderr = [stderr]
694 if stdout == None:
695 stdout = []
696 elif not isinstance(stdout,types.ListType):
697 stdout = [stdout]
698 if separate_stderr:
699 stderr.extend(s)
700 else:
701 stdout.extend(s)
702 return (1, stdout, stderr)
703
704
705 -def run_command_unbufferred(cmd,
706 prefix_line=None,
707 shell_executable=None,
708 directory=None,
709 osenv=None,
710 input_file_name=None,
711 **kwargs):
712 """
713 Run a command string using the subprocess module.
714
715 @type cmd: string
716 @param cmd: command line to execut with all args.
717 @type prefix_line: string
718 @param prefix_line: a string to prefix each output line. Default None
719 @type shell_executable: string
720 @param shell_executable: NOT USED BY THIS FUNCTION
721 @type directory: string
722 @param directory: a directory to change to before running the command.
723 @type osenv: dictionary
724 @param osenv: dict of environment vars to be passed to the new process
725 @type input_file_name: string
726 @param input_file_name: file name to read stdin from. Default none
727
728 @rtype: tuple
729 @return: (return code, list of stdout lines, empty list)
730
731 """
732 use_shell = False
733 if verbose(99):
734 msgb("RUN COMMAND", cmd)
735 msgb("RUN COMMAND repr", repr(cmd))
736 lines = []
737 cmd_args = _prepare_cmd(cmd)
738 try:
739 input_file_obj = _cond_open_input_file(directory, input_file_name)
740 sub = subprocess.Popen(cmd_args,
741 shell=use_shell,
742 executable=shell_executable,
743 stdin = input_file_obj,
744 stdout = subprocess.PIPE,
745 stderr = subprocess.STDOUT,
746 env=osenv,
747 cwd=directory,
748 **kwargs)
749 while 1:
750
751 line = sub.stdout.readline()
752 if line == '':
753 break
754 line = line.rstrip()
755 if prefix_line:
756 msgn(prefix_line)
757 msg(line)
758 lines.append(line + "\n")
759
760 sub.wait()
761 return (sub.returncode, lines, [])
762 except OSError, e:
763 lines.append("Execution failed for: %s\n" % (cmd))
764 lines.append("Result is %s\n" % (str(e)))
765 return (1, lines,[])
766
767
768 -def run_command_output_file(cmd,
769 output_file_name,
770 shell_executable=None,
771 directory=None,
772 osenv=None,
773 input_file_name=None,
774 **kwargs):
775 """
776 Run a command string using the subprocess module.
777
778 @type cmd: string
779 @param cmd: command line to execut with all args.
780 @type output_file_name: string
781 @param output_file_name: output file name
782 @type shell_executable: string
783 @param shell_executable: the shell executable
784 @type directory: string
785 @param directory: a directory to change to before running the command.
786 @type osenv: dictionary
787 @param osenv: dict of environment vars to be passed to the new process
788 @type input_file_name: string
789 @param input_file_name: file name to read stdin from. Default none
790
791 @rtype: tuple
792 @return: (return code, list of stdout lines)
793 """
794 use_shell = False
795 if verbose(99):
796 msgb("RUN COMMAND", cmd)
797 lines = []
798 cmd_args = _prepare_cmd(cmd)
799 try:
800 output = file(output_file_name,"w")
801 input_file_obj = _cond_open_input_file(directory, input_file_name)
802 sub = subprocess.Popen(cmd_args,
803 shell=use_shell,
804 executable=shell_executable,
805 stdin = input_file_obj,
806 stdout = subprocess.PIPE,
807 stderr = subprocess.STDOUT,
808 env=osenv,
809 cwd=directory,
810 **kwargs)
811
812 while 1:
813
814 line = sub.stdout.readline()
815 if line == '':
816 break
817 line = line.rstrip()
818 output.write(line + "\n")
819 lines.append(line + "\n")
820
821 output.close()
822 sub.wait()
823 return (sub.returncode, lines, [])
824 except OSError, e:
825 lines.append("Execution failed for: %s\n" % (cmd))
826 lines.append("Result is %s\n" % (str(e)))
827 return (1, lines,[])
828
829 -def run_cmd_io(cmd, fn_i, fn_o,shell_executable=None, directory=None):
830 """
831 Run a command string using the subprocess module. Read standard
832 input from fn_i and write stdout/stderr to fn_o.
833
834 @type cmd: string
835 @param cmd: command line to execut with all args.
836 @type fn_i: string
837 @param fn_i: input file name
838 @type fn_o: string
839 @param fn_o: output file name
840 @type shell_executable: string
841 @param shell_executable: the shell executable
842 @type directory: string
843 @param directory: a directory to change to before running the command.
844
845 @rtype: integer
846 @return: return code
847 """
848 use_shell = False
849 cmd_args = _prepare_cmd(cmd)
850 try:
851 fin = open(fn_i,'r')
852 fout = open(fn_o,'w')
853 sub = subprocess.Popen(cmd_args,
854 shell=use_shell,
855 executable=shell_executable,
856 stdin=fin,
857 stdout=fout,
858 stderr=subprocess.STDOUT,
859 cwd=directory)
860 retval = sub.wait()
861 fin.close()
862 fout.close()
863 return retval
864 except OSError, e:
865 die("Execution failed for cmd %s\nResult is %s\n" % (cmd,str(e)))
866
868 """Look upwards for a particular filesystem directory d as a
869 subdirectory of one of the ancestors. Return None on failure"""
870 dir = os.getcwd()
871 last = ''
872 while dir != last:
873 target_dir = os.path.join(dir,d)
874
875 if os.path.exists(target_dir):
876 return target_dir
877 last = dir
878 (dir,tail) = os.path.split(dir)
879 return None
880
882 """Remove n trailing path components from s by calling
883 os.path.dirname()"""
884 t = s
885 for i in range(0,n):
886 t = os.path.dirname(t)
887 return t
888
890 """Return the compressed version number of gcc"""
891 cmd = gcc + " -dumpversion"
892 try:
893 (retcode, stdout, stderr) = run_command(cmd)
894 if retcode == 0:
895 version = stdout[0]
896 return version.strip()
897 except:
898 return 'unknown'
899
901 cmd = full_path + " -dM -E - "
902 try:
903 (retcode, stdout, stderr) = run_command(cmd,
904 input_file_name="/dev/null")
905 if retcode == 0:
906 major=minor=patchlevel='x'
907 for line in stdout:
908 line = line.strip()
909 chunks = line.split()
910 if len(chunks) == 3:
911 if chunks[1] == '__clang_major__':
912 major = chunks[2]
913 elif chunks[1] == '__clang_minor__':
914 minor = chunks[2]
915 elif chunks[1] == '__clang_patchlevel__':
916 patchlevel = chunks[2]
917 version = "{}.{}.{}".format(major,minor,patchlevel)
918 return version
919 except:
920 return 'unknown'
921
922
925
928
930 """Return True if the specified gcc version string (gstr) is at or
931 after the specified major,minor,revision args"""
932
933 n = gstr.split('.')
934 if len(n) not in [2,3]:
935 die("Cannot compute gcc version from input string: [%s]" % (gstr))
936 ga = int(n[0])
937 gb = int(n[1])
938 if len(n) == 2:
939 gc = 0
940 else:
941 gc = int(n[2])
942
943 if ga > major:
944 return True
945 if ga == major and gb > minor:
946 return True
947 if ga == major and gb == minor and gc >= rev:
948 return True
949 return False
950
951 import threading
952
954 """
955 Internal function to mbuild util.py. Do not call directly.
956
957 Examples of use
958 env = os.environ
959 env['FOOBAR'] = 'hi'
960 # the command a.out prints out the getenv("FOOBAR") value
961 rc = _timed_command_t(["./a.out", "5"], seconds=4, env=env)
962 rc.timed_run()
963
964 rc = _timed_command_t(["/bin/sleep", "5"], seconds=4)
965 rc.timed_run()
966 """
967
968 - def __init__(self, cmd,
969 shell_executable=None,
970 directory=None,
971 osenv=None,
972 seconds=0,
973 input_file_name=None,
974 **kwargs):
975 """The kwargs are for the other parameters to Popen"""
976 threading.Thread.__init__(self)
977 self.cmd = cmd
978 self.kwargs = kwargs
979 self.seconds = seconds
980 self.timed_out = False
981 self.sub = None
982 self.osenv= osenv
983 self.input_file_name = input_file_name
984 self.directory = directory
985 self.shell_executable = shell_executable
986 self.exception_type = None
987 self.exception_object = None
988 self.exception_trace = None
989 self.exitcode = 0,
990 self.output = "",
991 self.stderr = "",
992
994 cmd = self.cmd
995
996 if _is_python_cmd(cmd):
997 kwargs = self.kwargs
998 xenv = kwargs.get('xenv')
999 args_lst = kwargs.get('args_lst')
1000 if args_lst == None:
1001 args_lst = []
1002 if xenv == None:
1003 (self.exitcode,self.output,self.stderr) = cmd(*args_lst)
1004 else:
1005 (self.exitcode,self.output,self.stderr) = cmd(xenv, *args_lst)
1006 return
1007
1008
1009 use_shell = False
1010 cmd_args = _prepare_cmd(cmd)
1011 input_file_obj = _cond_open_input_file(self.directory,
1012 self.input_file_name)
1013 try:
1014 self.sub = subprocess.Popen(cmd_args,
1015 shell=use_shell,
1016 executable=self.shell_executable,
1017 cwd=self.directory,
1018 env=self.osenv,
1019 stdin = input_file_obj,
1020 **self.kwargs)
1021 except:
1022 (self.exception_type,
1023 self.exception_object,
1024 self.exception_trace) = sys.exc_info()
1025 else:
1026 self.sub.wait()
1027
1029 """Returns False if the process times out. Also sets
1030 self.timed_out to True."""
1031
1032 self.timed_out=False
1033 self.start()
1034 if self.seconds:
1035 self.join(self.seconds)
1036 else:
1037 self.join()
1038
1039 if self.is_alive():
1040 try:
1041 if self.sub:
1042 if on_windows():
1043
1044
1045
1046 kill_cmd = "taskkill /F /T /PID %i" % (self.sub.pid)
1047 cmd_args = _prepare_cmd(kill_cmd)
1048 subprocess.Popen(cmd_args, shell=True)
1049 else:
1050 self.sub.kill()
1051 except:
1052 pass
1053
1054 self.join()
1055 self.timed_out=True
1056 return False
1057 return True
1058
1059
1061 return isinstance(cmd,types.FunctionType)
1062
1063
1064 -def run_command_timed( cmd,
1065 shell_executable=None,
1066 directory=None,
1067 osenv=None,
1068 seconds=0,
1069 input_file_name=None,
1070 **kwargs ):
1071 """Run a timed command. kwargs are keyword args for subprocess.Popen.
1072
1073 @type cmd: string or python function
1074 @param cmd: command to run
1075
1076 @type shell_executable: string
1077 @param shell_executable: the shell executable
1078
1079 @type directory: string
1080 @param directory: the directory to run the command in
1081
1082 @type osenv: dictionary
1083 @param osenv: dict of environment vars to be passed to the new process
1084
1085 @type seconds: number
1086 @param seconds: maximum execution time in seconds
1087
1088 @type input_file_name: string
1089 @param input_file_name: input filename when redirecting stdin.
1090
1091 @type kwargs: keyword args
1092 @param kwargs: keyword args for subprocess.Popen
1093
1094 @rtype: tuple
1095 return: (return code, list of stdout+stderr lines)
1096 """
1097
1098 def _get_exit_code(tc):
1099 exit_code = 399
1100 if tc.sub:
1101
1102
1103 if hasattr(tc.sub, 'returncode'):
1104 exit_code = tc.sub.returncode
1105 return exit_code
1106
1107
1108
1109 fo = tempfile.SpooledTemporaryFile()
1110 fe = tempfile.SpooledTemporaryFile()
1111 tc = _timed_command_t(cmd,
1112 shell_executable,
1113 directory,
1114 osenv,
1115 seconds,
1116 input_file_name,
1117 stdout=fo,
1118 stderr=fe,
1119 **kwargs)
1120
1121 tc.timed_run()
1122
1123 if _is_python_cmd(tc.cmd):
1124 exit_code = tc.exitcode
1125 output = tc.output
1126 stderr = tc.stderr
1127 else:
1128 fo.seek(0)
1129 output = fo.readlines()
1130 fo.close()
1131 fe.seek(0)
1132 stderr = [''.join(fe.readlines())]
1133 fe.close()
1134 exit_code = _get_exit_code(tc)
1135
1136 nl = '\n'
1137 if tc.timed_out:
1138 stderr.extend([ nl,
1139 'COMMAND TIMEOUT'+nl,
1140 'KILLING PROCCESS'+nl])
1141 if tc.exception_type:
1142 stderr.extend([ nl,
1143 'COMMAND ENCOUNTERD AN EXCEPTION' + nl])
1144 stderr.extend(traceback.format_exception(tc.exception_type,
1145 tc.exception_object,
1146 tc.exception_trace))
1147
1148 return (exit_code, output, stderr)
1149