from abc import ABCMeta, abstractmethod, abstractproperty import inspect import pip import sys import os import re BASE_DIR = os.path.abspath(os.path.dirname(__file__)) class BaseCommand: __metaclass__ = ABCMeta @abstractproperty def verbose_name(self): pass @abstractproperty def help(self): pass @abstractmethod def run(self): pass class Migrations(BaseCommand): verbose_name = 'migrations' help = 'Shows all migrations in project' MIGRATION_RE = re.compile(r'^\d{4}_.+\.py$') def __init__(self): self.delete = False if len(sys.argv) == 3 and sys.argv[-1] == 'delete': self.delete = True def _show_migrations_for_directory(self, abspath): print(os.path.relpath(abspath)) files = [i for i in os.listdir(abspath) if self.MIGRATION_RE.match(i)] for f in sorted(files): print('-- {}'.format(f)) print('') def _drop_migrations_for_directory(self, abspath): for filename in os.listdir(abspath): if self.MIGRATION_RE.match(filename): os.remove(os.path.join(abspath, filename)) def run(self): migrations_dirs = [] for root, dirs, files in os.walk(BASE_DIR): if 'migrations' in dirs: migrations_dirs.append(os.path.join(root, 'migrations')) for directory in sorted(migrations_dirs): if self.delete: self._drop_migrations_for_directory(directory) else: self._show_migrations_for_directory(directory) class Packages(BaseCommand): verbose_name = 'packages' help = 'Compares packages from requirements and installed' requirements_files = [ os.path.join(BASE_DIR, 'requirements.txt'), os.path.join(BASE_DIR, 'requirements_dev.txt') ] PACKAGE_RE = re.compile(r'(?P\S+)\s*==\s*(?P\S+)') def _get_installed_packages(self,): installed = {i.project_name.lower(): i.version.lower() for i in pip.get_installed_distributions()} return installed def _get_required_packages(self): required = {} for filename in self.requirements_files: with open(filename) as f: for line in f: matching = self.PACKAGE_RE.match(line) if matching: required[matching.group('name').lower()] = matching.group('version').lower() return required def run(self): installed = self._get_installed_packages() required = self._get_required_packages() for package, version in required.iteritems(): installed_version = installed.get(package) if installed_version: if installed_version != version: print('{} -- installed {} instead of {}'.format(package, installed_version, version)) else: print('{}=={} -- not installed yet'.format(package, version)) def main(): available_commands = {} current_module = sys.modules[__name__] for name, cls in inspect.getmembers(current_module, inspect.isclass): if cls.__module__ == __name__ and cls is not BaseCommand: available_commands[cls.verbose_name] = cls if len(sys.argv) < 2: print('Incorrect args count') else: command = sys.argv[1] if not command in available_commands.keys(): print('Unknown command. Available commands are: ') for i in available_commands.values(): print('{} -- {}'.format(i.verbose_name, i.help)) else: command_cls = available_commands[command] command_cls().run() if __name__ == '__main__': main()