<commit_before>#Distributed under the MIT licesnse.
#Copyright (c) 2011 <NAME> (<EMAIL>)

#Permission is hereby granted, free of charge, to any person obtaining a copy of
#this software and associated documentation files (the "Software"), to deal in
#the Software without restriction, including without limitation the rights to
#use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
#of the Software, and to permit persons to whom the Software is furnished to do
#so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all
#copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.

"""Generates FPGA Projects

This class is used to generate projects given a configuration file
"""

"""Changes:
    06/07/2012:
        -Added Documentation and licsense
    07/17/2013:
        -Cleaning up code

"""

__author__ = '<EMAIL> (<NAME>)'

import sys
import os
import shutil
import json
import collections

import utils
import arbiter
from module_processor import ModuleProcessor
from ibuilder_error import ModuleFactoryError
from ibuilder_error import ProjectGeneratorError as PGE

sys.path.append(os.path.join(os.path.dirname(__file__),
                             os.path.pardir,
                             os.path.pardir))

from common import site_manager
from common import status


def get_project_tags(config_filename):
    f = open(config_filename, "r")
    tags = json.load(f, object_pairs_hook = collections.OrderedDict)
    f.close()
    return tags

def get_output_dir(config_filename, debug = False):
    tags = get_project_tags(config_filename)
    return utils.resolve_path(tags["BASE_DIR"])

def generate_project(filename, user_paths = [], output_directory = None, status = None):
    """Generate a FPGA project

    The type of phroject is specific to the vendor called. For example, if the
    configuration file specified that the vendor is Xilinx then the generated
    project would be a PlanAhead project

    Args:
      filename: Name of the configuration file to be read
      user_paths: Paths used to search for modules
      output_directory: Path to override default output directory

    Returns:
      A result of success or fail
        True = Success
        False = Fail

    Raises:
      IOError: An error in project generation has occured
    """
    tags = get_project_tags(filename)

    if not utils.board_exists(tags["board"]):
        utils.install_remote_board_package(tags["board"], status = status)

    utils.clean_verilog_package_paths()
    if len(utils.get_local_verilog_paths()) == 0:
        utils.update_verilog_package()

    pg = ProjectGenerator(user_paths, status = status)
    result = pg.generate_project(filename, output_directory = output_directory)
    return result


