Skip to content
Snippets Groups Projects
Commit 89147d23 authored by Jonathan Maw's avatar Jonathan Maw
Browse files

_workspaces.py: Add a WorkspaceProject object

WorkspaceProject contains all the information needed to refer back to a
project from its workspace (currently this is the project path and the
element used to create this workspace)

This is stored within a WorkspaceProjectCache object, which keeps
WorkspaceProjects around so they don't need to be loaded from disk
repeatedly.

This is a part of #222
parent 7805a7ce
No related branches found
No related tags found
Loading
......@@ -25,6 +25,219 @@ from ._exceptions import LoadError, LoadErrorReason
BST_WORKSPACE_FORMAT_VERSION = 3
BST_WORKSPACE_PROJECT_FORMAT_VERSION = 1
WORKSPACE_PROJECT_FILE = ".bstproject.yaml"
# WorkspaceProject()
#
# An object to contain various helper functions and data required for
# referring from a workspace back to buildstream.
#
# Args:
# directory (str): The directory that the workspace exists in.
#
class WorkspaceProject():
def __init__(self, directory):
self._projects = []
self._directory = directory
# get_default_project_path()
#
# Retrieves the default path to a project.
#
# Returns:
# (str): The path to a project
#
def get_default_project_path(self):
return self._projects[0]['project-path']
# get_default_element()
#
# Retrieves the name of the element that owns this workspace.
#
# Returns:
# (str): The name of an element
#
def get_default_element(self):
return self._projects[0]['element-name']
# to_dict()
#
# Turn the members data into a dict for serialization purposes
#
# Returns:
# (dict): A dict representation of the WorkspaceProject
#
def to_dict(self):
ret = {
'projects': self._projects,
'format-version': BST_WORKSPACE_PROJECT_FORMAT_VERSION,
}
return ret
# from_dict()
#
# Loads a new WorkspaceProject from a simple dictionary
#
# Args:
# directory (str): The directory that the workspace exists in
# dictionary (dict): The dict to generate a WorkspaceProject from
#
# Returns:
# (WorkspaceProject): A newly instantiated WorkspaceProject
#
@classmethod
def from_dict(cls, directory, dictionary):
# Only know how to handle one format-version at the moment.
format_version = int(dictionary['format-version'])
assert format_version == BST_WORKSPACE_PROJECT_FORMAT_VERSION, \
"Format version {} not found in {}".format(BST_WORKSPACE_PROJECT_FORMAT_VERSION, dictionary)
workspace_project = cls(directory)
for item in dictionary['projects']:
workspace_project.add_project(item['project-path'], item['element-name'])
return workspace_project
# load()
#
# Loads the WorkspaceProject for a given directory. This directory may be a
# subdirectory of the workspace's directory.
#
# Args:
# directory (str): The directory
# Returns:
# (WorkspaceProject): The created WorkspaceProject, if in a workspace, or
# (NoneType): None, if the directory is not inside a workspace.
#
@classmethod
def load(cls, directory):
project_dir = cls.search_for_dir(directory)
if project_dir:
workspace_file = os.path.join(project_dir, WORKSPACE_PROJECT_FILE)
data_dict = _yaml.load(workspace_file)
return cls.from_dict(project_dir, data_dict)
else:
return None
# write()
#
# Writes the WorkspaceProject to disk
#
def write(self):
os.makedirs(self._directory, exist_ok=True)
_yaml.dump(self.to_dict(), self.get_filename())
# search_for_dir()
#
# Returns the directory that contains the workspace local project file,
# searching upwards from search_dir.
#
@staticmethod
def search_for_dir(search_dir):
return utils._search_upward_for_file(search_dir, WORKSPACE_PROJECT_FILE)
# get_filename()
#
# Returns the full path to the workspace local project file
#
def get_filename(self):
return os.path.join(self._directory, WORKSPACE_PROJECT_FILE)
# add_project()
#
# Adds an entry containing the project's path and element's name.
#
# Args:
# project_path (str): The path to the project that opened the workspace.
# element_name (str): The name of the element that the workspace belongs to.
#
def add_project(self, project_path, element_name):
assert (project_path and element_name)
self._projects.append({'project-path': project_path, 'element-name': element_name})
# WorkspaceProjectCache()
#
# A class to manage workspace project data for multiple workspaces.
#
class WorkspaceProjectCache():
def __init__(self):
self._projects = {} # Mapping of a workspace directory to its WorkspaceProject
# get()
#
# Returns a WorkspaceProject for a given directory, retrieving from the cache if
# present, and searching the filesystem for the file and loading it if not.
#
# Args:
# directory (str): The directory to search for a WorkspaceProject.
#
# Returns:
# (WorkspaceProject): The WorkspaceProject that was found for that directory.
# or (NoneType): None, if no WorkspaceProject can be found.
#
def get(self, directory):
try:
workspace_project = self._projects[directory]
except KeyError:
found_dir = WorkspaceProject.search_for_dir(directory)
if found_dir:
try:
workspace_project = self._projects[found_dir]
except KeyError:
workspace_project = WorkspaceProject.load(found_dir)
self._projects[found_dir] = workspace_project
else:
workspace_project = None
return workspace_project
# add()
#
# Adds the project path and element name to the WorkspaceProject that exists
# for that directory
#
# Args:
# directory (str): The directory to search for a WorkspaceProject.
# project_path (str): The path to the project that refers to this workspace
# element_name (str): The element in the project that was refers to this workspace
#
# Returns:
# (WorkspaceProject): The WorkspaceProject that was found for that directory.
#
def add(self, directory, project_path, element_name):
workspace_project = self.get(directory)
if not workspace_project:
workspace_project = WorkspaceProject(directory)
self._projects[directory] = workspace_project
workspace_project.add_project(project_path, element_name)
return workspace_project
# remove()
#
# Removes the project path and element name from the WorkspaceProject that exists
# for that directory.
#
# NOTE: This currently just deletes the file, but with support for multiple
# projects opening the same workspace, this will involve decreasing the count
# and deleting the file if there are no more projects.
#
# Args:
# directory (str): The directory to search for a WorkspaceProject.
#
def remove(self, directory):
workspace_project = self.get(directory)
if not workspace_project:
raise LoadError(LoadErrorReason.MISSING_FILE,
"Failed to find a {} file to remove".format(WORKSPACE_PROJECT_FILE))
path = workspace_project.get_filename()
try:
os.unlink(path)
except FileNotFoundError:
pass
# Workspace()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment