Beispiel #1
0
def match_regex_get_first_num(target_file, regex):
    """
    Match the given regex in the given file (get the first match),
    and return the first number in the matched string.
    """
    # TODO add doctest
    if isinstance(regex, str):
        # if regex is a string, compile to regex
        regex = re.compile(regex)
    elif not isinstance(regex, type(re.compile(''))):
        raise OCPIException("Error: regular expression invalid")

    # Have to use encoding/errors flags here to avoid failure when file has non-ASCII
    with open(target_file, encoding="utf8", errors='ignore') as tgt_file:
        for line in tgt_file:
            # List of all matches on the line
            matches = re.findall(regex, line)
            # Were any matches found?
            if matches and matches[0]:
                # Get the first number in the first match on the line
                first_num = first_num_in_str(matches[0])
                if first_num != None:
                    return first_num
    # no number/match found
    return None
Beispiel #2
0
def match_regex(target_file, regex):
    """
    Parse the target file for a regex and return the first group/element
    of the first match

    For example (doctest):
    Here, we have a line of text below and we parse this current file
    using a regular expression to grab the 'ns' number from the string.
    # This text right here contains a number (2.000ns)!!!! It should match the regex
    >>> match_regex(os.path.realpath(__file__), "#.*This text right.*\((.*)ns\)!!!!.*")
    '2.000'
    """
    if isinstance(regex, str):
        regex = re.compile(regex)
    elif not isinstance(regex, type(re.compile(''))):
        raise OCPIException("Error: regular expression invalid")

    # Have to use encoding/errors flags here to avoid failure when file has non-ASCII
    with open(target_file, encoding="utf8", errors="ignore") as tgt_file:
        for line in tgt_file:
            # List of all matches on the line
            matches = re.findall(regex, line)
            # Were any matches found?
            if matches and matches[0]:
                # Get the first match on the line
                match = matches[0]
                if isinstance(match, tuple):
                    # Match might be a tuple (if 1+ groups are in the pattern). In that case
                    # return the first group in the match tuple
                    return match[0]
                return match
    # no match found
    return None
Beispiel #3
0
def execute_cmd(settings, directory, action=None):
    """
    This command is a wrapper around any calls to make in order to encapsulate the use of make to a
    minimal number of places.  The function contains a hard-coded dictionary of generic settings to
    make variables that it uses to construct the call to make at that given directory
    """
    settings_dict = {'rcc_plats'       : "RccPlatforms",
                     'hdl_plat_strs'   : "HdlPlatforms",
                     'hdl_tgt_strs'    : "HdlTargets",
                     'only_plats'      : "OnlyPlatforms",
                     'ex_plats'        : "ExcludePlatforms",
                     'keep_sims'       : "KeepSimulations",
                     'acc_errors'      : "TestAccumulateErrors",
                     'view'            : "View",
                     'cases'           : "Cases",
                     'run_before'      : "OcpiRunBefore",
                     'run_after'       : "OcpiRunAfter",
                     'run_arg'         : "OcpiRunArgs",
                     'remote_test_sys' : "OCPI_REMOTE_TEST_SYSTEMS",
                     'verbose'         : "TestVerbose"}
    make_list = []

    make_list.append("make")
    make_list.append("-C")
    make_list.append(directory)
    debug_string = "make -C " + directory

    if action is not None:
        make_list.extend(action)
        debug_string += " " + ' '.join(action) + " "

    logging.debug("settings for make command: " + str(settings.items()))
    for setting, value in settings.items():
        if isinstance(value, bool):
            make_list.append(settings_dict[setting] + '=1')
            debug_string += " " + settings_dict[setting] + '=1'
        elif isinstance(value, list) or isinstance(value, set):
            make_list.append(settings_dict[setting] + '='  + ' '.join(value))
            if len(value) > 1:
                debug_string += " " + settings_dict[setting] + '="'  + ' '.join(value) + '"'
            else:
                debug_string += " " + settings_dict[setting] + '='  + ' '.join(value)
        else:
            raise OCPIException("Invalid setting data-type passed to execute_cmd().  Valid data-" +
                                "types are bool and list")

    logging.debug("running make command: " + debug_string)
    #shell=True is bad dont set it here running the following command was able to execute
    # arbitary code
    #ocpidev run test --hdl-platform \$\(./script.temp\)
    # all the script would need to do is cat isim then go on its merry way doing whatever it wanted
    child = subprocess.Popen(make_list)
    child.wait()
    return child.returncode
