Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into remove-legacy-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
smotornyuk committed Jun 25, 2021
2 parents 88db9fb + 5c386b8 commit 56a4148
Show file tree
Hide file tree
Showing 37 changed files with 774 additions and 98 deletions.
95 changes: 72 additions & 23 deletions ckan/cli/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import inspect
import logging
import os
import contextlib

import click
from itertools import groupby
Expand All @@ -11,6 +12,7 @@
import ckan.plugins as p
import ckan.plugins.toolkit as tk
import ckan.model as model
from ckan.common import config

log = logging.getLogger(__name__)

Expand All @@ -30,7 +32,6 @@ def init():
"""
log.info(u"Initialize the Database")
try:
import ckan.model as model
model.repo.init_db()
except Exception as e:
tk.error_shout(e)
Expand All @@ -47,7 +48,6 @@ def clean():
"""Clean the database.
"""
try:
import ckan.model as model
model.repo.clean_db()
except Exception as e:
tk.error_shout(e)
Expand All @@ -61,14 +61,8 @@ def clean():
def upgrade(version, plugin):
"""Upgrade the database.
"""
try:
import ckan.model as model
model.repo._alembic_ini = _resolve_alembic_config(plugin)
model.repo.upgrade_db(version)
except Exception as e:
tk.error_shout(e)
else:
click.secho(u'Upgrading DB: SUCCESS', fg=u'green', bold=True)
_run_migrations(plugin, version)
click.secho(u'Upgrading DB: SUCCESS', fg=u'green', bold=True)


@db.command()
Expand All @@ -77,26 +71,65 @@ def upgrade(version, plugin):
def downgrade(version, plugin):
"""Downgrade the database.
"""
try:
import ckan.model as model
model.repo._alembic_ini = _resolve_alembic_config(plugin)
model.repo.downgrade_db(version)
except Exception as e:
tk.error_shout(e)
else:
click.secho(u'Downgrading DB: SUCCESS', fg=u'green', bold=True)
_run_migrations(plugin, version, False)
click.secho(u'Downgrading DB: SUCCESS', fg=u'green', bold=True)


@db.command()
@click.option("--apply", is_flag=True, help="Apply all pending migrations")
def pending_migrations(apply):
"""List all sources with unapplied migrations.
"""
pending = _get_pending_plugins()
if not pending:
click.secho("All plugins are up-to-date", fg="green")
for plugin, n in sorted(pending.items()):
click.secho("{n} unapplied migrations for {p}".format(
p=click.style(plugin, bold=True),
n=click.style(str(n), bold=True)))
if apply:
_run_migrations(plugin)


def _get_pending_plugins():
from alembic.command import history
plugins = [(plugin, state)
for plugin, state
in ((plugin, current_revision(plugin))
for plugin in config['ckan.plugins'].split())
if state and not state.endswith('(head)')]
pending = {}
for plugin, current in plugins:
with _repo_for_plugin(plugin) as repo:
repo.setup_migration_version_control()
history(repo.alembic_config)
ahead = repo.take_alembic_output()
if current != 'base':
# The last revision in history describes step from void to the
# first revision. If we not on the `base`, we've already run
# this migration
ahead = ahead[:-1]
if ahead:
pending[plugin] = len(ahead)
return pending


def _run_migrations(plugin, version="head", forward=True):
if not version:
version = "head" if forward else "base"
with _repo_for_plugin(plugin) as repo:
if forward:
repo.upgrade_db(version)
else:
repo.downgrade_db(version)


@db.command()
@applies_to_plugin
def version(plugin):
"""Returns current version of data schema.
"""
import ckan.model as model
model.repo._alembic_ini = _resolve_alembic_config(plugin)
log.info(u"Returning current DB version")
model.repo.setup_migration_version_control()
current = model.repo.current_version()
current = current_revision(plugin)
try:
current = _version_hash_to_ordinal(current)
except ValueError:
Expand All @@ -106,6 +139,12 @@ def version(plugin):
bold=True)


def current_revision(plugin):
with _repo_for_plugin(plugin) as repo:
repo.setup_migration_version_control()
return repo.current_version()


@db.command(u"duplicate_emails", short_help=u"Check users email for duplicate")
def duplicate_emails():
u'''Check users email for duplicate'''
Expand Down Expand Up @@ -169,3 +208,13 @@ def _resolve_alembic_config(plugin):
import ckan.migration as _cm
migration_dir = os.path.dirname(_cm.__file__)
return os.path.join(migration_dir, u"alembic.ini")


@contextlib.contextmanager
def _repo_for_plugin(plugin):
original = model.repo._alembic_ini
model.repo._alembic_ini = _resolve_alembic_config(plugin)
try:
yield model.repo
finally:
model.repo._alembic_ini = original
36 changes: 35 additions & 1 deletion ckan/cli/generate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# encoding: utf-8

import contextlib
import os
import shutil

import alembic.command
import click
Expand Down Expand Up @@ -82,6 +84,8 @@ def extension(output_dir):
project_short = name[8:].lower().replace(u'-', u'_')
plugin_class_name = project_short.title().replace(u'_', u'') + u'Plugin'

include_examples = int(click.confirm(
"Do you want to include code examples?"))
context = {
u"project": name,
u"description": description,
Expand All @@ -91,7 +95,8 @@ def extension(output_dir):
u"github_user_name": github,
u"project_shortname": project_short,
u"plugin_class_name": plugin_class_name,
u"_source": u"cli"
u"include_examples": include_examples,
u"_source": u"cli",
}

if output_dir == u'.':
Expand All @@ -101,9 +106,38 @@ def extension(output_dir):
cookiecutter(template_loc, no_input=True, extra_context=context,
output_dir=output_dir)

if not include_examples:
remove_code_examples(
os.path.join(
output_dir, context["project"], "ckanext", project_short))

click.echo(u"\nWritten: {}/{}".format(output_dir, name))



_code_examples = [
"cli.py",
"helpers.py",
"logic",
"views.py",
"tests/logic",
"tests/test_helpers.py",
"tests/test_views.py",
]


def remove_code_examples(root: str):
"""Remove example files from extension's template.
"""
for item in _code_examples:
path = os.path.join(root, item)
with contextlib.suppress(FileNotFoundError):
if os.path.isdir(path):
shutil.rmtree(path)
else:
os.remove(path)


@generate.command(name=u'config',
short_help=u'Create a ckan.ini file.')
@click.argument(u'output_path', nargs=1)
Expand Down
46 changes: 1 addition & 45 deletions ckan/lib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,21 +748,6 @@ def are_there_flash_messages():

def _link_active(kwargs):
''' creates classes for the link_to calls '''
return _link_active_flask(kwargs)


def _link_active_pylons(kwargs):
highlight_controllers = kwargs.get('highlight_controllers', [])
if highlight_controllers and c.controller in highlight_controllers:
return True

highlight_actions = kwargs.get('highlight_actions',
kwargs.get('action', '')).split()
return (c.controller == kwargs.get('controller')
and c.action in highlight_actions)


def _link_active_flask(kwargs):
blueprint, endpoint = p.toolkit.get_endpoint()

highlight_controllers = kwargs.get('highlight_controllers', [])
Expand Down Expand Up @@ -879,10 +864,6 @@ def nav_link(text, *args, **kwargs):
:param condition: if ``False`` then no link is returned
'''
return nav_link_flask(text, *args, **kwargs)


def nav_link_flask(text, *args, **kwargs):
if len(args) > 1:
raise Exception('Too many unnamed parameters supplied')
blueprint, endpoint = p.toolkit.get_endpoint()
Expand All @@ -900,24 +881,6 @@ def nav_link_flask(text, *args, **kwargs):
return link


def nav_link_pylons(text, *args, **kwargs):
if len(args) > 1:
raise Exception('Too many unnamed parameters supplied')
if args:
kwargs['controller'] = kwargs.get('controller')
log.warning('h.nav_link() please supply controller as a named '
'parameter not a positional one')
named_route = kwargs.pop('named_route', '')
if kwargs.pop('condition', True):
if named_route:
link = _link_to(text, named_route, **kwargs)
else:
link = _link_to(text, **kwargs)
else:
link = ''
return link


@core_helper
@maintain.deprecated('h.nav_named_link is deprecated please '
'use h.nav_link\nNOTE: you will need to pass the '
Expand Down Expand Up @@ -1486,14 +1449,7 @@ def icon(name, alt=None, inline=True):

@core_helper
def resource_icon(res):
if False:
icon_name = 'page_white'
# if (res.is_404?): icon_name = 'page_white_error'
# also: 'page_white_gear'
# also: 'page_white_link'
return icon(icon_name)
else:
return icon(format_icon(res.get('format', '')))
return icon(format_icon(res.get('format', '')))


@core_helper
Expand Down
11 changes: 11 additions & 0 deletions ckan/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,12 +287,23 @@ def setup_migration_version_control(self):
self.alembic_config = alembic_config

def current_version(self):
"""Returns current revision of the migration repository.
Returns None for plugins that has no migrations and "base" for plugins
that has migrations but none of them were applied. If current revision
is the newest one, ` (head)` suffix added to the result
"""
from alembic.util import CommandError
try:
alembic_current(self.alembic_config)
return self.take_alembic_output()[0][0]
except (TypeError, IndexError):
# alembic is not initialized yet
return 'base'
except CommandError:
# trying to get revision of plugin without migrations
return None

def downgrade_db(self, version='base'):
self.setup_migration_version_control()
Expand Down
Loading

0 comments on commit 56a4148

Please sign in to comment.