class ProjectGenerator(object):
    """Generates IBuilder Projects"""

    def __init__(self, user_paths = [], status = None):
        self.user_paths = user_paths
        self.filegen = ModuleProcessor(user_paths = self.user_paths)
        self.project_tags = {}
        self.template_tags = {}
        self.s = status

    def _get_default_board_config(self, board):
        path = os.path.join(utils.get_board_directory(board), board)
        bd = utils.get_board_config(board)
        name = "default.json"
        if "default_project" in bd:
            name = bd["default_project"]
            
        default_path = os.path.join(path, "board", name)
        #print "Path: %s" % default_path

        board_dict = json.load(open(default_path, "r"), object_pairs_hook=collections.OrderedDict)
        if "parent_board" in bd:
            for parent in bd["parent_board"]:
                pd = utils.get_board_config(parent)
                name = "default.json"
                if "default_project" in pd:
                    name = pd["default_project"]

                path = os.path.join(utils.get_board_directory(parent), parent)
                default_path = os.path.join(path, "board", name)
                parent_dict = json.load(open(default_path, "r"), object_pairs_hook=collections.OrderedDict)

                for key in parent_dict:
                    #print "key: %s" % key
                    if key in board_dict:
                        if isinstance(board_dict[key], list):
                            #print "board_dict  [%s]: %s" % (key, str(board_dict[key]))
                            #print "parent_dict [%s]: %s" % (key, str(parent_dict[key]))
                            l = parent_dict[key] + board_dict[key]
                            #print "L: %s" % l
                            #Remove duplicates
                            board_dict[key] = list(set(l))
                    else:
                        board_dict[key] = parent_dict[key]
        #print "board dict: %s" % str(board_dict)
        return board_dict
        
    def read_config_file(self, filename="", debug=False):
        """Read in a configuration file name and create a class dictionary

        Args:
          filename: the filename of the configuration file to read in

        Return:
          Nothing

        Raises:
          TypeError
        """
        #try:
        if self.s: self.s.Verbose("Reading configuration file: %s" % filename)
        self.project_tags = json.load(open(filename, "r"), object_pairs_hook=collections.OrderedDict)
        path = os.path.join(utils.get_board_directory(self.project_tags["board"]), self.project_tags["board"])
        board_dict = self._get_default_board_config(self.project_tags["board"])

        #default_path = os.path.join(path, "board", "default.json")
        #board_dict = json.load(open(default_path, "r"), object_pairs_hook=collections.OrderedDict)
        for key in board_dict:
            #print "key: %s" % key
            if key not in self.project_tags:
                if self.s: self.s.Important("Injecting default board key (%s) into project configuration" % key)
                self.project_tags[key] = board_dict[key]
        #except IOError as err:
        #    if self.s: self.s.Fatal("Error while loadng the project tags: %s" % str(err))
        #    raise PGE("Error while loadng the project tags: %s" % str(err))
        #except TypeError as err:
        #    if self.s: self.s.Fatal("Error reading the tags in the project file: %s" % str(err))
        #    raise PGE("Error reading the tags in the project file: %s" % str(err))

    def read_template_file(self, filename, debug=False):
        """Attemp to read in template file

        If we can't find the template file immediately then search for it in
        the default template directory, if it's not there raise an Error

        Args:
            filename (string): Path to the template file

        Return:
            Nothing

        Raises:
            ProjectGeneratorError:
                Unable to find the template.json file
                Error while loading the template.json file
        """
        if not filename.endswith(".json"):
            filename = "%s.json" % filename
        if not os.path.exists(filename):
            test_path = os.path.join(utils.get_nysa_base(),
                                    "ibuilder",
                                    "templates",
                                    filename)
            if os.path.exists(test_path):
                filename = test_path
            else:
                if self.s: self.s.Fatal("Can't find template file at: %s" % (filename))
                raise PGE("Can't find template file at: %s" % (filename))
        try:
            if self.s: self.s.Verbose("Loading template file: %s" % filename)
            self.template_tags = json.load(open(filename, "r"))
        except IOError as err:
            if self.s: self.s.Fatal("Error while loading the template tags: %s" % str(err))
            raise PGE("Error while loading the template tags: %s" % str(err))
        except TypeError as err:
            if self.s: self.s.Fatal("Error reading the tags in the template file: %s" % str(err))
            raise PGE("Error reading the tags in the template file: %s" % str(err))
        except ValueError as err:
            if self.s: self.s.Fatal("Error parsing JSON in template file: %s" % str(err))
            raise PGE("Error parsing JSON in template file: %s" % str(err))

        #Fix all paths to be compatible with the OS and
        #Replace all "${NYSA}" with a
        #print "Replace NYSA name with real paths"
        utils.recursive_dict_name_fix(self.template_tags)

    def generate_project(self, config_filename, output_directory = None):
        """Generate the folders and files for the project

        Using the project tags and template tags this function generates all
        the directories and files of the project. It will go through the template
        structure and determine what files need to be added and call either
        a generation script (in the case of \"top.v\") or simply copy the file
        over (in the case of a peripheral or memory module.

        Args:
          config_filename: name of the JSON configuration file
            output_directory: Path to override default output directory

        Return:
          True: Success
          False: Failure

        Raises:
          TypeError
          IOError
          SapError
        """
        status = self.s
        if status: status.Debug("Openning site manager")

        sm = site_manager.SiteManager()
        path_dicts = sm.get_paths_dict()

        self.read_config_file(config_filename)
        path_dict = sm.get_paths_dict()
        if output_directory is not None:
            self.project_tags["BASE_DIR"] = output_directory

        board_dict = utils.get_board_config(self.project_tags["board"])
        cfiles = []
        cpaths = []

        if "paths" in board_dict:
            self.user_paths.extend(board_dict["paths"])

        pt = self.project_tags
        if "constraint_files" not in pt.keys():
            pt["constraint_files"] = []

        cfiles = pt["constraint_files"]
        for c in cfiles:
            cpaths.append(utils.get_constraint_file_path(self.project_tags["board"], c))
            #cpaths.append(utils.get_constraint_file_path(c))

        #if the user didn't specify any constraint files
        #load the default
        if len(cfiles) == 0:
            if status: status.Debug("loading default constraints for: %s" % board_dict["board_name"])
            cfiles = board_dict["default_constraint_files"]
            for c in cfiles:
                cpaths.append(utils.get_constraint_file_path(self.project_tags["board"], c))
                #cpaths.append(utils.get_constraint_file_path(c))


        #extrapolate the bus template
        clock_rate = ""
        for c in cpaths:
            clock_rate = utils.read_clock_rate(c)
            if len(clock_rate) > 0:
                #First place I can find the clock rate drop out
                break

        if len (clock_rate) == 0:
            if self.s: self.s.Fatal("Unable to find the clock rate in any of the constraint"
                      "files: %s" % str(cpaths))
            raise PGE("Unable to find the clock rate in any of the constraint"
                      "files: %s" % str(cpaths))

        #self.project_tags["CLOCK_RATE"] = utils.read_clock_rate(cpaths[0])
        self.project_tags["CLOCK_RATE"] = clock_rate<commit_msg>Added a check for the clock rate within the board config<commit_after>#Distributed under the MIT licesnse.
