blob: 15cff57f6b9fc3dd2638996abbbd2a45f9b76a9b [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Michael Walsh21791602018-03-23 16:45:00 -05002
3r"""
4See help text for details (--help or -h option)..
5
6Example properties file content:
7quiet=n
8test_mode=y
9pos=file1 file2 file3
10
11Example call:
12
13prop_call.py --prop_file_name=prop_file my_program
14
15The result is that the following command will be run:
16my_program --test_mode=y --quiet=n file1 file2 file3
17"""
18
19import sys
20import os
21
22save_path_0 = sys.path[0]
23del sys.path[0]
24
25from gen_arg import *
26from gen_print import *
27from gen_valid import *
28from gen_misc import *
29from gen_cmd import *
30
31# Restore sys.path[0].
32sys.path.insert(0, save_path_0)
33
34
35parser = argparse.ArgumentParser(
36 usage='%(prog)s [OPTIONS]',
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050037 description="%(prog)s will call a program using parameters retrieved"
38 + " from the given properties file.",
Michael Walsh21791602018-03-23 16:45:00 -050039 formatter_class=argparse.ArgumentDefaultsHelpFormatter,
40 prefix_chars='-+')
41
42parser.add_argument(
43 '--prop_dir_path',
44 default=os.environ.get("PROP_DIR_PATH", os.getcwd()),
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050045 help='The path to the directory that contains the properties file.'
46 + ' The default value is environment variable "PROP_DIR_PATH", if'
47 + ' set. Otherwise, it is the current working directory.')
Michael Walsh21791602018-03-23 16:45:00 -050048
49parser.add_argument(
50 '--prop_file_name',
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050051 help='The path to a properties file that contains the parameters to'
52 + ' pass to the program. If the properties file has a ".properties"'
53 + ' extension, the caller need not specify the extension. The format'
54 + ' of each line in the properties file should be as follows:'
55 + ' <parm_name=parm_value>. Do not quote the parm value. To specify'
56 + ' positional parms, use a parm name of "pos". For example: pos=this'
Michael Walsh21791602018-03-23 16:45:00 -050057 ' value')
58
59parser.add_argument(
60 'program_name',
61 help='The name of the program to be run.')
62
63# Populate stock_list with options we want.
64stock_list = [("test_mode", 0), ("quiet", 1), ("debug", 0)]
65
66
67def exit_function(signal_number=0,
68 frame=None):
Michael Walsh21791602018-03-23 16:45:00 -050069 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050070 Execute whenever the program ends normally or with the signals that we catch (i.e. TERM, INT).
Michael Walsh21791602018-03-23 16:45:00 -050071 """
72
73 dprint_executing()
74 dprint_var(signal_number)
75
76 qprint_pgm_footer()
77
78
79def signal_handler(signal_number,
80 frame):
Michael Walsh21791602018-03-23 16:45:00 -050081 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050082 Handle signals. Without a function to catch a SIGTERM or SIGINT, our program would terminate immediately
83 with return code 143 and without calling our exit_function.
Michael Walsh21791602018-03-23 16:45:00 -050084 """
85
Michael Walsh410b1782019-10-22 15:56:18 -050086 # Our convention is to set up exit_function with atexit.register() so there is no need to explicitly
87 # call exit_function from here.
Michael Walsh21791602018-03-23 16:45:00 -050088
89 dprint_executing()
90
Michael Walsh410b1782019-10-22 15:56:18 -050091 # Calling exit prevents us from returning to the code that was running when we received the signal.
Michael Walsh21791602018-03-23 16:45:00 -050092 exit(0)
93
94
95def validate_parms():
Michael Walsh21791602018-03-23 16:45:00 -050096 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050097 Validate program parameters, etc. Return True or False (i.e. pass/fail) accordingly.
Michael Walsh21791602018-03-23 16:45:00 -050098 """
99
100 global prop_dir_path
101 global prop_file_path
102
103 if not valid_dir_path(prop_dir_path):
104 return False
105 prop_dir_path = add_trailing_slash(prop_dir_path)
106
107 if not valid_value(prop_file_name):
108 return False
109
110 prop_file_path = prop_dir_path + prop_file_name
111
112 # If properties file is not found, try adding ".properties" extension.
113 if not os.path.isfile(prop_file_path):
114 alt_prop_file_path = prop_file_path + ".properties"
115 if os.path.isfile(alt_prop_file_path):
116 prop_file_path = alt_prop_file_path
117
118 if not valid_file_path(prop_file_path):
119 return False
120
121 if not valid_value(program_name):
122 return False
123
124 gen_post_validation(exit_function, signal_handler)
125
126 return True
127
128
129def main():
130
131 if not gen_get_options(parser, stock_list):
132 return False
133
134 if not validate_parms():
135 return False
136
137 qprint_pgm_header()
138
139 # Get the parameters from the properties file.
140 properties = my_parm_file(prop_file_path)
141 # The parms (including program name) need to go into a list.
142 parms = [program_name]
143 for key, value in properties.items():
144 if key == "pos":
145 # Process positional parm(s).
146 parms.extend(value.split())
147 else:
148 parms.append("--" + key + "=" + escape_bash_quotes(value))
149
150 # parm_string is only created for display in non-quiet mode.
151 parm_string = " ".join(parms[1:])
152 cmd_buf = program_name + " " + parm_string
153 qprint_issuing(cmd_buf)
154 if not test_mode:
155 os.execvp(program_name, parms)
156
157 return True
158
159
160# Main
161
162if not main():
163 exit(1)