# EMACS settings: -*- tab-width: 2; indent-tabs-mode: t; python-indent-offset: 2 -*-
# vim: tabstop=2:shiftwidth=2:noexpandtab
# kate: tab-width 2; replace-tabs off; indent-width 2;
#
# ==============================================================================
# Authors: Patrick Lehmann
#
# Python Class: TODO
#
# License:
# ==============================================================================
# Copyright 2007-2016 Technische Universitaet Dresden - Germany
# Chair of VLSI-Design, Diagnostics and Architecture
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
#
# load dependencies
from collections import OrderedDict
from textwrap import dedent
from lib.Decorators import ILazyLoadable, LazyLoadTrigger
from Base.Exceptions import CommonException
from Base.Project import Project as BaseProject, File, FileTypes, VHDLSourceFile, VerilogSourceFile, CocotbSourceFile #, ProjectFile
from Parser.FilesParser import FilesParserMixIn
from Parser.RulesParser import RulesParserMixIn
from DataBase import __POC_SOLUTION_KEYWORD__
from DataBase.Entity import Visibility
from ToolChain import ConfigurationException
__api__ = [
'Base',
'Repository', 'Solution', 'Project',
'ISEProject', 'VivadoProject', 'QuartusProject', 'LatticeProject', 'VirtualProject',
'FileListFile', 'RulesFile'
]
__all__ = __api__
[docs]class Base(ILazyLoadable):
"""
Base class for Repository, Solution and Project.
It implements ILazyLoadable.
"""
def __init__(self, host, sectionPrefix, sectionID, parent):
ILazyLoadable.__init__(self)
self._host = host
self._id = sectionID
self._configSection = "{0}.{1}".format(sectionPrefix, sectionID)
self._parent = parent
self._Load()
@property
def ID(self): return self._id
@property
def Parent(self): return self._parent
@property
def ConfigSectionName(self): return self._configSection
[docs] def _Load(self):
"""Implement this method for early loading."""
pass
[docs]class Repository(Base):
def __init__(self, host):
self._solutions = {}
kind = "Public"
if host.PoCConfig.has_option("INSTALL.PoC", "RepositoryKind"):
kind = host.PoCConfig['INSTALL.PoC']['RepositoryKind']
self._kind = Visibility.Parse(kind)
super().__init__(host, "SOLUTION", "Solutions", None)
@property
def Kind(self):
return self._kind
[docs] def _Load(self):
self._LazyLoadable_Load()
def __contains__(self, item):
return (item.lower() in self._solutions)
def __getitem__(self, item):
return self._solutions[item.lower()]
[docs] def _LazyLoadable_Load(self):
super()._LazyLoadable_Load()
# load solutions
for slnID in self._host.PoCConfig[self._configSection]:
if (self._host.PoCConfig[self._configSection][slnID] == __POC_SOLUTION_KEYWORD__):
self._solutions[slnID.lower()] = Solution(self._host, slnID, self)
[docs] def AddSolution(self, solutionID, solutionName, solutionRootPath):
solution = Solution(self._host, solutionID, self)
solution.Name = solutionName
solution.Path = solutionRootPath
self._host.PoCConfig[self._configSection][solutionID] = __POC_SOLUTION_KEYWORD__
self._solutions[solutionID] = solution
solution.Register()
solution.CreateFiles()
return solution
[docs] def RemoveSolution(self, solution):
if isinstance(solution, str):
solution = self._solutions[solution.lower()]
elif (not isinstance(solution, Solution)):
raise ValueError("Parameter solution is not of type str or Solution.")
solution.Unregister()
self._host.PoCConfig.remove_option(self._configSection, solution.ID)
@property
@LazyLoadTrigger
def Solutions(self):
"""Returns the list of all registered solutions."""
return self._solutions.values()
@property
@LazyLoadTrigger
def SolutionNames(self):
"""Returns the identifier list of all registered solutions."""
return self._solutions.keys()
[docs]class Solution(Base):
__SOLUTION_CONFIG_FILE__ = "solution.config.ini"
__SOLUTION_DEFAULT_FILE__ = "solution.defaults.ini"
def __init__(self, host, slnID, parent):
super().__init__(host, "SOLUTION", slnID, parent)
self._name = None
self._path = None
self._projects = {}
[docs] def Register(self):
self._host.PoCConfig[self._configSection] = OrderedDict()
self._host.PoCConfig[self._configSection]['Name'] = self._name
self._host.PoCConfig[self._configSection]['Path'] = self._path.as_posix()
[docs] def Unregister(self):
self._host.PoCConfig.remove_section(self._configSection)
[docs] def CreateFiles(self):
solutionConfigPath = self._path / ".poc"
if (not self._path.is_absolute()):
solutionConfigPath = self._host.Directories.Root / solutionConfigPath
try:
solutionConfigPath.mkdir(parents=True)
except OSError as ex:
raise ConfigurationException("Error while creating '{0!s}'.".format(solutionConfigPath)) from ex
solutionConfigFile = solutionConfigPath / self.__SOLUTION_CONFIG_FILE__
with solutionConfigFile.open('w') as fileHandle:
fileContent = dedent("""\
[SOLUTION.{slnID}]
DefaultLibrary =
""".format(slnID=self._id))
fileHandle.write(fileContent)
solutionDefaultFile = solutionConfigPath / self.__SOLUTION_DEFAULT_FILE__
with solutionDefaultFile.open('w') as fileHandle:
fileContent = dedent("""\
[SOLUTION.DEFAULTS]
""")
fileHandle.write(fileContent)
[docs] def _LazyLoadable_Load(self):
super()._LazyLoadable_Load()
self._name = self._host.PoCConfig[self._configSection]['Name']
self._path = self._host.Directories.Root / self._host.PoCConfig[self._configSection]['Path']
solutionConfigPath = self._path / ".poc"
if (not self._path.is_absolute()):
solutionConfigPath = self._host.Directories.Root / solutionConfigPath
configFiles = [
solutionConfigPath / self.__SOLUTION_CONFIG_FILE__,
solutionConfigPath / self.__SOLUTION_DEFAULT_FILE__
]
for configFile in configFiles:
if (not configFile.exists()):
raise ConfigurationException("Solution configuration file '{0!s}' not found.".format(configFile)) from FileNotFoundError(str(configFile))
self._host.PoCConfig.read(str(configFile))
# load projects
for option in self._host.PoCConfig[self._configSection]:
project = None
if (self._host.PoCConfig[self._configSection][option] == "ISEProject"):
project = ISEProject(self._host, option, self)
elif (self._host.PoCConfig[self._configSection][option] == "VivadoProject"):
project = VivadoProject(self._host, option, self)
elif (self._host.PoCConfig[self._configSection][option] == "QuartusProject"):
project = QuartusProject(self._host, option, self)
elif (self._host.PoCConfig[self._configSection][option] == "LatticeProject"):
project = LatticeProject(self._host, option, self)
if (project is not None):
self._projects[option.lower()] = project
@property
@LazyLoadTrigger
def Name(self):
"""Gets the name of this solution."""
return self._name
@Name.setter
def Name(self, value):
"""Sets the name of this solution."""
self._name = value
@property
@LazyLoadTrigger
def Path(self):
"""Gets the path to the solution."""
return self._path
@Path.setter
def Path(self, value):
"""Sets the path of the solution."""
self._path = value
@property
@LazyLoadTrigger
def Projects(self):
"""Gets a list of all registered projects."""
return self._projects.values()
@property
@LazyLoadTrigger
def ProjectNames(self):
"""Gets a list of identifiers of all registered projects."""
return self._projects.keys()
[docs]class Project(Base):
def __init__(self, host, prjID, parent):
super().__init__(host, "PROJECT", prjID, parent)
self._name = None
@property
@LazyLoadTrigger
def Name(self):
"""Gets the name of this solution."""
return self._name
@Name.setter
def Name(self, value):
"""Sets the name of this solution."""
self._name = value
[docs]class ISEProject(Project):
pass
[docs]class VivadoProject(Project):
pass
[docs]class QuartusProject(Project):
pass
[docs]class LatticeProject(Project):
pass
[docs]class VirtualProject(BaseProject):
pass
[docs]class FileListFile(File, FilesParserMixIn):
_FileType = FileTypes.FileListFile
def __init__(self, file, project = None, fileSet = None):
super().__init__(file, project=project, fileSet=fileSet)
FilesParserMixIn.__init__(self)
self._variables = None
self._classFileListFile = FileListFile
self._classVHDLSourceFile = VHDLSourceFile
self._classVerilogSourceFile = VerilogSourceFile
self._classCocotbSourceFile = CocotbSourceFile
[docs] def Parse(self, host):
if (self._fileSet is None): raise CommonException("File '{0!s}' is not associated to a fileset.".format(self._file))
if (self._project is None): raise CommonException("File '{0!s}' is not associated to a project.".format(self._file))
if (self._project.RootDirectory is None): raise CommonException("No RootDirectory configured for this project.")
# prepare FilesParserMixIn environment
self._rootDirectory = self.Project.RootDirectory
self._variables = self.Project.GetVariables()
self._Parse()
self._Resolve(host)
[docs] def CopyFilesToFileSet(self):
for file in self._files:
self._fileSet.AddFile(file)
[docs] def CopyExternalLibraries(self):
for lib in self._libraries:
self._project.AddExternalVHDLLibraries(lib)
def __str__(self):
return "FileList file: '{0!s}".format(self._file)
[docs]class RulesFile(File, RulesParserMixIn):
_FileType = FileTypes.RulesFile
def __init__(self, file, project = None, fileSet = None):
super().__init__(file, project=project, fileSet=fileSet)
RulesParserMixIn.__init__(self)
self._variables = None
[docs] def Parse(self):
if (self._fileSet is None): raise CommonException("File '{0!s}' is not associated to a fileset.".format(self._file))
if (self._project is None): raise CommonException("File '{0!s}' is not associated to a project.".format(self._file))
if (self._project.RootDirectory is None): raise CommonException("No RootDirectory configured for this project.")
# prepare FilesParserMixIn environment
self._rootDirectory = self.Project.RootDirectory
self._variables = self.Project.GetVariables()
self._Parse()
self._Resolve()
def __str__(self):
return "FileList file: '{0!s}".format(self._file)