Repository 'gonramp_apollo_tools'
hg clone https://toolshed.g2.bx.psu.edu/repos/yating-l/gonramp_apollo_tools

Changeset 0:ce4f91831680 (2018-02-16)
Commit message:
planemo upload for repository https://github.com/Yating-L/suite_gonramp_apollo.git commit 5367a00befb467f162d1870edb91f9face72e894
added:
README.rst
apollo/ApolloInstance.py
apollo/ApolloOrganism.py
apollo/ApolloOrganism.pyc
apollo/ApolloUser.py
apollo/__init__.py
apollo/__init__.pyc
apollo/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc
apolloUserManager.py
apolloUserManager.pyc
apolloUserManager.xml
gonramp_apollo_tools.iml
jbrowsehubToApollo.py
jbrowsehubToApollo.xml
logging.json
macros.xml
templates/__init__.py
templates/apollo-arrow.yml
test-data/adduserstogroup.csv
test-data/usersInfo.txt
test-data/usersInfo2.csv
tests/__pycache__/conftest.cpython-27-PYTEST.pyc
tests/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc
tests/func/__init__.pyc
tests/func/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc
todo.md
tool_dependencies.xml
util/Logger.py
util/Logger.pyc
util/Reader.py
util/__init__.py
util/__init__.pyc
util/santitizer.py
util/santitizer.pyc
util/subtools.py
b
diff -r 000000000000 -r ce4f91831680 README.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/README.rst Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,64 @@
+G-OnRamp Apollo Tools
+=====================
+
+A suite of Galaxy tools for managing a local Apollo server. It includes following tools:
+
+JBrowseHub to Apollo
+--------------------
+
+This Galaxy tool is used to create or overwrite an organism on an Apollo server with a jbrowse hub created by JBrowse Archive Creator. 
+
+Apollo User Manager
+-------------------
+
+This Galaxy tool is used to manage Apollo users. The currently supported operation including:
+
+  - Create a new user 
+  - Delete a user
+  - Add a user to a group (If the group doesn't exist, create the group)
+  - Remove a user to a group
+
+The tool can do these operations on one student at a time. It can also do the operations on multiple students at a time by uploading a text file, which including students information.
+
+The text file can be either CSV (comma-delimited) or Tabular (tab-delimited). It should have a header line, including names for each column. Example text files: 
+
+Text file for creating multiple users:
+
+.. csv-table:: 
+   :header: "useremail", "firstname", "lastname", "password"
+   :widths: 20, 10, 10, 10
+
+   "test1@demo.com", "test1", "demo", "1234"
+   "test2@demo.com", "test2", "demo", "1234"
+   "test3@demo.com", "test3", "demo", "1234"
+
+
+Text file for deleting multiple users:
+
+.. csv-table:: 
+    :header: "useremail"
+    :widths: 20
+
+    "test1@demo.com"
+    "test2@demo.com"
+    "test3@demo.com"
+
+Text file for adding multiple users to a group:
+
+.. csv-table:: 
+    :header: "useremail", "group"
+    :widths: 20, 20
+
+    "test1@demo.com", "Test group"
+    "test2@demo.com", "Test group"
+    "test3@demo.com", "Test group"
+
+Text file for removing multiple users to a group:
+
+.. csv-table:: 
+    :header: "useremail", "group"
+    :widths: 20, 20
+
+    "test1@demo.com", "Test group"
+    "test2@demo.com", "Test group"
+    "test3@demo.com", "Test group"
b
diff -r 000000000000 -r ce4f91831680 apollo/ApolloInstance.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apollo/ApolloInstance.py Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+import os
+import json
+import shutil
+import tempfile
+import logging
+import random
+import string
+from util import subtools
+from mako.lookup import TemplateLookup
+
+from ApolloOrganism import ApolloOrganism
+from ApolloUser import ApolloUser
+
+class ApolloInstance(object):
+    def __init__(self, apollo_host, apollo_admin, tool_directory):
+        self.apollo_host = apollo_host
+        self.tool_directory = tool_directory
+        self.logger = logging.getLogger(__name__)
+        self.apollo_admin =  apollo_admin
+        self.apolloTemplate = self._getApolloTemplate()
+        self._arrow_init()
+    
+    
+    def _arrow_init(self):
+        subtools.verify_user_login(self.apollo_admin['user_email'], self.apollo_admin['password'], self.apollo_host)
+        arrow_config = tempfile.NamedTemporaryFile(bufsize=0)
+        with open(arrow_config.name, 'w') as conf:
+            htmlMakoRendered = self.apolloTemplate.render(
+            apollo_host = self.apollo_host,
+            admin_user = self.apollo_admin['user_email'],
+            admin_pw = self.apollo_admin['password']
+        )
+            conf.write(htmlMakoRendered)
+
+        home_dir = os.path.expanduser('~')
+        arrow_config_dir = os.path.join(home_dir, '.apollo-arrow.yml')
+        shutil.copyfile(arrow_config.name, arrow_config_dir)
+        self.logger.debug("Initated arrow: apollo-arrow.yml= %s", arrow_config_dir)
+    
+    #TODO: Encode admin password
+    '''
+    def _generatePassword(self, length=8):
+        chars = string.digits + string.letters
+        pw = ''.join([random.choice(chars) for _ in range(length)])
+        return pw
+    '''
+
+    def _getApolloTemplate(self):
+        mylookup = TemplateLookup(directories=[os.path.join(self.tool_directory, 'templates')],
+                                  output_encoding='utf-8', encoding_errors='replace')
+        apolloTemplate = mylookup.get_template("apollo-arrow.yml")
+        return apolloTemplate
+
+   
+    def manageApolloOrganism(self, organism_name, organism_dir, action):
+        organism = ApolloOrganism(organism_name, organism_dir) 
+        if action == "add":
+            organism.addOrganism()
+            self.logger.info("Successfully add a new organism (%s) to Apollo", organism_name)
+        elif action == "overwrite":
+            organism.overwriteOrganism()
+            self.logger.info("Successfully overwrite the organism %s", organism_name)
+        else:
+            self.logger.error("Invalid operation %s", action)
+            exit(-1)
+
+    def manageApolloUser(self, operations_dictionary = dict()):
+        for operation, users_list in operations_dictionary.items(): 
+            apollo_user = ApolloUser(users_list)
+            if operation == "create":
+                apollo_user.createApolloUser()
+            elif operation == "delete":
+                apollo_user.deleteApolloUser()
+            elif operation == "add":
+                apollo_user.addApolloUserToGroup()
+            elif operation == "remove":
+                apollo_user.removeApolloUserFromeGroup()
+
+    
b
diff -r 000000000000 -r ce4f91831680 apollo/ApolloOrganism.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apollo/ApolloOrganism.py Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+
+import json
+import logging
+from util import subtools
+
+class ApolloOrganism(object):
+
+    def __init__(self, organism_name, organism_dir):
+        self.organism_name = organism_name
+        self.organism_dir = organism_dir
+        self.logger = logging.getLogger(__name__)
+
+    def addOrganism(self):
+        exist = subtools.arrow_get_organism(self.organism_name)
+        if not exist:
+            self.logger.debug("The organism does not exist.")
+            p = subtools.arrow_add_organism(self.organism_name, self.organism_dir)
+            if not p:
+                self.logger.error("The user is not authorized to add organism")
+                exit(-1)
+            organism = json.loads(p)
+            organism_id = organism['id']
+            self.logger.debug("A new organism %s was added to Apollo instance", p)
+            return organism_id
+        else:
+            self.logger.error("The organism %s is already on Apollo instance! Rerun the tool to use a different species name or choose to overwrite the organism", self.organism_name)
+            exit(-1)
+
+    #TODO: the JSON dictionary return by deleteOrganism still contains the deleted organism. Improve the API.
+    def deleteOrganism(self):
+        organism_id = subtools.arrow_get_organism(self.organism_name)
+        if organism_id:
+            self.logger.debug("Deleting the organism %s", self.organism_name)
+            subtools.arrow_delete_organism(organism_id)
+            if not subtools.arrow_get_organism(self.organism_name):
+                self.logger.debug("Organism %s has been deleted", self.organism_name)
+            else:
+                self.logger.error("Organism %s cannot be deleted", self.organism_name)
+                exit(-1)
+        else:
+            self.logger.error("Organism %s doesn't exist", self.organism_name)
+            exit(-1)
+
+    #TODO: API update_organism not working. Improve the API to enable updating directory.
+    def overwriteOrganism(self):
+        self.deleteOrganism()
+        p = subtools.arrow_add_organism(self.organism_name, self.organism_dir)
+        if not p:
+            self.logger.error("The user is not authorized to add organism")
+            exit(-1)
+        organism = json.loads(p)
+        organism_id = organism['id']
+        self.logger.debug("A new organism %s has been added to Apollo instance", p)
+        return organism_id
+        
+    
+    
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 apollo/ApolloOrganism.pyc
b
Binary file apollo/ApolloOrganism.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 apollo/ApolloUser.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apollo/ApolloUser.py Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+
+
+import os
+import sys
+import json
+import logging
+from util import subtools
+
+class ApolloUser(object):
+    """ 
+    This class is to manage Apollo users, such as create, delete, add users to a group or delete users from a group
+    
+    """
+
+    def __init__(self, users_list):
+        self.users_list = users_list
+        self.logger = logging.getLogger(__name__)
+
+
+    def createApolloUser(self):
+        for user in self.users_list:
+            if user['batch'] == "false":
+                subtools.arrow_create_user(user['useremail'], user['firstname'], user['lastname'], user['password'])
+            elif user['batch'] == "true":
+                users = self.parseUserInfoFile(user['format'], user['false_path'])
+                for u in users:
+                    if not 'useremail' in u:
+                        self.logger.error("Cannot find useremail in the text file, make sure you use the correct header, see README file for examples.")
+                    if not 'firstname' in u:
+                        self.logger.error("Cannot find firstname in the text file, make sure you use the correct header, see README file for examples.")
+                    if not 'lastname' in u:
+                        self.logger.error("Cannot find lastname in the text file, make sure you use the correct header, see README file for examples.")
+                    if not 'password' in u:
+                        self.logger.error("Cannot find password in the text file, make sure you use the correct header, see README file for examples.")
+                    subtools.arrow_create_user(u['useremail'], u['firstname'], u['lastname'], u['password'])
+    
+    
+    def parseUserInfoFile(self, file_format, filename):
+        if file_format == "tab":
+            delimiter = '\t'
+        elif file_format == "csv":
+            delimiter = ','
+        else:
+            self.logger.error("The %s format is not supported!", file_format)
+        with open(filename, 'r') as f:
+            lines = f.readlines()
+        headers = lines[0].split(delimiter)
+        users = []
+        lines = lines[1:]
+        for l in lines:
+            l = l.split(delimiter)
+            info = dict()
+            fields = len(l)
+            for i in range(fields):
+                title = headers[i].rstrip()
+                info[title] = l[i].rstrip()
+            users.append(info)
+        return users
+
+    def deleteApolloUser(self):
+        for user in self.users_list:
+            if user['batch'] == "false":
+                subtools.arrow_delete_user(user['useremail'])
+            elif user['batch'] == "true":
+                users = self.parseUserInfoFile(user['format'], user['false_path']) 
+                for u in users:
+                    if not 'useremail' in u:
+                        self.logger.error("Cannot find useremail in the text file, make sure you use the correct header, see README file for examples.")
+                    subtools.arrow_delete_user(u['useremail'])
+
+    def addApolloUserToGroup(self):
+        for user in self.users_list:
+            if user['batch'] == "false":
+                subtools.arrow_add_to_group(user['group'], user['useremail'])
+            elif user['batch'] == "true":
+                users = self.parseUserInfoFile(user['format'], user['false_path'])
+                for u in users:
+                    if not 'useremail' in u:
+                        self.logger.error("Cannot find useremail in the text file, make sure you use the correct header, see README file for examples.")
+                    if not 'group' in u:
+                        self.logger.error("Cannot find group in the text file, make sure you use the correct header, see README file for examples.")
+                    subtools.arrow_add_to_group(u['group'], u['useremail'])
+                
+    def removeApolloUserFromeGroup(self):
+        for user in self.users_list:
+            if user['batch'] == "false":
+                subtools.arrow_remove_from_group(user['group'], user['useremail'])
+            elif user['batch'] == "true":
+                users = self.parseUserInfoFile(user['format'], user['false_path'])
+                for u in users:
+                    if not 'useremail' in u:
+                        self.logger.error("Cannot find useremail in the text file, make sure you use the correct header, see README file for examples.")
+                    if not 'group' in u:
+                        self.logger.error("Cannot find group in the text file, make sure you use the correct header, see README file for examples.")
+                    subtools.arrow_remove_from_group(u['group'], u['useremail'])
+                
+
b
diff -r 000000000000 -r ce4f91831680 apollo/__init__.pyc
b
Binary file apollo/__init__.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 apollo/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc
b
Binary file apollo/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 apolloUserManager.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apolloUserManager.py Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+import os
+import sys
+import argparse
+import json
+import logging
+import socket
+from apollo.ApolloInstance import ApolloInstance
+from apollo.ApolloUser import ApolloUser
+from util.Reader import Reader
+from util.Logger import Logger
+
+
+def main(argv):
+    parser = argparse.ArgumentParser(description='Upload a hub to display on Apollo.')
+    parser.add_argument('-j', '--data_json', help='JSON file containing the metadata of the inputs')
+    parser.add_argument('-o', '--output', help='HTML output')
+    
+    # Get the args passed in parameter
+    args = parser.parse_args()
+    json_inputs_data = args.data_json
+    outputFile = args.output
+    
+    ##Parse JSON file with Reader
+    reader = Reader(json_inputs_data)
+
+    # Begin init variables
+    
+    apollo_port = reader.getPortNum()
+    apollo_host = "http://localhost:"+ apollo_port + "/apollo"
+    apollo_admin_user = reader.getAdminUser()
+    toolDirectory = reader.getToolDir()
+    extra_files_path = reader.getExtFilesPath()
+    debug_mode = reader.getDebugMode()
+    operations_dictionary = reader.getOperationList()
+    
+
+    
+        
+    #### Logging management ####
+    # If we are in Debug mode, also print in stdout the debug dump
+    log = Logger(tool_directory=toolDirectory, debug=debug_mode, extra_files_path=extra_files_path)
+    log.setup_logging()
+
+    logging.info("#### Apollo User Manager: Start on Apollo instance: %s #### ", apollo_host)
+    logging.debug('JSON parameters: %s\n\n', json.dumps(reader.args))
+
+    # Set up apollo
+    apollo = ApolloInstance(apollo_host, apollo_admin_user, toolDirectory) 
+    apollo.manageApolloUser(operations_dictionary)
+    outHtml(outputFile, apollo_host)
+    logging.info('#### Apollo User Manager: Congratulation! ####\n')
+
+def outHtml(outputFile, host_name):
+    with open(outputFile, 'w') as htmlfile:
+        htmlstr = 'The Apollo User Manager has done with operations on Apollo: <br>'
+        jbrowse_hub = '<li><a href = "%s" target="_blank">View JBrowse Hub on Apollo</a></li>' % host_name
+        htmlstr += jbrowse_hub
+        htmlfile.write(htmlstr)     
+        
+
+if __name__ == "__main__":
+    main(sys.argv)
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 apolloUserManager.pyc
b
Binary file apolloUserManager.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 apolloUserManager.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/apolloUserManager.xml Fri Feb 16 10:57:13 2018 -0500
[
b'@@ -0,0 +1,290 @@\n+<tool id="apollo_user_manager" name="Apollo User Manager" version="1.0.0">\n+    <description>\n+        This Galaxy tool is used to manage Apollo users. \n+    </description>\n+    <macros>\n+        <import>macros.xml</import>\n+    </macros>\n+\n+    <requirements>\n+        <requirement type="package" version="3.0.3">apollo_api</requirement>\n+    </requirements>\n+\n+    <stdio>\n+    </stdio>\n+\n+    <command detect_errors="exit_code"><![CDATA[\n+        mkdir -p $output.extra_files_path;\n+        ## Dump the tool parameters into a JSON file \n+        python $json_file parameters.json;\n+        python $__tool_directory__/apolloUserManager.py --data_json parameters.json -o $output\n+    ]]></command>\n+    <configfiles>\n+        <configfile name="json_file">\n+import json\n+import sys\n+\n+file_path = sys.argv[1]\n+#set global data_parameter_dict = {"operations": dict()}\n+## Function to retrieve the data of the inputs\n+#def prepare_json($operation_type, $data_dict, $batch)\n+    #silent $data_dict.update({"batch": str($batch)})\n+    #if $operation_type in $data_parameter_dict["operations"]\n+        #silent $data_parameter_dict["operations"][$operation_type].append($data_dict)\n+    #else\n+        #set array_inputs = []\n+        #silent $array_inputs.append($data_dict)\n+        #silent $data_parameter_dict["operations"].update({$operation_type: $array_inputs})\n+    #end if \n+#end def\n+\n+\n+\n+\n+#for $i, $f in enumerate($operation)\n+    #if $f.operation_type_selector.operation_type == "create"\n+        #set batch = $f.operation_type_selector.batch_selector.batch\n+        #if $batch == "false"\n+            #set data_dict = {"useremail": str($f.operation_type_selector.batch_selector.user_email), \n+                            "firstname": str($f.operation_type_selector.batch_selector.firstname),\n+                            "lastname": str($f.operation_type_selector.batch_selector.lastname),\n+                            "password": str($f.operation_type_selector.batch_selector.password)}\n+            \n+        #else \n+            #set data_dict = {"format": str($f.operation_type_selector.batch_selector.format), \n+                                "false_path": str($f.operation_type_selector.batch_selector.user_info_file)}\n+        #end if \n+        #silent $prepare_json("create", $data_dict, $batch)\n+    \n+    #elif $f.operation_type_selector.operation_type == "delete"\n+        #set batch = $f.operation_type_selector.batch_selector.batch\n+        #if $batch == "false"\n+            #set data_dict = {"useremail": str($f.operation_type_selector.batch_selector.user_email)}\n+        #else \n+            #set data_dict = {"format": str($f.operation_type_selector.batch_selector.format), \n+                                "false_path": str($f.operation_type_selector.batch_selector.user_info_file)}\n+        #end if \n+        #silent $prepare_json("delete", $data_dict, $batch)\n+    #elif $f.operation_type_selector.operation_type == "add"\n+        #set batch = $f.operation_type_selector.batch_selector.batch\n+        #if $batch == "false"\n+            #set data_dict = {"useremail": str($f.operation_type_selector.batch_selector.user_email),\n+                        "group": str($f.operation_type_selector.batch_selector.group_name)}\n+        #else \n+            #set data_dict = {"format": str($f.operation_type_selector.batch_selector.format), \n+                                "false_path": str($f.operation_type_selector.batch_selector.user_info_file)}\n+        #end if \n+        #silent $prepare_json("add", $data_dict, $batch)\n+    #elif $f.operation_type_selector.operation_type == "remove"\n+        #set batch = $f.operation_type_selector.batch_selector.batch\n+        #if $batch == "false"\n+            #set data_dict = {"useremail": str($f.operation_type_selector.batch_selector.user_email),\n+                        "group": str($f.operation_type_selector.batch_selector.group_name)}\n+        #else \n+            #set data_dict = {"format": str($f.operat'..b'      <conditional name="batch_selector">\n+                        <param name="batch" type="select" label="Manipulate a single user or multiple users">\n+                            <option value="false" selected="true">Single user</option>\n+                            <option value="true">Multiple users</option>\n+                        </param>\n+                        <when value="false">\n+                            <param name="user_email" type="text" label="User email" help="Specify the user email">\n+                                <sanitizer>\n+                                    <valid initial="string.letters,string.digits">\n+                                        <add value="@-=_.()/+*^,:?!"/>\n+                                    </valid>\n+                                </sanitizer>\n+                            </param>\n+                            <param type="text" name="group_name" size="30" value="unknown" label="Group name" />\n+                        </when>\n+                        <when value="true">\n+                            <expand macro="upload_text_file" />                        \n+                        </when>\n+                    </conditional>\n+                </when>\n+            </conditional>\n+        </repeat>\n+\n+        <conditional name="advanced_options">\n+            <param name="advanced_options_selector" type="select" label="Advanced options">\n+                <option value="off" selected="true">Hide advanced options</option>\n+                <option value="on">Display advanced options</option>\n+            </param>\n+            <!-- TODO: Avoid redundancy here -->\n+            <when value="on">\n+                <param name="port" type="integer" min="8000" max="8888" value="8080" label="Port number of Apollo" />\n+                <param name="debug_mode" type="select" label="Activate debug mode"> \n+                    <option value="false" selected="true">No</option>\n+                    <option value="true">Yes</option>\n+                    <help>\n+                        Use this option if you are a G-OnRamp developer\n+                    </help>\n+                </param>\n+            </when>\n+            <when value="off">\n+                <param name="port" type="hidden" value="8080" />\n+                <param name="debug_mode" type="hidden"\n+                       value="false">\n+                </param>\n+            </when>\n+        </conditional>\n+    </inputs>\n+    <outputs>\n+        <data format="txt" name="output" label="${tool.name} on ${on_string}" />\n+    </outputs>\n+\n+    <help>\n+        This Galaxy tool is used to manage Apollo users.The currently supported operation including:\n+\n+  - Create a new user \n+  - Delete a user\n+  - Add a user to a group (If the group doesn\'t exist, create the group)\n+  - Remove a user to a group\n+\n+The tool can do these operations on one student at a time. It can also do the operations on multiple students at a time by uploading a text file, which including students information.\n+\n+The text file can be either CSV (comma-delimited) or Tabular (tab-delimited). It should have a header line, including names for each column. Example text files: \n+\n+Text file for creating multiple users:\n+\n+.. csv-table:: \n+   :header: "useremail", "firstname", "lastname", "password"\n+   :widths: 20, 10, 10, 10\n+\n+   "test1@demo.com", "test1", "demo", "1234"\n+   "test2@demo.com", "test2", "demo", "1234"\n+   "test3@demo.com", "test3", "demo", "1234"\n+\n+\n+Text file for deleting multiple users:\n+\n+.. csv-table:: \n+    :header: "useremail"\n+    :widths: 20\n+\n+    "test1@demo.com"\n+    "test2@demo.com"\n+    "test3@demo.com"\n+\n+\n+Text file for adding / removing multiple users from a group:\n+\n+.. csv-table:: \n+   :header: "useremail", "group"\n+   :widths: 20, 20\n+\n+   "test1@demo.com", "annotation_group1"\n+   "test2@demo.com", "annotation_group1"\n+   "test3@demo.com", "annotation_group1"\n+\n+    </help>\n+    <citations>\n+    </citations>\n+</tool>\n\\ No newline at end of file\n'
b
diff -r 000000000000 -r ce4f91831680 gonramp_apollo_tools.iml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/gonramp_apollo_tools.iml Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 jbrowsehubToApollo.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jbrowsehubToApollo.py Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+import os
+import sys
+import argparse
+import json
+import logging
+import socket
+from apollo.ApolloInstance import ApolloInstance
+from util.Reader import Reader
+from util.Logger import Logger
+
+
+def main(argv):
+    parser = argparse.ArgumentParser(description='Upload a hub to display on Apollo.')
+    parser.add_argument('-j', '--data_json', help='JSON file containing the metadata of the inputs')
+    parser.add_argument('-o', '--output', help='HTML output')
+    
+    # Get the args passed in parameter
+    args = parser.parse_args()
+    json_inputs_data = args.data_json
+    outputFile = args.output
+    
+    ##Parse JSON file with Reader
+    reader = Reader(json_inputs_data)
+
+    # Begin init variables
+    extra_files_path = reader.getExtFilesPath()
+    jbrowse_hub = reader.getJBrowseHubDir()
+    #user_email = reader.getUserEmail() 
+    species_name = reader.getSpeciesName() 
+    #apollo_host = reader.getApolloHost()
+    apollo_port = reader.getPortNum()
+    apollo_host = "http://localhost:"+ apollo_port + "/apollo"
+    #apollo_host = "http://localhost:8080/apollo"
+    #apollo_user = reader.getApolloUser()
+    apollo_admin_user = reader.getAdminUser()
+    toolDirectory = reader.getToolDir()
+    debug_mode = reader.getDebugMode()
+    action = reader.getAction()
+
+    #### Logging management ####
+    # If we are in Debug mode, also print in stdout the debug dump
+    log = Logger(tool_directory=toolDirectory, debug=debug_mode, extra_files_path=extra_files_path)
+    log.setup_logging()
+
+    logging.info("#### JBrowsehub To Apollo: Start to %s JBrowse Hub to Apollo instance: %s #### ", action, apollo_host)
+    logging.debug('JSON parameters: %s\n\n', json.dumps(reader.args))
+
+    # Set up apollo
+    apollo = ApolloInstance(apollo_host, apollo_admin_user, toolDirectory) 
+    jbrowse_hub_dir = _getHubDir(jbrowse_hub)
+    apollo.manageApolloOrganism(species_name, jbrowse_hub_dir, action)  
+    outHtml(outputFile, apollo_host, species_name, action)
+
+    logging.info('#### JBrowsehub To Apollo: Congratulation! JBrowse Hub is uploaded! ####\n')
+    
+def _getHubDir(extra_files_path):
+    for root, dirs, files in os.walk(extra_files_path):
+        for name in files:
+            if name == "trackList.json":
+                logging.debug("JBrowse hub directory: %s", root)
+                return root
+    logging.error("Cannot find jbrowsehub")
+    exit(-1)
+
+def outHtml(outputFile, host_name, species_name, action):
+    with open(outputFile, 'w') as htmlfile:
+        if action == "add":
+            htmlstr = 'The Organism "%s" is added on Apollo: <br>' % species_name
+        elif action == "overwrite":
+            htmlstr = 'The Organism "%s" is overwritten on Apollo: <br>' % species_name
+        jbrowse_hub = '<li><a href = "%s" target="_blank">View JBrowse Hub on Apollo</a></li>' % host_name
+        htmlstr += jbrowse_hub
+        htmlfile.write(htmlstr)     
+
+if __name__ == "__main__":
+    main(sys.argv)
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 jbrowsehubToApollo.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jbrowsehubToApollo.xml Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,110 @@
+<tool id="jbrowsehubtoapollo" name="JBrowseHub To Apollo" version="1.0.0">
+    <description>
+        This Galaxy tool is used to prepare your files to be ready for displaying on Apollo
+    </description>
+
+    <requirements>
+        <requirement type="package" version="3.0.3">apollo_api</requirement>
+    </requirements>
+
+    <stdio>
+    </stdio>
+
+    <command detect_errors="exit_code"><![CDATA[
+        mkdir -p $output.extra_files_path;
+        ## Dump the tool parameters into a JSON file 
+        python $json_file parameters.json;
+        python $__tool_directory__/jbrowsehubToApollo.py --data_json parameters.json -o $output
+    ]]></command>
+    <configfiles>
+        <configfile name="json_file">
+import json
+import sys
+
+file_path = sys.argv[1]
+#set global data_parameter_dict = {}
+#silent $data_parameter_dict.update({"action": str($action)})
+#silent $data_parameter_dict.update({"action": str($action)})
+#silent $data_parameter_dict.update({"species_name": str($species_name)})
+#set apollo_admin = {"user_email": str($admin_username), "password": str($admin_password)}
+#silent $data_parameter_dict.update({"apollo_admin": $apollo_admin})
+#silent $data_parameter_dict.update({"tool_directory": str($__tool_directory__)})
+#silent $data_parameter_dict.update({"extra_files_path": str($output.extra_files_path)})
+#slient $data_parameter_dict.update({"jbrowse_hub": str($jbrowse_hub.extra_files_path)})
+#silent $data_parameter_dict.update({"port": str($advanced_options.port)})
+#silent $data_parameter_dict.update({"debug_mode": str($advanced_options.debug_mode)})
+with open(file_path, 'w') as f:
+    json.dump($data_parameter_dict, f)
+        </configfile>
+    </configfiles>
+
+
+    <inputs>
+        <param 
+                format="jbrowsehub" 
+                type="data"
+                name="jbrowse_hub" 
+                label="JBrowse Hub created by JBrowse Archive Creator" 
+        />
+
+        <param name="action" type="select" label="Choose to create a new organism or overwrite an organism">
+            <option value="add" selected="true">Add a new organism to Apollo</option>
+            <option value="overwrite">Overwrite an existing organism on Apollo</option>
+        </param>
+        
+        <param
+                name="species_name"
+                type="text"
+                size="30"
+                value="unknown"
+                label="Species name"
+        />
+
+        <param name="admin_username" type="text" label="Admin username" help="Login in with Apollo admin account">
+            <sanitizer>
+                <valid initial="string.letters,string.digits">
+                    <add value="@-=_.()/+*^,:?!"/>
+                </valid>
+            </sanitizer>
+        </param>
+
+        <param
+            name="admin_password"
+            type="text"
+            label="Admin password"
+        />
+
+        <conditional name="advanced_options">
+            <param name="advanced_options_selector" type="select" label="Advanced options">
+                <option value="off" selected="true">Hide advanced options</option>
+                <option value="on">Display advanced options</option>
+            </param>
+            <!-- TODO: Avoid redundancy here -->
+            <when value="on">
+                <param name="port" type="integer" min="8000" max="8888" value="8080" label="Port number of Apollo" />
+                <param name="debug_mode" type="select" label="Activate debug mode"> 
+                    <option value="false" selected="true">No</option>
+                    <option value="true">Yes</option>
+                    <help>
+                        Use this option if you are a G-OnRamp developer
+                    </help>
+                </param>
+            </when>
+            <when value="off">
+                <param name="port" type="hidden" value="8080" />
+                <param name="debug_mode" type="hidden"
+                       value="false">
+                </param>
+            </when>
+        </conditional>
+    </inputs>
+    <outputs>
+        <data format="html" name="output" label="${tool.name}" />
+    </outputs>
+
+    <help>
+        This Galaxy tool is used to create or overwrite an organism on an Apollo server with a jbrowse hub created by JBrowse Archive Creator. 
+    </help>
+    <citations>
+    </citations>
+</tool>
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 logging.json
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/logging.json Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,48 @@
+{
+    "version": 1,
+    "disable_existing_loggers": false,
+    "formatters": {
+        "simple": {
+            "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
+        }
+    },
+
+    "handlers": {
+        "console": {
+            "class": "logging.StreamHandler",
+            "level": "INFO",
+            "formatter": "simple",
+            "stream": "ext://sys.stdout"
+        },
+
+        "console_stderr": {
+            "class": "logging.StreamHandler",
+            "level": "ERROR",
+            "formatter": "simple",
+            "stream": "ext://sys.stderr"
+        },
+
+        "debug_file_handler": {
+            "class": "logging.handlers.RotatingFileHandler",
+            "level": "DEBUG",
+            "formatter": "simple",
+            "filename": "__main__.log",
+            "maxBytes": 10485760,
+            "backupCount": 20,
+            "encoding": "utf8"
+        }
+    },
+
+    "loggers": {
+        "Reader": {
+            "level": "INFO",
+            "handlers": ["console"],
+            "propagate": "yes"
+        }
+    },
+
+    "root": {
+        "level": "DEBUG",
+        "handlers": ["console", "console_stderr", "debug_file_handler"]
+    }
+}
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 macros.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/macros.xml Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,12 @@
+<macros>
+
+    <xml name="upload_text_file">
+        <param name="format" type="select" label="File format">
+            <option value="csv" selected="true">CSV</option>
+            <option value="tab">Tabular</option>
+        </param>
+        <param name="user_info_file" type="data" format="tabular,csv" label="A text file stored a list of users' information" help="tab delimited file or csv file." />
+    
+    </xml>
+
+</macros>
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 templates/apollo-arrow.yml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/apollo-arrow.yml Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,10 @@
+## Apollo's Arrow: Global Configuration File.
+# Each stanza should contian a single galaxy server to control.
+#
+# You can set the key __default to the name of a default instance
+__default: local
+
+local:
+    url: ${apollo_host}
+    username: ${admin_user}
+    password: ${admin_pw}
b
diff -r 000000000000 -r ce4f91831680 test-data/adduserstogroup.csv
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/adduserstogroup.csv Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,4 @@
+useremail,group
+test1@apollo.com,Test A
+test2@apollo.com,Test A
+test3@apollo.com,Test B
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 test-data/usersInfo.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/usersInfo.txt Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,4 @@
+useremail firstname lastname password
+test1@apollo.com test1 apollo 1234
+test2@apollo.com test2 apollo 1234    
+test3@apollo.com test3 apollo 4321
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 test-data/usersInfo2.csv
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/usersInfo2.csv Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,4 @@
+useremail,firstname,lastname,password
+test1@apollo.com,test1,apollo,1234
+test2@apollo.com,test2,apollo,1234
+test3@apollo.com,test3,apollo,4321
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 tests/__pycache__/conftest.cpython-27-PYTEST.pyc
b
Binary file tests/__pycache__/conftest.cpython-27-PYTEST.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 tests/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc
b
Binary file tests/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 tests/func/__init__.pyc
b
Binary file tests/func/__init__.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 tests/func/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc
b
Binary file tests/func/__pycache__/test_apolloInstance.cpython-27-PYTEST.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 todo.md
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/todo.md Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,9 @@
+# JBrowseHubToApollo's TODO
+
+- [ ] Correct new Apollo user's email address. Galaxy santitizes '@' to '__at__' 
+- [ ] Check password for admin login 
+
+### DONE
+
+
+- [x] upload jbrowsehub to Apollo instance
b
diff -r 000000000000 -r ce4f91831680 tool_dependencies.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tool_dependencies.xml Fri Feb 16 10:57:13 2018 -0500
b
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<tool_dependency>
+    
+    <package name="apollo_api" version="3.0.3">
+        <install version="1.0">
+            <actions>
+                <action type="download_by_url">https://github.com/galaxy-genome-annotation/python-apollo/archive/3.0.3.tar.gz</action>
+                <action type="make_directory">$INSTALL_DIR/apollo</action>
+                <action type="shell_command">
+                    export PYTHONPATH=$PYTHONPATH:$INSTALL_DIR/apollo &amp;&amp; 
+                    python setup.py install --install-lib $INSTALL_DIR/apollo
+                </action>
+                <action type="set_environment">
+                    <environment_variable action="append_to" name="PYTHONPATH">$INSTALL_DIR/apollo</environment_variable>
+                    <environment_variable action="append_to" name="PATH">$INSTALL_DIR/apollo</environment_variable>
+                </action>
+            </actions>
+        </install>
+    </package>
+
+
+    
+</tool_dependency>
b
diff -r 000000000000 -r ce4f91831680 util/Logger.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/util/Logger.py Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,40 @@
+import os
+import sys
+import json
+import logging
+import logging.config
+
+#from util.Filters import TraceBackFormatter
+
+class Logger(object):
+    def __init__(self, tool_directory, debug="False", extra_files_path=None):
+        self.tool_directory = tool_directory
+        self.default_level = logging.INFO
+        self.debug = debug
+        self.extra_files_path = extra_files_path
+
+    def setup_logging(self):
+        """
+        Setup logging configuration
+        reference: https://fangpenlin.com/posts/2012/08/26/good-logging-practice-in-python/
+        """
+        config_path = os.path.join(self.tool_directory, 'logging.json')
+        default_level=logging.INFO
+        if self.debug.lower() == "true":
+            default_level=logging.DEBUG
+        if os.path.exists(config_path):
+            with open(config_path, 'rt') as f:
+                config = json.load(f)
+            config["handlers"]["console"]["level"] = default_level
+            if self.extra_files_path:
+                for i in config["handlers"]:
+                    if "filename" in config["handlers"][i]:
+                        config["handlers"][i]["filename"] = os.path.join(self.extra_files_path, config["handlers"][i]["filename"])
+                logging.config.dictConfig(config)
+            else:
+                logging.config.dictConfig(config)
+                logging.warn("Extra files path is not set. The log files will exist at current working directory instead of final output folder")
+        else:
+            logging.basicConfig(level=default_level)
+            logging.warn("Cannot find logging configuration file!\n")
+
b
diff -r 000000000000 -r ce4f91831680 util/Logger.pyc
b
Binary file util/Logger.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 util/Reader.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/util/Reader.py Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,92 @@
+import json
+import re
+import logging
+import codecs
+import socket
+from apollo.ApolloUser import ApolloUser
+from util import santitizer 
+
+class Reader(object):
+
+    def __init__(self, input_json_file):
+        self.inputFile = input_json_file
+        self.args = self.loadJson()
+        
+    
+    def loadJson(self):
+        try:
+            data_file = codecs.open(self.inputFile, 'r', 'utf-8')   
+            return json.load(data_file) 
+        except IOError:
+            print "Cannot find JSON file\n"
+            exit(1)
+
+    def getJBrowseHubDir(self):
+        try:
+            return self.args["jbrowse_hub"]
+        except KeyError:
+            print ("jbrowse_hub is not defined in the input file!")
+            exit(1)
+
+    def getToolDir(self):
+        try:
+            return self.args["tool_directory"]
+        except KeyError:
+            print ("tool_directory is not defined in the input file!")
+            exit(1)
+
+    def getExtFilesPath(self):
+        try:
+            return self.args["extra_files_path"]
+        except KeyError:
+            print ("extra_files_path is not defined in the input file!")
+            exit(1)
+
+    def getUserEmail(self):
+        try:
+            return self.args["user_email"]
+        except KeyError:
+            print ("user_email is not defined in the input file!")
+            exit(1)
+    
+    def getDebugMode(self):
+        try:
+            return self.args["debug_mode"]
+        except KeyError:
+            print ("debug_mode is not defined in the input file!")
+            exit(1)
+            
+    def getPortNum(self):
+        try:
+            return self.args["port"]
+        except KeyError:
+            print ("port is not defined in the input file!")
+            exit(1)
+    
+    def getApolloHost(self):
+        #apollo_host = self.args.get("apollo_host")
+        hostname = socket.gethostname()
+        ip = socket.gethostbyname(hostname)
+        protocol = socket.getprotobyname(hostname)
+        apollo_host = str(protocol) + str(ip)
+        return apollo_host
+        
+        
+    def getSpeciesName(self):
+        species_name = santitizer.sanitize_name_input(self.args["species_name"])
+        return species_name 
+
+    def getAction(self):
+        action = self.args.get("action")
+        return action
+
+    def getAdminUser(self):
+        apollo_admin = self.args.get("apollo_admin")
+        return apollo_admin    
+
+
+    def getOperationList(self):
+        l = self.args.get("operations")
+        return l
+
+    
\ No newline at end of file
b
diff -r 000000000000 -r ce4f91831680 util/__init__.pyc
b
Binary file util/__init__.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 util/santitizer.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/util/santitizer.py Fri Feb 16 10:57:13 2018 -0500
[
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+
+"""
+This class handles the subprocess calls of the different tools used
+in HubArchiveCreator
+"""
+
+import logging
+import os
+import subprocess
+import sys
+import string
+import tempfile
+
+    
+def prefixTrackName(filename):       
+    """
+    santitize trackName. Because track name must begin with a letter and
+    contain only the following chars: [a-zA-Z0-9_].
+    See the "track" Common settings at:
+    https://genome.ucsc.edu/goldenpath/help/trackDb/trackDbHub.html#bigPsl_-_Pairwise_Alignments
+    skip the santitization for cytoBandIdeo track
+    """
+    if filename == 'cytoBandIdeo':
+        return filename
+    valid_chars = "_%s%s" % (string.ascii_letters, string.digits)
+    sanitize_name = ''.join([c if c in valid_chars else '_' for c in filename])
+    sanitize_name = "gonramp_" + sanitize_name
+    return sanitize_name
+
+def sanitize_name_input(string_to_sanitize):
+    """
+    Sanitize the string passed in parameter by replacing '/' and ' ' by '_'
+
+    :param string_to_sanitize:
+    :return :
+
+    :Example:
+
+    >>> sanitize_name_input('this/is an//example')
+    this_is_an__example
+    """
+    return string_to_sanitize \
+            .replace("/", "_") \
+            .replace(" ", "_")
+
+def sanitize_name_inputs(inputs_data):
+    """
+    Sanitize value of the keys "name" of the dictionary passed in parameter.
+
+    Because sometimes output from Galaxy, or even just file name, from user inputs, have spaces.
+    Also, it can contain '/' character and could break the use of os.path function.
+
+    :param inputs_data: dict[string, dict[string, string]]
+    """
+    for key in inputs_data:
+        inputs_data[key]["name"] = sanitize_name_input(inputs_data[key]["name"])
+
+def sanitize_group_name(group_name):
+    return group_name.lower().replace(' ', '_')
+
+def sanitize_name(input_name):
+    """
+    Galaxy will name all the files and dirs as *.dat, 
+    the function can replace '.' to '_' for the dirs
+    """
+    validChars = "_-%s%s" % (string.ascii_letters, string.digits)
+    sanitized_name = ''.join([c if c in validChars else '_' for c in input_name])
+    return "gonramp_" + sanitized_name
b
diff -r 000000000000 -r ce4f91831680 util/santitizer.pyc
b
Binary file util/santitizer.pyc has changed
b
diff -r 000000000000 -r ce4f91831680 util/subtools.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/util/subtools.py Fri Feb 16 10:57:13 2018 -0500
[
b'@@ -0,0 +1,220 @@\n+#!/usr/bin/env python\n+\n+"""\n+This file include common used functions for converting file format to gff3\n+"""\n+from collections import OrderedDict\n+import json\n+import subprocess\n+import os\n+import sys\n+import tempfile\n+import string\n+import logging\n+\n+class PopenError(Exception):\n+    def __init__(self, cmd, error, return_code):\n+        self.cmd = cmd\n+        self.error = error\n+        self.return_code = return_code\n+\n+    def __str__(self):\n+        message = "The subprocess {0} has returned the error: {1}.".format(\n+            self.cmd, self.return_code)\n+        message = \',\'.join(\n+            (message, "Its error message is: {0}".format(self.error)))\n+        return repr(message)\n+\n+\n+def _handleExceptionAndCheckCall(array_call, **kwargs):\n+    """\n+    This class handle exceptions and call the tool.\n+    It maps the signature of subprocess.check_call:\n+    See https://docs.python.org/2/library/subprocess.html#subprocess.check_call\n+    """\n+    stdout = kwargs.get(\'stdout\', subprocess.PIPE)\n+    stderr = kwargs.get(\'stderr\', subprocess.PIPE)\n+    shell = kwargs.get(\'shell\', False)\n+    stdin = kwargs.get(\'stdin\', None)\n+\n+    cmd = array_call[0]\n+\n+    output = None\n+    error = None\n+\n+    # TODO: Check the value of array_call and <=[0]\n+    logging.debug("Calling {0}:".format(cmd))\n+    logging.debug("%s", array_call)\n+    logging.debug("---------")\n+\n+    # TODO: Use universal_newlines option from Popen?\n+    try:\n+        p = subprocess.Popen(array_call, stdout=stdout,\n+                             stderr=stderr, shell=shell, stdin=stdin)\n+\n+        # TODO: Change this because of possible memory issues => https://docs.python.org/2/library/subprocess.html#subprocess.Popen.communicate\n+\n+        output, error = p.communicate()\n+\n+        if stdout == subprocess.PIPE:\n+            logging.debug("\\t{0}".format(output))\n+        else:\n+            logging.debug("\\tOutput in file {0}".format(stdout.name))\n+        # If we detect an error from the subprocess, then we raise an exception\n+        # TODO: Manage if we raise an exception for everything, or use CRITICAL etc... but not stop process\n+        # TODO: The responsability of returning a sys.exit() should not be there, but up in the app.\n+        if p.returncode:\n+            if stderr == subprocess.PIPE:\n+                raise PopenError(cmd, error, p.returncode)\n+            else:\n+                # TODO: To Handle properly with a design behind, if we received a option as a file for the error\n+                raise Exception("Error when calling {0}. Error as been logged in your file {1}. Error code: {2}".format(cmd, stderr.name, p.returncode))\n+\n+    except OSError as e:\n+        message = "The subprocess {0} has encountered an OSError: {1}".format(\n+            cmd, e.strerror)\n+        if e.filename:\n+            message = \'\\n\'.join(\n+                (message, ", against this file: {0}".format(e.filename)))\n+        logging.error(message)\n+        sys.exit(-1)\n+    except PopenError as p:\n+        message = "The subprocess {0} has returned the error: {1}.".format(\n+            p.cmd, p.return_code)\n+        message = \'\\n\'.join(\n+            (message, "Its error message is: {0}".format(p.error)))\n+\n+        logging.exception(message)\n+\n+        sys.exit(p.return_code)\n+    except Exception as e:\n+        message = "The subprocess {0} has encountered an unknown error: {1}".format(\n+            cmd, e)\n+        logging.exception(message)\n+\n+        sys.exit(-1)\n+    return output\n+\n+def arrow_add_organism(organism_name, organism_dir, public=False):\n+    array_call = [\'arrow\', \'organisms\', \'add_organism\', organism_name, organism_dir]\n+    if public:\n+        array_call.append(\'--public\')\n+    p = _handleExceptionAndCheckCall(array_call)\n+    #p = subprocess.check_output(array_call)\n+    return p\n+\n+def arrow_create_user(user_email, firstname, lastname, password, admin=False):\n+    """ \n+    Create a new user of Apollo, the default user_role is '..b': %s", j[\'error\'])\n+        exit(-1)\n+        \n+        \n+def arrow_delete_user(user_email):\n+    array_call = [\'arrow\', \'users\', \'delete_user\', user_email]\n+    p = _handleExceptionAndCheckCall(array_call)\n+    j = json.loads(p)\n+    if "error" in j:\n+        logging.error("Got error message: %s", j[\'error\'])\n+        exit(-1)\n+\n+def arrow_add_to_group(groupname, user_email):\n+    if not arrow_get_groups(groupname):\n+        arrow_create_group(groupname)\n+    array_call = [\'arrow\', \'users\', \'add_to_group\', groupname, user_email]\n+    p = _handleExceptionAndCheckCall(array_call)\n+    j = json.loads(p)\n+    if j != dict():\n+        logging.error("Error add user %s to group %s. The user doesn\'t exist", user_email, groupname)\n+\n+\n+def arrow_remove_from_group(groupname, user_email):\n+    if arrow_get_groups(groupname):\n+        array_call = [\'arrow\', \'users\', \'remove_from_group\', groupname, user_email]\n+        p = _handleExceptionAndCheckCall(array_call)\n+        j = json.loads(p)\n+        if j != dict():\n+            logging.error("Error remove user %s to group %s. The user doesn\'t exist", user_email, groupname)\n+    else:\n+        logging.error("Group %s doesn\'t exist. Check if you spell the name correctly", groupname)\n+\n+def arrow_create_group(groupname):\n+    if arrow_get_groups(groupname):\n+        logging.error("Group %s already exist. Create a group with another name.", groupname)\n+    array_call = [\'arrow\', \'groups\', \'create_group\', groupname]\n+    p = _handleExceptionAndCheckCall(array_call)\n+\n+def arrow_get_groups(groupname):\n+    array_call = [\'arrow\', \'groups\', \'get_groups\']\n+    p = _handleExceptionAndCheckCall(array_call)\n+    all_groups = json.loads(p)\n+    for g in all_groups:\n+        if g[\'name\'] == groupname:\n+            return True\n+    return False\n+\n+def arrow_update_organism_permissions(user_id, organism, **user_permissions):\n+    array_call = [\'arrow\', \'users\', \'update_organism_permissions\', str(user_id), str(organism)]\n+    admin = user_permissions.get("admin", False)\n+    write = user_permissions.get("write", False)\n+    read = user_permissions.get("read", False)\n+    export = user_permissions.get("export", False)\n+    if admin:\n+        array_call.append(\'--administrate\')\n+    if write:\n+        array_call.append(\'--write\')\n+    if read:\n+        array_call.append(\'--read\')\n+    if export:\n+        array_call.append(\'--export\')\n+    p = _handleExceptionAndCheckCall(array_call)\n+    return p\n+\n+def arrow_get_users(user_email):\n+    array_call = [\'arrow\', \'users\', \'get_users\']\n+    p = _handleExceptionAndCheckCall(array_call)\n+    all_users = json.loads(p)\n+    for d in all_users:\n+        if d[\'username\'] == user_email:\n+            return d[\'userId\']\n+    logging.error("Cannot find user %s", user_email)\n+\n+def arrow_get_organism(organism_name):\n+    array_call= [\'arrow\', \'organisms\', \'get_organisms\', \'--common_name\', organism_name]\n+    p = _handleExceptionAndCheckCall(array_call)\n+    org = json.loads(p)\n+    if \'error\' not in org:\n+        return org[0][\'id\']\n+    else:\n+        logging.debug("Got error msg %s when look for organism %s.", org[\'error\'], organism_name)\n+\n+def arrow_delete_organism(organism_id):\n+    array_call = [\'arrow\', \'organisms\', \'delete_organism\', str(organism_id)]\n+    p = _handleExceptionAndCheckCall(array_call)\n+    return p\n+    \n+def verify_user_login(username, password, apollo_host):\n+    user_info = {\'username\': username, \'password\': password}\n+    array_call = [\'curl\', \n+                  \'-b\', \'cookies.txt\', \n+                  \'-c\', \'cookies.txt\', \n+                  \'-H\', \'Content-Type:application/json\',\n+                  \'-d\', json.dumps(user_info),\n+                  apollo_host + \'/Login?operation=login\'\n+                  ]\n+    p = _handleExceptionAndCheckCall(array_call)\n+    msg = json.loads(p)\n+    if \'error\' in msg:\n+        logging.error("The Authentication for user %s failed. Get error message %s", username, msg[\'error\'])\n+        exit(-1)\n+    \n+        \n'