replace os.system with subprocess.call - add a timeout option in the mix
[tests.git] / system / utils.py
1 # -*- python3 -*-
2 # Thierry Parmentelat <thierry.parmentelat@inria.fr>
3 # Copyright (C) 2015 INRIA 
4 #
5 import sys
6 import time
7 import os
8 import re
9 import glob
10 import subprocess
11 from pprint import PrettyPrinter
12
13 options={}
14
15 def init_options(options_arg):
16     global options
17     options = options_arg
18
19 # how could this accept a list again ?
20 def header(message):
21     now = time.strftime("%H:%M:%S", time.localtime())
22     print("*", now, '--', message)
23
24 def pprint(message, spec, depth=2):
25     now = time.strftime("%H:%M:%S", time.localtime())
26     print(">", now, "--", message)
27     PrettyPrinter(indent=8, depth=depth).pprint(spec)
28
29
30 # set a default timeout to 15 minutes - this should be plenty even for installations
31 # call with timeout=None if the intention really is to wait until full completion
32 def system(command, background=False, silent=False, dry_run=None, timeout=15*60):
33     dry_run = dry_run if dry_run is not None else getattr(options, 'dry_run', False)
34     if dry_run:
35         print('dry_run:', command)
36         return 0
37     
38     if silent :    
39         if command.find(';') >= 0:
40             command = "({}) 2> /dev/null".format(command)
41         else: command += " 2> /dev/null"
42     if background:
43         command += " &"
44     if silent:
45         print('.', end=' ')
46         sys.stdout.flush()
47     else:
48         now = time.strftime("%H:%M:%S", time.localtime())
49         # don't show in summary
50         print("->", now, '--', end=' ')
51         sys.stdout.flush()
52     if not silent:
53         command = "set -x; " + command
54     try:
55         return subprocess.call(command, shell=True, timeout=timeout)
56     except subprocess.TimeoutExpired as e:
57         header("TIMEOUT when running command {}- {}".format(command, e))
58         return -1
59
60 ### WARNING : this ALWAYS does its job, even in dry_run mode
61 def output_of (command):
62     import subprocess
63     (code, string) = subprocess.getstatusoutput(command)
64     return (code, string)
65
66
67 # convenience: translating shell-like pattern into regexp
68 def match (string, pattern):
69     # tmp - there's probably much simpler
70     # rewrite * into .*, ? into .
71     pattern = pattern.replace("*",".*")
72     pattern = pattern.replace("?",".")
73     return re.compile(pattern).match(string)
74     
75 def locate_hooks_scripts (message, path, extensions):
76     print(message, 'searching', path, 'for extensions', extensions)
77     scripts = []
78     for ext in extensions:
79         # skip helper programs
80         scripts += glob.glob (path+'/[a-zA-Z]*.' + ext)
81     return scripts
82     
83 # quick & dirty - should probably use the parseroption object instead
84 # and move to TestMain as well
85 exclude_options_keys = [ 'ensure_value' , 'read_file', 'read_module' ]
86 def show_options (message, options):
87     now = time.strftime("%H:%M:%S", time.localtime())
88     print(">", now, "--", message)
89     for k in dir(options):
90         if k.find("_") == 0:
91             continue
92         if k in exclude_options_keys:
93             continue
94         print("    ", k, ":", getattr(options, k))
95
96
97