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 commands
10import glob
11
12import gen_print as gp
13import gen_misc as gm
14
15# Some help text that is common to more than one program.
16plug_in_dir_paths_help_text = \
17    'This is a colon-separated list of plug-in directory paths.  If one' +\
18    ' of the entries in the list is a plain directory name (i.e. no' +\
19    ' path info), it will be taken to be a native plug-in.  In that case,' +\
20    ' %(prog)s will search for the native plug-in in the "plug-ins"' +\
21    ' subdirectory of each path in the PATH environment variable until it' +\
22    ' is found.  Also, integrated plug-ins will automatically be appended' +\
23    ' to your plug_in_dir_paths list.  An integrated plug-in is any plug-in' +\
24    ' found using the PATH variable that contains a file named "integrated".'
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
30PATH_LIST = gm.return_path_list()
31
32
33def get_plug_in_base_paths():
34    r"""
35    Get plug-in base paths and return them as a list.
36
37    This function searches the PATH_LIST (created from PATH environment
38    variable) for any paths that have a "plug_ins" subdirectory.  All such
39    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
55# its value.
56plug_in_base_path_list = get_plug_in_base_paths()
57
58
59def find_plug_in_package(plug_in_name):
60    r"""
61    Find and return the normalized directory path of the specified plug in.
62    This is done by searching the global plug_in_base_path_list.
63
64    Description of arguments:
65    plug_in_name                    The unqualified name of the plug-in
66                                    package.
67    """
68
69    global plug_in_base_path_list
70    for plug_in_base_dir_path in plug_in_base_path_list:
71        candidate_plug_in_dir_path = os.path.normpath(plug_in_base_dir_path
72                                                      + plug_in_name) + \
73            os.sep
74        if os.path.isdir(candidate_plug_in_dir_path):
75            return candidate_plug_in_dir_path
76
77    return ""
78
79
80def validate_plug_in_package(plug_in_dir_path,
81                             mch_class="obmc"):
82    r"""
83    Validate the plug in package and return the normalized plug-in directory
84    path.
85
86    Description of arguments:
87    plug_in_dir_path                The "relative" or absolute path to a plug
88                                    in package directory.
89    mch_class                       The class of machine that we are testing
90                                    (e.g. "op" = "open power", "obmc" = "open
91                                    bmc", etc).
92    """
93
94    gp.dprint_executing()
95
96    if os.path.isabs(plug_in_dir_path):
97        # plug_in_dir_path begins with a slash so it is an absolute path.
98        candidate_plug_in_dir_path = os.path.normpath(plug_in_dir_path) +\
99            os.sep
100        if not os.path.isdir(candidate_plug_in_dir_path):
101            gp.print_error_report("Plug-in directory path \""
102                                  + plug_in_dir_path + "\" does not exist.\n")
103            exit(1)
104    else:
105        # The plug_in_dir_path is actually a simple name (e.g.
106        # "OBMC_Sample")...
107        candidate_plug_in_dir_path = find_plug_in_package(plug_in_dir_path)
108        if candidate_plug_in_dir_path == "":
109            global PATH_LIST
110            gp.print_error_report("Plug-in directory path \""
111                                  + plug_in_dir_path + "\" could not be found"
112                                  + " in any of the following directories:\n"
113                                  + gp.sprint_var(PATH_LIST))
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("The following file path could not be"
119                              + " found:\n"
120                              + gp.sprint_varx("supports_file_path",
121                                               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 + "\".\n")
126        exit(1)
127
128    return candidate_plug_in_dir_path
129
130
131def return_integrated_plug_ins(mch_class="obmc"):
132    r"""
133    Return a list of integrated plug-ins.  Integrated plug-ins are plug-ins
134    which are selected without regard for whether the user has specified them.
135    In other words, they are "integrated" into the program suite.  The
136    programmer designates a plug-in as integrated by putting a file named
137    "integrated" into the plug-in package directory.
138
139    Description of arguments:
140    mch_class                       The class of machine that we are testing
141                                    (e.g. "op" = "open power", "obmc" = "open
142                                    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(plug_in_base_path
157                                             + "*/supports_" + mch_class)
158        for candidate_path in mch_class_candidate_list:
159            integrated_plug_in_dir_path = os.path.dirname(candidate_path) +\
160                os.sep
161            integrated_file_path = integrated_plug_in_dir_path + "integrated"
162            if os.path.exists(integrated_file_path):
163                plug_in_name = \
164                    os.path.basename(os.path.dirname(candidate_path))
165                if plug_in_name not in integrated_plug_ins_list:
166                    # If this plug-in has not already been added to the list...
167                    integrated_plug_ins_list.append(plug_in_name)
168
169    return integrated_plug_ins_list
170
171
172def return_plug_in_packages_list(plug_in_dir_paths,
173                                 mch_class="obmc"):
174    r"""
175    Return a list of plug-in packages given the plug_in_dir_paths string.
176    This function calls validate_plug_in_package so it will fail if
177    plug_in_dir_paths contains any invalid plug-ins.
178
179    Description of arguments:
180    plug_in_dir_path                The "relative" or absolute path to a plug
181                                    in package directory.
182    mch_class                       The class of machine that we are testing
183                                    (e.g. "op" = "open power", "obmc" = "open
184                                    bmc", etc).
185    """
186
187    if plug_in_dir_paths != "":
188        plug_in_packages_list = plug_in_dir_paths.split(":")
189    else:
190        plug_in_packages_list = []
191
192    # Get a list of integrated plug-ins (w/o full path names).
193    integrated_plug_ins_list = return_integrated_plug_ins(mch_class)
194    # Put both lists together in plug_in_packages_list with no duplicates.
195    # NOTE: This won't catch duplicates if the caller specifies the full path
196    # name of a native plug-in but that should be rare enough.
197
198    plug_in_packages_list = plug_in_packages_list + integrated_plug_ins_list
199
200    plug_in_packages_list = \
201        list(set([validate_plug_in_package(path, mch_class)
202                  for path in plug_in_packages_list]))
203
204    return plug_in_packages_list
205