New valid_program() function

Change-Id: I0ac45502b6a4e8a38d7ec4b18bdd9df8c995ca66
Signed-off-by: Michael Walsh <micwalsh@us.ibm.com>
diff --git a/lib/gen_robot_valid.py b/lib/gen_robot_valid.py
index d49b00e..556561d 100755
--- a/lib/gen_robot_valid.py
+++ b/lib/gen_robot_valid.py
@@ -206,12 +206,20 @@
     process_error_message(error_message)
 
 
+def valid_program(var_name, *args, **kwargs):
+
+    var_value, args, kwargs = valid_init(var_name, *args, **kwargs)
+    error_message = \
+        gv.valid_program(var_value, *args, var_name=var_name, **kwargs)
+    process_error_message(error_message)
+
+
 # Modify the validation function docstrings by calling customize_doc_string
 # for each function in the func_names list.
 func_names = [
     "valid_type", "valid_value", "valid_range", "valid_integer",
     "valid_dir_path", "valid_file_path", "valid_path", "valid_list",
-    "valid_dict"
+    "valid_dict", "valid_program"
 ]
 
 for func_name in func_names:
diff --git a/lib/gen_valid.py b/lib/gen_valid.py
index 6ead645..8725077 100755
--- a/lib/gen_valid.py
+++ b/lib/gen_valid.py
@@ -6,7 +6,9 @@
 """
 
 import os
+import re
 import gen_print as gp
+import gen_cmd as gc
 import func_args as fa
 
 exit_on_error = False
@@ -568,12 +570,35 @@
     return process_error_message(error_message)
 
 
+def valid_program(var_value, *args, **kwargs):
+    r"""
+    The variable value is valid if it contains the name of a program which can
+    be located using the "which" command.
+
+    Description of argument(s):
+    var_value                       The value being validated.
+    """
+
+    error_message = ""
+    rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0,
+                               ignore_err=1)
+    if rc:
+        var_name = get_var_name(*args, **kwargs)
+        error_message += "The following required program could not be found"
+        error_message += " using the $PATH environment variable:\n"
+        error_message += gp.sprint_varx(var_name, var_value)
+        PATH = os.environ.get("PATH", "").split(":")
+        error_message += "\n"
+        error_message += gp.sprint_var(PATH)
+    return process_error_message(error_message)
+
+
 # Modify selected function docstrings by adding headers/footers.
 
 func_names = [
     "valid_type", "valid_value", "valid_range", "valid_integer",
     "valid_dir_path", "valid_file_path", "valid_path", "valid_list",
-    "valid_dict"
+    "valid_dict", "valid_program"
 ]
 
 raw_doc_strings = {}