1#!/usr/bin/env python3
2
3r"""
4This module provides functions which are useful for running plug-ins.
5"""
6
7import sys
8import os
9import glob
10
11import gen_print as gp
12import gen_misc as gm
13
14# Some help text that is common to more than one program.
15plug_in_dir_paths_help_text = \
16    'This is a colon-separated list of plug-in directory paths.  If one' +\
17    ' of the entries in the list is a plain directory name (i.e. no' +\
18    ' path info), it will be taken to be a native plug-in.  In that case,' +\
19    ' %(prog)s will search for the native plug-in in the "plug-ins"' +\
20    ' subdirectory of each path in the PATH environment variable until it' +\
21    ' is found.  Also, integrated plug-ins will automatically be appended' +\
22    ' to your plug_in_dir_paths list.  An integrated plug-in is any plug-in' +\
23    ' found using the PATH variable that contains a file named "integrated".'
24
25mch_class_help_text = \
26    'The class of machine that we are testing (e.g. "op" = "open power",' +\
27    ' "obmc" = "open bmc", etc).'
28
29PATH_LIST = gm.return_path_list()
30
31
32def get_plug_in_base_paths():
33    r"""
34    Get plug-in base paths and return them as a list.
35
36    This function searches the PATH_LIST (created from PATH environment variable) for any paths that have a
37    "plug_ins" subdirectory.  All such paths are considered plug_in_base paths.
38    """
39
40    global PATH_LIST
41
42    plug_in_base_path_list = []
43
44    for path in PATH_LIST:
45        candidate_plug_in_base_path = path + "plug_ins/"
46        if os.path.isdir(candidate_plug_in_base_path):
47            plug_in_base_path_list.append(candidate_plug_in_base_path)
48
49    return plug_in_base_path_list
50
51
52# Define global plug_in_base_path_list and call get_plug_in_base_paths to set its value.
53plug_in_base_path_list = get_plug_in_base_paths()
54
55
56def find_plug_in_package(plug_in_name):
57    r"""
58    Find and return the normalized directory path of the specified plug in.  This is done by searching the
59    global plug_in_base_path_list.
60
61    Description of arguments:
62    plug_in_name                    The unqualified name of the plug-in package.
63    """
64
65    global plug_in_base_path_list
66    for plug_in_base_dir_path in plug_in_base_path_list:
67        candidate_plug_in_dir_path = os.path.normpath(plug_in_base_dir_path
68                                                      + plug_in_name) + \
69            os.sep
70        if os.path.isdir(candidate_plug_in_dir_path):
71            return candidate_plug_in_dir_path
72
73    return ""
74
75
76def validate_plug_in_package(plug_in_dir_path,
77                             mch_class="obmc"):
78    r"""
79    Validate the plug in package and return the normalized plug-in directory path.
80
81    Description of arguments:
82    plug_in_dir_path                The "relative" or absolute path to a plug in package directory.
83    mch_class                       The class of machine that we are testing (e.g. "op" = "open power",
84                                    "obmc" = "open bmc", etc).
85    """
86
87    gp.dprint_executing()
88
89    if os.path.isabs(plug_in_dir_path):
90        # plug_in_dir_path begins with a slash so it is an absolute path.
91        candidate_plug_in_dir_path = os.path.normpath(plug_in_dir_path) +\
92            os.sep
93        if not os.path.isdir(candidate_plug_in_dir_path):
94            gp.print_error_report("Plug-in directory path \""
95                                  + plug_in_dir_path + "\" does not exist.\n")
96            exit(1)
97    else:
98        # The plug_in_dir_path is actually a simple name (e.g. "OBMC_Sample")...
99        candidate_plug_in_dir_path = find_plug_in_package(plug_in_dir_path)
100        if candidate_plug_in_dir_path == "":
101            global PATH_LIST
102            gp.print_error_report("Plug-in directory path \""
103                                  + plug_in_dir_path + "\" could not be found"
104                                  + " in any of the following directories:\n"
105                                  + gp.sprint_var(PATH_LIST))
106            exit(1)
107    # Make sure that this plug-in supports us...
108    supports_file_path = candidate_plug_in_dir_path + "supports_" + mch_class
109    if not os.path.exists(supports_file_path):
110        gp.print_error_report("The following file path could not be"
111                              + " found:\n"
112                              + gp.sprint_varx("supports_file_path",
113                                               supports_file_path)
114                              + "\nThis file is necessary to indicate that"
115                              + " the given plug-in supports the class of"
116                              + " machine we are testing, namely \""
117                              + mch_class + "\".\n")
118        exit(1)
119
120    return candidate_plug_in_dir_path
121
122
123def return_integrated_plug_ins(mch_class="obmc"):
124    r"""
125    Return a list of integrated plug-ins.  Integrated plug-ins are plug-ins which are selected without regard
126    for whether the user has specified them.  In other words, they are "integrated" into the program suite.
127    The programmer designates a plug-in as integrated by putting a file named "integrated" into the plug-in
128    package directory.
129
130    Description of arguments:
131    mch_class                       The class of machine that we are testing (e.g. "op" = "open power",
132                                    "obmc" = "open bmc", etc).
133    """
134
135    global plug_in_base_path_list
136
137    integrated_plug_ins_list = []
138
139    DEBUG_SKIP_INTEGRATED = int(os.getenv('DEBUG_SKIP_INTEGRATED', '0'))
140
141    if DEBUG_SKIP_INTEGRATED:
142        return integrated_plug_ins_list
143
144    for plug_in_base_path in plug_in_base_path_list:
145        # Get a list of all plug-in paths that support our mch_class.
146        mch_class_candidate_list = glob.glob(plug_in_base_path
147                                             + "*/supports_" + mch_class)
148        for candidate_path in mch_class_candidate_list:
149            integrated_plug_in_dir_path = os.path.dirname(candidate_path) +\
150                os.sep
151            integrated_file_path = integrated_plug_in_dir_path + "integrated"
152            if os.path.exists(integrated_file_path):
153                plug_in_name = \
154                    os.path.basename(os.path.dirname(candidate_path))
155                if plug_in_name not in integrated_plug_ins_list:
156                    # If this plug-in has not already been added to the list...
157                    integrated_plug_ins_list.append(plug_in_name)
158
159    return integrated_plug_ins_list
160
161
162def return_plug_in_packages_list(plug_in_dir_paths,
163                                 mch_class="obmc"):
164    r"""
165    Return a list of plug-in packages given the plug_in_dir_paths string.  This function calls
166    validate_plug_in_package so it will fail if plug_in_dir_paths contains any invalid plug-ins.
167
168    Description of arguments:
169    plug_in_dir_path                The "relative" or absolute path to a plug in package directory.
170    mch_class                       The class of machine that we are testing (e.g. "op" = "open power",
171                                    "obmc" = "open bmc", etc).
172    """
173
174    if plug_in_dir_paths != "":
175        plug_in_packages_list = plug_in_dir_paths.split(":")
176    else:
177        plug_in_packages_list = []
178
179    # Get a list of integrated plug-ins (w/o full path names).
180    integrated_plug_ins_list = return_integrated_plug_ins(mch_class)
181    # Put both lists together in plug_in_packages_list with no duplicates.  NOTE: This won't catch
182    # duplicates if the caller specifies the full path name of a native plug-in but that should be rare
183    # enough.
184
185    plug_in_packages_list = plug_in_packages_list + integrated_plug_ins_list
186
187    plug_in_packages_list = \
188        list(set([validate_plug_in_package(path, mch_class)
189                  for path in plug_in_packages_list]))
190
191    return plug_in_packages_list
192