Beispiel #4
0
    def print_table(self, none_str="N/A"):
        """
        Print a table of this Report's data-points. Lead with the headers and present
        each data-point's elements as per the order in "ordered_headers".
        Let the caller specify a string to use for empty/None entries (Default: N/A)
        """
        if self.data_points:
            # Fill in empty values in data-points with none_str
            for header in self.ordered_headers:
                for point in self.data_points:
                    if header not in point:
                        point[header] = none_str
            # Construct the list of rows. Do so following the ordered_headers order
            rows = []
            for point in self.data_points:
                row = []
                for header in self.ordered_headers:
                    elem = point[header]
                    if elem is None:
                        row.append(none_str)
                    elif isinstance(elem, str):
                        # element is a string, just append to row
                        row.append(elem)
                    elif isinstance(elem, list):
                        # element is a list, join its contents with comma and append to row
                        row.append(", ".join(elem))
                    else:
                        # Unsupported element type (not a string or list)
                        try:
                            row.append(str(elem))
                        except Exception as ex:
                            logging.error(ex)
                            raise OCPIException(
                                "Element in Report is not a string and could not"
                                + " be cast to a string.")

                rows.append(row)
            # Sort the rows by each header listed in sort_priority. Do this in reverse order
            # so the last sort key (and therefore the most significant) is the first element
            # in sort_priority
            for sort_header in reversed(self.sort_priority):
                rows.sort(key=operator.itemgetter(
                    self.ordered_headers.index(sort_header)))
            # insert the headers as row 0
            rows.insert(0, self.ordered_headers)
            # format the table using a generic function and print
            print(format_table(rows, underline="-"))
        else:
            logging.warning("Not printing table for empty report.")
Beispiel #5
0
 def __iadd__(self, other):
     """
     Adding a Report to this one is the equivalent of adding a Report's data_points
     to this Reports data-point list. If this Report's ordered_headers is empty,
     use the other Report's ordered_headers.
     if not isinstance(other, Report):
     """
     if not isinstance(other, Report):
         raise OCPIException(
             "Can only add another Report object to a Report.")
     # Headers are unchanged on addition unless headers are empty in which case,
     # user other's headers
     if not self.ordered_headers:
         self.ordered_headers = other.ordered_headers
     self.data_points += other.data_points
     return self
Beispiel #6
0
def get_paths_through_project_top(origin_path, dest_paths):
    """
    origin to each destination going through the project top (and potentially
    imports) when possible.
    """
    origin_top = get_path_to_project_top(origin_path, False)
    origin_top_rel = get_path_to_project_top(origin_path, True)
    if origin_top is None:
        raise OCPIException("origin_path \"" + str(origin_path) +
                            "\" is not in a project")
    paths_through_top = []
    for dest_p in dest_paths:
        paths_through_top.append(
            get_path_from_given_project_top(origin_top, dest_p,
                                            origin_top_rel))
    return paths_through_top
Beispiel #7
0
def get_paths_from_project_top(origin_path, dest_paths):
    """
    Given an origin and a list of destination paths, return a list of paths
    from origin's project top to each destination (potentially through imports).
    If a destination path is not in the current or an imported project,
    return an absolute path.
    """
    origin_top = get_path_to_project_top(origin_path, False)
    if origin_top is None:
        raise OCPIException("origin_path \"" + str(origin_path) +
                            "\" is not in a project")
    paths_from_top = []
    for dest_p in dest_paths:
        paths_from_top.append(
            get_path_from_given_project_top(origin_top, dest_p))
    return paths_from_top