#Copyright (c) 2011 <NAME> (<EMAIL>)

#Permission is hereby granted, free of charge, to any person obtaining a copy of
#this software and associated documentation files (the "Software"), to deal in
#the Software without restriction, including without limitation the rights to
#use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
#of the Software, and to permit persons to whom the Software is furnished to do
#so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in all
#copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.

"""Generates FPGA Projects

This class is used to generate projects given a configuration file
"""

"""Changes:
    06/07/2012:
        -Added Documentation and licsense
    07/17/2013:
        -Cleaning up code

"""

__author__ = '<EMAIL> (<NAME>)'

import sys
import os
import shutil
import json
import collections

import utils
import arbiter
from module_processor import ModuleProcessor
from ibuilder_error import ModuleFactoryError
from ibuilder_error import ProjectGeneratorError as PGE

sys.path.append(os.path.join(os.path.dirname(__file__),
                             os.path.pardir,
                             os.path.pardir))

from common import site_manager
from common import status


def get_project_tags(config_filename):
    f = open(config_filename, "r")
    tags = json.load(f, object_pairs_hook = collections.OrderedDict)
    f.close()
    return tags

def get_output_dir(config_filename, debug = False):
    tags = get_project_tags(config_filename)
    return utils.resolve_path(tags["BASE_DIR"])

def generate_project(filename, user_paths = [], output_directory = None, status = None):
    """Generate a FPGA project

    The type of phroject is specific to the vendor called. For example, if the
    configuration file specified that the vendor is Xilinx then the generated
    project would be a PlanAhead project

    Args:
      filename: Name of the configuration file to be read
      user_paths: Paths used to search for modules
      output_directory: Path to override default output directory

    Returns:
      A result of success or fail
        True = Success
        False = Fail

    Raises:
      IOError: An error in project generation has occured
    """
    tags = get_project_tags(filename)

    if not utils.board_exists(tags["board"]):
        utils.install_remote_board_package(tags["board"], status = status)

    utils.clean_verilog_package_paths()
    if len(utils.get_local_verilog_paths()) == 0:
        utils.update_verilog_package()

    pg = ProjectGenerator(user_paths, status = status)
    result = pg.generate_project(filename, output_directory = output_directory)
    return result


