diff --git a/lib/galaxy/tool_source_store/index.py b/lib/galaxy/tool_source_store/index.py index 494c65ba604..9226c8dcd48 100644 --- a/lib/galaxy/tool_source_store/index.py +++ b/lib/galaxy/tool_source_store/index.py @@ -51,6 +51,16 @@ class ToolIndexEntry: # === Status === hidden: bool = False disabled: bool = False + require_login: bool = False + + # === Filter metadata === + # ``tool_type`` is the Tool subclass key (``default``, ``data_manager``, + # ``interactive_tool``, ``data_source``, ...). Filter authors and + # ``DataManagerTool.allow_user_access`` (admin-only) both branch on this. + tool_type: str = "default" + # User-facing tags from ```` config (distinct from ``labels``). + # Surfaced for custom tool filters that bucket tools by tag. + tags: list[str] = field(default_factory=list) # === Tests (for /api/tools/tests_summary) === test_count: int = 0 @@ -135,6 +145,9 @@ class ToolIndexEntry: "source_class": self.source_class, "hidden": self.hidden, "disabled": self.disabled, + "require_login": self.require_login, + "tool_type": self.tool_type, + "tags": self.tags, "test_count": self.test_count, "requirements": self.requirements, "container_requirements": self.container_requirements, @@ -169,6 +182,9 @@ class ToolIndexEntry: source_class=data.get("source_class", "XmlToolSource"), hidden=data.get("hidden", False), disabled=data.get("disabled", False), + require_login=data.get("require_login", False), + tool_type=data.get("tool_type", "default"), + tags=data.get("tags", []), test_count=data.get("test_count", 0), requirements=data.get("requirements", []), container_requirements=data.get("container_requirements", []), diff --git a/lib/galaxy/tools/lazy_toolbox.py b/lib/galaxy/tools/lazy_toolbox.py index 905d1542f9e..d003743d071 100644 --- a/lib/galaxy/tools/lazy_toolbox.py +++ b/lib/galaxy/tools/lazy_toolbox.py @@ -47,6 +47,7 @@ from galaxy.tool_util.toolbox.filters import FilterFactory from galaxy.tool_util.toolbox.lineages.factory import LazyLineageMap from galaxy.tool_util.toolbox.lineages.interface import ToolLineage from galaxy.tool_util.toolbox.panel import ( + panel_item_types, ToolPanelElements, ToolSection, ) @@ -1287,6 +1288,32 @@ class LazyToolBox(ToolBox): except Exception: pass + # ``parse_require_login`` is what ``Tool.parse`` calls to set + # ``tool.require_login``. Default False matches ``Tool.__init__``. + require_login = False + if hasattr(tool_source, "parse_require_login"): + try: + require_login = bool(tool_source.parse_require_login(False)) + except Exception: + pass + + # ``tool_type`` is the Tool subclass key (``data_manager``, + # ``interactive_tool``, etc.). Stock filters branch on this for the + # admin-only check on ``DataManagerTool``; custom filters use it + # to categorize. + tool_type = "default" + if hasattr(tool_source, "parse_tool_type"): + try: + tool_type = tool_source.parse_tool_type() or "default" + except Exception: + pass + + # ``tags`` are currently not exposed via the ToolSource parser API. + # The field on ``ToolIndexEntry`` is here so admin/user filters that + # bucket tools by tag have a place to read from when the populator + # learns to fill it. + tags: list[str] = [] + return ToolIndexEntry( id=tool_id, uuid=uuid_val, @@ -1296,6 +1323,9 @@ class LazyToolBox(ToolBox): source_hash=source_hash, source_class=source_class, hidden=hidden, + require_login=require_login, + tool_type=tool_type, + tags=tags, indexed_at=datetime.utcnow(), ) except Exception as e: @@ -2291,8 +2321,11 @@ class LazyToolBox(ToolBox): Create a dictionary representation of the toolbox. For the *flat* listing (``in_panel=False``) we serve straight from - the index — no Tool loading needed. For the panel listing - (``in_panel=True``, e.g. ``tools?in_panel=True&view=custom_13``) + the index — no Tool loading needed — but still run every entry + through ``FilterFactory`` so admin / user toolbox filters apply + identically to the eager path. Filters take ``ToolFilterContext``, + which both ``Tool`` and ``ToolIndexEntry`` satisfy. For the panel + listing (``in_panel=True``, e.g. ``tools?in_panel=True&view=custom_13``) we defer to the parent: it walks ``_tool_panel_view_rendered`` which is built by ``apply_view`` against ``_integrated_tool_panel`` and produces the section-aware @@ -2307,16 +2340,17 @@ class LazyToolBox(ToolBox): if in_panel: return super().to_dict(trans, in_panel=True, tool_help=tool_help, view=view, **kwds) + filter_method = self._build_filter_method(trans) rval = [] - # Return data directly from index - no tool loading needed! for _tool_id, entry in self._tool_index.entries.items(): - # Skip hidden tools unless requested - if entry.hidden and not kwds.get("include_hidden", False): + # ``filter_method`` honours ``_not_hidden`` + ``_handle_authorization`` + # (the always-on stock filters) plus any ``tool_filters`` / + # ``user_tool_filters`` the operator configured. Both stock filters + # read only fields on ``ToolFilterContext``, which ``ToolIndexEntry`` + # exposes — no Tool materialisation needed. + if not filter_method(entry, panel_item_types.TOOL): continue - - # Convert index entry to API dict format - tool_dict = self._index_entry_to_api_dict(entry) - rval.append(tool_dict) + rval.append(self._index_entry_to_api_dict(entry)) log.debug(f"LazyToolBox.to_dict: returning {len(rval)} tools from index (no loading)") return rval diff --git a/tool-data/shed/bwa_mem_index.loc b/tool-data/shed/bwa_mem_index.loc new file mode 100644 index 00000000000..d4c10ceadcd --- /dev/null +++ b/tool-data/shed/bwa_mem_index.loc @@ -0,0 +1,38 @@ +#This is a sample file distributed with Galaxy that enables tools +#to use a directory of BWA indexed sequences data files. You will need +#to create these data files and then create a bwa_index.loc file +#similar to this one (store it in this directory) that points to +#the directories in which those files are stored. The bwa_index.loc +#file has this format (longer white space characters are TAB characters): +# +# +# +#So, for example, if you had phiX indexed stored in +#/depot/data2/galaxy/phiX/base/, +#then the bwa_index.loc entry would look like this: +# +#phiX174 phiX phiX Pretty /depot/data2/galaxy/phiX/base/phiX.fa +# +#and your /depot/data2/galaxy/phiX/base/ directory +#would contain phiX.fa.* files: +# +#-rw-r--r-- 1 james universe 830134 2005-09-13 10:12 phiX.fa.amb +#-rw-r--r-- 1 james universe 527388 2005-09-13 10:12 phiX.fa.ann +#-rw-r--r-- 1 james universe 269808 2005-09-13 10:12 phiX.fa.bwt +#...etc... +# +#Your bwa_index.loc file should include an entry per line for each +#index set you have stored. The "file" in the path does not actually +#exist, but it is the prefix for the actual index files. For example: +# +#phiX174 phiX phiX174 /depot/data2/galaxy/phiX/base/phiX.fa +#hg18canon hg18 hg18 Canonical /depot/data2/galaxy/hg18/base/hg18canon.fa +#hg18full hg18 hg18 Full /depot/data2/galaxy/hg18/base/hg18full.fa +#/orig/path/hg19.fa hg19 hg19 /depot/data2/galaxy/hg19/base/hg19.fa +#...etc... +# +#Note that for backwards compatibility with workflows, the unique ID of +#an entry must be the path that was in the original loc file, because that +#is the value stored in the workflow for that parameter. That is why the +#hg19 entry above looks odd. New genomes can be better-looking. +# diff --git a/tool-data/shed/bwa_mem_index.loc.sample b/tool-data/shed/bwa_mem_index.loc.sample new file mode 100644 index 00000000000..d4c10ceadcd --- /dev/null +++ b/tool-data/shed/bwa_mem_index.loc.sample @@ -0,0 +1,38 @@ +#This is a sample file distributed with Galaxy that enables tools +#to use a directory of BWA indexed sequences data files. You will need +#to create these data files and then create a bwa_index.loc file +#similar to this one (store it in this directory) that points to +#the directories in which those files are stored. The bwa_index.loc +#file has this format (longer white space characters are TAB characters): +# +# +# +#So, for example, if you had phiX indexed stored in +#/depot/data2/galaxy/phiX/base/, +#then the bwa_index.loc entry would look like this: +# +#phiX174 phiX phiX Pretty /depot/data2/galaxy/phiX/base/phiX.fa +# +#and your /depot/data2/galaxy/phiX/base/ directory +#would contain phiX.fa.* files: +# +#-rw-r--r-- 1 james universe 830134 2005-09-13 10:12 phiX.fa.amb +#-rw-r--r-- 1 james universe 527388 2005-09-13 10:12 phiX.fa.ann +#-rw-r--r-- 1 james universe 269808 2005-09-13 10:12 phiX.fa.bwt +#...etc... +# +#Your bwa_index.loc file should include an entry per line for each +#index set you have stored. The "file" in the path does not actually +#exist, but it is the prefix for the actual index files. For example: +# +#phiX174 phiX phiX174 /depot/data2/galaxy/phiX/base/phiX.fa +#hg18canon hg18 hg18 Canonical /depot/data2/galaxy/hg18/base/hg18canon.fa +#hg18full hg18 hg18 Full /depot/data2/galaxy/hg18/base/hg18full.fa +#/orig/path/hg19.fa hg19 hg19 /depot/data2/galaxy/hg19/base/hg19.fa +#...etc... +# +#Note that for backwards compatibility with workflows, the unique ID of +#an entry must be the path that was in the original loc file, because that +#is the value stored in the workflow for that parameter. That is why the +#hg19 entry above looks odd. New genomes can be better-looking. +#