Beispiel #8
0
def _get_asset_dir(noun="",
                   name=".",
                   library=None,
                   hdl_library=None,
                   hdl_platform=None):
    """
    Given a noun, a name, and library directives
    determine the target asset's directory from a project top.

    Basically, the arguments of this function specify/describe an asset in a project.
    This function completes that mapping of asset-description -> asset-directory,
    and returns the directory of interest relative to the top of the project.

    Args:
        noun: noun/asset-type of interest. Defaults to blank
        name: name of the asset to locate. Basically, what is the name of the asset of type <noun>
        library: the library in which the asset of interest lives
        hdl_library: the HDL library in which the asset of interest lives (in the hdl/ subtree)
        hdl_platform: the HDL platform in which the asset of interest lives.
                      might itself be the asset

    Return:
        asset: the project subdirectory containing the asset described via this function's arguments

    Notes:
        name and noun describe the name and type of asset being described.
        The library and platform arguments are location-directives or modifiers
        that dictate where to the asset is found.

    Examples (doctest):
        >>> _get_asset_dir(noun="library", name="components")
        'components'
        >>> _get_asset_dir(noun="library", name="dsp_comps")
        'components/dsp_comps'
        >>> _get_asset_dir(noun="library", name="components/dsp_comps")
        'components/dsp_comps'
        >>> _get_asset_dir(noun="library", name="hdl/devices")
        'hdl/devices'
        >>> _get_asset_dir(noun="worker", name="complex_mixer.hdl", library="dsp_comps")
        'components/dsp_comps/complex_mixer.hdl'
        >>> _get_asset_dir(noun="test", name="bias.test", library="components")
        'components/bias.test'
        >>> _get_asset_dir(noun="test", name="bias", library="components")
        'components/bias.test'
        >>> _get_asset_dir(noun="worker", name="ad9361_adc.hdl", hdl_library="devices")
        'hdl/devices/ad9361_adc.hdl'
        >>> _get_asset_dir(noun="worker", name="matchstiq_z1_avr.hdl", hdl_platform="matchstiq_z1")
        'hdl/platforms/matchstiq_z1/devices/matchstiq_z1_avr.hdl'
        >>> _get_asset_dir(noun="applications")
        'applications'
        >>> _get_asset_dir(noun="application", name="rx_app")
        'applications/rx_app'
        >>> _get_asset_dir(noun="application", name="rx_app")
        'applications/rx_app'
        >>> _get_asset_dir(noun="hdl-assemblies")
        'hdl/assemblies'
        >>> _get_asset_dir(noun="hdl-assembly", name="fsk_modem")
        'hdl/assemblies/fsk_modem'
        >>> _get_asset_dir(noun="hdl-assembly", name="fsk_modem")
        'hdl/assemblies/fsk_modem'
        >>> _get_asset_dir(noun="hdl-primitive", name="zynq")
        'hdl/primitives/zynq'
        >>> _get_asset_dir(noun="hdl-primitive", name="zynq")
        'hdl/primitives/zynq'
        >>> _get_asset_dir(noun="hdl-library", name="devices")
        'hdl/devices'
        >>> _get_asset_dir(noun="hdl-platform", name="matchstiq_z1")
        'hdl/platforms/matchstiq_z1'
        >>> _get_asset_dir(noun="project", name="assets")
        'assets'
        >>> _get_asset_dir(noun="project")
        '.'
        >>> _get_asset_dir(library="components", hdl_library="devices", hdl_platform="matchstiq_z1")
        Traceback (most recent call last):
            ...
        OCPIException: ...
        >>> _get_asset_dir(noun="INVALID")
        Traceback (most recent call last):
            ...
        OCPIException: ...
    """
    #TODO if i do show project in a lower level dir it should use find project top to locate the
    # directory of the project
    if noun == "test" and not name.endswith((".test", ".test/")):
        name += ".test"
    # library-directives are mutually exclusive
    if library is not None and hdl_library is not None:
        #raise OCPIException("library, hdl_library, and hdl_platform options are " +
        raise OCPIException("library and hdl_library are mutually exclusive.")

    # asset types that live inside a library
    library_assets = ["worker", "test"]

    # For most nouns, there is only a single directory to choose from
    if noun == "libraries" and library is None:
        asset = "components"
    elif noun in ["application", "applications"]:
        asset = "applications"
    elif noun in ["hdl-primitive", "hdl-primitives"]:
        asset = "hdl/primitives"
    elif noun == "hdl-platforms":
        asset = "hdl/platforms"
    elif noun in ["hdl-assembly", "hdl-assemblies"]:
        asset = "hdl/assemblies"
    elif noun == "hdl-platform" or hdl_platform is not None:
        # hdl platform is specified in some way

        # cannot have a platform noun AND directive
        if noun == "hdl-platform" and name is not "." and hdl_platform is not None:
            raise OCPIException(
                "Could not choose between two HDL platform directories: '" +
                name + "' and '" + hdl_platform + "'.")
        # default hdl platform if needed
        hdl_platform = name if hdl_platform is None else hdl_platform
        # hdl_platform location directive or noun implies directories
        # like hdl/platforms/<hdl-platform>
        if noun in library_assets + ["library", "workers", "tests"]:
            # can only specify library as 'devices' in a platform directory
            if noun == "library" and name not in [".", "devices", "devices/"]:
                raise OCPIException(
                    "Only valid library in an HDL platform is 'devices'")
            # if the hdl_platform location directive is used and a library-asset is being
            # located, drill down into the platform's devices library
            asset = "hdl/platforms/" + hdl_platform + "/devices"
        else:
            asset = "hdl/platforms/" + hdl_platform

    elif noun == "library" or library is not None:
        # library is specified in some way

        # cannot have a library noun AND directive
        if noun == "library" and name is not "." and library is not None:
            raise OCPIException(
                "Could not choose between two library directories: '" + name +
                "' and '" + library + "'.")
        # default library if needed
        library = name if library is None else library
        if library == "components" or "/" in library:
            # library is either the components directory or a full path - use it as-is
            asset = library
        else:
            # library is just a name (not a path) - prepend components/ to it
            asset = "components/" + library

    elif noun == "hdl-library" or hdl_library is not None:
        # hdl library is specified in some way

        # cannot have a library noun AND directive
        if noun == "hdl-library" and name is not "." and hdl_library is not None:
            raise OCPIException(
                "Could not choose between two hdl_library directories: '" +
                name + "' and '" + hdl_library + "'.")
        # default hdl library if needed
        hdl_library = name if hdl_library is None else hdl_library
        # hdl libraries live in the hdl/ subtree
        asset = "hdl/" + hdl_library

    elif noun in library_assets:
        asset = "components/"

    elif noun in ["project", "workers", "tests"]:
        # If we have gotten this far and a "workers" or "tests" is discovered, the only
        # remaining asset type that it can be is "project".

        # When locating a project, it is either the current project (name is none), or the
        # the directory is specified by name
        asset = "." if name is None else name

    elif noun is None:
        # when no noun or location-directive gives direction regarding where to look for an
        # asset, assume the top-level of the project
        asset = "."
    else:
        raise OCPIException("Invalid noun provided: " + str(noun))

    # If the asset-type/noun is a collection-type, then we already know its location.
    #     E.g. If the noun is 'library' (a collection-type) and the name is 'dsp_comps',
    #          then by now we have obtained asset='components/dsp_comps'. Just return that.
    # Otherwise append 'name' to the determined collection-type asset.
    #     E.g. If library directives describe a collection-type/asset named 'components/dsp_comps',
    #          and the noun is 'worker' with name 'complex_mixer.hdl', then this will result in
    #          'components/dsp_comps/complex_mixer.hdl
    if noun in COLLECTION_DIRTYPES or name is None:
        return asset
    else:
        return asset + "/" + name
