Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tower UI no longer shows revisions for downloaded pipelines. #2308

Merged
merged 9 commits into from
Jun 12, 2023
31 changes: 23 additions & 8 deletions nf_core/download.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import tarfile
import textwrap
from datetime import datetime
from distutils.version import StrictVersion
from zipfile import ZipFile

import git
Expand All @@ -27,7 +28,11 @@
import nf_core.list
import nf_core.utils
from nf_core.synced_repo import RemoteProgressbar, SyncedRepo
from nf_core.utils import NFCORE_CACHE_DIR, NFCORE_DIR
from nf_core.utils import (
NFCORE_CACHE_DIR,
NFCORE_DIR,
SingularityCacheFilePathValidator,
)

log = logging.getLogger(__name__)
stderr = rich.console.Console(
Expand Down Expand Up @@ -157,7 +162,7 @@ def download_workflow(self):
sys.exit(1)

summary_log = [
f"Pipeline revision: '{', '.join(self.revision) if len(self.revision) < 5 else self.revision[0]+',...,['+str(len(self.revision)-2)+' more revisions],...,'+self.revision[-1]}'",
f"Pipeline revision: '{', '.join(self.revision) if len(self.revision) < 5 else self.revision[0]+',['+str(len(self.revision)-2)+' more revisions],'+self.revision[-1]}'",
f"Pull containers: '{self.container}'",
]
if self.container == "singularity" and os.environ.get("NXF_SINGULARITY_CACHEDIR") is not None:
Expand Down Expand Up @@ -493,8 +498,8 @@ def prompt_singularity_cachedir_remote(self):
cachedir_index = None
while cachedir_index is None:
prompt_cachedir_index = questionary.path(
"Specify a list of the remote images already present in the remote system :",
file_filter="*.txt",
"Specify a list of the container images that are already present on the remote system:",
validate=SingularityCacheFilePathValidator,
style=nf_core.utils.nfcore_question_style,
).unsafe_ask()
cachedir_index = os.path.abspath(os.path.expanduser(prompt_cachedir_index))
Expand Down Expand Up @@ -531,7 +536,8 @@ def read_remote_containers(self):
except (FileNotFoundError, LookupError) as e:
log.error(f"[red]Issue with reading the specified remote $NXF_SINGULARITY_CACHE index:[/]\n{e}\n")
if stderr.is_interactive and rich.prompt.Confirm.ask(f"[blue]Specify a new index file and try again?"):
self.prompt_singularity_cachedir_remote(retry=True)
self.singularity_cache_index = None # reset chosen path to index file.
self.prompt_singularity_cachedir_remote()
else:
log.info("Proceeding without consideration of the remote $NXF_SINGULARITY_CACHE index.")
self.singularity_cache_index = None
Expand Down Expand Up @@ -731,7 +737,7 @@ def find_container_images(self, workflow_directory):
r"(?<=container)[^\${}]+\${([^{}]+)}(?![^{]*})", contents
)

if bool(container_definition) & bool(container_definition.group(1)):
if bool(container_definition) and bool(container_definition.group(1)):
pattern = re.escape(container_definition.group(1))
# extract the quoted string(s) following the variable assignment
container_names = re.findall(r"%s\s*=\s*[\"\']([^\"\']+)[\"\']" % pattern, contents)
Expand Down Expand Up @@ -1268,9 +1274,18 @@ def tidy_tags_and_branches(self):
for head in heads_to_remove:
self.repo.delete_head(head)

# ensure all desired branches are available
# ensure all desired revisions/branches are available
for revision in desired_revisions:
self.checkout(revision)
if self.repo.is_valid_object(revision):
self.checkout(revision)

# create "latest" branch to ensure at least one branch exists (required for Tower's UI to display revisions correctly)
latest = sorted(desired_revisions, key=StrictVersion)[-1]
self.repo.create_head("latest", latest)
self.checkout(latest)
if self.repo.head.is_detached:
self.repo.head.reset(index=True, working_tree=True)

self.heads = self.repo.heads

# get all tags and available remote_branches
Expand Down
17 changes: 17 additions & 0 deletions nf_core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,23 @@ def prompt_pipeline_release_branch(wf_releases, wf_branches, multiple=False):
)


class SingularityCacheFilePathValidator(questionary.Validator):
"""
Validator for file path specified as --singularity-cache-index argument in nf-core download
"""

def validate(self, value):
if len(value.text):
if os.path.isfile(value.text):
return True
else:
raise questionary.ValidationError(
message="Invalid remote cache index file", cursor_position=len(value.text)
)
else:
return True


def get_repo_releases_branches(pipeline, wfs):
"""Fetches details of a nf-core workflow to download.

Expand Down
8 changes: 7 additions & 1 deletion tests/test_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,14 @@ def test_download_workflow_for_tower(self, tmp_dir):
assert download_obj.workflow_repo
assert isinstance(download_obj.workflow_repo, WorkflowRepo)
assert issubclass(type(download_obj.workflow_repo), SyncedRepo)

# corroborate that the other revisions are inaccessible to the user.
assert len(download_obj.workflow_repo.tags) == len(download_obj.revision)
all_tags = {tag.name for tag in download_obj.workflow_repo.tags}
all_heads = {head.name for head in download_obj.workflow_repo.heads}

assert set(download_obj.revision) == all_tags
# assert that the download has a "latest" branch.
assert "latest" in all_heads

# download_obj.download_workflow_tower(location=tmp_dir) will run container image detection for all requested revisions
assert isinstance(download_obj.containers, list) and len(download_obj.containers) == 33
Expand Down