create ProjectManager class to avoid reloading plugins

This commit is contained in:
Doug Hellmann 2014-11-11 23:20:02 +00:00
parent ef76f4b15c
commit 053acaab52
2 changed files with 109 additions and 122 deletions

View File

@ -27,9 +27,10 @@ class Add(Command):
def take_action(self, parsed_args):
session = self.app.get_db_session()
pm = project.ProjectManager(session)
for project_name in parsed_args.project:
project_path = os.path.join(self.app.options.repo_root, project_name)
proj_obj = project.add_or_update(session, project_name, project_path)
pm.add_or_update(project_name, project_path)
session.commit()
@ -65,10 +66,11 @@ class Discover(Command):
def take_action(self, parsed_args):
session = self.app.get_db_session()
pm = project.ProjectManager(session)
for project_name in project.discover(self.app.options.repo_root):
full_path = os.path.join(self.app.options.repo_root,
project_name)
project.add_or_update(session, project_name, full_path)
pm.add_or_update(project_name, full_path)
session.commit()
@ -90,6 +92,7 @@ class Remove(Command):
def take_action(self, parsed_args):
session = self.app.get_db_session()
pm = project.ProjectManager(session)
for project_name in parsed_args.project:
project.remove(session, project_name)
session.commit()
pm.remove(project_name)
session.commit()

View File

