galaxy-commits
Threads by month
- ----- 2026 -----
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
commit/galaxy-central: inithello: Extension of framework to automate the installation of a list of tool shed repositories to also run any functional tests in the tools contained within each repository.
by Bitbucket 20 Feb '13
by Bitbucket 20 Feb '13
20 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/b9c93f559efa/
changeset: b9c93f559efa
user: inithello
date: 2013-02-20 20:27:36
summary: Extension of framework to automate the installation of a list of tool shed repositories to also run any functional tests in the tools contained within each repository.
affected #: 6 files
diff -r efebd50fd708aa3af73f954e4da68e88f2bced9a -r b9c93f559efa7a50cfa445b5f79c579690155589 install_and_test_tool_shed_repositories.sh
--- /dev/null
+++ b/install_and_test_tool_shed_repositories.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# A good place to look for nose info: http://somethingaboutorange.com/mrl/projects/nose/
+#rm -f ./test/tool_shed/run_functional_tests.log
+
+python test/install_and_test_tool_shed_repositories/functional_tests.py -v --with-nosehtml --html-report-file ./test/install_and_test_tool_shed_repositories/run_functional_tests.html test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py test/functional/test_toolbox.py
+
diff -r efebd50fd708aa3af73f954e4da68e88f2bced9a -r b9c93f559efa7a50cfa445b5f79c579690155589 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -4,10 +4,12 @@
# Assume we are run from the galaxy root directory, add lib to the python path
cwd = os.getcwd()
-new_path = [ os.path.join( cwd, "lib" ) ]
+new_path = [ os.path.join( cwd, "lib" ), os.path.join( cwd, "test" ) ]
new_path.extend( sys.path[1:] )
sys.path = new_path
+from base.util import parse_tool_panel_config
+
from galaxy import eggs
eggs.require( "nose" )
@@ -85,73 +87,6 @@
global_conf.update( get_static_settings() )
return global_conf
-def parse_tool_panel_config( config, shed_tools_dict ):
- """
- Parse a shed-related tool panel config to generate the shed_tools_dict. This only happens when testing tools installed from the tool shed.
- """
- last_galaxy_test_file_dir = None
- last_tested_repository_name = None
- last_tested_changeset_revision = None
- tool_path = None
- tree = util.parse_xml( config )
- root = tree.getroot()
- tool_path = root.get('tool_path')
- for elem in root:
- if elem.tag == 'tool':
- galaxy_test_file_dir, \
- last_tested_repository_name, \
- last_tested_changeset_revision = get_installed_repository_info( elem,
- last_galaxy_test_file_dir,
- last_tested_repository_name,
- last_tested_changeset_revision,
- tool_path )
- if galaxy_test_file_dir:
- if galaxy_test_file_dir != last_galaxy_test_file_dir:
- if not os.path.isabs( galaxy_test_file_dir ):
- galaxy_test_file_dir = os.path.join( os.getcwd(), galaxy_test_file_dir )
- guid = elem.get( 'guid' )
- shed_tools_dict[ guid ] = galaxy_test_file_dir
- last_galaxy_test_file_dir = galaxy_test_file_dir
- elif elem.tag == 'section':
- for section_elem in elem:
- if section_elem.tag == 'tool':
- galaxy_test_file_dir, \
- last_tested_repository_name, \
- last_tested_changeset_revision = get_installed_repository_info( section_elem,
- last_galaxy_test_file_dir,
- last_tested_repository_name,
- last_tested_changeset_revision,
- tool_path )
- if galaxy_test_file_dir:
- if galaxy_test_file_dir != last_galaxy_test_file_dir:
- if not os.path.isabs( galaxy_test_file_dir ):
- galaxy_test_file_dir = os.path.join( os.getcwd(), galaxy_test_file_dir )
- guid = section_elem.get( 'guid' )
- shed_tools_dict[ guid ] = galaxy_test_file_dir
- last_galaxy_test_file_dir = galaxy_test_file_dir
- return shed_tools_dict
-
-def get_installed_repository_info( elem, last_galaxy_test_file_dir, last_tested_repository_name, last_tested_changeset_revision, tool_path ):
- """
- Return the GALAXY_TEST_FILE_DIR, the containing repository name and the change set revision for the tool elem.
- This only happens when testing tools installed from the tool shed.
- """
- tool_config_path = elem.get( 'file' )
- installed_tool_path_items = tool_config_path.split( '/repos/' )
- sans_shed = installed_tool_path_items[ 1 ]
- path_items = sans_shed.split( '/' )
- repository_owner = path_items[ 0 ]
- repository_name = path_items[ 1 ]
- changeset_revision = path_items[ 2 ]
- if repository_name != last_tested_repository_name or changeset_revision != last_tested_changeset_revision:
- # Locate the test-data directory.
- installed_tool_path = os.path.join( installed_tool_path_items[ 0 ], 'repos', repository_owner, repository_name, changeset_revision )
- for root, dirs, files in os.walk( os.path.join(tool_path, installed_tool_path )):
- if 'test-data' in dirs:
- return os.path.join( root, 'test-data' ), repository_name, changeset_revision
- return None, repository_name, changeset_revision
- return last_galaxy_test_file_dir, last_tested_repository_name, last_tested_changeset_revision
-
def run_tests( test_config ):
loader = nose.loader.TestLoader( config=test_config )
plug_loader = test_config.plugins.prepareTestLoader( loader )
diff -r efebd50fd708aa3af73f954e4da68e88f2bced9a -r b9c93f559efa7a50cfa445b5f79c579690155589 test/base/util.py
--- /dev/null
+++ b/test/base/util.py
@@ -0,0 +1,80 @@
+import os, sys
+
+cwd = os.getcwd()
+if cwd not in sys.path:
+ sys.path.append( cwd )
+
+new_path = [ os.path.join( cwd, "lib" ) ]
+if new_path not in sys.path:
+ new_path.extend( sys.path )
+ sys.path = new_path
+
+from galaxy.util import parse_xml
+
+def get_installed_repository_info( elem, last_galaxy_test_file_dir, last_tested_repository_name, last_tested_changeset_revision, tool_path ):
+ """
+ Return the GALAXY_TEST_FILE_DIR, the containing repository name and the change set revision for the tool elem.
+ This only happens when testing tools installed from the tool shed.
+ """
+ tool_config_path = elem.get( 'file' )
+ installed_tool_path_items = tool_config_path.split( '/repos/' )
+ sans_shed = installed_tool_path_items[ 1 ]
+ path_items = sans_shed.split( '/' )
+ repository_owner = path_items[ 0 ]
+ repository_name = path_items[ 1 ]
+ changeset_revision = path_items[ 2 ]
+ if repository_name != last_tested_repository_name or changeset_revision != last_tested_changeset_revision:
+ # Locate the test-data directory.
+ installed_tool_path = os.path.join( installed_tool_path_items[ 0 ], 'repos', repository_owner, repository_name, changeset_revision )
+ for root, dirs, files in os.walk( os.path.join(tool_path, installed_tool_path )):
+ if 'test-data' in dirs:
+ return os.path.join( root, 'test-data' ), repository_name, changeset_revision
+ return None, repository_name, changeset_revision
+ return last_galaxy_test_file_dir, last_tested_repository_name, last_tested_changeset_revision
+
+def parse_tool_panel_config( config, shed_tools_dict ):
+ """
+ Parse a shed-related tool panel config to generate the shed_tools_dict. This only happens when testing tools installed from the tool shed.
+ """
+ last_galaxy_test_file_dir = None
+ last_tested_repository_name = None
+ last_tested_changeset_revision = None
+ tool_path = None
+ tree = parse_xml( config )
+ root = tree.getroot()
+ tool_path = root.get('tool_path')
+ for elem in root:
+ if elem.tag == 'tool':
+ galaxy_test_file_dir, \
+ last_tested_repository_name, \
+ last_tested_changeset_revision = get_installed_repository_info( elem,
+ last_galaxy_test_file_dir,
+ last_tested_repository_name,
+ last_tested_changeset_revision,
+ tool_path )
+ if galaxy_test_file_dir:
+ if galaxy_test_file_dir != last_galaxy_test_file_dir:
+ if not os.path.isabs( galaxy_test_file_dir ):
+ galaxy_test_file_dir = os.path.join( os.getcwd(), galaxy_test_file_dir )
+ guid = elem.get( 'guid' )
+ shed_tools_dict[ guid ] = galaxy_test_file_dir
+ last_galaxy_test_file_dir = galaxy_test_file_dir
+ elif elem.tag == 'section':
+ for section_elem in elem:
+ if section_elem.tag == 'tool':
+ galaxy_test_file_dir, \
+ last_tested_repository_name, \
+ last_tested_changeset_revision = get_installed_repository_info( section_elem,
+ last_galaxy_test_file_dir,
+ last_tested_repository_name,
+ last_tested_changeset_revision,
+ tool_path )
+ if galaxy_test_file_dir:
+ if galaxy_test_file_dir != last_galaxy_test_file_dir:
+ if not os.path.isabs( galaxy_test_file_dir ):
+ galaxy_test_file_dir = os.path.join( os.getcwd(), galaxy_test_file_dir )
+ guid = section_elem.get( 'guid' )
+ shed_tools_dict[ guid ] = galaxy_test_file_dir
+ last_galaxy_test_file_dir = galaxy_test_file_dir
+ return shed_tools_dict
+
diff -r efebd50fd708aa3af73f954e4da68e88f2bced9a -r b9c93f559efa7a50cfa445b5f79c579690155589 test/install_and_test_tool_shed_repositories/base/twilltestcase.py
--- a/test/install_and_test_tool_shed_repositories/base/twilltestcase.py
+++ b/test/install_and_test_tool_shed_repositories/base/twilltestcase.py
@@ -121,4 +121,12 @@
( timeout_counter, repository.status ) )
break
time.sleep( 1 )
+ def uninstall_repository( self, installed_repository ):
+ url = '/admin_toolshed/deactivate_or_uninstall_repository?id=%s' % self.security.encode_id( installed_repository.id )
+ self.visit_url( url )
+ tc.fv ( 1, "remove_from_disk", 'true' )
+ tc.submit( 'deactivate_or_uninstall_repository_button' )
+ strings_displayed = [ 'The repository named' ]
+ strings_displayed.append( 'has been uninstalled' )
+ self.check_for_strings( strings_displayed, strings_not_displayed=[] )
diff -r efebd50fd708aa3af73f954e4da68e88f2bced9a -r b9c93f559efa7a50cfa445b5f79c579690155589 test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
--- a/test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
+++ b/test/install_and_test_tool_shed_repositories/functional/test_install_repositories.py
@@ -1,18 +1,33 @@
-import new
+import new, logging
import install_and_test_tool_shed_repositories.base.test_db_util as test_db_util
from install_and_test_tool_shed_repositories.base.twilltestcase import InstallTestRepository
+log = logging.getLogger(__name__)
class TestInstallRepositories( InstallTestRepository ):
- """Abstract test case that installs a predefined list of repositories."""
+ """Abstract test case that installs and uninstalls a predefined list of repositories."""
def do_installation( self, repository_info_dict ):
self.logout()
self.login( email='test(a)bx.psu.edu', username='test' )
admin_user = test_db_util.get_user( 'test(a)bx.psu.edu' )
assert admin_user is not None, 'Problem retrieving user with email %s from the database' % admin_email
admin_user_private_role = test_db_util.get_private_role( admin_user )
+ # Install the repository through the web interface using twill.
self.install_repository( repository_info_dict )
-def build_tests( repository_dict=None ):
+ def do_uninstallation( self, repository_info_dict ):
+ self.logout()
+ self.login( email='test(a)bx.psu.edu', username='test' )
+ admin_user = test_db_util.get_user( 'test(a)bx.psu.edu' )
+ assert admin_user is not None, 'Problem retrieving user with email %s from the database' % admin_email
+ # Get the repository from the database.
+ repository = test_db_util.get_installed_repository_by_name_owner_changeset_revision( repository_info_dict[ 'name' ],
+ repository_info_dict[ 'owner' ],
+ repository_info_dict[ 'changeset_revision' ] )
+ admin_user_private_role = test_db_util.get_private_role( admin_user )
+ # Uninstall the repository through the web interface using twill.
+ self.uninstall_repository( repository )
+
+def generate_install_method( repository_dict=None ):
"""Generate abstract test cases for the defined list of repositories."""
if repository_dict is None:
return
@@ -20,7 +35,7 @@
G = globals()
# Eliminate all previous tests from G.
for key, val in G.items():
- if key.startswith( 'TestInstallRepository_' ):
+ if key.startswith( 'TestInstallRepository_' ) or key.startswith( 'TestUninstallRepository_' ):
del G[ key ]
# Create a new subclass with a method named install_repository_XXX that installs the repository specified by the provided dict.
name = "TestInstallRepository_" + repository_dict[ 'name' ]
@@ -37,3 +52,29 @@
# from baseclasses (which should be a tuple of classes) and with namespace dict.
new_class_obj = new.classobj( name, baseclasses, namespace )
G[ name ] = new_class_obj
+
+def generate_uninstall_method( repository_dict=None ):
+ """Generate abstract test cases for the defined list of repositories."""
+ if repository_dict is None:
+ return
+ # Push all the toolbox tests to module level
+ G = globals()
+ # Eliminate all previous tests from G.
+ for key, val in G.items():
+ if key.startswith( 'TestInstallRepository_' ) or key.startswith( 'TestUninstallRepository_' ):
+ del G[ key ]
+ # Create a new subclass with a method named install_repository_XXX that installs the repository specified by the provided dict.
+ name = "TestUninstallRepository_" + repository_dict[ 'name' ]
+ baseclasses = ( TestInstallRepositories, )
+ namespace = dict()
+ def make_uninstall_method( repository_dict ):
+ def test_install_repository( self ):
+ self.do_uninstallation( repository_dict )
+ return test_install_repository
+ test_method = make_uninstall_method( repository_dict )
+ test_method.__doc__ = "Uninstall the repository %s." % repository_dict[ 'name' ]
+ namespace[ 'install_repository_%s' % repository_dict[ 'name' ] ] = test_method
+ # The new.classobj function returns a new class object, with name name, derived
+ # from baseclasses (which should be a tuple of classes) and with namespace dict.
+ new_class_obj = new.classobj( name, baseclasses, namespace )
+ G[ name ] = new_class_obj
diff -r efebd50fd708aa3af73f954e4da68e88f2bced9a -r b9c93f559efa7a50cfa445b5f79c579690155589 test/install_and_test_tool_shed_repositories/functional_tests.py
--- a/test/install_and_test_tool_shed_repositories/functional_tests.py
+++ b/test/install_and_test_tool_shed_repositories/functional_tests.py
@@ -1,5 +1,9 @@
#!/usr/bin/env python
+# NOTE: This script cannot be run directly, because it needs to have test/functional/test_toolbox.py in sys.argv in
+# order to run functional tests on repository tools after installation. The install_and_test_tool_shed_repositories.sh
+# will execute this script with the appropriate parameters.
+
import os, sys, shutil, tempfile, re, string
# Assume we are run from the galaxy root directory, add lib to the python path
@@ -8,9 +12,9 @@
test_home_directory = os.path.join( cwd, 'test', 'install_and_test_tool_shed_repositories' )
default_test_file_dir = os.path.join( test_home_directory, 'test_data' )
+
# Here's the directory where everything happens. Temporary directories are created within this directory to contain
-# the hgweb.config file, the database, new repositories, etc. Since the tool shed browses repository contents via HTTP,
-# the full path to the temporary directroy wher eht repositories are located cannot contain invalid url characters.
+# the database, new repositories, etc.
galaxy_test_tmp_dir = os.path.join( test_home_directory, 'tmp' )
default_galaxy_locales = 'en'
default_galaxy_test_file_dir = "test-data"
@@ -43,12 +47,15 @@
import galaxy.app
from galaxy.app import UniverseApplication
from galaxy.web import buildapp
+from galaxy.util import parse_xml
import nose.core
import nose.config
import nose.loader
import nose.plugins.manager
+from base.util import parse_tool_panel_config
+
log = logging.getLogger( 'install_and_test_repositories' )
default_galaxy_test_port_min = 10000
@@ -66,11 +73,13 @@
</tool_sheds>
'''
+# Create a blank shed_tool_conf.xml to hold the installed repositories.
shed_tool_conf_xml_template = '''<?xml version="1.0"?><toolbox tool_path="${shed_tool_path}"></toolbox>
'''
+# Since we will be running functional tests, we'll need the upload tool, but the rest can be omitted.
tool_conf_xml = '''<?xml version="1.0"?><toolbox><section name="Get Data" id="getext">
@@ -79,11 +88,13 @@
</toolbox>
'''
+# And set up a blank tool_data_table_conf.xml and shed_tool_data_table_conf.xml.
tool_data_table_conf_xml_template = '''<?xml version="1.0"?><tables></tables>
'''
+# Define a default location to find the list of repositories to check.
galaxy_repository_list = os.environ.get( 'GALAXY_INSTALL_TEST_REPOSITORY_FILE', 'repository_list.json' )
if 'GALAXY_INSTALL_TEST_SECRET' not in os.environ:
@@ -92,7 +103,7 @@
else:
galaxy_encode_secret = os.environ[ 'GALAXY_INSTALL_TEST_SECRET' ]
-def get_repositories_to_install():
+def get_repositories_to_install( format='json' ):
'''
Get a list of repository info dicts to install. This method expects a json list of dicts with the following structure:
[
@@ -107,7 +118,10 @@
]
NOTE: If the tool shed URL specified in any dict is not present in the tool_sheds_conf.xml, the installation will fail.
'''
- return simplejson.loads( file( galaxy_repository_list, 'r' ).read() )
+ if format == 'json':
+ return simplejson.loads( file( galaxy_repository_list, 'r' ).read() )
+ else:
+ raise AssertonError( 'Unknown format %s.' % format )
def run_tests( test_config ):
loader = nose.loader.TestLoader( config=test_config )
@@ -126,7 +140,7 @@
def main():
# ---- Configuration ------------------------------------------------------
galaxy_test_host = os.environ.get( 'GALAXY_INSTALL_TEST_HOST', default_galaxy_test_host )
- galaxy_test_port = os.environ.get( 'GALAXY_INSTALL_TEST_PORT', None )
+ galaxy_test_port = os.environ.get( 'GALAXY_INSTALL_TEST_PORT', str( default_galaxy_test_port_max ) )
tool_path = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_PATH', 'tools' )
if 'HTTP_ACCEPT_LANGUAGE' not in os.environ:
@@ -134,28 +148,32 @@
galaxy_test_file_dir = os.environ.get( 'GALAXY_INSTALL_TEST_FILE_DIR', default_galaxy_test_file_dir )
if not os.path.isabs( galaxy_test_file_dir ):
galaxy_test_file_dir = os.path.abspath( galaxy_test_file_dir )
+ # Set up the tool dependency path for the Galaxy instance.
tool_dependency_dir = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR', None )
use_distributed_object_store = os.environ.get( 'GALAXY_INSTALL_TEST_USE_DISTRIBUTED_OBJECT_STORE', False )
if not os.path.isdir( galaxy_test_tmp_dir ):
os.mkdir( galaxy_test_tmp_dir )
galaxy_test_proxy_port = None
+ # Set up the configuration files for the Galaxy instance.
shed_tool_data_table_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_SHED_TOOL_DATA_TABLE_CONF', os.path.join( galaxy_test_tmp_dir, 'test_shed_tool_data_table_conf.xml' ) )
galaxy_tool_data_table_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DATA_TABLE_CONF', os.path.join( galaxy_test_tmp_dir, 'test_tool_data_table_conf.xml' ) )
galaxy_tool_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_CONF', os.path.join( galaxy_test_tmp_dir, 'test_tool_conf.xml' ) )
galaxy_shed_tool_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_SHED_TOOL_CONF', os.path.join( galaxy_test_tmp_dir, 'test_shed_tool_conf.xml' ) )
galaxy_migrated_tool_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_MIGRATED_TOOL_CONF', os.path.join( galaxy_test_tmp_dir, 'test_migrated_tool_conf.xml' ) )
galaxy_tool_sheds_conf_file = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_SHEDS_CONF', os.path.join( galaxy_test_tmp_dir, 'test_tool_sheds_conf.xml' ) )
- shed_tool_dict = os.environ.get( 'GALAXY_INSTALL_TEST_SHED_TOOL_DICT_FILE', os.path.join( galaxy_test_tmp_dir, 'shed_tool_dict' ) )
+ galaxy_shed_tools_dict = os.environ.get( 'GALAXY_INSTALL_TEST_SHED_TOOL_DICT_FILE', os.path.join( galaxy_test_tmp_dir, 'shed_tool_dict' ) )
if 'GALAXY_INSTALL_TEST_TOOL_DATA_PATH' in os.environ:
tool_data_path = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DATA_PATH' )
else:
tool_data_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
os.environ[ 'GALAXY_INSTALL_TEST_TOOL_DATA_PATH' ] = tool_data_path
+ # Configure the database connection and path.
if 'GALAXY_INSTALL_TEST_DBPATH' in os.environ:
galaxy_db_path = os.environ[ 'GALAXY_INSTALL_TEST_DBPATH' ]
else:
tempdir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
galaxy_db_path = os.path.join( tempdir, 'database' )
+ # Configure the paths Galaxy needs to install and test tools.
galaxy_file_path = os.path.join( galaxy_db_path, 'files' )
new_repos_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
galaxy_tempfiles = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
@@ -239,6 +257,7 @@
static_enabled=False,
app=app )
+ # Serve the app on a specified or random port.
if galaxy_test_port is not None:
server = httpserver.serve( webapp, host=galaxy_test_host, port=galaxy_test_port, start_loop=False )
else:
@@ -260,9 +279,10 @@
os.environ[ 'GALAXY_INSTALL_TEST_PORT' ] = galaxy_test_proxy_port
else:
os.environ[ 'GALAXY_INSTALL_TEST_PORT' ] = galaxy_test_port
+ # Start the server.
t = threading.Thread( target=server.serve_forever )
t.start()
- # Test if the server is up
+ # Test if the server is up.
for i in range( 10 ):
# Directly test the app, not the proxy.
conn = httplib.HTTPConnection( galaxy_test_host, galaxy_test_port )
@@ -273,27 +293,71 @@
else:
raise Exception( "Test HTTP server did not return '200 OK' after 10 tries" )
log.info( "Embedded galaxy web server started" )
- # ---- Load the module to generate installation methods -------------------
+ # ---- Load the modules to generate installation, testing, and uninstallation methods -------------------
import install_and_test_tool_shed_repositories.functional.test_install_repositories as test_install_repositories
+ import functional.test_toolbox as test_toolbox
if galaxy_test_proxy_port:
log.info( "Tests will be run against %s:%s" % ( galaxy_test_host, galaxy_test_proxy_port ) )
else:
log.info( "Tests will be run against %s:%s" % ( galaxy_test_host, galaxy_test_port ) )
success = False
try:
+ # Iterate through a list of repository info dicts.
for repository_dict in get_repositories_to_install():
- test_install_repositories.build_tests( repository_dict )
+ # Generate the method that will install this repository into the running Galaxy instance.
+ test_install_repositories.generate_install_method( repository_dict )
os.environ[ 'GALAXY_INSTALL_TEST_HOST' ] = galaxy_test_host
+ # Configure nose to run the install method as a test.
test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
test_config.configure( sys.argv )
- # Run the tests.
+ # Run the configured install method as a test. This method uses the Galaxy web interface to install the specified
+ # repository, with tool and repository dependencies also selected for installation.
result = run_tests( test_config )
success = result.wasSuccessful()
+ # If the installation succeeds, set up and run functional tests for this repository. This is equivalent to
+ # sh run_functional_tests.sh -installed
+ if success:
+ log.debug( 'Installation of %s succeeded, running any defined functional tests.' % repository_dict[ 'name' ] )
+ # Parse the tool panel config to get the test-data path for this repository.
+ shed_tools_dict = parse_tool_panel_config( galaxy_shed_tool_conf_file, {} )
+ # Write this to a file, so the functional test framework can find it.
+ file( galaxy_shed_tools_dict, 'w' ).write( simplejson.dumps( shed_tools_dict ) )
+ # Set up the environment so that test.functional.test_toolbox can find the Galaxy server we configured in this framework.
+ os.environ[ 'GALAXY_TOOL_SHED_TEST_FILE' ] = galaxy_shed_tools_dict
+ os.environ[ 'GALAXY_TEST_HOST' ] = galaxy_test_host
+ os.environ[ 'GALAXY_TEST_PORT' ] = galaxy_test_port
+ # Set the module-level variable 'toolbox', so that test.functional.test_toolbox will generate the appropriate test methods.
+ test_toolbox.toolbox = app.toolbox
+ # Generate the test methods for this installed repository. We need to pass in True here, or it will look
+ # in $GALAXY_HOME/test-data for test data, which may result in missing or invalid test files.
+ test_toolbox.build_tests( testing_shed_tools=True )
+ # Set up nose to run the generated functional tests.
+ test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
+ test_config.configure( sys.argv )
+ # Run the configured tests.
+ result = run_tests( test_config )
+ success = result.wasSuccessful()
+ if success:
+ log.debug( 'Repository %s installed and passed functional tests.' % repository_dict[ 'name' ] )
+ else:
+ log.debug( 'Repository %s installed, but did not pass functional tests.' % repository_dict[ 'name' ] )
+ # Generate an uninstall method for this repository, so that the next repository has a clean environment for testing.
+ test_install_repositories.generate_uninstall_method( repository_dict )
+ # Set up nose to run the generated uninstall method as a functional test.
+ test_config = nose.config.Config( env=os.environ, plugins=nose.plugins.manager.DefaultPluginManager() )
+ test_config.configure( sys.argv )
+ # Run the uninstall method. This method uses the Galaxy web interface to uninstall the previously installed
+ # repository and delete it from disk.
+ result = run_tests( test_config )
+ success = result.wasSuccessful()
+ else:
+ log.debug( 'Repository %s failed to install correctly.' % repository_dict[ 'name' ] )
except:
log.exception( "Failure running tests" )
log.info( "Shutting down" )
# ---- Tear down -----------------------------------------------------------
+ # Gracefully shut down the embedded web server and UniverseApplication.
if server:
log.info( "Shutting down embedded galaxy web server" )
server.server_close()
@@ -304,6 +368,7 @@
app.shutdown()
app = None
log.info( "Embedded galaxy application stopped" )
+ # Clean up test files unless otherwise specified.
if 'GALAXY_INSTALL_TEST_NO_CLEANUP' not in os.environ:
try:
for dir in [ galaxy_test_tmp_dir ]:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Move grid element initialization to main body to prevent it from happening too early. Pack scripts.
by Bitbucket 20 Feb '13
by Bitbucket 20 Feb '13
20 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7c3df0bcbc22/
changeset: 7c3df0bcbc22
branch: stable
user: jgoecks
date: 2013-02-17 20:59:02
summary: Move grid element initialization to main body to prevent it from happening too early. Pack scripts.
affected #: 4 files
diff -r 5ac8d92a066edefa4ab63936372ec9bcc689cafc -r 7c3df0bcbc222f478b1e21886fbb384d3dc96f31 static/scripts/galaxy.grids.js
--- a/static/scripts/galaxy.grids.js
+++ b/static/scripts/galaxy.grids.js
@@ -4,18 +4,6 @@
// not appended to the identifier of a nested array.
jQuery.ajaxSettings.traditional = true;
-// Initialize grid objects on load.
-$(document).ready(function() {
- init_grid_elements();
- init_grid_controls();
-
- // Initialize text filters to select text on click and use normal font when user is typing.
- $('input[type=text]').each(function() {
- $(this).click(function() { $(this).select(); } )
- .keyup(function () { $(this).css("font-style", "normal"); });
- });
-});
-
/**
* A Galaxy grid.
*/
diff -r 5ac8d92a066edefa4ab63936372ec9bcc689cafc -r 7c3df0bcbc222f478b1e21886fbb384d3dc96f31 static/scripts/packed/galaxy.grids.js
--- a/static/scripts/packed/galaxy.grids.js
+++ b/static/scripts/packed/galaxy.grids.js
@@ -1,1 +1,1 @@
-jQuery.ajaxSettings.traditional=true;$(document).ready(function(){init_grid_elements();init_grid_controls();$("input[type=text]").each(function(){$(this).click(function(){$(this).select()}).keyup(function(){$(this).css("font-style","normal")})})});var Grid=Backbone.Model.extend({defaults:{url_base:"",async:false,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:false,cur_page:1,num_pages:1,operation:undefined,item_ids:undefined},can_async_op:function(a){return _.indexOf(this.attributes.async_ops,a)!==-1},add_filter:function(e,f,b){if(b){var c=this.attributes.key,a;if(c===null||c===undefined){a=f}else{if(typeof(c)=="string"){if(c=="All"){a=f}else{var d=[];d[0]=c;d[1]=f;a=d}}else{a=c;a.push(f)}}this.attributes.filters[e]=a}else{this.attributes.filters[e]=f}},remove_filter:function(b,e){var a=this.attributes.filters[b];if(a===null||a===undefined){return false}var d=true;if(typeof(a)==="string"){if(a=="All"){d=false}else{delete this.attributes.filters[b]}}else{var c=_.indexOf(a,e);if(c!==-1){a.splice(c,1)}else{d=false}}return d},get_url_data:function(){var a={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes};if(this.attributes.operation){a.operation=this.attributes.operation}if(this.attributes.item_ids){a.id=this.attributes.item_ids}var b=this;_.each(_.keys(b.attributes.filters),function(c){a["f-"+c]=b.attributes.filters[c]});return a}});function init_operation_buttons(){$("input[name=operation]:submit").each(function(){$(this).click(function(){var b=$(this).val();var a=[];$("input[name=id]:checked").each(function(){a.push($(this).val())});do_operation(b,a)})})}function init_grid_controls(){init_operation_buttons();$(".submit-image").each(function(){$(this).mousedown(function(){$(this).addClass("gray-background")});$(this).mouseup(function(){$(this).removeClass("gray-background")})});$(".sort-link").each(function(){$(this).click(function(){set_sort_condition($(this).attr("sort_key"));return false})});$(".page-link > a").each(function(){$(this).click(function(){set_page($(this).attr("page_num"));return false})});$(".categorical-filter > a").each(function(){$(this).click(function(){set_categorical_filter($(this).attr("filter_key"),$(this).attr("filter_val"));return false})});$(".text-filter-form").each(function(){$(this).submit(function(){var d=$(this).attr("column_key");var c=$("#input-"+d+"-filter");var e=c.val();c.val("");add_filter_condition(d,e,true);return false})});var a=$("#input-tags-filter");if(a.length){a.autocomplete(history_tag_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}var b=$("#input-name-filter");if(b.length){b.autocomplete(history_name_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}$(".advanced-search-toggle").each(function(){$(this).click(function(){$("#standard-search").slideToggle("fast");$("#advanced-search").slideToggle("fast");return false})})}function init_grid_elements(){$(".grid").each(function(){var b=$(this).find("input.grid-row-select-checkbox");var a=$(this).find("span.grid-selected-count");var c=function(){a.text($(b).filter(":checked").length)};$(b).each(function(){$(this).change(c)});c()});$(".label").each(function(){var a=$(this).attr("href");if(a!==undefined&&a.indexOf("operation=")!=-1){$(this).click(function(){do_operation_from_href($(this).attr("href"));return false})}});$(".community_rating_star").rating({});make_popup_menus()}function go_page_one(){var a=grid.get("cur_page");if(a!==null&&a!==undefined&&a!=="all"){grid.set("cur_page",1)}}function add_filter_condition(c,e,a){if(e===""){return false}grid.add_filter(c,e,a);var d=$("<span>"+e+"<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");d.addClass("text-filter-val");d.click(function(){grid.remove_filter(c,e);$(this).remove();go_page_one();update_grid()});var b=$("#"+c+"-filtering-criteria");b.append(d);go_page_one();update_grid()}function add_tag_to_grid_filter(c,b){var a=c+(b!==undefined&&b!==""?":"+b:"");$("#advanced-search").show("fast");add_filter_condition("tags",a,true)}function set_sort_condition(f){var e=grid.get("sort_key");var d=f;if(e.indexOf(f)!==-1){if(e.substring(0,1)!=="-"){d="-"+f}else{}}$(".sort-arrow").remove();var c=(d.substring(0,1)=="-")?"↑":"↓";var a=$("<span>"+c+"</span>").addClass("sort-arrow");var b=$("#"+f+"-header");b.append(a);grid.set("sort_key",d);go_page_one();update_grid()}function set_categorical_filter(b,d){var a=grid.get("categorical_filters")[b],c=grid.get("filters")[b];$("."+b+"-filter").each(function(){var h=$.trim($(this).text());var f=a[h];var g=f[b];if(g==d){$(this).empty();$(this).addClass("current-filter");$(this).append(h)}else{if(g==c){$(this).empty();var e=$("<a href='#'>"+h+"</a>");e.click(function(){set_categorical_filter(b,g)});$(this).removeClass("current-filter");$(this).append(e)}}});grid.add_filter(b,d);go_page_one();update_grid()}function set_page(a){$(".page-link").each(function(){var g=$(this).attr("id"),e=parseInt(g.split("-")[2],10),c=grid.get("cur_page"),f;if(e===a){f=$(this).children().text();$(this).empty();$(this).addClass("inactive-link");$(this).text(f)}else{if(e===c){f=$(this).text();$(this).empty();$(this).removeClass("inactive-link");var d=$("<a href='#'>"+f+"</a>");d.click(function(){set_page(e)});$(this).append(d)}}});var b=true;if(a==="all"){grid.set("cur_page",a);b=false}else{grid.set("cur_page",parseInt(a,10))}update_grid(b)}function do_operation(b,a){b=b.toLowerCase();grid.set({operation:b,item_ids:a});if(grid.can_async_op(b)){update_grid(true)}else{go_to_URL()}}function do_operation_from_href(c){var f=c.split("?");if(f.length>1){var a=f[1];var e=a.split("&");var b=null;var g=-1;for(var d=0;d<e.length;d++){if(e[d].indexOf("operation")!=-1){b=e[d].split("=")[1]}else{if(e[d].indexOf("id")!=-1){g=e[d].split("=")[1]}}}do_operation(b,g);return false}}function go_to_URL(){grid.set("async",false);window.location=grid.get("url_base")+"?"+$.param(grid.get_url_data())}function update_grid(a){if(!grid.get("async")){go_to_URL();return}var b=(grid.get("operation")?"POST":"GET");$(".loading-elt-overlay").show();$.ajax({type:b,url:grid.get("url_base"),data:grid.get_url_data(),error:function(){alert("Grid refresh failed")},success:function(d){var c=d.split("*****");$("#grid-table-body").html(c[0]);$("#grid-table-footer").html(c[1]);$("#grid-table-body").trigger("update");init_grid_elements();init_operation_buttons();make_popup_menus();$(".loading-elt-overlay").hide();var e=$.trim(c[2]);if(e!==""){$("#grid-message").html(e).show();setTimeout(function(){$("#grid-message").hide()},5000)}},complete:function(){grid.set({operation:undefined,item_ids:undefined})}})}function check_all_items(){var a=document.getElementById("check_all"),b=document.getElementsByTagName("input"),d=0,c;if(a.checked===true){for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=true;d++}}}else{for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=false}}}init_grid_elements()};
\ No newline at end of file
+jQuery.ajaxSettings.traditional=true;var Grid=Backbone.Model.extend({defaults:{url_base:"",async:false,async_ops:[],categorical_filters:[],filters:{},sort_key:null,show_item_checkboxes:false,cur_page:1,num_pages:1,operation:undefined,item_ids:undefined},can_async_op:function(a){return _.indexOf(this.attributes.async_ops,a)!==-1},add_filter:function(e,f,b){if(b){var c=this.attributes.key,a;if(c===null||c===undefined){a=f}else{if(typeof(c)=="string"){if(c=="All"){a=f}else{var d=[];d[0]=c;d[1]=f;a=d}}else{a=c;a.push(f)}}this.attributes.filters[e]=a}else{this.attributes.filters[e]=f}},remove_filter:function(b,e){var a=this.attributes.filters[b];if(a===null||a===undefined){return false}var d=true;if(typeof(a)==="string"){if(a=="All"){d=false}else{delete this.attributes.filters[b]}}else{var c=_.indexOf(a,e);if(c!==-1){a.splice(c,1)}else{d=false}}return d},get_url_data:function(){var a={async:this.attributes.async,sort:this.attributes.sort_key,page:this.attributes.cur_page,show_item_checkboxes:this.attributes.show_item_checkboxes};if(this.attributes.operation){a.operation=this.attributes.operation}if(this.attributes.item_ids){a.id=this.attributes.item_ids}var b=this;_.each(_.keys(b.attributes.filters),function(c){a["f-"+c]=b.attributes.filters[c]});return a}});function init_operation_buttons(){$("input[name=operation]:submit").each(function(){$(this).click(function(){var b=$(this).val();var a=[];$("input[name=id]:checked").each(function(){a.push($(this).val())});do_operation(b,a)})})}function init_grid_controls(){init_operation_buttons();$(".submit-image").each(function(){$(this).mousedown(function(){$(this).addClass("gray-background")});$(this).mouseup(function(){$(this).removeClass("gray-background")})});$(".sort-link").each(function(){$(this).click(function(){set_sort_condition($(this).attr("sort_key"));return false})});$(".page-link > a").each(function(){$(this).click(function(){set_page($(this).attr("page_num"));return false})});$(".categorical-filter > a").each(function(){$(this).click(function(){set_categorical_filter($(this).attr("filter_key"),$(this).attr("filter_val"));return false})});$(".text-filter-form").each(function(){$(this).submit(function(){var d=$(this).attr("column_key");var c=$("#input-"+d+"-filter");var e=c.val();c.val("");add_filter_condition(d,e,true);return false})});var a=$("#input-tags-filter");if(a.length){a.autocomplete(history_tag_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}var b=$("#input-name-filter");if(b.length){b.autocomplete(history_name_autocomplete_url,{selectFirst:false,autoFill:false,highlight:false,mustMatch:false})}$(".advanced-search-toggle").each(function(){$(this).click(function(){$("#standard-search").slideToggle("fast");$("#advanced-search").slideToggle("fast");return false})})}function init_grid_elements(){$(".grid").each(function(){var b=$(this).find("input.grid-row-select-checkbox");var a=$(this).find("span.grid-selected-count");var c=function(){a.text($(b).filter(":checked").length)};$(b).each(function(){$(this).change(c)});c()});$(".label").each(function(){var a=$(this).attr("href");if(a!==undefined&&a.indexOf("operation=")!=-1){$(this).click(function(){do_operation_from_href($(this).attr("href"));return false})}});$(".community_rating_star").rating({});make_popup_menus()}function go_page_one(){var a=grid.get("cur_page");if(a!==null&&a!==undefined&&a!=="all"){grid.set("cur_page",1)}}function add_filter_condition(c,e,a){if(e===""){return false}grid.add_filter(c,e,a);var d=$("<span>"+e+"<a href='javascript:void(0);'><span class='delete-search-icon' /></a></span>");d.addClass("text-filter-val");d.click(function(){grid.remove_filter(c,e);$(this).remove();go_page_one();update_grid()});var b=$("#"+c+"-filtering-criteria");b.append(d);go_page_one();update_grid()}function add_tag_to_grid_filter(c,b){var a=c+(b!==undefined&&b!==""?":"+b:"");$("#advanced-search").show("fast");add_filter_condition("tags",a,true)}function set_sort_condition(f){var e=grid.get("sort_key");var d=f;if(e.indexOf(f)!==-1){if(e.substring(0,1)!=="-"){d="-"+f}else{}}$(".sort-arrow").remove();var c=(d.substring(0,1)=="-")?"↑":"↓";var a=$("<span>"+c+"</span>").addClass("sort-arrow");var b=$("#"+f+"-header");b.append(a);grid.set("sort_key",d);go_page_one();update_grid()}function set_categorical_filter(b,d){var a=grid.get("categorical_filters")[b],c=grid.get("filters")[b];$("."+b+"-filter").each(function(){var h=$.trim($(this).text());var f=a[h];var g=f[b];if(g==d){$(this).empty();$(this).addClass("current-filter");$(this).append(h)}else{if(g==c){$(this).empty();var e=$("<a href='#'>"+h+"</a>");e.click(function(){set_categorical_filter(b,g)});$(this).removeClass("current-filter");$(this).append(e)}}});grid.add_filter(b,d);go_page_one();update_grid()}function set_page(a){$(".page-link").each(function(){var g=$(this).attr("id"),e=parseInt(g.split("-")[2],10),c=grid.get("cur_page"),f;if(e===a){f=$(this).children().text();$(this).empty();$(this).addClass("inactive-link");$(this).text(f)}else{if(e===c){f=$(this).text();$(this).empty();$(this).removeClass("inactive-link");var d=$("<a href='#'>"+f+"</a>");d.click(function(){set_page(e)});$(this).append(d)}}});var b=true;if(a==="all"){grid.set("cur_page",a);b=false}else{grid.set("cur_page",parseInt(a,10))}update_grid(b)}function do_operation(b,a){b=b.toLowerCase();grid.set({operation:b,item_ids:a});if(grid.can_async_op(b)){update_grid(true)}else{go_to_URL()}}function do_operation_from_href(c){var f=c.split("?");if(f.length>1){var a=f[1];var e=a.split("&");var b=null;var g=-1;for(var d=0;d<e.length;d++){if(e[d].indexOf("operation")!=-1){b=e[d].split("=")[1]}else{if(e[d].indexOf("id")!=-1){g=e[d].split("=")[1]}}}do_operation(b,g);return false}}function go_to_URL(){grid.set("async",false);window.location=grid.get("url_base")+"?"+$.param(grid.get_url_data())}function update_grid(a){if(!grid.get("async")){go_to_URL();return}var b=(grid.get("operation")?"POST":"GET");$(".loading-elt-overlay").show();$.ajax({type:b,url:grid.get("url_base"),data:grid.get_url_data(),error:function(){alert("Grid refresh failed")},success:function(d){var c=d.split("*****");$("#grid-table-body").html(c[0]);$("#grid-table-footer").html(c[1]);$("#grid-table-body").trigger("update");init_grid_elements();init_operation_buttons();make_popup_menus();$(".loading-elt-overlay").hide();var e=$.trim(c[2]);if(e!==""){$("#grid-message").html(e).show();setTimeout(function(){$("#grid-message").hide()},5000)}},complete:function(){grid.set({operation:undefined,item_ids:undefined})}})}function check_all_items(){var a=document.getElementById("check_all"),b=document.getElementsByTagName("input"),d=0,c;if(a.checked===true){for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=true;d++}}}else{for(c=0;c<b.length;c++){if(b[c].name.indexOf("id")!==-1){b[c].checked=false}}}init_grid_elements()};
\ No newline at end of file
diff -r 5ac8d92a066edefa4ab63936372ec9bcc689cafc -r 7c3df0bcbc222f478b1e21886fbb384d3dc96f31 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,init_data:null,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")=="raw_data"?"state":this.get("data_type")=="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom==u});return new g({chrom:v.chrom,end:v.len})}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<=w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}return u},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",p.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,init_data:null,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<=w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}return u},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",p.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
diff -r 5ac8d92a066edefa4ab63936372ec9bcc689cafc -r 7c3df0bcbc222f478b1e21886fbb384d3dc96f31 templates/grid_base.mako
--- a/templates/grid_base.mako
+++ b/templates/grid_base.mako
@@ -129,6 +129,19 @@
cur_page: ${cur_page_num},
num_pages: ${num_pages}
});
+
+ // Initialize grid objects on load.
+ // FIXME: use a grid view object eventually.
+ $(document).ready(function() {
+ init_grid_elements();
+ init_grid_controls();
+
+ // Initialize text filters to select text on click and use normal font when user is typing.
+ $('input[type=text]').each(function() {
+ $(this).click(function() { $(this).select(); } )
+ .keyup(function () { $(this).css("font-style", "normal"); });
+ });
+ });
</script></%def>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/5ac8d92a066e/
changeset: 5ac8d92a066e
branch: stable
user: inithello
date: 2013-02-20 14:56:36
summary: Fix missing import in repository controller.
affected #: 1 file
diff -r d5896e8a60fa948f1713d4b5e30126a12a958679 -r 5ac8d92a066edefa4ab63936372ec9bcc689cafc lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1,4 +1,4 @@
-import os, logging, re, tempfile, shutil, ConfigParser
+import os, logging, re, tempfile, shutil, ConfigParser, string
from time import gmtime, strftime
from datetime import date, datetime
from galaxy import util, web
https://bitbucket.org/galaxy/galaxy-central/commits/efebd50fd708/
changeset: efebd50fd708
user: inithello
date: 2013-02-20 14:56:36
summary: Fix missing import in repository controller.
affected #: 1 file
diff -r 1895646e8ce0ed905f7fef8a8fc184ae1606a006 -r efebd50fd708aa3af73f954e4da68e88f2bced9a lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1,4 +1,4 @@
-import os, logging, re, tempfile, shutil, ConfigParser
+import os, logging, re, tempfile, shutil, ConfigParser, string
from time import gmtime, strftime
from datetime import date, datetime
from galaxy import util, web
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: More reporting for buildbot corrections
by Bitbucket 20 Feb '13
by Bitbucket 20 Feb '13
20 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1895646e8ce0/
changeset: 1895646e8ce0
user: carlfeberhard
date: 2013-02-20 02:00:27
summary: More reporting for buildbot corrections
affected #: 2 files
diff -r bff6388644ba9b2b5ccb102ce01380778fdefdfe -r 1895646e8ce0ed905f7fef8a8fc184ae1606a006 lib/galaxy/app.py
--- a/lib/galaxy/app.py
+++ b/lib/galaxy/app.py
@@ -20,6 +20,9 @@
from galaxy.openid.providers import OpenIDProviders
from galaxy.tools.data_manager.manager import DataManagers
+import logging
+log = logging.getLogger( __name__ )
+
class UniverseApplication( object ):
"""Encapsulates the state of a Universe application"""
def __init__( self, **kwargs ):
@@ -41,6 +44,8 @@
self.tool_shed_registry = galaxy.tool_shed.tool_shed_registry.Registry( self.config.root, self.config.tool_sheds_config )
else:
self.tool_shed_registry = None
+ log.debug( 'self.config.tool_sheds_config: %s, self.tool_shed_registry: %s',
+ self.config.tool_sheds_config, self.tool_shed_registry )
# Initialize database / check for appropriate schema version. # If this
# is a new installation, we'll restrict the tool migration messaging.
from galaxy.model.migrate.check import create_or_verify_database
diff -r bff6388644ba9b2b5ccb102ce01380778fdefdfe -r 1895646e8ce0ed905f7fef8a8fc184ae1606a006 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -277,7 +277,6 @@
os.makedirs( dir )
except OSError:
pass
- log.info( "Database connection:", database_connection )
# ---- Build Application --------------------------------------------------
app = None
@@ -293,7 +292,7 @@
kwargs[ 'object_store' ] = 'distributed'
kwargs[ 'distributed_object_store_config_file' ] = 'distributed_object_store_conf.xml.sample'
# Build the Universe Application
- log.debug( 'app.kwargs:\n%s', pprint.pformat( kwargs ) )
+ print 'app.kwargs:\n%s' %( pprint.pformat( kwargs ) )
app = UniverseApplication( job_queue_workers = 5,
id_secret = 'changethisinproductiontoo',
template_path = "templates",
@@ -321,6 +320,7 @@
running_functional_tests=True,
**kwargs )
log.info( "Embedded Universe application started" )
+
# ---- Run webserver ------------------------------------------------------
server = None
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: Fix for tool shed functional test 1060 failing when all tests are run.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bff6388644ba/
changeset: bff6388644ba
user: inithello
date: 2013-02-19 23:04:04
summary: Fix for tool shed functional test 1060 failing when all tests are run.
affected #: 1 file
diff -r bc0114ce0f7b5224cd4ef58d1dd2ef8b30c77a69 -r bff6388644ba9b2b5ccb102ce01380778fdefdfe test/tool_shed/functional/test_0060_workflows.py
--- a/test/tool_shed/functional/test_0060_workflows.py
+++ b/test/tool_shed/functional/test_0060_workflows.py
@@ -88,6 +88,8 @@
strings_displayed=[] )
workflow = file( self.get_filename( 'filtering_workflow/Workflow_for_0060_filter_workflow_repository.ga' ), 'r' ).read()
workflow = workflow.replace( '__TEST_TOOL_SHED_URL__', self.url.replace( 'http://', '' ) )
+ workflow = workflow.replace( 'Workflow for 0060_filter_workflow_repository',
+ 'New workflow for 0060_filter_workflow_repository' )
workflow_filepath = self.generate_temp_path( 'test_0060', additional_paths=[ 'filtering_workflow_2' ] )
if not os.path.exists( workflow_filepath ):
os.makedirs( workflow_filepath )
@@ -106,7 +108,7 @@
def test_0030_check_workflow_repository( self ):
"""Check for strings on the manage page for the filtering_workflow_0060 repository."""
repository = test_db_util.get_repository_by_name_and_owner( workflow_repository_name, common.test_user_1_name )
- strings_displayed = [ 'Workflows', 'Workflow for 0060_filter', '0.1' ]
+ strings_displayed = [ 'Workflows', 'New workflow for 0060_filter', '0.1' ]
strings_not_displayed = [ 'Valid tools', 'Invalid tools' ]
self.display_manage_repository_page( repository, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed )
def test_0035_verify_repository_metadata( self ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/bc0114ce0f7b/
changeset: bc0114ce0f7b
user: carlfeberhard
date: 2013-02-19 22:21:16
summary: functional_tests: fix import
affected #: 1 file
diff -r 7bf93ff108fe4a62ee3084d84a77fa9b71c8b1f7 -r bc0114ce0f7b5224cd4ef58d1dd2ef8b30c77a69 scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -40,6 +40,7 @@
import nose.loader
import nose.plugins.manager
+import pprint
log = logging.getLogger( "functional_tests.py" )
default_galaxy_test_host = "localhost"
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: Enhancement to tool shed functional tests for repositories that only contain a workflow.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7bf93ff108fe/
changeset: 7bf93ff108fe
user: inithello
date: 2013-02-19 22:01:18
summary: Enhancement to tool shed functional tests for repositories that only contain a workflow.
affected #: 2 files
diff -r 305680a482c3096b082daffa5ff665f5f60d1528 -r 7bf93ff108fe4a62ee3084d84a77fa9b71c8b1f7 test/tool_shed/functional/test_0060_workflows.py
--- a/test/tool_shed/functional/test_0060_workflows.py
+++ b/test/tool_shed/functional/test_0060_workflows.py
@@ -4,11 +4,17 @@
repository_name = 'filtering_0060'
repository_description="Galaxy's filtering tool for test 0060"
repository_long_description="Long description of Galaxy's filtering tool for test 0060"
+
workflow_filename = 'Workflow_for_0060_filter_workflow_repository.ga'
workflow_name = 'Workflow for 0060_filter_workflow_repository'
+
category_name = 'Test 0060 Workflow Features'
category_description = 'Test 0060 for workflow features'
+workflow_repository_name = 'filtering_workflow_0060'
+workflow_repository_description="Workflow referencing the filtering tool for test 0060"
+workflow_repository_long_description="Long description of the workflow for test 0060"
+
class TestToolShedWorkflowFeatures( ShedTwillTestCase ):
'''Test valid and invalid workflows.'''
def test_0000_initiate_users( self ):
@@ -69,7 +75,41 @@
strings_displayed=[],
strings_not_displayed=[] )
self.load_workflow_image_in_tool_shed( repository, workflow_name, strings_not_displayed=[ '#EBBCB2' ] )
- def test_0025_verify_repository_metadata( self ):
+ def test_0025_create_repository_with_only_workflow( self ):
+ """Create and populate the filtering_workflow_0060 repository"""
+ category = self.create_category( name=category_name, description=category_description )
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ self.get_or_create_repository( name=workflow_repository_name,
+ description=workflow_repository_description,
+ long_description=workflow_repository_long_description,
+ owner=common.test_user_1_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=[] )
+ workflow = file( self.get_filename( 'filtering_workflow/Workflow_for_0060_filter_workflow_repository.ga' ), 'r' ).read()
+ workflow = workflow.replace( '__TEST_TOOL_SHED_URL__', self.url.replace( 'http://', '' ) )
+ workflow_filepath = self.generate_temp_path( 'test_0060', additional_paths=[ 'filtering_workflow_2' ] )
+ if not os.path.exists( workflow_filepath ):
+ os.makedirs( workflow_filepath )
+ file( os.path.join( workflow_filepath, workflow_filename ), 'w+' ).write( workflow )
+ repository = test_db_util.get_repository_by_name_and_owner( workflow_repository_name, common.test_user_1_name )
+ self.upload_file( repository,
+ filename=workflow_filename,
+ filepath=workflow_filepath,
+ valid_tools_only=True,
+ uncompress_file=False,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded filtering workflow.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ self.load_workflow_image_in_tool_shed( repository, workflow_name, strings_displayed=[ '#EBBCB2' ] )
+ def test_0030_check_workflow_repository( self ):
+ """Check for strings on the manage page for the filtering_workflow_0060 repository."""
+ repository = test_db_util.get_repository_by_name_and_owner( workflow_repository_name, common.test_user_1_name )
+ strings_displayed = [ 'Workflows', 'Workflow for 0060_filter', '0.1' ]
+ strings_not_displayed = [ 'Valid tools', 'Invalid tools' ]
+ self.display_manage_repository_page( repository, strings_displayed=strings_displayed, strings_not_displayed=strings_not_displayed )
+ def test_0035_verify_repository_metadata( self ):
'''Verify that resetting the metadata does not change it.'''
repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.verify_unchanged_repository_metadata( repository )
diff -r 305680a482c3096b082daffa5ff665f5f60d1528 -r 7bf93ff108fe4a62ee3084d84a77fa9b71c8b1f7 test/tool_shed/functional/test_1060_install_repository_with_workflow.py
--- a/test/tool_shed/functional/test_1060_install_repository_with_workflow.py
+++ b/test/tool_shed/functional/test_1060_install_repository_with_workflow.py
@@ -1,15 +1,21 @@
from tool_shed.base.twilltestcase import ShedTwillTestCase, common, os
import tool_shed.base.test_db_util as test_db_util
-import logging
-log = logging.getLogger(__name__)
+
repository_name = 'filtering_0060'
repository_description="Galaxy's filtering tool for test 0060"
repository_long_description="Long description of Galaxy's filtering tool for test 0060"
+
workflow_filename = 'Workflow_for_0060_filter_workflow_repository.ga'
workflow_name = 'Workflow for 0060_filter_workflow_repository'
+second_workflow_name = 'New workflow for 0060_filter_workflow_repository'
+
category_name = 'Test 0060 Workflow Features'
category_description = 'Test 0060 for workflow features'
+workflow_repository_name = 'filtering_workflow_0060'
+workflow_repository_description="Workflow referencing the filtering tool for test 0060"
+workflow_repository_long_description="Long description of the workflow for test 0060"
+
class ToolWithRepositoryDependencies( ShedTwillTestCase ):
'''Test installing a repository with repository dependencies.'''
def test_0000_initiate_users( self ):
@@ -87,3 +93,61 @@
self.display_all_workflows( strings_not_displayed=[ 'Workflow for 0060_filter_workflow_repository' ] )
self.import_workflow( installed_repository, workflow_name )
self.display_all_workflows( strings_displayed=[ 'Workflow for 0060_filter_workflow_repository' ] )
+ def test_0020_create_filter_workflow_repository( self ):
+ '''Create, if necessary, a filtering repository with only a workflow.'''
+ category = self.create_category( name=category_name, description=category_description )
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ repository = self.get_or_create_repository( name=workflow_repository_name,
+ description=workflow_repository_description,
+ long_description=workflow_repository_long_description,
+ owner=common.test_user_1_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=[] )
+ if self.repository_is_new( repository ):
+ workflow = file( self.get_filename( 'filtering_workflow/Workflow_for_0060_filter_workflow_repository.ga' ), 'r' ).read()
+ workflow = workflow.replace( '__TEST_TOOL_SHED_URL__', self.url.replace( 'http://', '' ) )
+ workflow = workflow.replace( 'Workflow for 0060_filter_workflow_repository',
+ 'New workflow for 0060_filter_workflow_repository' )
+ workflow_filepath = self.generate_temp_path( 'test_0060', additional_paths=[ 'filtering_workflow_2' ] )
+ if not os.path.exists( workflow_filepath ):
+ os.makedirs( workflow_filepath )
+ file( os.path.join( workflow_filepath, workflow_filename ), 'w+' ).write( workflow )
+ self.upload_file( repository,
+ filename=workflow_filename,
+ filepath=workflow_filepath,
+ valid_tools_only=True,
+ uncompress_file=False,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded filtering workflow.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ self.load_workflow_image_in_tool_shed( repository,
+ 'New workflow for 0060_filter_workflow_repository',
+ strings_displayed=[ '#EBBCB2' ] )
+ def test_0025_install_repository_with_workflow( self ):
+ """Browse the available tool sheds in this Galaxy instance and preview the filtering workflow repository."""
+ self.preview_repository_in_tool_shed( workflow_repository_name,
+ common.test_user_1_name,
+ strings_displayed=[ 'filtering_workflow_0060', 'Workflows' ],
+ strings_not_displayed=[ 'Valid tools', 'Invalid tools' ] )
+ self.galaxy_logout()
+ self.galaxy_login( email=common.admin_email, username=common.admin_username )
+ self.install_repository( workflow_repository_name,
+ common.test_user_1_name,
+ 'Test 0060 Workflow Features',
+ install_tool_dependencies=False,
+ includes_tools=False )
+ def test_0030_import_workflow_from_installed_repository( self ):
+ '''Import the workflow from the installed repository and verify that it appears in the list of all workflows.'''
+ installed_repository = test_db_util.get_installed_repository_by_name_owner( workflow_repository_name, common.test_user_1_name )
+ self.display_installed_workflow_image( installed_repository,
+ 'New workflow for 0060_filter_workflow_repository',
+ strings_displayed=[ '#EBD9B2' ],
+ strings_not_displayed=[ '#EBBCB2' ] )
+ self.display_all_workflows( strings_not_displayed=[ 'New workflow for 0060_filter_workflow_repository' ] )
+ self.import_workflow( installed_repository,
+ 'New workflow for 0060_filter_workflow_repository',
+ strings_displayed=[ 'New workflow for 0060_filter_workflow_repository' ] )
+ self.display_all_workflows( strings_displayed=[ 'New workflow for 0060_filter_workflow_repository' ] )
+
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/305680a482c3/
changeset: 305680a482c3
user: greg
date: 2013-02-19 21:01:09
summary: Handle all Galaxy utilitiy types when reinstalling an uninstalled tool shed repository. The shed-related config file can now be selected when reinstalling repositories with any contents so that a differnt "tool_path" location can be selected for the location of the reinstalled repository.
affected #: 5 files
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -951,6 +951,7 @@
.first()
def get_update_to_changeset_revision_and_ctx_rev( trans, repository ):
"""Return the changeset revision hash to which the repository can be updated."""
+ changeset_revision_dict = {}
tool_shed_url = suc.get_url_from_repository_tool_shed( trans.app, repository )
url = suc.url_join( tool_shed_url, 'repository/get_changeset_revision_and_ctx_rev?name=%s&owner=%s&changeset_revision=%s' % \
( repository.name, repository.owner, repository.installed_changeset_revision ) )
@@ -959,18 +960,34 @@
encoded_update_dict = response.read()
if encoded_update_dict:
update_dict = encoding_util.tool_shed_decode( encoded_update_dict )
- changeset_revision = update_dict[ 'changeset_revision' ]
- ctx_rev = update_dict[ 'ctx_rev' ]
+ includes_data_managers = update_dict.get( 'includes_data_managers', False )
+ includes_datatypes = update_dict.get( 'includes_datatypes', False )
includes_tools = update_dict.get( 'includes_tools', False )
+ includes_tool_dependencies = update_dict.get( 'includes_tool_dependencies', False )
+ includes_workflows = update_dict.get( 'includes_workflows', False )
has_repository_dependencies = update_dict.get( 'has_repository_dependencies', False )
+ changeset_revision = update_dict.get( 'changeset_revision', None )
+ ctx_rev = update_dict.get( 'ctx_rev', None )
response.close()
+ changeset_revision_dict[ 'includes_data_managers' ] = includes_data_managers
+ changeset_revision_dict[ 'includes_datatypes' ] = includes_datatypes
+ changeset_revision_dict[ 'includes_tools' ] = includes_tools
+ changeset_revision_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
+ changeset_revision_dict[ 'includes_workflows' ] = includes_workflows
+ changeset_revision_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
+ changeset_revision_dict[ 'changeset_revision' ] = changeset_revision
+ changeset_revision_dict[ 'ctx_rev' ] = ctx_rev
except Exception, e:
log.debug( "Error getting change set revision for update from the tool shed for repository '%s': %s" % ( repository.name, str( e ) ) )
- includes_tools = False
- has_repository_dependencies = False
- changeset_revision = None
- ctx_rev = None
- return changeset_revision, ctx_rev, includes_tools, has_repository_dependencies
+ changeset_revision_dict[ 'includes_data_managers' ] = False
+ changeset_revision_dict[ 'includes_datatypes' ] = False
+ changeset_revision_dict[ 'includes_tools' ] = False
+ changeset_revision_dict[ 'includes_tool_dependencies' ] = False
+ changeset_revision_dict[ 'includes_workflows' ] = False
+ changeset_revision_dict[ 'has_repository_dependencies' ] = False
+ changeset_revision_dict[ 'changeset_revision' ] = None
+ changeset_revision_dict[ 'ctx_rev' ] = None
+ return changeset_revision_dict
def handle_missing_data_table_entry( app, relative_install_dir, tool_path, repository_tools_tups ):
"""
Inspect each tool to see if any have input parameters that are dynamically generated select lists that require entries in the
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1298,21 +1298,29 @@
@web.expose
def get_changeset_revision_and_ctx_rev( self, trans, **kwd ):
"""Handle a request from a local Galaxy instance to retrieve the changeset revision hash to which an installed repository can be updated."""
- def has_tools_and_repository_dependencies( repository_metadata ):
+ def has_galaxy_utilities( repository_metadata ):
+ includes_data_managers = False
+ includes_datatypes = False
includes_tools = False
has_repository_dependencies = False
+ includes_tool_dependencies = False
+ includes_workflows = False
if repository_metadata:
metadata = repository_metadata.metadata
if metadata:
+ if 'data_manager' in metadata:
+ includes_data_managers = True
+ if 'datatypes' in metadata:
+ includes_datatypes = True
if 'tools' in metadata:
includes_tools = True
- else:
- includes_tools = False
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
if 'repository_dependencies' in metadata:
has_repository_dependencies = True
- else:
- has_repository_dependencies = False
- return includes_tools, has_repository_dependencies
+ if 'workflows' in metadata:
+ includes_workflows = True
+ return includes_data_managers, includes_datatypes, includes_tools, includes_tool_dependencies, has_repository_dependencies, includes_workflows
params = util.Params( kwd )
message = util.restore_text( params.get( 'message', '' ) )
status = params.get( 'status', 'done' )
@@ -1324,7 +1332,8 @@
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
trans.security.encode_id( repository.id ),
changeset_revision )
- includes_tools, has_repository_dependencies = has_tools_and_repository_dependencies( repository_metadata )
+ includes_data_managers, includes_datatypes, includes_tools, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
+ has_galaxy_utilities( repository_metadata )
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
# Default to the received changeset revision and ctx_rev.
@@ -1333,8 +1342,12 @@
latest_changeset_revision = changeset_revision
update_dict = dict( changeset_revision=changeset_revision,
ctx_rev=ctx_rev,
+ includes_data_managers=includes_data_managers,
+ includes_datatypes=includes_datatypes,
includes_tools=includes_tools,
- has_repository_dependencies=has_repository_dependencies )
+ includes_tool_dependencies=includes_tool_dependencies,
+ has_repository_dependencies=has_repository_dependencies,
+ includes_workflows=includes_workflows )
if changeset_revision == repository.tip( trans.app ):
# If changeset_revision is the repository tip, there are no additional updates.
return encoding_util.tool_shed_encode( update_dict )
@@ -1356,7 +1369,8 @@
trans.security.encode_id( repository.id ),
changeset_hash )
if update_to_repository_metadata:
- includes_tools, has_repository_dependencies = has_tools_and_repository_dependencies( update_to_repository_metadata )
+ includes_data_managers, includes_datatypes, includes_tools, includes_tool_dependencies, has_repository_dependencies, includes_workflows = \
+ has_galaxy_utilities( update_to_repository_metadata )
# We found a RepositoryMetadata record.
if changeset_hash == repository.tip( trans.app ):
# The current ctx is the repository tip, so use it.
@@ -1369,7 +1383,11 @@
elif not update_to_changeset_hash and changeset_hash == changeset_revision:
# We've found the changeset in the changelog for which we need to get the next update.
update_to_changeset_hash = changeset_hash
+ update_dict[ 'includes_data_managers' ] = includes_data_managers
+ update_dict[ 'includes_datatypes' ] = includes_datatypes
update_dict[ 'includes_tools' ] = includes_tools
+ update_dict[ 'includes_tool_dependencies' ] = includes_tool_dependencies
+ update_dict[ 'includes_workflows' ] = includes_workflows
update_dict[ 'has_repository_dependencies' ] = has_repository_dependencies
update_dict[ 'changeset_revision' ] = str( latest_changeset_revision )
update_dict[ 'ctx_rev' ] = str( update_to_ctx.rev() )
@@ -1601,16 +1619,22 @@
repository_metadata=repository_metadata,
tool_dependencies=None,
repository_dependencies=None )
+ includes_data_managers = False
+ includes_datatypes = False
+ includes_tools = False
+ includes_workflows = False
+ readme_files_dict = None
metadata = repository_metadata.metadata
if metadata:
- readme_files_dict = suc.build_readme_files_dict( metadata )
+ if 'data_manager' in metadata:
+ includes_data_managers = True
+ if 'datatypes' in metadata:
+ includes_datatypes = True
if 'tools' in metadata:
includes_tools = True
- else:
- includes_tools = False
- else:
- readme_files_dict = None
- includes_tools = False
+ if 'workflows' in metadata:
+ includes_workflows = True
+ readme_files_dict = suc.build_readme_files_dict( metadata )
# See if the repo_info_dict was populated with repository_dependencies or tool_dependencies.
for name, repo_info_tuple in repo_info_dict.items():
description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, tool_dependencies = \
@@ -1623,9 +1647,12 @@
includes_tool_dependencies = True
else:
includes_tool_dependencies = False
- return dict( includes_tools=includes_tools,
+ return dict( includes_data_managers=includes_data_managers,
+ includes_datatypes=includes_datatypes,
+ includes_tools=includes_tools,
has_repository_dependencies=has_repository_dependencies,
includes_tool_dependencies=includes_tool_dependencies,
+ includes_workflows=includes_workflows,
readme_files_dict=readme_files_dict,
repo_info_dict=repo_info_dict )
def get_versions_of_tool( self, trans, repository, repository_metadata, guid ):
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -383,29 +383,23 @@
if repository.uninstalled:
# Since we're reinstalling the repository we need to find the latest changeset revision to which it can be updated so that we
# can reset the metadata if necessary. This will ensure that information about repository dependencies and tool dependencies
- # will be current. Only allow selecting a different section in the tool panel if the repository was uninstalled.
- current_changeset_revision, current_ctx_rev, includes_tools, has_repository_dependencies = \
- shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, repository )
- if current_ctx_rev == repository.ctx_rev:
- # The uninstalled repository is current.
- if repository.includes_tools or repository.has_repository_dependencies:
+ # will be current. Only allow selecting a different section in the tool panel if the repository was uninstalled.
+ changeset_revision_dict = shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, repository )
+ current_changeset_revision = changeset_revision_dict.get( 'changeset_revision', None )
+ current_ctx_rev = changeset_revision_dict.get( 'ctx_rev', None )
+ if current_changeset_revision and current_ctx_rev:
+ if current_ctx_rev == repository.ctx_rev:
+ # The uninstalled repository is current.
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='reselect_tool_panel_section',
**kwd ) )
else:
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='reinstall_repository',
- **kwd ) )
- else:
- # The uninstalled repository has updates available in the tool shed.
- updated_repo_info_dict = self.get_updated_repository_information( trans=trans,
- repository_id=trans.security.encode_id( repository.id ),
- repository_name=repository.name,
- repository_owner=repository.owner,
- changeset_revision=current_changeset_revision )
- has_repository_dependencies = updated_repo_info_dict.get( 'has_repository_dependencies', False )
- includes_tool_dependencies = updated_repo_info_dict.get( 'includes_tool_dependencies', False )
- if has_repository_dependencies or includes_tool_dependencies:
+ # The uninstalled repository has updates available in the tool shed.
+ updated_repo_info_dict = self.get_updated_repository_information( trans=trans,
+ repository_id=trans.security.encode_id( repository.id ),
+ repository_name=repository.name,
+ repository_owner=repository.owner,
+ changeset_revision=current_changeset_revision )
json_repo_info_dict = json.to_json_string( updated_repo_info_dict )
encoded_repo_info_dict = encoding_util.tool_shed_encode( json_repo_info_dict )
kwd[ 'latest_changeset_revision' ] = current_changeset_revision
@@ -414,10 +408,14 @@
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='reselect_tool_panel_section',
**kwd ) )
- else:
- return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
- action='reinstall_repository',
- **kwd ) )
+ else:
+ message = "Unable to get latest revision for repository <b>%s</b> from the tool shed, so repository " % str( repository.name )
+ message += "reinstallation is not possible at this time."
+ status = "error"
+ return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
+ action='browse_repositories',
+ message=message,
+ status=status ) )
else:
return trans.response.send_redirect( web.url_for( controller='admin_toolshed',
action='activate_repository',
@@ -903,8 +901,9 @@
if cloned_ok:
if reinstalling:
# Since we're reinstalling the repository we need to find the latest changeset revision to which is can be updated.
- current_changeset_revision, current_ctx_rev, includes_tools, has_repository_dependencies = \
- shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, tool_shed_repository )
+ changeset_revision_dict = shed_util.get_update_to_changeset_revision_and_ctx_rev( trans, tool_shed_repository )
+ current_changeset_revision = changeset_revision_dict.get( 'changeset_revision', None )
+ current_ctx_rev = changeset_revision_dict.get( 'ctx_rev', None )
if current_ctx_rev != ctx_rev:
repo = hg.repository( suc.get_configured_ui(), path=os.path.abspath( install_dir ) )
shed_util.pull_repository( repo, repository_clone_url, current_changeset_revision )
@@ -1367,7 +1366,7 @@
containers_dicts.append( containers_dict )
# Merge all containers into a single container.
containers_dict = shed_util.merge_containers_dicts_for_new_install( containers_dicts )
- # Handle tool dependencies chack box.
+ # Handle tool dependencies check box.
if trans.app.config.tool_dependency_dir is None:
if includes_tool_dependencies:
message = "Tool dependencies defined in this repository can be automatically installed if you set the value of your <b>tool_dependency_dir</b> "
@@ -1566,6 +1565,7 @@
Galaxy database will not be used since it is outdated.
"""
message = ''
+ status = 'done'
repository_id = kwd.get( 'id', None )
latest_changeset_revision = kwd.get( 'latest_changeset_revision', None )
latest_ctx_rev = kwd.get( 'latest_ctx_rev', None )
@@ -1580,19 +1580,36 @@
encoded_updated_repo_info_dict = kwd.get( 'updated_repo_info_dict', None )
updated_repo_info_dict = encoding_util.tool_shed_decode( encoded_updated_repo_info_dict )
readme_files_dict = updated_repo_info_dict.get( 'readme_files_dict', None )
+ includes_data_managers = updated_repo_info_dict.get( 'includes_data_managers', False )
+ includes_datatypes = updated_repo_info_dict.get( 'includes_datatypes', False )
includes_tools = updated_repo_info_dict.get( 'includes_tools', False )
+ includes_workflows = updated_repo_info_dict.get( 'includes_workflows', False )
has_repository_dependencies = updated_repo_info_dict.get( 'has_repository_dependencies', False )
includes_tool_dependencies = updated_repo_info_dict.get( 'includes_tool_dependencies', False )
repo_info_dict = updated_repo_info_dict[ 'repo_info_dict' ]
else:
# There are no updates available from the tool shed for the repository, so use it's locally stored metadata.
+ has_repository_dependencies = False
+ includes_data_managers = False
+ includes_datatypes = False
+ includes_tool_dependencies = False
+ includes_tools = False
+ includes_workflows = False
+ readme_files_dict = None
+ tool_dependencies = None
if metadata:
+ if 'data_manager' in metadata:
+ includes_data_managers = True
+ if 'datatypes' in metadata:
+ includes_datatypes = True
+ if 'tools' in metadata:
+ includes_tools = True
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
+ if 'workflows' in metadata:
+ includes_workflows = True
readme_files_dict = suc.build_readme_files_dict( metadata )
tool_dependencies = metadata.get( 'tool_dependencies', None )
- else:
- readme_files_dict = None
- tool_dependencies = None
- includes_tool_dependencies = tool_shed_repository.includes_tool_dependencies
repository_dependencies = self.get_repository_dependencies( trans=trans,
repository_id=repository_id,
repository_name=tool_shed_repository.name,
@@ -1615,33 +1632,39 @@
has_repository_dependencies = True
else:
has_repository_dependencies = False
- # Get the location in the tool panel in which the tool was originally loaded.
- if 'tool_panel_section' in metadata:
- tool_panel_dict = metadata[ 'tool_panel_section' ]
- if tool_panel_dict:
- if shed_util.panel_entry_per_tool( tool_panel_dict ):
- # The following forces everything to be loaded into 1 section (or no section) in the tool panel.
- tool_section_dicts = tool_panel_dict[ tool_panel_dict.keys()[ 0 ] ]
- tool_section_dict = tool_section_dicts[ 0 ]
- original_section_name = tool_section_dict[ 'name' ]
+ if includes_tools:
+ # Get the location in the tool panel in which the tools were originally loaded.
+ if 'tool_panel_section' in metadata:
+ tool_panel_dict = metadata[ 'tool_panel_section' ]
+ if tool_panel_dict:
+ if shed_util.panel_entry_per_tool( tool_panel_dict ):
+ # The following forces everything to be loaded into 1 section (or no section) in the tool panel.
+ tool_section_dicts = tool_panel_dict[ tool_panel_dict.keys()[ 0 ] ]
+ tool_section_dict = tool_section_dicts[ 0 ]
+ original_section_name = tool_section_dict[ 'name' ]
+ else:
+ original_section_name = tool_panel_dict[ 'name' ]
else:
- original_section_name = tool_panel_dict[ 'name' ]
+ original_section_name = ''
else:
original_section_name = ''
+ tool_panel_section_select_field = build_tool_panel_section_select_field( trans )
+ no_changes_check_box = CheckboxField( 'no_changes', checked=True )
+ if original_section_name:
+ message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel section <b>%s</b>. " \
+ % ( tool_shed_repository.name, original_section_name )
+ message += "Uncheck the <b>No changes</b> check box and select a different tool panel section to load the tools in a "
+ message += "different section in the tool panel. "
+ status = 'warning'
+ else:
+ message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel outside of any sections. " % tool_shed_repository.name
+ message += "Uncheck the <b>No changes</b> check box and select a tool panel section to load the tools into that section. "
+ status = 'warning'
else:
+ no_changes_check_box = None
original_section_name = ''
- tool_panel_section_select_field = build_tool_panel_section_select_field( trans )
- no_changes_check_box = CheckboxField( 'no_changes', checked=True )
- if original_section_name:
- message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel section <b>%s</b>. " \
- % ( tool_shed_repository.name, original_section_name )
- message += "Uncheck the <b>No changes</b> check box and select a different tool panel section to load the tools in a "
- message += "different section in the tool panel. "
- status = 'warning'
- else:
- message += "The tools contained in your <b>%s</b> repository were last loaded into the tool panel outside of any sections. " % tool_shed_repository.name
- message += "Uncheck the <b>No changes</b> check box and select a tool panel section to load the tools into that section. "
- status = 'warning'
+ tool_panel_section_select_field = None
+ shed_tool_conf_select_field = build_shed_tool_conf_select_field( trans )
containers_dict = shed_util.populate_containers_dict_for_new_install( trans=trans,
tool_shed_url=tool_shed_url,
tool_path=tool_path,
@@ -1669,12 +1692,17 @@
repository=tool_shed_repository,
no_changes_check_box=no_changes_check_box,
original_section_name=original_section_name,
+ includes_data_managers=includes_data_managers,
+ includes_datatypes=includes_datatypes,
+ includes_tools=includes_tools,
includes_tool_dependencies=includes_tool_dependencies,
+ includes_workflows=includes_workflows,
has_repository_dependencies=has_repository_dependencies,
install_repository_dependencies_check_box=install_repository_dependencies_check_box,
install_tool_dependencies_check_box=install_tool_dependencies_check_box,
containers_dict=containers_dict,
tool_panel_section_select_field=tool_panel_section_select_field,
+ shed_tool_conf_select_field=shed_tool_conf_select_field,
encoded_repo_info_dict=encoding_util.tool_shed_encode( repo_info_dict ),
repo_info_dict=repo_info_dict,
message=message,
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/reselect_tool_panel_section.mako
@@ -41,28 +41,55 @@
</div>
${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
%endif
- <div style="clear: both"></div>
- <div class="form-row">
- ${no_changes_check_box.get_html()}
- <label style="display: inline;">No changes</label>
- <div class="toolParamHelp" style="clear: both;">
- Uncheck and select a different tool panel section to load the tools into a different section in the tool panel.
+ %if shed_tool_conf_select_field:
+ <div class="form-row">
+ <table class="colored" width="100%">
+ <th bgcolor="#EBD9B2">Choose the configuration file whose tool_path setting will be used for installing repositories</th>
+ </table></div>
- </div>
- <div class="form-row">
- <label>Add new tool panel section:</label>
- <input name="new_tool_panel_section" type="textfield" value="" size="40"/>
- <div class="toolParamHelp" style="clear: both;">
- Add a new tool panel section to contain the installed tools (optional).
+ <%
+ if len( shed_tool_conf_select_field.options ) == 1:
+ select_help = "Your Galaxy instance is configured with 1 shed-related tool configuration file, so repositories will be "
+ select_help += "installed using it's <b>tool_path</b> setting."
+ else:
+ select_help = "Your Galaxy instance is configured with %d shed-related tool configuration files, " % len( shed_tool_conf_select_field.options )
+ select_help += "so select the file whose <b>tool_path</b> setting you want used for installing repositories."
+ %>
+ <div class="form-row">
+ <label>Shed tool configuration file:</label>
+ ${shed_tool_conf_select_field.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ ${select_help}
+ </div></div>
- </div>
- <div class="form-row">
- <label>Select existing tool panel section:</label>
- ${tool_panel_section_select_field.get_html()}
- <div class="toolParamHelp" style="clear: both;">
- Choose an existing section in your tool panel to contain the installed tools (optional).
+ <div style="clear: both"></div>
+ %else:
+ <input type="hidden" name="shed_tool_conf" value="${shed_tool_conf}"/>
+ %endif
+ %if includes_tools:
+ <div style="clear: both"></div>
+ <div class="form-row">
+ ${no_changes_check_box.get_html()}
+ <label style="display: inline;">No changes</label>
+ <div class="toolParamHelp" style="clear: both;">
+ Uncheck and select a different tool panel section to load the tools into a different section in the tool panel.
+ </div></div>
- </div>
+ <div class="form-row">
+ <label>Add new tool panel section:</label>
+ <input name="new_tool_panel_section" type="textfield" value="" size="40"/>
+ <div class="toolParamHelp" style="clear: both;">
+ Add a new tool panel section to contain the installed tools (optional).
+ </div>
+ </div>
+ <div class="form-row">
+ <label>Select existing tool panel section:</label>
+ ${tool_panel_section_select_field.get_html()}
+ <div class="toolParamHelp" style="clear: both;">
+ Choose an existing section in your tool panel to contain the installed tools (optional).
+ </div>
+ </div>
+ %endif
<div class="form-row"><input type="submit" name="select_tool_panel_section_button" value="Install"/></div>
diff -r 32fc25b8900059f63b0d41d52aa582f06426928c -r 305680a482c3096b082daffa5ff665f5f60d1528 templates/admin/tool_shed_repository/select_tool_panel_section.mako
--- a/templates/admin/tool_shed_repository/select_tool_panel_section.mako
+++ b/templates/admin/tool_shed_repository/select_tool_panel_section.mako
@@ -81,12 +81,12 @@
${render_dependencies_section( install_repository_dependencies_check_box, install_tool_dependencies_check_box, containers_dict )}
<div style="clear: both"></div>
%endif
- <div class="form-row">
- <table class="colored" width="100%">
- <th bgcolor="#EBD9B2">Choose the tool panel section to contain the installed tools (optional)</th>
- </table>
- </div>
%if shed_tool_conf_select_field:
+ <div class="form-row">
+ <table class="colored" width="100%">
+ <th bgcolor="#EBD9B2">Choose the tool panel section to contain the installed tools (optional)</th>
+ </table>
+ </div><%
if len( shed_tool_conf_select_field.options ) == 1:
select_help = "Your Galaxy instance is configured with 1 shed-related tool configuration file, so repositories will be "
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: functional_tests.py: add debugging statement for app config
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/32fc25b89000/
changeset: 32fc25b89000
user: carlfeberhard
date: 2013-02-19 20:31:56
summary: functional_tests.py: add debugging statement for app config
affected #: 1 file
diff -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 -r 32fc25b8900059f63b0d41d52aa582f06426928c scripts/functional_tests.py
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -84,7 +84,6 @@
global_conf.update( get_static_settings() )
return global_conf
-
def parse_tool_panel_config( config, shed_tools_dict ):
"""
Parse a shed-related tool panel config to generate the shed_tools_dict. This only happens when testing tools installed from the tool shed.
@@ -293,6 +292,7 @@
kwargs[ 'object_store' ] = 'distributed'
kwargs[ 'distributed_object_store_config_file' ] = 'distributed_object_store_conf.xml.sample'
# Build the Universe Application
+ log.debug( 'app.kwargs:\n%s', pprint.pformat( kwargs ) )
app = UniverseApplication( job_queue_workers = 5,
id_secret = 'changethisinproductiontoo',
template_path = "templates",
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: carlfeberhard: browser tests: refactor framework into modules; add history panel tests, anon-user history panel tests
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/973b8d73409f/
changeset: 973b8d73409f
user: carlfeberhard
date: 2013-02-19 20:04:41
summary: browser tests: refactor framework into modules; add history panel tests, anon-user history panel tests
affected #: 10 files
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/anon-history-tests.js
--- /dev/null
+++ b/test/casperjs/anon-history-tests.js
@@ -0,0 +1,181 @@
+// have to handle errors here - or phantom/casper won't bail but _HANG_
+try {
+ var utils = require( 'utils' ),
+ xpath = require( 'casper' ).selectXPath,
+ format = utils.format,
+
+ //...if there's a better way - please let me know, universe
+ scriptDir = require( 'system' ).args[3]
+ // remove the script filename
+ .replace( /[\w|\.|\-|_]*$/, '' )
+ // if given rel. path, prepend the curr dir
+ .replace( /^(?!\/)/, './' ),
+ spaceghost = require( scriptDir + 'spaceghost' ).create({
+ // script options here (can be overridden by CLI)
+ //verbose: true,
+ //logLevel: debug,
+ scriptDir: scriptDir
+ });
+
+ spaceghost.start();
+
+} catch( error ){
+ console.debug( error );
+ phantom.exit( 1 );
+}
+
+
+// -------------------------------------------------------------------
+/* TODO:
+ run a tool
+
+*/
+// =================================================================== globals and helpers
+var email = spaceghost.user.getRandomEmail(),
+ password = '123456';
+if( spaceghost.fixtureData.testUser ){
+ email = spaceghost.fixtureData.testUser.email;
+ password = spaceghost.fixtureData.testUser.password;
+}
+
+var galaxyCookieName = 'galaxysession',
+
+ nameSelector = 'div#history-name',
+ unnamedName = 'Unnamed history',
+ subtitleSelector = 'div#history-subtitle-area',
+ initialSizeStr = '0 bytes',
+ tagIconSelector = '#history-tag.icon-button',
+ annoIconSelector = '#history-annotate.icon-button',
+ //emptyMsgSelector = '#emptyHistoryMessage';
+ emptyMsgSelector = '.infomessagesmall',
+ emptyMsgStr = "Your history is empty. Click 'Get Data' on the left pane to start",
+
+ tooltipSelector = '.bs-tooltip',
+ anonNameTooltip = 'You must be logged in to edit your history name',
+
+ editableTextClass = 'editable-text',
+ editableTextInputSelector = 'input#renaming-active';
+
+var historyFrameInfo = {},
+ testUploadInfo = {};
+
+
+// =================================================================== TESTS
+// ------------------------------------------------------------------- anonymous new, history
+// open galaxy - ensure not logged in
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ var loggedInAs = spaceghost.user.loggedInAs();
+ this.debug( 'loggedInAs: ' + loggedInAs );
+ if( loggedInAs ){ this.logout(); }
+});
+
+// ------------------------------------------------------------------- check anon cookies
+spaceghost.then( function testAnonCookies(){
+ this.test.comment( 'session cookie for anon-user should be present and well formed' );
+ var cookies = this.page.cookies;
+ this.debug( this.jsonStr( this.page.cookies ) );
+ //??: what are 'well formed' values?
+ this.test.assert( cookies.length === 1, "Has one cookie" );
+ var galaxyCookie = cookies[0];
+ this.test.assert( galaxyCookie.name === galaxyCookieName, "Cookie named: " + galaxyCookieName );
+ this.test.assert( !galaxyCookie.secure, "Cookie.secure is false" );
+});
+
+// ------------------------------------------------------------------- check the empty history for well formedness
+// grab the history frame bounds for mouse later tests
+spaceghost.then( function(){
+ historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' );
+ //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) );
+});
+
+spaceghost.thenOpen( spaceghost.baseUrl, function testPanelStructure(){
+ this.test.comment( 'history panel for anonymous user, new history' );
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( "frame should have proper url and title: 'History'" );
+ this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' );
+ this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' );
+
+ this.test.comment( "history name should exist, be visible, and have text " + unnamedName );
+ this.test.assertExists( nameSelector, nameSelector + ' exists' );
+ this.test.assertVisible( nameSelector, 'History name is visible' );
+ this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName );
+
+ this.test.comment( "history subtitle should display size and size should be 0 bytes" );
+ this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
+ this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
+ this.test.assertSelectorHasText( subtitleSelector, initialSizeStr,
+ 'History subtitle has "' + initialSizeStr + '"' );
+
+ this.test.comment( "NO tags or annotations icons should be available for an anonymous user" );
+ this.test.assertDoesntExist( tagIconSelector, 'Tag icon button not found' );
+ this.test.assertDoesntExist( annoIconSelector, 'Annotation icon button not found' );
+
+ this.test.comment( "A message about the current history being empty should be displayed" );
+ this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' );
+ this.test.assertVisible( emptyMsgSelector, 'Empty history message is visible' );
+ this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr,
+ 'Message contains "' + emptyMsgStr + '"' );
+
+ this.test.comment( 'name should have a tooltip with info on anon-user name editing' );
+ // mouse over to find tooltip
+ //NOTE!!: bounds are returned relative to containing frame - need to adjust using historyFrameInfo
+ //TODO: into conv. fn
+ var nameInfo = this.getElementInfo( nameSelector );
+ //this.debug( 'nameInfo:' + this.jsonStr( nameInfo ) );
+ this.page.sendEvent( 'mousemove',
+ historyFrameInfo.x + nameInfo.x + 1, historyFrameInfo.y + nameInfo.y + 1 );
+ this.test.assertExists( tooltipSelector, "Found tooltip after name hover" );
+ this.test.assertSelectorHasText( tooltipSelector, anonNameTooltip );
+
+ this.test.comment( 'name should NOT be editable when clicked by anon-user' );
+ this.test.assert( nameInfo.attributes[ 'class' ].indexOf( editableTextClass ) === -1,
+ "Name field is not class for editable text" );
+ this.click( nameSelector );
+ this.test.assertDoesntExist( editableTextInputSelector, "Clicking on name does not create an input" );
+ });
+});
+
+// ------------------------------------------------------------------- anon user can upload file
+spaceghost.then( function testAnonUpload(){
+ this.test.comment( 'anon-user should be able to upload files' );
+ spaceghost.tools.uploadFile( '../../test-data/1.txt', function uploadCallback( _uploadInfo ){
+ this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) );
+ var hasHda = _uploadInfo.hdaElement,
+ hasClass = _uploadInfo.hdaElement.attributes[ 'class' ],
+ hasOkClass = _uploadInfo.hdaElement.attributes[ 'class' ].indexOf( 'historyItem-ok' ) !== -1;
+ this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.name );
+ uploadInfo = _uploadInfo;
+ });
+});
+spaceghost.then( function testAnonUpload(){
+ this.test.comment( "empty should be NO LONGER be displayed" );
+ this.test.assertNotVisible( emptyMsgSelector, 'Empty history message is not visible' );
+});
+
+
+// ------------------------------------------------------------------- anon user can run tool on file
+
+// ------------------------------------------------------------------- anon user registers/logs in -> same history
+spaceghost.user.loginOrRegisterUser( email, password );
+//??: why is a reload needed here? If we don't, loggedInAs === '' ...
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+
+ this.test.comment( 'anon-user should login and be associated with previous history' );
+ var loggedInAs = spaceghost.user.loggedInAs();
+ this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' );
+
+ this.withFrame( this.selectors.frames.history, function(){
+ var hdaInfo = this.historypanel.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
+ this.test.assert( hdaInfo !== null, "After logging in - found a matching hda by name and hid" );
+ if( hdaInfo ){
+ this.test.assert( uploadInfo.hdaElement.attributes.id === hdaInfo.attributes.id,
+ "After logging in - found a matching hda by hda view id: " + hdaInfo.attributes.id );
+ }
+ });
+});
+
+
+// ===================================================================
+spaceghost.run( function(){
+ this.test.done();
+});
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/casperjs_runner.py
--- a/test/casperjs/casperjs_runner.py
+++ b/test/casperjs/casperjs_runner.py
@@ -95,6 +95,8 @@
stderr_msg = process.stderr.readline()
stderr_msg = self.strip_escape_codes( stderr_msg.strip() )
log.debug( '(%s): %s', rel_script_path, stderr_msg )
+ # HACK: this is the last string displayed using the debug settings - afterwards it hangs
+ # so: bail on this string
if stderr_msg.startswith( self.casper_done_str ):
break
@@ -117,7 +119,7 @@
self.exec_path, self.casper_info )
raise
- self.handle_js_results( stdout_output )
+ return self.handle_js_results( stdout_output )
def build_command_line( self, rel_script_path, *args, **kwargs ):
"""Build the headless browser command line list for subprocess.
@@ -284,35 +286,61 @@
log.debug( '\n--------------- tearing down module' )
+test_user = {
+ 'email': 'test1(a)test.test',
+ 'password': '123456'
+}
+
# ==================================================================== TESTCASE EXAMPLE
-# these could be broken out into other files - shouldn't be necc. ATM
-class UserTests( CasperJSTestCase ):
+# these could be broken out into other py files - shouldn't be necc. ATM
+class Test_01_User( CasperJSTestCase ):
"""TestCase that uses javascript and a headless browser to test dynamic pages.
"""
+ #debug = True
def test_10_registration( self ):
"""User registration tests: register new user, logout, attempt bad registrations.
"""
# all keywords will be compiled into a single JSON obj and passed to the server
- self.run_js_script( 'registration-tests.js', self.env.url,
- testuser={ 'email': 'test1(a)test.test', 'password': '123456' })
+ self.run_js_script( 'registration-tests.js',
+ testuser=test_user )
+
#TODO:?? could theoretically do db cleanup, checks here with SQLALX
#TODO: have run_js_script return other persistant fixture data (uploaded files, etc.)
def test_20_login( self ):
"""User log in tests.
"""
- self.run_js_script( 'login-tests.js', self.env.url,
- testuser={ 'email': 'test1(a)test.test', 'password': '123456' })
+ self.run_js_script( 'login-tests.js',
+ testuser=test_user )
-class ToolTests( CasperJSTestCase ):
+class Test_02_Tools( CasperJSTestCase ):
"""(Minimal) casperjs tests for tools.
"""
#debug = True
def test_10_upload( self ):
"""Tests uploading files
"""
- self.run_js_script( 'upload-tests.js' )
+ self.run_js_script( 'upload-tests.js',
+ testuser=test_user )
+
+
+class Test_03_HistoryPanel( CasperJSTestCase ):
+ """(Minimal) casperjs tests for tools.
+ """
+ #debug = True
+ def test_00_history_panel( self ):
+ """Test history panel basics (controls, structure, refresh, history options menu, etc.).
+ """
+ self.run_js_script( 'history-panel-tests.js',
+ testuser=test_user )
+
+ def test_10_anonymous_histories( self ):
+ """Test history panel basics with an anonymous user.
+ """
+ self.run_js_script( 'anon-history-tests.js',
+ testuser=test_user )
+
# ==================================================================== MAIN
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/history-panel-tests.js
--- /dev/null
+++ b/test/casperjs/history-panel-tests.js
@@ -0,0 +1,252 @@
+// have to handle errors here - or phantom/casper won't bail but _HANG_
+try {
+ var utils = require( 'utils' ),
+ xpath = require( 'casper' ).selectXPath,
+ format = utils.format,
+
+ //...if there's a better way - please let me know, universe
+ scriptDir = require( 'system' ).args[3]
+ // remove the script filename
+ .replace( /[\w|\.|\-|_]*$/, '' )
+ // if given rel. path, prepend the curr dir
+ .replace( /^(?!\/)/, './' ),
+ spaceghost = require( scriptDir + 'spaceghost' ).create({
+ // script options here (can be overridden by CLI)
+ //verbose: true,
+ //logLevel: debug,
+ scriptDir: scriptDir
+ });
+
+ spaceghost.start();
+
+} catch( error ){
+ console.debug( error );
+ phantom.exit( 1 );
+}
+
+
+// ===================================================================
+/* TODO:
+*/
+// =================================================================== globals and helpers
+var email = spaceghost.user.getRandomEmail(),
+ password = '123456';
+if( spaceghost.fixtureData.testUser ){
+ email = spaceghost.fixtureData.testUser.email;
+ password = spaceghost.fixtureData.testUser.password;
+}
+var newHistoryName = "Test History";
+
+var nameSelector = 'div#history-name',
+ unnamedName = 'Unnamed history',
+ subtitleSelector = 'div#history-subtitle-area',
+ initialSizeStr = '0 bytes',
+ tagIconSelector = '#history-tag.icon-button',
+ annoIconSelector = '#history-annotate.icon-button',
+ //emptyMsgSelector = '#emptyHistoryMessage';
+ emptyMsgSelector = '.infomessagesmall',
+ emptyMsgStr = "Your history is empty. Click 'Get Data' on the left pane to start",
+
+ tooltipSelector = '.bs-tooltip',
+ nameTooltip = 'Click to rename history',
+
+ editableTextClass = 'editable-text',
+ editableTextInputSelector = 'input#renaming-active';
+
+var historyFrameInfo = {},
+ testUploadInfo = {};
+
+
+// =================================================================== TESTS
+// ------------------------------------------------------------------- start a new user
+spaceghost.user.loginOrRegisterUser( email, password );
+//??: why is a reload needed here? If we don't, loggedInAs === '' ...
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ var loggedInAs = spaceghost.user.loggedInAs();
+ this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' );
+});
+
+// ------------------------------------------------------------------- check structure of empty history
+// grab the history frame bounds for mouse later tests
+spaceghost.then( function(){
+ historyFrameInfo = this.getElementInfo( 'iframe[name="galaxy_history"]' );
+ //this.debug( 'historyFrameInfo:' + this.jsonStr( historyFrameInfo ) );
+});
+
+spaceghost.thenOpen( spaceghost.baseUrl, function testPanelStructure(){
+ this.test.comment( 'history panel, new history' );
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( "frame should have proper url and title: 'History'" );
+ this.test.assertMatch( this.getCurrentUrl(), /\/history/, 'Found history frame url' );
+ this.test.assertTitle( this.getTitle(), 'History', 'Found history frame title' );
+
+ this.test.comment( "history name should exist, be visible, and have text " + unnamedName );
+ this.test.assertExists( nameSelector, nameSelector + ' exists' );
+ this.test.assertVisible( nameSelector, 'History name is visible' );
+ this.test.assertSelectorHasText( nameSelector, unnamedName, 'History name is ' + unnamedName );
+
+ this.test.comment( "history subtitle should display size and size should be 0 bytes" );
+ this.test.assertExists( subtitleSelector, 'Found ' + subtitleSelector );
+ this.test.assertVisible( subtitleSelector, 'History subtitle is visible' );
+ this.test.assertSelectorHasText( subtitleSelector, initialSizeStr,
+ 'History subtitle has "' + initialSizeStr + '"' );
+
+ this.test.comment( "tags and annotation icons should be available" );
+ this.test.assertExists( tagIconSelector, 'Tag icon button found' );
+ this.test.assertExists( annoIconSelector, 'Annotation icon button found' );
+
+ this.test.comment( "A message about the current history being empty should be displayed" );
+ this.test.assertExists( emptyMsgSelector, emptyMsgSelector + ' exists' );
+ this.test.assertVisible( emptyMsgSelector, 'Empty history message is visible' );
+ this.test.assertSelectorHasText( emptyMsgSelector, emptyMsgStr,
+ 'Message contains "' + emptyMsgStr + '"' );
+
+ });
+});
+
+// ------------------------------------------------------------------- name editing
+spaceghost.then( function(){
+ this.test.comment( 'history panel, editing the history name' );
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( 'name should have a tooltip with proper info on name editing' );
+ var nameInfo = this.getElementInfo( nameSelector );
+ this.page.sendEvent( 'mousemove',
+ historyFrameInfo.x + nameInfo.x + 1, historyFrameInfo.y + nameInfo.y + 1 );
+ this.test.assertExists( tooltipSelector, "Found tooltip after name hover" );
+ this.test.assertSelectorHasText( tooltipSelector, nameTooltip );
+
+ this.test.comment( 'name should be create an input when clicked' );
+ this.test.assert( nameInfo.attributes[ 'class' ].indexOf( editableTextClass ) !== -1,
+ "Name field classed for editable text" );
+ this.click( nameSelector );
+ this.test.assertExists( editableTextInputSelector, "Clicking on name creates an input" );
+
+ this.test.comment( 'name should be editable by entering keys and pressing enter' );
+ //NOTE: casperjs.sendKeys adds a click before and a selector.blur after sending - won't work here
+ //TODO: to conv. fn
+ this.page.sendEvent( 'keypress', newHistoryName );
+ this.page.sendEvent( 'keypress', this.page.event.key.Enter );
+ this.wait( 1000, function(){
+ this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is ' + newHistoryName );
+ this.test.assertDoesntExist( editableTextInputSelector, "Input disappears after pressing enter" );
+ });
+ });
+});
+spaceghost.then( function(){
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( 'name should revert if user clicks away while editing' );
+ this.click( nameSelector );
+ this.page.sendEvent( 'keypress', "Woodchipper metagenomics, Fargo, ND" );
+
+ // click above the name input element
+ var inputInfo = this.getElementInfo( editableTextInputSelector );
+ this.page.sendEvent( 'mousedown',
+ historyFrameInfo.x + inputInfo.x + 1, historyFrameInfo.y + inputInfo.y - 5 );
+
+ this.wait( 1000, function(){
+ this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName );
+ this.test.assertDoesntExist( editableTextInputSelector, "Input disappears after clicking away" );
+ });
+ });
+});
+spaceghost.then( function(){
+ this.withFrame( this.selectors.frames.history, function(){
+ this.test.comment( 'name should revert if user hits ESC while editing' );
+ this.click( nameSelector );
+ this.page.sendEvent( 'keypress', "Arsenic Bacteria" );
+
+ this.page.sendEvent( 'keypress', this.page.event.key.Escape );
+ this.wait( 1000, function(){
+ this.test.assertSelectorHasText( nameSelector, newHistoryName, 'History name is STILL ' + newHistoryName );
+ this.test.assertDoesntExist( editableTextInputSelector, "Input disappears after hitting ESC" );
+ });
+ });
+});
+
+
+// ------------------------------------------------------------------- check structure of NON empty history
+/*
+// upload file: 1.txt
+spaceghost.then( function upload(){
+ this.test.comment( 'anon-user should be able to upload files' );
+ spaceghost.uploadFile( '../../test-data/1.txt', function uploadCallback( _uploadInfo ){
+ this.debug( 'uploaded HDA info: ' + this.jsonStr( _uploadInfo ) );
+ var hasHda = _uploadInfo.hdaElement,
+ hasClass = _uploadInfo.hdaElement.attributes[ 'class' ],
+ hasOkClass = _uploadInfo.hdaElement.attributes[ 'class' ].indexOf( 'historyItem-ok' ) !== -1;
+ this.test.assert( ( hasHda && hasClass && hasOkClass ), "Uploaded file: " + _uploadInfo.name );
+ uploadInfo = _uploadInfo;
+ });
+});
+
+//TODO: for each uploaded file: 1 file per (standard) datatype (or some subset)
+// txt, tabular, sam, bam, fasta, fastq, bed, gff,
+*/
+
+// -------------------------------------------------------------------
+//history panel
+ // structure of empty
+ // upload file
+ // structure of not empty
+ // tags
+ // annotation
+ // history refresh
+ // history options
+ // structure
+
+ // deleted
+
+ // hidden
+
+ // persistant expansion (or in hdaView?)
+
+//hdaView
+// with hpanel:
+ // (we assume hda is in the ok state)
+ // with collapsed hda:
+ // can we see the hid?
+ // can we see the title?
+ // three primary action buttons:
+ // they exist?
+ // Do they have good hrefs, targets?
+ // Are they enabled?
+ // do they have proper tooltips?
+ // display
+ // edit
+ // delete
+ //??: click through?
+
+ // with expaned hda:
+ // can we see the hid, title, and primary display buttons?
+
+ // misc info: no dbkey specified - is there a '?' link leading to edit attr?
+ // misc info: uploaded sam file
+ // misc info: format: sam
+
+ // secondary actions:
+ // download
+ // info
+ // rerun
+ // visualizations
+
+ // tags and annotations
+ //TODO: to their own file? tested elsewhere?
+
+ // peek:
+ // proper headers?
+ // lines?
+ // scrollbar?
+
+ // can re-collapse?
+
+
+
+
+
+
+
+
+// ===================================================================
+spaceghost.run( function(){
+ this.test.done();
+});
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/login-tests.js
--- a/test/casperjs/login-tests.js
+++ b/test/casperjs/login-tests.js
@@ -32,7 +32,7 @@
*/
// =================================================================== globals and helpers
-var email = spaceghost.getRandomEmail(),
+var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
email = spaceghost.fixtureData.testUser.email;
@@ -40,51 +40,38 @@
}
// =================================================================== TESTS
+// register a user (again...)
spaceghost.thenOpen( spaceghost.baseUrl, function(){
- this.test.comment( 'loading galaxy homepage' );
- // can we load galaxy?
- this.test.assertTitle( 'Galaxy' );
+ this.test.comment( 'registering: ' + email );
+ spaceghost.user.registerUser( email, password );
});
-// ------------------------------------------------------------------- should work
-
-// register a user (again...)
-spaceghost.then( function(){
- this.test.comment( 'registering: ' + email );
- spaceghost.registerUser( email, password );
-});
-// capture a sshot
-//spaceghost.then( function(){
-// this.clickLabel( 'User' );
-// this.capture( 'register.png' );
-//});
-
// log them out - check for empty logged in text
spaceghost.then( function(){
this.test.comment( 'logging out: ' + email );
- spaceghost.logout();
+ spaceghost.user.logout();
});
spaceghost.then( function(){
this.test.assertSelectorDoesntHaveText(
xpath( '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' ), /\w/ );
- this.test.assert( spaceghost.loggedInAs() === '', 'loggedInAs() is empty string' );
+ this.test.assert( spaceghost.user.loggedInAs() === '', 'loggedInAs() is empty string' );
});
// log them back in - check for email in logged in text
spaceghost.then( function(){
this.test.comment( 'logging back in: ' + email );
- spaceghost._submitLogin( email, password ); //No such user
+ spaceghost.user._submitLogin( email, password ); //No such user
});
-spaceghost.then( function(){
+spaceghost.thenOpen( spaceghost.baseUrl, function(){
this.test.assertSelectorHasText(
xpath( '//a[contains(text(),"Logged in as")]/span["id=#user-email"]' ), email );
- this.test.assert( spaceghost.loggedInAs() === email, 'loggedInAs() matches email' );
+ this.test.assert( spaceghost.user.loggedInAs() === email, 'loggedInAs() matches email' );
});
// finally log back out for next tests
spaceghost.then( function(){
this.test.comment( 'logging out: ' + email );
- spaceghost.logout();
+ spaceghost.user.logout();
});
// ------------------------------------------------------------------- shouldn't work
@@ -93,7 +80,7 @@
spaceghost.each( badEmails, function( self, badEmail ){
self.then( function(){
this.test.comment( 'attempting bad email: ' + badEmail );
- this._submitLogin( badEmail, password );
+ this.user._submitLogin( badEmail, password );
});
self.then(function(){
this.assertErrorMessage( 'No such user' );
@@ -105,7 +92,7 @@
spaceghost.each( badPasswords, function( self, badPassword ){
self.then( function(){
this.test.comment( 'attempting bad password: ' + badPassword );
- this._submitLogin( email, badPassword );
+ this.user._submitLogin( email, badPassword );
});
self.then(function(){
this.assertErrorMessage( 'Invalid password' );
@@ -118,7 +105,7 @@
this.assertStepsRaise( 'GalaxyError: LoginError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
- this.login( 'nihilist', '1234' );
+ this.user.login( 'nihilist', '1234' );
});
});
});
@@ -127,15 +114,16 @@
this.assertStepsRaise( 'GalaxyError: LoginError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad password' );
- this.login( email, '1234' );
+ this.user.login( email, '1234' );
});
});
});
spaceghost.then( function(){
- this.logout();
+ this.user.logout();
});
-
+/*
+*/
// ===================================================================
spaceghost.run( function(){
this.test.done();
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/modules/historypanel.js
--- /dev/null
+++ b/test/casperjs/modules/historypanel.js
@@ -0,0 +1,118 @@
+// =================================================================== module object, exports
+/** Creates a new tools module object.
+ * @exported
+ */
+exports.create = function createHistoryPanel( spaceghost ){
+ return new HistoryPanel( spaceghost );
+};
+
+/** HistoryPanel object constructor.
+ * @param {SpaceGhost} spaceghost a spaceghost instance
+ */
+var HistoryPanel = function HistoryPanel( spaceghost ){
+ this.options = {
+ progressIntervalDelay : 500
+ };
+ //??: circ ref?
+ this.spaceghost = spaceghost;
+};
+exports.HistoryPanel = HistoryPanel;
+
+HistoryPanel.prototype.toString = function toString(){
+ return this.spaceghost + '.HistoryPanel';
+};
+
+// -------------------------------------------------------------------
+/* TODO:
+ run a tool
+
+*/
+// =================================================================== INTERNAL
+
+// =================================================================== API (external)
+//TODO: to history module
+/** Find the casper element info of the hda wrapper given the hda title and hid.
+ * NOTE: if more than one is found, will return the first found.
+ * precondition: you should wrap this with withFrame( 'galaxy_history' ) :(
+ * @param {String} title the title of the hda
+ * @param {Int} hid (optional) the hid of the hda to look for
+ * @returns {Object|null} ElementInfo of the historyItemWrapper found, null if not found
+ */
+HistoryPanel.prototype.hdaElementInfoByTitle = function hdaElementInfoByTitle( title, hid ){
+ var spaceghost = this.spaceghost,
+ titleContains = ( hid !== undefined )?( hid + ': ' + title ):( title ),
+ wrapperInfo = null;
+
+ //NOTE: depends on jquery
+ wrapperInfo = spaceghost.evaluate( function( titleContains ){
+ // find the title, then the wrapper (2 containers up)
+ var $title = $( '.historyItemTitle:contains(' + titleContains + ')' );
+ var $wrapper = $title.parent().parent();
+ return (( $wrapper.attr( 'id' ) )?( __utils__.getElementInfo( '#' + $wrapper.attr( 'id' ) )):( null ));
+ }, titleContains );
+
+ return wrapperInfo;
+};
+
+/** Wait for the hda with given id to move into the given state.
+ * whenInStateFn and timeoutFn will be passed the hda element info (see Casper#getElementInfo)
+ * @param {String} hdaSelector selector for hda (should be historyItemWrapper)
+ * @param {String} finalState hda state to wait for (e.g. 'ok', 'error', 'running', 'queued', etc.)
+ * @param {Function} whenInStateFn called when hda goes into finalState
+ * @param {Function} timeoutFn called when maxWaitMs have passed without the desired state
+ * @param {Int} maxWaitMs number of milliseconds to wait before timing out (defaults to options.waitTimeout)
+ */
+HistoryPanel.prototype.waitForHdaState = function waitForHdaState( hdaSelector, finalState,
+ whenInStateFn, timeoutFn, maxWaitMs ){
+ //TODO:?? explicitly a historyWrapper id?
+ // we need a larger timeout for these - it can take a bit
+ maxWaitMs = maxWaitMs || this.spaceghost.options.waitTimeout;
+ var spaceghost = this.spaceghost,
+ finalStateClass = '.historyItem-' + finalState;
+
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.history, function(){
+
+ // save the old time out
+ var oldWaitTimeout = spaceghost.options.waitTimeout,
+
+ // output some progress indicator within the test (debug)
+ progressIntervalId = setInterval( function progress(){
+ // get the state from the hda wrapper's class
+ var state = spaceghost.evaluate( function( hdaSelector ){
+ if( !$( hdaSelector )[0] ){ return '(no hda found)'; }
+ var $wrapperClasses = $( hdaSelector ).attr( 'class' );
+ //TODO: remove magic string/regex
+ return $wrapperClasses.match( /historyItem\-(\w+)/ )[1];
+ }, hdaSelector );
+ spaceghost.debug( hdaSelector + ': ' + state );
+ }, spaceghost.historypanel.options.progressIntervalDelay ),
+
+ // when done, close down the progress reporter and reset the wait timeout to what it was
+ finallyFn = function(){
+ spaceghost.options.waitTimeout = oldWaitTimeout;
+ clearInterval( progressIntervalId );
+ };
+
+ spaceghost.options.waitTimeout = maxWaitMs;
+ spaceghost.waitForSelector( hdaSelector + finalStateClass,
+
+ // if the hda state became 'ok', call the whenInStateFn and close up
+ function _whenInState(){
+ var hdaInfo = spaceghost.elementInfoOrNull( hdaSelector );
+ spaceghost.debug( 'HDA now in state ' + finalState );
+ //spaceghost.debug( 'HDA:\n' + hdaInfo );
+ whenInStateFn.call( spaceghost, hdaInfo );
+ finallyFn();
+
+ // if we've timed out, call the timeoutFn and close up
+ }, function timeout(){
+ var hdaInfo = spaceghost.elementInfoOrNull( hdaSelector );
+ spaceghost.debug( 'HDA timed out. HDA = ' + spaceghost.jsonStr( hdaInfo ) );
+ timeoutFn.call( spaceghost, hdaInfo );
+ finallyFn();
+ }
+ );
+ });
+ });
+};
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/modules/tools.js
--- /dev/null
+++ b/test/casperjs/modules/tools.js
@@ -0,0 +1,221 @@
+// =================================================================== module object, exports
+/** Creates a new tools module object.
+ * @exported
+ */
+exports.create = function createTools( spaceghost ){
+ return new Tools( spaceghost );
+};
+
+/** Tools object constructor.
+ * @param {SpaceGhost} spaceghost a spaceghost instance
+ */
+var Tools = function Tools( spaceghost ){
+ //??: circ ref?
+ this.options = {
+ defaultUploadWait : ( 30 * 1000 )
+ };
+ this.spaceghost = spaceghost;
+};
+exports.Tools = Tools;
+
+Tools.prototype.toString = function toString(){
+ return this.spaceghost + '.Tools';
+};
+
+
+// =================================================================== INTERNAL
+/** Tests uploading a file.
+ * NOTE: this version does NOT throw an error on a bad upload.
+ * It is meant for testing the upload functionality and, therefore, is marked as private.
+ * Other tests should use uploadFile
+ * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
+ */
+Tools.prototype._uploadFile = function _uploadFile( filepath ){
+ var spaceghost = this.spaceghost,
+ uploadInfo = {};
+ //TODO: check file exists using phantom.fs
+ //TODO: pull from test data
+ uploadInfo[ spaceghost.selectors.tools.upload.fileInput ] = filepath;
+ spaceghost.debug( 'uploading file: ' + filepath );
+
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.tools, function(){
+ spaceghost.clickLabel( spaceghost.labels.tools.upload.panelLabel );
+ });
+ });
+
+ spaceghost.then( function beginUpload(){
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function(){
+ spaceghost.fill( spaceghost.selectors.tools.general.form, uploadInfo, false );
+
+ // the following throws:
+ // [error] [remote] Failed dispatching clickmouse event on xpath selector: //input[@value="Execute"]:
+ // PageError: TypeError: 'undefined' is not a function (evaluating '$(spaceghost).formSerialize()')
+ // ...and yet the upload still seems to work
+ spaceghost.click( xpath( spaceghost.selectors.tools.general.executeButton_xpath ) );
+ });
+ });
+
+ // debugging
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function afterUpload(){
+ var messageInfo = spaceghost.elementInfoOrNull( spaceghost.selectors.messages.all );
+ spaceghost.debug( 'post upload message:\n' + spaceghost.jsonStr( messageInfo ) );
+ });
+};
+
+/** Uploads a file.
+ * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
+ */
+//Tools.prototype.uploadFile = function uploadFile( filepath ){
+// this._uploadFile( filepath );
+// this.then( function(){
+// this.withFrame( this.selectors.frames.main, function mainAfterUpload(){
+// var messageInfo = this.elementInfoOrNull( this.selectors.messages.all );
+// if( ( !messageInfo )
+// || ( messageInfo.attributes[ 'class' ] !== 'donemessagelarge' )
+// || ( messageInfo.text.indexOf( this.text.upload.success ) === -1 ) ){
+// throw new GalaxyError( 'UploadError: ' + this.jsonStr( messageInfo ) );
+// }
+// });
+// });
+// return this;
+//};
+
+/** Parses the hid and name of a newly uploaded file from the tool execution donemessagelarge
+ * @param {String} doneMsgText the text extracted from the donemessagelarge after a tool execution
+ */
+Tools.prototype._parseDoneMessageForTool = function parseDoneMessageForTool( doneMsgText ){
+ //TODO: test on non-upload
+ var executionInfo = {};
+ var textMatch = doneMsgText.match( /added to the queue:\n\n(\d+)\: (.*)\n/m );
+ if( textMatch ){
+ if( textMatch.length > 1 ){
+ executionInfo.hid = parseInt( textMatch[1], 10 );
+ }
+ if( textMatch.length > 2 ){
+ executionInfo.name = textMatch[2];
+ }
+ executionInfo.name = textMatch[2];
+ }
+ return executionInfo;
+};
+
+// ------------------------------------------------------------------- get avail. tools
+// list available tools
+//spaceghost.then( function(){
+// spaceghost.withFrame( 'galaxy_tools', function(){
+// //var availableTools = this.fetchText( 'a.tool-link' );
+//
+// var availableTools = this.evaluate( function(){
+// //var toolTitles = __utils__.findAll( 'div.toolTitle' );
+// //return Array.prototype.map.call( toolTitles, function( e ){
+// // //return e.innerHtml;
+// // return e.textContent || e.innerText;
+// //}).join( '\n' );
+//
+// var toolLinks = __utils__.findAll( 'a.tool-link' );
+// return Array.prototype.map.call( toolLinks, function( e ){
+// //return e.innerHtml;
+// return e.textContent || e.innerText;
+// }).join( '\n' );
+// });
+// this.debug( 'availableTools: ' + availableTools );
+// });
+//});
+
+// =================================================================== API (external)
+/** get filename from filepath
+ * @param {String} filepath (POSIX) filepath
+ * @returns {String} filename part of filepath
+ */
+Tools.prototype.filenameFromFilepath = function filenameFromFilepath( filepath ){
+ var lastSepIndex = filepath.lastIndexOf( '/' );
+ if( lastSepIndex !== -1 ){
+ return filepath.slice( lastSepIndex + 1 );
+ }
+ return filepath;
+};
+
+/** Wait for the hda with given id to move into the given state.
+ * callback function will be passed an uploadInfo object in the form:
+ * filepath: the filepath of the uploaded file
+ * filename: the filename of the uploaded file
+ * hid: the hid of the uploaded file hda in the current history
+ * name: the name of the uploaded file hda
+ * hdaElement: the hda DOM (casperjs form) element info object (see Casper#getElementInfo)
+ * @param {String} filepath (POSIX) filepath
+ * @param {Function} callback callback function called after hda moves into ok state (will be passed uploadInfo)
+ * @param {Integer} timeoutAfterMs milliseconds to wait before timing out (defaults to options.defaultUploadWait)
+ */
+Tools.prototype.uploadFile = function uploadFile( filepath, callback, timeoutAfterMs ){
+ timeoutAfterMs = timeoutAfterMs || this.options.defaultUploadWait;
+ var spaceghost = this.spaceghost,
+ filename = this.filenameFromFilepath( filepath ),
+ uploadInfo = {};
+
+ // precondition: filepath is relative to scriptDir
+ filepath = spaceghost.options.scriptDir + '/' + filepath;
+
+ // upload the file erroring if a done message is not displayed, aggregate info about upload
+ spaceghost.info( 'uploading file: ' + filepath + ' (timeout after ' + timeoutAfterMs + ')' );
+ this._uploadFile( filepath );
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function toolExecuted(){
+ spaceghost.debug( 'checking for done message' );
+ var doneElementInfo = spaceghost.elementInfoOrNull( spaceghost.selectors.messages.donelarge );
+ if( !doneElementInfo ){
+ throw new spaceghost.GalaxyError( 'Upload Error: no done message uploading "' + filepath + '"' );
+ }
+ spaceghost.debug( 'doneElementInfo: ' + spaceghost.jsonStr( doneElementInfo ) );
+ // grab the hid and uploaded hda name from the done message
+ uploadInfo = spaceghost.tools._parseDoneMessageForTool( doneElementInfo.text );
+ uploadInfo.filename = filename;
+ uploadInfo.filepath = filepath;
+ spaceghost.debug( 'uploadInfo: ' + spaceghost.jsonStr( uploadInfo ) );
+ });
+
+ // the hpanel should refresh and display the uploading file, wait for that to go into the ok state
+ // throw if uploaded HDA doesn't appear, or it doesn't move to 'ok' after allotted time
+ spaceghost.then( function getNewHda(){
+ spaceghost.debug( 'beginning wait for upload file\'s ok state' );
+ // get the hda view DOM element from the upload name and hid
+ spaceghost.withFrame( spaceghost.selectors.frames.history, function(){
+ var hdaInfo = spaceghost.historypanel.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
+ if( !hdaInfo ){
+ throw new spaceghost.GalaxyError( 'Upload Error: uploaded file HDA not found: '
+ + uploadInfo.hid + ', ' + uploadInfo.name );
+ }
+ spaceghost.debug( 'hdaInfo: ' + spaceghost.jsonStr( hdaInfo ) );
+ uploadInfo.hdaElement = hdaInfo;
+ // uploadInfo now has filepath, filename, name, hid, and hdaElement
+ });
+
+ spaceghost.then( function waitForOk(){
+ spaceghost.debug( 'beginning wait for upload file\'s ok state' );
+
+ // currently best way to get hda state is using the historyItem-<state> class of the historyItemWrapper
+ var hdaStateClass = uploadInfo.hdaElement.attributes[ 'class' ].match( /historyItem\-(\w+)/ )[0];
+ if( hdaStateClass !== 'historyItem-ok' ){
+
+ spaceghost.historypanel.waitForHdaState( '#' + uploadInfo.hdaElement.attributes.id, 'ok',
+ function whenInStateFn( hdaInfo ){
+ // refresh hdaElement info
+ uploadInfo.hdaElement = hdaInfo;
+ callback.call( spaceghost, uploadInfo );
+
+ }, function timeoutFn( hdaInfo ){
+ var finalClass = (( hdaInfo )?( hdaInfo.attributes[ 'class' ] ):( undefined ));
+ spaceghost.debug( 'final classes: ' + finalClass );
+ throw new spaceghost.GalaxyError( 'Upload Error: timeout waiting for ok state: '
+ + '"' + uploadInfo.hid + ': ' + uploadInfo.name + '"'
+ + ' (waited ' + timeoutAfterMs + ' ms)' );
+
+ }, timeoutAfterMs );
+ }
+ });
+ });
+ return spaceghost;
+};
+//TODO: upload via url
+//TODO: upload by textarea
+
+
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/modules/user.js
--- /dev/null
+++ b/test/casperjs/modules/user.js
@@ -0,0 +1,209 @@
+// =================================================================== module object, exports
+/** Creates a new user module object.
+ * @exported
+ */
+exports.create = function createUser( spaceghost ){
+ return new User( spaceghost );
+};
+
+/** User object constructor.
+ * @param {SpaceGhost} spaceghost a spaceghost instance
+ */
+var User = function User( spaceghost ){
+ //??: circ ref?
+ this.spaceghost = spaceghost;
+};
+exports.User = User;
+
+User.prototype.toString = function toString(){
+ return this.spaceghost + '.User';
+};
+
+
+// =================================================================== INTERNAL
+/** Tests registering a new user on the Galaxy instance by submitting the registration form.
+ * NOTE: this version does NOT throw an error on a bad registration.
+ * It is meant for testing the registration functionality and, therefore, is marked as private.
+ * Other tests should use registerUser
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @param {String} username the users ...username! (optional: will use 1st part of email)
+ * @param {String} confirm password confirmation (optional: defaults to password)
+ */
+User.prototype._submitRegistration = function _submitRegistration( email, password, username, confirm ){
+ var spaceghost = this.spaceghost,
+ userInfo = {
+ email : email,
+ password: password,
+ // default username to first part of email
+ username:( !username && email.match( /^\w*/ ) )?( email.match( /^\w*/ ) ):( username ),
+ // default confirm: duplicate of password
+ confirm : ( confirm !== undefined )?( confirm ):( password )
+ };
+
+ spaceghost.debug( 'registering user:\n' + spaceghost.jsonStr( userInfo ) );
+ spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ spaceghost.clickLabel( spaceghost.labels.masthead.menus.user );
+ spaceghost.clickLabel( spaceghost.labels.masthead.userMenu.register );
+
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainBeforeRegister(){
+ spaceghost.debug( 'submitting registration... ' + spaceghost.getCurrentUrl() );
+ spaceghost.fill( spaceghost.selectors.registrationPage.form, userInfo, false );
+ // need manual submit (not a normal html form)
+ spaceghost.click( xpath( spaceghost.selectors.registrationPage.submit_xpath ) );
+ });
+
+ //// debugging
+ //spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterRegister(){
+ // var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ // spaceghost.debug( 'post registration message:\n' + spaceghost.jsonStr( messageInfo ) );
+ //});
+ });
+};
+
+/** Tests logging in a user on the Galaxy instance by submitting the login form.
+ * NOTE: this version does NOT throw an error on a bad login.
+ * It is meant for testing the login functionality and, therefore, is marked as private.
+ * Other tests should use login
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ */
+User.prototype._submitLogin = function logoutUser( email, password ){
+ var spaceghost = this.spaceghost,
+ loginInfo = {
+ //NOTE: keys are used as name selectors in the fill fn - must match the names of the inputs
+ email: email,
+ password: password
+ };
+
+ spaceghost.thenOpen( spaceghost.baseUrl, function(){
+
+ spaceghost.clickLabel( spaceghost.labels.masthead.menus.user );
+ spaceghost.clickLabel( spaceghost.labels.masthead.userMenu.login );
+
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainBeforeLogin(){
+ spaceghost.debug( '(' + spaceghost.getCurrentUrl() + ') logging in user:\n'
+ + spaceghost.jsonStr( loginInfo ) );
+ spaceghost.fill( spaceghost.selectors.loginPage.form, loginInfo, false );
+ spaceghost.click( xpath( spaceghost.selectors.loginPage.submit_xpath ) );
+ });
+
+ //// debugging
+ //spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterLogin(){
+ // //TODO: prob. could use a more generalized form of this for url breakdown/checking
+ // if( spaceghost.getCurrentUrl().search( spaceghost.selectors.loginPage.url_regex ) != -1 ){
+ // var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ // spaceghost.debug( 'post login message:\n' + spaceghost.jsonStr( messageInfo ) );
+ // }
+ //});
+ });
+};
+
+
+// =================================================================== API (external)
+/** Register a new user on the Galaxy instance.
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @param {String} username the users ...username! (optional: will use 1st part of email)
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.registerUser = function registerUser( email, password, username ){
+ var spaceghost = this.spaceghost;
+ this._submitRegistration( email, password, username );
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterRegister(){
+ var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ spaceghost.debug( 'post registration message:\n' + this.jsonStr( messageInfo ) );
+
+ if( messageInfo.attributes[ 'class' ] === 'errormessage' ){
+ throw new spaceghost.GalaxyError( 'RegistrationError: ' + messageInfo.html );
+ }
+ });
+ });
+ return spaceghost;
+};
+
+/** Logs in a user. Throws error on bad log in.
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.login = function login( email, password ){
+ var spaceghost = this.spaceghost;
+ this._submitLogin( email, password );
+ spaceghost.then( function(){
+ spaceghost.withFrame( spaceghost.selectors.frames.main, function mainAfterLogin(){
+ if( spaceghost.getCurrentUrl().search( spaceghost.selectors.loginPage.url_regex ) != -1 ){
+ var messageInfo = spaceghost.getElementInfo( spaceghost.selectors.messages.all );
+ if( messageInfo && messageInfo.attributes[ 'class' ] === 'errormessage' ){
+ throw new spaceghost.GalaxyError( 'LoginError: ' + messageInfo.html );
+ }
+ }
+ });
+ if( spaceghost.user.loggedInAs() === email ){
+ spaceghost.debug( 'logged in as ' + email );
+ }
+ });
+ return spaceghost;
+};
+
+/** Fetch the email of the currently logged in user (or '' if not logged in)
+ * @returns {String} email of currently logged in user or '' if no one logged in
+ */
+User.prototype.loggedInAs = function loggedInAs(){
+ var spaceghost = this.spaceghost,
+ userEmail = '';
+ try {
+ var loggedInInfo = spaceghost.getElementInfo( xpath( spaceghost.selectors.masthead.userMenu.userEmail_xpath ) );
+ userEmail = loggedInInfo.text;
+ } catch( err ){
+ spaceghost.error( err );
+ }
+ //console.debug( 'loggedInInfo:', spaceghost.jsonStr( loggedInInfo ) );
+ return userEmail;
+};
+
+/** Log out the current user
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.logout = function logoutUser(){
+ var spaceghost = this.spaceghost;
+ spaceghost.thenOpen( spaceghost.baseUrl, function(){
+ //TODO: handle already logged out
+ spaceghost.clickLabel( spaceghost.labels.masthead.menus.user );
+ spaceghost.clickLabel( spaceghost.labels.masthead.userMenu.logout );
+ });
+ return spaceghost;
+};
+
+/** Attempts to login a user - if that raises an error (LoginError), register the user
+ * @param {String} email the users email address
+ * @param {String} password the users password
+ * @param {String} username the users ...username! (optional: will use 1st part of email)
+ * @returns {SpaceGhost} the spaceghost instance (for chaining)
+ */
+User.prototype.loginOrRegisterUser = function loginOrRegisterUser( email, password, username ){
+ var spaceghost = this.spaceghost;
+ // attempt a login, if that fails - register
+ spaceghost.tryStepsCatch( function tryToLogin(){
+ spaceghost.open( spaceghost.baseUrl ).user.login( email, password );
+
+ }, function failedLoginRegister(){
+ spaceghost.open( spaceghost.baseUrl ).user.registerUser( email, password, username );
+ });
+ return spaceghost;
+};
+
+/** Gets a psuedo-random (unique?) email based on the time stamp.
+ * Helpful for testing registration.
+ * @param {String} username email user (defaults to 'test')
+ * @param {String} domain email domain (defaults to 'test.test')
+ * @returns {String} new email as string
+ */
+User.prototype.getRandomEmail = function getRandomEmail( username, domain ){
+ username = username || 'test';
+ domain = domain || 'test.test';
+ return username + Date.now() + '@' + domain;
+};
+
+
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/registration-tests.js
--- a/test/casperjs/registration-tests.js
+++ b/test/casperjs/registration-tests.js
@@ -24,7 +24,6 @@
phantom.exit( 1 );
}
-
// ===================================================================
/* TODO:
move selectors and assertText strings into global object for easier editing
@@ -33,7 +32,7 @@
*/
// =================================================================== globals and helpers
-var email = spaceghost.getRandomEmail(),
+var email = spaceghost.user.getRandomEmail(),
password = '123456',
confirm = password,
username = 'test' + Date.now();
@@ -60,29 +59,27 @@
// ------------------------------------------------------------------- register a new user
spaceghost.then( function(){
this.test.comment( 'registering user: ' + email );
- this._submitUserRegistration( email, password, username, confirm );
+ this.user._submitRegistration( email, password, username, confirm );
});
spaceghost.thenOpen( spaceghost.baseUrl, function(){
this.clickLabel( 'User' );
this.test.assertSelectorHasText( 'a #user-email', email, '#user-email === ' + email );
});
-
// ------------------------------------------------------------------- log out that user
spaceghost.then( function(){
this.test.comment( 'logging out user: ' + email );
- this.logout();
+ this.user.logout();
});
spaceghost.then( function(){
this.debug( 'email:' + this.getElementInfo( 'a #user-email' ).html );
this.test.assert( !this.getElementInfo( 'a #user-email' ).html, '#user-email is empty' );
});
-
// ------------------------------------------------------------------- bad user registrations
spaceghost.then( function(){
this.test.comment( 'attempting to re-register user: ' + email );
- this._submitUserRegistration( email, password, username, confirm );
+ this.user._submitRegistration( email, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'User with that email already exists' );
@@ -93,7 +90,7 @@
spaceghost.each( badEmails, function( self, badEmail ){
self.then( function(){
this.test.comment( 'attempting bad email: ' + badEmail );
- this._submitUserRegistration( badEmail, password, username, confirm );
+ this.user._submitRegistration( badEmail, password, username, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Enter a real email address' );
@@ -105,7 +102,7 @@
spaceghost.each( badPasswords, function( self, badPassword ){
self.then( function(){
this.test.comment( 'attempting bad password: ' + badPassword );
- this._submitUserRegistration( spaceghost.getRandomEmail(), badPassword, username, confirm );
+ this.user._submitRegistration( spaceghost.user.getRandomEmail(), badPassword, username, confirm );
});
self.then(function(){
this.assertErrorMessage( 'Use a password of at least 6 characters' );
@@ -117,7 +114,7 @@
spaceghost.each( badConfirms, function( self, badConfirm ){
self.then( function(){
this.test.comment( 'attempting bad password confirmation: ' + badConfirm );
- this._submitUserRegistration( spaceghost.getRandomEmail(), password, username, badConfirm );
+ this.user._submitRegistration( spaceghost.user.getRandomEmail(), password, username, badConfirm );
});
self.then(function(){
this.assertErrorMessage( 'Passwords do not match' );
@@ -128,10 +125,10 @@
//NOTE: that short username errors only show AFTER checking for existing/valid emails
// so: we need to generate new emails for each one
spaceghost.then( function(){
- var newEmail = spaceghost.getRandomEmail(),
+ var newEmail = spaceghost.user.getRandomEmail(),
badUsername = 'bob';
this.test.comment( 'attempting short username: ' + badUsername );
- this._submitUserRegistration( newEmail, password, badUsername, confirm );
+ this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name must be at least 4 characters in length' );
@@ -141,9 +138,9 @@
var badUsernames = [ 'BOBERT', 'Robert Paulson', 'bobert!', 'bob_dobbs' ];
spaceghost.each( badUsernames, function( self, badUsername ){
self.then( function(){
- var newEmail = spaceghost.getRandomEmail();
+ var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting bad username: ' + badUsername );
- this._submitUserRegistration( newEmail, password, badUsername, confirm );
+ this.user._submitRegistration( newEmail, password, badUsername, confirm );
});
self.then(function(){
this.assertErrorMessage( "Public name must contain only lower-case letters, numbers and '-'" );
@@ -152,28 +149,29 @@
// ...and the name can't be used already
spaceghost.then( function(){
- var newEmail = spaceghost.getRandomEmail();
+ var newEmail = spaceghost.user.getRandomEmail();
this.test.comment( 'attempting previously used username with new user: ' + newEmail );
- this._submitUserRegistration( newEmail, password, username, confirm );
+ this.user._submitRegistration( newEmail, password, username, confirm );
});
spaceghost.then(function(){
this.assertErrorMessage( 'Public name is taken; please choose another' );
});
-// ------------------------------------------------------------------- test the tests
+// ------------------------------------------------------------------- test the convenience fns
// these versions are for conv. use in other tests, they should throw errors if used improperly
spaceghost.then( function(){
this.assertStepsRaise( 'GalaxyError: RegistrationError', function(){
this.then( function(){
this.test.comment( 'testing (js) error thrown on bad email' );
- this.registerUser( '@internet', '123456', 'ignobel' );
+ this.user.registerUser( '@internet', '123456', 'ignobel' );
});
});
});
spaceghost.then( function(){
- this.logout();
+ //??: necessary?
+ this.user.logout();
});
// ===================================================================
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/spaceghost.js
--- a/test/casperjs/spaceghost.js
+++ b/test/casperjs/spaceghost.js
@@ -72,6 +72,14 @@
//console.debug( 'CasperError:' + CasperError );
+// ------------------------------------------------------------------- included libs
+//??: can we require underscore, etc. from the ../../static/scripts/lib?
+// yep!
+//var _ = require( '../../static/scripts/libs/underscore' );
+//var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
+//console.debug( JSON.stringify( _.pluck(stooges, 'name') ) );
+//exports._ = _;
+
// ------------------------------------------------------------------- error types
PageError.prototype = new CasperError();
PageError.prototype.constructor = CasperError;
@@ -79,6 +87,7 @@
CasperError.apply( this, arguments );
this.name = "PageError";
}
+SpaceGhost.prototype.PageError = PageError;
GalaxyError.prototype = new CasperError();
GalaxyError.prototype.constructor = CasperError;
@@ -86,6 +95,7 @@
CasperError.apply( this, arguments );
this.name = "GalaxyError";
}
+SpaceGhost.prototype.GalaxyError = GalaxyError;
AlertError.prototype = new CasperError();
AlertError.prototype.constructor = CasperError;
@@ -93,11 +103,12 @@
CasperError.apply( this, arguments );
this.name = "AlertError";
}
+SpaceGhost.prototype.AlertError = AlertError;
// =================================================================== METHODS / OVERRIDES
// ------------------------------------------------------------------- set up
/** More initialization: cli, event handlers, etc.
- * @param {Object} options option hash
+ * @param {Object} options option hash
*/
SpaceGhost.prototype.init = function init( options ){
//console.debug( 'init, options:', JSON.stringify( options, null, 2 ) );
@@ -122,6 +133,8 @@
].concat( this.options.clientScripts );
this.debug( 'clientScripts:\n' + this.jsonStr( this.options.clientScripts ) );
+ this._loadModules();
+
};
/** Allow CLI arguments to set options if the proper option name is used.
@@ -371,7 +384,16 @@
};
-// ------------------------------------------------------------------- page control
+// ------------------------------------------------------------------- sub modules
+/** Load sub modules (similar to casperjs.test)
+ */
+SpaceGhost.prototype._loadModules = function _loadModules(){
+ this.user = require( this.options.scriptDir + 'modules/user' ).create( this );
+ this.tools = require( this.options.scriptDir + 'modules/tools' ).create( this );
+ this.historypanel = require( this.options.scriptDir + 'modules/historypanel' ).create( this );
+};
+
+// =================================================================== PAGE CONTROL
/** An override of casper.open specifically for Galaxy.
* (Currently only used to change language headers)
*/
@@ -530,327 +552,8 @@
};
+
// =================================================================== GALAXY CONVENIENCE
-/** Gets a psuedo-random (unique?) email based on the time stamp.
- * Helpful for testing registration.
- * @param {String} username email user (defaults to 'test')
- * @param {String} domain email domain (defaults to 'test.test')
- */
-SpaceGhost.prototype.getRandomEmail = function getRandomEmail( username, domain ){
- username = username || 'test';
- domain = domain || 'test.test';
- return username + Date.now() + '@' + domain;
-};
-
-
-/** Tests registering a new user on the Galaxy instance by submitting the registration form.
- * NOTE: this version does NOT throw an error on a bad registration.
- * It is meant for testing the registration functionality and, therefore, is marked as private.
- * Other tests should use registerUser
- * @param {String} email the users email address
- * @param {String} password the users password
- * @param {String} username the users ...username! (optional: will use 1st part of email)
- * @param {String} confirm password confirmation (optional: defaults to password)
- */
-SpaceGhost.prototype._submitUserRegistration = function _submitUserRegistration( email, password, username, confirm ){
- var userInfo = {
- email : email,
- password: password,
- // default username to first part of email
- username:( !username && email.match( /^\w*/ ) )?( email.match( /^\w*/ ) ):( username ),
- // default confirm duplicate of password
- confirm : ( confirm !== undefined )?( confirm ):( password )
- };
- this.debug( 'registering user:\n' + this.jsonStr( userInfo ) );
-
- this.thenOpen( this.baseUrl, function(){
-
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.register );
-
- this.withFrame( this.selectors.frames.main, function mainBeforeRegister(){
- this.debug( 'submitting registration... ' + this.getCurrentUrl() );
- this.fill( this.selectors.registrationPage.form, userInfo, false );
- // need manual up
- this.click( xpath( this.selectors.registrationPage.submit_xpath ) );
- });
-
- this.withFrame( this.selectors.frames.main, function mainAfterRegister(){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- this.debug( 'post registration message:\n' + this.jsonStr( messageInfo ) );
- });
- });
-};
-
-/** Register a new user on the Galaxy instance.
- * @param {String} email the users email address
- * @param {String} password the users password
- * @param {String} username the users ...username! (optional: will use 1st part of email)
- */
-SpaceGhost.prototype.registerUser = function registerUser( email, password, username ){
- this._submitUserRegistration( email, password, username );
- this.then( function(){
- this.withFrame( this.selectors.frames.main, function mainAfterRegister(){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- this.debug( 'post registration message:\n' + this.jsonStr( messageInfo ) );
-
- if( messageInfo.attributes[ 'class' ] === 'errormessage' ){
- throw new GalaxyError( 'RegistrationError: ' + messageInfo.html );
- }
- });
- });
- return this;
-};
-
-/** Log out the current user
- */
-SpaceGhost.prototype.logout = function logoutUser(){
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.login );
- this.thenOpen( this.baseUrl, function(){
- //TODO: handle already logged out
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.logout );
- });
-};
-
-/** Tests logging in a user on the Galaxy instance by submitting the login form.
- * NOTE: this version does NOT throw an error on a bad login.
- * It is meant for testing the login functionality and, therefore, is marked as private.
- * Other tests should use login
- * @param {String} email the users email address
- * @param {String} password the users password
- */
-SpaceGhost.prototype._submitLogin = function logoutUser( email, password ){
- var loginInfo = {
- //NOTE: keys are used as name selectors in the fill fn - must match the names of the inputs
- email: email,
- password: password
- };
-
- this.thenOpen( this.baseUrl, function(){
-
- this.clickLabel( this.labels.masthead.menus.user );
- this.clickLabel( this.labels.masthead.userMenu.login );
-
- this.withFrame( this.selectors.frames.main, function mainBeforeLogin(){
- this.debug( '(' + this.getCurrentUrl() + ') logging in user:\n' + this.jsonStr( loginInfo ) );
- this.fill( this.selectors.loginPage.form, loginInfo, false );
- this.click( xpath( this.selectors.loginPage.submit_xpath ) );
- });
- this.withFrame( this.selectors.frames.main, function mainAfterLogin(){
- //TODO: prob. could use a more generalized form of this for url breakdown/checking
- if( this.getCurrentUrl().search( this.selectors.loginPage.url_regex ) != -1 ){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- this.debug( 'post login message:\n' + this.jsonStr( messageInfo ) );
- }
- });
- });
-};
-
-/** Logs in a user. Throws error on bad log in.
- * @param {String} email the users email address
- * @param {String} password the users password
- */
-SpaceGhost.prototype.login = function login( email, password ){
- this._submitLogin( email, password );
- this.then( function(){
- this.withFrame( this.selectors.frames.main, function mainAfterLogin(){
- if( this.getCurrentUrl().search( this.selectors.loginPage.url_regex ) != -1 ){
- var messageInfo = this.getElementInfo( this.selectors.messages.all );
- if( messageInfo && messageInfo.attributes[ 'class' ] === 'errormessage' ){
- throw new GalaxyError( 'LoginError: ' + messageInfo.html );
- }
- }
- });
- if( this.loggedInAs() === email ){
- this.debug( 'logged in as ' + email );
- }
- });
- return this;
-};
-
-/** Fetch the email of the currently logged in user (or '' if not logged in)
- * @returns {String} email of currently logged in user or '' if no one logged in
- */
-SpaceGhost.prototype.loggedInAs = function loggedInAs(){
- var userEmail = '';
- try {
- var loggedInInfo = this.getElementInfo( xpath( this.selectors.masthead.userMenu.userEmail_xpath ) );
- userEmail = loggedInInfo.text;
- } catch( err ){
- this.error( err );
- }
- //console.debug( 'loggedInInfo:', this.jsonStr( loggedInInfo ) );
- return userEmail;
-};
-
-/** Attempts to login a user - if that raises an error (LoginError), register the user
- * @param {String} email the users email address
- * @param {String} password the users password
- * @param {String} username the users ...username! (optional: will use 1st part of email)
- */
-SpaceGhost.prototype.loginOrRegisterUser = function loginOrRegisterUser( email, password, username ){
- // attempt a login, if that fails - register
- this.tryStepsCatch( function tryToLogin(){
- this.open( this.baseUrl ).login( email, password );
-
- }, function failedLoginRegister(){
- this.open( this.baseUrl ).registerUser( email, password, username );
- });
- return this;
-};
-
-/** Tests uploading a file.
- * NOTE: this version does NOT throw an error on a bad upload.
- * It is meant for testing the upload functionality and, therefore, is marked as private.
- * Other tests should use uploadFile
- * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
- */
-SpaceGhost.prototype._uploadFile = function _uploadFile( filepath ){
- var uploadInfo = {};
- //TODO: check file exists using phantom.fs
- //TODO: pull from test data
- uploadInfo[ this.tools.upload.fileInput ] = filepath;
- this.debug( 'uploading file: ' + filepath );
-
- spaceghost.then( function(){
- spaceghost.withFrame( this.selectors.frames.tools, function(){
- this.clickLabel( this.tools.upload.panelLabel );
- });
- });
-
- this.then( function beginUpload(){
- spaceghost.withFrame( this.selectors.frames.main, function(){
- this.fill( this.tools.general.form, uploadInfo, false );
-
- // the following throws:
- // [error] [remote] Failed dispatching clickmouse event on xpath selector: //input[@value="Execute"]:
- // PageError: TypeError: 'undefined' is not a function (evaluating '$(this).formSerialize()')
-
- // ...and yet the upload still seems to work
- this.click( xpath( this.tools.general.executeButton_xpath ) );
- });
- });
- this.withFrame( this.selectors.frames.main, function afterUpload(){
- var messageInfo = this.elementInfoOrNull( this.selectors.messages.all );
- this.debug( 'post upload message:\n' + this.jsonStr( messageInfo ) );
- });
-};
-
-/** Uploads a file.
- * @param {String} filepath the local filesystem path of the file to upload (absolute (?))
- */
-SpaceGhost.prototype.uploadFile = function uploadFile( filepath ){
- this._uploadFile( filepath );
- this.then( function(){
- this.withFrame( this.selectors.frames.main, function mainAfterUpload(){
- var messageInfo = this.elementInfoOrNull( this.selectors.messages.all );
- if( ( !messageInfo )
- || ( messageInfo.attributes[ 'class' ] !== 'donemessagelarge' )
- || ( messageInfo.text.indexOf( this.text.upload.success ) === -1 ) ){
- throw new GalaxyError( 'UploadError: ' + this.jsonStr( messageInfo ) );
- }
- });
- });
- return this;
-};
-
-/** Parses the hid and name of a newly uploaded file from the tool execution donemessagelarge
- * @param {String} doneMsgText the text extracted from the donemessagelarge after a tool execution
- */
-SpaceGhost.prototype.parseDoneMessageForTool = function parseDoneMessageForTool( doneMsgText ){
- //TODO: test on non-upload
- var executionInfo = {};
- var textMatch = doneMsgText.match( /added to the queue:\n\n(\d+)\: (.*)\n/m );
- if( textMatch ){
- if( textMatch.length > 1 ){
- executionInfo.hid = parseInt( textMatch[1], 10 );
- }
- if( textMatch.length > 2 ){
- executionInfo.name = textMatch[2];
- }
- executionInfo.name = textMatch[2];
- }
- return executionInfo;
-};
-
-/** Find the casper element info of the hda wrapper given the hda title and hid.
- * NOTE: if more than one is found, will return the first found.
- * precondition: you should wrap this with withFrame( 'galaxy_history' ) :(
- * @param {String} title the title of the hda
- * @param {Int} hid (optional) the hid of the hda to look for
- * @returns {Object|null} ElementInfo of the historyItemWrapper found, null if not found
- */
-SpaceGhost.prototype.hdaElementInfoByTitle = function hdaElementInfoByTitle( title, hid ){
- var spaceghost = this,
- titleContains = ( hid !== undefined )?( hid + ': ' + title ):( title ),
- wrapperInfo = null;
-
- wrapperInfo = spaceghost.evaluate( function( titleContains ){
- // find the title, then the wrapper (2 containers up)
- var $title = $( '.historyItemTitle:contains(' + titleContains + ')' );
- var $wrapper = $title.parent().parent();
- return (( $wrapper.attr( 'id' ) )?( __utils__.getElementInfo( '#' + $wrapper.attr( 'id' ) )):( null ));
- }, titleContains );
-
- return wrapperInfo;
-};
-
-/** Wait for the hda with given id to move into the given state.
- * @param {String} hdaSelector selector for hda (should be historyItemWrapper)
- * @param {String} finalState hda state to wait for (e.g. 'ok', 'error', 'running', 'queued', etc.)
- * @param {Function} whenInStateFn called when hda goes into finalState
- * @param {Function} timeoutFn called when maxWaitMs have passed without the desired state
- * @param {Int} maxWaitMs number of milliseconds to wait before timing out (defaults to options.waitTimeout)
- */
-SpaceGhost.prototype.waitForHdaState = function waitForHdaState( hdaSelector, finalState,
- whenInStateFn, timeoutFn, maxWaitMs ){
- //TODO:?? explicitly a historyWrapper id?
- maxWaitMs = maxWaitMs || this.options.waitTimeout;
- var finalStateClass = '.historyItem-' + finalState;
-
- this.then( function(){
- this.withFrame( this.selectors.frames.history, function(){
- // wait for state, preferrably debugging intermediate states
- var spaceghost = this,
-
- // we need a larger timeout for these - it can take a bit
- oldWaitTimeout = this.options.waitTimeout,
-
- // output some progress indicator within the test (debug)
- progressIntervalId = setInterval( function progress(){
- var state = spaceghost.evaluate( function( hdaSelector ){
- var $wrapperClasses = $( hdaSelector ).attr( 'class' );
- return $wrapperClasses.match( /historyItem\-(\w+)/ )[1];
- }, hdaSelector );
- spaceghost.debug( hdaSelector + ': ' + state );
- }, 1000 ),
-
- // when done, close down the progress reporter and reset the wait timeout to what it was
- finallyFn = function(){
- spaceghost.options.waitTimeout = oldWaitTimeout;
- clearInterval( progressIntervalId );
- };
-
- this.options.waitTimeout = maxWaitMs;
- this.waitForSelector( hdaSelector + finalStateClass, function _whenInState(){
- this.debug( 'HDA now in state ' + finalState + ':\n'
- + this.jsonStr( this.elementInfoOrNull( hdaSelector ) ) );
- whenInStateFn.call( this );
- finallyFn();
-
- }, function timeout(){
- this.debug( 'timed out:\n'
- + this.jsonStr( this.elementInfoOrNull( hdaSelector ) ) );
- timeoutFn.call( this );
- finallyFn();
- }
- );
- });
- });
-};
-
// =================================================================== MISCELAIN
/** Send message to stderr
*/
@@ -958,9 +661,10 @@
history : 'galaxy_history'
},
messages : {
- all : '[class*="message"]',
+ all : '[class*="message"]',
error : '.errormessage',
- done : '.donemessage'
+ done : '.donemessage',
+ donelarge : '.donemessagelarge'
},
loginPage : {
form : 'form#login',
@@ -970,6 +674,15 @@
registrationPage : {
form : 'form#registration',
submit_xpath : "//input[@value='Submit']"
+ },
+ tools : {
+ general : {
+ form : 'form#tool_form',
+ executeButton_xpath : '//input[@value="Execute"]'
+ },
+ upload : {
+ fileInput : 'files_0|file_data' // is this general?
+ }
}
};
@@ -983,17 +696,11 @@
login : 'Login',
logout : 'Logout'
}
- }
-};
-
-SpaceGhost.prototype.tools = {
- general : {
- form : 'form#tool_form',
- executeButton_xpath : '//input[@value="Execute"]'
},
- upload : {
- panelLabel : 'Upload File',
- fileInput : 'files_0|file_data' // is this general?
+ tools : {
+ upload : {
+ panelLabel : 'Upload File'
+ }
}
};
@@ -1007,6 +714,12 @@
}
};
+SpaceGhost.prototype.loadJSONFile = function loadJSONFile( filepath ){
+ //precondition: filepath is relative to script dir
+ filepath = this.options.scriptDir + filepath;
+ return JSON.parse( require( 'fs' ).read( filepath ) );
+};
+
// =================================================================== EXPORTS
/**
*/
@@ -1021,10 +734,3 @@
return new SpaceGhost(options);
};
-// ------------------------------------------------------------------- included libs
-//??: can we require underscore, etc. from the ../../static/scripts/lib?
-// yep!
-//var _ = require( '../../static/scripts/libs/underscore' );
-//var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];
-//console.debug( JSON.stringify( _.pluck(stooges, 'name') ) );
-//exports._ = _;
diff -r e45b9ade65b1a27ded8d55a3003b153035551148 -r 973b8d73409ff4ebc33cc3ff6faf172417fb1978 test/casperjs/upload-tests.js
--- a/test/casperjs/upload-tests.js
+++ b/test/casperjs/upload-tests.js
@@ -32,7 +32,7 @@
general tool execution
*/
// =================================================================== globals and helpers
-var email = spaceghost.getRandomEmail(),
+var email = spaceghost.user.getRandomEmail(),
password = '123456';
if( spaceghost.fixtureData.testUser ){
email = spaceghost.fixtureData.testUser.email;
@@ -42,44 +42,22 @@
// =================================================================== TESTS
// ------------------------------------------------------------------- start a new user
-spaceghost.loginOrRegisterUser( email, password );
+spaceghost.user.loginOrRegisterUser( email, password );
//??: why is a reload needed here? If we don't, loggedInAs === '' ...
spaceghost.thenOpen( spaceghost.baseUrl, function(){
- var loggedInAs = spaceghost.loggedInAs();
+ var loggedInAs = spaceghost.user.loggedInAs();
this.test.assert( loggedInAs === email, 'loggedInAs() matches email: "' + loggedInAs + '"' );
});
-// ------------------------------------------------------------------- get avail. tools
-// list available tools
-//spaceghost.then( function(){
-// spaceghost.withFrame( 'galaxy_tools', function(){
-// //var availableTools = this.fetchText( 'a.tool-link' );
-//
-// var availableTools = this.evaluate( function(){
-// //var toolTitles = __utils__.findAll( 'div.toolTitle' );
-// //return Array.prototype.map.call( toolTitles, function( e ){
-// // //return e.innerHtml;
-// // return e.textContent || e.innerText;
-// //}).join( '\n' );
-//
-// var toolLinks = __utils__.findAll( 'a.tool-link' );
-// return Array.prototype.map.call( toolLinks, function( e ){
-// //return e.innerHtml;
-// return e.textContent || e.innerText;
-// }).join( '\n' );
-// });
-// this.debug( 'availableTools: ' + availableTools );
-// });
-//});
-// ------------------------------------------------------------------- upload from fs
-// test uploading from the filesystem
+// ------------------------------------------------------------------- long form
+// upload a file from the filesystem
var uploadInfo = {};
spaceghost.then( function(){
// strangely, this works with a non-existant file --> empty txt file
var filename = '1.sam';
var filepath = this.options.scriptDir + '/../../test-data/' + filename;
- this._uploadFile( filepath );
+ this.tools._uploadFile( filepath );
// when an upload begins successfully...
// 1. main should reload with a donemessagelarge
@@ -90,7 +68,7 @@
this.test.assert( doneElementInfo !== null,
"Found donemessagelarge after uploading file" );
- uploadInfo = this.parseDoneMessageForTool( doneElementInfo.text );
+ uploadInfo = this.tools._parseDoneMessageForTool( doneElementInfo.text );
this.test.assert( uploadInfo.hid >= 0,
'Found sensible hid from upload donemessagelarge: ' + uploadInfo.hid );
this.test.assert( uploadInfo.name === filename,
@@ -99,12 +77,12 @@
});
-// wait for upload to finish
+// move to the history panel and wait for upload to finish
spaceghost.then( function(){
var hdaInfo = null;
this.withFrame( 'galaxy_history', function(){
- hdaInfo = this.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
+ hdaInfo = this.historypanel.hdaElementInfoByTitle( uploadInfo.name, uploadInfo.hid );
this.debug( 'hda:\n' + this.jsonStr( hdaInfo ) );
});
@@ -113,7 +91,7 @@
//precondition: needs class
var hdaStateClass = hdaInfo.attributes[ 'class' ].match( /historyItem\-(\w+)/ )[0];
if( hdaStateClass !== 'historyItem-ok' ){
- this.waitForHdaState( '#' + hdaInfo.attributes.id, 'ok',
+ this.historypanel.waitForHdaState( '#' + hdaInfo.attributes.id, 'ok',
function whenInStateFn(){
this.test.assert( true, 'Upload completed successfully for: ' + uploadInfo.name );
@@ -126,6 +104,34 @@
});
});
+spaceghost.then( function(){
+ this.test.comment( 'testing convenience function' );
+ spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
+ this.test.assert( uploadInfo.hdaElement !== null, "Convenience function produced hda in ok state" );
+ });
+});
+
+/*
+//??: this error's AND waitFor()s THREE times - something to do with assertStepsRaise + waitFor
+spaceghost.then( function(){
+ this.test.comment( 'testing convenience function timeout error' );
+ this.assertStepsRaise( 'GalaxyError: Upload Error: timeout waiting', function(){
+ spaceghost.then( function(){
+ spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
+ this.test.fail( "Convenience function did not timeout!" );
+ }, 250 );
+ });
+ });
+});
+
+// this correctly errors
+spaceghost.then( function(){
+ spaceghost.tools.uploadFile( '../../test-data/1.sam', function( uploadInfo ){
+ this.test.fail( "Convenience function did not timeout!" );
+ }, 250 );
+});
+*/
+
// ===================================================================
spaceghost.run( function(){
this.test.done();
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/d5896e8a60fa/
changeset: d5896e8a60fa
branch: stable
user: inithello
date: 2013-02-19 18:29:29
summary: Fix for installing a repository that only contains a workflow, then importing that workflow to Galaxy.
affected #: 1 file
diff -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 -r d5896e8a60fa948f1713d4b5e30126a12a958679 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -740,8 +740,8 @@
repository = suc.get_tool_shed_repository_by_id( trans, repository_id )
changeset_revision = repository.changeset_revision
metadata = repository.metadata
- workflows = metadata[ 'workflows' ]
- tools_metadata = metadata[ 'tools' ]
+ workflows = metadata.get( 'workflows', [] )
+ tools_metadata = metadata.get( 'tools', [] )
workflow_dict = None
for workflow_data_tuple in workflows:
# The value of workflow_data_tuple is ( relative_path_to_workflow_file, exported_workflow_dict ).
https://bitbucket.org/galaxy/galaxy-central/commits/e45b9ade65b1/
changeset: e45b9ade65b1
user: inithello
date: 2013-02-19 18:29:29
summary: Fix for installing a repository that only contains a workflow, then importing that workflow to Galaxy.
affected #: 1 file
diff -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee -r e45b9ade65b1a27ded8d55a3003b153035551148 lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
--- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
+++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py
@@ -745,8 +745,8 @@
repository = suc.get_tool_shed_repository_by_id( trans, repository_id )
changeset_revision = repository.changeset_revision
metadata = repository.metadata
- workflows = metadata[ 'workflows' ]
- tools_metadata = metadata[ 'tools' ]
+ workflows = metadata.get( 'workflows', [] )
+ tools_metadata = metadata.get( 'tools', [] )
workflow_dict = None
for workflow_data_tuple in workflows:
# The value of workflow_data_tuple is ( relative_path_to_workflow_file, exported_workflow_dict ).
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/445b212b1c6d/
changeset: 445b212b1c6d
user: natefoo
date: 2013-02-19 17:30:29
summary: Fix the manage jobs admin interface broken by the removal of the manager. This necessitated removing the job lock feature, although it should return in a future release when we have handler communication outside the database.
affected #: 4 files
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -1690,7 +1690,7 @@
"""
Implements the JobQueue / JobStopQueue interface but does nothing
"""
- def put( self, *args ):
+ def put( self, *args, **kwargs ):
return
def put_stop( self, *args ):
return
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -493,7 +493,7 @@
.filter( ( model.Job.state == model.Job.states.DELETED_NEW ) \
& ( model.Job.handler == self.app.config.server_name ) ).all()
for job in newly_deleted_jobs:
- jobs_to_check.append( ( job, None ) )
+ jobs_to_check.append( ( job, job.stderr ) )
# Also pull from the queue (in the case of Administrative stopped jobs)
try:
while 1:
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee lib/galaxy/web/base/controllers/admin.py
--- a/lib/galaxy/web/base/controllers/admin.py
+++ b/lib/galaxy/web/base/controllers/admin.py
@@ -1016,8 +1016,6 @@
deleted = []
msg = None
status = None
- if self.app.config.job_manager != self.app.config.server_name:
- return trans.show_error_message( 'This Galaxy instance (%s) is not the job manager (%s). If using multiple servers, please directly access the job manager instance to manage jobs.' % (self.app.config.server_name, self.app.config.job_manager) )
job_ids = util.listify( stop )
if job_ids and stop_msg in [ None, '' ]:
msg = 'Please enter an error message to display to the user describing why the job was terminated'
@@ -1026,7 +1024,15 @@
if stop_msg[-1] not in PUNCTUATION:
stop_msg += '.'
for job_id in job_ids:
- trans.app.job_manager.job_stop_queue.put( job_id, error_msg="This job was stopped by an administrator: %s For more information or help" % stop_msg )
+ error_msg = "This job was stopped by an administrator: %s <a href='%s' target='_blank'>Contact support</a> for additional help." \
+ % ( stop_msg, self.app.config.get("support_url", "http://wiki.galaxyproject.org/Support" ) )
+ if trans.app.config.track_jobs_in_database:
+ job = trans.app.model.Job.get( job_id )
+ job.stderr = error_msg
+ job.state = trans.app.model.Job.states.DELETED_NEW
+ trans.sa_session.add( job )
+ else:
+ trans.app.job_manager.job_stop_queue.put( job_id, error_msg=error_msg )
deleted.append( str( job_id ) )
if deleted:
msg = 'Queued job'
@@ -1035,11 +1041,7 @@
msg += ' for deletion: '
msg += ', '.join( deleted )
status = 'done'
- if ajl_submit:
- if job_lock == 'on':
- trans.app.job_manager.job_queue.job_lock = True
- else:
- trans.app.job_manager.job_queue.job_lock = False
+ trans.sa_session.flush()
cutoff_time = datetime.utcnow() - timedelta( seconds=int( cutoff ) )
jobs = trans.sa_session.query( trans.app.model.Job ) \
.filter( and_( trans.app.model.Job.table.c.update_time < cutoff_time,
@@ -1060,8 +1062,7 @@
last_updated = last_updated,
cutoff = cutoff,
msg = msg,
- status = status,
- job_lock = trans.app.job_manager.job_queue.job_lock )
+ status = status )
## ---- Utility methods -------------------------------------------------------
diff -r 9852dd712f5c628d1f635fe643f036eb2b930863 -r 445b212b1c6d8159cb5b6f81300cf5dd3f1eebee templates/admin/jobs.mako
--- a/templates/admin/jobs.mako
+++ b/templates/admin/jobs.mako
@@ -46,6 +46,7 @@
<td>Last Update</td><td>Tool</td><td>State</td>
+ <td>Inputs</td><td>Command Line</td><td>Job Runner</td><td>PID/Cluster ID</td>
@@ -67,6 +68,13 @@
<td>${last_updated[job.id]} ago</td><td>${job.tool_id}</td><td>${job.state}</td>
+ <%
+ try:
+ inputs = ", ".join( [ '%s %s' % ( da.dataset.id, da.dataset.state ) for da in job.input_datasets ] )
+ except:
+ inputs = 'Unable to determine inputs'
+ %>
+ <td>${inputs}</td><td>${job.command_line}</td><td>${job.job_runner_name}</td><td>${job.job_runner_external_id}</td>
@@ -125,32 +133,3 @@
</div></div></form>
-<form name="jobs" action="${h.url_for(controller='admin', action='jobs')}" method="POST">
- <p/>
- <div class="toolForm">
- <div class="toolFormTitle">
- Administrative Job Lock
- </div>
- <div class="toolFormBody">
- <div class="form-row">
- <input type="hidden" name="ajl_submit" value="True"/>
- %if job_lock==True:
- <p>Job dispatching is currently <strong>locked</strong>.</p>
- <label>
- <input type='checkbox' name='job_lock' checked='checked' />
- Prevent jobs from dispatching.
- </label>
- %else:
- <p>Job dispatching is currently <strong>unlocked</strong>.</p>
- <label>
- <input type='checkbox' name='job_lock' />
- Prevent jobs from dispatching.
- </label>
- %endif
- </div>
- <div class="form-row">
- <input type="submit" class="primary-button" name="submit" value="Update">
- </div>
- </div>
- </div>
-</form>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Trackster: prevent data requests for very small regions by using a (configurable) minimum region size. This improves performance when zoomed in on small regions. Pack scripts.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9852dd712f5c/
changeset: 9852dd712f5c
user: jgoecks
date: 2013-02-19 16:16:21
summary: Trackster: prevent data requests for very small regions by using a (configurable) minimum region size. This improves performance when zoomed in on small regions. Pack scripts.
affected #: 4 files
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/packed/viz/trackster/tracks.js
--- a/static/scripts/packed/viz/trackster/tracks.js
+++ b/static/scripts/packed/viz/trackster/tracks.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,x,l,u,L,Y,i){var q=ab.extend;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var aa=16,G=9,D=20,A=100,I=12000,S=400,K=5000,w=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20;function W(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw(true)}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new f(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){z.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Z=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});z.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){x.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("href","javascript:void(0);").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_drawables(),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new X(this,{content_div:this.top_labeltrack}));this.add_label_track(new X(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")}});q(Z.prototype,z.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=w;var ac=this,ad=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+w+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+w+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-w});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+w});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();ae.request_redraw(true);for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad!==undefined&&aj!==undefined){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/ |,/g,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){z.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=this.viewport_container.width()/(this.high-this.low);var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._draw()}}},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ae.dataset_id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=function(ae,aj,af){this.track=ae;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new N(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.original_dataset_id,tool_id:ac.name},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ai=new x.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new P(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new Y.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(y+ag.message)}else{af(ag)}}})}});var N=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){N.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};q(F.prototype,{restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(l.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};q(j.prototype,b.prototype);var O=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new x.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?W(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=new Y.Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new x.GenomeDataManager({dataset:this.dataset,data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new x.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.hda_ldda,regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},on_resize:function(){},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof X){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof R){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),af={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(v);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when(ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new s(this,af.tool,af.tool_state):null);this.tile_cache=new x.Cache(Q);if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw(true)},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,ao){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),aq=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;aq=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*S)),ak=true,ap=[],ai=function(ar){return(ar&&"track" in ar)};while((ac*S*ag)<ah){var am=this._get_tile_bounds(ac,ag),an=this.draw_helper(ad,am,ag,this.tiles_div,aq);if(ai(an)){ap.push(an)}else{ak=false}ac+=1}if(!ao){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ap,ae,aq,ao)}},postdraw_actions:function(ad,ae,ag,ac){var af=ab.find(ad,function(ah){return ah.has_icons});if(af){ab.each(ad,function(ah){if(!ah.has_icons){ah.html_elt.css("padding-top",D)}})}},draw_helper:function(ac,af,ar,ah,ai,ao){var an=this,aw=this._gen_tile_cache_key(ai,af);if(!ao){ao={}}var av=(ac?undefined:an.tile_cache.get_elt(aw));if(av){an.show_tile(av,ah,ai);return av}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){q(at,ao.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),au=af.get("start"),ad=af.get("end"),ap=Math.ceil((ad-au)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ap);ae.width=ap;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var av=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(av!==undefined){an.tile_cache.set_elt(aw,av);an.show_tile(av,ah,ai)}return av}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah,ai){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ah.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new l.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.hda_ldda},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var X=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(X.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){M.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ac){M.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,draw_helper:function(ad,ah,av,aj,al,at){var aq=this,aB=this._gen_tile_cache_key(al,ah);if(!at){at={}}var aA=(ad?undefined:aq.tile_cache.get_elt(aB));if(aA){aq.show_tile(aA,aj,al);return aA}var ak=[],aq,ao=true,aw,am;for(var ax=0;ax<this.drawables.length;ax++){aq=this.drawables[ax];aw=aq.data_manager.get_data(ah,aq.mode,av,aq.data_url_extra_params);if(V(aw)){ao=false}ak.push(aw);am=null;if(view.reference_track&&al>view.canvas_manager.char_width_px){am=view.reference_track.data_manager.get_data(ah,aq.mode,av,view.reference_track.data_url_extra_params);if(V(am)){ao=false}}ak.push(am)}if(ao){q(aw,at.more_tile_data);this.tile_predraw_init();var ag=aq.view.canvas_manager.new_canvas(),ay=ah.get("start"),ae=ah.get("end"),az=0,ar=Math.ceil((ae-ay)*al)+this.left_offset,ap=0,af=[],ax;var ac=0;for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];var an=aq.mode;if(an==="Auto"){an=aq.get_mode(aw);aq.update_auto_mode(an)}af.push(an);ac=aq.get_canvas_height(aw,an,al,ar);if(ac>ap){ap=ac}}ag.width=ar;ag.height=(at.height?at.height:ap);az=0;var au=ag.getContext("2d");au.translate(this.left_offset,0);au.globalAlpha=0.5;au.globalCompositeOperation="source-over";for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];am=ak[az+1];aA=aq.draw_tile(aw,au,af[ax],av,ah,al,am)}this.tile_cache.set_elt(aB,aA);this.show_tile(aA,aj,al);return aA}var ai=$.Deferred(),aq=this;$.when.apply($,ak).then(function(){view.request_redraw(false,false,false,aq);ai.resolve()});return ai},show_group:function(){var af=new P(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof h){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){M.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var B=function(ac){M.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ae,af,ac,ag,ah,ad){if(ah>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ae,af,ac,ag,ah,ad)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var h=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:l.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new L.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var t=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,af,ae,ah);var ag=l.get_random_color(),ac=l.get_random_color([ag,"#FFFFFF"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){M.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof O){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}else{if(ac==="summary_tree"){ac="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,A,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(ao==="summary_tree"||ao==="Coverage"){var aA=new L.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new O(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var R=function(ad,ac,ae){c.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(R.prototype,r.prototype,M.prototype,c.prototype);var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=l.get_random_color(),ac=l.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(T.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:R,ReadTrack:T,DiagonalHeatmapTrack:t,CompositeTrack:f,DrawableGroup:P};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{TracksterView:Z,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:T,VcfTrack:R,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","mvc/data","viz/trackster/filters"],function(ab,x,l,u,L,Y,i){var q=ab.extend;var V=function(ac){return("isResolved" in ac)};var n={};var k=function(ac,ad){n[ac.attr("id")]=ad};var m=function(ac,ae,ag,af){ag=".group";var ad={};n[ac.attr("id")]=af;ac.bind("drag",{handle:"."+ae,relative:true},function(ao,ap){var an=$(this),at=$(this).parent(),ak=at.children(),am=n[$(this).attr("id")],aj,ai,aq,ah,al;ai=$(this).parents(ag);if(ai.length!==0){aq=ai.position().top;ah=aq+ai.outerHeight();if(ap.offsetY<aq){$(this).insertBefore(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable_before(am,ar);return}else{if(ap.offsetY>ah){$(this).insertAfter(ai);var ar=n[ai.attr("id")];ar.remove_drawable(am);ar.container.add_drawable(am);return}}}ai=null;for(al=0;al<ak.length;al++){aj=$(ak.get(al));aq=aj.position().top;ah=aq+aj.outerHeight();if(aj.is(ag)&&this!==aj.get(0)&&ap.offsetY>=aq&&ap.offsetY<=ah){if(ap.offsetY-aq<ah-ap.offsetY){aj.find(".content-div").prepend(this)}else{aj.find(".content-div").append(this)}if(am.container){am.container.remove_drawable(am)}n[aj.attr("id")].add_drawable(am);return}}for(al=0;al<ak.length;al++){aj=$(ak.get(al));if(ap.offsetY<aj.position().top&&!(aj.hasClass("reference-track")||aj.hasClass("intro"))){break}}if(al===ak.length){if(this!==ak.get(al-1)){at.append(this);n[at.attr("id")].move_drawable(am,al)}}else{if(this!==ak.get(al)){$(this).insertBefore(ak.get(al));n[at.attr("id")].move_drawable(am,(ap.deltaY>0?al-1:al))}}}).bind("dragstart",function(){ad["border-top"]=ac.css("border-top");ad["border-bottom"]=ac.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ad)})};var aa=16,G=9,D=20,A=100,I=12000,S=400,K=5000,w=100,o="Cannot display dataset due to an error. ",J="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",E="No data for this chrom/contig.",v="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",y="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20;function W(ad,ac){if(!ac){ac=0}var ae=Math.pow(10,ac);return Math.round(ad*ae)/ae}var r=function(ad,ac,af){if(!r.id_counter){r.id_counter=0}this.id=r.id_counter++;this.name=af.name;this.view=ad;this.container=ac;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=af.drag_handle_class;this.is_overview=false;this.action_icons={};this.content_visible=true;this.container_div=this.build_container_div();this.header_div=this.build_header_div();if(this.header_div){this.container_div.append(this.header_div);this.icons_div=$("<div/>").css("float","left").hide().appendTo(this.header_div);this.build_action_icons(this.action_icons_def);this.header_div.append($("<div style='clear: both'/>"));this.header_div.dblclick(function(ag){ag.stopPropagation()});var ae=this;this.container_div.hover(function(){ae.icons_div.show()},function(){ae.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};r.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ac){if(ac.content_visible){ac.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ac.hide_contents();ac.content_visible=false}else{ac.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ac.content_visible=true;ac.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ad){var af=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ac=function(){ad.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(ag){if((ag.keyCode||ag.which)===27){af()}else{if((ag.keyCode||ag.which)===13){ac()}}};$(window).bind("keypress.check_enter_esc",ae);show_modal("Configure",ad.config.build_form(),{Cancel:af,OK:ac})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.remove()}}];q(r.prototype,{init:function(){},changed:function(){this.view.changed()},can_draw:function(){if(this.enabled&&this.content_visible){return true}return false},request_draw:function(){},_draw:function(){},to_dict:function(){},set_name:function(ac){this.old_name=this.name;this.name=ac;this.name_div.text(this.name)},revert_name:function(){if(this.old_name){this.name=this.old_name;this.name_div.text(this.name)}},remove:function(){this.changed();this.container.remove_drawable(this);var ac=this.view;this.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ad,ai,ah,ag,ac,af){var ae=this;this.action_icons[ad]=$("<a/>").attr("href","javascript:void(0);").attr("title",ai).addClass("icon-button").addClass(ah).tooltip().click(function(){ag(ae)}).appendTo(this.icons_div);if(af){this.action_icons[ad].hide()}},build_action_icons:function(ac){var ae;for(var ad=0;ad<ac.length;ad++){ae=ac[ad];this.add_action_icon(ae.name,ae.title,ae.css_class,ae.on_click_fn,ae.prepend,ae.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var z=function(ad,ac,ae){r.call(this,ad,ac,ae);this.obj_type=ae.obj_type;this.drawables=[]};q(z.prototype,r.prototype,{unpack_drawables:function(ae){this.drawables=[];var ad;for(var ac=0;ac<ae.length;ac++){ad=p(ae[ac],this.view,this);this.add_drawable(ad)}},init:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].init()}},_draw:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac]._draw()}},to_dict:function(){var ad=[];for(var ac=0;ac<this.drawables.length;ac++){ad.push(this.drawables[ac].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ad}},add_drawable:function(ac){this.drawables.push(ac);ac.container=this;this.changed()},add_drawable_before:function(ae,ac){this.changed();var ad=this.drawables.indexOf(ac);if(ad!==-1){this.drawables.splice(ad,0,ae);return true}return false},replace_drawable:function(ae,ac,ad){var af=this.drawables.indexOf(ae);if(af!==-1){this.drawables[af]=ac;if(ad){ae.container_div.replaceWith(ac.container_div)}this.changed()}return af},remove_drawable:function(ad){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);ad.container=null;this.changed();return true}return false},move_drawable:function(ad,ae){var ac=this.drawables.indexOf(ad);if(ac!==-1){this.drawables.splice(ac,1);this.drawables.splice(ae,0,ad);this.changed();return true}return false},get_drawables:function(){return this.drawables}});var P=function(ad,ac,af){q(af,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});z.call(this,ad,ac,af);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);k(this.container_div,this);k(this.content_div,this);m(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new i.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in af){this.unpack_drawables(af.drawables)}if("filters" in af){var ae=this.filters_manager;this.filters_manager=new i.FiltersManager(this,af.filters);ae.parent_div.replaceWith(this.filters_manager.parent_div);if(af.filters.visible){this.setup_multitrack_filtering()}}};q(P.prototype,r.prototype,z.prototype,{action_icons_def:[r.prototype.action_icons_def[0],r.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters();ac._restore_filter_managers()}else{ac.setup_multitrack_filtering();ac.request_draw(true)}ac.filters_manager.toggle()}},r.prototype.action_icons_def[2]],build_container_div:function(){var ac=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ac)}return ac},build_header_div:function(){var ac=$("<div/>").addClass("track-header");ac.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ac);return ac},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var ae=this.drawables.length;if(ae===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(ae===1){if(this.drawables[0] instanceof f){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var al,ak,ai,ao=true,ag=this.drawables[0].get_type(),ac=0;for(al=0;al<ae;al++){ai=this.drawables[al];if(ai.get_type()!==ag){can_composite=false;break}if(ai instanceof c){ac++}}if(ao||ac===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ac>1&&ac===this.drawables.length){var ap={},ad;ai=this.drawables[0];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];ap[ad.name]=[ad]}for(al=1;al<this.drawables.length;al++){ai=this.drawables[al];for(ak=0;ak<ai.filters_manager.filters.length;ak++){ad=ai.filters_manager.filters[ak];if(ad.name in ap){ap[ad.name].push(ad)}}}this.filters_manager.remove_all();var af,ah,aj,am;for(var an in ap){af=ap[an];if(af.length===ac){ah=new i.NumberFilter({name:af[0].name,index:af[0].index});this.filters_manager.add_filter(ah)}}if(this.filters_manager.filters.length>0){this.action_icons.filters_icon.show()}else{this.action_icons.filters_icon.hide()}}else{this.action_icons.filters_icon.hide()}}}},_restore_filter_managers:function(){for(var ac=0;ac<this.drawables.length;ac++){this.drawables[ac].filters_manager=this.saved_filters_managers[ac]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ac=0;ac<this.drawables.length;ac++){drawable=this.drawables[ac];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ag=[];for(var ad=0;ad<this.drawables.length;ad++){ag.push(this.drawables[ad].name)}var ae="Composite Track of "+this.drawables.length+" tracks ("+ag.join(", ")+")";var af=new f(this.view,this.view,{name:ae,drawables:this.drawables});var ac=this.container.replace_drawable(this,af,true);af.request_draw()},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);this.update_icons()},remove_drawable:function(ac){z.prototype.remove_drawable.call(this,ac);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ac=q(z.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ac},request_draw:function(ac,ae){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].request_draw(ac,ae)}}});var Z=Backbone.View.extend({initialize:function(ac){q(ac,{obj_type:"View"});z.call(this,"View",ac.container,ac);this.chrom=null;this.vis_id=ac.vis_id;this.dbkey=ac.dbkey;this.label_tracks=[];this.tracks_to_be_redrawn=[];this.max_low=0;this.max_high=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.load_chroms_deferred=null;this.render();this.canvas_manager=new x.CanvasManager(this.container.get(0).ownerDocument);this.reset()},render:function(){this.requested_redraw=false;var ae=this.container,ac=this;this.top_container=$("<div/>").addClass("top-container").appendTo(ae);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(ae);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(ae);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.top_container);this.viewport_container=$("<div/>").addClass("viewport-container").attr("id","viewport-container").appendTo(this.browser_content_div);this.content_div=this.viewport_container;k(this.viewport_container,ac);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var af=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){x.select_datasets(select_datasets_url,add_track_async_url,{"f-dbkey":ac.dbkey},function(ag){ab.each(ag,function(ah){ac.add_drawable(p(ah,ac,ac))})})});this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.bottom_container);this.nav_container=$("<div/>").addClass("trackster-nav-container").prependTo(this.top_container);this.nav=$("<div/>").addClass("trackster-nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.bottom_container);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_close=$("<a/>").attr("href","javascript:void(0);").attr("title","Close overview").addClass("icon-button overview-close tooltip").hide().appendTo(this.overview_viewport);this.overview_highlight=$("<div/>").addClass("overview-highlight").hide().appendTo(this.overview_viewport);this.overview_box_background=$("<div/>").addClass("overview-boxback").appendTo(this.overview_viewport);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.default_overview_height=this.overview_box.height();this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").append("<option value=''>Loading</option>").appendTo(this.nav_controls);var ad=function(ag){if(ag.type==="focusout"||(ag.keyCode||ag.which)===13||(ag.keyCode||ag.which)===27){if((ag.keyCode||ag.which)!==27){ac.go_to($(this).val())}$(this).hide();$(this).val("");ac.location_span.show();ac.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ad).appendTo(this.nav_controls);this.location_span=$("<span/>").addClass("location").attr("original-title","Click to change location").tooltip({placement:"bottom"}).appendTo(this.nav_controls);this.location_span.click(function(){ac.location_span.hide();ac.chrom_select.hide();ac.nav_input.val(ac.chrom+":"+ac.low+"-"+ac.high);ac.nav_input.css("display","inline-block");ac.nav_input.select();ac.nav_input.focus();ac.nav_input.autocomplete({source:function(ai,ag){var aj=[],ah=$.map(ac.get_drawables(),function(ak){return ak.data_manager.search_features(ai.term).success(function(al){aj=aj.concat(al)})});$.when.apply($,ah).done(function(){ag($.map(aj,function(ak){return{label:ak[0],value:ak[1]}}))})}})});if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.nav_controls)}this.zo_link=$("<a/>").attr("id","zoom-out").attr("title","Zoom out").tooltip({placement:"bottom"}).click(function(){ac.zoom_out();ac.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ac.zoom_in();ac.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ac.change_chrom(ac.chrom_select.val())});this.browser_content_div.click(function(ag){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ag){ac.zoom_in(ag.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ag,ah){this.current_x=ah.offsetX}).bind("drag",function(ag,ai){var aj=ai.offsetX-this.current_x;this.current_x=ai.offsetX;var ah=Math.round(aj/ac.viewport_container.width()*(ac.max_high-ac.max_low));ac.move_delta(-ah)});this.overview_close.click(function(){ac.reset_overview()});this.viewport_container.bind("draginit",function(ag,ah){if(ag.clientX>ac.viewport_container.width()-16){return false}}).bind("dragstart",function(ag,ah){ah.original_low=ac.low;ah.current_height=ag.clientY;ah.current_x=ah.offsetX}).bind("drag",function(ai,ak){var ag=$(this);var al=ak.offsetX-ak.current_x;var ah=ag.scrollTop()-(ai.clientY-ak.current_height);ag.scrollTop(ah);ak.current_height=ai.clientY;ak.current_x=ak.offsetX;var aj=Math.round(al/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}).bind("mousewheel",function(ai,ak,ah,ag){if(ah){ah*=50;var aj=Math.round(-ah/ac.viewport_container.width()*(ac.high-ac.low));ac.move_delta(aj)}});this.top_labeltrack.bind("dragstart",function(ag,ah){return $("<div />").css({height:ac.browser_content_div.height()+ac.top_labeltrack.height()+ac.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(ak,al){$(al.proxy).css({left:Math.min(ak.pageX,al.startX)-ac.container.offset().left,width:Math.abs(ak.pageX-al.startX)});var ah=Math.min(ak.pageX,al.startX)-ac.container.offset().left,ag=Math.max(ak.pageX,al.startX)-ac.container.offset().left,aj=(ac.high-ac.low),ai=ac.viewport_container.width();ac.update_location(Math.round(ah/ai*aj)+ac.low,Math.round(ag/ai*aj)+ac.low)}).bind("dragend",function(al,am){var ah=Math.min(al.pageX,am.startX),ag=Math.max(al.pageX,am.startX),aj=(ac.high-ac.low),ai=ac.viewport_container.width(),ak=ac.low;ac.low=Math.round(ah/ai*aj)+ak;ac.high=Math.round(ag/ai*aj)+ak;$(am.proxy).remove();ac.request_redraw()});this.add_label_track(new X(this,{content_div:this.top_labeltrack}));this.add_label_track(new X(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ac.resize_window()},500)});$(document).bind("redraw",function(){ac.redraw()});this.reset();$(window).trigger("resize")}});q(Z.prototype,z.prototype,{changed:function(){this.has_changes=true},update_intro_div:function(){if(this.drawables.length===0){this.intro_div.show()}else{this.intro_div.hide()}},trigger_navigate:function(ad,af,ac,ag){if(this.timer){clearTimeout(this.timer)}if(ag){var ae=this;this.timer=setTimeout(function(){ae.trigger("navigate",ad+":"+af+"-"+ac)},500)}else{view.trigger("navigate",ad+":"+af+"-"+ac)}},update_location:function(ac,ae){this.location_span.text(commatize(ac)+" - "+commatize(ae));this.nav_input.val(this.chrom+":"+commatize(ac)+"-"+commatize(ae));var ad=view.chrom_select.val();if(ad!==""){this.trigger_navigate(ad,view.low,view.high,true)}},load_chroms:function(ae){ae.num=w;var ac=this,ad=$.Deferred();$.ajax({url:chrom_url+"/"+this.dbkey,data:ae,dataType:"json",success:function(ag){if(ag.chrom_info.length===0){return}if(ag.reference){ac.add_label_track(new B(ac))}ac.chrom_data=ag.chrom_info;var aj='<option value="">Select Chrom/Contig</option>';for(var ai=0,af=ac.chrom_data.length;ai<af;ai++){var ah=ac.chrom_data[ai].chrom;aj+='<option value="'+ah+'">'+ah+"</option>"}if(ag.prev_chroms){aj+='<option value="previous">Previous '+w+"</option>"}if(ag.next_chroms){aj+='<option value="next">Next '+w+"</option>"}ac.chrom_select.html(aj);ac.chrom_start_index=ag.start_index;ad.resolve(ag.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ac.dbkey)}});return ad},change_chrom:function(ah,ad,aj){var ae=this;if(!ae.chrom_data){ae.load_chroms_deferred.then(function(){ae.change_chrom(ah,ad,aj)});return}if(!ah||ah==="None"){return}if(ah==="previous"){ae.load_chroms({low:this.chrom_start_index-w});return}if(ah==="next"){ae.load_chroms({low:this.chrom_start_index+w});return}var ai=$.grep(ae.chrom_data,function(ak,al){return ak.chrom===ah})[0];if(ai===undefined){ae.load_chroms({chrom:ah},function(){ae.change_chrom(ah,ad,aj)});return}else{if(ah!==ae.chrom){ae.chrom=ah;ae.chrom_select.val(ae.chrom);ae.max_high=ai.len-1;ae.reset();ae.request_redraw(true);for(var ag=0,ac=ae.drawables.length;ag<ac;ag++){var af=ae.drawables[ag];if(af.init){af.init()}}if(ae.reference_track){ae.reference_track.init()}}if(ad!==undefined&&aj!==undefined){ae.low=Math.max(ad,0);ae.high=Math.min(aj,ae.max_high)}else{ae.low=0;ae.high=ae.max_high}ae.reset_overview();ae.request_redraw()}},go_to:function(ag){ag=ag.replace(/ |,/g,"");var ak=this,ac,af,ad=ag.split(":"),ai=ad[0],aj=ad[1];if(aj!==undefined){try{var ah=aj.split("-");ac=parseInt(ah[0],10);af=parseInt(ah[1],10)}catch(ae){return false}}ak.change_chrom(ai,ac,af)},move_fraction:function(ae){var ac=this;var ad=ac.high-ac.low;this.move_delta(ae*ad)},move_delta:function(af){var ac=this;var ae=ac.high-ac.low;if(ac.low-af<ac.max_low){ac.low=ac.max_low;ac.high=ac.max_low+ae}else{if(ac.high-af>ac.max_high){ac.high=ac.max_high;ac.low=ac.max_high-ae}else{ac.high-=af;ac.low-=af}}ac.request_redraw();var ad=ac.chrom_select.val();this.trigger_navigate(ad,ac.low,ac.high,true)},add_drawable:function(ac){z.prototype.add_drawable.call(this,ac);ac.init();this.changed();this.update_intro_div()},add_label_track:function(ac){ac.view=this;ac.init();this.label_tracks.push(ac)},remove_drawable:function(ae,ad){z.prototype.remove_drawable.call(this,ae);if(ad){var ac=this;ae.container_div.hide(0,function(){$(this).remove();ac.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ak,ac,aj,al){var ai=this,ah=(al?[al]:ai.drawables),ae;var ad;for(var ag=0;ag<ah.length;ag++){ad=ah[ag];ae=-1;for(var af=0;af<ai.tracks_to_be_redrawn.length;af++){if(ai.tracks_to_be_redrawn[af][0]===ad){ae=af;break}}if(ae<0){ai.tracks_to_be_redrawn.push([ad,ac,aj])}else{ai.tracks_to_be_redrawn[ag][1]=ac;ai.tracks_to_be_redrawn[ag][2]=aj}}if(!this.requested_redraw){requestAnimationFrame(function(){ai._redraw(ak)});this.requested_redraw=true}},_redraw:function(am){this.requested_redraw=false;var aj=this.low,af=this.high;if(aj<this.max_low){aj=this.max_low}if(af>this.max_high){af=this.max_high}var al=this.high-this.low;if(this.high!==0&&al<this.min_separation){af=aj+this.min_separation}this.low=Math.floor(aj);this.high=Math.ceil(af);this.update_location(this.low,this.high);this.resolution_b_px=(this.high-this.low)/this.viewport_container.width();this.resolution_px_b=1/this.resolution_b_px;var ac=(this.low/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var ai=((this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())||0;var an=13;this.overview_box.css({left:ac,width:Math.max(an,ai)}).show();if(ai<an){this.overview_box.css("left",ac-(an-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ac,width:ai})}if(!am){var ae,ad,ak;for(var ag=0,ah=this.tracks_to_be_redrawn.length;ag<ah;ag++){ae=this.tracks_to_be_redrawn[ag][0];ad=this.tracks_to_be_redrawn[ag][1];ak=this.tracks_to_be_redrawn[ag][2];if(ae){ae._draw(ad,ak)}}this.tracks_to_be_redrawn=[];for(ag=0,ah=this.label_tracks.length;ag<ah;ag++){this.label_tracks[ag]._draw()}}},zoom_in:function(ad,ae){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var af=this.high-this.low,ag=af/2+this.low,ac=(af/this.zoom_factor)/2;if(ad){ag=ad/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ag-ac);this.high=Math.round(ag+ac);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ad=this.high-this.low,ae=ad/2+this.low,ac=(ad*this.zoom_factor)/2;this.low=Math.round(ae-ac);this.high=Math.round(ae+ac);this.changed();this.request_redraw()},resize_window:function(){this.viewport_container.height(this.container.height()-this.top_container.height()-this.bottom_container.height());this.request_redraw()},set_overview:function(ae){if(this.overview_drawable){if(this.overview_drawable.dataset_id===ae.dataset_id){return}this.overview_viewport.find(".track").remove()}var ad=ae.copy({content_div:this.overview_viewport}),ac=this;ad.header_div.hide();ad.is_overview=true;ac.overview_drawable=ad;this.overview_drawable.postdraw_actions=function(){ac.overview_highlight.show().height(ac.overview_drawable.content_div.height());ac.overview_viewport.height(ac.overview_drawable.content_div.height()+ac.overview_box.outerHeight());ac.overview_close.show();ac.resize_window()};ac.overview_drawable.request_draw();this.changed()},reset_overview:function(){$(".bs-tooltip").remove();this.overview_viewport.find(".track-tile").remove();this.overview_viewport.height(this.default_overview_height);this.overview_box.height(this.default_overview_height);this.overview_close.hide();this.overview_highlight.hide();view.resize_window();view.overview_drawable=null}});var s=function(ae,aj,af){this.track=ae;this.name=aj.name;this.params=[];var aq=aj.params;for(var ag=0;ag<aq.length;ag++){var al=aq[ag],ad=al.name,ap=al.label,ah=unescape(al.html),ar=al.value,an=al.type;if(an==="number"){this.params.push(new e(ad,ap,ah,(ad in af?af[ad]:ar),al.min,al.max))}else{if(an==="select"){this.params.push(new N(ad,ap,ah,(ad in af?af[ad]:ar)))}else{console.log("WARNING: unrecognized tool parameter type:",ad,an)}}}this.parent_div=$("<div/>").addClass("dynamic-tool").hide();this.parent_div.bind("drag",function(au){au.stopPropagation()}).click(function(au){au.stopPropagation()}).bind("dblclick",function(au){au.stopPropagation()});var ao=$("<div class='tool-name'>").appendTo(this.parent_div).text(this.name);var am=this.params;var ak=this;$.each(this.params,function(av,ay){var ax=$("<div>").addClass("param-row").appendTo(ak.parent_div);var au=$("<div>").addClass("param-label").text(ay.label).appendTo(ax);var aw=$("<div/>").addClass("param-input").html(ay.html).appendTo(ax);aw.find(":input").val(ay.value);$("<div style='clear: both;'/>").appendTo(ax)});this.parent_div.find("input").click(function(){$(this).select()});var at=$("<div>").addClass("param-row").appendTo(this.parent_div);var ai=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(at);var ac=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(at);ac.click(function(){ak.run_on_region()});ai.click(function(){ak.run_on_dataset()});if("visible" in af&&af.visible){this.parent_div.show()}};q(s.prototype,{update_params:function(){for(var ac=0;ac<this.params.length;ac++){this.params[ac].update_value()}},state_dict:function(){var ad={};for(var ac=0;ac<this.params.length;ac++){ad[this.params[ac].name]=this.params[ac].value}ad.visible=this.parent_div.is(":visible");return ad},get_param_values_dict:function(){var ac={};this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();ac[ad]=ae});return ac},get_param_values:function(){var ac=[];this.parent_div.find(":input").each(function(){var ad=$(this).attr("name"),ae=$(this).val();if(ad){ac[ac.length]=ae}});return ac},run_on_dataset:function(){var ac=this;ac.run({target_dataset_id:this.track.original_dataset_id,tool_id:ac.name},null,function(ad){show_modal(ac.name+" is Running",ac.name+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ai=new x.GenomeRegion({chrom:this.track.view.chrom,start:this.track.view.low,end:this.track.view.high}),ad={target_dataset_id:this.track.original_dataset_id,action:"rerun",tool_id:this.name,regions:[ai.toJSON()]},ah=this.track,ae=ad.tool_id+ah.tool_region_and_parameters_str(ai),ac;if(ah.container===view){var ag=new P(view,view,{name:this.name});var af=ah.container.replace_drawable(ah,ag,false);ag.container_div.insertBefore(ah.view.content_div.children()[af]);ag.add_drawable(ah);ah.container_div.appendTo(ag.content_div);ac=ag}else{ac=ah.container}var aj=new ah.constructor(view,ac,{name:ae,hda_ldda:"hda"});aj.init_for_tool_data();aj.change_mode(ah.mode);aj.set_filters_manager(ah.filters_manager.copy(aj));aj.update_icons();ac.add_drawable(aj);aj.tiles_div.text("Starting job.");this.update_params();this.run(ad,aj,function(ak){aj.set_dataset(new Y.Dataset(ak));aj.tiles_div.text("Running job.");aj.init()})},run:function(ac,ae,af){ac.inputs=this.get_param_values_dict();var ad=new l.ServerStateDeferred({ajax_settings:{url:galaxy_paths.get("tool_url"),data:JSON.stringify(ac),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ag){return ag!=="pending"}});$.when(ad.go()).then(function(ag){if(ag==="no converter"){ae.container_div.addClass("error");ae.content_div.text(J)}else{if(ag.error){ae.container_div.addClass("error");ae.content_div.text(y+ag.message)}else{af(ag)}}})}});var N=function(ad,ac,ae,af){this.name=ad;this.label=ac;this.html=$(ae);this.value=af};q(N.prototype,{update_value:function(){this.value=$(this.html).val()}});var e=function(ae,ad,ag,ah,af,ac){N.call(this,ae,ad,ag,ah);this.min=af;this.max=ac};q(e.prototype,N.prototype,{update_value:function(){N.prototype.update_value.call(this);this.value=parseFloat(this.value)}});var C=function(ac,ad){L.Scaler.call(this,ad);this.filter=ac};C.prototype.gen_val=function(ac){if(this.filter.high===Number.MAX_VALUE||this.filter.low===-Number.MAX_VALUE||this.filter.low===this.filter.high){return this.default_val}return((parseFloat(ac[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ac){this.track=ac.track;this.params=ac.params;this.values={};this.restore_values((ac.saved_values?ac.saved_values:{}));this.onchange=ac.onchange};q(F.prototype,{restore_values:function(ac){var ad=this;$.each(this.params,function(ae,af){if(ac[af.key]!==undefined){ad.values[af.key]=ac[af.key]}else{ad.values[af.key]=af.default_value}})},build_form:function(){var af=this;var ac=$("<div />");var ae;function ad(ak,ag){for(var ao=0;ao<ak.length;ao++){ae=ak[ao];if(ae.hidden){continue}var ai="param_"+ao;var at=af.values[ae.key];var av=$("<div class='form-row' />").appendTo(ag);av.append($("<label />").attr("for",ai).text(ae.label+":"));if(ae.type==="bool"){av.append($('<input type="checkbox" />').attr("id",ai).attr("name",ai).attr("checked",at))}else{if(ae.type==="text"){av.append($('<input type="text"/>').attr("id",ai).val(at).click(function(){$(this).select()}))}else{if(ae.type==="select"){var aq=$("<select />").attr("id",ai);for(var am=0;am<ae.options.length;am++){$("<option/>").text(ae.options[am].label).attr("value",ae.options[am].value).appendTo(aq)}aq.val(at);av.append(aq)}else{if(ae.type==="color"){var au=$("<div/>").appendTo(av),ap=$("<input />").attr("id",ai).attr("name",ai).val(at).css("float","left").appendTo(au).click(function(ax){$(".bs-tooltip").removeClass("in");var aw=$(this).siblings(".bs-tooltip").addClass("in");aw.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(aw).height()/2)+($(this).height()/2)}).show();aw.click(function(ay){ay.stopPropagation()});$(document).bind("click.color-picker",function(){aw.hide();$(document).unbind("click.color-picker")});ax.stopPropagation()}),an=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(au).attr("title","Set new random color").tooltip(),ar=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(au).hide(),aj=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(ar),ah=$("<div class='tooltip-arrow'></div>").appendTo(ar),al=$.farbtastic(aj,{width:100,height:100,callback:ap,color:at});au.append($("<div/>").css("clear","both"));(function(aw){an.click(function(){aw.setColor(l.get_random_color())})})(al)}else{av.append($("<input />").attr("id",ai).attr("name",ai).val(at))}}}}if(ae.help){av.append($("<div class='help'/>").text(ae.help))}}}ad(this.params,ac);return ac},update_from_form:function(ac){var ae=this;var ad=false;$.each(this.params,function(af,ah){if(!ah.hidden){var ai="param_"+af;var ag=ac.find("#"+ai).val();if(ah.type==="float"){ag=parseFloat(ag)}else{if(ah.type==="int"){ag=parseInt(ag)}else{if(ah.type==="bool"){ag=ac.find("#"+ai).is(":checked")}}}if(ag!==ae.values[ah.key]){ae.values[ah.key]=ag;ad=true}}});if(ad){this.onchange();this.track.changed()}}});var b=function(ac,ag,ae,ad,af){this.track=ac;this.region=ag;this.low=ag.get("start");this.high=ag.get("end");this.resolution=ae;this.html_elt=$("<div class='track-tile'/>").append(ad).height($(ad).attr("height"));this.data=af;this.stale=false};b.prototype.predisplay_actions=function(){};var j=function(ac,ah,ae,ad,af,ag){b.call(this,ac,ah,ae,ad,af);this.max_val=ag};q(j.prototype,b.prototype);var O=function(af,an,ag,ae,ai,ap,aj,aq,ad,am){b.call(this,af,an,ag,ae,ai);this.mode=aj;this.all_slotted=ad;this.feature_mapper=am;this.has_icons=false;if(aq){this.has_icons=true;var ak=this;ae=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:ae.width}).prependTo(this.html_elt);var al=new x.GenomeRegion({chrom:af.view.chrom,start:this.low,end:this.high}),ao=ai.length,ah=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ac=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ao+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ah.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()});ac.click(function(){ak.stale=true;af.data_manager.get_more_data(al,af.mode,ak.resolution,{},af.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();af.request_draw(true)}).dblclick(function(ar){ar.stopPropagation()})}};q(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ad=this,ac={};if(ad.mode!=="Pack"){return}$(this.html_elt).hover(function(){this.hovered=true;$(this).mousemove()},function(){this.hovered=false;$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()}).mousemove(function(ao){if(!this.hovered){return}var aj=$(this).offset(),an=ao.pageX-aj.left,am=ao.pageY-aj.top,at=ad.feature_mapper.get_feature_data(an,am),ak=(at?at[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!ak||$(this).attr("id")!==ak.toString()){$(this).remove()}});if(at){var af=ac[ak];if(!af){var ak=at[0],ap={name:at[3],start:at[1],end:at[2],strand:at[4]},ai=ad.track.filters_manager.filters,ah;for(var al=0;al<ai.length;al++){ah=ai[al];ap[ah.name]=at[ah.index]}var af=$("<div/>").attr("id",ak).addClass("feature-popup"),au=$("<table/>"),ar,aq,av;for(ar in ap){aq=ap[ar];av=$("<tr/>").appendTo(au);$("<th/>").appendTo(av).text(ar);$("<td/>").attr("align","left").appendTo(av).text(typeof(aq)==="number"?W(aq,2):aq)}af.append($("<div class='feature-popup-inner'>").append(au));ac[ak]=af}af.appendTo($(this).parents(".track-content").children(".overlay"));var ag=an+parseInt(ad.html_elt.css("left"))-af.width()/2,ae=am+parseInt(ad.html_elt.css("top"))+7;af.css("left",ag+"px").css("top",ae+"px")}else{if(!ao.isPropagationStopped()){ao.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ao)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var g=function(ad,ac,ae){q(ae,{drag_handle_class:"draghandle"});r.call(this,ad,ac,ae);this.dataset=new Y.Dataset({id:ae.dataset_id,hda_ldda:ae.hda_ldda});this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in ae?ae.data_query_wait:K);this.data_manager=("data_manager" in ae?ae.data_manager:new x.GenomeDataManager({dataset:this.dataset,genome:new x.Genome({key:ad.dbkey,chroms_info:{chrom_info:ad.chrom_data}}),data_mode_compatible:this.data_and_mode_compatible,can_subset:this.can_subset}));this.min_height_px=16;this.max_height_px=800;this.visible_height_px=0;this.content_div=$("<div class='track-content'>").appendTo(this.container_div);if(this.container){this.container.content_div.append(this.container_div);if(!("resize" in ae)||ae.resize){this.add_resize_handle()}}};q(g.prototype,r.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},r.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ac){ac.view.set_overview(ac)}},r.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ac){if(ac.filters_manager.visible()){ac.filters_manager.clear_filters()}else{ac.filters_manager.init_filters()}ac.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ac){ac.dynamic_tool_div.toggle();if(ac.dynamic_tool_div.is(":visible")){ac.set_name(ac.name+ac.tool_region_and_parameters_str())}else{ac.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ac){var af='<strong>Tool</strong>: <%= track.tool.name %><br/><strong>Dataset</strong>: <%= track.name %><br/><strong>Region(s)</strong>: <select name="regions"><option value="cur">current viewing area</option><option value="bookmarks">bookmarks</option><option value="both">current viewing area and bookmarks</option></select>',ae=ab.template(af,{track:ac});var ah=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){var aj=$('select[name="regions"] option:selected').val(),al,ai=new x.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),ak=ab.map($(".bookmark"),function(am){return new x.GenomeRegion({from_str:$(am).children(".position").text()})});if(aj==="cur"){al=[ai]}else{if(aj==="bookmarks"){al=ak}else{al=[ai].concat(ak)}}hide_modal();window.location.href=galaxy_paths.get("sweepster_url")+"?"+$.param({dataset_id:ac.dataset_id,hda_ldda:ac.hda_ldda,regions:JSON.stringify(new Backbone.Collection(al).toJSON())})},ag=function(ai){if((ai.keyCode||ai.which)===27){ah()}else{if((ai.keyCode||ai.which)===13){ad()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",ae,{No:ah,Yes:ad})}},r.prototype.action_icons_def[2]],can_draw:function(){if(this.dataset_id&&r.prototype.can_draw.call(this)){return true}return false},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ac=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ac)}this.name_div=$("<div/>").addClass("track-name").appendTo(ac).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ac},on_resize:function(){},add_resize_handle:function(){var ac=this;var af=false;var ae=false;var ad=$("<div class='track-resize'>");$(ac.container_div).hover(function(){if(ac.content_visible){af=true;ad.show()}},function(){af=false;if(!ae){ad.hide()}});ad.hide().bind("dragstart",function(ag,ah){ae=true;ah.original_height=$(ac.content_div).height()}).bind("drag",function(ah,ai){var ag=Math.min(Math.max(ai.original_height+ai.deltaY,ac.min_height_px),ac.max_height_px);$(ac.tiles_div).css("height",ag);ac.visible_height_px=(ac.max_height_px===ag?0:ag);ac.on_resize()}).bind("dragend",function(ag,ah){ac.tile_cache.clear();ae=false;if(!af){ad.hide()}ac.config.values.height=ac.visible_height_px;ac.changed()}).appendTo(ac.container_div)},set_display_modes:function(af,ai){this.display_modes=af;this.mode=(ai?ai:(this.config&&this.config.values.mode?this.config.values.mode:this.display_modes[0]));this.action_icons.mode_icon.attr("title","Set display mode (now: "+this.mode+")");var ad=this,ag={};for(var ae=0,ac=ad.display_modes.length;ae<ac;ae++){var ah=ad.display_modes[ae];ag[ah]=function(aj){return function(){ad.change_mode(aj);ad.icons_div.show();ad.container_div.mouseleave(function(){ad.icons_div.hide()})}}(ah)}make_popupmenu(this.action_icons.mode_icon,ag)},build_action_icons:function(){r.prototype.build_action_icons.call(this,this.action_icons_def);if(this.display_modes!==undefined){this.set_display_modes(this.display_modes)}},hide_contents:function(){this.tiles_div.hide();this.container_div.find(".yaxislabel, .track-resize").hide()},show_contents:function(){this.tiles_div.show();this.container_div.find(".yaxislabel, .track-resize").show();this.request_draw()},get_type:function(){if(this instanceof X){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof h){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof R){return"VcfTrack"}else{if(this instanceof f){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(ae){var ad=this;ad.enabled=false;ad.tile_cache.clear();ad.data_manager.clear();ad.content_div.css("height","auto");ad.tiles_div.text("").children().remove();ad.container_div.removeClass("nodata error pending");if(!ad.dataset_id){return}var ac=$.Deferred(),af={hda_ldda:ad.hda_ldda,data_type:this.dataset_check_type,chrom:ad.view.chrom,retry:ae};$.getJSON(this.dataset.url(),af,function(ag){if(!ag||ag==="error"||ag.kind==="error"){ad.container_div.addClass("error");ad.tiles_div.text(o);if(ag.message){ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ag.message+"</pre>",{Close:hide_modal})}));ad.tiles_div.append($("<span/>").text(" "));ad.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ad.init(true)}))}}else{if(ag==="no converter"){ad.container_div.addClass("error");ad.tiles_div.text(J)}else{if(ag==="no data"||(ag.data!==undefined&&(ag.data===null||ag.data.length===0))){ad.container_div.addClass("nodata");ad.tiles_div.text(E)}else{if(ag==="pending"){ad.container_div.addClass("pending");ad.tiles_div.html(v);setTimeout(function(){ad.init()},ad.data_query_wait)}else{if(ag==="data"||ag.status==="data"){if(ag.valid_chroms){ad.valid_chroms=ag.valid_chroms;ad.update_icons()}ad.tiles_div.text(U);if(ad.view.chrom){ad.tiles_div.text("");ad.tiles_div.css("height",ad.visible_height_px+"px");ad.enabled=true;$.when(ad.predraw_init()).done(function(){ac.resolve();ad.container_div.removeClass("nodata error pending");ad.request_draw()})}else{ac.resolve()}}}}}}});this.update_icons();return ac},predraw_init:function(){},get_drawables:function(){return this}});var M=function(ae,ad,af){g.call(this,ae,ad,af);var ac=this;m(ac.container_div,ac.drag_handle_class,".group",ac);this.filters_manager=new i.FiltersManager(this,("filters" in af?af.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=("tool" in af&&af.tool?new s(this,af.tool,af.tool_state):null);this.tile_cache=new x.Cache(Q);if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){this.dynamic_tool_div=this.tool.parent_div;this.header_div.after(this.dynamic_tool_div)}}this.tiles_div=$("<div/>").addClass("tiles").appendTo(this.content_div);this.overlay_div=$("<div/>").addClass("overlay").appendTo(this.content_div);if(af.mode){this.change_mode(af.mode)}};q(M.prototype,r.prototype,g.prototype,{action_icons_def:g.prototype.action_icons_def.concat([{name:"show_more_rows_icon",title:"To minimize track height, not all feature rows are displayed. Click to display more rows.",css_class:"exclamation",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.slotters[ac.view.resolution_px_b].max_rows*=2;ac.request_draw(true)},hide:true}]),copy:function(ac){var ad=this.to_dict();q(ad,{data_manager:this.data_manager});var ae=new this.constructor(this.view,ac,ad);ae.change_mode(this.mode);ae.enabled=this.enabled;return ae},set_filters_manager:function(ac){this.filters_manager=ac;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,hda_ldda:this.hda_ldda,dataset_id:this.dataset_id,prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},change_mode:function(ad){var ac=this;ac.mode=ad;ac.config.values.mode=ad;ac.tile_cache.clear();ac.request_draw();this.action_icons.mode_icon.attr("title","Set display mode (now: "+ac.mode+")");return ac},update_icons:function(){var ac=this;if(ac.filters_available){ac.action_icons.filters_icon.show()}else{ac.action_icons.filters_icon.hide()}if(ac.tool){ac.action_icons.tools_icon.show();ac.action_icons.param_space_viz_icon.show()}else{ac.action_icons.tools_icon.hide();ac.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ad,ac){return ad+"_"+ac},request_draw:function(ad,ac){this.view.request_redraw(false,ad,ac,this)},before_draw:function(){},_draw:function(ad,ao){if(!this.can_draw()){return}var al=this.view.low,ah=this.view.high,aj=ah-al,ae=this.view.container.width(),aq=this.view.resolution_px_b,ag=this.view.resolution_b_px;if(this.is_overview){al=this.view.max_low;ah=this.view.max_high;ag=(view.max_high-view.max_low)/ae;aq=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ac=Math.floor(al/(ag*S)),ak=true,ap=[],ai=function(ar){return(ar&&"track" in ar)};while((ac*S*ag)<ah){var am=this._get_tile_bounds(ac,ag),an=this.draw_helper(ad,am,ag,this.tiles_div,aq);if(ai(an)){ap.push(an)}else{ak=false}ac+=1}if(!ao){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;if(ak){this.tiles_div.children(".remove").remove();af.postdraw_actions(ap,ae,aq,ao)}},postdraw_actions:function(ad,ae,ag,ac){var af=ab.find(ad,function(ah){return ah.has_icons});if(af){ab.each(ad,function(ah){if(!ah.has_icons){ah.html_elt.css("padding-top",D)}})}},draw_helper:function(ac,af,ar,ah,ai,ao){var an=this,aw=this._gen_tile_cache_key(ai,af);if(!ao){ao={}}var av=(ac?undefined:an.tile_cache.get_elt(aw));if(av){an.show_tile(av,ah,ai);return av}var al=true;var at=an.data_manager.get_data(af,an.mode,ar,an.data_url_extra_params);if(V(at)){al=false}var aj;if(view.reference_track&&ai>view.canvas_manager.char_width_px){aj=view.reference_track.data_manager.get_data(af,an.mode,ar,view.reference_track.data_url_extra_params);if(V(aj)){al=false}}if(al){q(at,ao.more_tile_data);var ak=an.mode;if(ak==="Auto"){ak=an.get_mode(at);an.update_auto_mode(ak)}var ae=an.view.canvas_manager.new_canvas(),au=af.get("start"),ad=af.get("end"),ap=Math.ceil((ad-au)*ai)+an.left_offset,am=an.get_canvas_height(at,ak,ai,ap);ae.width=ap;ae.height=am;var aq=ae.getContext("2d");aq.translate(this.left_offset,0);var av=an.draw_tile(at,aq,ak,ar,af,ai,aj);if(av!==undefined){an.tile_cache.set_elt(aw,av);an.show_tile(av,ah,ai)}return av}var ag=$.Deferred();$.when(at,aj).then(function(){view.request_redraw(false,false,false,an);ag.resolve()});return ag},get_canvas_height:function(ac,ae,af,ad){return this.visible_height_px},draw_tile:function(ac,ad,ah,af,ag,ai,ae){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(ae,ah,ai){var ad=this,ac=ae.html_elt;ae.predisplay_actions();var ag=(ae.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ag-=this.left_offset}ac.css({position:"absolute",top:0,left:ag});if(ac.hasClass("remove")){ac.removeClass("remove")}else{ah.append(ac)}ae.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,ae.html_elt.height());ae.html_elt.parent().children().css("height",this.max_height_px+"px");var af=this.max_height_px;if(this.visible_height_px!==0){af=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",af+"px")},_get_tile_bounds:function(ac,ad){var af=Math.floor(ac*S*ad),ag=Math.ceil(S*ad),ae=(af+ag<=this.view.max_high?af+ag:this.view.max_high);return new x.GenomeRegion({chrom:this.view.chrom,start:af,end:ae})},tool_region_and_parameters_str:function(ae){var ac=this,ad=(ae!==undefined?ae.toString():"all");return" - region=["+ad+"], parameters=["+ac.tool.get_param_values().join(", ")+"]"},data_and_mode_compatible:function(ac,ad){return true},can_subset:function(ac){return false},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state";this.normal_postdraw_actions=this.postdraw_actions;this.postdraw_actions=function(ae,af,ah,ac){var ad=this;ad.normal_postdraw_actions(ae,af,ah,ac);ad.dataset_check_type="converted_datasets_state";ad.data_query_wait=K;var ag=new l.ServerStateDeferred({url:ad.dataset_state_url,url_params:{dataset_id:ad.dataset_id,hda_ldda:ad.hda_ldda},interval:ad.data_query_wait,success_fn:function(ai){return ai!=="pending"}});$.when(ag.go()).then(function(){ad.data_manager.set("data_type","data")});ad.postdraw_actions=ad.normal_postdraw_actions}}});var X=function(ad,ac){var ae={resize:false};g.call(this,ad,ac,ae);this.container_div.addClass("label-track")};q(X.prototype,g.prototype,{build_header_div:function(){},init:function(){this.enabled=true},_draw:function(){var ae=this.view,af=ae.high-ae.low,ai=Math.floor(Math.pow(10,Math.floor(Math.log(af)/Math.log(10)))),ac=Math.floor(ae.low/ai)*ai,ag=this.view.container.width(),ad=$("<div style='position: relative; height: 1.3em;'></div>");while(ac<ae.high){var ah=(ac-ae.low)/af*ag;ad.append($("<div class='label'>"+commatize(ac)+"</div>").css({position:"absolute",left:ah-1}));ac+=ai}this.content_div.children(":first").remove();this.content_div.append(ad)}});var f=function(ad,ac,ag){M.call(this,ad,ac,ag);this.drawables=[];this.left_offset=0;if("drawables" in ag){var af;for(var ae=0;ae<ag.drawables.length;ae++){af=ag.drawables[ae];this.drawables[ae]=p(af,ad,null);if(af.left_offset>this.left_offset){this.left_offset=af.left_offset}}this.enabled=true}if(this.drawables.length!==0){this.set_display_modes(this.drawables[0].display_modes,this.drawables[0].mode)}this.update_icons();this.obj_type="CompositeTrack"};q(f.prototype,M.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ac){$(".bs-tooltip").remove();ac.show_group()}}].concat(M.prototype.action_icons_def),to_dict:z.prototype.to_dict,add_drawable:z.prototype.add_drawable,unpack_drawables:z.prototype.unpack_drawables,change_mode:function(ac){M.prototype.change_mode.call(this,ac);for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].change_mode(ac)}},init:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].init())}var ac=this;$.when.apply($,ae).then(function(){ac.enabled=true;ac.request_draw()})},update_icons:function(){this.action_icons.filters_icon.hide();this.action_icons.tools_icon.hide();this.action_icons.param_space_viz_icon.hide()},can_draw:r.prototype.can_draw,draw_helper:function(ad,ah,av,aj,al,at){var aq=this,aB=this._gen_tile_cache_key(al,ah);if(!at){at={}}var aA=(ad?undefined:aq.tile_cache.get_elt(aB));if(aA){aq.show_tile(aA,aj,al);return aA}var ak=[],aq,ao=true,aw,am;for(var ax=0;ax<this.drawables.length;ax++){aq=this.drawables[ax];aw=aq.data_manager.get_data(ah,aq.mode,av,aq.data_url_extra_params);if(V(aw)){ao=false}ak.push(aw);am=null;if(view.reference_track&&al>view.canvas_manager.char_width_px){am=view.reference_track.data_manager.get_data(ah,aq.mode,av,view.reference_track.data_url_extra_params);if(V(am)){ao=false}}ak.push(am)}if(ao){q(aw,at.more_tile_data);this.tile_predraw_init();var ag=aq.view.canvas_manager.new_canvas(),ay=ah.get("start"),ae=ah.get("end"),az=0,ar=Math.ceil((ae-ay)*al)+this.left_offset,ap=0,af=[],ax;var ac=0;for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];var an=aq.mode;if(an==="Auto"){an=aq.get_mode(aw);aq.update_auto_mode(an)}af.push(an);ac=aq.get_canvas_height(aw,an,al,ar);if(ac>ap){ap=ac}}ag.width=ar;ag.height=(at.height?at.height:ap);az=0;var au=ag.getContext("2d");au.translate(this.left_offset,0);au.globalAlpha=0.5;au.globalCompositeOperation="source-over";for(ax=0;ax<this.drawables.length;ax++,az+=2){aq=this.drawables[ax];aw=ak[az];am=ak[az+1];aA=aq.draw_tile(aw,au,af[ax],av,ah,al,am)}this.tile_cache.set_elt(aB,aA);this.show_tile(aA,aj,al);return aA}var ai=$.Deferred(),aq=this;$.when.apply($,ak).then(function(){view.request_redraw(false,false,false,aq);ai.resolve()});return ai},show_group:function(){var af=new P(this.view,this.container,{name:this.name}),ac;for(var ae=0;ae<this.drawables.length;ae++){ac=this.drawables[ae];ac.update_icons();af.add_drawable(ac);ac.container=af;af.content_div.append(ac.container_div)}var ad=this.container.replace_drawable(this,af,true);af.request_draw()},tile_predraw_init:function(){var af=Number.MAX_VALUE,ac=-af,ad;for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];if(ad instanceof h){if(ad.prefs.min_value<af){af=ad.prefs.min_value}if(ad.prefs.max_value>ac){ac=ad.prefs.max_value}}}for(var ae=0;ae<this.drawables.length;ae++){ad=this.drawables[ae];ad.prefs.min_value=af;ad.prefs.max_value=ac}},postdraw_actions:function(ae,ah,aj,ad){M.prototype.postdraw_actions.call(this,ae,ah,aj,ad);var ag=-1;for(var af=0;af<ae.length;af++){var ac=ae[af].html_elt.find("canvas").height();if(ac>ag){ag=ac}}for(var af=0;af<ae.length;af++){var ai=ae[af];if(ai.html_elt.find("canvas").height()!==ag){this.draw_helper(true,ai.index,ai.resolution,ai.html_elt.parent(),aj,{height:ag});ai.html_elt.remove()}}}});var B=function(ac){M.call(this,ac,{content_div:ac.top_labeltrack},{resize:false});ac.reference_track=this;this.left_offset=200;this.visible_height_px=12;this.container_div.addClass("reference-track");this.content_div.css("background","none");this.content_div.css("min-height","0px");this.content_div.css("border","none");this.data_url=reference_url+"/"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new x.ReferenceTrackDataManager({data_url:this.data_url});this.hide_contents()};q(B.prototype,r.prototype,M.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},can_draw:r.prototype.can_draw,draw_helper:function(ae,af,ac,ag,ah,ad){if(ah>this.view.canvas_manager.char_width_px){return M.prototype.draw_helper.call(this,ae,af,ac,ag,ah,ad)}else{this.hide_contents();return null}},draw_tile:function(ak,al,ag,af,ai,am){var ae=this;if(am>this.view.canvas_manager.char_width_px){if(ak.data===null){this.hide_contents();return}var ad=al.canvas;al.font=al.canvas.manager.default_font;al.textAlign="center";ak=ak.data;for(var ah=0,aj=ak.length;ah<aj;ah++){var ac=Math.floor(ah*am);al.fillText(ak[ah],ac,10)}this.show_contents();return new b(ae,ai,af,ad,ak)}this.hide_contents()}});var h=function(ae,ad,af){var ac=this;this.display_modes=["Histogram","Line","Filled","Intensity"];this.mode="Histogram";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Color",type:"color",default_value:l.get_random_color()},{key:"min_value",label:"Min Value",type:"float",default_value:undefined},{key:"max_value",label:"Max Value",type:"float",default_value:undefined},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:32,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(h.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;$("#linetrack_"+this.dataset_id+"_minval").text(this.prefs.min_value);this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;$("#linetrack_"+this.dataset_id+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.request_draw()},predraw_init:function(){var ac=this;ac.vertical_range=undefined;return $.getJSON(ac.dataset.url(),{data_type:"data",stats:true,chrom:ac.view.chrom,low:0,high:ac.view.max_high,hda_ldda:ac.hda_ldda},function(ad){ac.container_div.addClass("line-track");var ag=ad.data;if(isNaN(parseFloat(ac.prefs.min_value))||isNaN(parseFloat(ac.prefs.max_value))){var ae=ag.min,ai=ag.max;ae=Math.floor(Math.min(0,Math.max(ae,ag.mean-2*ag.sd)));ai=Math.ceil(Math.max(0,Math.min(ai,ag.mean+2*ag.sd)));ac.prefs.min_value=ae;ac.prefs.max_value=ai;$("#track_"+ac.dataset_id+"_minval").val(ac.prefs.min_value);$("#track_"+ac.dataset_id+"_maxval").val(ac.prefs.max_value)}ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.total_frequency=ag.total_frequency;ac.container_div.find(".yaxislabel").remove();var ah=$("<div/>").text(W(ac.prefs.min_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_min_value(aj)}},help_text:"Set min value"}).addClass("yaxislabel bottom").attr("id","linetrack_"+ac.dataset_id+"_minval").prependTo(ac.container_div),af=$("<div/>").text(W(ac.prefs.max_value,3)).make_text_editable({num_cols:6,on_finish:function(aj){$(".bs-tooltip").remove();var aj=parseFloat(aj);if(!isNaN(aj)){ac.set_max_value(aj)}},help_text:"Set max value"}).addClass("yaxislabel top").attr("id","linetrack_"+ac.dataset_id+"_maxval").prependTo(ac.container_div)})},draw_tile:function(al,aj,ae,ad,ag,ak){var ac=aj.canvas,af=ag.get("start"),ai=ag.get("end"),ah=new L.LinePainter(al.data,af,ai,this.prefs,ae);ah.draw(aj,ac.width,ac.height,ak);return new b(this,ag,ad,ac,al.data)},can_subset:function(ac){return false}});var t=function(ae,ad,af){var ac=this;this.display_modes=["Heatmap"];this.mode="Heatmap";M.call(this,ae,ad,af);this.hda_ldda=af.hda_ldda;this.dataset_id=af.dataset_id;this.original_dataset_id=this.dataset_id;this.left_offset=0;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"pos_color",label:"Positive Color",type:"color",default_value:"#FF8C00"},{key:"neg_color",label:"Negative Color",type:"color",default_value:"#4169E1"},{key:"min_value",label:"Min Value",type:"float",default_value:-1},{key:"max_value",label:"Max Value",type:"float",default_value:1},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:500,hidden:true}],saved_values:af.prefs,onchange:function(){ac.set_name(ac.prefs.name);ac.vertical_range=ac.prefs.max_value-ac.prefs.min_value;ac.set_min_value(ac.prefs.min_value);ac.set_max_value(ac.prefs.max_value)}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.vertical_range=this.config.values.max_value-this.config.values.min_value};q(t.prototype,r.prototype,M.prototype,{on_resize:function(){this.request_draw(true)},set_min_value:function(ac){this.prefs.min_value=ac;this.tile_cache.clear();this.request_draw()},set_max_value:function(ac){this.prefs.max_value=ac;this.tile_cache.clear();this.request_draw()},draw_tile:function(ac,ae,ai,ag,ah,aj){var af=ae.canvas,ad=new L.DiagonalHeatmapPainter(ac.data,ah.get("start"),ah.get("end"),this.prefs,ai);ad.draw(ae,af.width,af.height,aj);return new b(this,ah,ag,af,ac.data)}});var c=function(af,ae,ah){var ad=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];M.call(this,af,ae,ah);var ag=l.get_random_color(),ac=l.get_random_color([ag,"#FFFFFF"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true,help:"Show the number of items in each bin when drawing summary histogram"},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"connector_style",label:"Connector style",type:"select",default_value:"fishbones",options:[{label:"Line with arrows",value:"fishbone"},{label:"Arcs",value:"arcs"}]},{key:"mode",type:"string",default_value:this.mode,hidden:true},{key:"height",type:"int",default_value:this.visible_height_px,hidden:true}],saved_values:ah.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.tile_cache.clear();ad.set_painter_from_config();ad.request_draw()}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");this.hda_ldda=ah.hda_ldda;this.dataset_id=ah.dataset_id;this.original_dataset_id=ah.dataset_id;this.show_labels_scale=0.001;this.showing_details=false;this.summary_draw_height=30;this.slotters={};this.start_end_dct={};this.left_offset=200;this.set_painter_from_config()};q(c.prototype,r.prototype,M.prototype,{set_dataset:function(ac){this.dataset_id=ac.get("id");this.hda_ldda=ac.get("hda_ldda");this.dataset=ac;this.data_manager.set("dataset",ac)},set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},before_draw:function(){this.max_height_px=0},postdraw_actions:function(ar,am,ah,ag){M.prototype.postdraw_actions.call(this,ar,ag);var al=this,ao;if(al.mode==="Coverage"){var ad=-1;for(ao=0;ao<ar.length;ao++){var an=ar[ao].max_val;if(an>ad){ad=an}}for(ao=0;ao<ar.length;ao++){var au=ar[ao];if(au.max_val!==ad){au.html_elt.remove();al.draw_helper(true,au.index,au.resolution,au.html_elt.parent(),ah,{more_tile_data:{max:ad}})}}}if(al.filters_manager){var ai=al.filters_manager.filters;for(var aq=0;aq<ai.length;aq++){ai[aq].update_ui_elt()}var at=false,ac,aj;for(ao=0;ao<ar.length;ao++){if(ar[ao].data.length){ac=ar[ao].data[0];for(var aq=0;aq<ai.length;aq++){aj=ai[aq];if(aj.applies_to(ac)&&aj.min!==aj.max){at=true;break}}}}if(al.filters_available!==at){al.filters_available=at;if(!al.filters_available){al.filters_manager.hide()}al.update_icons()}}this.container_div.find(".yaxislabel").remove();var af=ar[0];if(af instanceof j){var ak=(this.prefs.histogram_max?this.prefs.histogram_max:af.max_val),ae=$("<div/>").text(ak).make_text_editable({num_cols:12,on_finish:function(av){$(".bs-tooltip").remove();var av=parseFloat(av);al.prefs.histogram_max=(!isNaN(av)?av:null);al.tile_cache.clear();al.request_draw()},help_text:"Set max value; leave blank to use default"}).addClass("yaxislabel top").css("color",this.prefs.label_color);this.container_div.prepend(ae)}if(af instanceof O){var ap=true;for(ao=0;ao<ar.length;ao++){if(!ar[ao].all_slotted){ap=false;break}}if(!ap){this.action_icons.show_more_rows_icon.show()}else{this.action_icons.show_more_rows_icon.hide()}}else{this.action_icons.show_more_rows_icon.hide()}},update_auto_mode:function(ac){var ac;if(this.mode==="Auto"){if(ac==="no_detail"){ac="feature spans"}else{if(ac==="summary_tree"){ac="coverage histogram"}}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ac+")")}},incremental_slots:function(ag,ac,af){var ad=this.view.canvas_manager.dummy_context,ae=this.slotters[ag];if(!ae||(ae.mode!==af)){ae=new (u.FeatureSlotter)(ag,af,A,function(ah){return ad.measureText(ah)});this.slotters[ag]=ae}return ae.slot_features(ac)},get_mode:function(ac){if(ac.dataset_type==="summary_tree"){mode="summary_tree"}else{if(ac.extra_info==="no_detail"||this.is_overview){mode="no_detail"}else{if(this.view.high-this.view.low>I){mode="Squish"}else{mode="Pack"}}}return mode},get_canvas_height:function(ac,ag,ah,ad){if(ag==="summary_tree"||ag==="Coverage"){return this.summary_draw_height}else{var af=this.incremental_slots(ah,ac.data,ag);var ae=new (this.painter)(null,null,null,this.prefs,ag);return Math.max(aa,ae.get_required_height(af,ad))}},draw_tile:function(am,aq,ao,ar,af,aj,ae){var ap=this,ad=aq.canvas,ay=af.get("start"),ac=af.get("end"),ag=this.left_offset;if(ao==="summary_tree"||ao==="Coverage"){var aA=new L.SummaryTreePainter(am,ay,ac,this.prefs);aA.draw(aq,ad.width,ad.height,aj);return new j(ap,af,ar,ad,am.data,am.max)}var ai=[],an=this.slotters[aj].slots;all_slotted=true;if(am.data){var ak=this.filters_manager.filters;for(var at=0,av=am.data.length;at<av;at++){var ah=am.data[at];var au=false;var al;for(var ax=0,aC=ak.length;ax<aC;ax++){al=ak[ax];al.update_attrs(ah);if(!al.keep(ah)){au=true;break}}if(!au){ai.push(ah);if(!(ah[0] in an)){all_slotted=false}}}}var aB=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null);var az=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null);var aA=new (this.painter)(ai,ay,ac,this.prefs,ao,aB,az,ae);var aw=null;aq.fillStyle=this.prefs.block_color;aq.font=aq.canvas.manager.default_font;aq.textAlign="right";if(am.data){aw=aA.draw(aq,ad.width,ad.height,aj,an);aw.translation=-ag}return new O(ap,af,ar,ad,am.data,aj,ao,am.message,all_slotted,aw)},data_and_mode_compatible:function(ac,ad){if(ad==="Auto"){return true}else{if(ad==="Coverage"){return ac.dataset_type==="summary_tree"}else{if(ac.extra_info==="no_detail"||ac.dataset_type==="summary_tree"){return false}else{return true}}}},can_subset:function(ac){if(ac.dataset_type==="summary_tree"||ac.message||ac.extra_info==="no_detail"){return false}return true}});var R=function(ad,ac,ae){c.call(this,ad,ac,ae);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block color",type:"color",default_value:l.get_random_color()},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ae.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter};q(R.prototype,r.prototype,M.prototype,c.prototype);var T=function(ae,ad,ag){c.call(this,ae,ad,ag);var af=l.get_random_color(),ac=l.get_random_color([af,"#ffffff"]);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"block_color",label:"Block and sense strand color",type:"color",default_value:af},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ac},{key:"label_color",label:"Label color",type:"color",default_value:"black"},{key:"show_insertions",label:"Show insertions",type:"bool",default_value:false},{key:"show_differences",label:"Show differences only",type:"bool",default_value:true},{key:"show_counts",label:"Show summary counts",type:"bool",default_value:true},{key:"histogram_max",label:"Histogram maximum",type:"float",default_value:null,help:"Clear value to set automatically"},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.tile_cache.clear();this.track.request_draw()}});this.prefs=this.config.values;this.painter=L.ReadPainter;this.update_icons()};q(T.prototype,r.prototype,M.prototype,c.prototype);var d={LineTrack:h,FeatureTrack:c,VcfTrack:R,ReadTrack:T,DiagonalHeatmapTrack:t,CompositeTrack:f,DrawableGroup:P};var p=function(ae,ad,ac){if("copy" in ae){return ae.copy(ac)}else{var af=ae.obj_type;if(!af){af=ae.track_type}return new d[af](ad,ac,ae)}};return{TracksterView:Z,DrawableGroup:P,LineTrack:h,FeatureTrack:c,DiagonalHeatmapTrack:t,ReadTrack:T,VcfTrack:R,CompositeTrack:f,object_from_template:p}});
\ No newline at end of file
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/packed/viz/visualization.js
--- a/static/scripts/packed/viz/visualization.js
+++ b/static/scripts/packed/viz/visualization.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,init_data:null,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<=w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}return u},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",p.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
+define(["libs/underscore","mvc/data","viz/trackster/util","utils/config"],function(s,i,l,p){var a=function(u,x,w,v){$.ajax({url:u,data:w,error:function(){alert("Grid failed")},success:function(y){show_modal("Select datasets for new tracks",y,{Cancel:function(){hide_modal()},Add:function(){var z=[];$("input[name=id]:checked,input[name=ldda_ids]:checked").each(function(){var A={data_type:"track_config",hda_ldda:"hda"},B=$(this).val();if($(this).attr("name")!=="id"){A.hda_ldda="ldda"}z[z.length]=$.ajax({url:x+"/"+B,data:A,dataType:"json"})});$.when.apply($,z).then(function(){var A=(arguments[0] instanceof Array?$.map(arguments,function(B){return B[0]}):[arguments[0]]);v(A)});hide_modal()}})}})};var j=function(u){return("isResolved" in u)};var f=function(u){this.default_font=u!==undefined?u:"9px Monaco, Lucida Console, monospace";this.dummy_canvas=this.new_canvas();this.dummy_context=this.dummy_canvas.getContext("2d");this.dummy_context.font=this.default_font;this.char_width_px=this.dummy_context.measureText("A").width;this.patterns={};this.load_pattern("right_strand","/visualization/strand_right.png");this.load_pattern("left_strand","/visualization/strand_left.png");this.load_pattern("right_strand_inv","/visualization/strand_right_inv.png");this.load_pattern("left_strand_inv","/visualization/strand_left_inv.png")};s.extend(f.prototype,{load_pattern:function(u,y){var v=this.patterns,w=this.dummy_context,x=new Image();x.src=galaxy_paths.attributes.image_path+y;x.onload=function(){v[u]=w.createPattern(x,"repeat")}},get_pattern:function(u){return this.patterns[u]},new_canvas:function(){var u=$("<canvas/>")[0];if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(u)}u.manager=this;return u}});var q=Backbone.Model.extend({defaults:{num_elements:20,obj_cache:null,key_ary:null},initialize:function(u){this.clear()},get_elt:function(v){var w=this.attributes.obj_cache,x=this.attributes.key_ary,u=x.indexOf(v);if(u!==-1){if(w[v].stale){x.splice(u,1);delete w[v]}else{this.move_key_to_end(v,u)}}return w[v]},set_elt:function(v,x){var y=this.attributes.obj_cache,z=this.attributes.key_ary,w=this.attributes.num_elements;if(!y[v]){if(z.length>=w){var u=z.shift();delete y[u]}z.push(v)}y[v]=x;return x},move_key_to_end:function(v,u){this.attributes.key_ary.splice(u,1);this.attributes.key_ary.push(v)},clear:function(){this.attributes.obj_cache={};this.attributes.key_ary=[]},size:function(){return this.attributes.key_ary.length},most_recently_added:function(){return this.size()===0?null:this.attributes.key_ary[this.attributes.key_ary.length-1]}});var d=q.extend({defaults:s.extend({},q.prototype.defaults,{dataset:null,genome:null,init_data:null,min_region_size:500,filters_manager:null,data_type:"data",data_mode_compatible:function(u,v){return true},can_subset:function(u){return false}}),initialize:function(u){q.prototype.initialize.call(this);var v=this.get("init_data");if(v){this.add_data(v)}},add_data:function(u){if(this.get("num_elements")<u.length){this.set("num_elements",u.length)}var v=this;s.each(u,function(w){v.set_data(w.region,w)})},data_is_ready:function(){var x=this.get("dataset"),w=$.Deferred(),u=(this.get("data_type")==="raw_data"?"state":this.get("data_type")==="data"?"converted_datasets_state":"error"),v=new l.ServerStateDeferred({ajax_settings:{url:this.get("dataset").url(),data:{hda_ldda:x.get("hda_ldda"),data_type:u},dataType:"json"},interval:5000,success_fn:function(y){return y!=="pending"}});$.when(v.go()).then(function(y){w.resolve(y==="ok"||y==="data")});return w},search_features:function(u){var v=this.get("dataset"),w={query:u,hda_ldda:v.get("hda_ldda"),data_type:"features"};return $.getJSON(v.url(),w)},load_data:function(C,B,v,A){var y=this.get("dataset"),x={data_type:this.get("data_type"),chrom:C.get("chrom"),low:C.get("start"),high:C.get("end"),mode:B,resolution:v,hda_ldda:y.get("hda_ldda")};$.extend(x,A);var E=this.get("filters_manager");if(E){var F=[];var u=E.filters;for(var z=0;z<u.length;z++){F.push(u[z].name)}x.filter_cols=JSON.stringify(F)}var w=this,D=$.getJSON(y.url(),x,function(G){w.set_data(C,G)});this.set_data(C,D);return D},get_data:function(A,z,w,y){var B=this.get_elt(A);if(B&&(j(B)||this.get("data_mode_compatible")(B,z))){return B}var C=this.get("key_ary"),v=this.get("obj_cache"),D,u;for(var x=0;x<C.length;x++){D=C[x];u=new g({from_str:D});if(u.contains(A)){B=v[D];if(j(B)||(this.get("data_mode_compatible")(B,z)&&this.get("can_subset")(B))){this.move_key_to_end(D,x);return B}}}if(A.length()<this.attributes.min_region_size){var E=new g({from_str:this.most_recently_added()});if(!E||(A.get("start")>E.get("start"))){A.set("end",A.get("start")+this.attributes.min_region_size)}else{A.set("start",A.get("end")-this.attributes.min_region_size)}A.set("genome",this.attributes.genome);A.trim()}return this.load_data(A,z,w,y)},set_data:function(v,u){this.set_elt(v,u)},DEEP_DATA_REQ:"deep",BROAD_DATA_REQ:"breadth",get_more_data:function(C,B,x,A,y){var E=this._mark_stale(C);if(!(E&&this.get("data_mode_compatible")(E,B))){console.log("ERROR: problem with getting more data: current data is not compatible");return}var w=C.get("start");if(y===this.DEEP_DATA_REQ){$.extend(A,{start_val:E.data.length+1})}else{if(y===this.BROAD_DATA_REQ){w=(E.max_high?E.max_high:E.data[E.data.length-1][2])+1}}var D=C.copy().set("start",w);var v=this,z=this.load_data(D,B,x,A),u=$.Deferred();this.set_data(C,u);$.when(z).then(function(F){if(F.data){F.data=E.data.concat(F.data);if(F.max_low){F.max_low=E.max_low}if(F.message){F.message=F.message.replace(/[0-9]+/,F.data.length)}}v.set_data(C,F);u.resolve(F)});return u},can_get_more_detailed_data:function(v){var u=this.get_elt(v);return(u.dataset_type==="bigwig"&&u.data.length<8000)},get_more_detailed_data:function(x,z,v,y,w){var u=this._mark_stale(x);if(!u){console.log("ERROR getting more detailed data: no current data");return}if(!w){w={}}if(u.dataset_type==="bigwig"){w.num_samples=1000*y}else{if(u.dataset_type==="summary_tree"){w.level=Math.min(u.level-1,2)}}return this.load_data(x,z,v,w)},_mark_stale:function(v){var u=this.get_elt(v);if(!u){console.log("ERROR: no data to mark as stale: ",this.get("dataset"),v.toString())}u.stale=true;return u},get_genome_wide_data:function(u){var w=this,y=true,x=s.map(u.get("chroms_info").chrom_info,function(A){var z=w.get_elt(new g({chrom:A.chrom,start:0,end:A.len}));if(!z){y=false}return z});if(y){return x}var v=$.Deferred();$.getJSON(this.get("dataset").url(),{data_type:"genome_data"},function(z){w.add_data(z.data);v.resolve(z.data)});return v},get_elt:function(u){return q.prototype.get_elt.call(this,u.toString())},set_elt:function(v,u){return q.prototype.set_elt.call(this,v.toString(),u)}});var n=d.extend({initialize:function(u){var v=new Backbone.Model();v.urlRoot=u.data_url;this.set("dataset",v)},load_data:function(w,x,u,v){if(u>1){return{data:null}}return d.prototype.load_data.call(this,w,x,u,v)}});var c=Backbone.Model.extend({defaults:{name:null,key:null,chroms_info:null},initialize:function(u){this.id=u.dbkey},get_chroms_info:function(){return this.attributes.chroms_info.chrom_info},get_chrom_region:function(u){var v=s.find(this.get_chroms_info(),function(w){return w.chrom===u});return new g({chrom:v.chrom,end:v.len})},get_chrom_len:function(u){return s.find(this.get_chroms_info(),function(v){return v.chrom===u}).len}});var g=Backbone.RelationalModel.extend({defaults:{chrom:null,start:0,end:0,genome:null},initialize:function(v){if(v.from_str){var x=v.from_str.split(":"),w=x[0],u=x[1].split("-");this.set({chrom:w,start:parseInt(u[0],10),end:parseInt(u[1],10)})}},copy:function(){return new g({chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")})},length:function(){return this.get("end")-this.get("start")},toString:function(){return this.get("chrom")+":"+this.get("start")+"-"+this.get("end")},toJSON:function(){return{chrom:this.get("chrom"),start:this.get("start"),end:this.get("end")}},compute_overlap:function(B){var v=this.get("chrom"),A=B.get("chrom"),z=this.get("start"),x=B.get("start"),y=this.get("end"),w=B.get("end"),u;if(v&&A&&v!==A){return g.overlap_results.DIF_CHROMS}if(z<x){if(y<x){u=g.overlap_results.BEFORE}else{if(y<w){u=g.overlap_results.OVERLAP_START}else{u=g.overlap_results.CONTAINS}}}else{if(z>x){if(z>w){u=g.overlap_results.AFTER}else{if(y<=w){u=g.overlap_results.CONTAINED_BY}else{u=g.overlap_results.OVERLAP_END}}}else{u=(y>=w?g.overlap_results.CONTAINS:g.overlap_results.CONTAINED_BY)}}return u},trim:function(u){if(this.attributes.start<0){this.attributes.start=0}if(this.attributes.genome){var v=this.attributes.genome.get_chrom_len(this.attributes.chrom);if(this.attributes.end>v){this.attributes.end=v-1}}return this},contains:function(u){return this.compute_overlap(u)===g.overlap_results.CONTAINS},overlaps:function(u){return s.intersection([this.compute_overlap(u)],[g.overlap_results.DIF_CHROMS,g.overlap_results.BEFORE,g.overlap_results.AFTER]).length===0}},{overlap_results:{DIF_CHROMS:1000,BEFORE:1001,CONTAINS:1002,OVERLAP_START:1003,OVERLAP_END:1004,CONTAINED_BY:1005,AFTER:1006}});var m=Backbone.Collection.extend({model:g});var e=Backbone.RelationalModel.extend({defaults:{region:null,note:""},relations:[{type:Backbone.HasOne,key:"region",relatedModel:g}]});var r=Backbone.Collection.extend({model:e});var t=i.Dataset.extend({initialize:function(u){this.set("id",u.dataset_id);this.set("config",p.ConfigSettingCollection.from_config_dict(u.prefs));this.get("config").add([{key:"name",value:this.get("name")},{key:"color"}]);var v=this.get("preloaded_data");if(v){v=v.data}else{v=[]}this.set("data_manager",new d({dataset:this,init_data:v}))}});var o=Backbone.RelationalModel.extend({defaults:{title:"",type:""},url:galaxy_paths.get("visualization_url"),save:function(){return $.ajax({url:this.url(),type:"POST",dataType:"json",data:{vis_json:JSON.stringify(this)}})}});var k=o.extend({defaults:s.extend({},o.prototype.defaults,{dbkey:"",tracks:null,bookmarks:null,viewport:null}),relations:[{type:Backbone.HasMany,key:"tracks",relatedModel:t}],add_tracks:function(u){this.get("tracks").add(u)}});var b=Backbone.Model.extend({});var h=Backbone.Router.extend({initialize:function(v){this.view=v.view;this.route(/([\w]+)$/,"change_location");this.route(/([\w]+\:[\d,]+-[\d,]+)$/,"change_location");var u=this;u.view.on("navigate",function(w){u.navigate(w)})},change_location:function(u){this.view.go_to(u)}});return{BackboneTrack:t,BrowserBookmark:e,BrowserBookmarkCollection:r,Cache:q,CanvasManager:f,Genome:c,GenomeDataManager:d,GenomeRegion:g,GenomeRegionCollection:m,GenomeVisualization:k,ReferenceTrackDataManager:n,TrackBrowserRouter:h,TrackConfig:b,Visualization:o,select_datasets:a}});
\ No newline at end of file
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -2222,6 +2222,14 @@
obj_dict.data_manager :
new visualization.GenomeDataManager({
dataset: this.dataset,
+ // HACK: simulate 'genome' attributes from view for now.
+ // View should eventually use Genome object.
+ genome: new visualization.Genome({
+ key: view.dbkey,
+ chroms_info: {
+ chrom_info: view.chrom_data
+ }
+ }),
data_mode_compatible: this.data_and_mode_compatible,
can_subset: this.can_subset
}));
diff -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 -r 9852dd712f5c628d1f635fe643f036eb2b930863 static/scripts/viz/visualization.js
--- a/static/scripts/viz/visualization.js
+++ b/static/scripts/viz/visualization.js
@@ -166,21 +166,33 @@
return value;
},
- // Move key to end of cache. Keys are removed from the front, so moving a key to the end
- // delays the key's removal.
+ /**
+ * Move key to end of cache. Keys are removed from the front, so moving a key to the end
+ * delays the key's removal.
+ */
move_key_to_end: function(key, index) {
this.attributes.key_ary.splice(index, 1);
this.attributes.key_ary.push(key);
},
+ /**
+ * Clear all elements from the cache.
+ */
clear: function() {
this.attributes.obj_cache = {};
this.attributes.key_ary = [];
},
- // Returns the number of elements in the cache.
+ /** Returns the number of elements in the cache. */
size: function() {
return this.attributes.key_ary.length;
+ },
+
+ /** Returns key most recently added to cache. */
+ most_recently_added: function() {
+ return this.size() === 0 ? null :
+ // Most recent key is at the end of key array.
+ this.attributes.key_ary[this.attributes.key_ary.length - 1];
}
});
@@ -190,7 +202,9 @@
var GenomeDataManager = Cache.extend({
defaults: _.extend({}, Cache.prototype.defaults, {
dataset: null,
+ genome: null,
init_data: null,
+ min_region_size: 200,
filters_manager: null,
data_type: "data",
data_mode_compatible: function(entry, mode) { return true; },
@@ -356,6 +370,28 @@
}
}
+ // If needed, extend region to make it minimum size.
+ if (region.length() < this.attributes.min_region_size) {
+ // IDEA: alternative heuristic is to find adjacent cache entry to region and use that to extend.
+ // This would prevent bad extensions when zooming in/out while still preserving the behavior
+ // below.
+
+ // Use heuristic to extend region: extend relative to last data request.
+ var last_request = new GenomeRegion({from_str: this.most_recently_added()});
+ if (!last_request || (region.get('start') > last_request.get('start'))) {
+ // This request is after the last request, so extend right.
+ region.set('end', region.get('start') + this.attributes.min_region_size);
+ }
+ else {
+ // This request is after the last request, so extend left.
+ region.set('start', region.get('end') - this.attributes.min_region_size);
+ }
+
+ // Trim region to avoid invalid coordinates.
+ region.set('genome', this.attributes.genome);
+ region.trim();
+ }
+
return this.load_data(region, mode, resolution, extra_params);
},
@@ -574,6 +610,7 @@
* Returns a GenomeRegion object denoting a complete chromosome.
*/
get_chrom_region: function(chr_name) {
+ // FIXME: use findWhere in underscore 1.4
var chrom_info = _.find(this.get_chroms_info(), function(chrom_info) {
return chrom_info.chrom === chr_name;
});
@@ -581,6 +618,14 @@
chrom: chrom_info.chrom,
end: chrom_info.len
});
+ },
+
+ /** Returns the length of a chromosome. */
+ get_chrom_len: function(chr_name) {
+ // FIXME: use findWhere in underscore 1.4
+ return _.find(this.get_chroms_info(), function(chrom_info) {
+ return chrom_info.chrom === chr_name;
+ }).len;
}
});
@@ -591,7 +636,8 @@
defaults: {
chrom: null,
start: 0,
- end: 0
+ end: 0,
+ genome: null
},
/**
@@ -645,24 +691,24 @@
first_end = this.get('end'), second_end = a_region.get('end'),
overlap;
- // Look at chroms.
+ // Compare chroms.
if (first_chrom && second_chrom && first_chrom !== second_chrom) {
return GenomeRegion.overlap_results.DIF_CHROMS;
}
- // Look at regions.
+ // Compare regions.
if (first_start < second_start) {
if (first_end < second_start) {
overlap = GenomeRegion.overlap_results.BEFORE;
}
- else if (first_end <= second_end) {
+ else if (first_end < second_end) {
overlap = GenomeRegion.overlap_results.OVERLAP_START;
}
- else { // first_end > second_end
+ else { // first_end >= second_end
overlap = GenomeRegion.overlap_results.CONTAINS;
}
}
- else { // first_start >= second_start
+ else if (first_start > second_start) {
if (first_start > second_end) {
overlap = GenomeRegion.overlap_results.AFTER;
}
@@ -673,9 +719,34 @@
overlap = GenomeRegion.overlap_results.OVERLAP_END;
}
}
+ else { // first_start === second_start
+ overlap = (first_end >= second_end ?
+ GenomeRegion.overlap_results.CONTAINS :
+ GenomeRegion.overlap_results.CONTAINED_BY);
+ }
return overlap;
},
+
+ /**
+ * Trim a region to match genome's constraints.
+ */
+ trim: function(genome) {
+ // Assume that all chromosome/contigs start at 0.
+ if (this.attributes.start < 0) {
+ this.attributes.start = 0;
+ }
+
+ // Only try to trim the end if genome is set.
+ if (this.attributes.genome) {
+ var chrom_len = this.attributes.genome.get_chrom_len(this.attributes.chrom);
+ if (this.attributes.end > chrom_len) {
+ this.attributes.end = chrom_len - 1;
+ }
+ }
+
+ return this;
+ },
/**
* Returns true if this region contains a given region.
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: natefoo: Properly handle subdirectory collection in a job output's extra_files_path.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ddb55ff5fd1c/
changeset: ddb55ff5fd1c
user: natefoo
date: 2013-02-19 16:07:14
summary: Properly handle subdirectory collection in a job output's extra_files_path.
affected #: 1 file
diff -r 90f3b97fba53d68f955ddce9de97d12e10763b45 -r ddb55ff5fd1cdb5c2510eef55ab8d427c9e54003 lib/galaxy/tools/__init__.py
--- a/lib/galaxy/tools/__init__.py
+++ b/lib/galaxy/tools/__init__.py
@@ -2635,19 +2635,26 @@
"""
for name, hda in output.items():
temp_file_path = os.path.join( job_working_directory, "dataset_%s_files" % ( hda.dataset.id ) )
+ extra_dir = None
try:
- a_files = os.listdir( temp_file_path )
- if len( a_files ) > 0:
- for f in a_files:
+ # This skips creation of directories - object store
+ # automatically creates them. However, empty directories will
+ # not be created in the object store at all, which might be a
+ # problem.
+ for root, dirs, files in os.walk( temp_file_path ):
+ extra_dir = root.replace(job_working_directory, '', 1).lstrip(os.path.sep)
+ for f in files:
self.app.object_store.update_from_file(hda.dataset,
- extra_dir="dataset_%d_files" % hda.dataset.id,
+ extra_dir=extra_dir,
alt_name = f,
- file_name = os.path.join(temp_file_path, f),
+ file_name = os.path.join(root, f),
create = True,
preserve_symlinks = True )
- # Clean up after being handled by object store.
- # FIXME: If the object (e.g., S3) becomes async, this will
- # cause issues so add it to the object store functionality?
+ # Clean up after being handled by object store.
+ # FIXME: If the object (e.g., S3) becomes async, this will
+ # cause issues so add it to the object store functionality?
+ if extra_dir is not None:
+ # there was an extra_files_path dir, attempt to remove it
shutil.rmtree(temp_file_path)
except Exception, e:
log.debug( "Error in collect_associated_files: %s" % ( e ) )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Small fixes for trackster resolution calculation.
by Bitbucket 19 Feb '13
by Bitbucket 19 Feb '13
19 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/90f3b97fba53/
changeset: 90f3b97fba53
user: jgoecks
date: 2013-02-19 14:56:32
summary: Small fixes for trackster resolution calculation.
affected #: 1 file
diff -r 1f073bb32539ea9d978c04a892a36d995561cb30 -r 90f3b97fba53d68f955ddce9de97d12e10763b45 static/scripts/viz/trackster/tracks.js
--- a/static/scripts/viz/trackster/tracks.js
+++ b/static/scripts/viz/trackster/tracks.js
@@ -1427,11 +1427,12 @@
// -- Drawing code --
- // Calculate resolution in both pixels/base and bases/pixel; round bases/pixels for tile calculations.
- // TODO: require minimum difference in new resolution to update?
+ // Calculate resolution in both pixels/base and bases/pixel.
+ // TODO: require minimum difference in new resolution to update? This
+ // would help alleviate issues when window is being resized.
this.resolution_b_px = (this.high - this.low) / this.viewport_container.width();
- this.resolution_px_b = this.viewport_container.width() / (this.high - this.low);
-
+ this.resolution_px_b = 1 / this.resolution_b_px;
+
// Overview
var left_px = ( this.low / (this.max_high - this.max_low) * this.overview_viewport.width() ) || 0;
var width_px = ( (this.high - this.low)/(this.max_high - this.max_low) * this.overview_viewport.width() ) || 0;
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
2 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/a0f1ae0dc3ff/
changeset: a0f1ae0dc3ff
user: sfk
date: 2013-02-18 00:46:39
summary: Fixed a small bug when jobwrapper was referenced but it didnt exist
affected #: 1 file
diff -r 09c81e81952d4768d63fde4840f31958d8e23041 -r a0f1ae0dc3ff4474e46b8e54aea4b999d8e0d0e0 lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -607,7 +607,7 @@
try:
self.job_runners[runner_name].stop_job( job )
except KeyError:
- log.error( 'stop(): (%s) Invalid job runner: %s' % ( job_wrapper.job_id, runner_name ) )
+ log.error( 'stop(): (%s) Invalid job runner: %s' % ( job.get_id(), runner_name ) )
# Job and output dataset states have already been updated, so nothing is done here.
def recover( self, job, job_wrapper ):
https://bitbucket.org/galaxy/galaxy-central/commits/1f073bb32539/
changeset: 1f073bb32539
user: natefoo
date: 2013-02-19 14:53:25
summary: Merged in sfk/galaxy-central-random-bug-fix (pull request #126)
Fixed a small bug when jobwrapper was referenced but it didnt exist
affected #: 1 file
diff -r 31aca8c9901ecf4ad852f7114d6550d997374888 -r 1f073bb32539ea9d978c04a892a36d995561cb30 lib/galaxy/jobs/handler.py
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -607,7 +607,7 @@
try:
self.job_runners[runner_name].stop_job( job )
except KeyError:
- log.error( 'stop(): (%s) Invalid job runner: %s' % ( job_wrapper.job_id, runner_name ) )
+ log.error( 'stop(): (%s) Invalid job runner: %s' % ( job.get_id(), runner_name ) )
# Job and output dataset states have already been updated, so nothing is done here.
def recover( self, job, job_wrapper ):
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Fix for installing a repository from the tool shed that includes a repository dependency defintion where the required repository is owned by a user other than the dependent repository.
by Bitbucket 18 Feb '13
by Bitbucket 18 Feb '13
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8da37d3985ab/
changeset: 8da37d3985ab
branch: stable
user: greg
date: 2013-02-18 21:28:06
summary: Fix for installing a repository from the tool shed that includes a repository dependency defintion where the required repository is owned by a user other than the dependent repository.
affected #: 3 files
diff -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -714,7 +714,11 @@
for rd_tup in rd_tups:
tool_shed, name, owner, changeset_revision = rd_tup
# Updates to installed repository revisions may have occurred, so make sure to locate the appropriate repository revision if one exists.
- repository, current_changeset_revision = repository_was_previously_installed( trans, tool_shed, name, repo_info_tuple )
+ # We need to create a temporary repo_info_tuple that includes the correct repository owner which we get from the current rd_tup. The current
+ # tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td )
+ tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup )
+ tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None )
+ repository, current_changeset_revision = repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed, name, owner, changeset_revision, repository.id, repository.status ]
if repository.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
diff -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -953,6 +953,12 @@
return '%s://%s%s/repos/%s/%s' % ( protocol, username, base, repository.user.username, repository.name )
else:
return '%s/repos/%s/%s' % ( base_url, repository.user.username, repository.name )
+def generate_clone_url_from_repo_info_tup( repo_info_tup ):
+ """Generate teh URL for cloning a repositoyr given a tuple of toolshed, name, owner, changeset_revision."""
+ # Example tuple: ['http://localhost:9009', 'blast_datatypes', 'test', '461a4216e8ab']
+ toolshed, name, owner, changeset_revision = repo_info_tup
+ # Don't include the changeset_revision in clone urls.
+ return url_join( toolshed, 'repos', owner, name )
def generate_datatypes_metadata( datatypes_config, metadata_dict ):
"""Update the received metadata_dict with information from the parsed datatypes_config."""
tree = ElementTree.parse( datatypes_config )
diff -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 -r 8da37d3985ab9c489760e64d4e3eb707dfbeb4b8 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1461,12 +1461,15 @@
repository_clone_url = suc.generate_clone_url_for_repository_in_tool_shed( trans, repository )
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
metadata = repository_metadata.metadata
- if not includes_tools and 'tools' in metadata:
- includes_tools = True
- if not has_repository_dependencies and 'repository_dependencies' in metadata:
- has_repository_dependencies = True
- if not includes_tool_dependencies and 'tool_dependencies' in metadata:
- includes_tool_dependencies = True
+ if not includes_tools:
+ if 'tools' in metadata:
+ includes_tools = True
+ if not has_repository_dependencies:
+ if 'repository_dependencies' in metadata:
+ has_repository_dependencies = True
+ if not includes_tool_dependencies:
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Display the Orphan column in the valid tool dependencies container in the tool shed.
by Bitbucket 18 Feb '13
by Bitbucket 18 Feb '13
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/31aca8c9901e/
changeset: 31aca8c9901e
user: greg
date: 2013-02-18 22:00:43
summary: Display the Orphan column in the valid tool dependencies container in the tool shed.
affected #: 2 files
diff -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd -r 31aca8c9901ecf4ad852f7114d6550d997374888 lib/galaxy/webapps/community/util/container_util.py
--- a/lib/galaxy/webapps/community/util/container_util.py
+++ b/lib/galaxy/webapps/community/util/container_util.py
@@ -514,7 +514,7 @@
installation_status=None,
repository_id=None,
tool_dependency_id=None,
- is_orphan=None )
+ is_orphan='Orphan' )
folder.tool_dependencies.append( tool_dependency )
is_orphan_description = "these dependencies may not be required by tools in this repository"
for dependency_key, requirements_dict in tool_dependencies.items():
diff -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd -r 31aca8c9901ecf4ad852f7114d6550d997374888 templates/webapps/community/repository/common.mako
--- a/templates/webapps/community/repository/common.mako
+++ b/templates/webapps/community/repository/common.mako
@@ -628,13 +628,17 @@
${version_str | h}
</${cell_type}><${cell_type}>${tool_dependency.type | h}</${cell_type}>
- %if trans.webapp.name == 'galaxy':
- %if is_missing:
- <${cell_type}>${tool_dependency.installation_status | h}</${cell_type}>
- %elif tool_dependency.install_dir:
- <${cell_type}>${tool_dependency.install_dir | h}</${cell_type}>
+ <${cell_type}>
+ %if trans.webapp.name == 'galaxy':
+ %if is_missing:
+ ${tool_dependency.installation_status | h}
+ %elif tool_dependency.install_dir:
+ ${tool_dependency.install_dir | h}
+ %endif
+ %else:
+ ${tool_dependency.is_orphan | h}
%endif
- %endif
+ </${cell_type}></tr><%
my_row = row_counter.count
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: Tool shed functional tests for: Citable URLs, simple repository dependencies with multiple repository owners.
by Bitbucket 18 Feb '13
by Bitbucket 18 Feb '13
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ca145a616aee/
changeset: ca145a616aee
user: inithello
date: 2013-02-18 21:58:52
summary: Tool shed functional tests for: Citable URLs, simple repository dependencies with multiple repository owners.
affected #: 6 files
diff -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd test/tool_shed/base/twilltestcase.py
--- a/test/tool_shed/base/twilltestcase.py
+++ b/test/tool_shed/base/twilltestcase.py
@@ -695,11 +695,37 @@
self.check_for_strings( post_submit_strings_displayed, strings_not_displayed )
repository_ids = self.initiate_installation_process( new_tool_panel_section=new_tool_panel_section )
self.wait_for_repository_installation( repository_ids )
- def load_invalid_tool_page( self, repository, tool_xml, changeset_revision, strings_displayed=[], strings_not_displayed=[] ):
- url = '/repository/load_invalid_tool?repository_id=%s&tool_config=%s&changeset_revision=%s' % \
- ( self.security.encode_id( repository.id ), tool_xml, changeset_revision )
+ def load_citable_url( self,
+ username,
+ repository_name,
+ changeset_revision,
+ encoded_user_id,
+ encoded_repository_id,
+ strings_displayed=[],
+ strings_not_displayed=[],
+ strings_displayed_in_iframe=[],
+ strings_not_displayed_in_iframe=[] ):
+ url = '%s/view/%s' % ( self.url, username )
+ # If repository name is passed in, append that to the url.
+ if repository_name:
+ url += '/%s' % repository_name
+ if changeset_revision:
+ # Changeset revision should never be provided unless repository name also is.
+ assert repository_name is not None, 'Changeset revision is present, but repository name is not - aborting.'
+ url += '/%s' % changeset_revision
self.visit_url( url )
self.check_for_strings( strings_displayed, strings_not_displayed )
+ # Now load the page that should be displayed inside the iframe and check for strings.
+ if encoded_repository_id:
+ url = '/repository/view_repository?id=%s&operation=view_or_manage_repository' % encoded_repository_id
+ if changeset_revision:
+ url += '&changeset_revision=%s' % changeset_revision
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed_in_iframe, strings_not_displayed_in_iframe )
+ elif encoded_user_id:
+ url = '/repository/browse_repositories?user_id=%s&operation=repositories_by_user' % encoded_user_id
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed_in_iframe, strings_not_displayed_in_iframe )
def load_display_tool_page( self, repository, tool_xml_path, changeset_revision, strings_displayed=[], strings_not_displayed=[] ):
url = '/repository/display_tool?repository_id=%s&tool_config=%s&changeset_revision=%s' % \
( self.security.encode_id( repository.id ), tool_xml_path, changeset_revision )
@@ -709,6 +735,11 @@
url = '/admin/review_tool_migration_stages'
self.visit_galaxy_url( url )
self.check_for_strings( strings_displayed, strings_not_displayed )
+ def load_invalid_tool_page( self, repository, tool_xml, changeset_revision, strings_displayed=[], strings_not_displayed=[] ):
+ url = '/repository/load_invalid_tool?repository_id=%s&tool_config=%s&changeset_revision=%s' % \
+ ( self.security.encode_id( repository.id ), tool_xml, changeset_revision )
+ self.visit_url( url )
+ self.check_for_strings( strings_displayed, strings_not_displayed )
def load_workflow_image_in_tool_shed( self, repository, workflow_name, changeset_revision=None, strings_displayed=[], strings_not_displayed=[] ):
if not changeset_revision:
changeset_revision = self.get_repository_tip( repository )
diff -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd test/tool_shed/functional/test_0120_simple_repository_dependency_multiple_owners.py
--- /dev/null
+++ b/test/tool_shed/functional/test_0120_simple_repository_dependency_multiple_owners.py
@@ -0,0 +1,140 @@
+from tool_shed.base.twilltestcase import ShedTwillTestCase, common, os
+import tool_shed.base.test_db_util as test_db_util
+
+datatypes_repository_name = 'blast_datatypes_0120'
+datatypes_repository_description = 'Galaxy applicable datatypes for BLAST'
+datatypes_repository_long_description = 'Galaxy datatypes for the BLAST top hit descriptons tool'
+
+tool_repository_name = 'blastxml_to_top_descr_0120'
+tool_repository_description = 'BLAST top hit descriptions'
+tool_repository_long_description = 'Make a table from BLAST XML'
+
+'''
+Tool shed side:
+
+1) Create and populate blast_datatypes_0120.
+1a) Check for appropriate strings.
+2) Create and populate blastxml_to_top_descr_0120.
+2a) Check for appropriate strings.
+3) Upload repository_dependencies.xml to blastxml_to_top_descr_0120 that defines a relationship to blast_datatypes_0120.
+3a) Check for appropriate strings.
+'''
+
+base_datatypes_count = 0
+repository_datatypes_count = 0
+
+class TestRepositoryMultipleOwners( ShedTwillTestCase ):
+ def test_0000_initiate_users( self ):
+ """Create necessary user accounts and login as an admin user."""
+ """
+ Create all the user accounts that are needed for this test script to run independently of other tests.
+ Previously created accounts will not be re-created.
+ """
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ assert test_user_1 is not None, 'Problem retrieving user with email %s from the database' % common.test_user_1_email
+ test_user_1_private_role = test_db_util.get_private_role( test_user_1 )
+ self.logout()
+ self.login( email=common.test_user_2_email, username=common.test_user_2_name )
+ test_user_2 = test_db_util.get_user( common.test_user_1_email )
+ assert test_user_2 is not None, 'Problem retrieving user with email %s from the database' % common.test_user_2_email
+ test_user_2_private_role = test_db_util.get_private_role( test_user_2 )
+ self.logout()
+ self.login( email=common.admin_email, username=common.admin_username )
+ admin_user = test_db_util.get_user( common.admin_email )
+ assert admin_user is not None, 'Problem retrieving user with email %s from the database' % common.admin_email
+ admin_user_private_role = test_db_util.get_private_role( admin_user )
+ def test_0005_create_datatypes_repository( self ):
+ """Create and populate the blast_datatypes_0120 repository"""
+ """
+ We are at step 1.
+ Create and populate blast_datatypes.
+ """
+ category = self.create_category( name='Test 0120', description='Description of test 0120' )
+ self.logout()
+ self.login( email=common.test_user_2_email, username=common.test_user_2_name )
+ strings_displayed = [ 'Repository %s' % "'%s'" % datatypes_repository_name,
+ 'Repository %s has been created' % "'%s'" % datatypes_repository_name ]
+ repository = self.get_or_create_repository( name=datatypes_repository_name,
+ description=datatypes_repository_description,
+ long_description=datatypes_repository_long_description,
+ owner=common.test_user_2_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=strings_displayed )
+ self.upload_file( repository,
+ filename='blast/blast_datatypes.tar',
+ filepath=None,
+ valid_tools_only=True,
+ uncompress_file=True,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded blast_datatypes tarball.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ def test_0010_verify_datatypes_repository( self ):
+ '''Verify the blast_datatypes_0120 repository.'''
+ '''
+ We are at step 1a.
+ Check for appropriate strings, most importantly BlastXml, BlastNucDb, and BlastProtDb,
+ the datatypes that are defined in datatypes_conf.xml.
+ '''
+ global repository_datatypes_count
+ repository = test_db_util.get_repository_by_name_and_owner( datatypes_repository_name, common.test_user_2_name )
+ strings_displayed = [ 'BlastXml', 'BlastNucDb', 'BlastProtDb', 'application/xml', 'text/html', 'blastxml', 'blastdbn', 'blastdbp']
+ self.display_manage_repository_page( repository, strings_displayed=strings_displayed )
+ repository_datatypes_count = int( self.get_repository_datatypes_count( repository ) )
+ def test_0015_create_tool_repository( self ):
+ """Create and populate the blastxml_to_top_descr_0120 repository"""
+ """
+ We are at step 2.
+ Create and populate blastxml_to_top_descr_0120.
+ """
+ category = self.create_category( name='Test 0120', description='Description of test 0120' )
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ strings_displayed = [ 'Repository %s' % "'%s'" % tool_repository_name,
+ 'Repository %s has been created' % "'%s'" % tool_repository_name ]
+ repository = self.get_or_create_repository( name=tool_repository_name,
+ description=tool_repository_description,
+ long_description=tool_repository_long_description,
+ owner=common.test_user_1_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=strings_displayed )
+ self.upload_file( repository,
+ filename='blast/blastxml_to_top_descr.tar',
+ filepath=None,
+ valid_tools_only=True,
+ uncompress_file=True,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded blastxml_to_top_descr tarball.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ def test_0020_verify_tool_repository( self ):
+ '''Verify the blastxml_to_top_descr_0120 repository.'''
+ '''
+ We are at step 2a.
+ Check for appropriate strings, such as tool name, description, and version.
+ '''
+ repository = test_db_util.get_repository_by_name_and_owner( tool_repository_name, common.test_user_1_name )
+ strings_displayed = [ 'blastxml_to_top_descr_0120', 'BLAST top hit descriptions', 'Make a table from BLAST XML' ]
+ strings_displayed.extend( [ '0.0.1', 'Valid tools'] )
+ self.display_manage_repository_page( repository, strings_displayed=strings_displayed )
+ def test_0025_create_repository_dependency( self ):
+ '''Create a repository dependency on blast_datatypes_0120.'''
+ '''
+ We are at step 3.
+ Create a simple repository dependency for blastxml_to_top_descr_0120 that defines a dependency on blast_datatypes_0120.
+ '''
+ datatypes_repository = test_db_util.get_repository_by_name_and_owner( datatypes_repository_name, common.test_user_2_name )
+ tool_repository = test_db_util.get_repository_by_name_and_owner( tool_repository_name, common.test_user_1_name )
+ dependency_xml_path = self.generate_temp_path( 'test_0120', additional_paths=[ 'dependencies' ] )
+ self.create_repository_dependency( repository=tool_repository, depends_on=[ datatypes_repository ], filepath=dependency_xml_path )
+ def test_0040_verify_repository_dependency( self ):
+ '''Verify the created repository dependency.'''
+ '''
+ We are at step 3a.
+ Check the newly created repository dependency to ensure that it was defined and displays correctly.
+ '''
+ datatypes_repository = test_db_util.get_repository_by_name_and_owner( datatypes_repository_name, common.test_user_2_name )
+ tool_repository = test_db_util.get_repository_by_name_and_owner( tool_repository_name, common.test_user_1_name )
+ self.check_repository_dependency( tool_repository, datatypes_repository )
diff -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd test/tool_shed/functional/test_0420_citable_urls_for_repositories.py
--- /dev/null
+++ b/test/tool_shed/functional/test_0420_citable_urls_for_repositories.py
@@ -0,0 +1,233 @@
+from tool_shed.base.twilltestcase import ShedTwillTestCase, common, os
+import tool_shed.base.test_db_util as test_db_util
+import logging
+log = logging.getLogger(__name__)
+
+repository_name = 'filtering_0420'
+repository_description = 'Galaxy filtering tool for test 0420'
+repository_long_description = 'Long description of Galaxy filtering tool for test 0410'
+
+first_changeset_hash = ''
+
+'''
+1. Add and populate a repository to the tool shed with change set revision 0 (assume owner is test).
+2. Add valid change set revision 1.
+3. Visit the following url and check for appropriate strings: <tool shed base url>/view/user1
+4. Visit the following url and check for appropriate strings: <tool shed base url>/view/user1/filtering_0420
+ Resulting page should contain change set revision 1
+5. Visit the following url and check for appropriate strings: <tool shed base url>/view/user1/filtering_0420/<revision 0>
+ Resulting page should not contain change set revision 1, but should contain change set revision 0.
+6. Visit the following url and check for appropriate strings: <tool shed base url>/view/user1/filtering_0420/<invalid revision>
+7. Visit the following url and check for appropriate strings: <tool shed base url>/view/user1/<invalid repository name>
+8. Visit the following url and check for appropriate strings: <tool shed base url>/view/<invalid owner>
+'''
+
+class TestRepositoryCitableURLs( ShedTwillTestCase ):
+ '''Test repository citable url features.'''
+ def test_0000_initiate_users( self ):
+ """Create necessary user accounts and login as an admin user."""
+ """
+ Create all the user accounts that are needed for this test script to run independently of other tests.
+ Previously created accounts will not be re-created.
+ """
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ assert test_user_1 is not None, 'Problem retrieving user with email %s from the database' % common.test_user_1_email
+ test_user_1_private_role = test_db_util.get_private_role( test_user_1 )
+ self.logout()
+ self.login( email=common.admin_email, username=common.admin_username )
+ admin_user = test_db_util.get_user( common.admin_email )
+ assert admin_user is not None, 'Problem retrieving user with email %s from the database' % common.admin_email
+ admin_user_private_role = test_db_util.get_private_role( admin_user )
+ def test_0005_create_repository( self ):
+ """Create and populate the filtering_0420 repository"""
+ """
+ We are at step 1.
+ Add and populate a repository to the tool shed with change set revision 0 (assume owner is test_user_1).
+ """
+ global first_changeset_hash
+ category = self.create_category( name='Test 0400 Repository Citable URLs',
+ description='Test 0400 Repository Citable URLs category' )
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ strings_displayed = [ 'Repository %s' % "'%s'" % repository_name,
+ 'Repository %s has been created' % "'%s'" % repository_name ]
+ repository = self.get_or_create_repository( name=repository_name,
+ description=repository_description,
+ long_description=repository_long_description,
+ owner=common.test_user_1_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=strings_displayed )
+ self.upload_file( repository,
+ filename='filtering/filtering_2.2.0.tar',
+ filepath=None,
+ valid_tools_only=True,
+ uncompress_file=True,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded filtering 2.2.0 tarball.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ # We'll be checking for this hash later, after uploading another file to the repository, making get_repository_tip() not usable.
+ first_changeset_hash = self.get_repository_tip( repository )
+ def test_0010_upload_new_file_to_repository( self ):
+ '''Upload a readme file to the repository in order to create a second changeset revision.'''
+ '''
+ We are at step 2.
+ Add valid change set revision 1.
+ The repository should now contain two changeset revisions, 0:<revision hash> and 1:<revision hash>.
+ '''
+ repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
+ self.upload_file( repository,
+ filename='readme.txt',
+ filepath=None,
+ valid_tools_only=True,
+ uncompress_file=True,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded readme.txt.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ def test_0015_load_user_view_page( self ):
+ '''Load the /view/<username> page amd check for strings.'''
+ '''
+ We are at step 3.
+ Visit the following url and check for appropriate strings: <tool shed base url>/view/user1
+ '''
+ repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ encoded_user_id = self.security.encode_id( test_user_1.id )
+ # Since twill does not load the contents of an iframe, we need to check that the iframe has been generated correctly,
+ # then directly load the url that the iframe should be loading and check for the expected strings.
+ # The iframe should point to /repository/browse_repositories?user_id=<encoded user ID>&operation=repositories_by_user
+ strings_displayed = [ '/repository/browse_repositories', encoded_user_id, 'operation=repositories_by_user' ]
+ strings_displayed.append( encoded_user_id )
+ strings_displayed_in_iframe = [ 'user1', 'filtering_0420', 'Galaxy filtering tool for test 0420' ]
+ strings_displayed_in_iframe.append( self.get_repository_tip( repository ) )
+ self.load_citable_url( username='user1',
+ repository_name=None,
+ changeset_revision=None,
+ encoded_user_id=encoded_user_id,
+ encoded_repository_id=None,
+ strings_displayed=strings_displayed,
+ strings_displayed_in_iframe=strings_displayed_in_iframe )
+ def test_0020_load_repository_view_page( self ):
+ '''Load the /view/<user>/<repository> page and check for the appropriate strings.'''
+ '''
+ We are at step 4.
+ Visit the following url and check for strings: <tool shed base url>/view/user1/filtering_0420
+ Resulting page should contain change set revision 1
+ '''
+ repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ encoded_user_id = self.security.encode_id( test_user_1.id )
+ encoded_repository_id = self.security.encode_id( repository.id )
+ # Since twill does not load the contents of an iframe, we need to check that the iframe has been generated correctly,
+ # then directly load the url that the iframe should be loading and check for the expected strings.
+ # The iframe should point to /repository/bview_repository?id=<encoded repository ID>
+ strings_displayed = [ '/repository', 'view_repository', 'id=', encoded_repository_id ]
+ strings_displayed_in_iframe = [ 'user1', 'filtering_0420', 'Galaxy filtering tool for test 0420' ]
+ strings_displayed_in_iframe.append( self.get_repository_tip( repository ) )
+ strings_displayed_in_iframe.append( 'Sharable link to this repository:' )
+ strings_displayed_in_iframe.append( '%s/view/user1/filtering_0420' % self.url )
+ self.load_citable_url( username='user1',
+ repository_name='filtering_0420',
+ changeset_revision=None,
+ encoded_user_id=encoded_user_id,
+ encoded_repository_id=encoded_repository_id,
+ strings_displayed=strings_displayed,
+ strings_displayed_in_iframe=strings_displayed_in_iframe )
+ def test_0025_load_view_page_for_previous_revision( self ):
+ '''Load a citable url for a past changeset revision and verify that strings display.'''
+ '''
+ We are at step 5.
+ Visit the following url and check for appropriate strings: <tool shed base url>/view/user1/filtering_0420/<revision 0>
+ Resulting page should not contain change set revision 1, but should contain change set revision 0.
+ '''
+ global first_changeset_hash
+ repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ encoded_user_id = self.security.encode_id( test_user_1.id )
+ encoded_repository_id = self.security.encode_id( repository.id )
+ # We are checking the changeset revision pointed to by first_changeset_hash, stored in a global variable at the end of
+ # test_0005. The tip changeset hash should not be displayed here, but first_changeset_hash should.
+ tip_changeset_hash = self.get_repository_tip( repository )
+ # Since twill does not load the contents of an iframe, we need to check that the iframe has been generated correctly,
+ # then directly load the url that the iframe should be loading and check for the expected strings.
+ # The iframe should point to /repository/view_repository?id=<encoded repository ID>
+ strings_displayed = [ '/repository', 'view_repository', 'id=' + encoded_repository_id ]
+ strings_displayed_in_iframe = [ 'user1', 'filtering_0420', 'Galaxy filtering tool for test 0420', first_changeset_hash ]
+ strings_displayed_in_iframe.append( 'Sharable link to this repository revision:' )
+ strings_displayed_in_iframe.append( '%s/view/user1/filtering_0420/%s' % ( self.url, first_changeset_hash ) )
+ strings_not_displayed_in_iframe = [ tip_changeset_hash ]
+ self.load_citable_url( username='user1',
+ repository_name='filtering_0420',
+ changeset_revision=first_changeset_hash,
+ encoded_user_id=encoded_user_id,
+ encoded_repository_id=encoded_repository_id,
+ strings_displayed=strings_displayed,
+ strings_displayed_in_iframe=strings_displayed_in_iframe,
+ strings_not_displayed_in_iframe=strings_not_displayed_in_iframe )
+ def test_0030_load_sharable_url_with_invalid_changeset_revision( self ):
+ '''Load a citable url with an invalid changeset revision specified.'''
+ repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ encoded_user_id = self.security.encode_id( test_user_1.id )
+ encoded_repository_id = self.security.encode_id( repository.id )
+ changeset_hash = '!!invalid!!'
+ tip_revision = self.get_repository_tip( repository )
+ # Since twill does not load the contents of an iframe, we need to check that the iframe has been generated correctly,
+ # then directly load the url that the iframe should be loading and check for the expected strings.
+ # The iframe should point to /repository/view_repository?id=<encoded repository ID>&status=error
+ strings_displayed = [ '/repository', 'view_repository', 'id=' + encoded_repository_id ]
+ strings_displayed.extend( [ 'The+change+log', 'does+not+include+revision', '%21%21invalid%21%21', 'status=error' ] )
+ strings_displayed_in_iframe = [ 'user1', 'filtering_0420', 'Galaxy filtering tool for test 0420' ]
+ strings_displayed_in_iframe.append( 'Sharable link to this repository revision:' )
+ strings_displayed_in_iframe.append( '%s/view/user1/filtering_0420/%s' % ( self.url, changeset_hash ) )
+ strings_not_displayed_in_iframe = [ tip_revision ]
+ self.load_citable_url( username='user1',
+ repository_name='filtering_0420',
+ changeset_revision=changeset_hash,
+ encoded_user_id=encoded_user_id,
+ encoded_repository_id=encoded_repository_id,
+ strings_displayed=strings_displayed,
+ strings_displayed_in_iframe=strings_displayed_in_iframe,
+ strings_not_displayed_in_iframe=strings_not_displayed_in_iframe )
+ def test_0035_load_sharable_url_with_invalid_repository_name( self ):
+ '''Load a citable url with an invalid changeset revision specified.'''
+ '''
+ We are at step 7
+ Visit the following url and check for appropriate strings: <tool shed base url>/view/user1/!!invalid!!
+ '''
+ repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ encoded_user_id = self.security.encode_id( test_user_1.id )
+ tip_revision = self.get_repository_tip( repository )
+ # Since twill does not load the contents of an iframe, we need to check that the iframe has been generated correctly,
+ # then directly load the url that the iframe should be loading and check for the expected strings.
+ # The iframe should point to /repository/browse_repositories?user_id=<encoded user ID>&operation=repositories_by_user
+ strings_displayed = [ '/repository', 'browse_repositories', 'user1' ]
+ strings_displayed.extend( [ 'list+of+repositories+owned', 'does+not+include+one+named', '%21%21invalid%21%21', 'status=error' ] )
+ strings_displayed_in_iframe = [ 'user1', 'filtering_0420' ]
+ strings_displayed_in_iframe.append( 'Repositories owned by user1' )
+ strings_displayed_in_iframe.append( tip_revision )
+ self.load_citable_url( username='user1',
+ repository_name='!!invalid!!',
+ changeset_revision=None,
+ encoded_user_id=encoded_user_id,
+ encoded_repository_id=None,
+ strings_displayed=strings_displayed,
+ strings_displayed_in_iframe=strings_displayed_in_iframe )
+ def test_0040_load_sharable_url_with_invalid_owner( self ):
+ '''Load a citable url with an invalid owner.'''
+ '''
+ We are at step 8.
+ Visit the following url and check for appropriate strings: <tool shed base url>/view/!!invalid!!
+ '''
+ strings_displayed = [ 'The tool shed', self.url, 'contains no repositories owned by', '!!invalid!!' ]
+ self.load_citable_url( username='!!invalid!!',
+ repository_name=None,
+ changeset_revision=None,
+ encoded_user_id=None,
+ encoded_repository_id=None,
+ strings_displayed=strings_displayed )
+
\ No newline at end of file
diff -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd test/tool_shed/functional/test_1120_simple_repository_dependency_multiple_owners.py
--- /dev/null
+++ b/test/tool_shed/functional/test_1120_simple_repository_dependency_multiple_owners.py
@@ -0,0 +1,190 @@
+from tool_shed.base.twilltestcase import ShedTwillTestCase, common, os
+import tool_shed.base.test_db_util as test_db_util
+
+datatypes_repository_name = 'blast_datatypes_0120'
+datatypes_repository_description = 'Galaxy applicable datatypes for BLAST'
+datatypes_repository_long_description = 'Galaxy datatypes for the BLAST top hit descriptons tool'
+
+tool_repository_name = 'blastxml_to_top_descr_0120'
+tool_repository_description = 'BLAST top hit descriptions'
+tool_repository_long_description = 'Make a table from BLAST XML'
+
+'''
+Tool shed side:
+
+1) Create and populate blast_datatypes_0120.
+1a) Check for appropriate strings.
+2) Create and populate blastxml_to_top_descr_0120.
+2a) Check for appropriate strings.
+3) Upload repository_dependencies.xml to blastxml_to_top_descr_0120 that defines a relationship to blast_datatypes_0120.
+3a) Check for appropriate strings.
+
+
+Galaxy side:
+
+1) Install blastxml_to_top_descr_0120, with repository dependencies.
+1a) Check for appropriate strings in the installed blastxml_to_top_descr_0120 and blast_datatypes_0120 repositories.
+'''
+
+running_standalone = False
+
+class TestInstallRepositoryMultipleOwners( ShedTwillTestCase ):
+ def test_0000_initiate_users( self ):
+ """Create necessary user accounts and login as an admin user."""
+ """
+ Create all the user accounts that are needed for this test script to run independently of other tests.
+ Previously created accounts will not be re-created.
+ """
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ test_user_1 = test_db_util.get_user( common.test_user_1_email )
+ assert test_user_1 is not None, 'Problem retrieving user with email %s from the database' % common.test_user_1_email
+ test_user_1_private_role = test_db_util.get_private_role( test_user_1 )
+ self.logout()
+ self.login( email=common.test_user_2_email, username=common.test_user_2_name )
+ test_user_2 = test_db_util.get_user( common.test_user_1_email )
+ assert test_user_2 is not None, 'Problem retrieving user with email %s from the database' % common.test_user_2_email
+ test_user_2_private_role = test_db_util.get_private_role( test_user_2 )
+ self.logout()
+ self.login( email=common.admin_email, username=common.admin_username )
+ admin_user = test_db_util.get_user( common.admin_email )
+ assert admin_user is not None, 'Problem retrieving user with email %s from the database' % common.admin_email
+ admin_user_private_role = test_db_util.get_private_role( admin_user )
+ def test_0005_create_datatypes_repository( self ):
+ """Create and populate the blast_datatypes_0120 repository"""
+ """
+ We are at step 1.
+ Create and populate blast_datatypes.
+ """
+ category = self.create_category( name='Test 0120', description='Description of test 0120' )
+ self.logout()
+ self.login( email=common.test_user_2_email, username=common.test_user_2_name )
+ strings_displayed = [ 'Repository %s' % "'%s'" % datatypes_repository_name,
+ 'Repository %s has been created' % "'%s'" % datatypes_repository_name ]
+ repository = self.get_or_create_repository( name=datatypes_repository_name,
+ description=datatypes_repository_description,
+ long_description=datatypes_repository_long_description,
+ owner=common.test_user_2_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=strings_displayed )
+ if self.repository_is_new( repository ):
+ self.upload_file( repository,
+ filename='blast/blast_datatypes.tar',
+ filepath=None,
+ valid_tools_only=True,
+ uncompress_file=True,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded blast_datatypes tarball.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ def test_0010_verify_datatypes_repository( self ):
+ '''Verify the blast_datatypes_0120 repository.'''
+ '''
+ We are at step 1a.
+ Check for appropriate strings, most importantly BlastXml, BlastNucDb, and BlastProtDb,
+ the datatypes that are defined in datatypes_conf.xml.
+ '''
+ global repository_datatypes_count
+ repository = test_db_util.get_repository_by_name_and_owner( datatypes_repository_name, common.test_user_2_name )
+ strings_displayed = [ 'BlastXml', 'BlastNucDb', 'BlastProtDb', 'application/xml', 'text/html', 'blastxml', 'blastdbn', 'blastdbp']
+ self.display_manage_repository_page( repository, strings_displayed=strings_displayed )
+ repository_datatypes_count = int( self.get_repository_datatypes_count( repository ) )
+ def test_0015_create_tool_repository( self ):
+ """Create and populate the blastxml_to_top_descr_0120 repository"""
+ """
+ We are at step 2.
+ Create and populate blastxml_to_top_descr_0120.
+ """
+ global running_standalone
+ category = self.create_category( name='Test 0120', description='Description of test 0120' )
+ self.logout()
+ self.login( email=common.test_user_1_email, username=common.test_user_1_name )
+ strings_displayed = [ 'Repository %s' % "'%s'" % tool_repository_name,
+ 'Repository %s has been created' % "'%s'" % tool_repository_name ]
+ repository = self.get_or_create_repository( name=tool_repository_name,
+ description=tool_repository_description,
+ long_description=tool_repository_long_description,
+ owner=common.test_user_1_name,
+ category_id=self.security.encode_id( category.id ),
+ strings_displayed=strings_displayed )
+ if self.repository_is_new( repository ):
+ running_standalone = True
+ self.upload_file( repository,
+ filename='blast/blastxml_to_top_descr.tar',
+ filepath=None,
+ valid_tools_only=True,
+ uncompress_file=True,
+ remove_repo_files_not_in_tar=False,
+ commit_message='Uploaded blastxml_to_top_descr tarball.',
+ strings_displayed=[],
+ strings_not_displayed=[] )
+ def test_0020_verify_tool_repository( self ):
+ '''Verify the blastxml_to_top_descr_0120 repository.'''
+ '''
+ We are at step 2a.
+ Check for appropriate strings, such as tool name, description, and version.
+ '''
+ repository = test_db_util.get_repository_by_name_and_owner( tool_repository_name, common.test_user_1_name )
+ strings_displayed = [ 'blastxml_to_top_descr_0120', 'BLAST top hit descriptions', 'Make a table from BLAST XML' ]
+ strings_displayed.extend( [ '0.0.1', 'Valid tools'] )
+ self.display_manage_repository_page( repository, strings_displayed=strings_displayed )
+ def test_0025_create_repository_dependency( self ):
+ '''Create a repository dependency on blast_datatypes_0120.'''
+ '''
+ We are at step 3.
+ Create a simple repository dependency for blastxml_to_top_descr_0120 that defines a dependency on blast_datatypes_0120.
+ '''
+ global running_standalone
+ if running_standalone:
+ datatypes_repository = test_db_util.get_repository_by_name_and_owner( datatypes_repository_name, common.test_user_2_name )
+ tool_repository = test_db_util.get_repository_by_name_and_owner( tool_repository_name, common.test_user_1_name )
+ dependency_xml_path = self.generate_temp_path( 'test_1120', additional_paths=[ 'dependencies' ] )
+ self.create_repository_dependency( repository=tool_repository, depends_on=[ datatypes_repository ], filepath=dependency_xml_path )
+ def test_0040_verify_repository_dependency( self ):
+ '''Verify the created repository dependency.'''
+ '''
+ We are at step 3a.
+ Check the newly created repository dependency to ensure that it was defined and displays correctly.
+ '''
+ datatypes_repository = test_db_util.get_repository_by_name_and_owner( datatypes_repository_name, common.test_user_2_name )
+ tool_repository = test_db_util.get_repository_by_name_and_owner( tool_repository_name, common.test_user_1_name )
+ self.check_repository_dependency( tool_repository, datatypes_repository )
+ def test_0045_install_blastxml_to_top_descr( self ):
+ '''Install the blastxml_to_top_descr_0120 repository to Galaxy.'''
+ '''
+ We are at step 1, Galaxy side.
+ Install blastxml_to_top_descr_0120 to Galaxy, with repository dependencies, so that the datatypes repository is also installed.
+ '''
+ global base_datatypes_count
+ self.galaxy_logout()
+ self.galaxy_login( email=common.admin_email, username=common.admin_username )
+ base_datatypes_count = int( self.get_datatypes_count() )
+ post_submit_strings_displayed = [ 'blastxml_to_top_descr_0120', 'blast_datatypes_0120', 'New' ]
+ self.install_repository( name='blastxml_to_top_descr_0120',
+ owner=common.test_user_1_name,
+ category_name='Test 0120',
+ install_repository_dependencies=True,
+ post_submit_strings_displayed=post_submit_strings_displayed,
+ new_tool_panel_section='Test 0120' )
+ def test_0050_verify_repository_installation( self ):
+ '''Verify installation of blastxml_to_top_descr_0120 and blast_datatypes_0120.'''
+ '''
+ We are at step 1a, Galaxy side.
+ Check that the blastxml_to_top_descr_0120 and blast_datatypes_0120 repositories installed correctly, and that there
+ are now new datatypes in the registry matching the ones defined in blast_datatypes_0120. Also check that
+ blast_datatypes_0120 is labeled as an installed repository dependency of blastxml_to_top_descr_0120.
+ '''
+ global repository_datatypes_count
+ global base_datatypes_count
+ tool_repository = test_db_util.get_installed_repository_by_name_owner( tool_repository_name, common.test_user_1_name )
+ datatypes_repository = test_db_util.get_installed_repository_by_name_owner( datatypes_repository_name, common.test_user_2_name )
+ current_datatypes = int( self.get_datatypes_count() )
+ expected_count = base_datatypes_count + repository_datatypes_count
+ assert current_datatypes == expected_count, 'Installing %s did not add new datatypes. Expected: %d. Found: %d' % \
+ ( 'blastxml_to_top_descr_0120', expected_count, current_datatypes )
+ strings_displayed = [ 'Installed repository dependencies', 'user1', 'blast_datatypes_0120' ]
+ strings_displayed.extend( [ 'Valid tools', 'BLAST top hit', 'Make a table', datatypes_repository.installed_changeset_revision ] )
+ self.display_installed_repository_manage_page( tool_repository, strings_displayed=strings_displayed )
+ strings_displayed = [ 'Datatypes', 'blastxml', 'blastdbp', 'blastdbn', 'BlastXml', 'BlastNucDb', 'BlastProtDb' ]
+ strings_displayed.extend( [ 'application/xml', 'text/html' ] )
+ self.display_installed_repository_manage_page( datatypes_repository, strings_displayed=strings_displayed )
diff -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd test/tool_shed/test_data/blast/blast_datatypes.tar
Binary file test/tool_shed/test_data/blast/blast_datatypes.tar has changed
diff -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 -r ca145a616aee1ccb2499b115be9aeacc9ca2ecbd test/tool_shed/test_data/blast/blastxml_to_top_descr.tar
Binary file test/tool_shed/test_data/blast/blastxml_to_top_descr.tar has changed
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: greg: Fix for installing a repository from the tool shed that includes a repository dependency defintion where the required repository is owned by a user other than the dependent repository.
by Bitbucket 18 Feb '13
by Bitbucket 18 Feb '13
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/9e36d1ed099f/
changeset: 9e36d1ed099f
user: greg
date: 2013-02-18 21:28:06
summary: Fix for installing a repository from the tool shed that includes a repository dependency defintion where the required repository is owned by a user other than the dependent repository.
affected #: 3 files
diff -r 84b6c4608e357a466948d895d90d1a1d77f3cd71 -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -720,7 +720,11 @@
for rd_tup in rd_tups:
tool_shed, name, owner, changeset_revision = rd_tup
# Updates to installed repository revisions may have occurred, so make sure to locate the appropriate repository revision if one exists.
- repository, current_changeset_revision = repository_was_previously_installed( trans, tool_shed, name, repo_info_tuple )
+ # We need to create a temporary repo_info_tuple that includes the correct repository owner which we get from the current rd_tup. The current
+ # tuple looks like: ( description, repository_clone_url, changeset_revision, ctx_rev, repository_owner, repository_dependencies, installed_td )
+ tmp_clone_url = suc.generate_clone_url_from_repo_info_tup( rd_tup )
+ tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None )
+ repository, current_changeset_revision = repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
if repository:
new_rd_tup = [ tool_shed, name, owner, changeset_revision, repository.id, repository.status ]
if repository.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
diff -r 84b6c4608e357a466948d895d90d1a1d77f3cd71 -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -1068,6 +1068,12 @@
return '%s://%s%s/repos/%s/%s' % ( protocol, username, base, repository.user.username, repository.name )
else:
return '%s/repos/%s/%s' % ( base_url, repository.user.username, repository.name )
+def generate_clone_url_from_repo_info_tup( repo_info_tup ):
+ """Generate teh URL for cloning a repositoyr given a tuple of toolshed, name, owner, changeset_revision."""
+ # Example tuple: ['http://localhost:9009', 'blast_datatypes', 'test', '461a4216e8ab']
+ toolshed, name, owner, changeset_revision = repo_info_tup
+ # Don't include the changeset_revision in clone urls.
+ return url_join( toolshed, 'repos', owner, name )
def generate_data_manager_metadata( app, repository, repo_dir, data_manager_config_filename, metadata_dict, shed_config_dict=None ):
"""Update the received metadata_dict with information from the parsed data_manager_config_filename."""
if data_manager_config_filename is None:
diff -r 84b6c4608e357a466948d895d90d1a1d77f3cd71 -r 9e36d1ed099fb31eccbc6bf55f20c1bd3fec1773 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -1472,12 +1472,15 @@
repository_clone_url = suc.generate_clone_url_for_repository_in_tool_shed( trans, repository )
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
metadata = repository_metadata.metadata
- if not includes_tools and 'tools' in metadata:
- includes_tools = True
- if not has_repository_dependencies and 'repository_dependencies' in metadata:
- has_repository_dependencies = True
- if not includes_tool_dependencies and 'tool_dependencies' in metadata:
- includes_tool_dependencies = True
+ if not includes_tools:
+ if 'tools' in metadata:
+ includes_tools = True
+ if not has_repository_dependencies:
+ if 'repository_dependencies' in metadata:
+ has_repository_dependencies = True
+ if not includes_tool_dependencies:
+ if 'tool_dependencies' in metadata:
+ includes_tool_dependencies = True
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
ctx = suc.get_changectx_for_changeset( repo, changeset_revision )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/84b6c4608e35/
changeset: 84b6c4608e35
user: dan
date: 2013-02-18 21:10:57
summary: Fix typo in 7d0a0ca401f7.
affected #: 1 file
diff -r 7d0a0ca401f7cee8b2862c4191f4c1c073cc538d -r 84b6c4608e357a466948d895d90d1a1d77f3cd71 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -1418,7 +1418,7 @@
# Handle Data Managers
valid_data_managers = None
invalid_data_managers = None
- data_manager_errors = None
+ data_managers_errors = None
if 'data_manager' in metadata:
valid_data_managers = metadata['data_manager'].get( 'data_managers', None )
invalid_data_managers = metadata['data_manager'].get( 'invalid_data_managers', None )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/337e5b6bd7dc/
changeset: 337e5b6bd7dc
branch: stable
user: greg
date: 2013-02-18 17:04:29
summary: Fix for handling proprietary datatyps definitions in repositories being installed from the tool shed when only datatyes that subclass from those in the Galaxy frameowrk are defined (i.e., there are no proprietary datatype class files for the datatypes). In addition, this changeset now properly handles installing a tool shed repository that included prioretary datatype definitions (they were failing due to a bug in this same method).
affected #: 1 file
diff -r 8cd0793b0fc65b57f8fd93cfffc19ba105d190cf -r 337e5b6bd7dc5696087c436e54192149c1bc8bc3 lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -120,12 +120,24 @@
be False when a tool shed repository is being installed. Since installation is occurring after the datatypes registry
has been initialized, the registry's contents cannot be overridden by conflicting data types.
"""
- tree = util.parse_xml( datatypes_config )
+ try:
+ tree = util.parse_xml( datatypes_config )
+ except Exception, e:
+ log.debug( "Error parsing %s, exception: %s" % ( datatypes_config, str( e ) ) )
+ return None, None
datatypes_config_root = tree.getroot()
- # Path to datatype converters
- converter_path = None
- # Path to datatype display applications
- display_path = None
+ registration = datatypes_config_root.find( 'registration' )
+ if registration is None:
+ # We have valid XML, but not a valid proprietary datatypes definition.
+ return None, None
+ sniffers = datatypes_config_root.find( 'sniffers' )
+ converter_path, display_path = get_converter_and_display_paths( registration, relative_install_dir )
+ if converter_path:
+ # Path to datatype converters
+ registration.attrib[ 'proprietary_converter_path' ] = converter_path
+ if display_path:
+ # Path to datatype display applications
+ registration.attrib[ 'proprietary_display_path' ] = display_path
relative_path_to_datatype_file_name = None
datatype_files = datatypes_config_root.find( 'datatype_files' )
datatype_class_modules = []
@@ -148,12 +160,6 @@
break
break
if datatype_class_modules:
- registration = datatypes_config_root.find( 'registration' )
- converter_path, display_path = get_converter_and_display_paths( registration, relative_install_dir )
- if converter_path:
- registration.attrib[ 'proprietary_converter_path' ] = converter_path
- if display_path:
- registration.attrib[ 'proprietary_display_path' ] = display_path
for relative_path_to_datatype_file_name in datatype_class_modules:
datatype_file_name_path, datatype_file_name = os.path.split( relative_path_to_datatype_file_name )
for elem in registration.findall( 'datatype' ):
@@ -170,20 +176,16 @@
# The value of proprietary_path must be an absolute path due to job_working_directory.
elem.attrib[ 'proprietary_path' ] = os.path.abspath( datatype_file_name_path )
elem.attrib[ 'proprietary_datatype_module' ] = proprietary_datatype_module
- sniffers = datatypes_config_root.find( 'sniffers' )
- else:
- sniffers = None
- fd, proprietary_datatypes_config = tempfile.mkstemp()
- os.write( fd, '<?xml version="1.0"?>\n' )
- os.write( fd, '<datatypes>\n' )
- os.write( fd, '%s' % util.xml_to_string( registration ) )
- if sniffers:
- os.write( fd, '%s' % util.xml_to_string( sniffers ) )
- os.write( fd, '</datatypes>\n' )
- os.close( fd )
- os.chmod( proprietary_datatypes_config, 0644 )
- else:
- proprietary_datatypes_config = datatypes_config
+ # Temporarily persist the proprietary datatypes configuration file so it can be loaded into the datatypes registry.
+ fd, proprietary_datatypes_config = tempfile.mkstemp()
+ os.write( fd, '<?xml version="1.0"?>\n' )
+ os.write( fd, '<datatypes>\n' )
+ os.write( fd, '%s' % util.xml_to_string( registration ) )
+ if sniffers:
+ os.write( fd, '%s' % util.xml_to_string( sniffers ) )
+ os.write( fd, '</datatypes>\n' )
+ os.close( fd )
+ os.chmod( proprietary_datatypes_config, 0644 )
# Load proprietary datatypes
app.datatypes_registry.load_datatypes( root_dir=app.config.root, config=proprietary_datatypes_config, deactivate=deactivate, override=override )
if datatype_files:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: dan: Display Data Managers on repository info pagses in Tool Shed and Galaxy.
by Bitbucket 18 Feb '13
by Bitbucket 18 Feb '13
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/7d0a0ca401f7/
changeset: 7d0a0ca401f7
user: dan
date: 2013-02-18 19:46:08
summary: Display Data Managers on repository info pagses in Tool Shed and Galaxy.
affected #: 4 files
diff -r 852b9d795423015cba17d6c0d5b402f1055404dd -r 7d0a0ca401f7cee8b2862c4191f4c1c073cc538d lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -1415,6 +1415,14 @@
valid_tools = metadata.get( 'tools', None )
# Handle workflows.
workflows = metadata.get( 'workflows', None )
+ # Handle Data Managers
+ valid_data_managers = None
+ invalid_data_managers = None
+ data_manager_errors = None
+ if 'data_manager' in metadata:
+ valid_data_managers = metadata['data_manager'].get( 'data_managers', None )
+ invalid_data_managers = metadata['data_manager'].get( 'invalid_data_managers', None )
+ data_managers_errors = metadata['data_manager'].get( 'messages', None )
containers_dict = suc.build_repository_containers_for_galaxy( trans=trans,
repository=repository,
datatypes=datatypes,
@@ -1426,6 +1434,9 @@
tool_dependencies=installed_tool_dependencies,
valid_tools=valid_tools,
workflows=workflows,
+ valid_data_managers=valid_data_managers,
+ invalid_data_managers=invalid_data_managers,
+ data_managers_errors=data_managers_errors,
new_install=False,
reinstalling=reinstalling )
else:
@@ -1458,6 +1469,9 @@
tool_dependencies=installed_tool_dependencies,
valid_tools=None,
workflows=None,
+ valid_data_managers=None,
+ invalid_data_managers=None,
+ data_managers_errors=None,
new_install=True,
reinstalling=False )
# Merge the missing_repository_dependencies container contents to the installed_repository_dependencies container.
diff -r 852b9d795423015cba17d6c0d5b402f1055404dd -r 7d0a0ca401f7cee8b2862c4191f4c1c073cc538d lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -188,8 +188,8 @@
log.debug( "Error reading README file '%s' defined in metadata: %s" % ( str( relative_path_to_readme_file ), str( e ) ) )
return readme_files_dict
def build_repository_containers_for_galaxy( trans, repository, datatypes, invalid_tools, missing_repository_dependencies, missing_tool_dependencies,
- readme_files_dict, repository_dependencies, tool_dependencies, valid_tools, workflows, new_install=False,
- reinstalling=False ):
+ readme_files_dict, repository_dependencies, tool_dependencies, valid_tools, workflows, valid_data_managers,
+ invalid_data_managers, data_managers_errors, new_install=False, reinstalling=False ):
"""Return a dictionary of containers for the received repository's dependencies and readme files for display during installation to Galaxy."""
containers_dict = dict( datatypes=None,
invalid_tools=None,
@@ -199,7 +199,9 @@
missing_repository_dependencies=None,
tool_dependencies=None,
valid_tools=None,
- workflows=None )
+ workflows=None,
+ valid_data_managers=None,
+ invalid_data_managers=None )
# Some of the tool dependency folders will include links to display tool dependency information, and some of these links require the repository
# id. However we need to be careful because sometimes the repository object is None.
if repository:
@@ -294,6 +296,19 @@
repository_id=repository_id,
label='Workflows' )
containers_dict[ 'workflows' ] = workflows_root_folder
+ if valid_data_managers:
+ folder_id, valid_data_managers_root_folder = container_util.build_data_managers_folder( trans=trans,
+ folder_id=folder_id,
+ data_managers=valid_data_managers,
+ label='Valid Data Managers' )
+ containers_dict[ 'valid_data_managers' ] = valid_data_managers_root_folder
+ if invalid_data_managers or data_managers_errors:
+ folder_id, invalid_data_managers_root_folder = container_util.build_invalid_data_managers_folder( trans=trans,
+ folder_id=folder_id,
+ data_managers=invalid_data_managers,
+ error_messages=data_managers_errors,
+ label='Invalid Data Managers' )
+ containers_dict[ 'invalid_data_managers' ] = invalid_data_managers_root_folder
except Exception, e:
log.debug( "Exception in build_repository_containers_for_galaxy: %s" % str( e ) )
finally:
@@ -307,7 +322,9 @@
repository_dependencies=None,
tool_dependencies=None,
valid_tools=None,
- workflows=None )
+ workflows=None,
+ valid_data_managers=None
+ )
if repository_metadata:
metadata = repository_metadata.metadata
lock = threading.Lock()
@@ -399,6 +416,17 @@
repository_id=None,
label='Workflows' )
containers_dict[ 'workflows' ] = workflows_root_folder
+ # Valid Data Managers container
+ if metadata:
+ if 'data_manager' in metadata:
+ data_managers = metadata['data_manager'].get( 'data_managers', None )
+ folder_id, data_managers_root_folder = container_util.build_data_managers_folder( trans, folder_id, data_managers, label="Data Managers" )
+ containers_dict[ 'valid_data_managers' ] = data_managers_root_folder
+ error_messages = metadata['data_manager'].get( 'error_messages', None )
+ data_managers = metadata['data_manager'].get( 'invalid_data_managers', None )
+ folder_id, data_managers_root_folder = container_util.build_invalid_data_managers_folder( trans, folder_id, data_managers, error_messages, label="Invalid Data Managers" )
+ containers_dict[ 'invalid_data_managers' ] = data_managers_root_folder
+
except Exception, e:
log.debug( "Exception in build_repository_containers_for_tool_shed: %s" % str( e ) )
finally:
@@ -1044,20 +1072,6 @@
"""Update the received metadata_dict with information from the parsed data_manager_config_filename."""
if data_manager_config_filename is None:
return metadata_dict
- try:
- tree = util.parse_xml( data_manager_config_filename )
- except Exception, e:
- log.error( 'There was an error parsing your Data Manager config file "%s": %s' % ( data_manager_config_filename, e ) )
- return metadata_dict #we are not able to load any data managers
- tool_path = None
- if shed_config_dict:
- tool_path = shed_config_dict.get( 'tool_path', None )
- tools = {}
- for tool in metadata_dict.get( 'tools', [] ):
- tool_conf_name = tool['tool_config']
- if tool_path:
- tool_conf_name = os.path.join( tool_path, tool_conf_name )
- tools[tool_conf_name] = tool
repo_path = repository.repo_path( app )
try:
#Galaxy Side
@@ -1071,37 +1085,65 @@
relative_data_manager_dir = util.relpath( os.path.split( data_manager_config_filename )[0], repo_dir )
rel_data_manager_config_filename = os.path.join( relative_data_manager_dir, os.path.split( data_manager_config_filename )[1] )
data_managers = {}
- data_manager_metadata = { 'config_filename': rel_data_manager_config_filename, 'data_managers': data_managers }#'tool_config_files': tool_files }
+ invalid_data_managers = []
+ data_manager_metadata = { 'config_filename': rel_data_manager_config_filename, 'data_managers': data_managers, 'invalid_data_managers': invalid_data_managers, 'error_messages': [] }#'tool_config_files': tool_files }
metadata_dict[ 'data_manager' ] = data_manager_metadata
+ try:
+ tree = util.parse_xml( data_manager_config_filename )
+ except Exception, e:
+ error_message = 'There was an error parsing your Data Manager config file "%s": %s' % ( data_manager_config_filename, e )
+ log.error( error_message )
+ data_manager_metadata['error_messages'].append( error_message )
+ return metadata_dict #we are not able to load any data managers
+ tool_path = None
+ if shed_config_dict:
+ tool_path = shed_config_dict.get( 'tool_path', None )
+ tools = {}
+ for tool in metadata_dict.get( 'tools', [] ):
+ tool_conf_name = tool['tool_config']
+ if tool_path:
+ tool_conf_name = os.path.join( tool_path, tool_conf_name )
+ tools[tool_conf_name] = tool
root = tree.getroot()
data_manager_tool_path = root.get( 'tool_path', None )
if data_manager_tool_path:
relative_data_manager_dir = os.path.join( relative_data_manager_dir, data_manager_tool_path )
- for data_manager_elem in root.findall( 'data_manager' ):
+ for i, data_manager_elem in enumerate( root.findall( 'data_manager' ) ):
tool_file = data_manager_elem.get( 'tool_file', None )
data_manager_id = data_manager_elem.get( 'id', None )
if data_manager_id is None:
log.error( 'Data Manager entry is missing id attribute in "%s".' % ( data_manager_config_filename ) )
+ invalid_data_managers.append( { 'index': i, 'error_message': 'Data Manager entry is missing id attribute' } )
continue
+ data_manager_name = data_manager_elem.get( 'name', data_manager_id ) #fix me, default behavior is to fall back to tool.name
version = data_manager_elem.get( 'version', DataManager.DEFAULT_VERSION )
guid = generate_guid_for_object( repository_clone_url, DataManager.GUID_TYPE, data_manager_id, version )
data_tables = []
if tool_file is None:
log.error( 'Data Manager entry is missing tool_file attribute in "%s".' % ( data_manager_config_filename ) )
+ invalid_data_managers.append( { 'index': i, 'error_message': 'Data Manager entry is missing tool_file attribute' } )
+ continue
else:
+ bad_data_table = False
for data_table_elem in data_manager_elem.findall( 'data_table' ):
data_table_name = data_table_elem.get( 'name', None )
if data_table_name is None:
- log.error( 'Data Manager data_table entry is name attribute in "%s".' % ( data_manager_config_filename ) )
+ log.error( 'Data Manager data_table entry is missing name attribute in "%s".' % ( data_manager_config_filename ) )
+ invalid_data_managers.append( { 'index': i, 'error_message': 'Data Manager entry is missing name attribute' } )
+ bad_data_table = True
+ break
else:
data_tables.append( data_table_name )
+ if bad_data_table:
+ continue
data_manager_metadata_tool_file = os.path.join( relative_data_manager_dir, tool_file )
tool_metadata_tool_file = os.path.join( repo_files_directory, data_manager_metadata_tool_file )
tool = tools.get( tool_metadata_tool_file, None )
if tool is None:
log.error( "Unable to determine tools metadata for '%s'." % ( data_manager_metadata_tool_file ) )
+ invalid_data_managers.append( { 'index': i, 'error_message': 'Unable to determine tools metadata' } )
continue
- data_managers[ data_manager_id ] = { 'guid': guid, 'version': version, 'tool_config_file': data_manager_metadata_tool_file, 'data_tables': data_tables, 'tool_guid': tool['guid'] }
+ data_managers[ data_manager_id ] = { 'id': data_manager_id, 'name': data_manager_name, 'guid': guid, 'version': version, 'tool_config_file': data_manager_metadata_tool_file, 'data_tables': data_tables, 'tool_guid': tool['guid'] }
log.debug( 'Loaded Data Manager tool_files: %s' % ( tool_file ) )
return metadata_dict
def generate_datatypes_metadata( datatypes_config, metadata_dict ):
diff -r 852b9d795423015cba17d6c0d5b402f1055404dd -r 7d0a0ca401f7cee8b2862c4191f4c1c073cc538d lib/galaxy/webapps/community/util/container_util.py
--- a/lib/galaxy/webapps/community/util/container_util.py
+++ b/lib/galaxy/webapps/community/util/container_util.py
@@ -19,6 +19,8 @@
self.invalid_tool_dependencies = []
self.invalid_tools = []
self.valid_tools = []
+ self.valid_data_managers = []
+ self.invalid_data_managers = []
self.tool_dependencies = []
self.repository_dependencies = []
self.readme_files = []
@@ -47,6 +49,14 @@
repository_owner=owner,
changeset_revision=changeset_revision )
+class DataManager( object ):
+ """Data Manager object"""
+ def __init__( self, id=None, name=None, version=None, data_tables=None ):
+ self.id = id
+ self.name = name
+ self.version = version
+ self.data_tables = data_tables
+
class Datatype( object ):
"""Datatype object"""
def __init__( self, id=None, extension=None, type=None, mimetype=None, subclass=None ):
@@ -56,6 +66,13 @@
self.mimetype = mimetype
self.subclass = subclass
+class InvalidDataManager( object ):
+ """Data Manager object"""
+ def __init__( self, id=None, index=None, error=None ):
+ self.id = id
+ self.index = index
+ self.error = error
+
class InvalidRepositoryDependency( object ):
"""Invalid repository dependency definition object"""
def __init__( self, id=None, toolshed=None, repository_name=None, repository_owner=None, changeset_revision=None, error=None ):
@@ -151,6 +168,35 @@
self.repository_metadata_id = repository_metadata_id
self.repository_id = repository_id
+def build_data_managers_folder( trans, folder_id, data_managers, label=None ):
+ """Return a folder hierarchy containing Data Managers."""
+ if data_managers:
+ if label is None:
+ label = "Data Managers"
+ data_manager_id = 0
+ folder_id += 1
+ data_managers_root_folder = Folder( id=folder_id, key='root', label='root', parent=None )
+ folder_id += 1
+ key = "valid_data_managers"
+ folder = Folder( id=folder_id, key=key, label=label, parent=data_managers_root_folder )
+ data_managers_root_folder.folders.append( folder )
+ # Insert a header row.
+ data_manager_id += 1
+ data_manager = DataManager( id=data_manager_id,
+ name='Name',
+ version='Version',
+ data_tables='Data Tables' )
+ folder.valid_data_managers.append( data_manager )
+ for data_manager_dict in data_managers.itervalues():
+ data_manager_id += 1
+ data_manager = DataManager( id=data_manager_id,
+ name=data_manager_dict.get( 'name', '' ),
+ version=data_manager_dict.get( 'version', '' ),
+ data_tables=", ".join( data_manager_dict.get( 'data_tables', '' ) ) )
+ folder.valid_data_managers.append( data_manager )
+ else:
+ data_managers_root_folder = None
+ return folder_id, data_managers_root_folder
def build_datatypes_folder( trans, folder_id, datatypes, label='Datatypes' ):
"""Return a folder hierarchy containing datatypes."""
if datatypes:
@@ -179,6 +225,42 @@
else:
datatypes_root_folder = None
return folder_id, datatypes_root_folder
+def build_invalid_data_managers_folder( trans, folder_id, data_managers, error_messages=None, label=None ):
+ """Return a folder hierarchy containing invalid Data Managers."""
+ if data_managers or error_messages:
+ if label is None:
+ label = "Invalid Data Managers"
+ data_manager_id = 0
+ folder_id += 1
+ data_managers_root_folder = Folder( id=folder_id, key='root', label='root', parent=None )
+ folder_id += 1
+ key = "invalid_data_managers"
+ folder = Folder( id=folder_id, key=key, label=label, parent=data_managers_root_folder )
+ data_managers_root_folder.folders.append( folder )
+ # Insert a header row.
+ data_manager_id += 1
+ data_manager = InvalidDataManager( id=data_manager_id,
+ index='Element Index',
+ error='Error' )
+ folder.invalid_data_managers.append( data_manager )
+ if error_messages:
+ for error_message in error_messages:
+ data_manager_id += 1
+ data_manager = InvalidDataManager( id=data_manager_id,
+ index=0,
+ error=error_message )
+ folder.invalid_data_managers.append( data_manager )
+ has_errors = True
+ for data_manager_dict in data_managers:
+ data_manager_id += 1
+ data_manager = InvalidDataManager( id=data_manager_id,
+ index=data_manager_dict.get( 'index', 0 ) + 1,
+ error=data_manager_dict.get( 'error_message', '' ) )
+ folder.invalid_data_managers.append( data_manager )
+ has_errors = True
+ else:
+ data_managers_root_folder = None
+ return folder_id, data_managers_root_folder
def build_invalid_repository_dependencies_root_folder( trans, folder_id, invalid_repository_dependencies_dict ):
"""Return a folder hierarchy containing invalid repository dependencies."""
label = 'Invalid repository dependencies'
diff -r 852b9d795423015cba17d6c0d5b402f1055404dd -r 7d0a0ca401f7cee8b2862c4191f4c1c073cc538d templates/webapps/community/repository/common.mako
--- a/templates/webapps/community/repository/common.mako
+++ b/templates/webapps/community/repository/common.mako
@@ -248,6 +248,14 @@
else:
folder_label = "%s<i> - click the name to view an SVG image of the workflow</i>" % folder_label
col_span_str = 'colspan="4"'
+ elif folder.valid_data_managers:
+ if folder.description:
+ folder_label = "%s<i> - %s</i>" % ( folder_label, folder.description )
+ col_span_str = 'colspan="3"'
+ elif folder.invalid_data_managers:
+ if folder.description:
+ folder_label = "%s<i> - %s</i>" % ( folder_label, folder.description )
+ col_span_str = 'colspan="2"'
%><td ${col_span_str} style="padding-left: ${folder_pad}px;"><span class="expandLink folder-${encoded_id}-click">
@@ -305,6 +313,18 @@
${render_datatype( datatype, pad, my_row, row_counter, row_is_header )}
%endfor
%endif
+ %if folder.valid_data_managers:
+ %for index, data_manager in enumerate( folder.valid_data_managers ):
+ <% row_is_header = index == 0 %>
+ ${render_valid_data_manager( data_manager, pad, my_row, row_counter, row_is_header )}
+ %endfor
+ %endif
+ %if folder.invalid_data_managers:
+ %for index, data_manager in enumerate( folder.invalid_data_managers ):
+ <% row_is_header = index == 0 %>
+ ${render_invalid_data_manager( data_manager, pad, my_row, row_counter, row_is_header )}
+ %endfor
+ %endif
</%def><%def name="render_datatype( datatype, pad, parent, row_counter, row_is_header=False )">
@@ -331,6 +351,51 @@
%></%def>
+<%def name="render_valid_data_manager( data_manager, pad, parent, row_counter, row_is_header=False )">
+ <%
+ encoded_id = trans.security.encode_id( data_manager.id )
+ if row_is_header:
+ cell_type = 'th'
+ else:
+ cell_type = 'td'
+ %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ <${cell_type} style="padding-left: ${pad+20}px;">${data_manager.name | h}</${cell_type}>
+ <${cell_type}>${data_manager.version | h}</${cell_type}>
+ <${cell_type}>${data_manager.data_tables | h}</${cell_type}>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
+<%def name="render_invalid_data_manager( data_manager, pad, parent, row_counter, row_is_header=False )">
+ <%
+ encoded_id = trans.security.encode_id( data_manager.id )
+ if row_is_header:
+ cell_type = 'th'
+ else:
+ cell_type = 'td'
+ %>
+ <tr class="datasetRow"
+ %if parent is not None:
+ parent="${parent}"
+ %endif
+ id="libraryItem-${encoded_id}">
+ <${cell_type} style="padding-left: ${pad+20}px;">${data_manager.index | h}</${cell_type}>
+ <${cell_type}>${data_manager.error | h}</${cell_type}>
+ </tr>
+ <%
+ my_row = row_counter.count
+ row_counter.increment()
+ %>
+</%def>
+
<%def name="render_invalid_repository_dependency( invalid_repository_dependency, pad, parent, row_counter )"><%
encoded_id = trans.security.encode_id( invalid_repository_dependency.id )
@@ -638,6 +703,8 @@
missing_tool_dependencies_root_folder = containers_dict.get( 'missing_tool_dependencies', None )
valid_tools_root_folder = containers_dict.get( 'valid_tools', None )
workflows_root_folder = containers_dict.get( 'workflows', None )
+ valid_data_managers_root_folder = containers_dict.get( 'valid_data_managers', None )
+ invalid_data_managers_root_folder = containers_dict.get( 'invalid_data_managers', None )
has_contents = datatypes_root_folder or invalid_tools_root_folder or valid_tools_root_folder or workflows_root_folder
has_dependencies = \
@@ -736,6 +803,20 @@
${render_folder( invalid_tools_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
</table>
%endif
+ %if valid_data_managers_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="2" cellpadding="2" border="0" width="100%" class="tables container-table" id="valid_tools">
+ ${render_folder( valid_data_managers_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
+ %if invalid_data_managers_root_folder:
+ <p/>
+ <% row_counter = RowCounter() %>
+ <table cellspacing="2" cellpadding="2" border="0" width="100%" class="tables container-table" id="invalid_tools">
+ ${render_folder( invalid_data_managers_root_folder, 0, parent=None, row_counter=row_counter, is_root_folder=True )}
+ </table>
+ %endif
%if workflows_root_folder:
<p/><% row_counter = RowCounter() %>
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/852b9d795423/
changeset: 852b9d795423
user: greg
date: 2013-02-18 17:04:29
summary: Fix for handling proprietary datatyps definitions in repositories being installed from the tool shed when only datatyes that subclass from those in the Galaxy frameowrk are defined (i.e., there are no proprietary datatype class files for the datatypes). In addition, this changeset now properly handles installing a tool shed repository that included prioretary datatype definitions (they were failing due to a bug in this same method).
affected #: 1 file
diff -r 36ab5b39b985d84d02b449eeaa4876ad73190317 -r 852b9d795423015cba17d6c0d5b402f1055404dd lib/galaxy/util/shed_util.py
--- a/lib/galaxy/util/shed_util.py
+++ b/lib/galaxy/util/shed_util.py
@@ -125,12 +125,24 @@
be False when a tool shed repository is being installed. Since installation is occurring after the datatypes registry
has been initialized, the registry's contents cannot be overridden by conflicting data types.
"""
- tree = util.parse_xml( datatypes_config )
+ try:
+ tree = util.parse_xml( datatypes_config )
+ except Exception, e:
+ log.debug( "Error parsing %s, exception: %s" % ( datatypes_config, str( e ) ) )
+ return None, None
datatypes_config_root = tree.getroot()
- # Path to datatype converters
- converter_path = None
- # Path to datatype display applications
- display_path = None
+ registration = datatypes_config_root.find( 'registration' )
+ if registration is None:
+ # We have valid XML, but not a valid proprietary datatypes definition.
+ return None, None
+ sniffers = datatypes_config_root.find( 'sniffers' )
+ converter_path, display_path = get_converter_and_display_paths( registration, relative_install_dir )
+ if converter_path:
+ # Path to datatype converters
+ registration.attrib[ 'proprietary_converter_path' ] = converter_path
+ if display_path:
+ # Path to datatype display applications
+ registration.attrib[ 'proprietary_display_path' ] = display_path
relative_path_to_datatype_file_name = None
datatype_files = datatypes_config_root.find( 'datatype_files' )
datatype_class_modules = []
@@ -153,12 +165,6 @@
break
break
if datatype_class_modules:
- registration = datatypes_config_root.find( 'registration' )
- converter_path, display_path = get_converter_and_display_paths( registration, relative_install_dir )
- if converter_path:
- registration.attrib[ 'proprietary_converter_path' ] = converter_path
- if display_path:
- registration.attrib[ 'proprietary_display_path' ] = display_path
for relative_path_to_datatype_file_name in datatype_class_modules:
datatype_file_name_path, datatype_file_name = os.path.split( relative_path_to_datatype_file_name )
for elem in registration.findall( 'datatype' ):
@@ -175,20 +181,16 @@
# The value of proprietary_path must be an absolute path due to job_working_directory.
elem.attrib[ 'proprietary_path' ] = os.path.abspath( datatype_file_name_path )
elem.attrib[ 'proprietary_datatype_module' ] = proprietary_datatype_module
- sniffers = datatypes_config_root.find( 'sniffers' )
- else:
- sniffers = None
- fd, proprietary_datatypes_config = tempfile.mkstemp()
- os.write( fd, '<?xml version="1.0"?>\n' )
- os.write( fd, '<datatypes>\n' )
- os.write( fd, '%s' % util.xml_to_string( registration ) )
- if sniffers:
- os.write( fd, '%s' % util.xml_to_string( sniffers ) )
- os.write( fd, '</datatypes>\n' )
- os.close( fd )
- os.chmod( proprietary_datatypes_config, 0644 )
- else:
- proprietary_datatypes_config = datatypes_config
+ # Temporarily persist the proprietary datatypes configuration file so it can be loaded into the datatypes registry.
+ fd, proprietary_datatypes_config = tempfile.mkstemp()
+ os.write( fd, '<?xml version="1.0"?>\n' )
+ os.write( fd, '<datatypes>\n' )
+ os.write( fd, '%s' % util.xml_to_string( registration ) )
+ if sniffers:
+ os.write( fd, '%s' % util.xml_to_string( sniffers ) )
+ os.write( fd, '</datatypes>\n' )
+ os.close( fd )
+ os.chmod( proprietary_datatypes_config, 0644 )
# Load proprietary datatypes
app.datatypes_registry.load_datatypes( root_dir=app.config.root, config=proprietary_datatypes_config, deactivate=deactivate, override=override )
if datatype_files:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
18 Feb '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/36ab5b39b985/
changeset: 36ab5b39b985
user: greg
date: 2013-02-18 16:01:40
summary: A bit of messaging cleanup in the tool shed.
affected #: 3 files
diff -r 131f63d242216522ffb06cada3684fbf93fe9254 -r 36ab5b39b985d84d02b449eeaa4876ad73190317 lib/galaxy/util/shed_util_common.py
--- a/lib/galaxy/util/shed_util_common.py
+++ b/lib/galaxy/util/shed_util_common.py
@@ -1166,6 +1166,33 @@
else:
valid_tool_dependencies_dict[ 'set_environment' ] = [ requirements_dict ]
return valid_tool_dependencies_dict
+def generate_message_for_invalid_repository_dependencies( metadata_dict ):
+ """Return the error message associated with an invalid repository dependency for display in the caller."""
+ message = ''
+ if metadata_dict:
+ invalid_repository_dependencies_dict = metadata_dict.get( 'invalid_repository_dependencies', None )
+ if invalid_repository_dependencies_dict:
+ invalid_repository_dependencies = invalid_repository_dependencies_dict[ 'invalid_repository_dependencies' ]
+ for repository_dependency_tup in invalid_repository_dependencies:
+ toolshed, name, owner, changeset_revision, error = repository_dependency_tup
+ if error:
+ message = '%s ' % str( error )
+ return message
+def generate_message_for_invalid_tool_dependencies( metadata_dict ):
+ """
+ Due to support for orphan tool dependencies (which are always valid) tool dependency definitions can only be invalid if they include a definition for a complex
+ repository dependency and the repository dependency definition is invalid. This method retrieves the error message associated with the invalid tool dependency
+ for display in the caller.
+ """
+ message = ''
+ if metadata_dict:
+ invalid_tool_dependencies = metadata_dict.get( 'invalid_tool_dependencies', None )
+ if invalid_tool_dependencies:
+ for td_key, requirement_dict in invalid_tool_dependencies.items():
+ error = requirement_dict.get( 'error', None )
+ if error:
+ message = '%s ' % str( error )
+ return message
def generate_message_for_invalid_tools( trans, invalid_file_tups, repository, metadata_dict, as_html=True, displaying_invalid_tool=False ):
if as_html:
new_line = '<br/>'
@@ -1211,7 +1238,6 @@
is considered valid but perhaps an orphan due to it's actual invalidity.
"""
message = ''
- status = 'done'
if metadata_dict:
orphan_tool_dependencies = metadata_dict.get( 'orphan_tool_dependencies', None )
if orphan_tool_dependencies:
@@ -1237,8 +1263,7 @@
version = requirements_dict[ 'version' ]
message += "<b>* name:</b> %s, <b>type:</b> %s, <b>version:</b> %s<br/>" % ( str( name ), str( type ), str( version ) )
message += "<br/>"
- status = 'warning'
- return message, status
+ return message
def generate_metadata_for_changeset_revision( app, repository, changeset_revision, repository_clone_url, shed_config_dict=None, relative_install_dir=None,
repository_files_dir=None, resetting_all_metadata_on_repository=False, updating_installed_repository=False,
persist=False ):
diff -r 131f63d242216522ffb06cada3684fbf93fe9254 -r 36ab5b39b985d84d02b449eeaa4876ad73190317 lib/galaxy/webapps/community/controllers/repository.py
--- a/lib/galaxy/webapps/community/controllers/repository.py
+++ b/lib/galaxy/webapps/community/controllers/repository.py
@@ -2000,10 +2000,11 @@
key_rd_dicts_to_be_processed=None,
all_repository_dependencies=None,
handled_key_rd_dicts=None )
- if metadata:
- if 'orphan_tool_dependencies' in metadata:
- orphan_message, status = suc.generate_message_for_orphan_tool_dependencies( metadata )
- message += orphan_message
+ # Handle messaging for orphan tool dependencies.
+ orphan_message = suc.generate_message_for_orphan_tool_dependencies( metadata )
+ if orphan_message:
+ message += orphan_message
+ status = 'warning'
if is_malicious:
if trans.app.security_agent.can_push( trans.app, trans.user, repository ):
message += malicious_error_can_push
@@ -2752,10 +2753,11 @@
key_rd_dicts_to_be_processed=None,
all_repository_dependencies=None,
handled_key_rd_dicts=None )
- if metadata:
- if 'orphan_tool_dependencies' in metadata:
- orphan_message, status = suc.generate_message_for_orphan_tool_dependencies( metadata )
- message += orphan_message
+ # Handle messaging for orphan tool dependencies.
+ orphan_message = suc.generate_message_for_orphan_tool_dependencies( metadata )
+ if orphan_message:
+ message += orphan_message
+ status = 'warning'
else:
repository_metadata_id = None
metadata = None
diff -r 131f63d242216522ffb06cada3684fbf93fe9254 -r 36ab5b39b985d84d02b449eeaa4876ad73190317 lib/galaxy/webapps/community/controllers/upload.py
--- a/lib/galaxy/webapps/community/controllers/upload.py
+++ b/lib/galaxy/webapps/community/controllers/upload.py
@@ -167,33 +167,29 @@
message += " %d files were removed from the repository root. " % len( files_to_remove )
kwd[ 'message' ] = message
suc.set_repository_metadata_due_to_new_tip( trans, repository, content_alert_str=content_alert_str, **kwd )
- # Provide a warning message if a tool_dependencies.xml file is provided, but tool dependencies weren't loaded due to a requirement tag mismatch
- # or some other problem.
if repository.metadata_revisions:
# A repository's metadata revisions are order descending by update_time, so the zeroth revision will be the tip just after an upload.
metadata_dict = repository.metadata_revisions[0].metadata
else:
metadata_dict = {}
+ # Provide a warning message if a tool_dependencies.xml file is provided, but tool dependencies weren't loaded due to a requirement tag mismatch
+ # or some other problem. Tool dependency definitions can define orphan tool dependencies (no relationship to any tools contained in the repository),
+ # so warning messages are important because orphans are always valid. The repository owner must be warned in case they did not intend to define an
+ # orphan dependency, but simply provided incorrect information (tool shed, name owner, changeset_revision) for the definition.
# Handle messaging for orphan tool dependencies.
- orphan_message, status = suc.generate_message_for_orphan_tool_dependencies( metadata_dict )
+ orphan_message = suc.generate_message_for_orphan_tool_dependencies( metadata_dict )
if orphan_message:
message += orphan_message
- # Display message for invalid tool sependencies.
- invalid_tool_dependencies = metadata_dict.get( 'invalid_tool_dependencies', None )
- if invalid_tool_dependencies:
- for td_key, requirement_dict in invalid_tool_dependencies.items():
- error = requirement_dict.get( 'error', None )
- if error:
- message = "%s %s" % ( message, str( error ) )
+ status = 'warning'
+ # Handle messaging for invalid tool dependencies.
+ invalid_tool_dependencies_message = suc.generate_message_for_invalid_tool_dependencies( metadata_dict )
+ if invalid_tool_dependencies_message:
+ message += invalid_tool_dependencies_message
status = 'error'
- # Display message for invalid repository dependencies.
- invalid_repository_dependencies_dict = metadata_dict.get( 'invalid_repository_dependencies', None )
- if invalid_repository_dependencies_dict:
- invalid_repository_dependencies = invalid_repository_dependencies_dict[ 'invalid_repository_dependencies' ]
- for repository_dependency_tup in invalid_repository_dependencies:
- toolshed, name, owner, changeset_revision, error = repository_dependency_tup
- if error:
- message += "%s %s" % ( message, str( error ) )
+ # Handle messaging for invalid repository dependencies.
+ invalid_repository_dependencies_message = suc.generate_message_for_invalid_repository_dependencies( metadata_dict )
+ if invalid_repository_dependencies_message:
+ message += invalid_repository_dependencies_message
status = 'error'
# Reset the tool_data_tables by loading the empty tool_data_table_conf.xml file.
suc.reset_tool_data_tables( trans.app )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0