class ProjectGenerator(object):
    """Generates IBuilder Projects"""

    def __init__(self, user_paths = [], status = None):
        self.user_paths = user_paths
        self.filegen = ModuleProcessor(user_paths = self.user_paths)
        self.project_tags = {}
        self.template_tags = {}
        self.s = status

    def _get_default_board_config(self, board):
        path = os.path.join(utils.get_board_directory(board), board)
        bd = utils.get_board_config(board)
        name = "default.json"
        if "default_project" in bd:
            name = bd["default_project"]
            
        default_path = os.path.join(path, "board", name)
        #print "Path: %s" % default_path

        board_dict = json.load(open(default_path, "r"), object_pairs_hook=collections.OrderedDict)
        if "parent_board" in bd:
            for parent in bd["parent_board"]:
                pd = utils.get_board_config(parent)
                name = "default.json"
                if "default_project" in pd:
                    name = pd["default_project"]

                path = os.path.join(utils.get_board_directory(parent), parent)
                default_path = os.path.join(path, "board", name)
                parent_dict = json.load(open(default_path, "r"), object_pairs_hook=collections.OrderedDict)

                for key in parent_dict:
                    #print "key: %s" % key
                    if key in board_dict:
                        if isinstance(board_dict[key], list):
                            #print "board_dict  [%s]: %s" % (key, str(board_dict[key]))
                            #print "parent_dict [%s]: %s" % (key, str(parent_dict[key]))
                            l = parent_dict[key] + board_dict[key]
                            #print "L: %s" % l
                            #Remove duplicates
                            board_dict[key] = list(set(l))
                    else:
                        board_dict[key] = parent_dict[key]
        #print "board dict: %s" % str(board_dict)
        return board_dict
        
    def read_config_file(self, filename="", debug=False):
        """Read in a configuration file name and create a class dictionary

        Args:
          filename: the filename of the configuration file to read in

        Return:
          Nothing

        Raises:
          TypeError
        """
        #try:
        if self.s: self.s.Verbose("Reading configuration file: %s" % filename)
        self.project_tags = json.load(open(filename, "r"), object_pairs_hook=collections.OrderedDict)
        path = os.path.join(utils.get_board_directory(self.project_tags["board"]), self.project_tags["board"])
        board_dict = self._get_default_board_config(self.project_tags["board"])

        #default_path = os.path.join(path, "board", "default.json")
        #board_dict = json.load(open(default_path, "r"), object_pairs_hook=collections.OrderedDict)
        for key in board_dict:
            #print "key: %s" % key
            if key not in self.project_tags:
                if self.s: self.s.Important("Injecting default board key (%s) into project configuration" % key)
                self.project_tags[key] = board_dict[key]
        #except IOError as err:
        #    if self.s: self.s.Fatal("Error while loadng the project tags: %s" % str(err))
        #    raise PGE("Error while loadng the project tags: %s" % str(err))
        #except TypeError as err:
        #    if self.s: self.s.Fatal("Error reading the tags in the project file: %s" % str(err))
        #    raise PGE("Error reading the tags in the project file: %s" % str(err))

    def read_template_file(self, filename, debug=False):
        """Attemp to read in template file

        If we can't find the template file immediately then search for it in
        the default template directory, if it's not there raise an Error

        Args:
            filename (string): Path to the template file

        Return:
            Nothing

        Raises:
            ProjectGeneratorError:
                Unable to find the template.json file
                Error while loading the template.json file
        """
        if not filename.endswith(".json"):
            filename = "%s.json" % filename
        if not os.path.exists(filename):
            test_path = os.path.join(utils.get_nysa_base(),
                                    "ibuilder",
                                    "templates",
                                    filename)
            if os.path.exists(test_path):
                filename = test_path
            else:
                if self.s: self.s.Fatal("Can't find template file at: %s" % (filename))
                raise PGE("Can't find template file at: %s" % (filename))
        try:
            if self.s: self.s.Verbose("Loading template file: %s" % filename)
            self.template_tags = json.load(open(filename, "r"))
        except IOError as err:
            if self.s: self.s.Fatal("Error while loading the template tags: %s" % str(err))
            raise PGE("Error while loading the template tags: %s" % str(err))
        except TypeError as err:
            if self.s: self.s.Fatal("Error reading the tags in the template file: %s" % str(err))
            raise PGE("Error reading the tags in the template file: %s" % str(err))
        except ValueError as err:
            if self.s: self.s.Fatal("Error parsing JSON in template file: %s" % str(err))
            raise PGE("Error parsing JSON in template file: %s" % str(err))

        #Fix all paths to be compatible with the OS and
        #Replace all "${NYSA}" with a
        #print "Replace NYSA name with real paths"
        utils.recursive_dict_name_fix(self.template_tags)

    def generate_project(self, config_filename, output_directory = None):
        """Generate the folders and files for the project

        Using the project tags and template tags this function generates all
        the directories and files of the project. It will go through the template
        structure and determine what files need to be added and call either
        a generation script (in the case of \"top.v\") or simply copy the file
        over (in the case of a peripheral or memory module.

        Args:
          config_filename: name of the JSON configuration file
            output_directory: Path to override default output directory

        Return:
          True: Success
          False: Failure

        Raises:
          TypeError
          IOError
          SapError
        """
        status = self.s
        if status: status.Debug("Openning site manager")

        sm = site_manager.SiteManager()
        path_dicts = sm.get_paths_dict()

        self.read_config_file(config_filename)
        path_dict = sm.get_paths_dict()
        if output_directory is not None:
            self.project_tags["BASE_DIR"] = output_directory

        board_dict = utils.get_board_config(self.project_tags["board"])
        cfiles = []
        cpaths = []

        if "paths" in board_dict:
            self.user_paths.extend(board_dict["paths"])

        pt = self.project_tags
        if "constraint_files" not in pt.keys():
            pt["constraint_files"] = []

        cfiles = pt["constraint_files"]
        for c in cfiles:
            cpaths.append(utils.get_constraint_file_path(self.project_tags["board"], c))
            #cpaths.append(utils.get_constraint_file_path(c))

        #if the user didn't specify any constraint files
        #load the default
        if len(cfiles) == 0:
            if status: status.Debug("loading default constraints for: %s" % board_dict["board_name"])
            cfiles = board_dict["default_constraint_files"]
            for c in cfiles:
                cpaths.append(utils.get_constraint_file_path(self.project_tags["board"], c))
                #cpaths.append(utils.get_constraint_file_path(c))


        #extrapolate the bus template
        clock_rate = ""
        if "clockrate" in board_dict:
            if self.s: self.s.Info("User Specified a clockrate of: %d" % board_dict["clockrate"])
            clock_rate = board_dict["clockrate"]
        if len(clock_rate) == 0:
            for c in cpaths:
                clock_rate = utils.read_clock_rate(c)
                if len(clock_rate) > 0:
                    #First place I can find the clock rate drop out
                    break

        if len (clock_rate) == 0:
            if self.s: self.s.Fatal("Unable to find the clock rate in any of the constraint"
                      "files: %s" % str(cpaths))
            raise PGE("Unable to find the clock rate in any of the constraint"
                      "files: %s" % str(cpaths))

        #self.project_tags["CLOCK_RATE"] = utils.read_clock_rate(cpaths[0])
        self.project_tags["CLOCK_RATE"] = clock_rate
{'fraction_non_alphanumeric': 0.08855228662976988, 'fraction_numerical': 0.0021222587491157253, 'mean_word_length': 2.3299154773451574, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7123762', 'n_tokens_mistral': 6739, 'n_tokens_neox': 6473, 'n_words': 2149}