From 5d733ad58a94197330b38ad76263500d717538a9 Mon Sep 17 00:00:00 2001 From: Chandrasekhar Ramakrishnan <chandrasekhar.ramakrishnan@id.ethz.ch> Date: Mon, 13 Mar 2017 16:25:44 +0100 Subject: [PATCH] SSDM-4670: Sync with openBIS server. --- src/python/OBis/obis/conftest.py | 7 +- src/python/OBis/obis/dm/data_mgmt.py | 120 ++++++++++++++++++++-- src/python/OBis/obis/dm/data_mgmt_test.py | 41 +++++++- src/python/OBis/obis/dm/repo_test.py | 6 +- src/python/OBis/obis/scripts/cli.py | 23 ++++- 5 files changed, 174 insertions(+), 23 deletions(-) diff --git a/src/python/OBis/obis/conftest.py b/src/python/OBis/obis/conftest.py index d581c429afd..26ef109812c 100644 --- a/src/python/OBis/obis/conftest.py +++ b/src/python/OBis/obis/conftest.py @@ -12,9 +12,4 @@ Copyright (c) 2017 Chandrasekhar Ramakrishnan. All rights reserved. import pytest from . import dm - - -@pytest.fixture(scope="session") -def shared_dm(): - git_config = {'find_git': True} - return dm.DataMgmt(git_config=git_config) +from unittest.mock import Mock diff --git a/src/python/OBis/obis/dm/data_mgmt.py b/src/python/OBis/obis/dm/data_mgmt.py index a0648350e7d..e5bc38334eb 100644 --- a/src/python/OBis/obis/dm/data_mgmt.py +++ b/src/python/OBis/obis/dm/data_mgmt.py @@ -16,6 +16,7 @@ import subprocess from contextlib import contextmanager from . import config as dm_config import traceback +import getpass import pybis @@ -225,12 +226,8 @@ class GitDataMgmt(AbstractDataMgmt): return result def sync(self): - # TODO create a data set in openBIS - # - check if openBIS has been setup. If not, prompt the user to set up openbis. - # - write a file to the .git/obis folder containing the commit id. Filename includes a timestamp so they can be sorted. - # - call openbis to create a data set, using the existing data set as a parent, if there is one - # - save the data set id to .git/obis/datasetid. - return CommandResult(returncode=0, output="") + cmd = OpenbisSync(self.openbis, self.git_wrapper, self.config_resolver) + return cmd.run() def commit(self, msg, auto_add=True, sync=True): if auto_add: @@ -314,9 +311,112 @@ class GitWrapper(object): class OpenbisSync(object): """A command object for synchronizing with openBIS.""" - def __init__(self, git_path=None, git_annex_path=None, find_git=None): - self.git_path = git_path - self.git_annex_path = git_annex_path + def __init__(self, openbis, git_wrapper, config_resolver): + self.openbis = openbis + self.git_wrapper = git_wrapper + self.config_resolver = config_resolver + self.config_dict = config_resolver.config_dict() + + def user(self): + return self.config_dict.get('user') + + def external_dms_id(self): + return self.config_dict.get('external_dms_id') + + def data_set_type(self): + return self.config_dict.get('data_set_type') + + def sample_id(self): + return self.config_dict.get('sample_id') + + 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 self.data_set_type() is None: + missing_config_settings.append('data_set_type') + if self.data_set_type() is None: + missing_config_settings.append('sample_id') + 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 login(self): + if self.openbis.is_session_active(): + return CommandResult(returncode=0, output="") + user = self.user() + passwd = getpass.getpass("Password for {}".format(user)) + try: + self.openbis.login(user, passwd) + except ValueError: + msg = "Could not log into openbis {}".format(self.config_dict['openbis_url']) + return CommandResult(returncode=-1, output=msg) + + def get_external_data_management_system(self): + external_dms_id = self.external_dms_id() + if external_dms_id is None: + return None + external_dms = self.openbis.get_external_data_management_system(external_dms_id) + return external_dms + + def create_external_data_management_system(self): + external_dms_id = self.external_dms_id() + user = self.user() + result = self.git_wrapper.get_top_level_path() + if result.failure(): + return result + top_level_path = result.output + path_name = os.path.basename(top_level_path) + if external_dms_id is None: + external_dms_id = "{}-{}".format(user, path_name) + try: + edms = self.openbis.create_external_data_management_system(external_dms_id, external_dms_id, + "localhost:/{}".format(top_level_path)) + return CommandResult(returncode=0, output=""), edms + except ValueError as e: + return CommandResult(returncode=-1, output=str(e)), None + + def create_data_set(self, external_dms): + # Get the commit id + data_set_type = self.data_set_type() + result = self.git_wrapper.get_top_level_path() + if result.failure(): + return result + top_level_path = result.output + # TODO Get commit id + commit_id = '12345' + sample_id = self.sample_id() + try: + data_set = self.openbis.new_git_data_set(data_set_type, top_level_path, commit_id, external_dms.code, + sample_id) + return CommandResult(returncode=0, output=""), data_set + except ValueError as e: + return CommandResult(returncode=-1, output=str(e)), None def run(self): - pass + # TODO create a data set in openBIS + # - write a file to the .git/obis folder containing the commit id. Filename includes a timestamp so they can be sorted. + + result = self.check_configuration() + if result.failure(): + return result + result = self.login() + if result.failure(): + return result + + # If there is no external data management system, create one. + external_dms = self.get_external_data_management_system() + if external_dms is None: + result, external_dms = self.create_external_data_management_system() + if result.failure(): + return result + + self.config_resolver.set_value_for_parameter('external_dms_id', external_dms.code, 'local') + + # create a data set, using the existing data set as a parent, if there is one + result, data_set = self.create_data_set(external_dms) + # - save the data set id to .git/obis/datasetid. + return CommandResult(returncode=0, output="") diff --git a/src/python/OBis/obis/dm/data_mgmt_test.py b/src/python/OBis/obis/dm/data_mgmt_test.py index 42270778a78..1887570589c 100644 --- a/src/python/OBis/obis/dm/data_mgmt_test.py +++ b/src/python/OBis/obis/dm/data_mgmt_test.py @@ -12,6 +12,14 @@ import os import shutil from . import data_mgmt +from unittest.mock import Mock, MagicMock +from pybis.pybis import ExternalDMS, DataSet + + +def shared_dm(): + git_config = {'find_git': True} + dm = data_mgmt.DataMgmt(git_config=git_config) + return dm def test_no_git(tmpdir): @@ -43,11 +51,13 @@ def git_status(path=None, annex=False): return data_mgmt.run_shell(cmd) -def test_data_use_case(shared_dm, tmpdir): +def test_data_use_case(tmpdir): + dm = shared_dm() + tmp_dir_path = str(tmpdir) assert git_status(tmp_dir_path).returncode == 128 # The folder should not be a git repo at first. - result = shared_dm.init_data(tmp_dir_path, "test") + result = dm.init_data(tmp_dir_path, "test") assert result.returncode == 0 assert git_status(tmp_dir_path).returncode == 0 # The folder should be a git repo now @@ -56,7 +66,11 @@ def test_data_use_case(shared_dm, tmpdir): copy_test_data(tmpdir) with data_mgmt.cd(tmp_dir_path): - result = shared_dm.commit("Added data.") + dm = shared_dm() + prepare_registration_expectations(dm) + set_registration_configuration(dm) + + result = dm.commit("Added data.") assert result.returncode == 0 # The zip should be in the annex @@ -81,6 +95,27 @@ def test_data_use_case(shared_dm, tmpdir): assert stat.st_nlink == 1 +def set_registration_configuration(dm): + resolver = dm.config_resolver + resolver.set_value_for_parameter('openbis_url', "https://localhost:8443", 'local') + resolver.set_value_for_parameter('user', "auser", 'local') + resolver.set_value_for_parameter('data_set_type', "DS_TYPE", 'local') + resolver.set_value_for_parameter('sample_id', "/SAMPLE/ID", 'local') + + +def prepare_registration_expectations(dm): + dm.openbis = Mock() + dm.openbis.is_session_active = MagicMock(return_value=True) + edms = ExternalDMS(dm.openbis, {'code': 'AUSER-PATH', 'label': 'AUSER-PATH'}) + dm.openbis.create_external_data_management_system = MagicMock(return_value=edms) + + data_set = DataSet(dm.openbis, None, + {'code': 'DS-1', 'properties': {}, + "parents": [], "children": [], "samples": [], 'tags': [], + 'physicalData': None}) + dm.openbis.new_git_data_set = MagicMock(data_set) + + def copy_test_data(tmpdir): # Put some (binary) content into our new repository test_data_folder = os.path.join(os.path.dirname(__file__), '..', 'test-data') diff --git a/src/python/OBis/obis/dm/repo_test.py b/src/python/OBis/obis/dm/repo_test.py index fd5f25ad18c..a52644c6d4e 100644 --- a/src/python/OBis/obis/dm/repo_test.py +++ b/src/python/OBis/obis/dm/repo_test.py @@ -8,10 +8,12 @@ repo_test.py Created by Chandrasekhar Ramakrishnan on 2017-03-03. Copyright (c) 2017 Chandrasekhar Ramakrishnan. All rights reserved. """ +from unittest.mock import Mock, MagicMock from . import repo as dm_repo from . import data_mgmt -from .data_mgmt_test import git_status, copy_test_data +from .data_mgmt_test import git_status, copy_test_data, prepare_registration_expectations, \ + set_registration_configuration def test_data_use_case(tmpdir): @@ -19,6 +21,8 @@ def test_data_use_case(tmpdir): assert git_status(tmp_dir_path).returncode == 128 # The folder should not be a git repo at first. repo = dm_repo.DataRepo(tmp_dir_path) + prepare_registration_expectations(repo.dm_api) + set_registration_configuration(repo.dm_api) result = repo.init("test") assert result.returncode == 0 diff --git a/src/python/OBis/obis/scripts/cli.py b/src/python/OBis/obis/scripts/cli.py index 0c7e7abf85d..9eab84b807d 100644 --- a/src/python/OBis/obis/scripts/cli.py +++ b/src/python/OBis/obis/scripts/cli.py @@ -45,14 +45,31 @@ def cli(ctx, quiet): @cli.command() +@click.option('-g', '--is_global', default=False, is_flag=True, help='Configure global or local.') +@click.argument('property', default="") +@click.argument('value', default="") @click.pass_context -@click.option('-g', '--global', default=False, is_flag=True, help='Configure global or local.') -def config(ctx): +def config(ctx, is_global, property, value): """Configure the openBIS setup. Configure the openBIS server url, the data set type, and the data set properties. """ - click_echo("config") + ctx.obj['global'] = is_global + resolver = shared_data_mgmt().config_resolver + is_global = ctx.obj['global'] + if is_global: + resolver.location_search_order = ['global'] + else: + resolver.location_search_order = ['local'] + + config_dict = resolver.config_dict() + if not property: + click.echo("{}".format(config_dict)) + elif not value: + click.echo("{}".format(config_dict[property])) + else: + loc = 'global' if is_global else 'local' + resolver.set_value_for_parameter(property, value, loc) @cli.group() -- GitLab