Beispiel #9
0
def get_ocpidev_working_dir(origin_path=".",
                            noun="",
                            name=".",
                            library=None,
                            hdl_library=None,
                            hdl_platform=None):
    """
    Given an origin path, noun, name  and location/library directives,
    determine the target assets's directory to work in.

    Basically, the arguments of this function describe the current state/location in a project
    as well as a description of where to look for an asset of a certain name and type.
    This function completes that mapping of:
    'current-state/location + asset-description' -> asset-directory,
    and returns the working directory of interest.

    First, this function converts the current state/location to location/library directives
    like library, hdl_library, hdl_platform and collection_type. So basically, convert the
    current-state + location-directives, to just location-directives. These location-directives
    along with descriptors like noun and name comprise an asset-description.

    At that point, the _get_asset_dir() function can be called which converts an asset-description
    to asset-directory. This nested function call does not require any current-state/location
    information, and will provide the location of the target asset relative to a project top.

    Finally, the path to the project of interest is prepended to this asset-directory and
    the resulting full-path is returned.

    Args:
        origin_path: path from which we are operating - this provides runtime context that may
                     translate to location directives:
                         (library/hdl_library/hdl_platform/collection_type)
        noun: noun/asset-type of interest. Defaults to blank
        name: name of the asset to locate. Basically, what is the name of the asset of type <noun>
        library: the library in which the asset of interest lives
        hdl_library: the HDL library in which the asset of interest lives (in the hdl/ subtree)
        hdl_platform: the HDL platform in which the asset of interest lives.
                      might itself be the asset

    Return:
        asset_dir: the full path to asset described via this function's arguments

    Notes:
        name and noun describe the name and type of asset being described.
        The library, platform arguments are location-directives or modifiers
        that dictate where to the asset should be found.
    """

    logging.debug("Getting ocpidev working dir from options:\n" +
                  str((origin_path, noun, name, library, hdl_library,
                       hdl_platform)))

    # If the noun is project, append name to origin_path to ensure we operate from within a project
    # from here forward
    if noun == "project":
        origin_path = origin_path + "/" + name
        name = "."

    #from _opencpi.util import OCPIException
    if not is_path_in_project(origin_path):
        raise OCPIException(
            "Path \"" + os.path.realpath(origin_path) +
            "\" is not in a project, so its settings " +
            "as a subdirectory of a project could not be determined.")

    # if this is a collection type, we care about the current directory's dirtype,
    # otherwise we want the current asset's containing collection's dirtype
    cur_dirtype = get_dirtype(origin_path)
    if cur_dirtype is not None and cur_dirtype in COLLECTION_DIRTYPES:
        # operating on a collection-type, so just proceed as usual
        working_dir = origin_path
        dirtype = cur_dirtype
    else:
        # not operating on a collection-type. It is most convenient here
        # to determine the location/library-directives associated with the
        # asset's containing collection
        working_dir = origin_path + "/.."
        dirtype = get_dirtype(working_dir)
        # if no name was provided, set name to the origin_path's basename to preserve that
        # information as we move to the parent collection
        if (name is None
                or name == ".") and get_dirtype(origin_path) is not None:
            name = os.path.basename(os.path.realpath(origin_path))

    # error checking
    if (library is not None or hdl_library
            is not None) and dirtype in ["library", "hdl-library"]:
        raise OCPIException(
            "[hdl-]library option cannot be provided when operating in a " +
            "directory of [hdl-]library type.")
    if (hdl_platform is not None) and dirtype in "hdl_platform":
        raise OCPIException(
            "hdl-platform option cannot be provided when operating in a " +
            "directory of hdl-platform type.")

    working_basename = os.path.basename(os.path.realpath(working_dir))

    # if origin path is the 'hdl' subdir, and library is set, prepend 'hdl/'
    if dirtype is None and working_basename == "hdl" and library is not None:
        library = "hdl/" + library

    elif dirtype == "library":
        # Determine where this library lives to choose which locatin-directive
        # to set
        parent_dt = get_dirtype(working_dir + "/..")
        parent_basename = os.path.basename(
            os.path.realpath(working_dir + "/.."))
        library = working_basename
        if parent_dt in ["project", "libraries"]:
            # if the parent directory is type project or libraries, then this is
            # a component library (e.g. components or a sublibrary of components)
            library = working_basename
        elif parent_dt == "hdl-platform":
            # parent directory is an HDL platform, so set that directive
            hdl_platform = parent_basename
        elif parent_dt is None and parent_basename == "hdl":
            # parent directory has no type and is named 'hdl'. So, this is an hdl library
            # e.g. devices, cards, adapters
            library = "hdl/" + working_basename

    elif dirtype == "hdl-platform":
        hdl_platform = working_basename

    logging.debug(
        "Getting ocpidev working dir from options (auxiliary function):\n" +
        str((noun, name, library, hdl_library, hdl_platform, dirtype)))

    # If no noun was specified, and the dirtype is a collection, set noun to dirtype
    # For example, if a command was run in hdl/assemblies, but no noun was specified,
    # then just set the noun to hdl-assemblies
    if noun == "":
        noun = dirtype if dirtype in COLLECTION_DIRTYPES else ""

    # Now that the current state/directory has been converted to location directives,
    # call this helper function to convert or state-less asset-description to an
    # asset-directory from a project top
    asset_from_pj_top = _get_asset_dir(noun, name, library, hdl_library,
                                       hdl_platform)

    proj_path = get_path_to_project_top(origin_path)

    # prepend the asset-directory with the path to the project top
    asset_dir = os.path.realpath(proj_path + "/" + asset_from_pj_top)

    # ensure existence and return
    if os.path.exists(asset_dir):
        return asset_dir
    else:
        raise OCPIException("Determined working directory of \"" + asset_dir +
                            "\" that does " + "not exist.")
