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