diff --git a/aeromancer/requirements/alembic/versions/17770a76e3c7_add_global_requirement_table.py b/aeromancer/requirements/alembic/versions/17770a76e3c7_add_global_requirement_table.py new file mode 100644 index 0000000..366ff45 --- /dev/null +++ b/aeromancer/requirements/alembic/versions/17770a76e3c7_add_global_requirement_table.py @@ -0,0 +1,30 @@ +"""add global_requirement table + +Revision ID: 17770a76e3c7 +Revises: 203851643975 +Create Date: 2014-11-12 12:58:13.309422 + +""" + +# revision identifiers, used by Alembic. +revision = '17770a76e3c7' +down_revision = '203851643975' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.create_table( + 'global_requirement', + sa.Column('id', sa.Integer, primary_key=True), + sa.Column('line_id', sa.Integer, + sa.ForeignKey('line.id', name='fk_requirement_line_id')), + sa.Column('name', sa.String()), + ) + pass + + +def downgrade(): + op.drop_table('global_requirement') + pass diff --git a/aeromancer/requirements/cli.py b/aeromancer/requirements/cli.py index b6e8db4..064d7a5 100644 --- a/aeromancer/requirements/cli.py +++ b/aeromancer/requirements/cli.py @@ -8,6 +8,8 @@ from aeromancer import utils from cliff.lister import Lister +from sqlalchemy import distinct + class List(Lister): """List the requirements for a project""" @@ -53,3 +55,18 @@ class Uses(Lister): ).order_by(models.Project.name) return (('Name', 'Spec', 'File'), ((r.project.name, r.line.content.strip(), r.line.file.name) for r in query.all())) + + +class Unused(Lister): + """List global requirements not used by any projects""" + + log = logging.getLogger(__name__) + + def take_action(self, parsed_args): + session = self.app.get_db_session() + used_requirements = session.query(distinct(req_models.Requirement.name)) + query = session.query(req_models.GlobalRequirement).filter( + req_models.GlobalRequirement.name.notin_(used_requirements) + ).order_by(req_models.GlobalRequirement.name) + return (('Name', 'Spec'), + ((r.name, r.line.content.strip()) for r in query.all())) diff --git a/aeromancer/requirements/handler.py b/aeromancer/requirements/handler.py index 00d5981..a3d96c9 100644 --- a/aeromancer/requirements/handler.py +++ b/aeromancer/requirements/handler.py @@ -2,8 +2,9 @@ import logging import pkg_resources +from aeromancer.db import models as models from aeromancer.filehandler import base -from . import models +from aeromancer.requirements import models as req_models LOG = logging.getLogger(__name__) @@ -37,7 +38,7 @@ class RequirementsHandler(base.FileHandler): parent_project = file_obj.project for dist_name, line in read_requirements_file(file_obj): LOG.debug('requirement: %s', dist_name) - new_r = models.Requirement( + new_r = req_models.Requirement( name=dist_name, line=line, project=parent_project, @@ -46,10 +47,33 @@ class RequirementsHandler(base.FileHandler): def delete_data_for_file(self, session, file_obj): LOG.debug('deleting requirements from %r', file_obj.path) - for line in file_obj.lines: - query = session.query(models.Requirement).filter( - models.Requirement.line_id == line.id - ) - for req in query.all(): - session.delete(req) + query = session.query(req_models.Requirement).join(models.Line).filter( + models.Line.file_id == file_obj.id + ) + for r in query.all(): + session.delete(r) + return + + +class GlobalRequirementsHandler(base.FileHandler): + + INTERESTING_PATTERNS = [ + 'global-requirements.txt', + ] + + def process_file(self, session, file_obj): + LOG.info('loading global requirements from %s', file_obj.project_path) + parent_project = file_obj.project + for dist_name, line in read_requirements_file(file_obj): + LOG.debug('global requirement: %s', dist_name) + new_r = req_models.GlobalRequirement( + name=dist_name, + line=line, + ) + session.add(new_r) + + def delete_data_for_file(self, session, file_obj): + LOG.debug('deleting global requirements from %r', file_obj.path) + query = session.query(req_models.GlobalRequirement) + query.delete() return diff --git a/aeromancer/requirements/models.py b/aeromancer/requirements/models.py index c6871d2..b2535ea 100644 --- a/aeromancer/requirements/models.py +++ b/aeromancer/requirements/models.py @@ -19,3 +19,15 @@ class Requirement(models.Base): models.Project, backref='requirements', ) + + +class GlobalRequirement(models.Base): + __tablename__ = 'global_requirement' + id = Column(Integer, primary_key=True) + name = Column(String, nullable=False) + line_id = Column(Integer, ForeignKey('line.id')) + line = relationship( + models.Line, + uselist=False, + single_parent=True, + ) diff --git a/setup.cfg b/setup.cfg index ee343a6..b74ae8d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -56,7 +56,9 @@ aeromancer.cli = rescan = aeromancer.cli.project:Rescan discover = aeromancer.cli.project:Discover requirements list = aeromancer.requirements.cli:List + requirements unused = aeromancer.requirements.cli:Unused what uses = aeromancer.requirements.cli:Uses aeromancer.filehandler = requirements = aeromancer.requirements.handler:RequirementsHandler + global_requirements = aeromancer.requirements.handler:GlobalRequirementsHandler