Beispiel #10
0
def set_vars_from_make(mk_file, mk_arg="", verbose=None):
    """
    Collect a dictionary of variables from a makefile
    --------------------------------------------------
    First arg is .mk file to use
    Second arg is make arguments needed to invoke correct output
        The output can be an assignment or a target
    Third arg is a verbosity flag
    Return a dictionary of variable names mapped to values from make

    OCPI_LOG_LEVEL>=6  will print stderr from make for user to see
    OCPI_LOG_LEVEL>=10 will pass OCPI_DEBUG_MAKE to make command and will
                       print both stdout and stderr for user to see
    """
    with open(os.devnull, 'w') as fnull:
        make_exists = subprocess.Popen(["which", "make"],\
                      stdout=subprocess.PIPE, stderr=fnull).communicate()[0]
        if make_exists is None or make_exists == "":
            if verbose != None and verbose != "":
                logging.error("The '\"make\"' command is not available.")
            return 1

        # If log level >= 10 set OCPI_DEBUG_MAKE=1 (max debug level)
        ocpi_log_level = int(os.environ.get('OCPI_LOG_LEVEL', 0))
        if ocpi_log_level >= 10:
            mk_dbg = "OCPI_DEBUG_MAKE=1"
        else:
            mk_dbg = ""

        # If mk_file is a "Makefile" then we use the -C option on the directory containing
        # the makefile else (is a .mk) use the -f option on the file
        if mk_file.endswith("/Makefile"):
            make_cmd = "make " + mk_dbg + " -n -r -s -C " + os.path.dirname(mk_file) + " " + mk_arg
        else:
            make_cmd = "make " + mk_dbg + " -n -r -s -f " + mk_file + " " + mk_arg

        logging.debug("Calling make via:" + str(make_cmd.split()))

        child = subprocess.Popen(make_cmd.split(), stderr=subprocess.PIPE, stdout=subprocess.PIPE,
                                 universal_newlines=True)
        mk_output, mk_err = child.communicate()

        # Print out output from make if log level is high
        logging.debug("STDOUT output from Make (set_vars_from_make):\n" + str(mk_output))

        # Print out stderr from make if log level is medium/high or if make returned error
        if child.returncode != 0 or ocpi_log_level >= 6:
            if mk_err:
                logging.error("STDERR output from Make (set_vars_from_make):\n" + str(mk_err))
            if child.returncode != 0:
                raise OCPIException("The following make command returned an error:\n" + make_cmd)

        try:
            grep_str = re.search(r'(^|\n)[a-zA-Z_][a-zA-Z_]*=.*',
                                 str(mk_output.strip())).group()
        except AttributeError:
            logging.warning("No variables are set from \"" + mk_file + "\"")
            return None

        assignment_strs = [x.strip() for x in grep_str.split(';') if len(x.strip()) > 0]
        make_vars = {}
        for var_assignment in assignment_strs:
            var_name, var_val = var_assignment.split('=')
            # If the value is an empty string or just matching quotes, assign [] as the value
            if var_val == "\"\"" or var_val == "\'\'" or var_val == "":
                assignment_value = []
            else:
                assignment_value = var_val.strip('"').strip().split(' ')
            make_vars[var_name] = assignment_value
        return make_vars