Skip to content

Commit

Permalink
Merge pull request #2025 from mirpedrol/loginfo
Browse files Browse the repository at this point in the history
modify install log.info messages and set command as a class
  • Loading branch information
mirpedrol authored Nov 18, 2022
2 parents 3ed5f29 + 4bb9b37 commit bacb003
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 370 deletions.
103 changes: 0 additions & 103 deletions nf_core/components/components_install.py

This file was deleted.

281 changes: 281 additions & 0 deletions nf_core/components/install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
import logging
import os
import re
from pathlib import Path

import questionary
from rich.console import Console
from rich.syntax import Syntax

import nf_core.modules.modules_utils
import nf_core.utils
from nf_core.components.components_command import ComponentCommand
from nf_core.components.components_utils import prompt_component_version_sha
from nf_core.modules.modules_json import ModulesJson
from nf_core.modules.modules_repo import NF_CORE_MODULES_NAME

log = logging.getLogger(__name__)


class ComponentInstall(ComponentCommand):
def __init__(
self,
pipeline_dir,
component_type,
force=False,
prompt=False,
sha=None,
remote_url=None,
branch=None,
no_pull=False,
installed_by=False,
):
super().__init__(component_type, pipeline_dir, remote_url, branch, no_pull)
self.force = force
self.prompt = prompt
self.sha = sha
if installed_by:
self.installed_by = installed_by
else:
self.installed_by = self.component_type

def install(self, component, silent=False):
if self.repo_type == "modules":
log.error(f"You cannot install a {component} in a clone of nf-core/modules")
return False
# Check whether pipelines is valid
if not self.has_valid_directory():
return False

if self.component_type == "modules":
# Check modules directory structure
self.check_modules_structure()

# Verify that 'modules.json' is consistent with the installed modules and subworkflows
modules_json = ModulesJson(self.dir)
modules_json.check_up_to_date()

# Verify SHA
if not self.modules_repo.verify_sha(self.prompt, self.sha):
return False

# Check and verify component name
component = self.collect_and_verify_name(component, self.modules_repo)
if not component:
return False

# Get current version
current_version = modules_json.get_component_version(
self.component_type, component, self.modules_repo.remote_url, self.modules_repo.repo_path
)

# Set the install folder based on the repository name
install_folder = os.path.join(self.dir, self.component_type, self.modules_repo.repo_path)

# Compute the component directory
component_dir = os.path.join(install_folder, component)

# Check that the component is not already installed
component_not_installed = self.check_component_installed(
component, current_version, component_dir, self.modules_repo, self.force, self.prompt, silent
)
if not component_not_installed:
log.debug(
f"{self.component_type[:-1].title()} is already installed and force is not set.\nAdding the new installation source {self.installed_by} for {self.component_type[:-1]} {component} to 'modules.json' without installing the {self.component_type}."
)
modules_json.load()
modules_json.update(self.component_type, self.modules_repo, component, current_version, self.installed_by)
return False

version = self.get_version(component, self.sha, self.prompt, current_version, self.modules_repo)
if not version:
return False

# Remove component if force is set and component is installed
install_track = None
if self.force:
log.info(f"Removing installed version of '{self.modules_repo.repo_path}/{component}'")
self.clear_component_dir(component, component_dir)
install_track = self.clean_modules_json(component, self.modules_repo, modules_json)

log.info(f"{'Rei' if self.force else 'I'}nstalling '{component}'")
log.debug(
f"Installing {self.component_type} '{component}' at modules hash {version} from {self.modules_repo.remote_url}"
)

# Download component files
if not self.install_component_files(component, version, self.modules_repo, install_folder):
return False

# Update module.json with newly installed subworkflow
modules_json.load()
modules_json.update(
self.component_type, self.modules_repo, component, version, self.installed_by, install_track
)

if self.component_type == "subworkflows":
# Install included modules and subworkflows
self.install_included_components(component_dir)

if not silent:
# Print include statement
component_name = "_".join(component.upper().split("/"))
log.info(f"Use the following statement to include this {self.component_type[:-1]}:")
Console().print(
Syntax(
f"include {{ {component_name} }} from '.{os.path.join(install_folder, component)}/main'",
"groovy",
theme="ansi_dark",
padding=1,
)
)
if self.component_type == "subworkflows":
subworkflow_config = os.path.join(install_folder, component, "nextflow.config")
if os.path.isfile(subworkflow_config):
log.info("Add the following config statement to use this subworkflow:")
Console().print(
Syntax(f"includeConfig '{subworkflow_config}'", "groovy", theme="ansi_dark", padding=1)
)
return True

def get_modules_subworkflows_to_install(self, subworkflow_dir):
"""
Parse the subworkflow test main.nf file to retrieve all imported modules and subworkflows.
"""
modules = []
subworkflows = []
with open(Path(subworkflow_dir, "main.nf"), "r") as fh:
for line in fh:
regex = re.compile(
r"include(?: *{ *)([a-zA-Z\_0-9]*)(?: *as *)?(?:[a-zA-Z\_0-9]*)?(?: *})(?: *from *)(?:'|\")(.*)(?:'|\")"
)
match = regex.match(line)
if match and len(match.groups()) == 2:
name, link = match.groups()
if link.startswith("../../../"):
name_split = name.lower().split("_")
modules.append("/".join(name_split))
elif link.startswith("../"):
subworkflows.append(name.lower())
return modules, subworkflows

def install_included_components(self, subworkflow_dir):
"""
Install included modules and subworkflows
"""
modules_to_install, subworkflows_to_install = self.get_modules_subworkflows_to_install(subworkflow_dir)
for s_install in subworkflows_to_install:
original_installed = self.installed_by
self.installed_by = Path(subworkflow_dir).parts[-1]
self.install(s_install, silent=True)
self.installed_by = original_installed
for m_install in modules_to_install:
original_component_type = self.component_type
self.component_type = "modules"
original_installed = self.installed_by
self.installed_by = Path(subworkflow_dir).parts[-1]
self.install(m_install, silent=True)
self.component_type = original_component_type
self.installed_by = original_installed

def collect_and_verify_name(self, component, modules_repo):
"""
Collect component name.
Check that the supplied name is an available module/subworkflow.
"""
if component is None:
component = questionary.autocomplete(
f"{'Tool' if self.component_type == 'modules' else 'Subworkflow'} name:",
choices=modules_repo.get_avail_components(self.component_type),
style=nf_core.utils.nfcore_question_style,
).unsafe_ask()

# Check that the supplied name is an available module/subworkflow
if component and component not in modules_repo.get_avail_components(self.component_type):
log.error(
f"{self.component_type[:-1].title()} '{component}' not found in list of available {self.component_type}."
)
log.info(f"Use the command 'nf-core {self.component_type} list' to view available software")
return False

if not modules_repo.component_exists(component, self.component_type):
warn_msg = f"{self.component_type[:-1].title()} '{component}' not found in remote '{modules_repo.remote_url}' ({modules_repo.branch})"
log.warning(warn_msg)
return False

return component

def check_component_installed(self, component, current_version, component_dir, modules_repo, force, prompt, silent):
"""
Check that the module/subworkflow is not already installed.
Return:
True: if the component is not installed
False: if the component is installed
"""
if (current_version is not None and os.path.exists(component_dir)) and not force:
if not silent:
log.info(f"{self.component_type[:-1].title()} is already installed.")

if prompt:
message = (
"?" if self.component_type == "modules" else " of this subworkflow and all it's imported modules?"
)
force = questionary.confirm(
f"{self.component_type[:-1].title()} {component} is already installed. \nDo you want to force the reinstallation{message}",
style=nf_core.utils.nfcore_question_style,
default=False,
).unsafe_ask()

if not force:
if not silent:
repo_flag = (
"" if modules_repo.repo_path == NF_CORE_MODULES_NAME else f"-g {modules_repo.remote_url} "
)
branch_flag = "" if modules_repo.branch == "master" else f"-b {modules_repo.branch} "

log.info(
f"To update '{component}' run 'nf-core {self.component_type} {repo_flag}{branch_flag}update {component}'. To force reinstallation use '--force'"
)
return False

return True

def get_version(self, component, sha, prompt, current_version, modules_repo):
"""
Get the version to install
"""
if sha:
version = sha
elif prompt:
try:
version = prompt_component_version_sha(
component,
self.component_type,
installed_sha=current_version,
modules_repo=modules_repo,
)
except SystemError as e:
log.error(e)
return False
else:
# Fetch the latest commit for the module
version = modules_repo.get_latest_component_version(component, self.component_type)
return version

def clean_modules_json(self, component, modules_repo, modules_json):
"""
Remove installed version of module/subworkflow from modules.json
"""
for repo_url, repo_content in modules_json.modules_json["repos"].items():
for dir, dir_components in repo_content[self.component_type].items():
for name, component_values in dir_components.items():
if name == component and dir == modules_repo.repo_path:
repo_to_remove = repo_url
log.info(
f"Removing {self.component_type[:-1]} '{modules_repo.repo_path}/{component}' from repo '{repo_to_remove}' from modules.json"
)
modules_json.remove_entry(
self.component_type, component, repo_to_remove, modules_repo.repo_path
)
return component_values["installed_by"]
2 changes: 1 addition & 1 deletion nf_core/components/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def update(self, component=None, silent=False, updated=None, check_diff_exist=Tr
style=nf_core.utils.nfcore_question_style,
).unsafe_ask()
if recursive_update and len(modules_to_update + subworkflows_to_update) > 0:
# Write all the differences of linked componenets to a diff file
# Write all the differences of linked components to a diff file
self.update_linked_components(
modules_to_update, subworkflows_to_update, updated, check_diff_exist=False
)
Expand Down
Loading

0 comments on commit bacb003

Please sign in to comment.