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