@ -16,48 +16,16 @@ from aeromancer import utils
LOG = logging.getLogger(__name__)
def _delete_filehandler_data_from_project(session, proj_obj):
# We have to explicitly have the handlers delete their data
# because the parent-child relationship of the tables is reversed
# because the plugins define the relationships.
file_handlers = filehandler.load_handlers()
LOG.debug('deleting plugin data for %s', proj_obj.name)
for file_obj in proj_obj.files:
for fh in file_handlers:
if fh.obj.supports_file(file_obj):
fh.obj.delete_data_for_file(session, file_obj)
def add_or_update(session, name, path):
"""Create a new project definition or update an existing one"""
query = session.query(Project).filter(Project.name == name)
try:
proj_obj = query.one()
proj_obj.path = path
LOG.info('updating project %s from %s', name, path)
except NoResultFound:
proj_obj = Project(name=name, path=path)
LOG.info('adding project %s from %s', name, path)
session.add(proj_obj)
update(session, proj_obj)
return proj_obj
def remove(session, name):
"""Delete stored data for the named project"""
query = session.query(Project).filter(Project.name == name)
try:
proj_obj = query.one()
LOG.info('removing project %s', name)
except NoResultFound:
return
_delete_filehandler_data_from_project(session, proj_obj)
session.delete(proj_obj)
def update(session, proj_obj):
_update_project_files(session, proj_obj)
def discover(repo_root):
"""Discover project-like directories under the repository root"""
with utils.working_dir(repo_root):
return itertools.ifilter(
lambda x: os.path.isdir(os.path.join(repo_root, x)),
itertools.chain(
glob.glob('openstack*/*'),
glob.glob('stackforge/*'),
)
)
def _find_files_in_project(path):
"""Return a list of the files managed in the project.
@ -71,88 +39,104 @@ def _find_files_in_project(path):
return output.split('\0')
_DO_NOT_READ = [
'*.doc',
'*.docx',
'*.graffle',
'*.odp',
'*.pptx',
'*.vsd',
class ProjectManager(object):
'*.gif',
'*.ico',
'*.jpeg',
'*.jpg',
'*.png',
'*.ttf',
_DO_NOT_READ = [
'*.doc', '*.docx', '*.graffle', '*.odp', '*.pptx', '*.vsd',
'*.gif', '*.ico', '*.jpeg', '*.jpg', '*.png', '*.ttf',
'*.gpg',
'*.jar', # Why do we check in jar files?!
'*.swf', '*.eot',
'*.woff', # webfont; horizon
'*.xml',
'*.gz', '*.zip', '*.z',
]
'*.gpg',
def __init__(self, session):
self.file_handlers = filehandler.load_handlers()
self.session = session
'*.jar', # Why do we check in jar files?!
def _delete_filehandler_data_from_project(self, proj_obj):
# We have to explicitly have the handlers delete their data
# because the parent-child relationship of the tables is reversed
# because the plugins define the relationships.
LOG.debug('deleting plugin data for %s', proj_obj.name)
for file_obj in proj_obj.files:
for fh in self.file_handlers:
if fh.obj.supports_file(file_obj):
fh.obj.delete_data_for_file(self.session, file_obj)
'*.swf',
'*.eot',
'*.woff', # webfont; horizon
def get_project(self, name):
"""Return an existing project, if there is one"""
query = self.session.query(Project).filter(Project.name == name)
try:
return query.one()
except NoResultFound:
return None
'*.xml',
'*.gz',
'*.zip',
'*.z',
]
def _update_project_files(session, proj_obj):
"""Update the files stored for each project"""
LOG.debug('reading file contents in %s', proj_obj.name)
# Delete any existing files in case the list of files being
# managed has changed. This naive, and we can do better, but as a
# first version it's OK.
_delete_filehandler_data_from_project(session, proj_obj)
for file_obj in proj_obj.files:
session.delete(file_obj)
file_handlers = filehandler.load_handlers()
# FIXME(dhellmann): Concurrency?
# Now load the files currently being managed by git.
for filename in _find_files_in_project(proj_obj.path):
fullname = os.path.join(proj_obj.path, filename)
if not os.path.isfile(fullname):
continue
new_file = File(project=proj_obj, name=filename, path=fullname)
session.add(new_file)
if any(fnmatch.fnmatch(filename, dnr) for dnr in _DO_NOT_READ):
LOG.debug('ignoring contents of %s', fullname)
def add_or_update(self, name, path):
"""Create a new project definition or update an existing one"""
proj_obj = self.get_project(name)
if proj_obj:
proj_obj.path = path
LOG.info('updating project %s from %s', name, path)
else:
with io.open(fullname, mode='r', encoding='utf-8') as f:
try:
body = f.read()
except UnicodeDecodeError:
# FIXME(dhellmann): Be smarter about trying other
# encodings?
LOG.warn('Could not read %s as a UTF-8 encoded file, ignoring',
fullname)
continue
lines = body.splitlines()
LOG.debug('%s/%s has %s lines', proj_obj.name, filename, len(lines))
for num, content in enumerate(lines, 1):
session.add(Line(file=new_file, number=num, content=content))
proj_obj = Project(name=name, path=path)
LOG.info('adding project %s from %s', name, path)
self.session.add(proj_obj)
self.update(proj_obj)
return proj_obj
# Invoke plugins for processing files in special ways
for fh in file_handlers:
if fh.obj.supports_file(new_file):
fh.obj.process_file(session, new_file)
def update(self, proj_obj):
"""Update the settings for an existing project"""
self._update_project_files(proj_obj)
def remove(self, name):
"""Delete stored data for the named project"""
query = self.session.query(Project).filter(Project.name == name)
try:
proj_obj = query.one()
LOG.info('removing project %s', name)
except NoResultFound:
return
self._delete_filehandler_data_from_project(proj_obj)
self.session.delete(proj_obj)
def discover(repo_root):
"""Discover project-like directories under the repository root"""
with utils.working_dir(repo_root):
return itertools.ifilter(
lambda x: os.path.isdir(os.path.join(repo_root, x)),
itertools.chain(
glob.glob('openstack*/*'),
glob.glob('stackforge/*'),
)
)
def _update_project_files(self, proj_obj):
"""Update the files stored for each project"""
LOG.debug('reading file contents in %s', proj_obj.name)
# Delete any existing files in case the list of files being
# managed has changed. This naive, and we can do better, but as a
# first version it's OK.
self._delete_filehandler_data_from_project(proj_obj)
for file_obj in proj_obj.files:
self.session.delete(file_obj)
# Now load the files currently being managed by git.
for filename in _find_files_in_project(proj_obj.path):
fullname = os.path.join(proj_obj.path, filename)
if not os.path.isfile(fullname):
continue
new_file = File(project=proj_obj, name=filename, path=fullname)
self.session.add(new_file)
if any(fnmatch.fnmatch(filename, dnr) for dnr in self._DO_NOT_READ):
LOG.debug('ignoring contents of %s', fullname)
else:
with io.open(fullname, mode='r', encoding='utf-8') as f:
try:
body = f.read()
except UnicodeDecodeError:
# FIXME(dhellmann): Be smarter about trying other
# encodings?
LOG.warn('Could not read %s as a UTF-8 encoded file, ignoring',
fullname)
continue
lines = body.splitlines()
LOG.debug('%s/%s has %s lines', proj_obj.name, filename, len(lines))
for num, content in enumerate(lines, 1):
self.session.add(Line(file=new_file, number=num, content=content))
# Invoke plugins for processing files in special ways
for fh in self.file_handlers:
if fh.obj.supports_file(new_file):
fh.obj.process_file(self.session, new_file)