import socket import os import pybis from .openbis_command import OpenbisCommand, ContentCopySelector from ..checksum import validate_checksum from ..command_result import CommandResult from ..utils import cd from ..utils import run_shell from ..utils import complete_openbis_config from ... import dm class Clone(OpenbisCommand): """ Implements the clone command. Copies a repository from a content copy of a data set and adds the local copy as a new content copy using the addref command. """ def __init__(self, dm, data_set_id, ssh_user, content_copy_index): self.data_set_id = data_set_id self.ssh_user = ssh_user self.content_copy_index = content_copy_index self.load_global_config(dm) super(Clone, self).__init__(dm) def check_configuration(self): missing_config_settings = [] if self.openbis is None: missing_config_settings.append('openbis_url') if self.user() is None: missing_config_settings.append('user') if len(missing_config_settings) > 0: return CommandResult(returncode=-1, output="Missing configuration settings for {}.".format(missing_config_settings)) return CommandResult(returncode=0, output="") def run(self): result = self.prepare_run() if result.failure(): return result data_set = self.openbis.get_dataset(self.data_set_id) content_copy = ContentCopySelector(data_set, self.content_copy_index).select() host = content_copy['externalDms']['address'].split(':')[0] path = content_copy['path'] repository_folder = path.split('/')[-1] result = self.copy_repository(self.ssh_user, host, path) if result.failure(): return result result = self.checkout_commit(content_copy, path) if result.failure(): return result data_set = self.openbis.get_dataset(self.data_set_id) validate_checksum(self.openbis, data_set.file_list, data_set.permId, repository_folder) return self.add_content_copy_to_openbis(repository_folder) def copy_repository(self, ssh_user, host, path): # abort if local folder already exists repository_folder = path.split('/')[-1] if os.path.exists(repository_folder): return CommandResult(returncode=-1, output="Folder for repository to clone already exists: " + repository_folder) # check if local or remote if host == socket.gethostname(): location = path else: location = ssh_user + "@" if ssh_user is not None else "" location += host + ":" + path # copy repository return run_shell(["rsync", "--progress", "-av", location, "."]) def checkout_commit(self, content_copy, path): """ Checks out the commit of the content copy from which the clone was made in case there are newer commits / data sets. So the new copy is based on the data set given as an input. """ commit_hash = content_copy['gitCommitHash'] repository_folder = path.split('/')[-1] with cd(repository_folder): return self.git_wrapper.git_checkout(commit_hash) def add_content_copy_to_openbis(self, repository_folder): with cd(repository_folder): data_mgmt = dm.DataMgmt(openbis_config={}, git_config={'find_git': True}) return data_mgmt.addref()