mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Do not initialize a full repository registry in ToolShed 2.0.
It seems like it is only used by repository_grids - which I think are unused by the new tool shed. I don't recall writing any client side grid framework code and my PR description did claim it was mako free.
This commit is contained in:
@@ -59,9 +59,7 @@ class CategoryManager:
|
||||
|
||||
def to_dict(self, category: Category) -> Dict[str, Any]:
|
||||
category_dict = category.to_dict(view="collection", value_mapper=get_value_mapper(self.app))
|
||||
category_dict["repositories"] = self.app.repository_registry.viewable_repositories_and_suites_by_category.get(
|
||||
category.name, 0
|
||||
)
|
||||
category_dict["repositories"] = category.active_repository_count()
|
||||
category_dict["url"] = web.url_for(
|
||||
controller="categories", action="show", id=self.app.security.encode_id(category.id)
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ from sqlalchemy import (
|
||||
or_,
|
||||
select,
|
||||
)
|
||||
from typing_extensions import Protocol
|
||||
|
||||
import tool_shed.repository_types.util as rt_util
|
||||
from tool_shed.util import (
|
||||
@@ -18,11 +19,77 @@ from tool_shed.webapp.model import (
|
||||
Repository,
|
||||
RepositoryMetadata,
|
||||
)
|
||||
from .structured_app import ToolShedApp
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Registry:
|
||||
class RegistryInterface(Protocol):
|
||||
|
||||
# only used in legacy controllers - can drop when drop old tool shed webapp
|
||||
def add_category_entry(self, category): ...
|
||||
|
||||
def add_entry(self, repository):
|
||||
# used when creating a repository
|
||||
# Used in legacy add_repository_registry_entry API endpoint - already deemed not worth pulling over to 2.0
|
||||
# used in legacy undelete_repository admin controller
|
||||
# used in legacy deprecate controller
|
||||
...
|
||||
|
||||
def edit_category_entry(self, old_name, new_name):
|
||||
# used in legacy admin controller
|
||||
...
|
||||
|
||||
def is_valid(self, repository) -> bool:
|
||||
# probably not used outside this class but also not hurting anything
|
||||
...
|
||||
|
||||
def remove_category_entry(self, category): ...
|
||||
|
||||
def remove_entry(self, repository): ...
|
||||
|
||||
|
||||
# stop gap to implement the same general interface as repository_registry but do nothing,
|
||||
# I don't think this stuff is needed - outside potentially old test cases?
|
||||
class NullRepositoryRegistry(RegistryInterface):
|
||||
|
||||
def __init__(self, app: ToolShedApp):
|
||||
self.app = app
|
||||
|
||||
# all of these are only used by repository_grids - which I think the tool shed 2.0
|
||||
# does not use at all - but they are part of the "public interface" consumed by
|
||||
# the full registry.
|
||||
self.certified_level_one_viewable_repositories_and_suites_by_category: dict = {}
|
||||
self.certified_level_one_viewable_suites_by_category: dict = {}
|
||||
self.viewable_repositories_and_suites_by_category: dict = {}
|
||||
self.viewable_suites_by_category: dict = {}
|
||||
self.viewable_valid_repositories_and_suites_by_category: dict = {}
|
||||
self.viewable_valid_suites_by_category: dict = {}
|
||||
|
||||
def add_category_entry(self, category):
|
||||
# only used in legacy controllers - can drop when drop old tool shed webapp
|
||||
pass
|
||||
|
||||
def add_entry(self, repository):
|
||||
# used when creating a repository, and maybe more?
|
||||
pass
|
||||
|
||||
def edit_category_entry(self, old_name, new_name):
|
||||
pass
|
||||
|
||||
def is_valid(self, repository) -> bool:
|
||||
if repository and not repository.deleted and not repository.deprecated and repository.downloadable_revisions:
|
||||
return True
|
||||
return False
|
||||
|
||||
def remove_category_entry(self, category):
|
||||
pass
|
||||
|
||||
def remove_entry(self, repository):
|
||||
pass
|
||||
|
||||
|
||||
class Registry(RegistryInterface):
|
||||
def __init__(self, app):
|
||||
log.debug("Loading the repository registry...")
|
||||
self.app = app
|
||||
@@ -32,17 +99,30 @@ class Registry:
|
||||
self.certified_level_one_suite_tuples = []
|
||||
# These category dictionaries contain entries where the key is the category and the value is the integer count
|
||||
# of viewable repositories within that category.
|
||||
|
||||
# only used internally to class and by repository_grids
|
||||
self.certified_level_one_viewable_repositories_and_suites_by_category = {}
|
||||
# only used internally to class and by repository_grids
|
||||
self.certified_level_one_viewable_suites_by_category = {}
|
||||
self.certified_level_two_repository_and_suite_tuples = []
|
||||
self.certified_level_two_suite_tuples = []
|
||||
self.certified_level_two_viewable_repositories_and_suites_by_category = {}
|
||||
self.certified_level_two_viewable_suites_by_category = {}
|
||||
|
||||
# not even used in legacy shed code...
|
||||
# self.certified_level_two_repository_and_suite_tuples = []
|
||||
# self.certified_level_two_suite_tuples = []
|
||||
# self.certified_level_two_viewable_repositories_and_suites_by_category = {}
|
||||
# self.certified_level_two_viewable_suites_by_category = {}
|
||||
|
||||
# only used internally to class
|
||||
self.repository_and_suite_tuples = []
|
||||
# only used internally to class
|
||||
self.suite_tuples = []
|
||||
|
||||
# only used internally to class and by repository_grids
|
||||
self.viewable_repositories_and_suites_by_category = {}
|
||||
# only used internally to class and by repository_grids
|
||||
self.viewable_suites_by_category = {}
|
||||
# only used internally to class and by repository_grids
|
||||
self.viewable_valid_repositories_and_suites_by_category = {}
|
||||
# only used internally to class and by repository_grids
|
||||
self.viewable_valid_suites_by_category = {}
|
||||
self.load()
|
||||
|
||||
@@ -152,6 +232,7 @@ class Registry:
|
||||
self.certified_level_one_viewable_suites_by_category[new_name] = 0
|
||||
|
||||
def get_certified_level_one_clause_list(self):
|
||||
# only used internally to class
|
||||
clause_list = []
|
||||
for repository in get_repositories(self.sa_session):
|
||||
certified_level_one_tuple = self.get_certified_level_one_tuple(repository)
|
||||
@@ -169,6 +250,7 @@ class Registry:
|
||||
"""
|
||||
Return True if the latest installable changeset_revision of the received repository is level one certified.
|
||||
"""
|
||||
# only used internally to class
|
||||
if repository is None:
|
||||
return (None, False)
|
||||
if repository.deleted or repository.deprecated:
|
||||
@@ -190,6 +272,7 @@ class Registry:
|
||||
return (None, False)
|
||||
|
||||
def is_level_one_certified(self, repository_metadata):
|
||||
# only used internally to class
|
||||
if repository_metadata:
|
||||
repository = repository_metadata.repository
|
||||
if repository:
|
||||
@@ -206,12 +289,13 @@ class Registry:
|
||||
return tuple in self.certified_level_one_repository_and_suite_tuples
|
||||
return False
|
||||
|
||||
def is_valid(self, repository):
|
||||
def is_valid(self, repository) -> bool:
|
||||
if repository and not repository.deleted and not repository.deprecated and repository.downloadable_revisions:
|
||||
return True
|
||||
return False
|
||||
|
||||
def load_certified_level_one_repository_and_suite_tuple(self, repository):
|
||||
# only used internally to class
|
||||
# The received repository has been determined to be level one certified.
|
||||
name = str(repository.name)
|
||||
owner = str(repository.user.username)
|
||||
@@ -226,6 +310,7 @@ class Registry:
|
||||
self.certified_level_one_repository_and_suite_tuples.append(certified_level_one_tuple)
|
||||
|
||||
def load_repository_and_suite_tuple(self, repository):
|
||||
# only used internally to class
|
||||
name = str(repository.name)
|
||||
owner = str(repository.user.username)
|
||||
for repository_metadata in repository.metadata_revisions:
|
||||
@@ -238,6 +323,7 @@ class Registry:
|
||||
self.suite_tuples.append(tuple)
|
||||
|
||||
def load_repository_and_suite_tuples(self):
|
||||
# only used internally to class
|
||||
# Load self.certified_level_one_repository_and_suite_tuples and self.certified_level_one_suite_tuples.
|
||||
clauses = self.get_certified_level_one_clause_list()
|
||||
for repository in get_certified_repositories_with_user(self.sa_session, clauses, model.User):
|
||||
@@ -247,11 +333,12 @@ class Registry:
|
||||
self.load_repository_and_suite_tuple(repository)
|
||||
|
||||
def load_viewable_repositories_and_suites_by_category(self):
|
||||
# only used internally to class
|
||||
# Clear all dictionaries just in case they were previously loaded.
|
||||
self.certified_level_one_viewable_repositories_and_suites_by_category = {}
|
||||
self.certified_level_one_viewable_suites_by_category = {}
|
||||
self.certified_level_two_viewable_repositories_and_suites_by_category = {}
|
||||
self.certified_level_two_viewable_suites_by_category = {}
|
||||
# self.certified_level_two_viewable_repositories_and_suites_by_category = {}
|
||||
# self.certified_level_two_viewable_suites_by_category = {}
|
||||
self.viewable_repositories_and_suites_by_category = {}
|
||||
self.viewable_suites_by_category = {}
|
||||
self.viewable_valid_repositories_and_suites_by_category = {}
|
||||
@@ -363,6 +450,7 @@ class Registry:
|
||||
|
||||
@property
|
||||
def sa_session(self):
|
||||
# only used internally to class
|
||||
return self.app.model.session
|
||||
|
||||
def unload_certified_level_one_repository_and_suite_tuple(self, repository):
|
||||
|
||||
@@ -4,7 +4,7 @@ from galaxy.structured_app import BasicSharedApp
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from tool_shed.managers.model_cache import ModelCache
|
||||
from tool_shed.repository_registry import Registry as RepositoryRegistry
|
||||
from tool_shed.repository_registry import RegistryInterface
|
||||
from tool_shed.repository_types.registry import Registry as RepositoryTypesRegistry
|
||||
from tool_shed.util.hgweb_config import HgWebConfigManager
|
||||
from tool_shed.webapp.model import mapping
|
||||
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
|
||||
class ToolShedApp(BasicSharedApp):
|
||||
repository_types_registry: "RepositoryTypesRegistry"
|
||||
model: "mapping.ToolShedModelMapping"
|
||||
repository_registry: "RepositoryRegistry"
|
||||
repository_registry: "RegistryInterface"
|
||||
hgweb_config_manager: "HgWebConfigManager"
|
||||
security_agent: "CommunityRBACAgent"
|
||||
model_cache: "ModelCache"
|
||||
|
||||
@@ -108,7 +108,10 @@ class UniverseApplication(ToolShedApp, SentryClientMixin, HaltableContainer):
|
||||
self.hgweb_config_manager.hgweb_config_dir = self.config.hgweb_config_dir
|
||||
self.hgweb_config_manager.hgweb_repo_prefix = self.config.hgweb_repo_prefix
|
||||
# Initialize the repository registry.
|
||||
self.repository_registry = tool_shed.repository_registry.Registry(self)
|
||||
if config.SHED_API_VERSION != "v2":
|
||||
self.repository_registry = tool_shed.repository_registry.Registry(self)
|
||||
else:
|
||||
self.repository_registry = tool_shed.repository_registry.NullRepositoryRegistry(self)
|
||||
# Configure Sentry client if configured
|
||||
self.configure_sentry_client()
|
||||
# used for cachebusting -- refactor this into a *SINGLE* UniverseApplication base.
|
||||
|
||||
@@ -26,8 +26,7 @@ from galaxy.webapps.base.webapp import (
|
||||
GalaxyWebTransaction,
|
||||
)
|
||||
from galaxy.webapps.util import wrap_if_allowed
|
||||
|
||||
SHED_API_VERSION = os.environ.get("TOOL_SHED_API_VERSION", "v1")
|
||||
from .config import SHED_API_VERSION
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ from galaxy.version import (
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
TOOLSHED_APP_NAME = "tool_shed"
|
||||
SHED_API_VERSION = os.environ.get("TOOL_SHED_API_VERSION", "v1")
|
||||
|
||||
|
||||
class ToolShedAppConfiguration(BaseAppConfiguration, CommonConfigurationMixin):
|
||||
|
||||
@@ -166,7 +166,7 @@ def initialize_fast_app(gx_webapp, tool_shed_app):
|
||||
app = get_fastapi_instance()
|
||||
add_exception_handler(app)
|
||||
add_request_id_middleware(app)
|
||||
from .buildapp import SHED_API_VERSION
|
||||
from .config import SHED_API_VERSION
|
||||
|
||||
def mount_static(directory: Path):
|
||||
name = directory.name
|
||||
|
||||
@@ -28,6 +28,7 @@ from sqlalchemy import (
|
||||
not_,
|
||||
String,
|
||||
Table,
|
||||
text,
|
||||
TEXT,
|
||||
true,
|
||||
UniqueConstraint,
|
||||
@@ -35,6 +36,7 @@ from sqlalchemy import (
|
||||
from sqlalchemy.orm import (
|
||||
Mapped,
|
||||
mapped_column,
|
||||
object_session,
|
||||
registry,
|
||||
relationship,
|
||||
)
|
||||
@@ -618,6 +620,22 @@ class Category(Base, Dictifiable):
|
||||
dict_collection_visible_keys = ["id", "name", "description", "deleted"]
|
||||
dict_element_visible_keys = ["id", "name", "description", "deleted"]
|
||||
|
||||
def active_repository_count(self, session=None) -> int:
|
||||
statement = """
|
||||
SELECT count(*) as count
|
||||
FROM repository r
|
||||
INNER JOIN repository_category_association rca on rca.repository_id = r.id
|
||||
WHERE
|
||||
rca.category_id = :category_id
|
||||
AND r.private = false
|
||||
AND r.deleted = false
|
||||
and r.deprecated = false
|
||||
"""
|
||||
if session is None:
|
||||
session = object_session(self)
|
||||
params = {"category_id": self.id}
|
||||
return session.execute(text(statement), params).scalar()
|
||||
|
||||
def __init__(self, deleted=False, **kwd):
|
||||
super().__init__(**kwd)
|
||||
self.deleted = deleted
|
||||
|
||||
@@ -33,6 +33,7 @@ from tool_shed.webapp.model import (
|
||||
Category,
|
||||
mapping,
|
||||
Repository,
|
||||
RepositoryCategoryAssociation,
|
||||
User,
|
||||
)
|
||||
from tool_shed_client.schema import CreateCategoryRequest
|
||||
@@ -195,3 +196,12 @@ def create_category(provides_repositories: ProvidesRepositoriesContext, create:
|
||||
|
||||
request = CreateCategoryRequest(**create)
|
||||
return CategoryManager(provides_repositories.app).create(provides_repositories, request)
|
||||
|
||||
|
||||
def attach_category(provides_repositories: ProvidesRepositoriesContext, repository: Repository, category: Category):
|
||||
assoc = RepositoryCategoryAssociation(
|
||||
repository=repository,
|
||||
category=category,
|
||||
)
|
||||
provides_repositories.sa_session.add(assoc)
|
||||
provides_repositories.sa_session.flush()
|
||||
|
||||
@@ -12,12 +12,9 @@ from tool_shed.context import (
|
||||
ProvidesUserContext,
|
||||
)
|
||||
from tool_shed.webapp.graphql.schema import schema
|
||||
from tool_shed.webapp.model import (
|
||||
Category,
|
||||
Repository,
|
||||
RepositoryCategoryAssociation,
|
||||
)
|
||||
from tool_shed.webapp.model import Repository
|
||||
from ._util import (
|
||||
attach_category,
|
||||
create_category,
|
||||
repository_fixture,
|
||||
upload_directories_to_repository,
|
||||
@@ -110,15 +107,6 @@ def test_simple_repositories(provides_repositories: ProvidesRepositoriesContext,
|
||||
assert new_repository.name in repository_names
|
||||
|
||||
|
||||
def attach_category(provides_repositories: ProvidesRepositoriesContext, repository: Repository, category: Category):
|
||||
assoc = RepositoryCategoryAssociation(
|
||||
repository=repository,
|
||||
category=category,
|
||||
)
|
||||
provides_repositories.sa_session.add(assoc)
|
||||
provides_repositories.sa_session.flush()
|
||||
|
||||
|
||||
def test_relay_repos_by_category(provides_repositories: ProvidesRepositoriesContext, new_repository: Repository):
|
||||
name = new_repository.name
|
||||
category = create_category(provides_repositories, {"name": "test_graphql_relay_categories_1"})
|
||||
|
||||
@@ -5,6 +5,8 @@ from tool_shed.webapp.model import (
|
||||
User,
|
||||
)
|
||||
from ._util import (
|
||||
attach_category,
|
||||
create_category,
|
||||
repository_fixture,
|
||||
TEST_DATA_FILES,
|
||||
TestToolShedApp,
|
||||
@@ -83,6 +85,27 @@ def test_upload_dry_run_ok(provides_repositories: ProvidesRepositoriesContext, n
|
||||
assert old_tip == new_tip
|
||||
|
||||
|
||||
def test_category_count(provides_repositories: ProvidesRepositoriesContext, new_repository: Repository):
|
||||
category = create_category(provides_repositories, {"name": "test_category_count_1"})
|
||||
attach_category(provides_repositories, new_repository, category)
|
||||
|
||||
category = new_repository.categories[0].category
|
||||
assert category.active_repository_count() == 1
|
||||
|
||||
tar_resource = TEST_DATA_FILES.joinpath("column_maker/column_maker.tar")
|
||||
upload_ok, *_ = upload_tar(
|
||||
provides_repositories,
|
||||
new_repository.user.username,
|
||||
new_repository,
|
||||
tar_resource,
|
||||
commit_message="Commit Message",
|
||||
)
|
||||
assert upload_ok
|
||||
|
||||
category = new_repository.categories[0].category
|
||||
assert category.active_repository_count() == 1
|
||||
|
||||
|
||||
def test_upload_dry_run_failed(provides_repositories: ProvidesRepositoriesContext, new_repository: Repository):
|
||||
tar_resource = TEST_DATA_FILES.joinpath("safetar_with_symlink.tar")
|
||||
upload_ok, message, _, _, _, _ = upload_tar(
|
||||
|
||||
Reference in New Issue
Block a user