def _migrate_extension_models(self, ext_class): """Perform database migrations for an extension's models. This will call out to Django Evolution to handle the migrations. Args: ext_class (djblets.extensions.extension.Extension): The class for the extension to migrate. """ try: from django_evolution.management.commands.evolve import \ Command as Evolution except ImportError: raise InstallExtensionError( "Unable to migrate the extension's database tables. Django " "Evolution is not installed.") try: stream = StringIO() evolution = Evolution() evolution.style = no_style() evolution.execute(verbosity=0, interactive=False, execute=True, hint=False, compile_sql=False, purge=False, database=False, stdout=stream, stderr=stream) output = stream.getvalue() if output: logging.info('Evolved extension models for %s: %s', ext_class.id, stream.read()) stream.close() except CommandError as e: # Something went wrong while running django-evolution, so # grab the output. We can't raise right away because we # still need to put stdout back the way it was output = stream.getvalue() stream.close() logging.error('Error evolving extension models: %s: %s', e, output, exc_info=1) load_error = self._store_load_error(ext_class.id, output) raise InstallExtensionError(six.text_type(e), load_error)
def _install_extension_media_internal(self, ext_class): """Installs extension data. Performs any installation necessary for an extension. If the extension has a legacy htdocs/ directory for static media files, they will be installed into MEDIA_ROOT/ext/, and a warning will be logged. If the extension has a modern static/ directory, they will be installed into STATIC_ROOT/ext/. """ ext_htdocs_path = ext_class.info.installed_htdocs_path ext_htdocs_path_exists = os.path.exists(ext_htdocs_path) if ext_htdocs_path_exists: # First, get rid of the old htdocs contents, so we can start # fresh. shutil.rmtree(ext_htdocs_path, ignore_errors=True) if pkg_resources.resource_exists(ext_class.__module__, 'htdocs'): # This is an older extension that doesn't use the static file # support. Log a deprecation notice and then install the files. logging.warning('The %s extension uses the deprecated "htdocs" ' 'directory for static files. It should be updated ' 'to use a "static" directory instead.' % ext_class.info.name) extracted_path = \ pkg_resources.resource_filename(ext_class.__module__, 'htdocs') shutil.copytree(extracted_path, ext_htdocs_path, symlinks=True) # We only want to install static media on a non-DEBUG install. # Otherwise, we run the risk of creating a new 'static' directory and # causing Django to look up all static files (not just from # extensions) from there instead of from their source locations. if not settings.DEBUG: ext_static_path = ext_class.info.installed_static_path ext_static_path_exists = os.path.exists(ext_static_path) if ext_static_path_exists: # Also get rid of the old static contents. shutil.rmtree(ext_static_path, ignore_errors=True) if pkg_resources.resource_exists(ext_class.__module__, 'static'): extracted_path = \ pkg_resources.resource_filename(ext_class.__module__, 'static') shutil.copytree(extracted_path, ext_static_path, symlinks=True) # Mark the extension as installed ext_class.registration.installed = True ext_class.registration.save() # Now let's build any tables that this extension might need self._add_to_installed_apps(ext_class) # Call syncdb to create the new tables loading.cache.loaded = False call_command('syncdb', verbosity=0, interactive=False) # Run evolve to do any table modification try: stream = StringIO() evolution = Evolution() evolution.style = no_style() evolution.execute(verbosity=0, interactive=False, execute=True, hint=False, compile_sql=False, purge=False, database=False, stdout=stream, stderr=stream) output = stream.getvalue() if output: logging.info('Evolved extension models for %s: %s', ext_class.id, stream.read()) stream.close() except CommandError as e: # Something went wrong while running django-evolution, so # grab the output. We can't raise right away because we # still need to put stdout back the way it was output = stream.getvalue() stream.close() logging.error('Error evolving extension models: %s: %s', e, output, exc_info=1) load_error = self._store_load_error(ext_class.id, output) raise InstallExtensionError(six.text_type(e), load_error) # Remove this again, since we only needed it for syncdb and # evolve. _init_extension will add it again later in # the install. self._remove_from_installed_apps(ext_class) # Mark the extension as installed ext_class.registration.installed = True ext_class.registration.save()