galaxy-commits
Threads by month
- ----- 2026 -----
- October
- 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: Dave Bouvier: Fix for filtering out repository dependencies that are only required when compiling a tool dependency because the precompiled binary was not found or failed to install.
by commits-noreply@bitbucket.org 11 Sep '13
by commits-noreply@bitbucket.org 11 Sep '13
11 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/cd91ec8f1405/
Changeset: cd91ec8f1405
User: Dave Bouvier
Date: 2013-09-10 20:35:06
Summary: Fix for filtering out repository dependencies that are only required when compiling a tool dependency because the precompiled binary was not found or failed to install.
Affected #: 1 file
diff -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e -r cd91ec8f14059167cdfda2ab606035c97ead5469 lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -678,7 +678,7 @@
current_repository_key_rd_dicts = get_updated_changeset_revisions_for_repository_dependencies( trans, current_repository_key_rd_dicts )
for key_rd_dict in current_repository_key_rd_dicts:
# Filter out repository dependencies that are required only if compiling the dependent repository's tool dependency.
- all_repository_dependencieskey_rd_dict = filter_only_if_compiling_contained_td( key_rd_dict )
+ key_rd_dict = filter_only_if_compiling_contained_td( key_rd_dict )
if key_rd_dict:
is_circular = False
if not in_key_rd_dicts( key_rd_dict, handled_key_rd_dicts ) and not in_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
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: Slight refactoring of message generation in the tool shed.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/595c30bc8df5/
Changeset: 595c30bc8df5
User: greg
Date: 2013-09-10 20:19:46
Summary: Slight refactoring of message generation in the tool shed.
Affected #: 5 files
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -2159,11 +2159,17 @@
all_repository_dependencies=None,
handled_key_rd_dicts=None )
if str( repository.type ) != rt_util.TOOL_DEPENDENCY_DEFINITION:
- # Handle messaging for orphan tool dependencies.
- orphan_message = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata )
- if orphan_message:
- message += orphan_message
+ # Handle messaging for resetting repository type to the optimal value.
+ change_repository_type_message = tool_dependency_util.generate_message_for_repository_type_change( trans, repository )
+ if change_repository_type_message:
+ message += change_repository_type_message
status = 'warning'
+ else:
+ # Handle messaging for orphan tool dependency definitions.
+ orphan_message = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, 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
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e lib/galaxy/webapps/tool_shed/controllers/upload.py
--- a/lib/galaxy/webapps/tool_shed/controllers/upload.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/upload.py
@@ -207,15 +207,20 @@
else:
metadata_dict = {}
if str( repository.type ) != rt_util.TOOL_DEPENDENCY_DEFINITION:
- # 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 = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata_dict )
- if orphan_message:
- message += orphan_message
+ change_repository_type_message = tool_dependency_util.generate_message_for_repository_type_change( trans, repository )
+ if change_repository_type_message:
+ message += change_repository_type_message
status = 'warning'
+ else:
+ # 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 = tool_dependency_util.generate_message_for_orphan_tool_dependencies( trans, repository, metadata_dict )
+ if orphan_message:
+ message += orphan_message
+ status = 'warning'
# Handle messaging for invalid tool dependencies.
invalid_tool_dependencies_message = tool_dependency_util.generate_message_for_invalid_tool_dependencies( metadata_dict )
if invalid_tool_dependencies_message:
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -906,13 +906,13 @@
repository_dependency_tups=invalid_repository_dependency_tups,
is_valid=False,
description=description )
- # We need to continue to restrict the behavior of orphan tool dependencies, possibly eliminating them altoghether at some point.
+ # We need to continue to restrict the behavior for defining orphan tool dependencies, possibly eliminating them altoghether at some point.
check_for_orphan_tool_dependencies = False
if app.name == 'tool_shed':
- if repository.type == rt_util.UNRESTRICTED and 'tools' not in metadata_dict:
+ if repository.type != rt_util.TOOL_DEPENDENCY_DEFINITION and not repository.can_change_type_to( app, rt_util.TOOL_DEPENDENCY_DEFINITION ):
check_for_orphan_tool_dependencies = True
- elif 'tools' in metadata_dict:
- check_for_orphan_tool_dependencies = True
+ elif 'tools' in metadata_dict:
+ check_for_orphan_tool_dependencies = True
if check_for_orphan_tool_dependencies:
# Determine and store orphan tool dependencies.
orphan_tool_dependencies = get_orphan_tool_dependencies( metadata_dict )
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -150,14 +150,17 @@
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/>"
- elif repository.can_change_type_to( trans.app, rt_util.TOOL_DEPENDENCY_DEFINITION ):
- tool_dependency_definition_type_class = trans.app.repository_types_registry.get_class_by_label( rt_util.TOOL_DEPENDENCY_DEFINITION )
- message += "This repository currently contains a single file named <b>%s</b>. If additional files will " % suc.TOOL_DEPENDENCY_DEFINITION_FILENAME
- message += "not be added to this repository, then it's type should be set to <b>%s</b>.<br/>" % tool_dependency_definition_type_class.label
- else:
- message += "This repository contains no tools, so it's defined tool dependencies are considered orphans within this repository.<br/>"
return message
+def generate_message_for_repository_type_change( trans, repository ):
+ message = ''
+ if repository.can_change_type_to( trans.app, rt_util.TOOL_DEPENDENCY_DEFINITION ):
+ tool_dependency_definition_type_class = trans.app.repository_types_registry.get_class_by_label( rt_util.TOOL_DEPENDENCY_DEFINITION )
+ message += "This repository currently contains a single file named <b>%s</b>. If additional files will " % suc.TOOL_DEPENDENCY_DEFINITION_FILENAME
+ message += "not be added to this repository, then it's type should be set to <b>%s</b>.<br/>" % tool_dependency_definition_type_class.label
+ return message
+
+
def get_download_url_for_platform( url_templates, platform_info_dict ):
'''
Compare the dict returned by get_platform_info() with the values specified in the url_template element. Return
diff -r 04a3137539d245fa294f73f8b6467a5b13e6d028 -r 595c30bc8df5dfd626d78cc4e030ac1910b54f4e test/tool_shed/functional/test_0100_complex_repository_dependencies.py
--- a/test/tool_shed/functional/test_0100_complex_repository_dependencies.py
+++ b/test/tool_shed/functional/test_0100_complex_repository_dependencies.py
@@ -54,7 +54,7 @@
strings_displayed=[ 'This repository currently contains a single file named <b>tool_dependencies.xml</b>' ],
strings_not_displayed=[] )
# Visit the manage repository page for package_bwa_0_5_9_0100.
- self.display_manage_repository_page( repository, strings_displayed=[ 'Tool dependencies', 'may not be', 'in this repository' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'Tool dependencies', 'will not be', 'to this repository' ] )
def test_0010_create_bwa_base_repository( self ):
'''Create and populate bwa_base_0100.'''
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: Don't generate error messages when resetting metadata on installed tool shed repositories that have repository dependencies that are not installed because they were not needed for compiling the dependent repository's tool dependency.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/04a3137539d2/
Changeset: 04a3137539d2
User: greg
Date: 2013-09-10 19:29:18
Summary: Don't generate error messages when resetting metadata on installed tool shed repositories that have repository dependencies that are not installed because they were not needed for compiling the dependent repository's tool dependency.
Affected #: 1 file
diff -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 -r 04a3137539d245fa294f73f8b6467a5b13e6d028 lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -1195,14 +1195,17 @@
repository = suc.get_repository_for_dependency_relationship( app, cleaned_toolshed, name, owner, updated_changeset_revision )
if repository:
return repository_dependency_tup, is_valid, error_message
- # We'll currently default to setting the repository dependency definition as invalid if an installed repository cannot be found.
- # This may not be ideal because the tool shed may have simply been inaccessible when metadata was being generated for the installed
- # tool shed repository.
- error_message = "Ignoring invalid repository dependency definition for tool shed %s, name %s, owner %s, changeset revision %s "% \
- ( toolshed, name, owner, changeset_revision )
- log.debug( error_message )
- is_valid = False
- return repository_dependency_tup, is_valid, error_message
+ # Don't generate an error message for missing repository dependencies that are required only if compiling the dependent repository's
+ # tool dependency.
+ if not only_if_compiling_contained_td:
+ # We'll currently default to setting the repository dependency definition as invalid if an installed repository cannot be found.
+ # This may not be ideal because the tool shed may have simply been inaccessible when metadata was being generated for the installed
+ # tool shed repository.
+ error_message = "Ignoring invalid repository dependency definition for tool shed %s, name %s, owner %s, changeset revision %s "% \
+ ( toolshed, name, owner, changeset_revision )
+ log.debug( error_message )
+ is_valid = False
+ return repository_dependency_tup, is_valid, error_message
else:
# We're in the tool shed.
if suc.tool_shed_is_this_tool_shed( toolshed ):
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
3 new commits in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/0bc38956530a/
Changeset: 0bc38956530a
Branch: dataset-cleanup
User: lance_parsons
Date: 2013-04-18 17:24:09
Summary: Basic administrative dataset cleanup script
Affected #: 3 files
diff -r 18b23ed8de5b384f142db349e7379c03567758df -r 0bc38956530a382faea4b42e771037672c2a6b0c scripts/cleanup_datasets/admin_cleanup_datasets.py
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+"""
+Mark datasets as deleted that are older than specified cutoff
+and (optionaly) with a tool_id that matches the specified search
+string.
+
+This script is useful for administrators to cleanup after users who
+leave many old datasets around. It was modeled after the cleanup_datasets.py
+script originally distributed with Galaxy.
+
+Basic Usage:
+ admin_cleanup_datasets.py universe_wsgi.ini -d 60 \
+ --template=email_template.txt
+
+Required Arguments:
+ config_file - the Galaxy configuration file (universe_wsgi.ini)
+
+Optional Arguments:
+ -d --days - number of days old the dataset must be (default: 60)
+ --tool_id - string to search for in dataset tool_id
+ --template - Mako template file to use for email notification
+ -i --info_only - Print results, but don't email or delete anything
+ -e --email_only - Email notifications, but don't delete anything
+ Useful for notifying users of pending deletion
+
+ --smtp - Specify smtp server
+ If not specified, use smtp settings specified in config file
+ --fromaddr - Specify from address
+ If not specified, use error_email_to specified in config file
+
+Email Template Variables:
+ cutoff - the cutoff in days
+ email - the users email address
+ datasets - a list of tuples containing 'dataset' and 'history' names
+
+
+Author: Lance Parsons (lparsons(a)princeton.edu)
+"""
+import os
+import sys
+import shutil
+import logging
+from collections import defaultdict
+
+log = logging.getLogger()
+log.setLevel(10)
+log.addHandler(logging.StreamHandler(sys.stdout))
+
+from cleanup_datasets import CleanupDatasetsApplication
+import pkg_resources
+pkg_resources.require("SQLAlchemy >= 0.4")
+
+#pkg_resources.require("Mako")
+from mako.template import Template
+
+import time
+import ConfigParser
+from datetime import datetime, timedelta
+from time import strftime
+from optparse import OptionParser
+
+import galaxy.config
+import galaxy.model.mapping
+import sqlalchemy as sa
+from galaxy.model.orm import and_
+import galaxy.util
+
+assert sys.version_info[:2] >= (2, 4)
+
+
+def main():
+ """
+ Datasets that are older than the specified cutoff and for which the tool_id
+ contains the specified text will be marked as deleted in user's history and
+ the user will be notified by email using the specified template file.
+ """
+ parser = OptionParser()
+ parser.add_option("-d", "--days", dest="days", action="store",
+ type="int", help="number of days (60)", default=60)
+ parser.add_option("--tool_id", default="",
+ help="Text to match against tool_id")
+ parser.add_option("--template", default=None,
+ help="Mako Template file to use as email "
+ "Variables are 'cutoff' for the cutoff in days, "
+ "'email' for users email and "
+ "'datasets' which is a list of tuples "
+ "containing 'dataset' and 'history' names. "
+ "Default: admin_cleanup_deletion_template.txt")
+ parser.add_option("-i", "--info_only", action="store_true",
+ dest="info_only", help="info about the requested action",
+ default=False)
+ parser.add_option("-e", "--email_only", action="store_true",
+ dest="email_only", help="Send emails only, don't delete",
+ default=False)
+ parser.add_option("--smtp", default=None,
+ help="SMTP Server to use to send email. "
+ "Default: [read from galaxy ini file]")
+ parser.add_option("--fromaddr", default=None,
+ help="From address to use to send email. "
+ "Default: [read from galaxy ini file]")
+ (options, args) = parser.parse_args()
+ ini_file = args[0]
+
+ config_parser = ConfigParser.ConfigParser({'here': os.getcwd()})
+ config_parser.read(ini_file)
+ config_dict = {}
+ for key, value in config_parser.items("app:main"):
+ config_dict[key] = value
+
+ if options.smtp is not None:
+ config_dict['smtp_server'] = options.smtp
+ if config_dict.get('smtp_server') is None:
+ parser.error("SMTP Server must be specified as an option (--smtp) "
+ "or in the config file (smtp_server)")
+
+ if options.fromaddr is not None:
+ config_dict['error_email_to'] = options.fromaddr
+ if config_dict.get('error_email_to') is None:
+ parser.error("From address must be specified as an option "
+ "(--fromaddr) or in the config file "
+ "(error_email_to)")
+
+ scriptdir = os.path.dirname(os.path.abspath(__file__))
+ template_file = options.template
+ if template_file is None:
+ default_template = os.path.join(scriptdir,
+ 'admin_cleanup_deletion_template.txt')
+ sample_template_file = "%s.sample" % default_template
+ if os.path.exists(default_template):
+ template_file = default_template
+ elif os.path.exists(sample_template_file):
+ print "Copying %s to %s" % (sample_template_file, default_template)
+ shutil.copyfile(sample_template_file, default_template)
+ template_file = default_template
+ else:
+ parser.error("Default template (%s) or sample template (%s) not "
+ "found, please specify template as an option "
+ "(--template)." % default_template,
+ sample_template_file)
+ elif not os.path.exists(template_file):
+ parser.error("Specified template file (%s) not found." % template_file)
+
+ config = galaxy.config.Configuration(**config_dict)
+
+ app = CleanupDatasetsApplication(config)
+ cutoff_time = datetime.utcnow() - timedelta(days=options.days)
+ now = strftime("%Y-%m-%d %H:%M:%S")
+
+ print "##########################################"
+ print "\n# %s - Handling stuff older than %i days" % (now, options.days)
+
+ if options.info_only:
+ print "# Displaying info only ( --info_only )\n"
+ elif options.email_only:
+ print "# Sending emails only, not deleting ( --email_only )\n"
+
+ administrative_delete_datasets(
+ app, cutoff_time, options.days, tool_id=options.tool_id,
+ template_file=template_file, config=config,
+ email_only=options.email_only, info_only=options.info_only)
+ app.shutdown()
+ sys.exit(0)
+
+
+def administrative_delete_datasets(app, cutoff_time, cutoff_days,
+ tool_id, template_file,
+ config, email_only=False,
+ info_only=False):
+ # Marks dataset history association deleted and email users
+ start = time.time()
+ # We really only need the id column here, but sqlalchemy barfs when
+ # trying to select only 1 column
+ hda_ids_query = sa.select(
+ (app.model.HistoryDatasetAssociation.table.c.id,
+ app.model.HistoryDatasetAssociation.table.c.deleted),
+ whereclause=and_(
+ app.model.Dataset.table.c.deleted == False,
+ app.model.HistoryDatasetAssociation.table.c.update_time
+ < cutoff_time,
+ app.model.Job.table.c.tool_id.like("%%%s%%" % tool_id),
+ app.model.HistoryDatasetAssociation.table.c.deleted == False),
+ from_obj=[sa.outerjoin(
+ app.model.Dataset.table,
+ app.model.HistoryDatasetAssociation.table)
+ .outerjoin(app.model.JobToOutputDatasetAssociation.table)
+ .outerjoin(app.model.Job.table)])
+ deleted_instance_count = 0
+ # skip = []
+ user_notifications = defaultdict(list)
+ # Add all datasets associated with Histories to our list
+ hda_ids = []
+ hda_ids.extend(
+ [row.id for row in hda_ids_query.execute()])
+ # Process each of the Dataset objects
+ for hda_id in hda_ids:
+ user_query = sa.select(
+ [app.model.HistoryDatasetAssociation.table,
+ app.model.History.table,
+ app.model.User.table],
+ whereclause=and_(
+ app.model.HistoryDatasetAssociation.table.c.id == hda_id),
+ from_obj=[sa.join(app.model.User.table,
+ app.model.History.table)
+ .join(app.model.HistoryDatasetAssociation.table)],
+ use_labels=True)
+ for result in user_query.execute():
+ user_notifications[result[app.model.User.table.c.email]].append(
+ (result[app.model.HistoryDatasetAssociation.table.c.name],
+ result[app.model.History.table.c.name]))
+ deleted_instance_count += 1
+ if not info_only and not email_only:
+ # Get the HistoryDatasetAssociation objects
+ hda = app.sa_session.query(
+ app.model.HistoryDatasetAssociation).get(hda_id)
+ if not hda.deleted:
+ # Mark the HistoryDatasetAssociation as deleted
+ hda.deleted = True
+ app.sa_session.add(hda)
+ print ("Marked HistoryDatasetAssociation id %d as "
+ "deleted" % hda.id)
+ app.sa_session.flush()
+
+ emailtemplate = Template(filename=template_file)
+ for (email, dataset_list) in user_notifications.iteritems():
+ msgtext = emailtemplate.render(email=email,
+ datasets=dataset_list,
+ cutoff=cutoff_days)
+ subject = "Galaxy Server Cleanup " \
+ "- %d datasets DELETED" % len(dataset_list)
+ fromaddr = config.error_email_to
+ print ""
+ print "From: %s" % fromaddr
+ print "To: %s" % email
+ print "Subject: %s" % subject
+ print "----------"
+ print msgtext
+ if not info_only:
+ #msg = MIMEText(msgtext)
+ #msg['Subject'] = subject
+ #msg['From'] = 'noone(a)nowhere.com'
+ #msg['To'] = email
+ galaxy.util.send_mail(fromaddr, email, subject,
+ msgtext, config)
+ #s = smtplib.SMTP(smtp_server)
+ #s.sendmail(['lparsons(a)princeton.edu'], email, msg.as_string())
+ #s.quit()
+
+ stop = time.time()
+ print ""
+ print "Marked %d dataset instances as deleted" % deleted_instance_count
+ print "Total elapsed time: ", stop - start
+ print "##########################################"
+
+
+if __name__ == "__main__":
+ main()
diff -r 18b23ed8de5b384f142db349e7379c03567758df -r 0bc38956530a382faea4b42e771037672c2a6b0c scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and have been DELETED:
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+You may be able to undelete them by logging into Galaxy, navigating to the appropriate history, selecting "Include Deleted Datasets" from the history options menu, and clicking on the link to undelete each dataset that you want to keep. You can then download the datasets. Thank you for your understanding and cooporation in this necessary cleanup in order to keep the Galaxy resource available. Please don't hesitate to contact us if you have any questions.
+
+ -- Galaxy Administrators
diff -r 18b23ed8de5b384f142db349e7379c03567758df -r 0bc38956530a382faea4b42e771037672c2a6b0c scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and will be deleted soon. Be sure to download any datasets you need to keep.
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+Please contact us if you have any questions.
+
+ -- Galaxy Administrators
https://bitbucket.org/galaxy/galaxy-central/commits/e4734c99812a/
Changeset: e4734c99812a
Branch: dataset-cleanup
User: lance_parsons
Date: 2013-04-18 21:43:00
Summary: Fix admin_cleanup_datasets.py for copied datasets
Affected #: 1 file
diff -r 0bc38956530a382faea4b42e771037672c2a6b0c -r e4734c99812ad2f240b2fa963ea9af3fa710bd74 scripts/cleanup_datasets/admin_cleanup_datasets.py
--- a/scripts/cleanup_datasets/admin_cleanup_datasets.py
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -17,7 +17,7 @@
Optional Arguments:
-d --days - number of days old the dataset must be (default: 60)
- --tool_id - string to search for in dataset tool_id
+ --tool_id - string to search for in dataset tool_id (default: all)
--template - Mako template file to use for email notification
-i --info_only - Print results, but don't email or delete anything
-e --email_only - Email notifications, but don't delete anything
@@ -47,8 +47,8 @@
log.addHandler(logging.StreamHandler(sys.stdout))
from cleanup_datasets import CleanupDatasetsApplication
-import pkg_resources
-pkg_resources.require("SQLAlchemy >= 0.4")
+#import pkg_resources
+#pkg_resources.require("SQLAlchemy >= 0.4")
#pkg_resources.require("Mako")
from mako.template import Template
@@ -77,8 +77,9 @@
parser = OptionParser()
parser.add_option("-d", "--days", dest="days", action="store",
type="int", help="number of days (60)", default=60)
- parser.add_option("--tool_id", default="",
- help="Text to match against tool_id")
+ parser.add_option("--tool_id", default=None,
+ help="Text to match against tool_id"
+ "Default: match all")
parser.add_option("--template", default=None,
help="Mako Template file to use as email "
"Variables are 'cutoff' for the cutoff in days, "
@@ -168,6 +169,7 @@
info_only=False):
# Marks dataset history association deleted and email users
start = time.time()
+ # Get HDAs older than cutoff time (ignore tool_id at this point)
# We really only need the id column here, but sqlalchemy barfs when
# trying to select only 1 column
hda_ids_query = sa.select(
@@ -177,20 +179,28 @@
app.model.Dataset.table.c.deleted == False,
app.model.HistoryDatasetAssociation.table.c.update_time
< cutoff_time,
- app.model.Job.table.c.tool_id.like("%%%s%%" % tool_id),
app.model.HistoryDatasetAssociation.table.c.deleted == False),
from_obj=[sa.outerjoin(
app.model.Dataset.table,
- app.model.HistoryDatasetAssociation.table)
- .outerjoin(app.model.JobToOutputDatasetAssociation.table)
- .outerjoin(app.model.Job.table)])
- deleted_instance_count = 0
- # skip = []
- user_notifications = defaultdict(list)
- # Add all datasets associated with Histories to our list
+ app.model.HistoryDatasetAssociation.table)])
+
+ # Add all datasets associated with Histories to our list
hda_ids = []
hda_ids.extend(
[row.id for row in hda_ids_query.execute()])
+
+ # Now find the tool_id that generated the dataset (even if it was copied)
+ tool_matched_ids = []
+ if tool_id is not None:
+ for hda_id in hda_ids:
+ this_tool_id = _get_tool_id_for_hda(app, hda_id)
+ if this_tool_id is not None and tool_id in this_tool_id:
+ tool_matched_ids.append(hda_id)
+ hda_ids = tool_matched_ids
+
+ deleted_instance_count = 0
+ user_notifications = defaultdict(list)
+
# Process each of the Dataset objects
for hda_id in hda_ids:
user_query = sa.select(
@@ -252,5 +262,22 @@
print "##########################################"
+def _get_tool_id_for_hda(app, hda_id):
+ # TODO Some datasets don't seem to have an entry in jtod or a copied_from
+ if hda_id is None:
+ return None
+ job = app.sa_session.query(app.model.Job).\
+ join(app.model.JobToOutputDatasetAssociation).\
+ filter(app.model.JobToOutputDatasetAssociation.table.c.dataset_id ==
+ hda_id).first()
+ if job is not None:
+ return job.tool_id
+ else:
+ hda = app.sa_session.query(app.model.HistoryDatasetAssociation).\
+ get(hda_id)
+ return _get_tool_id_for_hda(app, hda.
+ copied_from_history_dataset_association_id)
+
+
if __name__ == "__main__":
main()
https://bitbucket.org/galaxy/galaxy-central/commits/1e30cdb6d3b8/
Changeset: 1e30cdb6d3b8
User: dannon
Date: 2013-09-10 19:14:10
Summary: Merged in lance_parsons/galaxy-central-pull-requests/dataset-cleanup (pull request #158)
Basic administrative dataset cleanup script
Affected #: 3 files
diff -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 scripts/cleanup_datasets/admin_cleanup_datasets.py
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_datasets.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python
+"""
+Mark datasets as deleted that are older than specified cutoff
+and (optionaly) with a tool_id that matches the specified search
+string.
+
+This script is useful for administrators to cleanup after users who
+leave many old datasets around. It was modeled after the cleanup_datasets.py
+script originally distributed with Galaxy.
+
+Basic Usage:
+ admin_cleanup_datasets.py universe_wsgi.ini -d 60 \
+ --template=email_template.txt
+
+Required Arguments:
+ config_file - the Galaxy configuration file (universe_wsgi.ini)
+
+Optional Arguments:
+ -d --days - number of days old the dataset must be (default: 60)
+ --tool_id - string to search for in dataset tool_id (default: all)
+ --template - Mako template file to use for email notification
+ -i --info_only - Print results, but don't email or delete anything
+ -e --email_only - Email notifications, but don't delete anything
+ Useful for notifying users of pending deletion
+
+ --smtp - Specify smtp server
+ If not specified, use smtp settings specified in config file
+ --fromaddr - Specify from address
+ If not specified, use error_email_to specified in config file
+
+Email Template Variables:
+ cutoff - the cutoff in days
+ email - the users email address
+ datasets - a list of tuples containing 'dataset' and 'history' names
+
+
+Author: Lance Parsons (lparsons(a)princeton.edu)
+"""
+import os
+import sys
+import shutil
+import logging
+from collections import defaultdict
+
+log = logging.getLogger()
+log.setLevel(10)
+log.addHandler(logging.StreamHandler(sys.stdout))
+
+from cleanup_datasets import CleanupDatasetsApplication
+#import pkg_resources
+#pkg_resources.require("SQLAlchemy >= 0.4")
+
+#pkg_resources.require("Mako")
+from mako.template import Template
+
+import time
+import ConfigParser
+from datetime import datetime, timedelta
+from time import strftime
+from optparse import OptionParser
+
+import galaxy.config
+import galaxy.model.mapping
+import sqlalchemy as sa
+from galaxy.model.orm import and_
+import galaxy.util
+
+assert sys.version_info[:2] >= (2, 4)
+
+
+def main():
+ """
+ Datasets that are older than the specified cutoff and for which the tool_id
+ contains the specified text will be marked as deleted in user's history and
+ the user will be notified by email using the specified template file.
+ """
+ parser = OptionParser()
+ parser.add_option("-d", "--days", dest="days", action="store",
+ type="int", help="number of days (60)", default=60)
+ parser.add_option("--tool_id", default=None,
+ help="Text to match against tool_id"
+ "Default: match all")
+ parser.add_option("--template", default=None,
+ help="Mako Template file to use as email "
+ "Variables are 'cutoff' for the cutoff in days, "
+ "'email' for users email and "
+ "'datasets' which is a list of tuples "
+ "containing 'dataset' and 'history' names. "
+ "Default: admin_cleanup_deletion_template.txt")
+ parser.add_option("-i", "--info_only", action="store_true",
+ dest="info_only", help="info about the requested action",
+ default=False)
+ parser.add_option("-e", "--email_only", action="store_true",
+ dest="email_only", help="Send emails only, don't delete",
+ default=False)
+ parser.add_option("--smtp", default=None,
+ help="SMTP Server to use to send email. "
+ "Default: [read from galaxy ini file]")
+ parser.add_option("--fromaddr", default=None,
+ help="From address to use to send email. "
+ "Default: [read from galaxy ini file]")
+ (options, args) = parser.parse_args()
+ ini_file = args[0]
+
+ config_parser = ConfigParser.ConfigParser({'here': os.getcwd()})
+ config_parser.read(ini_file)
+ config_dict = {}
+ for key, value in config_parser.items("app:main"):
+ config_dict[key] = value
+
+ if options.smtp is not None:
+ config_dict['smtp_server'] = options.smtp
+ if config_dict.get('smtp_server') is None:
+ parser.error("SMTP Server must be specified as an option (--smtp) "
+ "or in the config file (smtp_server)")
+
+ if options.fromaddr is not None:
+ config_dict['error_email_to'] = options.fromaddr
+ if config_dict.get('error_email_to') is None:
+ parser.error("From address must be specified as an option "
+ "(--fromaddr) or in the config file "
+ "(error_email_to)")
+
+ scriptdir = os.path.dirname(os.path.abspath(__file__))
+ template_file = options.template
+ if template_file is None:
+ default_template = os.path.join(scriptdir,
+ 'admin_cleanup_deletion_template.txt')
+ sample_template_file = "%s.sample" % default_template
+ if os.path.exists(default_template):
+ template_file = default_template
+ elif os.path.exists(sample_template_file):
+ print "Copying %s to %s" % (sample_template_file, default_template)
+ shutil.copyfile(sample_template_file, default_template)
+ template_file = default_template
+ else:
+ parser.error("Default template (%s) or sample template (%s) not "
+ "found, please specify template as an option "
+ "(--template)." % default_template,
+ sample_template_file)
+ elif not os.path.exists(template_file):
+ parser.error("Specified template file (%s) not found." % template_file)
+
+ config = galaxy.config.Configuration(**config_dict)
+
+ app = CleanupDatasetsApplication(config)
+ cutoff_time = datetime.utcnow() - timedelta(days=options.days)
+ now = strftime("%Y-%m-%d %H:%M:%S")
+
+ print "##########################################"
+ print "\n# %s - Handling stuff older than %i days" % (now, options.days)
+
+ if options.info_only:
+ print "# Displaying info only ( --info_only )\n"
+ elif options.email_only:
+ print "# Sending emails only, not deleting ( --email_only )\n"
+
+ administrative_delete_datasets(
+ app, cutoff_time, options.days, tool_id=options.tool_id,
+ template_file=template_file, config=config,
+ email_only=options.email_only, info_only=options.info_only)
+ app.shutdown()
+ sys.exit(0)
+
+
+def administrative_delete_datasets(app, cutoff_time, cutoff_days,
+ tool_id, template_file,
+ config, email_only=False,
+ info_only=False):
+ # Marks dataset history association deleted and email users
+ start = time.time()
+ # Get HDAs older than cutoff time (ignore tool_id at this point)
+ # We really only need the id column here, but sqlalchemy barfs when
+ # trying to select only 1 column
+ hda_ids_query = sa.select(
+ (app.model.HistoryDatasetAssociation.table.c.id,
+ app.model.HistoryDatasetAssociation.table.c.deleted),
+ whereclause=and_(
+ app.model.Dataset.table.c.deleted == False,
+ app.model.HistoryDatasetAssociation.table.c.update_time
+ < cutoff_time,
+ app.model.HistoryDatasetAssociation.table.c.deleted == False),
+ from_obj=[sa.outerjoin(
+ app.model.Dataset.table,
+ app.model.HistoryDatasetAssociation.table)])
+
+ # Add all datasets associated with Histories to our list
+ hda_ids = []
+ hda_ids.extend(
+ [row.id for row in hda_ids_query.execute()])
+
+ # Now find the tool_id that generated the dataset (even if it was copied)
+ tool_matched_ids = []
+ if tool_id is not None:
+ for hda_id in hda_ids:
+ this_tool_id = _get_tool_id_for_hda(app, hda_id)
+ if this_tool_id is not None and tool_id in this_tool_id:
+ tool_matched_ids.append(hda_id)
+ hda_ids = tool_matched_ids
+
+ deleted_instance_count = 0
+ user_notifications = defaultdict(list)
+
+ # Process each of the Dataset objects
+ for hda_id in hda_ids:
+ user_query = sa.select(
+ [app.model.HistoryDatasetAssociation.table,
+ app.model.History.table,
+ app.model.User.table],
+ whereclause=and_(
+ app.model.HistoryDatasetAssociation.table.c.id == hda_id),
+ from_obj=[sa.join(app.model.User.table,
+ app.model.History.table)
+ .join(app.model.HistoryDatasetAssociation.table)],
+ use_labels=True)
+ for result in user_query.execute():
+ user_notifications[result[app.model.User.table.c.email]].append(
+ (result[app.model.HistoryDatasetAssociation.table.c.name],
+ result[app.model.History.table.c.name]))
+ deleted_instance_count += 1
+ if not info_only and not email_only:
+ # Get the HistoryDatasetAssociation objects
+ hda = app.sa_session.query(
+ app.model.HistoryDatasetAssociation).get(hda_id)
+ if not hda.deleted:
+ # Mark the HistoryDatasetAssociation as deleted
+ hda.deleted = True
+ app.sa_session.add(hda)
+ print ("Marked HistoryDatasetAssociation id %d as "
+ "deleted" % hda.id)
+ app.sa_session.flush()
+
+ emailtemplate = Template(filename=template_file)
+ for (email, dataset_list) in user_notifications.iteritems():
+ msgtext = emailtemplate.render(email=email,
+ datasets=dataset_list,
+ cutoff=cutoff_days)
+ subject = "Galaxy Server Cleanup " \
+ "- %d datasets DELETED" % len(dataset_list)
+ fromaddr = config.error_email_to
+ print ""
+ print "From: %s" % fromaddr
+ print "To: %s" % email
+ print "Subject: %s" % subject
+ print "----------"
+ print msgtext
+ if not info_only:
+ #msg = MIMEText(msgtext)
+ #msg['Subject'] = subject
+ #msg['From'] = 'noone(a)nowhere.com'
+ #msg['To'] = email
+ galaxy.util.send_mail(fromaddr, email, subject,
+ msgtext, config)
+ #s = smtplib.SMTP(smtp_server)
+ #s.sendmail(['lparsons(a)princeton.edu'], email, msg.as_string())
+ #s.quit()
+
+ stop = time.time()
+ print ""
+ print "Marked %d dataset instances as deleted" % deleted_instance_count
+ print "Total elapsed time: ", stop - start
+ print "##########################################"
+
+
+def _get_tool_id_for_hda(app, hda_id):
+ # TODO Some datasets don't seem to have an entry in jtod or a copied_from
+ if hda_id is None:
+ return None
+ job = app.sa_session.query(app.model.Job).\
+ join(app.model.JobToOutputDatasetAssociation).\
+ filter(app.model.JobToOutputDatasetAssociation.table.c.dataset_id ==
+ hda_id).first()
+ if job is not None:
+ return job.tool_id
+ else:
+ hda = app.sa_session.query(app.model.HistoryDatasetAssociation).\
+ get(hda_id)
+ return _get_tool_id_for_hda(app, hda.
+ copied_from_history_dataset_association_id)
+
+
+if __name__ == "__main__":
+ main()
diff -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_deletion_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and have been DELETED:
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+You may be able to undelete them by logging into Galaxy, navigating to the appropriate history, selecting "Include Deleted Datasets" from the history options menu, and clicking on the link to undelete each dataset that you want to keep. You can then download the datasets. Thank you for your understanding and cooporation in this necessary cleanup in order to keep the Galaxy resource available. Please don't hesitate to contact us if you have any questions.
+
+ -- Galaxy Administrators
diff -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 -r 1e30cdb6d3b82a68da8daddc86411eecc33be444 scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
--- /dev/null
+++ b/scripts/cleanup_datasets/admin_cleanup_warning_template.txt.sample
@@ -0,0 +1,11 @@
+Galaxy Server Cleanup
+---------------------
+The following datasets you own on Galaxy are older than ${cutoff} days and will be deleted soon. Be sure to download any datasets you need to keep.
+
+% for dataset, history in datasets:
+ "${dataset}" in history "${history}"
+% endfor
+
+Please contact us if you have any questions.
+
+ -- Galaxy Administrators
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: Framework enhancements for handling installation of repositories into Galaxy that have repository dependencies that are needed only for compiling a tool dependency.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/69bec229bdf8/
Changeset: 69bec229bdf8
User: greg
Date: 2013-09-10 17:59:22
Summary: Framework enhancements for handling installation of repositories into Galaxy that have repository dependencies that are needed only for compiling a tool dependency.
Affected #: 7 files
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -2280,8 +2280,20 @@
handled_key_rd_dicts=None )
if metadata:
if 'repository_dependencies' in metadata and not repository_dependencies:
- message += 'The repository dependency definitions for this repository are invalid and will be ignored.'
- status = 'error'
+ # See if we have an invalid repository dependency definition or if the repository dependency is required only for compiling the
+ # repository's tool dependency.
+ invalid = False
+ repository_dependencies_dict = metadata[ 'repository_dependencies' ]
+ rd_tups = repository_dependencies_dict.get( 'repository_dependencies', [] )
+ for rd_tup in rd_tups:
+ rdtool_shed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if not util.asbool( rd_only_if_compiling_contained_td ):
+ invalid = True
+ break
+ if invalid:
+ message += 'The repository dependency definitions for this repository are invalid and will be ignored.'
+ status = 'error'
else:
repository_metadata_id = None
metadata = None
@@ -2718,20 +2730,8 @@
name = kwd.get( 'name', None )
owner = kwd.get( 'owner', None )
changeset_revision = kwd.get( 'changeset_revision', None )
- repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
- repo_dir = repository.repo_path( trans.app )
- repo = hg.repository( suc.get_configured_ui(), repo_dir )
- # Get the upper bound changeset revision.
- upper_bound_changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
- # Build the list of changeset revision hashes defining each available update up to, but excluding, upper_bound_changeset_revision.
- changeset_hashes = []
- for changeset in suc.reversed_lower_upper_bounded_changelog( repo, changeset_revision, upper_bound_changeset_revision ):
- # Make sure to exclude upper_bound_changeset_revision.
- if changeset != upper_bound_changeset_revision:
- changeset_hashes.append( str( repo.changectx( changeset ) ) )
- if changeset_hashes:
- changeset_hashes_str = ','.join( changeset_hashes )
- return changeset_hashes_str
+ if name and owner and changeset_revision:
+ return suc.get_updated_changeset_revisions( trans, name, owner, changeset_revision )
return ''
@web.expose
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/galaxy_install/install_manager.py
--- a/lib/tool_shed/galaxy_install/install_manager.py
+++ b/lib/tool_shed/galaxy_install/install_manager.py
@@ -270,7 +270,8 @@
continue
for rd_tup in rd_tups:
prior_install_ids = []
- tool_shed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( rd_tup )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
if util.asbool( prior_installation_required ):
for tsr in tool_shed_repositories:
if tsr.name == name and tsr.owner == owner and tsr.changeset_revision == changeset_revision:
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/common_util.py
--- a/lib/tool_shed/util/common_util.py
+++ b/lib/tool_shed/util/common_util.py
@@ -46,8 +46,8 @@
if rd_key in [ 'root_key', 'description' ]:
continue
for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td \
- = parse_repository_dependency_tuple( rd_tup )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ parse_repository_dependency_tuple( rd_tup )
tool_shed_accessible, tool_dependencies = get_tool_dependencies( app,
tool_shed,
name,
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/container_util.py
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -984,7 +984,7 @@
tool_dependency_id=None,
is_orphan='Orphan' )
folder.tool_dependencies.append( tool_dependency )
- is_orphan_description = "these dependencies may not be required by tools in this repository"
+ not_used_by_local_tools_description = "these dependencies may not be required by tools in this repository"
for dependency_key, requirements_dict in tool_dependencies.items():
tool_dependency_id += 1
if dependency_key in [ 'set_environment' ]:
@@ -995,7 +995,7 @@
# TODO: handle this is Galaxy
is_orphan = False
if is_orphan:
- folder.description = is_orphan_description
+ folder.description = not_used_by_local_tools_description
name = set_environment_dict.get( 'name', None )
type = set_environment_dict[ 'type' ]
repository_id = set_environment_dict.get( 'repository_id', None )
@@ -1018,10 +1018,9 @@
if trans.webapp.name == 'tool_shed':
is_orphan = requirements_dict.get( 'is_orphan', False )
else:
- # TODO: handle this is Galaxy
is_orphan = False
if is_orphan:
- folder.description = is_orphan_description
+ folder.description = not_used_by_local_tools_description
name = requirements_dict[ 'name' ]
version = requirements_dict[ 'version' ]
type = requirements_dict[ 'type' ]
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -19,7 +19,9 @@
from tool_shed.util import tool_dependency_util
from tool_shed.util import tool_util
from tool_shed.util import xml_util
+from tool_shed.galaxy_install.tool_dependencies import install_util
from tool_shed.galaxy_install.tool_dependencies import td_common_util
+import tool_shed.repository_types.util as rt_util
import pkg_resources
@@ -904,10 +906,18 @@
repository_dependency_tups=invalid_repository_dependency_tups,
is_valid=False,
description=description )
- # Determine and store orphan tool dependencies.
- orphan_tool_dependencies = get_orphan_tool_dependencies( metadata_dict )
- if orphan_tool_dependencies:
- metadata_dict[ 'orphan_tool_dependencies' ] = orphan_tool_dependencies
+ # We need to continue to restrict the behavior of orphan tool dependencies, possibly eliminating them altoghether at some point.
+ check_for_orphan_tool_dependencies = False
+ if app.name == 'tool_shed':
+ if repository.type == rt_util.UNRESTRICTED and 'tools' not in metadata_dict:
+ check_for_orphan_tool_dependencies = True
+ elif 'tools' in metadata_dict:
+ check_for_orphan_tool_dependencies = True
+ if check_for_orphan_tool_dependencies:
+ # Determine and store orphan tool dependencies.
+ orphan_tool_dependencies = get_orphan_tool_dependencies( metadata_dict )
+ if orphan_tool_dependencies:
+ metadata_dict[ 'orphan_tool_dependencies' ] = orphan_tool_dependencies
return metadata_dict, error_message
def generate_tool_metadata( tool_config, tool, repository_clone_url, metadata_dict ):
@@ -1128,16 +1138,6 @@
sample_file_metadata_paths.append( relative_path_to_sample_file )
return sample_file_metadata_paths, sample_file_copy_paths
-def get_updated_changeset_revisions_from_tool_shed( app, tool_shed_url, name, owner, changeset_revision ):
- """
- Get all appropriate newer changeset revisions for the repository defined by the received tool_shed_url / name / owner combination.
- """
- url = suc.url_join( tool_shed_url,
- 'repository/updated_changeset_revisions?name=%s&owner=%s&changeset_revision=%s' %
- ( name, owner, changeset_revision ) )
- text = common_util.tool_shed_get( app, tool_shed_url, url )
- return text
-
def handle_existing_tool_dependencies_that_changed_in_update( app, repository, original_dependency_dict, new_dependency_dict ):
"""
This method is called when a Galaxy admin is getting updates for an installed tool shed repository in order to cover the case where an
@@ -1188,7 +1188,7 @@
return repository_dependency_tup, is_valid, error_message
else:
# Send a request to the tool shed to retrieve appropriate additional changeset revisions with which the repository may have been installed.
- text = get_updated_changeset_revisions_from_tool_shed( app, toolshed, name, owner, changeset_revision )
+ text = install_util.get_updated_changeset_revisions_from_tool_shed( app, toolshed, name, owner, changeset_revision )
if text:
updated_changeset_revisions = util.listify( text )
for updated_changeset_revision in updated_changeset_revisions:
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -1,7 +1,9 @@
import logging
import os
from galaxy import eggs
+from galaxy.util import asbool
from galaxy.util import json
+from galaxy.util import listify
import tool_shed.util.shed_util_common as suc
from tool_shed.util import common_util
from tool_shed.util import common_install_util
@@ -263,9 +265,9 @@
message = '%s ' % str( error )
return message
-def get_key_for_repository_changeset_revision( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
+def get_key_for_repository_changeset_revision( trans, toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
prior_installation_required, only_if_compiling_contained_td = \
- get_prior_installation_required_and_only_if_compiling_contained_td( toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
+ get_prior_installation_required_and_only_if_compiling_contained_td( trans, toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
# Create a key with the value of prior_installation_required defaulted to False.
key = container_util.generate_repository_dependencies_key_for_repository( toolshed_base_url=toolshed_base_url,
repository_name=repository.name,
@@ -275,21 +277,47 @@
only_if_compiling_contained_td=only_if_compiling_contained_td )
return key
-def get_prior_installation_required_and_only_if_compiling_contained_td( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
+def get_prior_installation_required_and_only_if_compiling_contained_td( trans, toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
"""
- If all_repository_dependencies contains a repository dependency tuple that is associated with the received repository, return the
- value of the tuple's prior_installation_required component.
+ This method is called from the tool shed and never Galaxy. If all_repository_dependencies contains a repository dependency tuple that is associated with
+ the received repository, return the value of the tuple's prior_installation_required component.
"""
- for rd_key, rd_tups in all_repository_dependencies.items():
- if rd_key in [ 'root_key', 'description' ]:
- continue
+ if all_repository_dependencies:
+ for rd_key, rd_tups in all_repository_dependencies.items():
+ if rd_key in [ 'root_key', 'description' ]:
+ continue
+ for rd_tup in rd_tups:
+ rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ if rd_toolshed == toolshed_base_url and \
+ rd_name == repository.name and \
+ rd_owner == repository.user.username and \
+ rd_changeset_revision == repository_metadata.changeset_revision:
+ return rd_prior_installation_required, rd_only_if_compiling_contained_td
+ elif repository_metadata:
+ # Get the list of changeset revisions from the tool shed to which the repository may be updated.
+ metadata = repository_metadata.metadata
+ current_changeset_revision = str( repository_metadata.changeset_revision )
+ # Get the changeset revision to which the current value of required_repository_changeset_revision should be updated if it's not current.
+ text = suc.get_updated_changeset_revisions( trans,
+ name=str( repository.name ),
+ owner=str( repository.user.username ),
+ changeset_revision=current_changeset_revision )
+ if text:
+ valid_changeset_revisions = listify( text )
+ if current_changeset_revision not in valid_changeset_revisions:
+ valid_changeset_revisions.append( current_changeset_revision )
+ else:
+ valid_changeset_revisions = [ current_changeset_revision ]
+ repository_dependencies_dict = metadata[ 'repository_dependencies' ]
+ rd_tups = repository_dependencies_dict.get( 'repository_dependencies', [] )
for rd_tup in rd_tups:
rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( rd_tup )
if rd_toolshed == toolshed_base_url and \
rd_name == repository.name and \
rd_owner == repository.user.username and \
- rd_changeset_revision == repository_metadata.changeset_revision:
+ rd_changeset_revision in valid_changeset_revisions:
return rd_prior_installation_required, rd_only_if_compiling_contained_td
# Default both prior_installation_required and only_if_compiling_contained_td to False.
return 'False', 'False'
@@ -333,7 +361,11 @@
metadata = repository_metadata.metadata
if metadata:
if 'repository_dependencies' in metadata:
- current_repository_key = get_key_for_repository_changeset_revision( toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
+ current_repository_key = get_key_for_repository_changeset_revision( trans,
+ toolshed_base_url,
+ repository,
+ repository_metadata,
+ all_repository_dependencies )
repository_dependencies_dict = metadata[ 'repository_dependencies' ]
if not all_repository_dependencies:
all_repository_dependencies = initialize_all_repository_dependencies( current_repository_key,
@@ -583,6 +615,22 @@
return True
return False
+def filter_only_if_compiling_contained_td( key_rd_dict ):
+ """
+ Return a copy of the received key_rd_dict with repository dependencies that are needed only_if_compiling_contained_td filtered out
+ of the list of repository dependencies for each rd_key.
+ """
+ filtered_key_rd_dict = {}
+ for rd_key, required_rd_tup in key_rd_dict.items():
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( required_rd_tup )
+ if not asbool( only_if_compiling_contained_td ):
+ if rd_key in filtered_key_rd_dict:
+ filtered_key_rd_dict[ rd_key ].append( required_rd_tup )
+ else:
+ filtered_key_rd_dict[ rd_key ] = [ required_rd_tup ]
+ return filtered_key_rd_dict
+
def merge_missing_repository_dependencies_to_installed_container( containers_dict ):
"""Merge the list of missing repository dependencies into the list of installed repository dependencies."""
missing_rd_container_root = containers_dict.get( 'missing_repository_dependencies', None )
@@ -629,32 +677,35 @@
current_repository_key_rd_dicts = remove_ropository_dependency_reference_to_self( current_repository_key_rd_dicts )
current_repository_key_rd_dicts = get_updated_changeset_revisions_for_repository_dependencies( trans, current_repository_key_rd_dicts )
for key_rd_dict in current_repository_key_rd_dicts:
- is_circular = False
- if not in_key_rd_dicts( key_rd_dict, handled_key_rd_dicts ) and not in_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
- filtered_current_repository_key_rd_dicts.append( key_rd_dict )
- repository_dependency = key_rd_dict[ current_repository_key ]
- if current_repository_key in all_repository_dependencies:
- # Add all repository dependencies for the current repository into it's entry in all_repository_dependencies.
- all_repository_dependencies_val = all_repository_dependencies[ current_repository_key ]
- if repository_dependency not in all_repository_dependencies_val:
- all_repository_dependencies_val.append( repository_dependency )
- all_repository_dependencies[ current_repository_key ] = all_repository_dependencies_val
- elif not in_all_repository_dependencies( current_repository_key, repository_dependency, all_repository_dependencies ):
- # Handle circular repository dependencies.
- if is_circular_repository_dependency( current_repository_key, repository_dependency, all_repository_dependencies ):
- is_circular = True
- circular_repository_dependencies, handled_key_rd_dicts, all_repository_dependencies = \
- handle_circular_repository_dependency( current_repository_key,
- repository_dependency,
- circular_repository_dependencies,
- handled_key_rd_dicts,
- all_repository_dependencies )
- else:
- all_repository_dependencies[ current_repository_key ] = [ repository_dependency ]
- if not is_circular and can_add_to_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
- new_key_rd_dict = {}
- new_key_rd_dict[ current_repository_key ] = repository_dependency
- key_rd_dicts_to_be_processed.append( new_key_rd_dict )
+ # Filter out repository dependencies that are required only if compiling the dependent repository's tool dependency.
+ all_repository_dependencieskey_rd_dict = filter_only_if_compiling_contained_td( key_rd_dict )
+ if key_rd_dict:
+ is_circular = False
+ if not in_key_rd_dicts( key_rd_dict, handled_key_rd_dicts ) and not in_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
+ filtered_current_repository_key_rd_dicts.append( key_rd_dict )
+ repository_dependency = key_rd_dict[ current_repository_key ]
+ if current_repository_key in all_repository_dependencies:
+ # Add all repository dependencies for the current repository into it's entry in all_repository_dependencies.
+ all_repository_dependencies_val = all_repository_dependencies[ current_repository_key ]
+ if repository_dependency not in all_repository_dependencies_val:
+ all_repository_dependencies_val.append( repository_dependency )
+ all_repository_dependencies[ current_repository_key ] = all_repository_dependencies_val
+ elif not in_all_repository_dependencies( current_repository_key, repository_dependency, all_repository_dependencies ):
+ # Handle circular repository dependencies.
+ if is_circular_repository_dependency( current_repository_key, repository_dependency, all_repository_dependencies ):
+ is_circular = True
+ circular_repository_dependencies, handled_key_rd_dicts, all_repository_dependencies = \
+ handle_circular_repository_dependency( current_repository_key,
+ repository_dependency,
+ circular_repository_dependencies,
+ handled_key_rd_dicts,
+ all_repository_dependencies )
+ else:
+ all_repository_dependencies[ current_repository_key ] = [ repository_dependency ]
+ if not is_circular and can_add_to_key_rd_dicts( key_rd_dict, key_rd_dicts_to_be_processed ):
+ new_key_rd_dict = {}
+ new_key_rd_dict[ current_repository_key ] = repository_dependency
+ key_rd_dicts_to_be_processed.append( new_key_rd_dict )
return filtered_current_repository_key_rd_dicts, key_rd_dicts_to_be_processed, handled_key_rd_dicts, all_repository_dependencies
def prune_invalid_repository_dependencies( repository_dependencies ):
diff -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 -r 69bec229bdf85900f7d581e735aa69ee2cc2aeb9 lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -1190,6 +1190,27 @@
return {}
return tool_shed_status_dict
+def get_updated_changeset_revisions( trans, name, owner, changeset_revision ):
+ """
+ Return a string of comma-separated changeset revision hashes for all available updates to the received changeset revision for the repository
+ defined by the received name and owner.
+ """
+ repository = get_repository_by_name_and_owner( trans.app, name, owner )
+ repo_dir = repository.repo_path( trans.app )
+ repo = hg.repository( get_configured_ui(), repo_dir )
+ # Get the upper bound changeset revision.
+ upper_bound_changeset_revision = get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
+ # Build the list of changeset revision hashes defining each available update up to, but excluding, upper_bound_changeset_revision.
+ changeset_hashes = []
+ for changeset in reversed_lower_upper_bounded_changelog( repo, changeset_revision, upper_bound_changeset_revision ):
+ # Make sure to exclude upper_bound_changeset_revision.
+ if changeset != upper_bound_changeset_revision:
+ changeset_hashes.append( str( repo.changectx( changeset ) ) )
+ if changeset_hashes:
+ changeset_hashes_str = ','.join( changeset_hashes )
+ return changeset_hashes_str
+ return ''
+
def get_url_from_tool_shed( app, tool_shed ):
"""
The value of tool_shed is something like: toolshed.g2.bx.psu.edu. We need the URL to this tool shed, which is something like:
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: Dave Bouvier: Make the "keep tool dependencies" feature for the install and test framework optional.
by commits-noreply@bitbucket.org 10 Sep '13
by commits-noreply@bitbucket.org 10 Sep '13
10 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/82833b9b6f4f/
Changeset: 82833b9b6f4f
User: Dave Bouvier
Date: 2013-09-09 20:48:35
Summary: Make the "keep tool dependencies" feature for the install and test framework optional.
Affected #: 3 files
diff -r ed3c786622741814a07589a1e642cca75c51c822 -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 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
@@ -136,11 +136,17 @@
break
time.sleep( 1 )
- def uninstall_repository( self, installed_repository ):
+ def uninstall_repository( self, installed_repository, deactivate_only=False ):
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", 'false' )
+ if deactivate_only:
+ tc.fv ( 1, "remove_from_disk", 'false' )
+ else:
+ tc.fv ( 1, "remove_from_disk", 'true' )
tc.submit( 'deactivate_or_uninstall_repository_button' )
strings_displayed = [ 'The repository named' ]
- strings_displayed.append( 'has been deactivated' )
- self.check_for_strings( strings_displayed, strings_not_displayed=[] )
+ if deactivate_only:
+ strings_displayed.append( 'has been deactivated' )
+ else:
+ strings_displayed.append( 'has been uninstalled' )
+ self.check_for_strings( strings_displayed, strings_not_displayed=[] )
\ No newline at end of file
diff -r ed3c786622741814a07589a1e642cca75c51c822 -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 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
@@ -16,7 +16,7 @@
# Install the repository through the web interface using twill.
self.install_repository( repository_info_dict )
- def do_uninstallation( self, repository_info_dict ):
+ def do_uninstallation( self, repository_info_dict, deactivate_only=False ):
self.logout()
self.login( email='test(a)bx.psu.edu', username='test' )
admin_user = test_db_util.get_user( 'test(a)bx.psu.edu' )
@@ -27,7 +27,7 @@
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 )
+ self.uninstall_repository( repository, deactivate_only )
def generate_install_method( repository_dict=None ):
"""Generate abstract test cases for the defined list of repositories."""
@@ -55,7 +55,7 @@
new_class_obj = new.classobj( name, baseclasses, namespace )
G[ name ] = new_class_obj
-def generate_uninstall_method( repository_dict=None ):
+def generate_uninstall_method( repository_dict=None, deactivate_only=False ):
"""Generate abstract test cases for the defined list of repositories."""
if repository_dict is None:
return
@@ -63,20 +63,20 @@
G = globals()
# Eliminate all previous tests from G.
for key, val in G.items():
- if key.startswith( 'TestInstallRepository_' ) or key.startswith( 'TestUninstallRepository_' ) or key.startswith( 'TestForTool_' ):
+ if key.startswith( 'TestInstallRepository_' ) or key.startswith( 'TestForTool_' ):
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' ]
+ name = "TestUninstallRepository_%s_%s" % ( repository_dict[ 'name' ], repository_dict[ 'changeset_revision' ] )
baseclasses = ( InstallTestRepositories, )
namespace = dict()
def make_uninstall_method( repository_dict ):
def test_install_repository( self ):
- self.do_uninstallation( repository_dict )
+ self.do_uninstallation( repository_dict, deactivate_only )
return test_install_repository
test_method = make_uninstall_method( repository_dict )
test_method.__doc__ = "Uninstall the repository %s." % repository_dict[ 'name' ]
- namespace[ 'uninstall_repository_%s' % repository_dict[ 'name' ] ] = test_method
+ namespace[ 'uninstall_repository_%s_%s' % ( repository_dict[ 'name' ], repository_dict[ 'changeset_revision' ] ) ] = 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
+ G[ name ] = new_class_obj
\ No newline at end of file
diff -r ed3c786622741814a07589a1e642cca75c51c822 -r 82833b9b6f4fbdf1408864bbf7781a02200ca633 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,6 +1,6 @@
#!/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
+# 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.
@@ -157,7 +157,7 @@
<tables></tables>
'''
-
+
# The tool shed url and api key must be set for this script to work correctly. Additionally, if the tool shed url does not
# point to one of the defaults, the GALAXY_INSTALL_TEST_TOOL_SHEDS_CONF needs to point to a tool sheds configuration file
# that contains a definition for that tool shed.
@@ -169,7 +169,7 @@
if tool_shed_api_key is None:
print "This script requires the GALAXY_INSTALL_TEST_TOOL_SHED_API_KEY environment variable to be set and non-empty."
exit( 1 )
-
+
if galaxy_tool_shed_url is None:
print "This script requires the GALAXY_INSTALL_TEST_TOOL_SHED_URL environment variable to be set and non-empty."
exit( 1 )
@@ -188,12 +188,12 @@
testing_single_repository[ 'changeset_revision' ] = os.environ[ 'repository_revision' ]
else:
testing_single_repository[ 'changeset_revision' ] = None
-
+
class ReportResults( Plugin ):
'''Simple Nose plugin to record the IDs of all tests run, regardless of success.'''
name = "reportresults"
passed = dict()
-
+
def options( self, parser, env=os.environ ):
super( ReportResults, self ).options( parser, env=env )
@@ -224,7 +224,7 @@
return passed_tests
return []
-def execute_uninstall_method( app ):
+def execute_uninstall_method( app, deactivate_only=False ):
# Clean out any generated tests.
remove_generated_tests( app )
sa_session = app.model.context.current
@@ -244,11 +244,11 @@
log.debug( 'Changeset revision %s of repository %s queued for uninstallation.', changeset_revision, name )
repository_dict = dict( name=name, owner=owner, changeset_revision=changeset_revision )
# Generate a test method to uninstall this repository through the embedded Galaxy application's web interface.
- test_install_repositories.generate_uninstall_method( repository_dict )
+ test_install_repositories.generate_uninstall_method( repository_dict, deactivate_only )
# 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
+ # 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()
@@ -258,7 +258,7 @@
if 'api' in parts and parts.index( 'api' ) != 0:
parts.pop( parts.index( 'api' ) )
parts.insert( 0, 'api' )
- elif 'api' not in parts:
+ elif 'api' not in parts:
parts.insert( 0, 'api' )
url = url_join( base, *parts )
if key:
@@ -318,8 +318,8 @@
NOTE: If the tool shed URL specified in any dict is not present in the tool_sheds_conf.xml, the installation will fail.
'''
assert tool_shed_api_key is not None, 'Cannot proceed without tool shed API key.'
- params = urllib.urlencode( dict( do_not_test='false',
- downloadable='true',
+ params = urllib.urlencode( dict( do_not_test='false',
+ downloadable='true',
malicious='false',
includes_tools='true',
skip_tool_test='false' ) )
@@ -334,7 +334,7 @@
repository_info_dict = get_repository_info_from_api( galaxy_tool_shed_url, repository_to_install_dict )
if repository_info_dict[ 'latest_revision' ] == '000000000000':
continue
- owner = repository_info_dict[ 'owner' ]
+ owner = repository_info_dict[ 'owner' ]
name = repository_info_dict[ 'name' ]
changeset_revision = repository_to_install_dict[ 'changeset_revision' ]
repository_id = repository_to_install_dict[ 'repository_id' ]
@@ -343,9 +343,9 @@
# and therefore do not need to be checked. If they are undeleted, this script will then test them the next time it runs.
if repository_info_dict[ 'deleted' ]:
log.info( "Skipping revision %s of repository id %s (%s/%s) since the repository is deleted...",
- changeset_revision,
- repository_id,
- name,
+ changeset_revision,
+ repository_id,
+ name,
owner )
continue
# Now merge the dict returned from /api/repository_revisions with the detailed dict we just retrieved.
@@ -360,8 +360,8 @@
else:
skipped_previous = ''
if testing_single_repository:
- log.info( 'Testing single repository with name %s and owner %s.',
- testing_single_repository[ 'name' ],
+ log.info( 'Testing single repository with name %s and owner %s.',
+ testing_single_repository[ 'name' ],
testing_single_repository[ 'owner' ])
for repository_to_install in detailed_repository_list:
if repository_to_install[ 'name' ] == testing_single_repository[ 'name' ] \
@@ -415,7 +415,7 @@
[
{
'reason': The default reason or the reason specified in this section,
- 'repositories':
+ 'repositories':
[
( name, owner, changeset revision if changeset revision else None ),
( name, owner, changeset revision if changeset revision else None )
@@ -423,7 +423,7 @@
},
{
'reason': The default reason or the reason specified in this section,
- 'repositories':
+ 'repositories':
[
( name, owner, changeset revision if changeset revision else None ),
( name, owner, changeset revision if changeset revision else None )
@@ -473,8 +473,8 @@
return update( tool_shed_api_key, '%s' % ( url_join( galaxy_tool_shed_url, 'api', 'repository_revisions', metadata_id ) ), params, return_formatted=False )
def remove_generated_tests( app ):
- # Delete any configured tool functional tests from the test_toolbox.__dict__, otherwise nose will find them
- # and try to re-run the tests after uninstalling the repository, which will cause false failure reports,
+ # Delete any configured tool functional tests from the test_toolbox.__dict__, otherwise nose will find them
+ # and try to re-run the tests after uninstalling the repository, which will cause false failure reports,
# since the test data has been deleted from disk by now.
tests_to_delete = []
tools_to_delete = []
@@ -525,7 +525,7 @@
# ---- 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', 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:
os.environ[ 'HTTP_ACCEPT_LANGUAGE' ] = default_galaxy_locales
@@ -536,6 +536,11 @@
if not os.path.isdir( galaxy_test_tmp_dir ):
os.mkdir( galaxy_test_tmp_dir )
galaxy_test_proxy_port = None
+ # Allow the option to keep or delete tool dependencies when a repository has been tested.
+ if 'GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES' in os.environ:
+ deactivate_only = True
+ else:
+ deactivate_only = False
# 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', tool_data_table_conf )
@@ -553,19 +558,19 @@
# Configure the database connection and path.
if 'GALAXY_INSTALL_TEST_DBPATH' in os.environ:
galaxy_db_path = os.environ[ 'GALAXY_INSTALL_TEST_DBPATH' ]
- else:
+ 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 )
- galaxy_shed_tool_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir, prefix='shed_tools' )
+ galaxy_shed_tool_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir, prefix='shed_tools' )
galaxy_migrated_tool_path = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
# Set up the tool dependency path for the Galaxy instance.
tool_dependency_dir = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR', None )
if tool_dependency_dir is None:
- tool_dependency_dir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
+ tool_dependency_dir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
os.environ[ 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR' ] = tool_dependency_dir
os.environ[ 'GALAXY_TOOL_DEPENDENCY_DIR' ] = tool_dependency_dir
if 'GALAXY_INSTALL_TEST_DBURI' in os.environ:
@@ -639,13 +644,13 @@
# Set the global_conf[ '__file__' ] option to the location of the temporary .ini file, which gets passed to set_metadata.sh.
kwargs[ 'global_conf' ] = get_webapp_global_conf()
kwargs[ 'global_conf' ][ '__file__' ] = galaxy_config_file
- # ---- Build Galaxy Application --------------------------------------------------
+ # ---- Build Galaxy Application --------------------------------------------------
if not database_connection.startswith( 'sqlite://' ):
kwargs[ 'database_engine_option_max_overflow' ] = '20'
kwargs[ 'database_engine_option_pool_size' ] = '10'
kwargs[ 'config_file' ] = galaxy_config_file
app = UniverseApplication( **kwargs )
-
+
log.info( "Embedded Galaxy application started" )
# ---- Run galaxy webserver ------------------------------------------------------
@@ -703,7 +708,7 @@
if additional_tool_data_tables:
app.tool_data_tables.add_new_entries_from_config_file( config_filename=additional_tool_data_tables,
tool_data_path=additional_tool_data_path,
- shed_tool_data_table_config=None,
+ shed_tool_data_table_config=None,
persist=False )
# Initialize some variables for the summary that will be printed to stdout.
repositories_passed = []
@@ -784,14 +789,14 @@
# Iterate through the list of repositories defined not to be installed. This should be a list of dicts in the following format:
# {
# 'reason': The default reason or the reason specified in this section,
- # 'repositories':
+ # 'repositories':
# [
# ( name, owner, changeset revision if changeset revision else None ),
# ( name, owner, changeset revision if changeset revision else None )
# ]
# },
# If changeset revision is None, that means the entire repository is excluded from testing, otherwise only the specified
- # revision should be skipped.
+ # revision should be skipped.
# TODO: When a repository is selected to be skipped, use the API to update the tool shed with the defined skip reason.
skip_this_repository = False
skip_because = None
@@ -831,11 +836,11 @@
log.exception( 'Error getting installed repository.' )
success = False
pass
- # If the installation succeeds, configure and run functional tests for this repository. This is equivalent to
+ # If the installation succeeds, configure 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 all defined functional tests.', name )
- # Generate the shed_tools_dict that specifies the location of test data contained within this repository. If the repository
+ # Generate the shed_tools_dict that specifies the location of test data contained within this repository. If the repository
# does not have a test-data directory, this will return has_test_data = False, and we will set the do_not_test flag to True,
# and the tools_functionally_correct flag to False, as well as updating tool_test_results.
file( galaxy_shed_tools_dict, 'w' ).write( to_json_string( dict() ) )
@@ -876,8 +881,8 @@
# 'tool_dependencies':
# [
# {
- # 'type': 'Type of tool dependency, e.g. package, set_environment, etc.',
- # 'name': 'Name of the tool dependency.',
+ # 'type': 'Type of tool dependency, e.g. package, set_environment, etc.',
+ # 'name': 'Name of the tool dependency.',
# 'version': 'Version if this is a package, otherwise blank.',
# 'error_message': 'The error message returned when installation was attempted.',
# },
@@ -885,8 +890,8 @@
# 'repository_dependencies':
# [
# {
- # 'tool_shed': 'The tool shed that this repository was installed from.',
- # 'name': 'The name of the repository that failed to install.',
+ # 'tool_shed': 'The tool shed that this repository was installed from.',
+ # 'name': 'The name of the repository that failed to install.',
# 'owner': 'Owner of the failed repository.',
# 'changeset_revision': 'Changeset revision of the failed repository.',
# 'error_message': 'The error message that was returned when the repository failed to install.',
@@ -895,8 +900,8 @@
# 'current_repository':
# [
# {
- # 'tool_shed': 'The tool shed that this repository was installed from.',
- # 'name': 'The name of the repository that failed to install.',
+ # 'tool_shed': 'The tool shed that this repository was installed from.',
+ # 'name': 'The name of the repository that failed to install.',
# 'owner': 'Owner of the failed repository.',
# 'changeset_revision': 'Changeset revision of the failed repository.',
# 'error_message': 'The error message that was returned when the repository failed to install.',
@@ -919,7 +924,7 @@
# },
# ]
# "not_tested":
- # {
+ # {
# "reason": "The Galaxy development team has determined that this repository should not be installed and tested by the automated framework."
# }
# }
@@ -949,14 +954,14 @@
params[ 'tools_functionally_correct' ] = False
params[ 'missing_test_components' ] = True
params[ 'do_not_test' ] = str( set_do_not_test )
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
# Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
# repository using Twill.
- execute_uninstall_method( app )
+ execute_uninstall_method( app, deactivate_only )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
test_toolbox.toolbox = app.toolbox
repositories_failed.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
@@ -968,15 +973,15 @@
log.error( 'Updating repository and skipping functional tests.' )
# In keeping with the standard display layout, add the error message to the dict for each tool individually.
for dependency in failed_tool_dependencies:
- test_result = dict( type=dependency.type,
- name=dependency.name,
+ test_result = dict( type=dependency.type,
+ name=dependency.name,
version=dependency.version,
error_message=dependency.error_message )
repository_status[ 'installation_errors' ][ 'tool_dependencies' ].append( test_result )
for dependency in repository.repository_dependencies_with_installation_errors:
- test_result = dict( tool_shed=dependency.tool_shed,
- name=dependency.name,
- owner=dependency.owner,
+ test_result = dict( tool_shed=dependency.tool_shed,
+ name=dependency.name,
+ owner=dependency.owner,
changeset_revision=dependency.changeset_revision,
error_message=dependency.error_message )
repository_status[ 'installation_errors' ][ 'repository_dependencies' ].append( test_result )
@@ -984,14 +989,19 @@
params[ 'tools_functionally_correct' ] = False
params[ 'do_not_test' ] = False
params[ 'test_install_error' ] = True
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
# Run the cleanup method. This removes tool functional test methods from the test_toolbox module and uninstalls the
- # repository using Twill.
- execute_uninstall_method( app )
+ # repository using Twill. If tool dependencies failed installation, select to uninstall instead of deavctivate,
+ # to make way for the next attempt. Otherwise, default to the value determined by the environment variable
+ # GALAXY_INSTALL_TEST_KEEP_TOOL_DEPENDENCIES.
+ if failed_tool_dependencies:
+ execute_uninstall_method( app, deactivate_only=False )
+ else:
+ execute_uninstall_method( app, deactivate_only=deactivate_only )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
test_toolbox.toolbox = app.toolbox
repositories_failed_install.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
@@ -1007,7 +1017,7 @@
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
+ # 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.
@@ -1037,10 +1047,10 @@
params[ 'tools_functionally_correct' ] = True
params[ 'do_not_test' ] = False
params[ 'test_install_error' ] = False
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
log.debug( 'Revision %s of repository %s installed and passed functional tests.', changeset_revision, name )
else:
@@ -1081,7 +1091,7 @@
if output_type in tmp_output:
test_status[ output_type ] = '\n'.join( tmp_output[ output_type ] )
repository_status[ 'failed_tests' ].append( test_status )
- # Call the register_test_result method, which executes a PUT request to the repository_revisions API controller with the outcome
+ # Call the register_test_result method, which executes a PUT request to the repository_revisions API controller with the outcome
# of the tests, and updates tool_test_results with the relevant log data.
# This also sets the do_not_test and tools_functionally correct flags to the appropriate values, and updates the time_last_tested
# field to today's date.
@@ -1090,19 +1100,19 @@
params[ 'tools_functionally_correct' ] = False
params[ 'test_install_error' ] = False
params[ 'do_not_test' ] = str( set_do_not_test )
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
log.debug( 'Revision %s of repository %s installed successfully, but did not pass functional tests.',
- changeset_revision, name )
+ changeset_revision, name )
# Run the uninstall method. This removes tool functional test methods from the test_toolbox module and uninstalls the
# repository using Twill.
log.debug( 'Uninstalling changeset revision %s of repository %s',
- repository_info_dict[ 'changeset_revision' ],
+ repository_info_dict[ 'changeset_revision' ],
repository_info_dict[ 'name' ] )
- success = execute_uninstall_method( app )
+ success = execute_uninstall_method( app, deactivate_only )
if not success:
log.error( 'Repository %s failed to uninstall.', repository_info_dict[ 'name' ] )
# Set the test_toolbox.toolbox module-level variable to the new app.toolbox.
@@ -1115,28 +1125,28 @@
except:
log.exception( 'Unable to uninstall, no installed repository found.' )
continue
- test_result = dict( tool_shed=repository.tool_shed,
- name=repository.name,
- owner=repository.owner,
+ test_result = dict( tool_shed=repository.tool_shed,
+ name=repository.name,
+ owner=repository.owner,
changeset_revision=repository.changeset_revision,
error_message=repository.error_message )
repository_status[ 'installation_errors' ][ 'repository_dependencies' ].append( test_result )
params[ 'tools_functionally_correct' ] = False
params[ 'test_install_error' ] = True
params[ 'do_not_test' ] = False
- register_test_result( galaxy_tool_shed_url,
- metadata_revision_id,
- repository_status,
- repository_info_dict,
+ register_test_result( galaxy_tool_shed_url,
+ metadata_revision_id,
+ repository_status,
+ repository_info_dict,
params )
- success = execute_uninstall_method( app )
+ success = execute_uninstall_method( app, deactivate_only )
if not success:
log.error( 'Repository %s failed to uninstall.', repository_info_dict[ 'name' ] )
repositories_failed_install.append( dict( name=name, owner=owner, changeset_revision=changeset_revision ) )
log.debug( 'Repository %s failed to install correctly.', repository_info_dict[ 'name' ] )
except:
log.exception( "Failure running tests" )
-
+
log.info( "Shutting down" )
# ---- Tear down -----------------------------------------------------------
# Gracefully shut down the embedded web server and UniverseApplication.
@@ -1191,7 +1201,7 @@
# Normally, the value of 'success' would determine whether this test suite is marked as passed or failed
# in the automated buildbot framework. However, due to the procedure used here, we only want to report
# failure if a repository fails to install correctly. Therefore, we have overriden the value of 'success'
- # here based on what actions the script has executed.
+ # here based on what actions the script has executed.
if success:
return 0
else:
@@ -1202,4 +1212,4 @@
print "####################################################################################"
print "# %s - running repository installation and testing script." % now
print "####################################################################################"
- sys.exit( main() )
+ sys.exit( main() )
\ No newline at end of file
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: Enable repository dependencies to be specially categorized if they should be installed only to allow the dependent repository's tool dependency to be compiled (in most cases the tool dependency should hopefully be installed as a compiled binary).
by commits-noreply@bitbucket.org 09 Sep '13
by commits-noreply@bitbucket.org 09 Sep '13
09 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ed3c78662274/
Changeset: ed3c78662274
User: greg
Date: 2013-09-09 20:26:58
Summary: Enable repository dependencies to be specially categorized if they should be installed only to allow the dependent repository's tool dependency to be compiled (in most cases the tool dependency should hopefully be installed as a compiled binary).
Affected #: 11 files
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/galaxy/model/__init__.py
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -3571,6 +3571,10 @@
@property
def repository_dependencies( self ):
+ """
+ Return all of this repository's repository dependencies, ignoring their attributes like prior_installation_required and
+ only_if_compiling_contained_td.
+ """
required_repositories = []
for rrda in self.required_repositories:
repository_dependency = rrda.repository_dependency
@@ -3608,7 +3612,7 @@
if required_repository.status == self.installation_status.ERROR:
required_repositories_with_installation_errors.append( required_repository )
return required_repositories_with_installation_errors
-
+
@property
def requires_prior_installation_of( self ):
"""
@@ -3624,15 +3628,18 @@
if self.has_repository_dependencies:
rd_tups = self.metadata[ 'repository_dependencies' ][ 'repository_dependencies' ]
for rd_tup in rd_tups:
- if len( rd_tup ) == 4:
- # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required to False.
- tool_shed, name, owner, changeset_revision = rd_tup
- prior_installation_required = False
- elif len( rd_tup ) == 5:
+ if len( rd_tup ) == 5:
tool_shed, name, owner, changeset_revision, prior_installation_required = rd_tup
- prior_installation_required = galaxy.util.asbool( str( prior_installation_required ) )
- if prior_installation_required:
- required_rd_tups_that_must_be_installed.append( ( tool_shed, name, owner, changeset_revision, prior_installation_required ) )
+ if galaxy.util.asbool( prior_installation_required ):
+ required_rd_tups_that_must_be_installed.append( ( tool_shed, name, owner, changeset_revision, 'True', 'False' ) )
+ elif len( rd_tup ) == 6:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup
+ # The repository dependency will only be required to be previsously installed if it does not fall into the category of
+ # a repository that must be installed only so that it's contained tool dependency can be used for compiling the tool
+ # dependency of the dependent repository.
+ if not galaxy.util.asbool( only_if_compiling_contained_td ):
+ if galaxy.util.asbool( prior_installation_required ):
+ required_rd_tups_that_must_be_installed.append( ( tool_shed, name, owner, changeset_revision, 'True', 'False' ) )
return required_rd_tups_that_must_be_installed
@property
@@ -3686,6 +3693,19 @@
return tool_shed_url.rstrip( '/' )
@property
+ def tuples_of_repository_dependencies_needed_for_compiling_td( self ):
+ """Return this repository's repository dependencies that are necessary only for compiling this repository's tool dependencies."""
+ rd_tups_of_repositories_needed_for_compiling_td = []
+ if self.has_repository_dependencies:
+ rd_tups = self.metadata[ 'repository_dependencies' ][ 'repository_dependencies' ]
+ for rd_tup in rd_tups:
+ if len( rd_tup ) == 6:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup
+ if galaxy.util.asbool( only_if_compiling_contained_td ):
+ rd_tups_of_repositories_needed_for_compiling_td.append( ( tool_shed, name, owner, changeset_revision, 'False', 'True' ) )
+ return rd_tups_of_repositories_needed_for_compiling_td
+
+ @property
def uninstalled_repository_dependencies( self ):
"""Return the repository's repository dependencies that have been uninstalled."""
uninstalled_required_repositories = []
@@ -3723,6 +3743,7 @@
def __init__( self, tool_shed_repository_id=None ):
self.tool_shed_repository_id = tool_shed_repository_id
+
class ToolDependency( object ):
installation_status = Bunch( NEVER_INSTALLED='Never installed',
INSTALLING='Installing',
@@ -3734,6 +3755,7 @@
WARNING = 'queued',
ERROR = 'error',
UNINSTALLED = 'deleted_new' )
+
def __init__( self, tool_shed_repository_id=None, name=None, version=None, type=None, status=None, error_message=None ):
self.tool_shed_repository_id = tool_shed_repository_id
self.name = name
@@ -3741,21 +3763,26 @@
self.type = type
self.status = status
self.error_message = error_message
+
@property
def can_install( self ):
return self.status in [ self.installation_status.NEVER_INSTALLED, self.installation_status.UNINSTALLED ]
+
@property
def can_uninstall( self ):
return self.status in [ self.installation_status.ERROR, self.installation_status.INSTALLED ]
+
@property
def can_update( self ):
return self.status in [ self.installation_status.NEVER_INSTALLED,
self.installation_status.INSTALLED,
self.installation_status.ERROR,
self.installation_status.UNINSTALLED ]
+
@property
def in_error_state( self ):
return self.status == self.installation_status.ERROR
+
def installation_directory( self, app ):
if self.type == 'package':
return os.path.join( app.config.tool_dependency_dir,
@@ -3772,6 +3799,7 @@
self.tool_shed_repository.name,
self.tool_shed_repository.installed_changeset_revision )
+
class ToolVersion( object, Dictifiable ):
dict_element_visible_keys = ( 'id', 'tool_shed_repository' )
def __init__( self, id=None, create_time=None, tool_id=None, tool_shed_repository=None ):
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -1648,7 +1648,7 @@
encoded_repository_ids = []
changeset_revisions = []
for required_repository_tup in decoded_required_repository_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required = \
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( required_repository_tup )
repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
encoded_repository_ids.append( trans.security.encode_id( repository.id ) )
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/galaxy_install/repository_util.py
--- a/lib/tool_shed/galaxy_install/repository_util.py
+++ b/lib/tool_shed/galaxy_install/repository_util.py
@@ -101,7 +101,8 @@
# rd_key is something like: 'http://localhost:9009__ESEP__package_rdkit_2012_12__ESEP__test__ESEP__d635f…'
# rd_val is something like: [['http://localhost:9009', 'package_numpy_1_7', 'test', 'cddd64ecd985', 'True']]
try:
- tool_shed, name, owner, changeset_revision, prior_installation_required = container_util.get_components_from_key( rd_key )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ container_util.get_components_from_key( rd_key )
except:
tool_shed, name, owner, changeset_revision = container_util.get_components_from_key( rd_val )
installed_repository = suc.get_tool_shed_repository_by_shed_name_owner_changeset_revision( trans.app, tool_shed, name, owner, changeset_revision )
@@ -109,7 +110,7 @@
installed_repositories.append( installed_repository )
for rd_val in rd_vals:
try:
- tool_shed, name, owner, changeset_revision, prior_installation_required = rd_val
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_val
except:
tool_shed, name, owner, changeset_revision = rd_val
installed_repository = suc.get_tool_shed_repository_by_shed_name_owner_changeset_revision( trans.app, tool_shed, name, owner, changeset_revision )
@@ -627,7 +628,7 @@
folder_id += 1
# Generate the label by retrieving the repository name.
try:
- toolshed, name, owner, changeset_revision, prior_installation_required = \
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
container_util.get_components_from_key( old_container_repository_dependencies_folder.key )
except ValueError:
# For backward compatibility to the 12/20/12 Galaxy release.
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -165,11 +165,20 @@
missing_rd_tups = []
for tsr in repository.repository_dependencies:
prior_installation_required = suc.set_prior_installation_required( repository, tsr )
- rd_tup = [ tsr.tool_shed, tsr.name, tsr.owner, tsr.changeset_revision, prior_installation_required, tsr.id, tsr.status ]
+ only_if_compiling_contained_td = suc.set_only_if_compiling_contained_td( repository, tsr )
+ rd_tup = [ tsr.tool_shed, tsr.name, tsr.owner, tsr.changeset_revision, prior_installation_required, only_if_compiling_contained_td, tsr.id, tsr.status ]
if tsr.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
installed_rd_tups.append( rd_tup )
else:
- missing_rd_tups.append( rd_tup )
+ # We'll only add the rd_tup to the missing_rd_tups list if the received repository has tool dependencies that are not
+ # correctly installed. This may prove to be a weak check since the repository in question may not have anything to do
+ # with compiling the missing tool dependencies. If we discover that this is a problem, more granular checking will be
+ # necessary here.
+ if repository.missing_tool_dependencies:
+ if not repository_dependency_needed_only_for_compiling_tool_dependency( repository, tsr ):
+ missing_rd_tups.append( rd_tup )
+ else:
+ missing_rd_tups.append( rd_tup )
if installed_rd_tups or missing_rd_tups:
# Get the description from the metadata in case it has a value.
repository_dependencies = metadata.get( 'repository_dependencies', {} )
@@ -180,7 +189,8 @@
repository.name,
repository.owner,
repository.installed_changeset_revision,
- prior_installation_required )
+ prior_installation_required,
+ only_if_compiling_contained_td )
if installed_rd_tups:
installed_repository_dependencies[ 'root_key' ] = root_key
installed_repository_dependencies[ root_key ] = installed_rd_tups
@@ -211,7 +221,8 @@
if key in [ 'description', 'root_key' ]:
continue
for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( rd_tup )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
# Updates to installed repository revisions may have occurred, so make sure to locate the appropriate repository revision if one exists.
# 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 )
@@ -219,17 +230,39 @@
tmp_repo_info_tuple = ( None, tmp_clone_url, changeset_revision, None, owner, None, None )
repository, current_changeset_revision = suc.repository_was_previously_installed( trans, tool_shed, name, tmp_repo_info_tuple )
if repository:
- new_rd_tup = [ tool_shed, name, owner, changeset_revision, str( prior_installation_required ), repository.id, repository.status ]
+ new_rd_tup = [ tool_shed,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ repository.id,
+ repository.status ]
if repository.status == trans.model.ToolShedRepository.installation_status.INSTALLED:
if new_rd_tup not in installed_rd_tups:
installed_rd_tups.append( new_rd_tup )
else:
+ # A repository dependency that is not installed will not be considered missing if it's value for only_if_compiling_contained_td is
+ # True This is because this type of repository dependency will only be considered at the time that the specified tool dependency
+ # is being installed, and even then only if the compiled binary of the tool dependency could not be installed due to the unsupported
+ # installation environment.
+ if not util.asbool( only_if_compiling_contained_td ):
+ if new_rd_tup not in missing_rd_tups:
+ missing_rd_tups.append( new_rd_tup )
+ else:
+ new_rd_tup = [ tool_shed,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ None,
+ 'Never installed' ]
+ if not util.asbool( only_if_compiling_contained_td ):
+ # A repository dependency that is not installed will not be considered missing if it's value for only_if_compiling_contained_td is
+ # True - see above...
if new_rd_tup not in missing_rd_tups:
missing_rd_tups.append( new_rd_tup )
- else:
- new_rd_tup = [ tool_shed, name, owner, changeset_revision, str( prior_installation_required ), None, 'Never installed' ]
- if new_rd_tup not in missing_rd_tups:
- missing_rd_tups.append( new_rd_tup )
if installed_rd_tups:
installed_repository_dependencies[ 'root_key' ] = root_key
installed_repository_dependencies[ root_key ] = installed_rd_tups
@@ -286,20 +319,32 @@
if key in [ 'root_key', 'description' ]:
continue
try:
- toolshed, name, owner, changeset_revision, prior_installation_required = container_util.get_components_from_key( key )
- components_list = [ toolshed, name, owner, changeset_revision, prior_installation_required ]
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ container_util.get_components_from_key( key )
+ components_list = [ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td ]
except ValueError:
- # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required to False in the caller.
+ # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required and only_if_compiling_contained_td
+ # to False in the caller.
toolshed, name, owner, changeset_revision = container_util.get_components_from_key( key )
components_list = [ toolshed, name, owner, changeset_revision ]
- if components_list not in required_repository_tups:
- required_repository_tups.append( components_list )
- for components_list in val:
+ only_if_compiling_contained_td = 'False'
+ # Skip listing a repository dependency if it is required only to compile a tool dependency defined for the dependent repository.
+ if not util.asbool( only_if_compiling_contained_td ):
if components_list not in required_repository_tups:
required_repository_tups.append( components_list )
+ for components_list in val:
+ try:
+ only_if_compiling_contained_td = components_list[ 5 ]
+ except:
+ only_if_compiling_contained_td = 'False'
+ # TODO: Fix this to display the tool dependency if only_if_compiling_contained_td is True, but clarify that installation may not
+ # happen.
+ if not util.asbool( only_if_compiling_contained_td ):
+ if components_list not in required_repository_tups:
+ required_repository_tups.append( components_list )
else:
# We have a single repository with no dependencies.
- components_list = [ tool_shed_url, repository_name, repository_owner, changeset_revision, 'False' ]
+ components_list = [ tool_shed_url, repository_name, repository_owner, changeset_revision, 'False', 'False' ]
required_repository_tups.append( components_list )
if required_repository_tups:
# The value of required_repository_tups is a list of tuples, so we need to encode it.
@@ -393,3 +438,16 @@
app.model.ToolDependency.installation_status.ERROR ]:
installed_tool_dependencies.append( tool_dependency )
return installed_tool_dependencies
+
+def repository_dependency_needed_only_for_compiling_tool_dependency( repository, repository_dependency ):
+ for rd_tup in repository.tuples_of_repository_dependencies_needed_for_compiling_td:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = rd_tup
+ # TODO: we may discover that we need to check more than just installed_changeset_revision and changeset_revision here, in which
+ # case we'll need to contact the tool shed to get the list of all possible changeset_revisions.
+ if repository_dependency.tool_shed == tool_shed and \
+ repository_dependency.name == name and \
+ repository_dependency.owner == owner and \
+ ( repository_dependency.installed_changeset_revision == changeset_revision or \
+ repository_dependency.changeset_revision == changeset_revision ):
+ return True
+ return False
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/common_util.py
--- a/lib/tool_shed/util/common_util.py
+++ b/lib/tool_shed/util/common_util.py
@@ -46,7 +46,8 @@
if rd_key in [ 'root_key', 'description' ]:
continue
for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required = parse_repository_dependency_tuple( rd_tup )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td \
+ = parse_repository_dependency_tuple( rd_tup )
tool_shed_accessible, tool_dependencies = get_tool_dependencies( app,
tool_shed,
name,
@@ -155,26 +156,26 @@
return None
def parse_repository_dependency_tuple( repository_dependency_tuple, contains_error=False ):
+ # Default both prior_installation_required and only_if_compiling_contained_td to False in cases where metadata should be reset on the
+ # repository containing the repository_dependency definition.
+ prior_installation_required = 'False'
+ only_if_compiling_contained_td = 'False'
if contains_error:
if len( repository_dependency_tuple ) == 5:
- # Metadata should have been reset on the repository containing this repository_dependency definition.
tool_shed, name, owner, changeset_revision, error = repository_dependency_tuple
- # Default prior_installation_required to False.
- prior_installation_required = False
elif len( repository_dependency_tuple ) == 6:
toolshed, name, owner, changeset_revision, prior_installation_required, error = repository_dependency_tuple
- prior_installation_required = str( prior_installation_required )
- return toolshed, name, owner, changeset_revision, prior_installation_required, error
+ elif len( repository_dependency_tuple ) == 7:
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, error = repository_dependency_tuple
+ return toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, error
else:
if len( repository_dependency_tuple ) == 4:
- # Metadata should have been reset on the repository containing this repository_dependency definition.
tool_shed, name, owner, changeset_revision = repository_dependency_tuple
- # Default prior_installation_required to False.
- prior_installation_required = False
elif len( repository_dependency_tuple ) == 5:
tool_shed, name, owner, changeset_revision, prior_installation_required = repository_dependency_tuple
- prior_installation_required = str( prior_installation_required )
- return tool_shed, name, owner, changeset_revision, prior_installation_required
+ elif len( repository_dependency_tuple ) == 6:
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = repository_dependency_tuple
+ return tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td
def tool_shed_get( app, tool_shed_url, uri ):
"""Make contact with the tool shed via the uri provided."""
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/container_util.py
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -64,13 +64,15 @@
self.repository_dependencies.remove( contained_repository_dependency )
def to_repository_dependency( self, repository_dependency_id ):
- toolshed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( self.key.split( STRSEP ) )
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( self.key.split( STRSEP ) )
return RepositoryDependency( id=repository_dependency_id,
toolshed=toolshed,
repository_name=name,
repository_owner=owner,
changeset_revision=changeset_revision,
- prior_installation_required=asbool( prior_installation_required ) )
+ prior_installation_required=asbool( prior_installation_required ),
+ only_if_compiling_contained_td=asbool( only_if_compiling_contained_td ) )
class DataManager( object ):
@@ -120,13 +122,15 @@
class InvalidRepositoryDependency( object ):
"""Invalid repository dependency definition object"""
- def __init__( self, id=None, toolshed=None, repository_name=None, repository_owner=None, changeset_revision=None, prior_installation_required=False, error=None ):
+ def __init__( self, id=None, toolshed=None, repository_name=None, repository_owner=None, changeset_revision=None, prior_installation_required=False,
+ only_if_compiling_contained_td=False, error=None ):
self.id = id
self.toolshed = toolshed
self.repository_name = repository_name
self.repository_owner = repository_owner
self.changeset_revision = changeset_revision
self.prior_installation_required = prior_installation_required
+ self.only_if_compiling_contained_td = only_if_compiling_contained_td
self.error = error
@@ -194,19 +198,25 @@
"""Repository dependency object"""
def __init__( self, id=None, toolshed=None, repository_name=None, repository_owner=None, changeset_revision=None, prior_installation_required=False,
- installation_status=None, tool_shed_repository_id=None ):
+ only_if_compiling_contained_td=False, installation_status=None, tool_shed_repository_id=None ):
self.id = id
self.toolshed = toolshed
self.repository_name = repository_name
self.repository_owner = repository_owner
self.changeset_revision = changeset_revision
self.prior_installation_required = prior_installation_required
+ self.only_if_compiling_contained_td = only_if_compiling_contained_td
self.installation_status = installation_status
self.tool_shed_repository_id = tool_shed_repository_id
@property
def listify( self ):
- return [ self.toolshed, self.repository_name, self.repository_owner, self.changeset_revision, asbool( str( self.prior_installation_required ) ) ]
+ return [ self.toolshed,
+ self.repository_name,
+ self.repository_owner,
+ self.changeset_revision,
+ self.prior_installation_required,
+ self.only_if_compiling_contained_td ]
class RepositoryInstallationError( object ):
@@ -463,9 +473,14 @@
for invalid_repository_dependency in invalid_repository_dependencies:
folder_id += 1
invalid_repository_dependency_id += 1
- toolshed, name, owner, changeset_revision, prior_installation_required, error = \
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, error = \
common_util.parse_repository_dependency_tuple( invalid_repository_dependency, contains_error=True )
- key = generate_repository_dependencies_key_for_repository( toolshed, name, owner, changeset_revision, prior_installation_required )
+ key = generate_repository_dependencies_key_for_repository( toolshed,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td )
label = "Repository <b>%s</b> revision <b>%s</b> owned by <b>%s</b>" % ( name, changeset_revision, owner )
folder = Folder( id=folder_id,
key=key,
@@ -477,6 +492,7 @@
repository_owner=owner,
changeset_revision=changeset_revision,
prior_installation_required=asbool( prior_installation_required ),
+ only_if_compiling_contained_td=asbool( only_if_compiling_contained_td ),
error=error )
folder.invalid_repository_dependencies.append( ird )
invalid_repository_dependencies_folder.folders.append( folder )
@@ -1230,12 +1246,13 @@
return cast_empty_repository_dependency_folders( sub_folder, repository_dependency_id )
return folder, repository_dependency_id
-def generate_repository_dependencies_folder_label_from_key( repository_name, repository_owner, changeset_revision, prior_installation_required, key ):
+def generate_repository_dependencies_folder_label_from_key( repository_name, repository_owner, changeset_revision, prior_installation_required,
+ only_if_compiling_contained_td, key ):
"""Return a repository dependency label based on the repository dependency key."""
- if key_is_current_repositorys_key( repository_name, repository_owner, changeset_revision, prior_installation_required, key ):
+ if key_is_current_repositorys_key( repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, key ):
label = 'Repository dependencies'
else:
- if prior_installation_required:
+ if asbool( prior_installation_required ):
prior_installation_required_str = " <i>(prior install required)</i>"
else:
prior_installation_required_str = ""
@@ -1243,9 +1260,10 @@
( repository_name, changeset_revision, repository_owner, prior_installation_required_str )
return label
-def generate_repository_dependencies_key_for_repository( toolshed_base_url, repository_name, repository_owner, changeset_revision, prior_installation_required ):
- # FIXME: assumes tool shed is current tool shed since repository dependencies across tool sheds is not yet supported.
- return '%s%s%s%s%s%s%s%s%s' % ( str( toolshed_base_url ).rstrip( '/' ),
+def generate_repository_dependencies_key_for_repository( toolshed_base_url, repository_name, repository_owner, changeset_revision, prior_installation_required,
+ only_if_compiling_contained_td ):
+ """Assumes tool shed is current tool shed since repository dependencies across tool sheds is not yet supported."""
+ return '%s%s%s%s%s%s%s%s%s%s%s' % ( str( toolshed_base_url ).rstrip( '/' ),
STRSEP,
str( repository_name ),
STRSEP,
@@ -1253,7 +1271,9 @@
STRSEP,
str( changeset_revision ),
STRSEP,
- str( prior_installation_required ) )
+ str( prior_installation_required ),
+ STRSEP,
+ str( only_if_compiling_contained_td ) )
def generate_tool_dependencies_key( name, version, type ):
return '%s%s%s%s%s' % ( str( name ), STRSEP, str( version ), STRSEP, str( type ) )
@@ -1266,22 +1286,27 @@
return None
def get_components_from_repository_dependency_for_installed_repository( trans, repository_dependency ):
- """
- Parse a repository dependency and return components necessary for proper display in Galaxy on the Manage repository page.
- """
+ """Parse a repository dependency and return components necessary for proper display in Galaxy on the Manage repository page."""
+ # Default prior_installation_required and only_if_compiling_contained_td to False.
+ prior_installation_required = 'False'
+ only_if_compiling_contained_td = 'False'
if len( repository_dependency ) == 6:
# Metadata should have been reset on this installed repository, but it wasn't.
tool_shed_repository_id = repository_dependency[ 4 ]
installation_status = repository_dependency[ 5 ]
tool_shed, name, owner, changeset_revision = repository_dependency[ 0:4 ]
- # Default prior_installation_required to False.
- prior_installation_required = False
- repository_dependency = [ tool_shed, name, owner, changeset_revision, prior_installation_required ]
+ repository_dependency = [ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td ]
elif len( repository_dependency ) == 7:
- # We have a repository dependency tuple that includes a prior_installation_required value.
+ # We have a repository dependency tuple that includes a prior_installation_required value but not a only_if_compiling_contained_td value.
tool_shed_repository_id = repository_dependency[ 5 ]
installation_status = repository_dependency[ 6 ]
- repository_dependency = repository_dependency[ 0:5 ]
+ tool_shed, name, owner, changeset_revision, prior_installation_required = repository_dependency[ 0:5 ]
+ repository_dependency = [ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td ]
+ elif len( repository_dependency ) == 8:
+ # We have a repository dependency tuple that includes both a prior_installation_required value and a only_if_compiling_contained_td value.
+ tool_shed_repository_id = repository_dependency[ 6 ]
+ installation_status = repository_dependency[ 7 ]
+ repository_dependency = repository_dependency[ 0:6 ]
else:
tool_shed_repository_id = None
installation_status = 'unknown'
@@ -1295,31 +1320,41 @@
return tool_shed_repository_id, installation_status, repository_dependency
def get_components_from_key( key ):
- # FIXME: assumes tool shed is current tool shed since repository dependencies across tool sheds is not yet supported.
+ """Assumes tool shed is current tool shed since repository dependencies across tool sheds is not yet supported."""
items = key.split( STRSEP )
toolshed_base_url = items[ 0 ]
repository_name = items[ 1 ]
repository_owner = items[ 2 ]
changeset_revision = items[ 3 ]
- if len( items ) == 5:
- prior_installation_required = asbool( str( items[ 4 ] ) )
- return toolshed_base_url, repository_name, repository_owner, changeset_revision, prior_installation_required
+ if len( items ) >= 5:
+ try:
+ prior_installation_required = items[ 4 ]
+ except:
+ prior_installation_required = 'False'
+ try:
+ only_if_compiling_contained_td = items[ 5 ]
+ except:
+ only_if_compiling_contained_td = 'False'
+ return toolshed_base_url, repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td
else:
# For backward compatibility to the 12/20/12 Galaxy release we have to return the following, and callers must handle exceptions.
return toolshed_base_url, repository_name, repository_owner, changeset_revision
def handle_repository_dependencies_container_entry( trans, repository_dependencies_folder, rd_key, rd_value, folder_id, repository_dependency_id, folder_keys ):
try:
- toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required = get_components_from_key( rd_key )
+ toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ get_components_from_key( rd_key )
except ValueError:
- # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required to False.
+ # For backward compatibility to the 12/20/12 Galaxy release, default prior_installation_required and only_if_compiling_contained_td to 'False'.
toolshed, repository_name, repository_owner, changeset_revision = get_components_from_key( rd_key )
- prior_installation_required = False
+ prior_installation_required = 'False'
+ only_if_compiling_contained_td = 'False'
folder = get_folder( repository_dependencies_folder, rd_key )
label = generate_repository_dependencies_folder_label_from_key( repository_name,
repository_owner,
changeset_revision,
prior_installation_required,
+ only_if_compiling_contained_td,
repository_dependencies_folder.key )
if folder:
if rd_key not in folder_keys:
@@ -1351,7 +1386,7 @@
installation_status = None
can_create_dependency = not is_subfolder_of( sub_folder, repository_dependency )
if can_create_dependency:
- toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required = \
+ toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( repository_dependency )
repository_dependency_id += 1
repository_dependency = RepositoryDependency( id=repository_dependency_id,
@@ -1360,6 +1395,7 @@
repository_owner=repository_owner,
changeset_revision=changeset_revision,
prior_installation_required=asbool( prior_installation_required ),
+ only_if_compiling_contained_td=asbool( only_if_compiling_contained_td ),
installation_status=installation_status,
tool_shed_repository_id=tool_shed_repository_id )
# Insert the repository_dependency into the folder.
@@ -1367,25 +1403,35 @@
return repository_dependencies_folder, folder_id, repository_dependency_id
def is_subfolder_of( folder, repository_dependency ):
- toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required = \
+ toolshed, repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( repository_dependency )
- key = generate_repository_dependencies_key_for_repository( toolshed, repository_name, repository_owner, changeset_revision, asbool( prior_installation_required ) )
+ key = generate_repository_dependencies_key_for_repository( toolshed,
+ repository_name,
+ repository_owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td )
for sub_folder in folder.folders:
if key == sub_folder.key:
return True
return False
-def key_is_current_repositorys_key( repository_name, repository_owner, changeset_revision, prior_installation_required, key ):
+def key_is_current_repositorys_key( repository_name, repository_owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, key ):
try:
- toolshed_base_url, key_name, key_owner, key_changeset_revision, key_prior_installation_required = get_components_from_key( key )
+ toolshed_base_url, key_name, key_owner, key_changeset_revision, key_prior_installation_required, key_only_if_compiling_contained_td = \
+ get_components_from_key( key )
except ValueError:
# For backward compatibility to the 12/20/12 Galaxy release, default key_prior_installation_required to False.
toolshed_base_url, key_name, key_owner, key_changeset_revision = get_components_from_key( key )
- key_prior_installation_required = False
- return repository_name == key_name and \
+ key_prior_installation_required = 'False'
+ key_only_if_compiling_contained_td = 'False'
+ if repository_name == key_name and \
repository_owner == key_owner and \
changeset_revision == key_changeset_revision and \
- prior_installation_required == key_prior_installation_required
+ prior_installation_required == key_prior_installation_required and \
+ only_if_compiling_contained_td == key_only_if_compiling_contained_td:
+ return True
+ return False
def populate_repository_dependencies_container( trans, repository_dependencies_folder, repository_dependencies, folder_id, repository_dependency_id ):
folder_keys = repository_dependencies.keys()
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -199,19 +199,23 @@
def compare_repository_dependencies( trans, ancestor_repository_dependencies, current_repository_dependencies ):
"""Determine if ancestor_repository_dependencies is the same as or a subset of current_repository_dependencies."""
- # The list of repository_dependencies looks something like: [["http://localhost:9009", "emboss_datatypes", "test", "ab03a2a5f407", False]].
+ # The list of repository_dependencies looks something like:
+ # [["http://localhost:9009", "emboss_datatypes", "test", "ab03a2a5f407", "False", "False"]].
# Create a string from each tuple in the list for easier comparison.
if len( ancestor_repository_dependencies ) <= len( current_repository_dependencies ):
for ancestor_tup in ancestor_repository_dependencies:
- ancestor_tool_shed, ancestor_repository_name, ancestor_repository_owner, ancestor_changeset_revision, ancestor_prior_installation_required = ancestor_tup
+ a_tool_shed, a_repo_name, a_repo_owner, a_changeset_revision, a_prior_installation_required, a_only_if_compiling_contained_td = \
+ ancestor_tup
found_in_current = False
for current_tup in current_repository_dependencies:
- current_tool_shed, current_repository_name, current_repository_owner, current_changeset_revision, current_prior_installation_required = current_tup
- if current_tool_shed == ancestor_tool_shed and \
- current_repository_name == ancestor_repository_name and \
- current_repository_owner == ancestor_repository_owner and \
- current_changeset_revision == ancestor_changeset_revision and \
- util.string_as_bool( current_prior_installation_required ) == util.string_as_bool( ancestor_prior_installation_required ):
+ c_tool_shed, c_repo_name, c_repo_owner, c_changeset_revision, c_prior_installation_required, c_only_if_compiling_contained_td = \
+ current_tup
+ if c_tool_shed == a_tool_shed and \
+ c_repo_name == a_repo_name and \
+ c_repo_owner == a_repo_owner and \
+ c_changeset_revision == a_changeset_revision and \
+ util.string_as_bool( c_prior_installation_required ) == util.string_as_bool( a_prior_installation_required ) and \
+ util.string_as_bool( c_only_if_compiling_contained_td ) == util.string_as_bool( a_only_if_compiling_contained_td ):
found_in_current = True
break
if not found_in_current:
@@ -354,9 +358,11 @@
Determine if the only difference between rd_tup and a dependency definition in the list of repository_dependencies is the changeset_revision value.
"""
new_metadata_required = False
- rd_tool_shed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required = common_util.parse_repository_dependency_tuple( rd_tup )
+ rd_tool_shed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
for repository_dependency in repository_dependencies:
- tool_shed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( repository_dependency )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( repository_dependency )
if rd_tool_shed == tool_shed and rd_name == name and rd_owner == owner:
# Determine if the repository represented by the dependency tuple is an instance of the repository type TipOnly.
required_repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
@@ -750,7 +756,9 @@
# We have a complex repository dependency. If the returned value of repository_dependency_is_valid is True, the tool
# dependency definition will be set as invalid. This is currently the only case where a tool dependency definition is
# considered invalid.
- repository_dependency_tup, repository_dependency_is_valid, error_message = handle_repository_elem( app=app, repository_elem=sub_elem )
+ repository_dependency_tup, repository_dependency_is_valid, error_message = handle_repository_elem( app=app,
+ repository_elem=sub_elem,
+ only_if_compiling_contained_td=False )
elif sub_elem.tag == 'install':
package_install_version = sub_elem.get( 'version', '1.0' )
if package_install_version == '1.0':
@@ -763,7 +771,8 @@
in_actions_group, actions_elem = actions_elem_tuple
if in_actions_group:
# Since we're inside an <actions_group> tag set, inspect the actions_elem to see if a complex repository dependency
- # is defined.
+ # is defined. By definition, complex repository dependency definitions contained within the last <actions> tag set
+ # within an <actions_group> tag set will have the value of "only_if_compiling_contained_td" set to True in
for action_elem in actions_elem:
if action_elem.tag == 'package':
# <package name="libgtextutils" version="0.6">
@@ -776,7 +785,9 @@
if sub_action_elem.tag == 'repository':
# We have a complex repository dependency.
repository_dependency_tup, repository_dependency_is_valid, error_message = \
- handle_repository_elem( app=app, repository_elem=sub_action_elem )
+ handle_repository_elem( app=app,
+ repository_elem=sub_action_elem,
+ only_if_compiling_contained_td=True )
if requirements_dict:
dependency_key = '%s/%s' % ( package_name, package_version )
if repository_dependency_is_valid:
@@ -806,13 +817,21 @@
valid_repository_dependencies_dict = dict( description=root.get( 'description' ) )
valid_repository_dependency_tups = []
for repository_elem in root.findall( 'repository' ):
- repository_dependency_tup, repository_dependency_is_valid, error_message = handle_repository_elem( app, repository_elem )
+ repository_dependency_tup, repository_dependency_is_valid, error_message = handle_repository_elem( app,
+ repository_elem,
+ only_if_compiling_contained_td=False )
if repository_dependency_is_valid:
valid_repository_dependency_tups.append( repository_dependency_tup )
else:
# Append the error_message to the repository dependencies tuple.
- toolshed, name, owner, changeset_revision, prior_installation_required = repository_dependency_tup
- repository_dependency_tup = ( toolshed, name, owner, changeset_revision, str( prior_installation_required ), error_message )
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = repository_dependency_tup
+ repository_dependency_tup = ( toolshed,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td,
+ error_message )
invalid_repository_dependency_tups.append( repository_dependency_tup )
if invalid_repository_dependency_tups:
invalid_repository_dependencies_dict[ 'repository_dependencies' ] = invalid_repository_dependency_tups
@@ -859,8 +878,9 @@
# We have an invalid complex repository dependency, so mark the tool dependency as invalid.
tool_dependency_is_valid = False
# Append the error message to the invalid repository dependency tuple.
- toolshed, name, owner, changeset_revision, prior_installation_required = repository_dependency_tup
- repository_dependency_tup = ( toolshed, name, owner, changeset_revision, str( prior_installation_required ), message )
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = repository_dependency_tup
+ repository_dependency_tup = \
+ ( toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, message )
invalid_repository_dependency_tups.append( repository_dependency_tup )
error_message = '%s %s' % ( error_message, message )
elif elem.tag == 'set_environment':
@@ -1137,7 +1157,7 @@
deleted_tool_dependency_names.append( original_dependency_val_dict[ 'name' ] )
return updated_tool_dependency_names, deleted_tool_dependency_names
-def handle_repository_elem( app, repository_elem ):
+def handle_repository_elem( app, repository_elem, only_if_compiling_contained_td=False ):
"""
Process the received repository_elem which is a <repository> tag either from a repository_dependencies.xml file or a tool_dependencies.xml file.
If the former, we're generating repository dependencies metadata for a repository in the tool shed. If the latter, we're generating package
@@ -1155,7 +1175,7 @@
owner = repository_elem.get( 'owner' )
changeset_revision = repository_elem.get( 'changeset_revision' )
prior_installation_required = str( repository_elem.get( 'prior_installation_required', False ) )
- repository_dependency_tup = [ toolshed, name, owner, changeset_revision, str( prior_installation_required ) ]
+ repository_dependency_tup = [ toolshed, name, owner, changeset_revision, prior_installation_required, str( only_if_compiling_contained_td ) ]
user = None
repository = None
if app.name == 'galaxy':
@@ -1974,9 +1994,9 @@
repository_dependencies_dict = metadata.get( 'invalid_repository_dependencies', None )
for repository_dependency_tup in repository_dependency_tups:
if is_valid:
- tool_shed, name, owner, changeset_revision, prior_installation_required = repository_dependency_tup
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = repository_dependency_tup
else:
- tool_shed, name, owner, changeset_revision, prior_installation_required, error_message = repository_dependency_tup
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, error_message = repository_dependency_tup
if repository_dependencies_dict:
repository_dependencies = repository_dependencies_dict.get( 'repository_dependencies', [] )
for repository_dependency_tup in repository_dependency_tups:
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -33,30 +33,30 @@
for key, val in repository_dependencies.items():
if key in [ 'root_key', 'description' ]:
continue
- dependent_repository = None
+ d_repository = None
try:
- dependent_toolshed, dependent_name, dependent_owner, dependent_changeset_revision, dependent_prior_installation_required = \
+ d_toolshed, d_name, d_owner, d_changeset_revision, d_prior_installation_required, d_only_if_compiling_contained_td = \
container_util.get_components_from_key( key )
except ValueError:
# For backward compatibility to the 12/20/12 Galaxy release.
- dependent_toolshed, dependent_name, dependent_owner, dependent_changeset_revision = container_util.get_components_from_key( key )
+ d_toolshed, d_name, d_owner, d_changeset_revision = container_util.get_components_from_key( key )
for tsr in tool_shed_repositories:
# Get the the tool_shed_repository defined by name, owner and changeset_revision. This is the repository that will be
- # dependent upon each of the tool shed repositories contained in val.
- # TODO: Check tool_shed_repository.tool_shed as well when repository dependencies across tool sheds is supported.
- if tsr.name == dependent_name and tsr.owner == dependent_owner and tsr.changeset_revision == dependent_changeset_revision:
- dependent_repository = tsr
+ # dependent upon each of the tool shed repositories contained in val. We'll need to check tool_shed_repository.tool_shed
+ # as well if/when repository dependencies across tool sheds is supported.
+ if tsr.name == d_name and tsr.owner == d_owner and tsr.changeset_revision == d_changeset_revision:
+ d_repository = tsr
break
- if dependent_repository is None:
+ if d_repository is None:
# The dependent repository is not in the received list so look in the database.
- dependent_repository = suc.get_or_create_tool_shed_repository( trans, dependent_toolshed, dependent_name, dependent_owner, dependent_changeset_revision )
+ d_repository = suc.get_or_create_tool_shed_repository( trans, d_toolshed, d_name, d_owner, d_changeset_revision )
# Process each repository_dependency defined for the current dependent repository.
for repository_dependency_components_list in val:
required_repository = None
- rd_toolshed, rd_name, rd_owner, rd_changeset_revision, prior_installation_required = \
+ rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( repository_dependency_components_list )
# Get the the tool_shed_repository defined by rd_name, rd_owner and rd_changeset_revision. This is the repository that will be
- # required by the current dependent_repository.
+ # required by the current d_repository.
# TODO: Check tool_shed_repository.tool_shed as well when repository dependencies across tool sheds is supported.
for tsr in tool_shed_repositories:
if tsr.name == rd_name and tsr.owner == rd_owner and tsr.changeset_revision == rd_changeset_revision:
@@ -65,9 +65,9 @@
if required_repository is None:
# The required repository is not in the received list so look in the database.
required_repository = suc.get_or_create_tool_shed_repository( trans, rd_toolshed, rd_name, rd_owner, rd_changeset_revision )
- # Ensure there is a repository_dependency relationship between dependent_repository and required_repository.
+ # Ensure there is a repository_dependency relationship between d_repository and required_repository.
rrda = None
- for rd in dependent_repository.repository_dependencies:
+ for rd in d_repository.repository_dependencies:
if rd.id == required_repository.id:
rrda = rd
break
@@ -78,8 +78,8 @@
repository_dependency = trans.model.RepositoryDependency( tool_shed_repository_id=required_repository.id )
trans.sa_session.add( repository_dependency )
trans.sa_session.flush()
- # Build the relationship between the dependent_repository and the required_repository.
- rrda = trans.model.RepositoryRepositoryDependencyAssociation( tool_shed_repository_id=dependent_repository.id,
+ # Build the relationship between the d_repository and the required_repository.
+ rrda = trans.model.RepositoryRepositoryDependencyAssociation( tool_shed_repository_id=d_repository.id,
repository_dependency_id=repository_dependency.id )
trans.sa_session.add( rrda )
trans.sa_session.flush()
@@ -257,40 +257,42 @@
if invalid_repository_dependencies_dict:
invalid_repository_dependencies = invalid_repository_dependencies_dict.get( 'invalid_repository_dependencies', [] )
for repository_dependency_tup in invalid_repository_dependencies:
- toolshed, name, owner, changeset_revision, prior_installation_required, error = \
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td, error = \
common_util.parse_repository_dependency_tuple( repository_dependency_tup, contains_error=True )
if error:
message = '%s ' % str( error )
return message
def get_key_for_repository_changeset_revision( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
- prior_installation_required = get_prior_installation_required_for_key( toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
+ prior_installation_required, only_if_compiling_contained_td = \
+ get_prior_installation_required_and_only_if_compiling_contained_td( toolshed_base_url, repository, repository_metadata, all_repository_dependencies )
# Create a key with the value of prior_installation_required defaulted to False.
key = container_util.generate_repository_dependencies_key_for_repository( toolshed_base_url=toolshed_base_url,
repository_name=repository.name,
repository_owner=repository.user.username,
changeset_revision=repository_metadata.changeset_revision,
- prior_installation_required=prior_installation_required )
+ prior_installation_required=prior_installation_required,
+ only_if_compiling_contained_td=only_if_compiling_contained_td )
return key
-def get_prior_installation_required_for_key( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
+def get_prior_installation_required_and_only_if_compiling_contained_td( toolshed_base_url, repository, repository_metadata, all_repository_dependencies ):
"""
If all_repository_dependencies contains a repository dependency tuple that is associated with the received repository, return the
value of the tuple's prior_installation_required component.
"""
- rd_tuple = ( toolshed_base_url, repository.name, repository.user.username, repository_metadata.changeset_revision )
for rd_key, rd_tups in all_repository_dependencies.items():
if rd_key in [ 'root_key', 'description' ]:
continue
for rd_tup in rd_tups:
- rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required = common_util.parse_repository_dependency_tuple( rd_tup )
+ rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
if rd_toolshed == toolshed_base_url and \
rd_name == repository.name and \
rd_owner == repository.user.username and \
rd_changeset_revision == repository_metadata.changeset_revision:
- return rd_prior_installation_required
- # Default prior_installation_required to False.
- return False
+ return rd_prior_installation_required, rd_only_if_compiling_contained_td
+ # Default both prior_installation_required and only_if_compiling_contained_td to False.
+ return 'False', 'False'
def get_repository_dependencies_for_installed_tool_shed_repository( trans, repository ):
"""
@@ -374,7 +376,7 @@
for key_rd_dict in key_rd_dicts:
key = key_rd_dict.keys()[ 0 ]
repository_dependency = key_rd_dict[ key ]
- rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required = \
+ rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
common_util.parse_repository_dependency_tuple( repository_dependency )
if suc.tool_shed_is_this_tool_shed( rd_toolshed ):
repository = suc.get_repository_by_name_and_owner( trans.app, rd_name, rd_owner )
@@ -397,12 +399,13 @@
changeset_revision )
if repository_metadata:
new_key_rd_dict = {}
- new_key_rd_dict[ key ] = [ rd_toolshed, rd_name, rd_owner, repository_metadata.changeset_revision, str( rd_prior_installation_required ) ]
+ new_key_rd_dict[ key ] = \
+ [ rd_toolshed, rd_name, rd_owner, repository_metadata.changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td ]
# We have the updated changset revision.
updated_key_rd_dicts.append( new_key_rd_dict )
else:
try:
- toolshed, repository_name, repository_owner, repository_changeset_revision, prior_installation_required = \
+ toolshed, repository_name, repository_owner, repository_changeset_revision, prior_installation_required, rd_only_if_compiling_contained_td = \
container_util.get_components_from_key( key )
except ValueError:
# For backward compatibility to the 12/20/12 Galaxy release.
@@ -412,7 +415,7 @@
log.debug( message )
else:
try:
- toolshed, repository_name, repository_owner, repository_changeset_revision, prior_installation_required = \
+ toolshed, repository_name, repository_owner, repository_changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
container_util.get_components_from_key( key )
except ValueError:
# For backward compatibility to the 12/20/12 Galaxy release.
@@ -462,7 +465,8 @@
def handle_key_rd_dicts_for_repository( trans, current_repository_key, repository_key_rd_dicts, key_rd_dicts_to_be_processed, handled_key_rd_dicts, circular_repository_dependencies ):
key_rd_dict = repository_key_rd_dicts.pop( 0 )
repository_dependency = key_rd_dict[ current_repository_key ]
- toolshed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( repository_dependency )
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( repository_dependency )
if suc.tool_shed_is_this_tool_shed( toolshed ):
required_repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
required_repository_metadata = metadata_util.get_repository_metadata_by_repository_id_changeset_revision( trans,
@@ -691,11 +695,13 @@
clean_key_rd_dicts = []
key = key_rd_dicts[ 0 ].keys()[ 0 ]
repository_tup = key.split( container_util.STRSEP )
- rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required = common_util.parse_repository_dependency_tuple( repository_tup )
+ rd_toolshed, rd_name, rd_owner, rd_changeset_revision, rd_prior_installation_required, rd_only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( repository_tup )
for key_rd_dict in key_rd_dicts:
k = key_rd_dict.keys()[ 0 ]
repository_dependency = key_rd_dict[ k ]
- toolshed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( repository_dependency )
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( repository_dependency )
if rd_toolshed == toolshed and rd_name == name and rd_owner == owner:
log.debug( "Removing repository dependency for repository %s owned by %s since it refers to a revision within itself." % ( name, owner ) )
else:
@@ -705,8 +711,14 @@
return clean_key_rd_dicts
def get_repository_dependency_as_key( repository_dependency ):
- tool_shed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( repository_dependency )
- return container_util.generate_repository_dependencies_key_for_repository( tool_shed, name, owner, changeset_revision, str( prior_installation_required ) )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( repository_dependency )
+ return container_util.generate_repository_dependencies_key_for_repository( tool_shed,
+ name,
+ owner,
+ changeset_revision,
+ prior_installation_required,
+ only_if_compiling_contained_td )
def get_repository_dependency_by_repository_id( trans, decoded_repository_id ):
return trans.sa_session.query( trans.model.RepositoryDependency ) \
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -325,7 +325,8 @@
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', False]
- toolshed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( repo_info_tup )
+ toolshed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( repo_info_tup )
# Don't include the changeset_revision in clone urls.
return url_join( toolshed, 'repos', owner, name )
@@ -975,16 +976,24 @@
if key in [ 'description', 'root_key' ]:
continue
for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision, prior_installation_required = common_util.parse_repository_dependency_tuple( rd_tup )
- if asbool( prior_installation_required ):
- if trans.webapp.name == 'galaxy':
- repository = get_repository_for_dependency_relationship( trans.app, tool_shed, name, owner, changeset_revision )
- else:
- repository = get_repository_by_name_and_owner( trans.app, name, owner )
- if repository:
- encoded_repository_id = trans.security.encode_id( repository.id )
- if encoded_repository_id in tsr_ids:
- prior_tsr_ids.append( encoded_repository_id )
+ tool_shed, name, owner, changeset_revision, prior_installation_required, only_if_compiling_contained_td = \
+ common_util.parse_repository_dependency_tuple( rd_tup )
+ # If only_if_compiling_contained_td is False, then the repository dependency is not required to be installed prior to the dependent
+ # repository even if prior_installation_required is True. This is because the only meaningful content of the repository dependency
+ # is it's contained tool dependency, which is required in order to compile the dependent repository's tool dependency. In the scenario
+ # where the repository dependency is not installed prior to the dependent repository's tool dependency compilation process, the tool
+ # dependency compilation framework will install the repository dependency prior to compilation of the dependent repository's tool
+ # dependency.
+ if not asbool( only_if_compiling_contained_td ):
+ if asbool( prior_installation_required ):
+ if trans.webapp.name == 'galaxy':
+ repository = get_repository_for_dependency_relationship( trans.app, tool_shed, name, owner, changeset_revision )
+ else:
+ repository = get_repository_by_name_and_owner( trans.app, name, owner )
+ if repository:
+ encoded_repository_id = trans.security.encode_id( repository.id )
+ if encoded_repository_id in tsr_ids:
+ prior_tsr_ids.append( encoded_repository_id )
return prior_tsr_ids
def get_repository_in_tool_shed( trans, id ):
@@ -1425,9 +1434,21 @@
"""Return a reversed list of changesets in the repository changelog up to and including the included_upper_bounds_changeset_revision."""
return reversed_lower_upper_bounded_changelog( repo, INITIAL_CHANGELOG_HASH, included_upper_bounds_changeset_revision )
+def set_only_if_compiling_contained_td( repository, required_repository ):
+ """Return True if the received required_repository is only needed to compile a tool dependency defined for the received repository."""
+ # This method is called only from Galaxy when rendering repository dependencies for an installed tool shed repository.
+ # TODO: Do we need to check more than changeset_revision here?
+ required_repository_tup = [ required_repository.tool_shed, required_repository.name, required_repository.owner, required_repository.changeset_revision ]
+ for tup in repository.tuples_of_repository_dependencies_needed_for_compiling_td:
+ partial_tup = tup[ 0:4 ]
+ if partial_tup == required_repository_tup:
+ return 'True'
+ return 'False'
+
def set_prior_installation_required( repository, required_repository ):
"""Return True if the received required_repository must be installed before the received repository."""
# This method is called only from Galaxy when rendering repository dependencies for an installed tool shed repository.
+ # TODO: Do we need to check more than changeset_revision here?
required_repository_tup = [ required_repository.tool_shed, required_repository.name, required_repository.owner, required_repository.changeset_revision ]
# Get the list of repository dependency tuples associated with the received repository where prior_installation_required is True.
required_rd_tups_that_must_be_installed = repository.requires_prior_installation_of
@@ -1435,9 +1456,9 @@
# Repository dependency tuples in metadata include a prior_installation_required value, so strip it for comparision.
partial_required_rd_tup = required_rd_tup[ 0:4 ]
if partial_required_rd_tup == required_repository_tup:
- # Return the boolean value of prior_installation_required, which defaults to False.
- return required_rd_tup[ 4 ]
- return False
+ # Return the string value of prior_installation_required, which defaults to 'False'.
+ return str( required_rd_tup[ 4 ] )
+ return 'False'
def size_string( raw_text, size=MAX_DISPLAY_SIZE ):
"""Return a subset of a string (up to MAX_DISPLAY_SIZE) translated to a safe string for display in a browser."""
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -347,15 +347,17 @@
get_installed_and_missing_tool_dependencies( trans, required_repository, tool_dependencies )
if required_repository_installed_tool_dependencies:
# Add the install_dir attribute to the tool_dependencies.
- required_repository_installed_tool_dependencies = add_installation_directories_to_tool_dependencies( trans=trans,
- tool_dependencies=required_repository_installed_tool_dependencies )
+ required_repository_installed_tool_dependencies = \
+ add_installation_directories_to_tool_dependencies( trans=trans,
+ tool_dependencies=required_repository_installed_tool_dependencies )
for td_key, td_dict in required_repository_installed_tool_dependencies.items():
if td_key not in repository_installed_tool_dependencies:
repository_installed_tool_dependencies[ td_key ] = td_dict
if required_repository_missing_tool_dependencies:
# Add the install_dir attribute to the tool_dependencies.
- required_repository_missing_tool_dependencies = add_installation_directories_to_tool_dependencies( trans=trans,
- tool_dependencies=required_repository_missing_tool_dependencies )
+ required_repository_missing_tool_dependencies = \
+ add_installation_directories_to_tool_dependencies( trans=trans,
+ tool_dependencies=required_repository_missing_tool_dependencies )
for td_key, td_dict in required_repository_missing_tool_dependencies.items():
if td_key not in repository_missing_tool_dependencies:
repository_missing_tool_dependencies[ td_key ] = td_dict
diff -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 -r ed3c786622741814a07589a1e642cca75c51c822 templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -619,7 +619,7 @@
<%def name="render_repository_dependency( repository_dependency, pad, parent, row_counter, row_is_header=False )"><%
- from galaxy.util import string_as_bool
+ from galaxy.util import asbool
encoded_id = trans.security.encode_id( repository_dependency.id )
if trans.webapp.name == 'galaxy':
if repository_dependency.tool_shed_repository_id:
@@ -633,8 +633,7 @@
repository_name = str( repository_dependency.repository_name )
repository_owner = str( repository_dependency.repository_owner )
changeset_revision = str( repository_dependency.changeset_revision )
- prior_installation_required = string_as_bool( str( repository_dependency.prior_installation_required ) )
- if prior_installation_required:
+ if asbool( str( repository_dependency.prior_installation_required ) ):
prior_installation_required_str = " <i>(prior install required)</i>"
else:
prior_installation_required_str = ""
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: Dave Bouvier: When the install and test framework has finished testing a repository, use deactivate instead of uninstall, so that installed tool dependencies are retained.
by commits-noreply@bitbucket.org 09 Sep '13
by commits-noreply@bitbucket.org 09 Sep '13
09 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/149dbd29acbc/
Changeset: 149dbd29acbc
User: Dave Bouvier
Date: 2013-09-09 19:44:03
Summary: When the install and test framework has finished testing a repository, use deactivate instead of uninstall, so that installed tool dependencies are retained.
Affected #: 1 file
diff -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 -r 149dbd29acbce6396a969662a9b899cdbb7bdb46 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
@@ -6,7 +6,9 @@
log = logging.getLogger( __name__ )
+
class InstallTestRepository( TwillTestCase ):
+
def setUp( self ):
# Security helper
id_secret = os.environ.get( 'GALAXY_INSTALL_TEST_SECRET', 'changethisinproductiontoo' )
@@ -24,21 +26,22 @@
self.galaxy_tool_dependency_dir = os.environ.get( 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR' )
self.shed_tools_dict = {}
self.home()
- def initiate_installation_process( self,
- install_tool_dependencies=False,
- install_repository_dependencies=True,
- no_changes=True,
+
+ def initiate_installation_process( self,
+ install_tool_dependencies=False,
+ install_repository_dependencies=True,
+ no_changes=True,
new_tool_panel_section=None ):
html = self.last_page()
- # Since the installation process is by necessity asynchronous, we have to get the parameters to 'manually' initiate the
- # installation process. This regex will return the tool shed repository IDs in group(1), the encoded_kwd parameter in
- # group(2), and the reinstalling flag in group(3) and pass them to the manage_repositories method in the Galaxy
+ # Since the installation process is by necessity asynchronous, we have to get the parameters to 'manually' initiate the
+ # installation process. This regex will return the tool shed repository IDs in group(1), the encoded_kwd parameter in
+ # group(2), and the reinstalling flag in group(3) and pass them to the manage_repositories method in the Galaxy
# admin_toolshed controller.
install_parameters = re.search( 'initiate_repository_installation\( "([^"]+)", "([^"]+)", "([^"]+)" \);', html )
if install_parameters:
iri_ids = install_parameters.group(1)
# In some cases, the returned iri_ids are of the form: "[u'<encoded id>', u'<encoded id>']"
- # This regex ensures that non-hex characters are stripped out of the list, so that util.listify/decode_id
+ # This regex ensures that non-hex characters are stripped out of the list, so that util.listify/decode_id
# will handle them correctly. It's safe to pass the cleaned list to manage_repositories, because it can parse
# comma-separated values.
repository_ids = str( iri_ids )
@@ -49,8 +52,9 @@
( ','.join( util.listify( repository_ids ) ), encoded_kwd, reinstalling )
self.visit_url( url )
return util.listify( repository_ids )
- def install_repository( self, repository_info_dict, install_tool_dependencies=True, install_repository_dependencies=True,
- strings_displayed=[], strings_not_displayed=[], preview_strings_displayed=[],
+
+ def install_repository( self, repository_info_dict, install_tool_dependencies=True, install_repository_dependencies=True,
+ strings_displayed=[], strings_not_displayed=[], preview_strings_displayed=[],
post_submit_strings_displayed=[], new_tool_panel_section=None, **kwd ):
name = repository_info_dict[ 'name' ]
owner = repository_info_dict[ 'owner' ]
@@ -59,23 +63,23 @@
tool_shed_url = repository_info_dict[ 'tool_shed_url' ]
preview_params = urllib.urlencode( dict( repository_id=encoded_repository_id, changeset_revision=changeset_revision ) )
self.visit_url( '%s/repository/preview_tools_in_changeset?%s' % ( tool_shed_url, preview_params ) )
- install_params = urllib.urlencode( dict( repository_ids=encoded_repository_id,
+ install_params = urllib.urlencode( dict( repository_ids=encoded_repository_id,
changeset_revisions=changeset_revision,
galaxy_url=self.url ) )
- # If the tool shed does not have the same hostname as the Galaxy server being used for these tests,
- # twill will not carry over previously set cookies for the Galaxy server when following the
- # install_repositories_by_revision redirect, so we have to include 403 in the allowed HTTP
+ # If the tool shed does not have the same hostname as the Galaxy server being used for these tests,
+ # twill will not carry over previously set cookies for the Galaxy server when following the
+ # install_repositories_by_revision redirect, so we have to include 403 in the allowed HTTP
# status codes and log in again.
url = '%s/repository/install_repositories_by_revision?%s' % ( tool_shed_url, install_params )
self.visit_url( url, allowed_codes=[ 200, 403 ] )
self.logout()
self.login( email='test(a)bx.psu.edu', username='test' )
- install_params = urllib.urlencode( dict( repository_ids=encoded_repository_id,
+ install_params = urllib.urlencode( dict( repository_ids=encoded_repository_id,
changeset_revisions=changeset_revision,
tool_shed_url=tool_shed_url ) )
url = '/admin_toolshed/prepare_for_install?%s' % install_params
self.visit_url( url )
- # This section is tricky, due to the way twill handles form submission. The tool dependency checkbox needs to
+ # This section is tricky, due to the way twill handles form submission. The tool dependency checkbox needs to
# be hacked in through tc.browser, putting the form field in kwd doesn't work.
if 'install_tool_dependencies' in self.last_page():
form = tc.browser.get_form( 'select_tool_panel_section' )
@@ -105,12 +109,14 @@
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 visit_url( self, url, allowed_codes=[ 200 ] ):
new_url = tc.go( url )
return_code = tc.browser.get_code()
assert return_code in allowed_codes, 'Invalid HTTP return code %s, allowed codes: %s' % \
- ( return_code, ', '.join( str( code ) for code in allowed_codes ) )
+ ( return_code, ', '.join( str( code ) for code in allowed_codes ) )
return new_url
+
def wait_for_repository_installation( self, repository_ids ):
final_states = [ model.ToolShedRepository.installation_status.ERROR,
model.ToolShedRepository.installation_status.INSTALLED ]
@@ -129,12 +135,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.fv ( 1, "remove_from_disk", 'false' )
tc.submit( 'deactivate_or_uninstall_repository_button' )
strings_displayed = [ 'The repository named' ]
- strings_displayed.append( 'has been uninstalled' )
+ strings_displayed.append( 'has been deactivated' )
self.check_for_strings( strings_displayed, strings_not_displayed=[] )
-
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: marten: reworked some jobs from the reports webapp and modified templates accordingly
by commits-noreply@bitbucket.org 09 Sep '13
by commits-noreply@bitbucket.org 09 Sep '13
09 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1a868f109ed9/
Changeset: 1a868f109ed9
User: marten
Date: 2013-09-09 19:24:15
Summary: reworked some jobs from the reports webapp and modified templates accordingly
forces NO session for the DB because it is not needed
Affected #: 10 files
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -341,6 +341,8 @@
self.__user = None
self.galaxy_session = None
self.error_message = None
+
+
if self.environ.get('is_api_request', False):
# With API requests, if there's a key, use it and associate the
# user with the transaction.
@@ -348,6 +350,8 @@
# If an error message is set here, it's sent back using
# trans.show_error in the response -- in expose_api.
self.error_message = self._authenticate_api( session_cookie )
+ elif self.app.name == "reports":
+ self.galaxy_session = None
else:
#This is a web request, get or create session.
self._ensure_valid_session( session_cookie )
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 lib/galaxy/webapps/reports/controllers/jobs.py
--- a/lib/galaxy/webapps/reports/controllers/jobs.py
+++ b/lib/galaxy/webapps/reports/controllers/jobs.py
@@ -47,26 +47,23 @@
return query
# We are either filtering on a date like YYYY-MM-DD or on a month like YYYY-MM,
# so we need to figure out which type of date we have
- if column_filter.count( '-' ) == 2:
- # We are filtering on a date like YYYY-MM-DD
+ if column_filter.count( '-' ) == 2: # We are filtering on a date like YYYY-MM-DD
year, month, day = map( int, column_filter.split( "-" ) )
start_date = date( year, month, day )
end_date = start_date + timedelta( days=1 )
- return query.filter( and_( self.model_class.table.c.create_time >= start_date,
- self.model_class.table.c.create_time < end_date ) )
- if column_filter.count( '-' ) == 1:
- # We are filtering on a month like YYYY-MM
+ if column_filter.count( '-' ) == 1: # We are filtering on a month like YYYY-MM
year, month = map( int, column_filter.split( "-" ) )
start_date = date( year, month, 1 )
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
- return query.filter( and_( self.model_class.table.c.create_time >= start_date,
+
+ return query.filter( and_( self.model_class.table.c.create_time >= start_date,
self.model_class.table.c.create_time < end_date ) )
# Grid definition
use_async = False
model_class = model.Job
title = "Jobs"
- template='/webapps/reports/grid.mako'
+ template = '/webapps/reports/grid.mako'
default_sort_key = "id"
columns = [
JobIdColumn( "Id",
@@ -112,12 +109,21 @@
num_rows_per_page = 50
preserve_state = False
use_paging = True
+
def build_initial_query( self, trans, **kwd ):
+ params = util.Params( kwd )
+ monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+ monitor_user_id = get_monitor_id( trans, monitor_email )
return trans.sa_session.query( self.model_class ) \
.join( model.User ) \
+ .filter( model.Job.table.c.user_id != monitor_user_id )\
.enable_eagerloads( False )
class Jobs( BaseUIController ):
+ """
+ Class contains functions for querying data requested by user via the webapp. It exposes the functions and
+ responds to requests with the filled .mako templates.
+ """
specified_date_list_grid = SpecifiedDateListGrid()
@@ -160,7 +166,7 @@
if job.user:
kwd[ 'email' ] = job.user.email
else:
- kwd[ 'email' ] = None # For anonymous users
+ kwd[ 'email' ] = None # For anonymous users
return trans.response.send_redirect( web.url_for( controller='jobs',
action='user_per_month',
**kwd ) )
@@ -169,11 +175,20 @@
elif operation == "unfinished":
kwd[ 'f-state' ] = 'Unfinished'
return self.specified_date_list_grid( trans, **kwd )
+
@web.expose
def specified_month_all( self, trans, **kwd ):
+ """
+ Queries the DB for all jobs in given month, defaults to current month.
+ """
+ message = ''
+
params = util.Params( kwd )
- message = ''
monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+
+ # In case we don't know which is the monitor user we will query for all jobs
+ monitor_user_id = get_monitor_id( trans, monitor_email )
+
# If specified_date is not received, we'll default to the current month
specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
specified_month = specified_date[ :7 ]
@@ -182,32 +197,43 @@
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
month_label = start_date.strftime( "%B" )
year_label = start_date.strftime( "%Y" )
- q = sa.select( ( sa.func.date( model.Job.table.c.create_time ).label( 'date' ),
- sa.func.sum( sa.case( [ ( model.User.table.c.email == monitor_email, 1 ) ], else_=0 ) ).label( 'monitor_jobs' ),
- sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- whereclause = sa.and_( model.Job.table.c.create_time >= start_date,
- model.Job.table.c.create_time < end_date ),
- from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
- group_by = [ 'date' ],
- order_by = [ sa.desc( 'date' ) ] )
+
+
+ month_jobs = sa.select( ( sa.func.date( model.Job.table.c.create_time ).label( 'date' ),
+ sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
+ whereclause=sa.and_( model.Job.table.c.user_id != monitor_user_id,
+ model.Job.table.c.create_time >= start_date,
+ model.Job.table.c.create_time < end_date ),
+ from_obj=[ model.Job.table ],
+ group_by=[ 'date' ],
+ order_by=[ sa.desc( 'date' ) ] )
+
jobs = []
- for row in q.execute():
+ for row in month_jobs.execute():
jobs.append( ( row.date.strftime( "%A" ),
- row.date,
- row.total_jobs - row.monitor_jobs,
- row.monitor_jobs,
+ row.date.strftime( "%d" ),
row.total_jobs,
- row.date.strftime( "%d" ) ) )
+ row.date
+ ) )
return trans.fill_template( '/webapps/reports/jobs_specified_month_all.mako',
month_label=month_label,
year_label=year_label,
month=month,
jobs=jobs,
+ is_user_jobs_only=monitor_user_id,
message=message )
@web.expose
def specified_month_in_error( self, trans, **kwd ):
+ """
+ Queries the DB for the user jobs in error.
+ """
+ message = ''
params = util.Params( kwd )
- message = ''
+ monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+
+ # In case we don't know which is the monitor user we will query for all jobs instead
+ monitor_user_id = get_monitor_id( trans, monitor_email )
+
# If specified_date is not received, we'll default to the current month
specified_date = kwd.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
specified_month = specified_date[ :7 ]
@@ -216,16 +242,19 @@
end_date = start_date + timedelta( days=calendar.monthrange( year, month )[1] )
month_label = start_date.strftime( "%B" )
year_label = start_date.strftime( "%Y" )
- q = sa.select( ( sa.func.date( model.Job.table.c.create_time ).label( 'date' ),
- sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- whereclause = sa.and_( model.Job.table.c.state == 'error',
- model.Job.table.c.create_time >= start_date,
- model.Job.table.c.create_time < end_date ),
- from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
- group_by = [ 'date' ],
- order_by = [ sa.desc( 'date' ) ] )
+
+ month_jobs_in_error = sa.select( ( sa.func.date( model.Job.table.c.create_time ).label( 'date' ),
+ sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
+ whereclause=sa.and_( model.Job.table.c.user_id != monitor_user_id,
+ model.Job.table.c.state == 'error',
+ model.Job.table.c.create_time >= start_date,
+ model.Job.table.c.create_time < end_date ),
+ from_obj=[ model.Job.table ],
+ group_by=[ 'date' ],
+ order_by=[ sa.desc( 'date' ) ] )
+
jobs = []
- for row in q.execute():
+ for row in month_jobs_in_error.execute():
jobs.append( ( row.date.strftime( "%A" ),
row.date,
row.total_jobs,
@@ -235,62 +264,98 @@
year_label=year_label,
month=month,
jobs=jobs,
- message=message )
+ message=message,
+ is_user_jobs_only=monitor_user_id )
@web.expose
def per_month_all( self, trans, **kwd ):
+ """
+ Queries the DB for all jobs. Avoids monitor jobs.
+ """
+
+ message = ''
params = util.Params( kwd )
- message = ''
monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
- q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
- sa.func.sum( sa.case( [( model.User.table.c.email == monitor_email, 1 )], else_=0 ) ).label( 'monitor_jobs' ),
- sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
- group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
- order_by = [ sa.desc( 'date' ) ] )
+
+ # In case we don't know which is the monitor user we will query for all jobs
+ monitor_user_id = get_monitor_id( trans, monitor_email )
+
+ jobs_by_month = sa.select( ( sa.func.date_trunc( 'month', model.Job.table.c.create_time ).label( 'date' ),
+ sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
+ whereclause=model.Job.table.c.user_id != monitor_user_id,
+ from_obj=[ model.Job.table ],
+ group_by=[ 'date' ],
+ order_by=[ sa.desc( 'date' ) ] )
+
jobs = []
- for row in q.execute():
- jobs.append( ( row.date.strftime( "%Y-%m" ),
- row.total_jobs - row.monitor_jobs,
- row.monitor_jobs,
+ for row in jobs_by_month.execute():
+ jobs.append( (
+ row.date.strftime( "%Y-%m" ),
row.total_jobs,
row.date.strftime( "%B" ),
- row.date.strftime( "%Y" ) ) )
+ row.date.strftime( "%y" )
+ ) )
+
return trans.fill_template( '/webapps/reports/jobs_per_month_all.mako',
jobs=jobs,
+ is_user_jobs_only=monitor_user_id,
message=message )
@web.expose
def per_month_in_error( self, trans, **kwd ):
+ """
+ Queries the DB for user jobs in error. Filters out monitor jobs.
+ """
+
+ message = ''
params = util.Params( kwd )
- message = ''
- q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
- sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- whereclause = model.Job.table.c.state == 'error',
- from_obj = [ model.Job.table ],
- group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
- order_by = [ sa.desc( 'date' ) ] )
+ monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+
+ # In case we don't know which is the monitor user we will query for all jobs
+ monitor_user_id = get_monitor_id( trans, monitor_email )
+
+ jobs_in_error_by_month = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
+ sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
+ whereclause=sa.and_ ( model.Job.table.c.state == 'error',
+ model.Job.table.c.user_id != monitor_user_id ),
+ from_obj=[ model.Job.table ],
+ group_by=[ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
+ order_by=[ sa.desc( 'date' ) ] )
+
jobs = []
- for row in q.execute():
+ for row in jobs_in_error_by_month.execute():
jobs.append( ( row.date.strftime( "%Y-%m" ),
row.total_jobs,
row.date.strftime( "%B" ),
- row.date.strftime( "%Y" ) ) )
+ row.date.strftime( "%y" ) ) )
return trans.fill_template( '/webapps/reports/jobs_per_month_in_error.mako',
jobs=jobs,
- message=message )
+ message=message,
+ is_user_jobs_only=monitor_user_id )
+
@web.expose
def per_user( self, trans, **kwd ):
params = util.Params( kwd )
message = ''
+ monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+
jobs = []
- q = sa.select( ( model.User.table.c.email.label( 'user_email' ),
+ jobs_per_user = sa.select( ( model.User.table.c.email.label( 'user_email' ),
sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- from_obj = [ sa.outerjoin( model.Job.table, model.User.table ) ],
- group_by = [ 'user_email' ],
- order_by = [ sa.desc( 'total_jobs' ), 'user_email' ] )
- for row in q.execute():
- jobs.append( ( row.user_email,
+ from_obj=[ sa.outerjoin( model.Job.table, model.User.table ) ],
+ group_by=[ 'user_email' ],
+ order_by=[ sa.desc( 'total_jobs' ), 'user_email' ] )
+ for row in jobs_per_user.execute():
+ if ( row.user_email == None ):
+ jobs.append ( ( 'Anonymous',
+ row.total_jobs ) )
+ elif ( row.user_email == monitor_email ):
+ continue
+ else:
+ jobs.append( ( row.user_email,
row.total_jobs ) )
- return trans.fill_template( '/webapps/reports/jobs_per_user.mako', jobs=jobs, message=message )
+ return trans.fill_template( '/webapps/reports/jobs_per_user.mako',
+ jobs=jobs,
+ message=message )
+
@web.expose
def user_per_month( self, trans, **kwd ):
params = util.Params( kwd )
@@ -298,13 +363,13 @@
email = util.restore_text( params.get( 'email', '' ) )
q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- whereclause = sa.and_( model.Job.table.c.session_id == model.GalaxySession.table.c.id,
+ whereclause=sa.and_( model.Job.table.c.session_id == model.GalaxySession.table.c.id,
model.GalaxySession.table.c.user_id == model.User.table.c.id,
model.User.table.c.email == email
),
- from_obj = [ sa.join( model.Job.table, model.User.table ) ],
- group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
- order_by = [ sa.desc( 'date' ) ] )
+ from_obj=[ sa.join( model.Job.table, model.User.table ) ],
+ group_by=[ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
+ order_by=[ sa.desc( 'date' ) ] )
jobs = []
for row in q.execute():
jobs.append( ( row.date.strftime( "%Y-%m" ),
@@ -314,34 +379,51 @@
return trans.fill_template( '/webapps/reports/jobs_user_per_month.mako',
email=util.sanitize_text( email ),
jobs=jobs, message=message )
+
@web.expose
def per_tool( self, trans, **kwd ):
+ message = ''
+
params = util.Params( kwd )
- message = ''
+ monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+
+ # In case we don't know which is the monitor user we will query for all jobs
+ monitor_user_id = get_monitor_id( trans, monitor_email )
+
jobs = []
q = sa.select( ( model.Job.table.c.tool_id.label( 'tool_id' ),
sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- from_obj = [ model.Job.table ],
- group_by = [ 'tool_id' ],
- order_by = [ 'tool_id' ] )
+ whereclause=model.Job.table.c.user_id != monitor_user_id,
+ from_obj=[ model.Job.table ],
+ group_by=[ 'tool_id' ],
+ order_by=[ 'tool_id' ] )
for row in q.execute():
jobs.append( ( row.tool_id,
row.total_jobs ) )
return trans.fill_template( '/webapps/reports/jobs_per_tool.mako',
jobs=jobs,
- message=message )
+ message=message,
+ is_user_jobs_only=monitor_user_id )
+
@web.expose
def tool_per_month( self, trans, **kwd ):
+ message = ''
+
params = util.Params( kwd )
- message = ''
+ monitor_email = params.get( 'monitor_email', 'monitor(a)bx.psu.edu' )
+
+ # In case we don't know which is the monitor user we will query for all jobs
+ monitor_user_id = get_monitor_id( trans, monitor_email )
+
tool_id = params.get( 'tool_id', 'Add a column1' )
specified_date = params.get( 'specified_date', datetime.utcnow().strftime( "%Y-%m-%d" ) )
q = sa.select( ( sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ).label( 'date' ),
sa.func.count( model.Job.table.c.id ).label( 'total_jobs' ) ),
- whereclause = model.Job.table.c.tool_id == tool_id,
- from_obj = [ model.Job.table ],
- group_by = [ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
- order_by = [ sa.desc( 'date' ) ] )
+ whereclause=sa.and_( model.Job.table.c.tool_id == tool_id,
+ model.Job.table.c.user_id != monitor_user_id ),
+ from_obj=[ model.Job.table ],
+ group_by=[ sa.func.date_trunc( 'month', sa.func.date( model.Job.table.c.create_time ) ) ],
+ order_by=[ sa.desc( 'date' ) ] )
jobs = []
for row in q.execute():
jobs.append( ( row.date.strftime( "%Y-%m" ),
@@ -352,7 +434,9 @@
specified_date=specified_date,
tool_id=tool_id,
jobs=jobs,
- message=message )
+ message=message,
+ is_user_jobs_only=monitor_user_id )
+
@web.expose
def job_info( self, trans, **kwd ):
params = util.Params( kwd )
@@ -362,49 +446,20 @@
return trans.fill_template( '/webapps/reports/job_info.mako',
job=job,
message=message )
- @web.expose
- def per_domain( self, trans, **kwd ):
- # TODO: rewrite using alchemy
- params = util.Params( kwd )
- message = ''
- engine = model.mapping.metadata.engine
- jobs = []
- s = """
- SELECT
- substr(bar.first_pass_domain, bar.dot_position, 4) AS domain,
- count(job_id) AS total_jobs
- FROM
- (SELECT
- user_email AS user_email,
- first_pass_domain,
- position('.' in first_pass_domain) AS dot_position,
- job_id AS job_id
- FROM
- (SELECT
- email AS user_email,
- substr(email, char_length(email)-3, char_length(email)) AS first_pass_domain,
- job.id AS job_id
- FROM
- job
- LEFT OUTER JOIN galaxy_session ON galaxy_session.id = job.session_id
- LEFT OUTER JOIN galaxy_user ON galaxy_session.user_id = galaxy_user.id
- WHERE
- job.session_id = galaxy_session.id
- AND
- galaxy_session.user_id = galaxy_user.id
- ) AS foo
- ) AS bar
- GROUP BY
- domain
- ORDER BY
- total_jobs DESC
- """
- job_rows = engine.text( s ).execute().fetchall()
- for job in job_rows:
- jobs.append( ( job.domain, job.total_jobs ) )
- return trans.fill_template( '/webapps/reports/jobs_per_domain.mako', jobs=jobs, message=message )
## ---- Utility methods -------------------------------------------------------
def get_job( trans, id ):
return trans.sa_session.query( trans.model.Job ).get( trans.security.decode_id( id ) )
+
+def get_monitor_id( trans, monitor_email ):
+ """
+ A convenience method to obtain the monitor job id.
+ """
+ monitor_user_id = None
+ monitor_row = trans.sa_session.query( trans.model.User.table.c.id ) \
+ .filter( trans.model.User.table.c.email == monitor_email ) \
+ .first()
+ if monitor_row is not None:
+ monitor_user_id = monitor_row[0]
+ return monitor_user_id
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_per_domain.mako
--- a/templates/webapps/reports/jobs_per_domain.mako
+++ /dev/null
@@ -1,35 +0,0 @@
-<%inherit file="/base.mako"/>
-<%namespace file="/message.mako" import="render_msg" />
-
-%if message:
- ${render_msg( message, 'done' )}
-%endif
-
-<div class="toolForm">
- <div class="toolFormBody">
- <h3 align="center">Jobs Per Domain</h3>
- <h4 align="center">This report does not account for unauthenticated users.</h4>
- <table align="center" width="60%" class="colored">
- %if len( jobs ) == 0:
- <tr><td colspan="2">There are no jobs</td></tr>
- %else:
- <tr class="header">
- <td>Domain</td>
- <td>Total Jobs</td>
- </tr>
- <% ctr = 0 %>
- %for job in jobs:
- %if ctr % 2 == 1:
- <tr class="odd_row">
- %else:
- <tr class="tr">
- %endif
- <td>${job[0]}</td>
- <td>${job[1]}</td>
- </tr>
- <% ctr += 1 %>
- %endfor
- %endif
- </table>
- </div>
-</div>
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_per_month_all.mako
--- a/templates/webapps/reports/jobs_per_month_all.mako
+++ b/templates/webapps/reports/jobs_per_month_all.mako
@@ -7,17 +7,19 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">Jobs Per Month</h3>
- <h4 align="center">Click Month to view the number of jobs for each day of that month</h4>
+ <h4 align="center">Jobs Per Month</h4>
+ <h5 align="center">Click Month to view details.</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
- <tr><td colspan="4">There are no jobs</td></tr>
+ <tr><td colspan="4">There are no jobs.</td></tr>
%else:
<tr class="header"><td>Month</td>
- <td>User Jobs</td>
- <td>Monitor Jobs</td>
- <td>Total</td>
+ %if is_user_jobs_only:
+ <td>User Jobs</td>
+ %else:
+ <td>User + Monitor Jobs</td>
+ %endif
</tr><% ctr = 0 %>
%for job in jobs:
@@ -26,10 +28,8 @@
%else:
<tr class="tr">
%endif
- <td><a href="${h.url_for( controller='jobs', action='specified_month_all', specified_date=job[0]+'-01' )}">${job[4]} ${job[5]}</a></td>
+ <td><a href="${h.url_for( controller='jobs', action='specified_month_all', specified_date=job[0]+'-01' )}">${job[2]} ${job[3]}</a></td><td>${job[1]}</td>
- <td>${job[2]}</td>
- <td>${job[3]}</td></tr><% ctr += 1 %>
%endfor
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_per_month_in_error.mako
--- a/templates/webapps/reports/jobs_per_month_in_error.mako
+++ b/templates/webapps/reports/jobs_per_month_in_error.mako
@@ -7,15 +7,19 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">Jobs In Error Per Month</h3>
- <h4 align="center">Click Month to view the number of jobs in error for each day of that month</h4>
+ <h4 align="center">Jobs In Error Per Month</h4>
+ <h5 align="center">Click Month to view details.</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
- <tr><td colspan="2">There are no jobs in the error state</td></tr>
+ <tr><td colspan="2">There are no jobs in the error state.</td></tr>
%else:
<tr class="header"><td>Month</td>
- <td>Jobs In Error</td>
+ %if is_user_jobs_only:
+ <td>User Jobs in Error</td>
+ %else:
+ <td>User + Monitor Jobs in Error</td>
+ %endif
</tr><% ctr = 0 %>
%for job in jobs:
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_per_tool.mako
--- a/templates/webapps/reports/jobs_per_tool.mako
+++ b/templates/webapps/reports/jobs_per_tool.mako
@@ -7,15 +7,19 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">Jobs Per Tool</h3>
- <h4 align="center">Click Tool Id to view jobs per month for that tool</h4>
+ <h4 align="center">Jobs Per Tool</h4>
+ <h5 align="center">Click Tool Id to view details</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
- <tr><td colspan="2">There are no jobs</td></tr>
+ <tr><td colspan="2">There are no jobs.</td></tr>
%else:
<tr class="header"><td>Tool id</td>
- <td>Total Jobs</td>
+ %if is_user_jobs_only:
+ <td>User Jobs</td>
+ %else:
+ <td>User + Monitor Jobs</td>
+ %endif
</tr><% ctr = 0 %>
%for job in jobs:
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_per_user.mako
--- a/templates/webapps/reports/jobs_per_user.mako
+++ b/templates/webapps/reports/jobs_per_user.mako
@@ -7,11 +7,11 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">Jobs Per User</h3>
- <h4 align="center">Click User to view jobs per month for that user</h4>
+ <h4 align="center">Jobs Per User</h4>
+ <h5 align="center">Click User to view details.</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
- <tr><td colspan="2">There are no jobs</td></tr>
+ <tr><td colspan="2">There are no jobs.</td></tr>
%else:
<tr class="header"><td>User</td>
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_specified_month_all.mako
--- a/templates/webapps/reports/jobs_specified_month_all.mako
+++ b/templates/webapps/reports/jobs_specified_month_all.mako
@@ -7,8 +7,8 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">All Jobs for ${month_label} ${year_label}</h3>
- <h4 align="center">Click Total Jobs to see jobs for that day</h4>
+ <h4 align="center">Jobs for ${month_label} ${year_label}</h4>
+ <h5 align="center">Click Jobs to see their details</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
<tr><td colspan="5">There are no jobs for ${month_label} ${year_label}</td></tr>
@@ -16,9 +16,11 @@
<tr class="header"><td>Day</td><td>Date</td>
- <td>User Jobs</td>
- <td>Monitor Jobs</td>
- <td>Total Jobs</td>
+ %if is_user_jobs_only:
+ <td>User Jobs</td>
+ %else:
+ <td>User + Monitor Jobs</td>
+ %endif
</tr><% ctr = 0 %>
%for job in jobs:
@@ -28,10 +30,8 @@
<tr class="tr">
%endif
<td>${job[0]}</td>
- <td>${month_label} ${job[5]}, ${year_label}</td>
- <td>${job[2]}</td>
- <td>${job[3]}</td>
- <td><a href="${h.url_for( controller='jobs', action='specified_date_handler', specified_date=job[1], webapp='reports' )}">${job[4]}</a></td>
+ <td>${month_label} ${job[1]}, ${year_label}</td>
+ <td><a href="${h.url_for( controller='jobs', action='specified_date_handler', specified_date=job[3], webapp='reports' )}">${job[2]}</a></td></tr><% ctr += 1 %>
%endfor
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_specified_month_in_error.mako
--- a/templates/webapps/reports/jobs_specified_month_in_error.mako
+++ b/templates/webapps/reports/jobs_specified_month_in_error.mako
@@ -7,8 +7,8 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">Jobs in Error for ${month_label} ${year_label}</h3>
- <h4 align="center">Click Jobs in Error to view jobs in error for that day</h4>
+ <h4 align="center">Jobs in Error for ${month_label} ${year_label}</h4>
+ <h5 align="center">Click Jobs to see their details</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
<tr><td colspan="3">There are no jobs in the error state for ${month_label} ${year_label}</td></tr>
@@ -16,7 +16,11 @@
<tr class="header"><td>Day</td><td>Date</td>
- <td>Jobs in Error</td>
+ %if is_user_jobs_only:
+ <td>User Jobs in Error</td>
+ %else:
+ <td>User + Monitor Jobs in Error</td>
+ %endif
</tr><% ctr = 0 %>
%for job in jobs:
diff -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 -r 1a868f109ed985b738c709422dbd6cccbc5cdd32 templates/webapps/reports/jobs_tool_per_month.mako
--- a/templates/webapps/reports/jobs_tool_per_month.mako
+++ b/templates/webapps/reports/jobs_tool_per_month.mako
@@ -7,15 +7,19 @@
<div class="toolForm"><div class="toolFormBody">
- <h3 align="center">Jobs per month for tool "${tool_id}"</h3>
- <h4 align="center">Click Total Jobs to see the tool's jobs for that month</h4>
+ <h4 align="center">Jobs per month for tool "${tool_id}"</h4>
+ <h5 align="center">Click Jobs to view details</h5><table align="center" width="60%" class="colored">
%if len( jobs ) == 0:
<tr><td colspan="2">There are no jobs for tool "${tool_id}"</td></tr>
%else:
<tr class="header"><td>Month</td>
- <td>Total Jobs</td>
+ %if is_user_jobs_only:
+ <td>User Jobs</td>
+ %else:
+ <td>User + Monitor Jobs</td>
+ %endif
</tr><% ctr = 0 %>
%for job in jobs:
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/97d020901403/
Changeset: 97d020901403
Branch: stable
User: carlfeberhard
Date: 2013-09-09 17:20:40
Summary: Fix to dbkey select in library upload when 'unspecified' is not in dbkey list
Affected #: 1 file
diff -r 9fe9aa6ac504bc7703ba5d465e68170d79e89905 -r 97d0209014039d0f9aaa7f48a188708de1829786 templates/webapps/galaxy/library/common/common.mako
--- a/templates/webapps/galaxy/library/common/common.mako
+++ b/templates/webapps/galaxy/library/common/common.mako
@@ -275,8 +275,9 @@
# move unspecified to the first option and set as default if not last_used_build
#TODO: remove when we decide on a common dbkey selector widget
unspecified = ('unspecified (?)', '?')
- dbkeys.remove( unspecified )
- dbkeys.insert( 0, unspecified )
+ if unspecified in dbkeys:
+ dbkeys.remove( unspecified )
+ dbkeys.insert( 0, unspecified )
default_selected = last_used_build or '?'
%>
%for dbkey in dbkeys:
https://bitbucket.org/galaxy/galaxy-central/commits/b62b2b4daeac/
Changeset: b62b2b4daeac
User: carlfeberhard
Date: 2013-09-09 17:21:06
Summary: Merge stable
Affected #: 1 file
diff -r 354fb3e262bbf08cf5b77f70da1bb45ee947841c -r b62b2b4daeacc819016d6208078fa1fdd5b467c4 templates/webapps/galaxy/library/common/common.mako
--- a/templates/webapps/galaxy/library/common/common.mako
+++ b/templates/webapps/galaxy/library/common/common.mako
@@ -275,8 +275,9 @@
# move unspecified to the first option and set as default if not last_used_build
#TODO: remove when we decide on a common dbkey selector widget
unspecified = ('unspecified (?)', '?')
- dbkeys.remove( unspecified )
- dbkeys.insert( 0, unspecified )
+ if unspecified in dbkeys:
+ dbkeys.remove( unspecified )
+ dbkeys.insert( 0, unspecified )
default_selected = last_used_build or '?'
%>
%for dbkey in dbkeys:
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: Richard Burhans: Fixed initial installation of virtualenv
by commits-noreply@bitbucket.org 07 Sep '13
by commits-noreply@bitbucket.org 07 Sep '13
07 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/354fb3e262bb/
Changeset: 354fb3e262bb
User: Richard Burhans
Date: 2013-09-07 00:03:51
Summary: Fixed initial installation of virtualenv
Affected #: 1 file
diff -r 8f3110cc7851e67256a6d24d7e41ad65e5a507dd -r 354fb3e262bbf08cf5b77f70da1bb45ee947841c lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -155,12 +155,10 @@
if not os.path.exists( venv_dir ):
with make_tmp_dir() as work_dir:
downloaded_filename = VIRTUALENV_URL.rsplit('/', 1)[-1]
- downloaded_file_path = td_common_util.url_download( work_dir, downloaded_filename, VIRTUALENV_URL )
- if td_common_util.istar( downloaded_file_path ):
- td_common_util.extract_tar( downloaded_file_path, work_dir )
- dir = td_common_util.tar_extraction_directory( work_dir, downloaded_filename )
- else:
- log.error( "Failed to download virtualenv: Downloaded file '%s' is not a tar file", downloaded_filename )
+ try:
+ dir = td_common_util.url_download( work_dir, downloaded_filename, VIRTUALENV_URL )
+ except:
+ log.error( "Failed to download virtualenv: td_common_util.url_download( '%s', '%s', '%s' ) threw an exception", work_dir, downloaded_filename, VIRTUALENV_URL )
return False
full_path_to_dir = os.path.abspath( os.path.join( work_dir, dir ) )
shutil.move( full_path_to_dir, venv_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: dan: Display command-line on dataset info page for admin users.
by commits-noreply@bitbucket.org 07 Sep '13
by commits-noreply@bitbucket.org 07 Sep '13
07 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/8f3110cc7851/
Changeset: 8f3110cc7851
User: dan
Date: 2013-09-06 23:09:58
Summary: Display command-line on dataset info page for admin users.
Affected #: 1 file
diff -r 1a5f25751066598601aef4ad34da4b3bea8deaca -r 8f3110cc7851e67256a6d24d7e41ad65e5a507dd templates/show_params.mako
--- a/templates/show_params.mako
+++ b/templates/show_params.mako
@@ -123,6 +123,9 @@
%if trans.user_is_admin() or trans.app.config.expose_dataset_path:
<tr><td>Full Path:</td><td>${hda.file_name | h}</td></tr>
%endif
+ %if job and job.command_line and trans.user_is_admin():
+ <tr><td>Job Command-Line:</td><td>${ job.command_line | h }</td></tr>
+ %endif
</table><br />
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: Dave Bouvier: Fix tool shed API value mappers.
by commits-noreply@bitbucket.org 07 Sep '13
by commits-noreply@bitbucket.org 07 Sep '13
07 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/1a5f25751066/
Changeset: 1a5f25751066
User: Dave Bouvier
Date: 2013-09-06 23:06:18
Summary: Fix tool shed API value mappers.
Affected #: 3 files
diff -r f82d49deb6d05648d2ab114cff6d689b38806d65 -r 1a5f25751066598601aef4ad34da4b3bea8deaca lib/galaxy/webapps/tool_shed/api/repositories.py
--- a/lib/galaxy/webapps/tool_shed/api/repositories.py
+++ b/lib/galaxy/webapps/tool_shed/api/repositories.py
@@ -14,18 +14,6 @@
log = logging.getLogger( __name__ )
-def default_repository_value_mapper( trans, repository ):
- value_mapper={ 'id' : trans.security.encode_id( repository.id ),
- 'user_id' : trans.security.encode_id( repository.user_id ) }
- return value_mapper
-
-def default_repository_metadata_value_mapper( trans, repository_metadata ):
- value_mapper = { 'id' : trans.security.encode_id( repository_metadata.id ),
- 'repository_id' : trans.security.encode_id( repository_metadata.repository_id ) }
- if repository_metadata.time_last_tested:
- value_mapper[ 'time_last_tested' ] = time_ago( repository_metadata.time_last_tested )
- return value_mapper
-
class RepositoriesController( BaseAPIController ):
"""RESTful controller for interactions with repositories in the Tool Shed."""
@@ -108,12 +96,17 @@
]
}
"""
+ metadata_value_mapper = { 'id' : trans.security.encode_id,
+ 'repository_id' : trans.security.encode_id,
+ 'time_last_tested' : time_ago }
+ repository_value_mapper = { 'id' : trans.security.encode_id,
+ 'user_id' : trans.security.encode_id }
# Example URL: http://localhost:9009/api/repositories/get_repository_revision_install_info…
try:
# Get the repository information.
repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
encoded_repository_id = trans.security.encode_id( repository.id )
- repository_dict = repository.to_dict( view='element', value_mapper=default_repository_value_mapper( trans, repository ) )
+ repository_dict = repository.to_dict( view='element', value_mapper=repository_value_mapper )
repository_dict[ 'url' ] = web.url_for( controller='repositories',
action='show',
id=encoded_repository_id )
@@ -130,7 +123,7 @@
if repository_metadata:
encoded_repository_metadata_id = trans.security.encode_id( repository_metadata.id )
repository_metadata_dict = repository_metadata.to_dict( view='collection',
- value_mapper=default_repository_metadata_value_mapper( trans, repository_metadata ) )
+ value_mapper=metadata_value_mapper )
repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
action='show',
id=encoded_repository_metadata_id )
@@ -155,6 +148,8 @@
GET /api/repositories
Displays a collection (list) of repositories.
"""
+ value_mapper = { 'id' : trans.security.encode_id,
+ 'user_id' : trans.security.encode_id }
# Example URL: http://localhost:9009/api/repositories
repository_dicts = []
deleted = util.string_as_bool( deleted )
@@ -164,7 +159,7 @@
.order_by( trans.app.model.Repository.table.c.name ) \
.all()
for repository in query:
- repository_dict = repository.to_dict( view='collection', value_mapper=default_repository_value_mapper( trans, repository ) )
+ repository_dict = repository.to_dict( view='collection', value_mapper=value_mapper )
repository_dict[ 'url' ] = web.url_for( controller='repositories',
action='show',
id=trans.security.encode_id( repository.id ) )
@@ -184,10 +179,12 @@
:param id: the encoded id of the Repository object
"""
+ value_mapper = { 'id' : trans.security.encode_id,
+ 'user_id' : trans.security.encode_id }
# Example URL: http://localhost:9009/api/repositories/f9cad7b01a472135
try:
repository = suc.get_repository_in_tool_shed( trans, id )
- repository_dict = repository.to_dict( view='element', value_mapper=default_repository_value_mapper( trans, repository ) )
+ repository_dict = repository.to_dict( view='element', value_mapper=value_mapper )
repository_dict[ 'url' ] = web.url_for( controller='repositories',
action='show',
id=trans.security.encode_id( repository.id ) )
diff -r f82d49deb6d05648d2ab114cff6d689b38806d65 -r 1a5f25751066598601aef4ad34da4b3bea8deaca lib/galaxy/webapps/tool_shed/api/repository_revisions.py
--- a/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
+++ b/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
@@ -11,13 +11,6 @@
log = logging.getLogger( __name__ )
-def default_value_mapper( trans, repository_metadata ):
- value_mapper = { 'id' : trans.security.encode_id( repository_metadata.id ),
- 'repository_id' : trans.security.encode_id( repository_metadata.repository_id ) }
- if repository_metadata.time_last_tested:
- value_mapper[ 'time_last_tested' ] = time_ago( repository_metadata.time_last_tested )
- return value_mapper
-
class RepositoryRevisionsController( BaseAPIController ):
"""RESTful controller for interactions with tool shed repository revisions."""
@@ -79,6 +72,9 @@
GET /api/repository_revisions
Displays a collection (list) of repository revisions.
"""
+ value_mapper = { 'id' : trans.security.encode_id,
+ 'repository_id' : trans.security.encode_id,
+ 'time_last_tested' : time_ago }
# Example URL: http://localhost:9009/api/repository_revisions
repository_metadata_dicts = []
# Build up an anded clause list of filters.
@@ -128,7 +124,7 @@
.all()
for repository_metadata in query:
repository_metadata_dict = repository_metadata.to_dict( view='collection',
- value_mapper=default_value_mapper( trans, repository_metadata ) )
+ value_mapper=value_mapper )
repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
action='show',
id=trans.security.encode_id( repository_metadata.id ) )
@@ -148,10 +144,13 @@
:param id: the encoded id of the `RepositoryMetadata` object
"""
+ value_mapper = { 'id' : trans.security.encode_id,
+ 'repository_id' : trans.security.encode_id,
+ 'time_last_tested' : time_ago }
# Example URL: http://localhost:9009/api/repository_revisions/bb125606ff9ea620
try:
repository_metadata = metadata_util.get_repository_metadata_by_id( trans, id )
- repository_metadata_dict = repository_metadata.as_dict( value_mapper=default_value_mapper( trans, repository_metadata ) )
+ repository_metadata_dict = repository_metadata.to_dict( value_mapper=value_mapper )
repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
action='show',
id=trans.security.encode_id( repository_metadata.id ) )
@@ -168,6 +167,7 @@
PUT /api/repository_revisions/{encoded_repository_metadata_id}/{payload}
Updates the value of specified columns of the repository_metadata table based on the key / value pairs in payload.
"""
+ value_mapper = dict( id=trans.security.encode_id, repository_id=trans.security.encode_id, time_last_tested=time_ago )
repository_metadata_id = kwd.get( 'id', None )
try:
repository_metadata = metadata_util.get_repository_metadata_by_id( trans, repository_metadata_id )
@@ -188,7 +188,7 @@
log.error( message, exc_info=True )
trans.response.status = 500
return message
- repository_metadata_dict = repository_metadata.as_dict( value_mapper=default_value_mapper( trans, repository_metadata ) )
+ repository_metadata_dict = repository_metadata.to_dict( value_mapper=value_mapper )
repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
action='show',
id=trans.security.encode_id( repository_metadata.id ) )
diff -r f82d49deb6d05648d2ab114cff6d689b38806d65 -r 1a5f25751066598601aef4ad34da4b3bea8deaca lib/galaxy/webapps/tool_shed/model/__init__.py
--- a/lib/galaxy/webapps/tool_shed/model/__init__.py
+++ b/lib/galaxy/webapps/tool_shed/model/__init__.py
@@ -154,9 +154,6 @@
self.times_downloaded = times_downloaded
self.deprecated = deprecated
- def as_dict( self, value_mapper=None ):
- return self.to_dict( view='element', value_mapper=value_mapper )
-
def can_change_type( self, app ):
# Allow changing the type only if the repository has no contents, has never been installed, or has never been changed from
# the default type.
@@ -233,7 +230,7 @@
class RepositoryMetadata( object, Dictifiable ):
dict_collection_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable', 'has_repository_dependencies', 'includes_datatypes',
- 'includes_tools', 'includes_tool_dependencies', 'includes_tools_for_display_in_tool_panel', 'includes_workflows' )
+ 'includes_tools', 'includes_tool_dependencies', 'includes_tools_for_display_in_tool_panel', 'includes_workflows', 'time_last_tested' )
dict_element_visible_keys = ( 'id', 'repository_id', 'changeset_revision', 'malicious', 'downloadable', 'tools_functionally_correct', 'do_not_test',
'test_install_error', 'time_last_tested', 'tool_test_results', 'has_repository_dependencies', 'includes_datatypes',
'includes_tools', 'includes_tool_dependencies', 'includes_tools_for_display_in_tool_panel', 'includes_workflows' )
@@ -270,9 +267,6 @@
return True
return False
- def as_dict( self, value_mapper=None ):
- return self.to_dict( view='element', value_mapper=value_mapper )
-
class SkipToolTest( object, Dictifiable ):
dict_collection_visible_keys = ( 'id', 'repository_metadata_id', 'initial_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: Dave Bouvier: Set the tool depepndency path for repository installation and testing.
by commits-noreply@bitbucket.org 07 Sep '13
by commits-noreply@bitbucket.org 07 Sep '13
07 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f82d49deb6d0/
Changeset: f82d49deb6d0
User: Dave Bouvier
Date: 2013-09-06 22:53:07
Summary: Set the tool depepndency path for repository installation and testing.
Affected #: 1 file
diff -r f4a839856cfb06c01845cdd96f2893f4b70250bb -r f82d49deb6d05648d2ab114cff6d689b38806d65 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
@@ -567,6 +567,7 @@
if tool_dependency_dir is None:
tool_dependency_dir = tempfile.mkdtemp( dir=galaxy_test_tmp_dir )
os.environ[ 'GALAXY_INSTALL_TEST_TOOL_DEPENDENCY_DIR' ] = tool_dependency_dir
+ os.environ[ 'GALAXY_TOOL_DEPENDENCY_DIR' ] = tool_dependency_dir
if 'GALAXY_INSTALL_TEST_DBURI' in os.environ:
database_connection = os.environ[ 'GALAXY_INSTALL_TEST_DBURI' ]
else:
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: Partial framework support for enhanced tool dependency definitions that enable installation of binaries into specified architectures. More coming soon...
by commits-noreply@bitbucket.org 06 Sep '13
by commits-noreply@bitbucket.org 06 Sep '13
06 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/f4a839856cfb/
Changeset: f4a839856cfb
User: greg
Date: 2013-09-06 15:38:12
Summary: Partial framework support for enhanced tool dependency definitions that enable installation of binaries into specified architectures. More coming soon...
Affected #: 8 files
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb 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
@@ -252,7 +252,7 @@
tool_shed_repository.uninstalled = True
# Remove all installed tool dependencies, but don't touch any repository dependencies..
for tool_dependency in tool_shed_repository.installed_tool_dependencies:
- uninstalled, error_message = tool_dependency_util.remove_tool_dependency( trans, tool_dependency )
+ uninstalled, error_message = tool_dependency_util.remove_tool_dependency( trans.app, tool_dependency )
if error_message:
errors = '%s %s' % ( errors, error_message )
tool_shed_repository.deleted = True
@@ -1559,7 +1559,7 @@
if tool_dependency.can_uninstall:
tool_dependencies_for_uninstallation.append( tool_dependency )
for tool_dependency in tool_dependencies_for_uninstallation:
- uninstalled, error_message = tool_dependency_util.remove_tool_dependency( trans, tool_dependency )
+ uninstalled, error_message = tool_dependency_util.remove_tool_dependency( trans.app, tool_dependency )
if error_message:
errors = True
message = '%s %s' % ( message, error_message )
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -281,8 +281,6 @@
source_dir=os.path.join( action_dict[ 'source_directory' ] ),
destination_dir=os.path.join( action_dict[ 'destination_directory' ] ) )
elif action_type == 'move_file':
- # TODO: Remove this hack that resets current_dir so that the pre-compiled bwa binary can be found.
- # current_dir = '/Users/gvk/workspaces_2008/bwa/bwa-0.5.9'
td_common_util.move_file( current_dir=current_dir,
source=os.path.join( action_dict[ 'source' ] ),
destination_dir=os.path.join( action_dict[ 'destination' ] ) )
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -12,6 +12,7 @@
from tool_shed.util import encoding_util
from tool_shed.util import tool_dependency_util
from tool_shed.util import xml_util
+from tool_shed.galaxy_install.tool_dependencies import td_common_util
from galaxy.model.orm import and_
from galaxy.web import url_for
from galaxy.util import asbool
@@ -106,6 +107,92 @@
text = common_util.tool_shed_get( app, tool_shed_url, url )
return text
+def handle_complex_repository_dependency_for_package( app, elem, package_name, package_version, tool_shed_repository ):
+ tool_dependency = None
+ tool_shed = elem.attrib[ 'toolshed' ]
+ required_repository_name = elem.attrib[ 'name' ]
+ required_repository_owner = elem.attrib[ 'owner' ]
+ default_required_repository_changeset_revision = elem.attrib[ 'changeset_revision' ]
+ required_repository = get_tool_shed_repository_by_tool_shed_name_owner_changeset_revision( app,
+ tool_shed,
+ required_repository_name,
+ required_repository_owner,
+ default_required_repository_changeset_revision )
+ tmp_filename = None
+ if required_repository:
+ required_repository_changeset_revision = required_repository.installed_changeset_revision
+ # Define the installation directory for the required tool dependency package in the required repository.
+ required_repository_package_install_dir = \
+ get_tool_dependency_install_dir( app=app,
+ repository_name=required_repository_name,
+ repository_owner=required_repository_owner,
+ repository_changeset_revision=required_repository_changeset_revision,
+ tool_dependency_type='package',
+ tool_dependency_name=package_name,
+ tool_dependency_version=package_version )
+ # Define the this dependent repository's tool dependency installation directory that will contain the env.sh file with a path to the
+ # required repository's installed tool dependency package.
+ dependent_install_dir = get_tool_dependency_install_dir( app=app,
+ repository_name=tool_shed_repository.name,
+ repository_owner=tool_shed_repository.owner,
+ repository_changeset_revision=tool_shed_repository.installed_changeset_revision,
+ tool_dependency_type='package',
+ tool_dependency_name=package_name,
+ tool_dependency_version=package_version )
+ # Set this dependent repository's tool dependency env.sh file with a path to the required repository's installed tool dependency package.
+ # We can get everything we need from the discovered installed required_repository.
+ if required_repository.status in [ app.model.ToolShedRepository.installation_status.DEACTIVATED,
+ app.model.ToolShedRepository.installation_status.INSTALLED ]:
+ if not os.path.exists( required_repository_package_install_dir ):
+ print 'Missing required tool dependency directory %s' % str( required_repository_package_install_dir )
+ repo_files_dir = required_repository.repo_files_directory( app )
+ tool_dependencies_config = get_absolute_path_to_file_in_repository( repo_files_dir, 'tool_dependencies.xml' )
+ if tool_dependencies_config:
+ config_to_use = tool_dependencies_config
+ else:
+ message = "Unable to locate required tool_dependencies.xml file for revision %s of installed repository %s owned by %s." % \
+ ( str( required_repository.changeset_revision ), str( required_repository.name ), str( required_repository.owner ) )
+ raise Exception( message )
+ else:
+ # Make a call to the tool shed to get the changeset revision to which the current value of required_repository_changeset_revision
+ # should be updated if it's not current.
+ text = get_updated_changeset_revisions_from_tool_shed( app=app,
+ tool_shed_url=tool_shed,
+ name=required_repository_name,
+ owner=required_repository_owner,
+ changeset_revision=required_repository_changeset_revision )
+ if text:
+ updated_changeset_revisions = listify( text )
+ # The list of changeset revisions is in reverse order, so the newest will be first.
+ required_repository_changeset_revision = updated_changeset_revisions[ 0 ]
+ # Make a call to the tool shed to get the required repository's tool_dependencies.xml file.
+ tmp_filename = create_temporary_tool_dependencies_config( app,
+ tool_shed,
+ required_repository_name,
+ required_repository_owner,
+ required_repository_changeset_revision )
+ config_to_use = tmp_filename
+ tool_dependency, actions_dict = populate_actions_dict( app=app,
+ dependent_install_dir=dependent_install_dir,
+ required_install_dir=required_repository_package_install_dir,
+ tool_shed_repository=tool_shed_repository,
+ required_repository=required_repository,
+ package_name=package_name,
+ package_version=package_version,
+ tool_dependencies_config=config_to_use )
+ if tmp_filename:
+ try:
+ os.remove( tmp_filename )
+ except:
+ pass
+ # Install and build the package via fabric.
+ install_and_build_package_via_fabric( app, tool_dependency, actions_dict )
+ else:
+ message = "Unable to locate required tool shed repository named %s owned by %s with revision %s." % \
+ ( str( required_repository_name ), str( required_repository_owner ), str( default_required_repository_changeset_revision ) )
+ raise Exception( message )
+ return tool_dependency
+
def handle_set_environment_entry_for_package( app, install_dir, tool_shed_repository, package_name, package_version, elem, required_repository ):
"""
Populate a list of actions for creating an env.sh file for a dependent repository. The received elem is the <package> tag set associated
@@ -222,88 +309,9 @@
for package_elem in elem:
if package_elem.tag == 'repository':
# We have a complex repository dependency definition.
- tool_shed = package_elem.attrib[ 'toolshed' ]
- required_repository_name = package_elem.attrib[ 'name' ]
- required_repository_owner = package_elem.attrib[ 'owner' ]
- default_required_repository_changeset_revision = package_elem.attrib[ 'changeset_revision' ]
- required_repository = get_tool_shed_repository_by_tool_shed_name_owner_changeset_revision( app,
- tool_shed,
- required_repository_name,
- required_repository_owner,
- default_required_repository_changeset_revision )
- tmp_filename = None
- if required_repository:
- required_repository_changeset_revision = required_repository.installed_changeset_revision
- # Define the installation directory for the required tool dependency package in the required repository.
- required_repository_package_install_dir = \
- get_tool_dependency_install_dir( app=app,
- repository_name=required_repository_name,
- repository_owner=required_repository_owner,
- repository_changeset_revision=required_repository_changeset_revision,
- tool_dependency_type='package',
- tool_dependency_name=package_name,
- tool_dependency_version=package_version )
- # Define the this dependent repository's tool dependency installation directory that will contain the env.sh file with a path to the
- # required repository's installed tool dependency package.
- dependent_install_dir = get_tool_dependency_install_dir( app=app,
- repository_name=tool_shed_repository.name,
- repository_owner=tool_shed_repository.owner,
- repository_changeset_revision=tool_shed_repository.installed_changeset_revision,
- tool_dependency_type='package',
- tool_dependency_name=package_name,
- tool_dependency_version=package_version )
- # Set this dependent repository's tool dependency env.sh file with a path to the required repository's installed tool dependency package.
- # We can get everything we need from the discovered installed required_repository.
- if required_repository.status in [ app.model.ToolShedRepository.installation_status.DEACTIVATED,
- app.model.ToolShedRepository.installation_status.INSTALLED ]:
- if not os.path.exists( required_repository_package_install_dir ):
- print 'Missing required tool dependency directory %s' % str( required_repository_package_install_dir )
- repo_files_dir = required_repository.repo_files_directory( app )
- tool_dependencies_config = get_absolute_path_to_file_in_repository( repo_files_dir, 'tool_dependencies.xml' )
- if tool_dependencies_config:
- config_to_use = tool_dependencies_config
- else:
- message = "Unable to locate required tool_dependencies.xml file for revision %s of installed repository %s owned by %s." % \
- ( str( required_repository.changeset_revision ), str( required_repository.name ), str( required_repository.owner ) )
- raise Exception( message )
- else:
- # Make a call to the tool shed to get the changeset revision to which the current value of required_repository_changeset_revision
- # should be updated if it's not current.
- text = get_updated_changeset_revisions_from_tool_shed( app=app,
- tool_shed_url=tool_shed,
- name=required_repository_name,
- owner=required_repository_owner,
- changeset_revision=required_repository_changeset_revision )
- if text:
- updated_changeset_revisions = listify( text )
- # The list of changeset revisions is in reverse order, so the newest will be first.
- required_repository_changeset_revision = updated_changeset_revisions[ 0 ]
- # Make a call to the tool shed to get the required repository's tool_dependencies.xml file.
- tmp_filename = create_temporary_tool_dependencies_config( app,
- tool_shed,
- required_repository_name,
- required_repository_owner,
- required_repository_changeset_revision )
- config_to_use = tmp_filename
- tool_dependency, actions_dict = populate_actions_dict( app=app,
- dependent_install_dir=dependent_install_dir,
- required_install_dir=required_repository_package_install_dir,
- tool_shed_repository=tool_shed_repository,
- required_repository=required_repository,
- package_name=package_name,
- package_version=package_version,
- tool_dependencies_config=config_to_use )
- if tmp_filename:
- try:
- os.remove( tmp_filename )
- except:
- pass
- # Install and build the package via fabric.
- install_and_build_package_via_fabric( app, tool_dependency, actions_dict )
- else:
- message = "Unable to locate required tool shed repository named %s owned by %s with revision %s." % \
- ( str( required_repository_name ), str( required_repository_owner ), str( default_required_repository_changeset_revision ) )
- raise Exception( message )
+ rd_tool_dependency = handle_complex_repository_dependency_for_package( app, package_elem, package_name, package_version, tool_shed_repository )
+ if rd_tool_dependency and rd_tool_dependency.status == app.model.ToolDependency.installation_status.ERROR:
+ print "Error installing tool dependency for required repository: %s" % str( rd_tool_dependency.error_message )
elif package_elem.tag == 'install':
# <install version="1.0">
# Get the installation directory for tool dependencies that will be installed for the received tool_shed_repository.
@@ -333,114 +341,32 @@
type='package',
status=app.model.ToolDependency.installation_status.INSTALLING,
set_status=True )
- # Get the information that defines the current platform.
+ # Get the information about the current platform in case the tool dependency definition includes tag sets for installing
+ # compiled binaries.
platform_info_dict = tool_dependency_util.get_platform_info_dict()
if package_install_version == '1.0':
- # Handle tool dependency installation using a fabric method included in the Galaxy framework. The first thing we do
- # is check the installation architecture to see if we have a precompiled binary that works on the target system.
+ # Handle tool dependency installation using a fabric method included in the Galaxy framework.
+ actions_elem_tuples = td_common_util.parse_package_elem( package_elem,
+ platform_info_dict=platform_info_dict,
+ include_after_install_actions=True )
+ # At this point we have a list of <actions> elems that are either defined within an <actions_group> tag set with <actions>
+ # sub-elements that contains os and architecture attributes filtered by the platform into which the appropriate compiled
+ # binary will be installed, or not defined within an <actions_group> tag set and not filtered.
binary_installed = False
- actions_elem_tuples = []
- # Build a list of grouped and ungrouped <actions> tagsets to be processed in the order they are defined in the
- # tool_dependencies.xml file.
- for elem in package_elem:
- # Default to not treating actions as grouped.
- grouped = False
- # Skip any element that is not <actions> or <actions_group>. This will also skip comments and <readme> tags.
- if elem.tag not in [ 'actions', 'actions_group' ]:
- continue
- if elem.tag == 'actions':
- # We have an <actions> tag that should not be matched against a specific combination of architecture and operating system.
- grouped = False
- actions_elem_tuples.append( ( grouped, elem ) )
- else:
- # Record the number of <actions> elements, in order to filter out any <action> elements that precede <actions>
- # elements.
- actions_elem_count = len( elem.findall( 'actions' ) )
- # Record the number of <actions> elements that have architecture and os specified, in order to filter out any
- # platform-independent <actions> elements that come before platform-specific <actions> elements. This call to
- # elem.findall is filtered by tags that have both the os and architecture specified.
- # For more details, see http://docs.python.org/2/library/xml.etree.elementtree.html Section 19.7.2.1.
- platform_actions_element_count = len( elem.findall( 'actions[@architecture][@os]' ) )
- platform_actions_elements_processed = 0
- actions_elems_processed = 0
- # We have an actions_group element, and its child <actions> elements should therefore be compared with the current
- # operating system and processor architecture.
- grouped = True
- # The tagsets that will go into the actions_elem_list are those that install a precompiled binary if the
- # architecture and operating system match its defined attributes. If precompiled binary is not installed
- # the first <actions> tag following those that have the os and architecture attributes will be processed
- # in order to install and compile the source.
- actions_elem_list = []
- # The tagsets that will go into the after_install_actions list are <action> tags instead of <actions> tags. These
- # will only be processed if they are at the end of the <actions_group> tagset. See below for details.
- after_install_actions = []
- platform_independent_actions = []
- # Loop through the <actions_group> element and build the actions_elem_list and the after_install_actions list.
- for child_element in elem:
- if child_element.tag == 'actions':
- actions_elems_processed += 1
- system = child_element.get( 'os' )
- architecture = child_element.get( 'architecture' )
- # Skip <actions> tags that have only one of architecture or os specified, in order for the count in
- # platform_actions_elements_processed to remain accurate.
- if ( system and not architecture ) or ( architecture and not system ):
- log.debug( 'Error: Both architecture and os attributes must be specified in an <actions> tag.' )
- continue
- # Since we are inside an <actions_group> tagset, compare it with our current platform information and filter
- # the <actions> tagsets that don't match. Require both the os and architecture attributes to be defined in
- # order to find a match.
- if system and architecture:
- platform_actions_elements_processed += 1
- # If either the os or architecture do not match the platform, this <actions> tag will not be considered
- # a match. Skip it and proceed with checking the next one.
- if platform_info_dict[ 'os' ] != system or platform_info_dict[ 'architecture' ] != architecture:
- continue
- else:
- # <actions> tags without both os and architecture attributes are only allowed to be specified after
- # platform-specific <actions> tags. If we find a platform-independent <actions> tag before all
- # platform-specific <actions> tags have been processed, log a message stating this and skip to the
- # next <actions> tag.
- if platform_actions_elements_processed < platform_actions_element_count:
- message = 'Error: <actions> tags without os and architecture attributes are only allowed '
- message += 'after <actions> tags with os and architecture attributes specified. Skipping '
- message += 'current <actions> tag.'
- log.debug( message )
- continue
- # If we reach this point, it means one of two things: 1) The system and architecture attributes are not
- # defined in this <actions> tag, or 2) The system and architecture attributes are defined, and they are
- # an exact match for the current platform. Append the child element to the list of elements to process.
- actions_elem_list.append( child_element )
- elif child_element.tag == 'action':
- # Any <action> tags within an <actions_group> tagset must come after all <actions> tags.
- if actions_elems_processed == actions_elem_count:
- # If all <actions> elements have been processed, then this <action> element can be appended to the
- # list of actions to execute within this group.
- after_install_actions.append( child_element )
- else:
- # If any <actions> elements remain to be processed, then log a message stating that <action>
- # elements are not allowed to precede any <actions> elements within an <actions_group> tagset.
- message = 'Error: <action> tags are only allowed at the end of an <actions_group> '
- message += 'tagset, after all <actions> tags. '
- message += 'Skipping <%s> element with type %s.' % ( child_element.tag, child_element.get( 'type' ) )
- log.debug( message )
- continue
- if after_install_actions:
- actions_elem_list.extend( after_install_actions )
- actions_elem_tuples.append( ( grouped, actions_elem_list ) )
- # At this point we have a list of <actions> elems that are either defined within an <actions_group> tagset, and filtered by
- # the current platform, or not defined within an <actions_group> tagset, and not filtered.
- for grouped, actions_elems in actions_elem_tuples:
- if grouped:
- # Platform matching is only performed inside <actions_group> tagsets, os and architecture attributes are otherwise ignored.
+ for in_actions_group, actions_elems in actions_elem_tuples:
+ if in_actions_group:
+ # Platform matching is only performed inside <actions_group> tag sets, os and architecture attributes are otherwise
+ # ignored.
for actions_elem in actions_elems:
system = actions_elem.get( 'os' )
architecture = actions_elem.get( 'architecture' )
- # If this <actions> element has the os and architecture attributes defined, then we only want to process
- # until a successful installation is achieved.
+ # If this <actions> element has the os and architecture attributes defined, then we only want to process until a
+ # successful installation is achieved.
if system and architecture:
- # If an <actions> tag has been defined that matches our current platform, and the recipe specified
- # within that <actions> tag has been successfully processed, skip any remaining platform-specific
- # <actions> tags.
+ # If an <actions> tag has been defined that matches our current platform, and the recipe specified within
+ # that <actions> tag has been successfully processed, skip any remaining platform-specific <actions> tags.
+ # We cannot break out of the look here because there may be <action> tags at the end of the <actions_group>
+ # tag set that must be processed.
if binary_installed:
continue
# No platform-specific <actions> recipe has yet resulted in a successful installation.
@@ -451,33 +377,32 @@
actions_elem=actions_elem,
action_elem=None )
sa_session.refresh( tool_dependency )
- if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR:
+ if tool_dependency.status == app.model.ToolDependency.installation_status.INSTALLED:
# If an <actions> tag was found that matches the current platform, and the install_via_fabric method
# did not result in an error state, set binary_installed to True in order to skip any remaining
# platform-specific <actions> tags.
- if not binary_installed:
- binary_installed = True
+ binary_installed = True
else:
- # Otherwise, move on to the next matching <actions> tag, or any defined <actions> tags that do not
- # contain platform-dependent recipes.
- if binary_installed:
- binary_installed = False
- print 'Encountered an error downloading binary for %s version %s: %s' % \
- ( package_name, package_version, tool_dependency.error_message )
+ # Process the next matching <actions> tag, or any defined <actions> tags that do not contain platform
+ # dependent recipes.
+ print 'Error downloading binary for %s version %s: %s' % \
+ ( package_name, package_version, tool_dependency.error_message )
else:
# If no <actions> tags have been defined that match our current platform, or none of the matching
# <actions> tags resulted in a successful tool dependency status, proceed with one and only one
# <actions> tag that is not defined to be platform-specific.
if not binary_installed:
- log.debug( 'Platform-specific recipe failed or not found. Proceeding with platform-independent install recipe.' )
+ print 'Binary installation did not occur, so proceeding with install and compile recipe.'
+ # Make sure to reset for installation if attempt at binary installation resulted in an error.
+ if tool_dependency.status != app.model.ToolDependency.installation_status.NEW:
+ removed, error_message = tool_dependency_util.remove_tool_dependency( app, tool_dependency )
install_via_fabric( app,
tool_dependency,
install_dir,
package_name=package_name,
actions_elem=actions_elem,
action_elem=None )
- break
- # Perform any final actions that have been defined within the actions_group tagset, but outside of
+ # Perform any final actions that have been defined within the actions_group tag set, but outside of
# an <actions> tag, such as a set_environment entry, or a download_file or download_by_url command to
# retrieve extra data for this tool dependency. Only do this if the tool dependency is not in an error
# state, otherwise skip this action.
@@ -490,7 +415,7 @@
action_elem=actions_elem )
else:
# <actions> tags outside of an <actions_group> tag shall not check os or architecture, and if the attributes are
- # defined, they will be ignored. All <actions> tags outside of an <actions_group> tagset shall always be processed.
+ # defined, they will be ignored. All <actions> tags outside of an <actions_group> tag set shall always be processed.
# This is the default and original behavior of the install_package method.
install_via_fabric( app,
tool_dependency,
@@ -519,12 +444,12 @@
def install_via_fabric( app, tool_dependency, install_dir, package_name=None, proprietary_fabfile_path=None, actions_elem=None, action_elem=None, **kwd ):
"""Parse a tool_dependency.xml file's <actions> tag set to gather information for the installation via fabric."""
- sa_session = app.model.context.current
def evaluate_template( text ):
""" Substitute variables defined in XML blocks from dependencies file."""
return Template( text ).safe_substitute( td_common_util.get_env_var_values( install_dir ) )
+ sa_session = app.model.context.current
if not os.path.exists( install_dir ):
os.makedirs( install_dir )
actions_dict = dict( install_dir=install_dir )
@@ -535,7 +460,7 @@
env_var_dicts = []
if actions_elem is not None:
elems = actions_elem
- if elems.get( 'architecture' ) is not None:
+ if elems.get( 'os' ) is not None and elems.get( 'architecture' ) is not None:
is_binary_download = True
else:
is_binary_download = False
@@ -750,7 +675,6 @@
new_value = new_value.split( ';' )[ 0 ]
return new_value
-
def populate_actions_dict( app, dependent_install_dir, required_install_dir, tool_shed_repository, required_repository, package_name, package_version, tool_dependencies_config ):
"""
Populate an actions dictionary that can be sent to fabric_util.install_and_build_package. This method handles the scenario where a tool_dependencies.xml
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/td_common_util.py
@@ -239,6 +239,105 @@
os.makedirs( destination_directory )
shutil.move( source_file, destination_directory )
+def parse_package_elem( package_elem, platform_info_dict=None, include_after_install_actions=True ):
+ """
+ Parse a <package> element within a tool dependency definition and return a list of action tuples. This method is called when setting
+ metadata on a repository that includes a tool_dependencies.xml file or when installing a repository that includes a tool_dependencies.xml
+ file. If installing, platform_info_dict must be a valid dictionary and include_after_install_actions must be True.
+ """
+ # The actions_elem_tuples list contains <actions> tag sets (possibly inside of an <actions_group> tag set) to be processed in the order
+ # they are defined in the tool_dependencies.xml file.
+ actions_elem_tuples = []
+ # The tag sets that will go into the actions_elem_list are those that install a compiled binary if the architecture and operating system
+ # match it's defined attributes. If compiled binary is not installed, the first <actions> tag set [following those that have the os and
+ # architecture attributes] that does not have os or architecture attributes will be processed. This tag set must contain the recipe for
+ # downloading and compiling source.
+ actions_elem_list = []
+ for elem in package_elem:
+ if elem.tag == 'actions':
+ # We have an <actions> tag that should not be matched against a specific combination of architecture and operating system.
+ in_actions_group = False
+ actions_elem_tuples.append( ( in_actions_group, elem ) )
+ elif elem.tag == 'actions_group':
+ # We have an actions_group element, and its child <actions> elements should therefore be compared with the current operating system
+ # and processor architecture.
+ in_actions_group = True
+ # Record the number of <actions> elements so we can filter out any <action> elements that precede <actions> elements.
+ actions_elem_count = len( elem.findall( 'actions' ) )
+ # Record the number of <actions> elements that have architecture and os specified, in order to filter out any platform-independent
+ # <actions> elements that come before platform-specific <actions> elements. This call to elem.findall is filtered by tags that have
+ # both the os and architecture specified. For more details, see http://docs.python.org/2/library/xml.etree.elementtree.html Section
+ # 19.7.2.1.
+ platform_actions_element_count = len( elem.findall( 'actions[@architecture][@os]' ) )
+ platform_actions_elements_processed = 0
+ actions_elems_processed = 0
+ # The tag sets that will go into the after_install_actions list are <action> tags instead of <actions> tags. These will be processed
+ # only if they are at the very end of the <actions_group> tag set (after all <actions> tag sets). See below for details.
+ after_install_actions = []
+ # Inspect the <actions_group> element and build the actions_elem_list and the after_install_actions list.
+ for child_element in elem:
+ if child_element.tag == 'actions':
+ actions_elems_processed += 1
+ system = child_element.get( 'os' )
+ architecture = child_element.get( 'architecture' )
+ # Skip <actions> tags that have only one of architecture or os specified, in order for the count in
+ # platform_actions_elements_processed to remain accurate.
+ if ( system and not architecture ) or ( architecture and not system ):
+ log.debug( 'Error: Both architecture and os attributes must be specified in an <actions> tag.' )
+ continue
+ # Since we are inside an <actions_group> tag set, compare it with our current platform information and filter the <actions>
+ # tag sets that don't match. Require both the os and architecture attributes to be defined in order to find a match.
+ if system and architecture:
+ platform_actions_elements_processed += 1
+ # If either the os or architecture do not match the platform, this <actions> tag will not be considered a match. Skip
+ # it and proceed with checking the next one.
+ if platform_info_dict:
+ if platform_info_dict[ 'os' ] != system or platform_info_dict[ 'architecture' ] != architecture:
+ continue
+ else:
+ # We must not be installing a repository into Galaxy, so determining if we can install a binary is not necessary.
+ continue
+ else:
+ # <actions> tags without both os and architecture attributes are only allowed to be specified after platform-specific
+ # <actions> tags. If we find a platform-independent <actions> tag before all platform-specific <actions> tags have been
+ # processed.
+ if platform_actions_elements_processed < platform_actions_element_count:
+ message = 'Error: <actions> tags without os and architecture attributes are only allowed after all <actions> tags with '
+ message += 'os and architecture attributes have been defined. Skipping the <actions> tag set with no os or architecture '
+ message += 'attributes that has been defined between two <actions> tag sets that have these attributes defined. '
+ log.debug( message )
+ continue
+ # If we reach this point, it means one of two things: 1) The system and architecture attributes are not defined in this
+ # <actions> tag, or 2) The system and architecture attributes are defined, and they are an exact match for the current
+ # platform. Append the child element to the list of elements to process.
+ actions_elem_list.append( child_element )
+ elif child_element.tag == 'action':
+ # Any <action> tags within an <actions_group> tag set must come after all <actions> tags.
+ if actions_elems_processed == actions_elem_count:
+ # If all <actions> elements have been processed, then this <action> element can be appended to the list of actions to
+ # execute within this group.
+ after_install_actions.append( child_element )
+ else:
+ # If any <actions> elements remain to be processed, then log a message stating that <action> elements are not allowed
+ # to precede any <actions> elements within an <actions_group> tag set.
+ message = 'Error: <action> tags are only allowed at the end of an <actions_group> tag set after all <actions> tags. '
+ message += 'Skipping <%s> element with type %s.' % ( child_element.tag, child_element.get( 'type' ) )
+ log.debug( message )
+ continue
+ if platform_info_dict is None and not include_after_install_actions:
+ # We must be setting metadata on a repository.
+ actions_elem_tuples.append( ( in_actions_group, actions_elem_list[ 0 ] ) )
+ elif platform_info_dict is not None and include_after_install_actions:
+ # We must be installing a repository.
+ if after_install_actions:
+ actions_elem_list.extend( after_install_actions )
+ actions_elem_tuples.append( ( in_actions_group, actions_elem_list ) )
+ else:
+ # Skip any element that is not <actions> or <actions_group> - this will skip comments, <repository> tags and <readme> tags.
+ in_actions_group = False
+ continue
+ return actions_elem_tuples
+
def tar_extraction_directory( file_path, file_name ):
"""Try to return the correct extraction directory."""
file_name = file_name.strip()
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/util/commit_util.py
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -133,6 +133,24 @@
bzipped_file.close()
shutil.move( uncompressed, uploaded_file_name )
+def handle_complex_repository_dependency_elem( trans, elem, sub_elem_index, sub_elem, sub_elem_altered, altered, unpopulate=False ):
+ """
+ Populate or unpopulate the toolshed and changeset_revision attributes of a <repository> tag that defines a complex repository
+ dependency.
+ """
+ # The received sub_elem looks something like the following:
+ # <repository name="package_eigen_2_0" owner="test" prior_installation_required="True" />
+ revised, repository_elem, error_message = handle_repository_dependency_elem( trans, sub_elem, unpopulate=unpopulate )
+ if error_message:
+ exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
+ raise Exception( exception_message )
+ if revised:
+ elem[ sub_elem_index ] = repository_elem
+ sub_elem_altered = True
+ if not altered:
+ altered = True
+ return altered, sub_elem_altered, elem
+
def handle_directory_changes( trans, repository, full_path, filenames_in_archive, remove_repo_files_not_in_tar, new_repo_alert, commit_message,
undesirable_dirs_removed, undesirable_files_removed ):
repo_dir = repository.repo_path( trans.app )
@@ -300,7 +318,30 @@
error_message = 'Unable to locate repository with name %s and owner %s. ' % ( str( name ), str( owner ) )
return revised, elem, error_message
+def handle_set_environment_for_install( trans, package_altered, altered, actions_elem, action_index, action_elem, unpopulate=False ):
+ # <action type="set_environment_for_install">
+ # <repository name="package_eigen_2_0" owner="test" changeset_revision="09eb05087cd0">
+ # <package name="eigen" version="2.0.17" />
+ # </repository>
+ # </action>
+ for repo_index, repo_elem in enumerate( action_elem ):
+ revised, repository_elem, error_message = handle_repository_dependency_elem( trans, repo_elem, unpopulate=unpopulate )
+ if error_message:
+ exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
+ raise Exception( exception_message )
+ if revised:
+ action_elem[ repo_index ] = repository_elem
+ package_altered = True
+ if not altered:
+ altered = True
+ if package_altered:
+ actions_elem[ action_index ] = action_elem
+ return package_altered, altered, actions_elem
+
def handle_tool_dependencies_definition( trans, tool_dependencies_config, unpopulate=False ):
+ """
+ Populate or unpopulate the tooshed and changeset_revision attributes of each <repository> tag defined within a tool_dependencies.xml file.
+ """
altered = False
# Make sure we're looking at a valid tool_dependencies.xml file.
tree, error_message = xml_util.parse_xml( tool_dependencies_config )
@@ -308,51 +349,88 @@
return False, None
root = tree.getroot()
if root.tag == 'tool_dependency':
+ package_altered = False
for root_index, root_elem in enumerate( root ):
# <package name="eigen" version="2.0.17">
+ package_altered = False
if root_elem.tag == 'package':
- package_altered = False
for package_index, package_elem in enumerate( root_elem ):
if package_elem.tag == 'repository':
- # <repository name="package_eigen_2_0" owner="test" changeset_revision="09eb05087cd0" prior_installation_required="True" />
- revised, repository_elem, error_message = handle_repository_dependency_elem( trans, package_elem, unpopulate=unpopulate )
- if error_message:
- exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
- raise Exception( exception_message )
- if revised:
- root_elem[ package_index ] = repository_elem
- package_altered = True
- if not altered:
- altered = True
+ # We have a complex repository dependency.
+ altered, package_altered, root_elem = handle_complex_repository_dependency_elem( trans,
+ root_elem,
+ package_index,
+ package_elem,
+ package_altered,
+ altered,
+ unpopulate=unpopulate )
elif package_elem.tag == 'install':
# <install version="1.0">
for actions_index, actions_elem in enumerate( package_elem ):
- for action_index, action_elem in enumerate( actions_elem ):
- action_type = action_elem.get( 'type' )
- if action_type == 'set_environment_for_install':
- # <action type="set_environment_for_install">
- # <repository name="package_eigen_2_0" owner="test" changeset_revision="09eb05087cd0">
- # <package name="eigen" version="2.0.17" />
- # </repository>
- # </action>
- for repo_index, repo_elem in enumerate( action_elem ):
- revised, repository_elem, error_message = handle_repository_dependency_elem( trans, repo_elem, unpopulate=unpopulate )
- if error_message:
- exception_message = 'The tool_dependencies.xml file contains an invalid <repository> tag. %s' % error_message
- raise Exception( exception_message )
- if revised:
- action_elem[ repo_index ] = repository_elem
- package_altered = True
- if not altered:
- altered = True
- if package_altered:
- actions_elem[ action_index ] = action_elem
+ if actions_elem.tag == 'actions_group':
+ # Inspect all entries in the <actions_group> tag set, skipping <actions> tag sets that define os and architecture
+ # attributes. We want to inspect only the last <actions> tag set contained within the <actions_group> tag set to
+ # see if a complex repository dependency is defined.
+ for actions_group_index, actions_group_elem in enumerate( actions_elem ):
+ if actions_group_elem.tag == 'actions':
+ # Skip all actions tags that include os or architecture attributes.
+ system = actions_group_elem.get( 'os' )
+ architecture = actions_group_elem.get( 'architecture' )
+ if system or architecture:
+ continue
+ # ...
+ # <actions>
+ # <package name="libgtextutils" version="0.6">
+ # <repository name="package_libgtextutils_0_6" owner="test" prior_installation_required="True" />
+ # </package>
+ # ...
+ for last_actions_index, last_actions_elem in enumerate( actions_group_elem ):
+ last_actions_package_altered = False
+ if last_actions_elem.tag == 'package':
+ for last_actions_elem_package_index, last_actions_elem_package_elem in enumerate( last_actions_elem ):
+ if last_actions_elem_package_elem.tag == 'repository':
+ # We have a complex repository dependency.
+ altered, last_actions_package_altered, last_actions_elem = \
+ handle_complex_repository_dependency_elem( trans,
+ last_actions_elem,
+ last_actions_elem_package_index,
+ last_actions_elem_package_elem,
+ last_actions_package_altered,
+ altered,
+ unpopulate=unpopulate )
+ if last_actions_package_altered:
+ last_actions_elem[ last_actions_elem_package_index ] = last_actions_elem_package_elem
+ actions_group_elem[ last_actions_index ] = last_actions_elem
+ else:
+ last_actions_elem_action_type = last_actions_elem.get( 'type' )
+ if last_actions_elem_action_type == 'set_environment_for_install':
+ last_actions_package_altered, altered, last_actions_elem = \
+ handle_set_environment_for_install( trans,
+ last_actions_package_altered,
+ altered,
+ actions_group_elem,
+ last_actions_index,
+ last_actions_elem,
+ unpopulate=unpopulate )
+ elif actions_elem.tag == 'actions':
+ # We are not in an <actions_group> tag set, so we must be in an <actions> tag set.
+ for action_index, action_elem in enumerate( actions_elem ):
+
+ action_type = action_elem.get( 'type' )
+ if action_type == 'set_environment_for_install':
+ package_altered, altered, actions_elem = handle_set_environment_for_install( trans,
+ package_altered,
+ altered,
+ actions_elem,
+ action_index,
+ action_elem,
+ unpopulate=unpopulate )
if package_altered:
package_elem[ actions_index ] = actions_elem
- if package_altered:
- root_elem[ package_index ] = package_elem
- if package_altered:
- root[ root_index ] = root_elem
+ if package_altered:
+ root_elem[ package_index ] = package_elem
+ if package_altered:
+ root[ root_index ] = root_elem
return altered, root
return False, None
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -242,9 +242,8 @@
def get_installed_and_missing_tool_dependencies_for_new_install( trans, all_tool_dependencies ):
"""Return the lists of installed tool dependencies and missing tool dependencies for a set of repositories being installed into Galaxy."""
- # FIXME: this method currently populates and returns only missing tool dependencies since tool dependencies defined for complex repository dependency
- # relationships is not currently supported. This method should be enhanced to search for installed tool dependencies defined as complex repository
- # dependency relationships when that feature is implemented.
+ # FIXME: confirm that this method currently populates and returns only missing tool dependencies. If so, this method should be enhanced to search for
+ # installed tool dependencies defined as complex repository dependency relationships.
if all_tool_dependencies:
tool_dependencies = {}
missing_tool_dependencies = {}
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/util/metadata_util.py
--- a/lib/tool_shed/util/metadata_util.py
+++ b/lib/tool_shed/util/metadata_util.py
@@ -751,6 +751,32 @@
# dependency definition will be set as invalid. This is currently the only case where a tool dependency definition is
# considered invalid.
repository_dependency_tup, repository_dependency_is_valid, error_message = handle_repository_elem( app=app, repository_elem=sub_elem )
+ elif sub_elem.tag == 'install':
+ package_install_version = sub_elem.get( 'version', '1.0' )
+ if package_install_version == '1.0':
+ # Complex repository dependencies can be defined within the last <actions> tag set contained in an <actions_group> tag set.
+ # Comments, <repository> tag sets and <readme> tag sets will be skipped in td_common_util.parse_package_elem().
+ actions_elem_tuples = td_common_util.parse_package_elem( sub_elem, platform_info_dict=None, include_after_install_actions=False )
+ if actions_elem_tuples:
+ # We now have a list of a single tuple that looks something like: [(True, <Element 'actions' at 0x104017850>)]
+ actions_elem_tuple = actions_elem_tuples[ 0 ]
+ in_actions_group, actions_elem = actions_elem_tuple
+ if in_actions_group:
+ # Since we're inside an <actions_group> tag set, inspect the actions_elem to see if a complex repository dependency
+ # is defined.
+ for action_elem in actions_elem:
+ if action_elem.tag == 'package':
+ # <package name="libgtextutils" version="0.6">
+ # <repository name="package_libgtextutils_0_6" owner="test" prior_installation_required="True" />
+ # </package>
+ ae_package_name = action_elem.get( 'name', None )
+ ae_package_version = action_elem.get( 'version', None )
+ if ae_package_name and ae_package_version:
+ for sub_action_elem in action_elem:
+ if sub_action_elem.tag == 'repository':
+ # We have a complex repository dependency.
+ repository_dependency_tup, repository_dependency_is_valid, error_message = \
+ handle_repository_elem( app=app, repository_elem=sub_action_elem )
if requirements_dict:
dependency_key = '%s/%s' % ( package_name, package_version )
if repository_dependency_is_valid:
diff -r 53f51406718dbe21dc1deec10749e9dadd0ee77c -r f4a839856cfb06c01845cdd96f2893f4b70250bb lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -365,14 +365,15 @@
missing_tool_dependencies = repository_missing_tool_dependencies
return installed_tool_dependencies, missing_tool_dependencies
-def remove_tool_dependency( trans, tool_dependency ):
- dependency_install_dir = tool_dependency.installation_directory( trans.app )
+def remove_tool_dependency( app, tool_dependency ):
+ sa_session = app.model.context.current
+ dependency_install_dir = tool_dependency.installation_directory( app )
removed, error_message = remove_tool_dependency_installation_directory( dependency_install_dir )
if removed:
- tool_dependency.status = trans.model.ToolDependency.installation_status.UNINSTALLED
+ tool_dependency.status = app.model.ToolDependency.installation_status.UNINSTALLED
tool_dependency.error_message = None
- trans.sa_session.add( tool_dependency )
- trans.sa_session.flush()
+ sa_session.add( tool_dependency )
+ sa_session.flush()
return removed, error_message
def remove_tool_dependency_installation_directory( dependency_install_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: Dave Bouvier: Display the clone URL on an empty repository's view and manage pages for any user with write access.
by commits-noreply@bitbucket.org 06 Sep '13
by commits-noreply@bitbucket.org 06 Sep '13
06 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/53f51406718d/
Changeset: 53f51406718d
User: Dave Bouvier
Date: 2013-09-05 23:04:41
Summary: Display the clone URL on an empty repository's view and manage pages for any user with write access.
Affected #: 2 files
diff -r ea75f5629c38a529cf70c6578a74dac7a8073880 -r 53f51406718dbe21dc1deec10749e9dadd0ee77c templates/webapps/tool_shed/repository/manage_repository.mako
--- a/templates/webapps/tool_shed/repository/manage_repository.mako
+++ b/templates/webapps/tool_shed/repository/manage_repository.mako
@@ -133,7 +133,7 @@
<label>${sharable_link_label}</label>
${render_sharable_str( repository, changeset_revision=sharable_link_changeset_revision )}
</div>
- %if can_download:
+ %if can_download or can_push:
<div class="form-row"><label>Clone this repository:</label>
${render_clone_str( repository )}
diff -r ea75f5629c38a529cf70c6578a74dac7a8073880 -r 53f51406718dbe21dc1deec10749e9dadd0ee77c templates/webapps/tool_shed/repository/view_repository.mako
--- a/templates/webapps/tool_shed/repository/view_repository.mako
+++ b/templates/webapps/tool_shed/repository/view_repository.mako
@@ -86,7 +86,7 @@
<label>${sharable_link_label}</label>
${render_sharable_str( repository, changeset_revision=sharable_link_changeset_revision )}
</div>
- %if can_download:
+ %if can_download or can_push:
<div class="form-row"><label>Clone this repository:</label>
${render_clone_str( 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
commit/galaxy-central: natefoo: Add the now-required 'config' param to the DistributedObjectStore's call to the superclass __jnit__().
by commits-noreply@bitbucket.org 06 Sep '13
by commits-noreply@bitbucket.org 06 Sep '13
06 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/ea75f5629c38/
Changeset: ea75f5629c38
User: natefoo
Date: 2013-09-05 21:28:44
Summary: Add the now-required 'config' param to the DistributedObjectStore's call to the superclass __jnit__().
Affected #: 1 file
diff -r 559602ed992f131caa530aa468e86b3cd97c1bc5 -r ea75f5629c38a529cf70c6578a74dac7a8073880 lib/galaxy/objectstore/__init__.py
--- a/lib/galaxy/objectstore/__init__.py
+++ b/lib/galaxy/objectstore/__init__.py
@@ -372,7 +372,7 @@
"""
def __init__(self, config, fsmon=False):
- super(DistributedObjectStore, self).__init__()
+ super(DistributedObjectStore, self).__init__(config)
self.distributed_config = config.distributed_object_store_config_file
assert self.distributed_config is not None, "distributed object store ('object_store = distributed') " \
"requires a config file, please set one in " \
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: Correctly treat VCF format and genotyping fields as optional.
by commits-noreply@bitbucket.org 05 Sep '13
by commits-noreply@bitbucket.org 05 Sep '13
05 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/559602ed992f/
Changeset: 559602ed992f
User: jgoecks
Date: 2013-09-05 20:19:50
Summary: Correctly treat VCF format and genotyping fields as optional.
Affected #: 1 file
diff -r 087a792e45bcfb48d0717f6947520b44d9b56d11 -r 559602ed992f131caa530aa468e86b3cd97c1bc5 lib/galaxy/visualization/data_providers/genome.py
--- a/lib/galaxy/visualization/data_providers/genome.py
+++ b/lib/galaxy/visualization/data_providers/genome.py
@@ -670,9 +670,15 @@
# Split line and aggregate data.
feature = line.split()
pos, c_id, ref, alt, qual, c_filter, info = feature[ 1:8 ]
- format = feature[ 8 ]
- samples_data = feature [ 9: ]
- # VCF is 1-based.
+
+ # Format and samples data are optional.
+ format = None
+ samples_data = []
+ if len( feature ) > 8:
+ format = feature[ 8 ]
+ samples_data = feature [ 9: ]
+
+ # VCF is 1-based but provided position is 0-based.
pos = int( pos ) - 1
# FIXME: OK to skip?
@@ -680,11 +686,11 @@
count -= 1
continue
- # Count number of samples matching each allele.
+ # Set up array to track allele counts.
allele_counts = [ 0 for i in range ( alt.count( ',' ) + 1 ) ]
+ sample_gts = []
- # Process and pack sample genotype.
- sample_gts = []
+ # Process and pack samples' genotype and count alleles across samples.
alleles_seen = {}
has_alleles = False
@@ -711,7 +717,7 @@
genotype = ''
sample_gts.append( genotype )
-
+
# Add locus data.
locus_data = [
-1,
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: JS Localization: fix replicate quotameter code in galaxy.masthead.mako; add mako localization function file
by commits-noreply@bitbucket.org 05 Sep '13
by commits-noreply@bitbucket.org 05 Sep '13
05 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/087a792e45bc/
Changeset: 087a792e45bc
User: carlfeberhard
Date: 2013-09-05 19:49:46
Summary: JS Localization: fix replicate quotameter code in galaxy.masthead.mako; add mako localization function file
Affected #: 2 files
diff -r 4e86427c63f63b1d9a3278ea0adfbe0e89906c83 -r 087a792e45bcfb48d0717f6947520b44d9b56d11 templates/webapps/galaxy/galaxy.masthead.mako
--- a/templates/webapps/galaxy/galaxy.masthead.mako
+++ b/templates/webapps/galaxy/galaxy.masthead.mako
@@ -230,7 +230,7 @@
<!-- quota meter -->
${h.templates( "helpers-common-templates", "template-user-quotaMeter-quota", "template-user-quotaMeter-usage" )}
- ${h.js( "mvc/base-mvc", "mvc/user/user-model", "mvc/user/user-quotameter" )}
+ ${h.js( "mvc/base-mvc", "utils/localization", "mvc/user/user-model", "mvc/user/user-quotameter" )}
<script type="text/javascript">
// start a Galaxy namespace for objects created
diff -r 4e86427c63f63b1d9a3278ea0adfbe0e89906c83 -r 087a792e45bcfb48d0717f6947520b44d9b56d11 templates/webapps/galaxy/utils/localization.mako
--- /dev/null
+++ b/templates/webapps/galaxy/utils/localization.mako
@@ -0,0 +1,12 @@
+<%def name="localize_js_strings( strings_to_localize )">
+##PRECONDITION: static/scripts/utils/localization.js should be loaded first
+## adds localized versions of strings to the JS GalaxyLocalization for use in later JS
+## where strings_to_localize is a list of strings to localize
+<script type="text/javascript">
+ ## strings need to be mako rendered in order to use the '_' gettext helper for localization
+ ## these are then cached in the js object
+ GalaxyLocalization.setLocalizedString(
+ ${ h.to_json_string( dict([ ( string, _(string) ) for string in strings_to_localize ]) ) }
+ );
+</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/4f5276b1cfaf/
Changeset: 4f5276b1cfaf
User: carlfeberhard
Date: 2013-09-05 18:09:06
Summary: JS Localization: move out of base-mvc and history.mako into separate files
Affected #: 8 files
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d static/scripts/mvc/base-mvc.js
--- a/static/scripts/mvc/base-mvc.js
+++ b/static/scripts/mvc/base-mvc.js
@@ -89,84 +89,6 @@
};
-// =============================================================================
-/** @class string localizer (and global short form alias)
- *
- * @example
- * // set with either:
- * GalaxyLocalization.setLocalizedString( original, localized )
- * GalaxyLocalization.setLocalizedString({ original1 : localized1, original2 : localized2 })
- * // get with either:
- * GalaxyLocalization.localize( string )
- * _l( string )
- *
- * @constructs
- */
-//TODO: move to Galaxy.Localization (maybe galaxy.base.js)
-var GalaxyLocalization = jQuery.extend( {}, {
- /** shortened, alias reference to GalaxyLocalization.localize */
- ALIAS_NAME : '_l',
- /** map of available localized strings (english -> localized) */
- localizedStrings : {},
-
- /** Set a single English string -> localized string association, or set an entire map of those associations
- * @param {String or Object} str_or_obj english (key) string or a map of english -> localized strings
- * @param {String} localized string if str_or_obj was a string
- */
- setLocalizedString : function( str_or_obj, localizedString ){
- //console.debug( this + '.setLocalizedString:', str_or_obj, localizedString );
- var self = this;
-
- // DRY non-duplicate assignment function
- var setStringIfNotDuplicate = function( original, localized ){
- // do not set if identical - strcmp expensive but should only happen once per page per word
- if( original !== localized ){
- self.localizedStrings[ original ] = localized;
- }
- };
-
- if( jQuery.type( str_or_obj ) === "string" ){
- setStringIfNotDuplicate( str_or_obj, localizedString );
-
- } else if( jQuery.type( str_or_obj ) === "object" ){
- jQuery.each( str_or_obj, function( key, val ){
- //console.debug( 'key=>val', key, '=>', val );
- // could recurse here but no reason
- setStringIfNotDuplicate( key, val );
- });
-
- } else {
- throw( 'Localization.setLocalizedString needs either a string or object as the first argument,' +
- ' given: ' + str_or_obj );
- }
- },
-
- /** Attempt to get a localized string for strToLocalize. If not found, return the original strToLocalize.
- * @param {String} strToLocalize the string to localize
- * @returns either the localized string if found or strToLocalize if not found
- */
- localize : function( strToLocalize ){
- //console.debug( this + '.localize:', strToLocalize );
-
- //// uncomment this section to cache strings that need to be localized but haven't been
- //if( !_.has( this.localizedStrings, strToLocalize ) ){
- // //console.debug( 'localization NOT found:', strToLocalize );
- // if( !this.nonLocalized ){ this.nonLocalized = {}; }
- // this.nonLocalized[ strToLocalize ] = false;
- //}
-
- // return the localized version if it's there, the strToLocalize if not
- return this.localizedStrings[ strToLocalize ] || strToLocalize;
- },
-
- /** String representation. */
- toString : function(){ return 'GalaxyLocalization'; }
-});
-
-// global localization alias
-window[ GalaxyLocalization.ALIAS_NAME ] = function( str ){ return GalaxyLocalization.localize( str ); };
-
-
//==============================================================================
/**
* @class persistant storage adapter.
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d static/scripts/packed/mvc/base-mvc.js
--- a/static/scripts/packed/mvc/base-mvc.js
+++ b/static/scripts/packed/mvc/base-mvc.js
@@ -1,1 +1,1 @@
-var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){var a=this.logger.log;if(typeof this.logger.log==="object"){a=Function.prototype.bind.call(this.logger.log,this.logger)}return a.apply(this.logger,arguments)}return undefined}};var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(a){return this.localizedStrings[a]||a},toString:function(){return"GalaxyLocalization"}});window[GalaxyLocalization.ALIAS_NAME]=function(a){return GalaxyLocalization.localize(a)};var PersistantStorage=function(j,g){if(!j){throw ("PersistantStorage needs storageKey argument")}g=g||{};var h=sessionStorage,c=function i(l){return JSON.parse(this.getItem(l))},b=function e(l,m){return this.setItem(l,JSON.stringify(m))},d=function f(l){return this.removeItem(l)};function a(m,l){m=m||{};l=l||null;return{get:function(n){if(n===undefined){return m}else{if(m.hasOwnProperty(n)){return(jQuery.type(m[n])==="object")?(new a(m[n],this)):(m[n])}}return undefined},set:function(n,o){m[n]=o;this._save();return this},deleteKey:function(n){delete m[n];this._save();return this},_save:function(){return l._save()},toString:function(){return("StorageRecursionHelper("+m+")")}}}var k={};data=c.call(h,j);if(data===null||data===undefined){data=jQuery.extend(true,{},g);b.call(h,j,data)}k=new a(data);jQuery.extend(k,{_save:function(l){return b.call(h,j,k.get())},destroy:function(){return d.call(h,j)},toString:function(){return"PersistantStorage("+j+")"}});return k};
\ No newline at end of file
+var BaseModel=Backbone.RelationalModel.extend({defaults:{name:null,hidden:false},show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}});var BaseView=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){if(this.model.attributes.hidden){this.$el.hide()}else{this.$el.show()}}});var LoggableMixin={logger:null,log:function(){if(this.logger){var a=this.logger.log;if(typeof this.logger.log==="object"){a=Function.prototype.bind.call(this.logger.log,this.logger)}return a.apply(this.logger,arguments)}return undefined}};var PersistantStorage=function(j,g){if(!j){throw ("PersistantStorage needs storageKey argument")}g=g||{};var h=sessionStorage,c=function i(l){return JSON.parse(this.getItem(l))},b=function e(l,m){return this.setItem(l,JSON.stringify(m))},d=function f(l){return this.removeItem(l)};function a(m,l){m=m||{};l=l||null;return{get:function(n){if(n===undefined){return m}else{if(m.hasOwnProperty(n)){return(jQuery.type(m[n])==="object")?(new a(m[n],this)):(m[n])}}return undefined},set:function(n,o){m[n]=o;this._save();return this},deleteKey:function(n){delete m[n];this._save();return this},_save:function(){return l._save()},toString:function(){return("StorageRecursionHelper("+m+")")}}}var k={};data=c.call(h,j);if(data===null||data===undefined){data=jQuery.extend(true,{},g);b.call(h,j,data)}k=new a(data);jQuery.extend(k,{_save:function(l){return b.call(h,j,k.get())},destroy:function(){return d.call(h,j)},toString:function(){return"PersistantStorage("+j+")"}});return k};
\ No newline at end of file
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d static/scripts/packed/mvc/tools.js
--- a/static/scripts/packed/mvc/tools.js
+++ b/static/scripts/packed/mvc/tools.js
@@ -1,1 +1,1 @@
-define(["libs/underscore","viz/trackster/util","mvc/data","libs/backbone/backbone-relational"],function(x,a,y){var g={hidden:false,show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},is_visible:function(){return !this.attributes.hidden}};var e=Backbone.RelationalModel.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},subModelTypes:{integer:"IntegerToolParameter","float":"FloatToolParameter",data:"DataToolParameter",select:"SelectToolParameter"},initialize:function(){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new e(this.toJSON())},set_value:function(z){this.set("value",z||"")}});var o={};Backbone.Relational.store.addModelScope(o);var j=o.DataToolParameter=e.extend({});var d=o.IntegerToolParameter=e.extend({set_value:function(z){this.set("value",parseInt(z,10))},get_samples:function(){return d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}});var f=o.FloatToolParameter=d.extend({set_value:function(z){this.set("value",parseFloat(z))}});var t=o.SelectToolParameter=e.extend({get_samples:function(){return x.map(this.get("options"),function(z){return z[0]})}});var i=Backbone.RelationalModel.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[],outputs:[]},relations:[{type:Backbone.HasMany,key:"inputs",relatedModel:e}],urlRoot:galaxy_config.root+"api/tools",remove_inputs:function(A){var z=this,B=z.get("inputs").filter(function(C){return(A.indexOf(C.get("type"))!==-1)});z.get("inputs").remove(B)},copy:function(A){var B=new i(this.toJSON());if(A){var z=new Backbone.Collection();B.get("inputs").each(function(C){if(C.get_samples()){z.push(C)}});B.set("inputs",z)}return B},apply_search_results:function(z){(x.indexOf(z,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(z,A){this.get("inputs").find(function(B){return B.get("name")===z}).set("value",A)},set_input_values:function(A){var z=this;x.each(x.keys(A),function(B){z.set_input_value(B,A[B])})},run:function(){return this._run()},rerun:function(A,z){return this._run({action:"rerun",target_dataset_id:A.id,regions:z})},get_inputs_dict:function(){var z={};this.get("inputs").each(function(A){z[A.get("name")]=A.get("value")});return z},_run:function(B){var C=x.extend({tool_id:this.id,inputs:this.get_inputs_dict()},B);var A=$.Deferred(),z=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(C),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(D){return D!=="pending"}});$.when(z.go()).then(function(D){A.resolve(new y.DatasetCollection().reset(D))});return A}});x.extend(i.prototype,g);var q=Backbone.View.extend({});var m=Backbone.Collection.extend({model:i});var v=Backbone.Model.extend(g);var k=Backbone.Model.extend({defaults:{elems:[],open:false},clear_search_results:function(){x.each(this.attributes.elems,function(z){z.show()});this.show();this.set("open",false)},apply_search_results:function(A){var B=true,z;x.each(this.attributes.elems,function(C){if(C instanceof v){z=C;z.hide()}else{if(C instanceof i){if(C.apply_search_results(A)){B=false;if(z){z.show()}}}}});if(B){this.hide()}else{this.show();this.set("open",true)}}});x.extend(k.prototype,g);var c=Backbone.Model.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var B=this.attributes.query;if(B.length<this.attributes.min_chars_for_search){this.set("results",null);return}var A=B+"*";if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var z=this;this.timer=setTimeout(function(){$.get(z.attributes.search_url,{query:A},function(C){z.set("results",C);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},200)},clear_search:function(){this.set("query","");this.set("results",null)}});x.extend(c.prototype,g);var n=Backbone.Model.extend({initialize:function(z){this.attributes.tool_search=z.tool_search;this.attributes.tool_search.on("change:results",this.apply_search_results,this);this.attributes.tools=z.tools;this.attributes.layout=new Backbone.Collection(this.parse(z.layout))},parse:function(A){var z=this,B=function(E){var D=E.model_class;if(D.indexOf("Tool")===D.length-4){return z.attributes.tools.get(E.id)}else{if(D==="ToolSection"){var C=x.map(E.elems,B);E.elems=C;return new k(E)}else{if(D==="ToolSectionLabel"){return new v(E)}}}};return x.map(A,B)},clear_search_results:function(){this.get("layout").each(function(z){if(z instanceof k){z.clear_search_results()}else{z.show()}})},apply_search_results:function(){var A=this.get("tool_search").get("results");if(A===null){this.clear_search_results();return}var z=null;this.get("layout").each(function(B){if(B instanceof v){z=B;z.hide()}else{if(B instanceof i){if(B.apply_search_results(A)){if(z){z.show()}}}else{z=null;B.apply_search_results(A)}}})}});var s=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var l=s.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var b=s.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.text));return this}});var r=s.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){s.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var z=this.$el.find(".toolSectionBody");x.each(this.model.attributes.elems,function(A){if(A instanceof i){var B=new l({model:A,className:"toolTitle"});B.render();z.append(B.$el)}else{if(A instanceof v){var C=new b({model:A});C.render();z.append(C.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var p=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find(".tooltip").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(z){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===z.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var w=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.model.get("tool_search").on("change:results",this.handle_search_results,this)},render:function(){var z=this;var A=new p({model:this.model.get("tool_search")});A.render();z.$el.append(A.$el);this.model.get("layout").each(function(C){if(C instanceof k){var B=new r({model:C});B.render();z.$el.append(B.$el)}else{if(C instanceof i){var D=new l({model:C,className:"toolTitleNoSection"});D.render();z.$el.append(D.$el)}else{if(C instanceof v){var E=new b({model:C});E.render();z.$el.append(E.$el)}}}});z.$el.find("a.tool-link").click(function(D){var C=$(this).attr("class").split(/\s+/)[0],B=z.model.get("tools").get(C);z.trigger("tool_link_click",D,B)});return this},handle_search_results:function(){var z=this.model.get("tool_search").get("results");if(z&&z.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var u=Backbone.View.extend({className:"toolForm",template:Handlebars.templates.tool_form,render:function(){this.$el.children().remove();this.$el.append(this.template(this.model.toJSON()))}});var h=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new w({collection:this.collection});this.tool_form_view=new u()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var z=this;this.tool_panel_view.on("tool_link_click",function(B,A){B.preventDefault();z.show_tool(A)})},show_tool:function(A){var z=this;A.fetch().done(function(){z.tool_form_view.model=A;z.tool_form_view.render();z.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:e,IntegerToolParameter:d,SelectToolParameter:t,Tool:i,ToolCollection:m,ToolSearch:c,ToolPanel:n,ToolPanelView:w,ToolFormView:u}});
\ No newline at end of file
+define(["libs/underscore","viz/trackster/util","mvc/data","libs/backbone/backbone-relational"],function(x,a,y){var g={hidden:false,show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},toggle:function(){this.set("hidden",!this.get("hidden"))},is_visible:function(){return !this.attributes.hidden}};var e=Backbone.RelationalModel.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},subModelTypes:{integer:"IntegerToolParameter","float":"FloatToolParameter",data:"DataToolParameter",select:"SelectToolParameter"},initialize:function(){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new e(this.toJSON())},set_value:function(z){this.set("value",z||"")}});var o={};Backbone.Relational.store.addModelScope(o);var j=o.DataToolParameter=e.extend({});var d=o.IntegerToolParameter=e.extend({set_value:function(z){this.set("value",parseInt(z,10))},get_samples:function(){return d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}});var f=o.FloatToolParameter=d.extend({set_value:function(z){this.set("value",parseFloat(z))}});var t=o.SelectToolParameter=e.extend({get_samples:function(){return x.map(this.get("options"),function(z){return z[0]})}});var i=Backbone.RelationalModel.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[],outputs:[]},relations:[{type:Backbone.HasMany,key:"inputs",relatedModel:e}],urlRoot:galaxy_config.root+"api/tools",remove_inputs:function(A){var z=this,B=z.get("inputs").filter(function(C){return(A.indexOf(C.get("type"))!==-1)});z.get("inputs").remove(B)},copy:function(A){var B=new i(this.toJSON());if(A){var z=new Backbone.Collection();B.get("inputs").each(function(C){if(C.get_samples()){z.push(C)}});B.set("inputs",z)}return B},apply_search_results:function(z){(x.indexOf(z,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(z,A){this.get("inputs").find(function(B){return B.get("name")===z}).set("value",A)},set_input_values:function(A){var z=this;x.each(x.keys(A),function(B){z.set_input_value(B,A[B])})},run:function(){return this._run()},rerun:function(A,z){return this._run({action:"rerun",target_dataset_id:A.id,regions:z})},get_inputs_dict:function(){var z={};this.get("inputs").each(function(A){z[A.get("name")]=A.get("value")});return z},_run:function(B){var C=x.extend({tool_id:this.id,inputs:this.get_inputs_dict()},B);var A=$.Deferred(),z=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(C),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(D){return D!=="pending"}});$.when(z.go()).then(function(D){A.resolve(new y.DatasetCollection().reset(D))});return A}});x.extend(i.prototype,g);var q=Backbone.View.extend({});var m=Backbone.Collection.extend({model:i});var v=Backbone.Model.extend(g);var k=Backbone.Model.extend({defaults:{elems:[],open:false},clear_search_results:function(){x.each(this.attributes.elems,function(z){z.show()});this.show();this.set("open",false)},apply_search_results:function(A){var B=true,z;x.each(this.attributes.elems,function(C){if(C instanceof v){z=C;z.hide()}else{if(C instanceof i){if(C.apply_search_results(A)){B=false;if(z){z.show()}}}}});if(B){this.hide()}else{this.show();this.set("open",true)}}});x.extend(k.prototype,g);var c=Backbone.Model.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var B=this.attributes.query;if(B.length<this.attributes.min_chars_for_search){this.set("results",null);return}var A=B+"*";if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var z=this;this.timer=setTimeout(function(){$.get(z.attributes.search_url,{query:A},function(C){z.set("results",C);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},200)},clear_search:function(){this.set("query","");this.set("results",null)}});x.extend(c.prototype,g);var n=Backbone.Model.extend({initialize:function(z){this.attributes.tool_search=z.tool_search;this.attributes.tool_search.on("change:results",this.apply_search_results,this);this.attributes.tools=z.tools;this.attributes.layout=new Backbone.Collection(this.parse(z.layout))},parse:function(A){var z=this,B=function(E){var D=E.model_class;if(D.indexOf("Tool")===D.length-4){return z.attributes.tools.get(E.id)}else{if(D==="ToolSection"){var C=x.map(E.elems,B);E.elems=C;return new k(E)}else{if(D==="ToolSectionLabel"){return new v(E)}}}};return x.map(A,B)},clear_search_results:function(){this.get("layout").each(function(z){if(z instanceof k){z.clear_search_results()}else{z.show()}})},apply_search_results:function(){var A=this.get("tool_search").get("results");if(A===null){this.clear_search_results();return}var z=null;this.get("layout").each(function(B){if(B instanceof v){z=B;z.hide()}else{if(B instanceof i){if(B.apply_search_results(A)){if(z){z.show()}}}else{z=null;B.apply_search_results(A)}}})}});var s=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var l=s.extend({tagName:"div",template:Handlebars.templates.tool_link,render:function(){this.$el.append(this.template(this.model.toJSON()));return this}});var b=s.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.text));return this}});var r=s.extend({tagName:"div",className:"toolSectionWrapper",template:Handlebars.templates.panel_section,initialize:function(){s.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(this.template(this.model.toJSON()));var z=this.$el.find(".toolSectionBody");x.each(this.model.attributes.elems,function(A){if(A instanceof i){var B=new l({model:A,className:"toolTitle"});B.render();z.append(B.$el)}else{if(A instanceof v){var C=new b({model:A});C.render();z.append(C.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var p=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",template:Handlebars.templates.tool_search,events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(this.template(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find(".tooltip").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(z){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===z.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var w=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.model.get("tool_search").on("change:results",this.handle_search_results,this)},render:function(){var z=this;var A=new p({model:this.model.get("tool_search")});A.render();z.$el.append(A.$el);this.model.get("layout").each(function(C){if(C instanceof k){var B=new r({model:C});B.render();z.$el.append(B.$el)}else{if(C instanceof i){var D=new l({model:C,className:"toolTitleNoSection"});D.render();z.$el.append(D.$el)}else{if(C instanceof v){var E=new b({model:C});E.render();z.$el.append(E.$el)}}}});z.$el.find("a.tool-link").click(function(D){var C=$(this).attr("class").split(/\s+/)[0],B=z.model.get("tools").get(C);z.trigger("tool_link_click",D,B)});return this},handle_search_results:function(){var z=this.model.get("tool_search").get("results");if(z&&z.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var u=Backbone.View.extend({className:"toolForm",template:Handlebars.templates.tool_form,render:function(){this.$el.children().remove();this.$el.append(this.template(this.model.toJSON()))}});var h=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new w({collection:this.collection});this.tool_form_view=new u()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var z=this;this.tool_panel_view.on("tool_link_click",function(B,A){B.preventDefault();z.show_tool(A)})},show_tool:function(A){var z=this;A.fetch().done(function(){z.tool_form_view.model=A;z.tool_form_view.render();z.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:e,IntegerToolParameter:d,SelectToolParameter:t,Tool:i,ToolCollection:m,ToolSearch:c,ToolPanel:n,ToolPanelView:w,ToolFormView:u}});
\ No newline at end of file
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d 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","viz/trackster/filters","mvc/data","mvc/tools"],function(ac,w,j,s,L,h,X,R){var o=ac.extend;var l={};var i=function(ad,ae){l[ad.attr("id")]=ae};var k=function(ad,af,ah,ag){ah=".group";var ae={};l[ad.attr("id")]=ag;ad.bind("drag",{handle:"."+af,relative:true},function(ap,aq){var ao=$(this),au=$(this).parent(),al=au.children(),an=l[$(this).attr("id")],ak,aj,ar,ai,am;aj=$(this).parents(ah);if(aj.length!==0){ar=aj.position().top;ai=ar+aj.outerHeight();if(aq.offsetY<ar){$(this).insertBefore(aj);var at=l[aj.attr("id")];at.remove_drawable(an);at.container.add_drawable_before(an,at);return}else{if(aq.offsetY>ai){$(this).insertAfter(aj);var at=l[aj.attr("id")];at.remove_drawable(an);at.container.add_drawable(an);return}}}aj=null;for(am=0;am<al.length;am++){ak=$(al.get(am));ar=ak.position().top;ai=ar+ak.outerHeight();if(ak.is(ah)&&this!==ak.get(0)&&aq.offsetY>=ar&&aq.offsetY<=ai){if(aq.offsetY-ar<ai-aq.offsetY){ak.find(".content-div").prepend(this)}else{ak.find(".content-div").append(this)}if(an.container){an.container.remove_drawable(an)}l[ak.attr("id")].add_drawable(an);return}}for(am=0;am<al.length;am++){ak=$(al.get(am));if(aq.offsetY<ak.position().top&&!(ak.hasClass("reference-track")||ak.hasClass("intro"))){break}}if(am===al.length){if(this!==al.get(am-1)){au.append(this);l[au.attr("id")].move_drawable(an,am)}}else{if(this!==al.get(am)){$(this).insertBefore(al.get(am));l[au.attr("id")].move_drawable(an,(aq.deltaY>0?am-1:am))}}}).bind("dragstart",function(){ae["border-top"]=ad.css("border-top");ae["border-bottom"]=ad.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ae)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,m="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.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ae,ad){if(!ad){ad=0}var af=Math.pow(10,ad);return Math.round(ae*af)/af}var p=function(ae,ad,ag){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.name=ag.name;this.view=ae;this.container=ad;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ag.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(ah){ah.stopPropagation()});var af=this;this.container_div.hover(function(){af.icons_div.show()},function(){af.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ad){if(ad.content_visible){ad.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ad.hide_contents();ad.content_visible=false}else{ad.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ad.content_visible=true;ad.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ae){var ag=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){ae.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},af=function(ah){if((ah.keyCode||ah.which)===27){ag()}else{if((ah.keyCode||ah.which)===13){ad()}}};$(window).bind("keypress.check_enter_esc",af);show_modal("Configure",ae.config.build_form(),{Cancel:ag,OK:ad})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.remove()}}];o(p.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(ad){},to_dict:function(){},set_name:function(ad){this.old_name=this.name;this.name=ad;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 ad=this.view;this.container_div.hide(0,function(){$(this).remove();ad.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ae,aj,ai,ah,ad,ag){var af=this;this.action_icons[ae]=$("<a/>").attr("href","javascript:void(0);").attr("title",aj).addClass("icon-button").addClass(ai).tooltip().click(function(){ah(af)}).appendTo(this.icons_div);if(ag){this.action_icons[ae].hide()}},build_action_icons:function(ad){var af;for(var ae=0;ae<ad.length;ae++){af=ad[ae];this.add_action_icon(af.name,af.title,af.css_class,af.on_click_fn,af.prepend,af.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ae,ad,af){p.call(this,ae,ad,af);this.obj_type=af.obj_type;this.drawables=[]};o(y.prototype,p.prototype,{unpack_drawables:function(af){this.drawables=[];var ae;for(var ad=0;ad<af.length;ad++){ae=n(af[ad],this.view,this);this.add_drawable(ae)}},init:function(){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].init()}},_draw:function(ad){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae]._draw(ad)}},to_dict:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ae}},add_drawable:function(ad){this.drawables.push(ad);ad.container=this;this.changed()},add_drawable_before:function(af,ad){this.changed();var ae=this.drawables.indexOf(ad);if(ae!==-1){this.drawables.splice(ae,0,af);return true}return false},replace_drawable:function(af,ad,ae){var ag=this.drawables.indexOf(af);if(ag!==-1){this.drawables[ag]=ad;if(ae){af.container_div.replaceWith(ad.container_div)}this.changed()}return ag},remove_drawable:function(ae){var ad=this.drawables.indexOf(ae);if(ad!==-1){this.drawables.splice(ad,1);ae.container=null;this.changed();return true}return false},move_drawable:function(ae,af){var ad=this.drawables.indexOf(ae);if(ad!==-1){this.drawables.splice(ad,1);this.drawables.splice(af,0,ae);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(ag){var ad=this.drawables.slice(0),ae=[],af;while(ad.length!==0){af=ad.shift();if(af instanceof ag){ae.push(af)}else{if(af.drawables){ad=ad.concat(af.drawables)}}}return ae}});var P=function(ae,ad,ag){o(ag,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ae,ad,ag);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);i(this.container_div,this);i(this.content_div,this);k(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new h.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ag){this.unpack_drawables(ag.drawables)}if("filters" in ag){var af=this.filters_manager;this.filters_manager=new h.FiltersManager(this,ag.filters);af.parent_div.replaceWith(this.filters_manager.parent_div);if(ag.filters.visible){this.setup_multitrack_filtering()}}};o(P.prototype,p.prototype,y.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ad){if(ad.filters_manager.visible()){ad.filters_manager.clear_filters();ad._restore_filter_managers()}else{ad.setup_multitrack_filtering();ad.request_draw({clear_tile_cache:true})}ad.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var ad=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ad)}return ad},build_header_div:function(){var ad=$("<div/>").addClass("track-header");ad.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ad);return ad},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var af=this.drawables.length;if(af===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(af===1){if(this.drawables[0] instanceof e){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var am,al,aj,ap=true,ah=this.drawables[0].get_type(),ad=0;for(am=0;am<af;am++){aj=this.drawables[am];if(aj.get_type()!==ah){can_composite=false;break}if(aj instanceof c){ad++}}if(ap||ad===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ad>1&&ad===this.drawables.length){var aq={},ae;aj=this.drawables[0];for(al=0;al<aj.filters_manager.filters.length;al++){ae=aj.filters_manager.filters[al];aq[ae.name]=[ae]}for(am=1;am<this.drawables.length;am++){aj=this.drawables[am];for(al=0;al<aj.filters_manager.filters.length;al++){ae=aj.filters_manager.filters[al];if(ae.name in aq){aq[ae.name].push(ae)}}}this.filters_manager.remove_all();var ag,ai,ak,an;for(var ao in aq){ag=aq[ao];if(ag.length===ad){ai=new h.NumberFilter({name:ag[0].name,index:ag[0].index});this.filters_manager.add_filter(ai)}}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 ad=0;ad<this.drawables.length;ad++){this.drawables[ad].filters_manager=this.saved_filters_managers[ad]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ad=0;ad<this.drawables.length;ad++){drawable=this.drawables[ad];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ae=new e(this.view,this.view,{name:this.name,drawables:this.drawables});var ad=this.container.replace_drawable(this,ae,true);ae.request_draw()},add_drawable:function(ad){y.prototype.add_drawable.call(this,ad);this.update_icons()},remove_drawable:function(ad){y.prototype.remove_drawable.call(this,ad);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ad=o(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ad},request_draw:function(ad){ac.each(this.drawables,function(ae){ae.request_draw(ad)})}});var Y=Backbone.View.extend({initialize:function(ad){o(ad,{obj_type:"View"});y.call(this,"View",ad.container,ad);this.chrom=null;this.vis_id=ad.vis_id;this.dbkey=ad.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 w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],saved_values:ad.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var af=this.container,ad=this;this.top_container=$("<div/>").addClass("top-container").appendTo(af);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(af);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(af);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;i(this.viewport_container,ad);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ag=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ad.dbkey},function(ah){ac.each(ah,function(ai){ad.add_drawable(n(ai,ad,ad))})})});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 ae=function(ah){if(ah.type==="focusout"||(ah.keyCode||ah.which)===13||(ah.keyCode||ah.which)===27){if((ah.keyCode||ah.which)!==27){ad.go_to($(this).val())}$(this).hide();$(this).val("");ad.location_span.show();ad.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ae).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(){ad.location_span.hide();ad.chrom_select.hide();ad.nav_input.val(ad.chrom+":"+ad.low+"-"+ad.high);ad.nav_input.css("display","inline-block");ad.nav_input.select();ad.nav_input.focus();ad.nav_input.autocomplete({source:function(aj,ah){var ak=[],ai=$.map(ad.get_tracks(c),function(al){return al.data_manager.search_features(aj.term).success(function(am){ak=ak.concat(am)})});$.when.apply($,ai).done(function(){ah($.map(ak,function(al){return{label:al[0],value:al[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(){ad.zoom_out();ad.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ad.zoom_in();ad.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ad.change_chrom(ad.chrom_select.val())});this.browser_content_div.click(function(ah){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ah){ad.zoom_in(ah.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ah,ai){this.current_x=ai.offsetX}).bind("drag",function(ah,aj){var ak=aj.offsetX-this.current_x;this.current_x=aj.offsetX;var ai=Math.round(ak/ad.viewport_container.width()*(ad.max_high-ad.max_low));ad.move_delta(-ai)});this.overview_close.click(function(){ad.reset_overview()});this.viewport_container.bind("draginit",function(ah,ai){if(ah.clientX>ad.viewport_container.width()-16){return false}}).bind("dragstart",function(ah,ai){ai.original_low=ad.low;ai.current_height=ah.clientY;ai.current_x=ai.offsetX}).bind("drag",function(aj,al){var ah=$(this);var am=al.offsetX-al.current_x;var ai=ah.scrollTop()-(aj.clientY-al.current_height);ah.scrollTop(ai);al.current_height=aj.clientY;al.current_x=al.offsetX;var ak=Math.round(am/ad.viewport_container.width()*(ad.high-ad.low));ad.move_delta(ak)}).bind("mousewheel",function(aj,al,ai,ah){if(ai){ai*=50;var ak=Math.round(-ai/ad.viewport_container.width()*(ad.high-ad.low));ad.move_delta(ak)}});this.top_labeltrack.bind("dragstart",function(ah,ai){return $("<div />").css({height:ad.browser_content_div.height()+ad.top_labeltrack.height()+ad.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(al,am){$(am.proxy).css({left:Math.min(al.pageX,am.startX)-ad.container.offset().left,width:Math.abs(al.pageX-am.startX)});var ai=Math.min(al.pageX,am.startX)-ad.container.offset().left,ah=Math.max(al.pageX,am.startX)-ad.container.offset().left,ak=(ad.high-ad.low),aj=ad.viewport_container.width();ad.update_location(Math.round(ai/aj*ak)+ad.low,Math.round(ah/aj*ak)+ad.low)}).bind("dragend",function(am,an){var ai=Math.min(am.pageX,an.startX),ah=Math.max(am.pageX,an.startX),ak=(ad.high-ad.low),aj=ad.viewport_container.width(),al=ad.low;ad.low=Math.round(ai/aj*ak)+al;ad.high=Math.round(ah/aj*ak)+al;$(an.proxy).remove();ad.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ad.resize_window()},500)});$(document).bind("redraw",function(){ad.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ad){return this.config.values[ad.toLowerCase()+"_color"]||this.config.values.n_color}});o(Y.prototype,y.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(ae,ag,ad,ah){if(this.timer){clearTimeout(this.timer)}if(ah){var af=this;this.timer=setTimeout(function(){af.trigger("navigate",ae+":"+ag+"-"+ad)},500)}else{view.trigger("navigate",ae+":"+ag+"-"+ad)}},update_location:function(ad,af){this.location_span.text(commatize(ad)+" - "+commatize(af));this.nav_input.val(this.chrom+":"+commatize(ad)+"-"+commatize(af));var ae=view.chrom_select.val();if(ae!==""){this.trigger_navigate(ae,view.low,view.high,true)}},load_chroms:function(af){af.num=v;var ad=this,ae=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:af,dataType:"json",success:function(ah){if(ah.chrom_info.length===0){return}if(ah.reference){ad.add_label_track(new B(ad))}ad.chrom_data=ah.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,ag=ad.chrom_data.length;aj<ag;aj++){var ai=ad.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ah.prev_chroms){ak+='<option value="previous">Previous '+v+"</option>"}if(ah.next_chroms){ak+='<option value="next">Next '+v+"</option>"}ad.chrom_select.html(ak);ad.chrom_start_index=ah.start_index;ae.resolve(ah.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ad.dbkey)}});return ae},change_chrom:function(ai,ae,ak){var af=this;if(!af.chrom_data){af.load_chroms_deferred.then(function(){af.change_chrom(ai,ae,ak)});return}if(!ai||ai==="None"){return}if(ai==="previous"){af.load_chroms({low:this.chrom_start_index-v});return}if(ai==="next"){af.load_chroms({low:this.chrom_start_index+v});return}var aj=$.grep(af.chrom_data,function(al,am){return al.chrom===ai})[0];if(aj===undefined){af.load_chroms({chrom:ai},function(){af.change_chrom(ai,ae,ak)});return}else{if(ai!==af.chrom){af.chrom=ai;af.chrom_select.val(af.chrom);af.max_high=aj.len-1;af.reset();for(var ah=0,ad=af.drawables.length;ah<ad;ah++){var ag=af.drawables[ah];if(ag.init){ag.init()}}if(af.reference_track){af.reference_track.init()}}if(ae&&ak){af.low=Math.max(ae,0);af.high=Math.min(ak,af.max_high)}else{af.low=0;af.high=af.max_high}af.reset_overview();af.request_redraw()}},go_to:function(ah){ah=ah.replace(/,/g,"");ah=ah.replace(/:|\-/g," ");var ae=ah.split(/\s+/),ag=ae[0],af=(ae[1]?parseInt(ae[1],10):null),ad=(ae[2]?parseInt(ae[2],10):null);if(!ad){af=af-15;ad=af+15}this.change_chrom(ag,af,ad)},move_fraction:function(af){var ad=this;var ae=ad.high-ad.low;this.move_delta(af*ae)},move_delta:function(ag){var ad=this;var af=ad.high-ad.low;if(ad.low-ag<ad.max_low){ad.low=ad.max_low;ad.high=ad.max_low+af}else{if(ad.high-ag>ad.max_high){ad.high=ad.max_high;ad.low=ad.max_high-af}else{ad.high-=ag;ad.low-=ag}}ad.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ad.request_redraw()},200);var ae=ad.chrom_select.val();this.trigger_navigate(ae,ad.low,ad.high,true)},add_drawable:function(ad){y.prototype.add_drawable.call(this,ad);ad.init();this.changed();this.update_intro_div()},add_label_track:function(ad){ad.view=this;ad.init();this.label_tracks.push(ad)},remove_drawable:function(af,ae){y.prototype.remove_drawable.call(this,af);if(ae){var ad=this;af.container_div.hide(0,function(){$(this).remove();ad.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ae,af){var ad=this,ag=(af?[af]:ad.drawables);ac.each(ag,function(ah){var ai=ac.find(ad.tracks_to_be_redrawn,function(aj){return aj[0]===ah});if(ai){ai[1]=ae}else{ad.tracks_to_be_redrawn.push([ah,ae])}});if(!this.requested_redraw){requestAnimationFrame(function(){ad._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ad=this.low,ah=this.high;if(ad<this.max_low){ad=this.max_low}if(ah>this.max_high){ah=this.max_high}var ae=this.high-this.low;if(this.high!==0&&ae<this.min_separation){ah=ad+this.min_separation}this.low=Math.floor(ad);this.high=Math.ceil(ah);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 ag=(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 af=13;this.overview_box.css({left:ag,width:Math.max(af,ai)}).show();if(ai<af){this.overview_box.css("left",ag-(af-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ag,width:ai})}ac.each(this.tracks_to_be_redrawn,function(al){var aj=al[0],ak=al[1];if(aj){aj._draw(ak)}});this.tracks_to_be_redrawn=[];ac.each(this.label_tracks,function(aj){aj._draw()})},zoom_in:function(ae,af){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ag=this.high-this.low,ah=ag/2+this.low,ad=(ag/this.zoom_factor)/2;if(ae){ah=ae/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ah-ad);this.high=Math.round(ah+ad);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ae=this.high-this.low,af=ae/2+this.low,ad=(ae*this.zoom_factor)/2;this.low=Math.round(af-ad);this.high=Math.round(af+ad);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(af){if(this.overview_drawable){if(this.overview_drawable.dataset.id===af.dataset.id){return}this.overview_viewport.find(".track").remove()}var ae=af.copy({content_div:this.overview_viewport}),ad=this;ae.header_div.hide();ae.is_overview=true;ad.overview_drawable=ae;this.overview_drawable.postdraw_actions=function(){ad.overview_highlight.show().height(ad.overview_drawable.content_div.height());ad.overview_viewport.height(ad.overview_drawable.content_div.height()+ad.overview_box.outerHeight());ad.overview_close.show();ad.resize_window()};ad.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 q=Backbone.RelationalModel.extend({defaults:{track:null,tool:null,},relations:[{type:Backbone.HasOne,key:"tool",relatedModel:R.Tool}],initialize:function(ad){this.get("tool").remove_inputs(["data","hidden_data","conditional"])}});var t=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var af=this.$el.addClass("param-row"),ag=this.model;var ad=$("<div>").addClass("param-label").text(ag.get("label")).appendTo(af);var ae=$("<div/>").addClass("param-input").html(ag.get("html")).appendTo(af);ae.find(":input").val(ag.get("value"));$("<div style='clear: both;'/>").appendTo(af)},update_value:function(ad){this.model.set_value($(ad.target).val())}});var ab=Backbone.View.extend({render:function(){var ae=this;tool=this.model.get("tool"),parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ai){ai.stopPropagation()}).click(function(ai){ai.stopPropagation()}).bind("dblclick",function(ai){ai.stopPropagation()}).keydown(function(ai){ai.stopPropagation()});var af=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(aj){var ai=new t({model:aj});ai.render();parent_div.append(ai.$el)});parent_div.find("input").click(function(){$(this).select()});var ag=$("<div>").addClass("param-row").appendTo(parent_div);var ah=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ag);var ad=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(ag);ad.click(function(){ae.run_on_region()});ah.click(function(){ae.run_on_dataset()})},update_params:function(){for(var ad=0;ad<this.params.length;ad++){this.params[ad].update_value()}},state_dict:function(){var ad=this.model.get("tool").get_param_values_dict();ad.visible=this.parent_div.is(":visible");return ad},run_on_dataset:function(){var ad=this.model.get("tool");this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ad.id},null,function(ae){show_modal(ad.get("name")+" is Running",ad.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ae=this.model.get("track"),ah=this.model.get("tool"),aj=new w.GenomeRegion({chrom:ae.view.chrom,start:ae.view.low,end:ae.view.high}),ak={target_dataset_id:ae.dataset.id,action:"rerun",tool_id:ah.id,regions:[aj.toJSON()]},ai=ae,am=ak.tool_id+ai.tool_region_and_parameters_str(aj),ad;if(ai.container===view){var al=new P(view,view,{name:this.name});var ag=ai.container.replace_drawable(ai,al,false);al.container_div.insertBefore(ai.view.content_div.children()[ag]);al.add_drawable(ai);ai.container_div.appendTo(al.content_div);ad=al}else{ad=ai.container}var af=new ai.constructor(view,ad,{name:am,hda_ldda:"hda"});af.init_for_tool_data();af.change_mode(ai.mode);af.set_filters_manager(ai.filters_manager.copy(af));af.update_icons();ad.add_drawable(af);af.tiles_div.text("Starting job.");this.run(ak,af,function(an){af.set_dataset(new X.Dataset(an));af.tiles_div.text("Running job.");af.init()})},run:function(ad,af,ag){ad.inputs=this.model.get("tool").get_inputs_dict();var ae=new j.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ad),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ah){return ah!=="pending"}});$.when(ae.go()).then(function(ah){if(ah==="no converter"){af.container_div.addClass("error");af.content_div.text(J)}else{if(ah.error){af.container_div.addClass("error");af.content_div.text(x+ah.message)}else{ag(ah)}}})}});var C=function(ad,ae){L.Scaler.call(this,ae);this.filter=ad};C.prototype.gen_val=function(ad){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(ad[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ad){this.track=ad.track;this.params=ad.params;this.values={};this.restore_values((ad.saved_values?ad.saved_values:{}));this.onchange=ad.onchange};o(F.prototype,{set_param_default_value:function(ae,ad){var af=ac.find(this.params,function(ag){return ag.key===ae});if(af){af.default_value=ad}},set_param_value:function(ad,ae){var af=ac.find(this.params,function(ag){return ag.key===ad});if(af){if(typeof ae==="string"||ae instanceof String){if(ae.trim()===""){ae=af.default_value}else{if(af.type==="float"){ae=parseFloat(ae)}else{if(af.type==="int"){ae=parseInt(ae,10)}}}}}if(this.values[ad]!==ae){this.values[ad]=ae;return true}else{return false}},restore_values:function(ad){var ae=this;$.each(this.params,function(af,ag){if(ad[ag.key]!==undefined){ae.values[ag.key]=ad[ag.key]}else{ae.values[ag.key]=ag.default_value}})},build_form:function(){var ag=this;var ad=$("<div />");var af;function ae(al,ah){for(var ap=0;ap<al.length;ap++){af=al[ap];if(af.hidden){continue}var aj="param_"+ap;var au=ag.values[af.key];var aw=$("<div class='form-row' />").appendTo(ah);aw.append($("<label />").attr("for",aj).text(af.label+":"));if(af.type==="bool"){aw.append($('<input type="checkbox" />').attr("id",aj).attr("name",aj).attr("checked",au))}else{if(af.type==="text"){aw.append($('<input type="text"/>').attr("id",aj).val(au).click(function(){$(this).select()}))}else{if(af.type==="select"){var ar=$("<select />").attr("id",aj);for(var an=0;an<af.options.length;an++){$("<option/>").text(af.options[an].label).attr("value",af.options[an].value).appendTo(ar)}ar.val(au);aw.append(ar)}else{if(af.type==="color"){var av=$("<div/>").appendTo(aw),aq=$("<input />").attr("id",aj).attr("name",aj).val(au).css("float","left").appendTo(av).click(function(ay){$(".bs-tooltip").removeClass("in");var ax=$(this).siblings(".bs-tooltip").addClass("in");ax.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(ax).height()/2)+($(this).height()/2)}).show();ax.click(function(az){az.stopPropagation()});$(document).bind("click.color-picker",function(){ax.hide();$(document).unbind("click.color-picker")});ay.stopPropagation()}),ao=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(av).attr("title","Set new random color").tooltip(),at=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(av).hide(),ak=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(at),ai=$("<div class='tooltip-arrow'></div>").appendTo(at),am=$.farbtastic(ak,{width:100,height:100,callback:aq,color:au});av.append($("<div/>").css("clear","both"));(function(ax){ao.click(function(){ax.setColor(j.get_random_color())})})(am)}else{aw.append($("<input />").attr("id",aj).attr("name",aj).val(au))}}}}if(af.help){aw.append($("<div class='help'/>").text(af.help))}}}ae(this.params,ad);return ad},update_from_form:function(ad){var af=this;var ae=false;$.each(this.params,function(ag,ai){if(!ai.hidden){var aj="param_"+ag;var ah=ad.find("#"+aj).val();if(ai.type==="bool"){ah=ad.find("#"+aj).is(":checked")}ae=af.set_param_value(ai.key,ah)||ae}});if(ae){this.onchange();this.track.changed()}}});var b=function(ad,ah,af,ae,ag){this.track=ad;this.region=ah;this.low=ah.get("start");this.high=ah.get("end");this.resolution=af;this.html_elt=$("<div class='track-tile'/>").append(ae).height($(ae).attr("height"));this.data=ag;this.stale=false};b.prototype.predisplay_actions=function(){};var M=function(ad,ah,af,ae,ag){b.call(this,ad,ah,af,ae,ag)};M.prototype.predisplay_actions=function(){};var O=function(ag,ao,ah,af,aj,aq,ak,ar,ae,an){b.call(this,ag,ao,ah,af,aj);this.mode=ak;this.all_slotted=ae;this.feature_mapper=an;this.has_icons=false;if(ar){this.has_icons=true;var al=this;af=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:af.width}).prependTo(this.html_elt);var am=new w.GenomeRegion({chrom:ag.view.chrom,start:this.low,end:this.high}),ap=aj.length,ai=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ap+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ad=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ap+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ai.click(function(){al.stale=true;ag.data_manager.get_more_data(am,ag.mode,al.resolution,{},ag.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ag.request_draw()}).dblclick(function(at){at.stopPropagation()});ad.click(function(){al.stale=true;ag.data_manager.get_more_data(am,ag.mode,al.resolution,{},ag.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ag.request_draw()}).dblclick(function(at){at.stopPropagation()})}};o(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ae=this,ad={};if(ae.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(ap){if(!this.hovered){return}var ak=$(this).offset(),ao=ap.pageX-ak.left,an=ap.pageY-ak.top,au=ae.feature_mapper.get_feature_data(ao,an),al=(au?au[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!al||$(this).attr("id")!==al.toString()){$(this).remove()}});if(au){var ag=ad[al];if(!ag){var al=au[0],aq={name:au[3],start:au[1],end:au[2],strand:au[4]},aj=ae.track.filters_manager.filters,ai;for(var am=0;am<aj.length;am++){ai=aj[am];aq[ai.name]=au[ai.index]}var ag=$("<div/>").attr("id",al).addClass("feature-popup"),av=$("<table/>"),at,ar,aw;for(at in aq){ar=aq[at];aw=$("<tr/>").appendTo(av);$("<th/>").appendTo(aw).text(at);$("<td/>").attr("align","left").appendTo(aw).text(typeof(ar)==="number"?V(ar,2):ar)}ag.append($("<div class='feature-popup-inner'>").append(av));ad[al]=ag}ag.appendTo($(this).parents(".track-content").children(".overlay"));var ah=ao+parseInt(ae.html_elt.css("left"))-ag.width()/2,af=an+parseInt(ae.html_elt.css("top"))+7;ag.css("left",ah+"px").css("top",af+"px")}else{if(!ap.isPropagationStopped()){ap.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ap)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var f=function(ae,ad,af){o(af,{drag_handle_class:"draghandle"});p.call(this,ae,ad,af);this.dataset=null;if(af.dataset){this.dataset=(af.dataset instanceof Backbone.Model?af.dataset:new X.Dataset(af.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in af?af.data_query_wait:K);this.data_manager=("data_manager" in af?af.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ae.dbkey,chroms_info:{chrom_info:ae.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 af)||af.resize){this.add_resize_handle()}}};o(f.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ad){ad.view.set_overview(ad)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ad){if(ad.filters_manager.visible()){ad.filters_manager.clear_filters()}else{ad.filters_manager.init_filters()}ad.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ad){ad.dynamic_tool_div.toggle();if(ad.dynamic_tool_div.is(":visible")){ad.set_name(ad.name+ad.tool_region_and_parameters_str())}else{ad.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ad){var ag='<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>',af=ac.template(ag,{track:ad});var ai=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(){var ak=$('select[name="regions"] option:selected').val(),am,aj=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),al=ac.map($(".bookmark"),function(an){return new w.GenomeRegion({from_str:$(an).children(".position").text()})});if(ak==="cur"){am=[aj]}else{if(ak==="bookmarks"){am=al}else{am=[aj].concat(al)}}hide_modal();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(am).toJSON())})},ah=function(aj){if((aj.keyCode||aj.which)===27){ai()}else{if((aj.keyCode||aj.which)===13){ae()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",af,{No:ai,Yes:ae})}},p.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&p.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ad=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ad)}this.name_div=$("<div/>").addClass("track-name").appendTo(ad).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ad},set_dataset:function(ad){this.dataset=ad;this.data_manager.set("dataset",ad)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ad=this;var ag=false;var af=false;var ae=$("<div class='track-resize'>");$(ad.container_div).hover(function(){if(ad.content_visible){ag=true;ae.show()}},function(){ag=false;if(!af){ae.hide()}});ae.hide().bind("dragstart",function(ah,ai){af=true;ai.original_height=$(ad.content_div).height()}).bind("drag",function(ai,aj){var ah=Math.min(Math.max(aj.original_height+aj.deltaY,ad.min_height_px),ad.max_height_px);$(ad.tiles_div).css("height",ah);ad.visible_height_px=(ad.max_height_px===ah?0:ah);ad.on_resize()}).bind("dragend",function(ah,ai){ad.tile_cache.clear();af=false;if(!ag){ae.hide()}ad.config.values.height=ad.visible_height_px;ad.changed()}).appendTo(ad.container_div)},set_display_modes:function(ag,aj){this.display_modes=ag;this.mode=(aj?aj:(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 ae=this,ah={};for(var af=0,ad=ae.display_modes.length;af<ad;af++){var ai=ae.display_modes[af];ah[ai]=function(ak){return function(){ae.change_mode(ak);ae.icons_div.show();ae.container_div.mouseleave(function(){ae.icons_div.hide()})}}(ai)}make_popupmenu(this.action_icons.mode_icon,ah)},build_action_icons:function(){p.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 W){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof g){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof e){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(af){var ae=this;ae.enabled=false;ae.tile_cache.clear();ae.data_manager.clear();ae.tiles_div.css("height","auto");ae.tiles_div.text("").children().remove();ae.container_div.removeClass("nodata error pending");if(!ae.dataset.id){return}var ad=$.Deferred(),ag={hda_ldda:ae.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ae.view.chrom,retry:af};$.getJSON(this.dataset.url(),ag,function(ah){if(!ah||ah==="error"||ah.kind==="error"){ae.container_div.addClass("error");ae.tiles_div.text(m);if(ah.message){ae.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ah.message+"</pre>",{Close:hide_modal})}));ae.tiles_div.append($("<span/>").text(" "));ae.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ae.init(true)}))}}else{if(ah==="no converter"){ae.container_div.addClass("error");ae.tiles_div.text(J)}else{if(ah==="no data"||(ah.data!==undefined&&(ah.data===null||ah.data.length===0))){ae.container_div.addClass("nodata");ae.tiles_div.text(E)}else{if(ah==="pending"){ae.container_div.addClass("pending");ae.tiles_div.html(u);setTimeout(function(){ae.init()},ae.data_query_wait)}else{if(ah==="data"||ah.status==="data"){if(ah.valid_chroms){ae.valid_chroms=ah.valid_chroms;ae.update_icons()}ae.tiles_div.text(U);if(ae.view.chrom){ae.tiles_div.text("");ae.tiles_div.css("height",ae.visible_height_px+"px");ae.enabled=true;$.when.apply($,ae.predraw_init()).done(function(){ad.resolve();ae.container_div.removeClass("nodata error pending");ae.request_draw()})}else{ad.resolve()}}}}}}});this.update_icons();return ad},predraw_init:function(){var ad=this;return $.getJSON(ad.dataset.url(),{data_type:"data",stats:true,chrom:ad.view.chrom,low:0,high:ad.view.max_high,hda_ldda:ad.dataset.get("hda_ldda")},function(ae){ad.container_div.addClass("line-track");var ag=ae.data;if(ag&&ag.min&&ag.max){var af=ag.min,ah=ag.max;af=Math.floor(Math.min(0,Math.max(af,ag.mean-2*ag.sd)));ah=Math.ceil(Math.max(0,Math.min(ah,ag.mean+2*ag.sd)));ad.config.set_param_default_value("min_value",af);ad.config.set_param_default_value("max_value",ah);ad.prefs.min_value=af;ad.prefs.max_value=ah}})},get_drawables:function(){return this}});var N=function(af,ae,ah){f.call(this,af,ae,ah);var ad=this;k(ad.container_div,ad.drag_handle_class,".group",ad);this.filters_manager=new h.FiltersManager(this,("filters" in ah?ah.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ah.tool?new q({track:this,tool:ah.tool,tool_state:ah.tool_state}):null);this.tile_cache=new w.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var ag=new ab({model:this.tool});ag.render();this.dynamic_tool_div=ag.$el;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(ah.mode){this.change_mode(ah.mode)}};o(N.prototype,p.prototype,f.prototype,{action_icons_def:f.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(ad){$(".bs-tooltip").remove();ad.slotters[ad.view.resolution_px_b].max_rows*=2;ad.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ad){var ae=this.to_dict();o(ae,{data_manager:this.data_manager});var af=new this.constructor(this.view,ad,ae);af.change_mode(this.mode);af.enabled=this.enabled;return af},set_filters_manager:function(ad){this.filters_manager=ad;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ad=this;return $.getJSON(ad.dataset.url(),{data_type:"data",stats:true,chrom:ad.view.chrom,low:0,high:ad.view.max_high,hda_ldda:ad.dataset.get("hda_ldda")},function(ae){var ag=ae.data;if(isNaN(parseFloat(ad.prefs.min_value))||isNaN(parseFloat(ad.prefs.max_value))){var af=ag.min,ah=ag.max;af=Math.floor(Math.min(0,Math.max(af,ag.mean-2*ag.sd)));ah=Math.ceil(Math.max(0,Math.min(ah,ag.mean+2*ag.sd)));ad.prefs.min_value=af;ad.prefs.max_value=ah}})},change_mode:function(ae){var ad=this;ad.mode=ae;ad.config.values.mode=ae;if(ae==="Auto"){this.data_manager.clear()}ad.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ad.mode+")");return ad},update_icons:function(){var ad=this;if(ad.filters_available){ad.action_icons.filters_icon.show()}else{ad.action_icons.filters_icon.hide()}if(ad.tool){ad.action_icons.tools_icon.show();ad.action_icons.param_space_viz_icon.show()}else{ad.action_icons.tools_icon.hide();ad.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ae,ad){return ae+"_"+ad},request_draw:function(ad){if(ad&&ad.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ad,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ah=this.view.high,ak=ah-al,ae=this.view.container.width(),ap=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;ap=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ad=Math.floor(al/(ag*S)),am,ai,aj=[],ao=[];while((ad*S*ag)<ah){am=this._get_tile_bounds(ad,ag);ai=this.draw_helper(am,ag,ap,aq);aj.push(ai);$.when(ai).then(function(ar){ao.push(ar)});ad+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;$.when.apply($,aj).then(function(){af.tiles_div.children(".remove").remove();ao=ac.filter(ao,function(ar){return ar!==null});if(ao.length!==0){af.postdraw_actions(ao,ae,ap,an)}})},_add_yaxis_label:function(ag,ai){var ae=this,ah=(ag==="max"?"top":"bottom"),aj=(ag==="max"?"max":"min"),ad=(ag==="max"?"max_value":"min_value"),ai=ai||function(){ae.request_draw({clear_tile_cache:true})},af=this.container_div.find(".yaxislabel."+ah);if(af.length!==0){af.text(ae.prefs[ad])}else{af=$("<div/>").text(ae.prefs[ad]).make_text_editable({num_cols:12,on_finish:function(ak){$(".bs-tooltip").remove();ae.config.set_param_value(ad,ak);ai()},help_text:"Set "+aj+" value"}).addClass("yaxislabel "+ah).css("color",this.prefs.label_color);this.container_div.prepend(af)}},postdraw_actions:function(ag,ah,aj,ad){var af=ac.filter(ag,function(ak){return(ak instanceof M)});if(af.length>0){this.max_height_px=0;var ae=this;ac.each(ag,function(ak){if(!(ak instanceof M)){ak.html_elt.remove();ae.draw_helper(ak.region,ak.resolution,aj,{force:true,mode:"Coverage"})}});ae._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ai=ac.find(ag,function(ak){return ak.has_icons});if(ai){ac.each(ag,function(ak){if(!ak.has_icons){ak.html_elt.css("padding-top",D)}})}}},get_mode:function(ad){return this.mode},update_auto_mode:function(ad){},_get_drawables:function(){return[this]},draw_helper:function(am,ag,ap,aq){if(!aq){aq={}}var ae=aq.force,ao=!(aq.data_fetch===false),aj=aq.mode||this.mode,af=this,ah=this._get_drawables(),an=this._gen_tile_cache_key(ap,am),ai=function(ar){return(ar&&"track" in ar)};var ak=(ae?undefined:af.tile_cache.get_elt(an));if(ak){if(ai(ak)){af.show_tile(ak,ap)}return ak}if(!ao){return null}var al=function(){var ar=(ac.find(A,function(au){return au===aj})?"Coverage":aj);var at=ac.map(ah,function(au){return au.data_manager.get_data(am,ar,ag,af.data_url_extra_params)});if(view.reference_track){at.push(view.reference_track.data_manager.get_data(am,aj,ag,view.reference_track.data_url_extra_params))}return at};var ad=$.Deferred();af.tile_cache.set_elt(an,ad);$.when.apply($,al()).then(function(){var ar=al(),ax=ar,aD;if(view.reference_track){aD=view.reference_track.data_manager.subset_entry(ar.pop(),am)}var ay=[],av=[];ac.each(ah,function(aI,aF){var aH=aI.mode,aG=ax[aF];if(aH==="Auto"){aH=aI.get_mode(aG);aI.update_auto_mode(aH)}ay.push(aH);av.push(aI.get_canvas_height(aG,aH,ap,at))});var aw=af.view.canvas_manager.new_canvas(),az=am.get("start"),aE=am.get("end"),au=0,at=Math.ceil((aE-az)*ap)+af.left_offset,aB=ac.max(av),aA;aw.width=at;aw.height=(aq.height||aB);var aC=aw.getContext("2d");aC.translate(af.left_offset,0);if(ah.length>1){aC.globalAlpha=0.5;aC.globalCompositeOperation="source-over"}ac.each(ah,function(aG,aF){aA=aG.draw_tile(ax[aF],aC,ay[aF],ag,am,ap,aD)});if(aA!==undefined){af.tile_cache.set_elt(an,aA);af.show_tile(aA,ap)}ad.resolve(aA)});return ad},get_canvas_height:function(ad,af,ag,ae){return this.visible_height_px},_draw_line_track_tile:function(ad,af,aj,ah,ai,ak){var ag=af.canvas,ae=new L.LinePainter(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj);ae.draw(af,ag.width,ag.height,ak);return new M(this,ai,ah,ag,ad.data)},draw_tile:function(ad,ae,ai,ag,ah,aj,af){console.log("Warning: TiledTrack.draw_tile() not implemented.")},show_tile:function(af,ai){var ae=this,ad=af.html_elt;af.predisplay_actions();var ah=(af.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ah-=this.left_offset}ad.css({position:"absolute",top:0,left:ah});if(ad.hasClass("remove")){ad.removeClass("remove")}else{this.tiles_div.append(ad)}af.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,af.html_elt.height());af.html_elt.parent().children().css("height",this.max_height_px+"px");var ag=this.max_height_px;if(this.visible_height_px!==0){ag=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ag+"px")},_get_tile_bounds:function(ad,ae){var ag=Math.floor(ad*S*ae),ah=Math.ceil(S*ae),af=(ag+ah<=this.view.max_high?ag+ah:this.view.max_high);return new w.GenomeRegion({chrom:this.view.chrom,start:ag,end:af})},tool_region_and_parameters_str:function(ag){var ad=this,af=(ag!==undefined?ag.toString():"all"),ae=ac.values(ad.tool.get("tool").get_inputs_dict()).join(", ");return" - region=["+af+"], parameters=["+ae+"]"},data_and_mode_compatible:function(ad,ae){if(ae==="Auto"){return true}else{if(ae==="Coverage"){return ad.dataset_type==="bigwig"}else{if(ad.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ad){if(ad.dataset_type==="bigwig"||ad.message||ad.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var W=function(ae,ad){var af={resize:false};f.call(this,ae,ad,af);this.container_div.addClass("label-track")};o(W.prototype,f.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ah){var af=this.view,ag=af.high-af.low,ak=Math.floor(Math.pow(10,Math.floor(Math.log(ag)/Math.log(10)))),ad=Math.floor(af.low/ak)*ak,ai=this.view.container.width(),ae=$("<div style='position: relative; height: 1.3em;'></div>");while(ad<af.high){var aj=(ad-af.low)/ag*ai;ae.append($("<div class='label'>"+commatize(ad)+"</div>").css({position:"absolute",left:aj-1}));ad+=ak}this.content_div.children(":first").remove();this.content_div.append(ae)}});var e=function(ae,ad,ah){this.display_modes=A;N.call(this,ae,ad,ah);this.drawables=[];if("drawables" in ah){var ag;for(var af=0;af<ah.drawables.length;af++){ag=ah.drawables[af];this.drawables[af]=n(ag,ae,null);if(ag.left_offset>this.left_offset){this.left_offset=ag.left_offset}}this.enabled=true}ac.each(this.drawables,function(ai){if(ai instanceof c||ai instanceof T){ai.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};o(e.prototype,N.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.show_group()}}].concat(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ad){N.prototype.change_mode.call(this,ad);for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae].change_mode(ad)}},init:function(){var af=[];for(var ae=0;ae<this.drawables.length;ae++){af.push(this.drawables[ae].init())}var ad=this;$.when.apply($,af).then(function(){ad.enabled=true;ad.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:p.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var ag=new P(this.view,this.container,{name:this.name}),ad;for(var af=0;af<this.drawables.length;af++){ad=this.drawables[af];ad.update_icons();ag.add_drawable(ad);ad.container=ag;ag.content_div.append(ad.container_div)}var ae=this.container.replace_drawable(this,ag,true);ag.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ae=ac.min(ac.map(this.drawables,function(af){return af.prefs.min_value})),ad=ac.max(ac.map(this.drawables,function(af){return af.prefs.max_value}));this.prefs.min_value=ae;this.prefs.max_value=ad;ac.each(this.drawables,function(af){af.prefs.min_value=ae;af.prefs.max_value=ad})},update_all_min_max:function(){var ad=this;ac.each(this.drawables,function(ae){ae.prefs.min_value=ad.prefs.min_value;ae.prefs.max_value=ad.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(aj,ad,am,ai){N.prototype.postdraw_actions.call(this,aj,ad,am,ai);var ah=-1;for(var af=0;af<aj.length;af++){var ak=aj[af].html_elt.find("canvas").height();if(ak>ah){ah=ak}}for(var af=0;af<aj.length;af++){var ag=aj[af];if(ag.html_elt.find("canvas").height()!==ah){this.draw_helper(ag.region,ag.resolution,am,{force:true,height:ah});ag.html_elt.remove()}}var ae=this,al=function(){ae.update_all_min_max()};this._add_yaxis_label("min",al);this._add_yaxis_label("max",al)}});var B=function(ad){N.call(this,ad,{content_div:ad.top_labeltrack},{resize:false});ad.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=galaxy_config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};o(B.prototype,p.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:p.prototype.can_draw,draw_helper:function(af,ae,ag,ad){if(ag>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,af,ae,ag,ad)}else{this.tiles_div.hide();return null}},can_subset:function(ad){return true},draw_tile:function(ag,am,ah,ae,aj,an){var af=this.data_manager.subset_entry(ag,aj),al=af.data;var ad=am.canvas;am.font=am.canvas.manager.default_font;am.textAlign="center";for(var ai=0,ak=al.length;ai<ak;ai++){am.fillStyle=this.view.get_base_color(al[ai]);am.fillText(al[ai],Math.floor(ai*an),10)}return new b(this,aj,ae,ad,af)}});var g=function(af,ae,ag){var ad=this;this.display_modes=A;this.mode="Histogram";N.call(this,af,ae,ag);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:j.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:ag.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};o(g.prototype,p.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ad,ae,ah,af,ag,ai){return this._draw_line_track_tile(ad,ae,ah,af,ag,ai)},can_subset:function(ad){return(ad.data[1][0]-ad.data[0][0]===1)},postdraw_actions:function(ae,af,ag,ad){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var r=function(af,ae,ag){var ad=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,af,ae,ag);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:ag.prefs,onchange:function(){ad.set_name(ad.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};o(r.prototype,p.prototype,N.prototype,{draw_tile:function(ad,af,aj,ah,ai,ak){var ag=af.canvas,ae=new L.DiagonalHeatmapPainter(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj);ae.draw(af,ag.width,ag.height,ak);return new b(this,ai,ah,ag,ad.data)}});var c=function(ag,af,ai){var ae=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ag,af,ai);var ah=j.get_random_color(),ad=j.get_random_color([ah,"#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:ah},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ad},{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:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",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:ai.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.set_painter_from_config();ae.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");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()};o(c.prototype,p.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(an,af,ao,am){N.prototype.postdraw_actions.call(this,an,af,ao,am);var ah=this,ai;if(ah.filters_manager){var ag=ah.filters_manager.filters;for(var ak=0;ak<ag.length;ak++){ag[ak].update_ui_elt()}var aj=false,al,ae;for(ai=0;ai<an.length;ai++){if(an[ai].data.length){al=an[ai].data[0];for(var ak=0;ak<ag.length;ak++){ae=ag[ak];if(ae.applies_to(al)&&ae.min!==ae.max){aj=true;break}}}}if(ah.filters_available!==aj){ah.filters_available=aj;if(!ah.filters_available){ah.filters_manager.hide()}ah.update_icons()}}if(an[0] instanceof O){var ad=true;for(ai=0;ai<an.length;ai++){if(!an[ai].all_slotted){ad=false;break}}if(!ad){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(ad){var ad;if(this.mode==="Auto"){if(ad==="no_detail"){ad="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ad+")")}},incremental_slots:function(ah,ad,ag){var ae=this.view.canvas_manager.dummy_context,af=this.slotters[ah];if(!af||(af.mode!==ag)){af=new (s.FeatureSlotter)(ah,ag,z,function(ai){return ae.measureText(ai)});this.slotters[ah]=af}return af.slot_features(ad)},get_mode:function(ad){if(ad.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(ad,ah,ai,ae){if(ah==="Coverage"||ad.dataset_type==="bigwig"){return this.summary_draw_height}else{var ag=this.incremental_slots(ai,ad.data,ah);var af=new (this.painter)(null,null,null,this.prefs,ah);return Math.max(aa,af.get_required_height(ag,ae))}},draw_tile:function(an,ar,ap,at,ag,ak,af){var aq=this,ae=ar.canvas,az=ag.get("start"),ad=ag.get("end"),ah=this.left_offset;if(an.dataset_type==="bigwig"){return this._draw_line_track_tile(an,ar,ap,at,ag,ak)}var aj=[],ao=this.slotters[ak].slots;all_slotted=true;if(an.data){var al=this.filters_manager.filters;for(var au=0,aw=an.data.length;au<aw;au++){var ai=an.data[au];var av=false;var am;for(var ay=0,aD=al.length;ay<aD;ay++){am=al[ay];am.update_attrs(ai);if(!am.keep(ai)){av=true;break}}if(!av){aj.push(ai);if(!(ai[0] in ao)){all_slotted=false}}}}var aC=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),aA=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aB=new (this.painter)(aj,az,ad,this.prefs,ap,aC,aA,af,function(aE){return aq.view.get_base_color(aE)});var ax=null;ar.fillStyle=this.prefs.block_color;ar.font=ar.canvas.manager.default_font;ar.textAlign="right";if(an.data){ax=aB.draw(ar,ae.width,ae.height,ak,ao);ax.translation=-ah}return new O(aq,ag,at,ae,an.data,ak,ap,an.message,all_slotted,ax)}});var Z=function(ae,ad,af){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:j.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};o(Z.prototype,p.prototype,N.prototype,{draw_tile:function(ad,ag,aj,ah,ai,ak){if(ad.dataset_type==="bigwig"){return this._draw_line_track_tile(ad,ag,"Histogram",ah,ai,ak)}else{var af=this.view,ae=new (this.painter)(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj,function(al){return af.get_base_color(al)});ae.draw(ag,ag.canvas.width,ag.canvas.height,ak);return new b(this,ai,ah,ag.canvas,ad.data)}},get_canvas_height:function(ad,ah,ai,af){if(ad.dataset_type==="bigwig"){return this.summary_draw_height}else{var ag=new (this.painter)(null,null,null,this.prefs,ah);var ae=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ae===0&&ad.data.length!==0){ae=ad.data[0][7].match(/,/g);if(ae===null){ae=1}else{ae=ae.length+1}}return ag.get_required_height(ae)}},predraw_init:function(){var ad=[f.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ad.push(this.dataset.fetch())}return ad},postdraw_actions:function(ag,ah,aj,ae){N.prototype.postdraw_actions.call(this,ag,ah,aj,ae);var af=ac.filter(ag,function(ak){return(ak instanceof M)});if(af.length===0&&this.prefs.show_labels){var ad;if(this.container_div.find(".yaxislabel.variant").length===0){ad=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ad+"px",top:(this.prefs.summary_height-ad)/2+"px"}));if(this.prefs.show_sample_data){var ai=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ad=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ad,"line-height":ad});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(af,ae,ah){c.call(this,af,ae,ah);var ag=j.get_random_color(),ad=j.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 and sense strand color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ad},{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:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ah.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(af.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};o(T.prototype,p.prototype,N.prototype,c.prototype);var d={CompositeTrack:e,DrawableGroup:P,DiagonalHeatmapTrack:r,FeatureTrack:c,LineTrack:g,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var n=function(af,ae,ad){if("copy" in af){return af.copy(ad)}else{var ag=af.obj_type;if(!ag){ag=af.track_type}return new d[ag](ae,ad,af)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:g,FeatureTrack:c,DiagonalHeatmapTrack:r,ReadTrack:T,VariantTrack:Z,CompositeTrack:e,object_from_template:n}});
\ No newline at end of file
+define(["libs/underscore","viz/visualization","viz/trackster/util","viz/trackster/slotting","viz/trackster/painters","viz/trackster/filters","mvc/data","mvc/tools"],function(ac,w,j,s,L,h,X,R){var o=ac.extend;var l={};var i=function(ad,ae){l[ad.attr("id")]=ae};var k=function(ad,af,ah,ag){ah=".group";var ae={};l[ad.attr("id")]=ag;ad.bind("drag",{handle:"."+af,relative:true},function(ap,aq){var ao=$(this),au=$(this).parent(),al=au.children(),an=l[$(this).attr("id")],ak,aj,ar,ai,am;aj=$(this).parents(ah);if(aj.length!==0){ar=aj.position().top;ai=ar+aj.outerHeight();if(aq.offsetY<ar){$(this).insertBefore(aj);var at=l[aj.attr("id")];at.remove_drawable(an);at.container.add_drawable_before(an,at);return}else{if(aq.offsetY>ai){$(this).insertAfter(aj);var at=l[aj.attr("id")];at.remove_drawable(an);at.container.add_drawable(an);return}}}aj=null;for(am=0;am<al.length;am++){ak=$(al.get(am));ar=ak.position().top;ai=ar+ak.outerHeight();if(ak.is(ah)&&this!==ak.get(0)&&aq.offsetY>=ar&&aq.offsetY<=ai){if(aq.offsetY-ar<ai-aq.offsetY){ak.find(".content-div").prepend(this)}else{ak.find(".content-div").append(this)}if(an.container){an.container.remove_drawable(an)}l[ak.attr("id")].add_drawable(an);return}}for(am=0;am<al.length;am++){ak=$(al.get(am));if(aq.offsetY<ak.position().top&&!(ak.hasClass("reference-track")||ak.hasClass("intro"))){break}}if(am===al.length){if(this!==al.get(am-1)){au.append(this);l[au.attr("id")].move_drawable(an,am)}}else{if(this!==al.get(am)){$(this).insertBefore(al.get(am));l[au.attr("id")].move_drawable(an,(aq.deltaY>0?am-1:am))}}}).bind("dragstart",function(){ae["border-top"]=ad.css("border-top");ae["border-bottom"]=ad.css("border-bottom");$(this).css({"border-top":"1px solid blue","border-bottom":"1px solid blue"})}).bind("dragend",function(){$(this).css(ae)})};var aa=16,G=9,D=20,z=100,I=12000,S=400,K=5000,v=100,m="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.",u="Preparing data. This can take a while for a large dataset. If the visualization is saved and closed, preparation will continue in the background.",x="Tool cannot be rerun: ",a="Loading data...",U="Ready for display",Q=10,H=20,A=["Histogram","Line","Filled","Intensity"];function V(ae,ad){if(!ad){ad=0}var af=Math.pow(10,ad);return Math.round(ae*af)/af}var p=function(ae,ad,ag){if(!p.id_counter){p.id_counter=0}this.id=p.id_counter++;this.name=ag.name;this.view=ae;this.container=ad;this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name}],saved_values:ag.prefs,onchange:function(){this.track.set_name(this.track.config.values.name)}});this.prefs=this.config.values;this.drag_handle_class=ag.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(ah){ah.stopPropagation()});var af=this;this.container_div.hover(function(){af.icons_div.show()},function(){af.icons_div.hide()});$("<div style='clear: both'/>").appendTo(this.container_div)}};p.prototype.action_icons_def=[{name:"toggle_icon",title:"Hide/show content",css_class:"toggle",on_click_fn:function(ad){if(ad.content_visible){ad.action_icons.toggle_icon.addClass("toggle-expand").removeClass("toggle");ad.hide_contents();ad.content_visible=false}else{ad.action_icons.toggle_icon.addClass("toggle").removeClass("toggle-expand");ad.content_visible=true;ad.show_contents()}}},{name:"settings_icon",title:"Edit settings",css_class:"settings-icon",on_click_fn:function(ae){var ag=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ad=function(){ae.config.update_from_form($(".dialog-box"));hide_modal();$(window).unbind("keypress.check_enter_esc")},af=function(ah){if((ah.keyCode||ah.which)===27){ag()}else{if((ah.keyCode||ah.which)===13){ad()}}};$(window).bind("keypress.check_enter_esc",af);show_modal("Configure",ae.config.build_form(),{Cancel:ag,OK:ad})}},{name:"remove_icon",title:"Remove",css_class:"remove-icon",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.remove()}}];o(p.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(ad){},to_dict:function(){},set_name:function(ad){this.old_name=this.name;this.name=ad;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 ad=this.view;this.container_div.hide(0,function(){$(this).remove();ad.update_intro_div()})},build_container_div:function(){},build_header_div:function(){},add_action_icon:function(ae,aj,ai,ah,ad,ag){var af=this;this.action_icons[ae]=$("<a/>").attr("href","javascript:void(0);").attr("title",aj).addClass("icon-button").addClass(ai).tooltip().click(function(){ah(af)}).appendTo(this.icons_div);if(ag){this.action_icons[ae].hide()}},build_action_icons:function(ad){var af;for(var ae=0;ae<ad.length;ae++){af=ad[ae];this.add_action_icon(af.name,af.title,af.css_class,af.on_click_fn,af.prepend,af.hide)}},update_icons:function(){},hide_contents:function(){},show_contents:function(){},get_drawables:function(){}});var y=function(ae,ad,af){p.call(this,ae,ad,af);this.obj_type=af.obj_type;this.drawables=[]};o(y.prototype,p.prototype,{unpack_drawables:function(af){this.drawables=[];var ae;for(var ad=0;ad<af.length;ad++){ae=n(af[ad],this.view,this);this.add_drawable(ae)}},init:function(){for(var ad=0;ad<this.drawables.length;ad++){this.drawables[ad].init()}},_draw:function(ad){for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae]._draw(ad)}},to_dict:function(){var ae=[];for(var ad=0;ad<this.drawables.length;ad++){ae.push(this.drawables[ad].to_dict())}return{name:this.name,prefs:this.prefs,obj_type:this.obj_type,drawables:ae}},add_drawable:function(ad){this.drawables.push(ad);ad.container=this;this.changed()},add_drawable_before:function(af,ad){this.changed();var ae=this.drawables.indexOf(ad);if(ae!==-1){this.drawables.splice(ae,0,af);return true}return false},replace_drawable:function(af,ad,ae){var ag=this.drawables.indexOf(af);if(ag!==-1){this.drawables[ag]=ad;if(ae){af.container_div.replaceWith(ad.container_div)}this.changed()}return ag},remove_drawable:function(ae){var ad=this.drawables.indexOf(ae);if(ad!==-1){this.drawables.splice(ad,1);ae.container=null;this.changed();return true}return false},move_drawable:function(ae,af){var ad=this.drawables.indexOf(ae);if(ad!==-1){this.drawables.splice(ad,1);this.drawables.splice(af,0,ae);this.changed();return true}return false},get_drawables:function(){return this.drawables},get_tracks:function(ag){var ad=this.drawables.slice(0),ae=[],af;while(ad.length!==0){af=ad.shift();if(af instanceof ag){ae.push(af)}else{if(af.drawables){ad=ad.concat(af.drawables)}}}return ae}});var P=function(ae,ad,ag){o(ag,{obj_type:"DrawableGroup",drag_handle_class:"group-handle"});y.call(this,ae,ad,ag);this.content_div=$("<div/>").addClass("content-div").attr("id","group_"+this.id+"_content_div").appendTo(this.container_div);i(this.container_div,this);i(this.content_div,this);k(this.container_div,this.drag_handle_class,".group",this);this.filters_manager=new h.FiltersManager(this);this.header_div.after(this.filters_manager.parent_div);this.saved_filters_managers=[];if("drawables" in ag){this.unpack_drawables(ag.drawables)}if("filters" in ag){var af=this.filters_manager;this.filters_manager=new h.FiltersManager(this,ag.filters);af.parent_div.replaceWith(this.filters_manager.parent_div);if(ag.filters.visible){this.setup_multitrack_filtering()}}};o(P.prototype,p.prototype,y.prototype,{action_icons_def:[p.prototype.action_icons_def[0],p.prototype.action_icons_def[1],{name:"composite_icon",title:"Show composite track",css_class:"layers-stack",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.show_composite_track()}},{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ad){if(ad.filters_manager.visible()){ad.filters_manager.clear_filters();ad._restore_filter_managers()}else{ad.setup_multitrack_filtering();ad.request_draw({clear_tile_cache:true})}ad.filters_manager.toggle()}},p.prototype.action_icons_def[2]],build_container_div:function(){var ad=$("<div/>").addClass("group").attr("id","group_"+this.id);if(this.container){this.container.content_div.append(ad)}return ad},build_header_div:function(){var ad=$("<div/>").addClass("track-header");ad.append($("<div/>").addClass(this.drag_handle_class));this.name_div=$("<div/>").addClass("track-name").text(this.name).appendTo(ad);return ad},hide_contents:function(){this.tiles_div.hide()},show_contents:function(){this.tiles_div.show();this.request_draw()},update_icons:function(){var af=this.drawables.length;if(af===0){this.action_icons.composite_icon.hide();this.action_icons.filters_icon.hide()}else{if(af===1){if(this.drawables[0] instanceof e){this.action_icons.composite_icon.show()}this.action_icons.filters_icon.hide()}else{var am,al,aj,ap=true,ah=this.drawables[0].get_type(),ad=0;for(am=0;am<af;am++){aj=this.drawables[am];if(aj.get_type()!==ah){can_composite=false;break}if(aj instanceof c){ad++}}if(ap||ad===1){this.action_icons.composite_icon.show()}else{this.action_icons.composite_icon.hide();$(".bs-tooltip").remove()}if(ad>1&&ad===this.drawables.length){var aq={},ae;aj=this.drawables[0];for(al=0;al<aj.filters_manager.filters.length;al++){ae=aj.filters_manager.filters[al];aq[ae.name]=[ae]}for(am=1;am<this.drawables.length;am++){aj=this.drawables[am];for(al=0;al<aj.filters_manager.filters.length;al++){ae=aj.filters_manager.filters[al];if(ae.name in aq){aq[ae.name].push(ae)}}}this.filters_manager.remove_all();var ag,ai,ak,an;for(var ao in aq){ag=aq[ao];if(ag.length===ad){ai=new h.NumberFilter({name:ag[0].name,index:ag[0].index});this.filters_manager.add_filter(ai)}}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 ad=0;ad<this.drawables.length;ad++){this.drawables[ad].filters_manager=this.saved_filters_managers[ad]}this.saved_filters_managers=[]},setup_multitrack_filtering:function(){if(this.filters_manager.filters.length>0){this.saved_filters_managers=[];for(var ad=0;ad<this.drawables.length;ad++){drawable=this.drawables[ad];this.saved_filters_managers.push(drawable.filters_manager);drawable.filters_manager=this.filters_manager}}this.filters_manager.init_filters()},show_composite_track:function(){var ae=new e(this.view,this.view,{name:this.name,drawables:this.drawables});var ad=this.container.replace_drawable(this,ae,true);ae.request_draw()},add_drawable:function(ad){y.prototype.add_drawable.call(this,ad);this.update_icons()},remove_drawable:function(ad){y.prototype.remove_drawable.call(this,ad);this.update_icons()},to_dict:function(){if(this.filters_manager.visible()){this._restore_filter_managers()}var ad=o(y.prototype.to_dict.call(this),{filters:this.filters_manager.to_dict()});if(this.filters_manager.visible()){this.setup_multitrack_filtering()}return ad},request_draw:function(ad){ac.each(this.drawables,function(ae){ae.request_draw(ad)})}});var Y=Backbone.View.extend({initialize:function(ad){o(ad,{obj_type:"View"});y.call(this,"View",ad.container,ad);this.chrom=null;this.vis_id=ad.vis_id;this.dbkey=ad.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 w.CanvasManager(this.container.get(0).ownerDocument);this.reset();this.config=new F({track:this,params:[{key:"a_color",label:"A Color",type:"color",default_value:"#FF0000"},{key:"c_color",label:"C Color",type:"color",default_value:"#00FF00"},{key:"g_color",label:"G Color",type:"color",default_value:"#0000FF"},{key:"t_color",label:"T Color",type:"color",default_value:"#FF00FF"},{key:"n_color",label:"N Color",type:"color",default_value:"#AAAAAA"}],saved_values:ad.prefs,onchange:function(){track.request_redraw({clear_tile_cache:true})}})},render:function(){this.requested_redraw=false;var af=this.container,ad=this;this.top_container=$("<div/>").addClass("top-container").appendTo(af);this.browser_content_div=$("<div/>").addClass("content").css("position","relative").appendTo(af);this.bottom_container=$("<div/>").addClass("bottom-container").appendTo(af);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;i(this.viewport_container,ad);this.intro_div=$("<div/>").addClass("intro").appendTo(this.viewport_container).hide();var ag=$("<div/>").text("Add Datasets to Visualization").addClass("action-button").appendTo(this.intro_div).click(function(){w.select_datasets(galaxy_config.root+"visualization/list_current_history_datasets",galaxy_config.root+"api/datasets",{"f-dbkey":ad.dbkey},function(ah){ac.each(ah,function(ai){ad.add_drawable(n(ai,ad,ad))})})});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 ae=function(ah){if(ah.type==="focusout"||(ah.keyCode||ah.which)===13||(ah.keyCode||ah.which)===27){if((ah.keyCode||ah.which)!==27){ad.go_to($(this).val())}$(this).hide();$(this).val("");ad.location_span.show();ad.chrom_select.show()}};this.nav_input=$("<input/>").addClass("nav-input").hide().bind("keyup focusout",ae).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(){ad.location_span.hide();ad.chrom_select.hide();ad.nav_input.val(ad.chrom+":"+ad.low+"-"+ad.high);ad.nav_input.css("display","inline-block");ad.nav_input.select();ad.nav_input.focus();ad.nav_input.autocomplete({source:function(aj,ah){var ak=[],ai=$.map(ad.get_tracks(c),function(al){return al.data_manager.search_features(aj.term).success(function(am){ak=ak.concat(am)})});$.when.apply($,ai).done(function(){ah($.map(ak,function(al){return{label:al[0],value:al[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(){ad.zoom_out();ad.request_redraw()}).appendTo(this.nav_controls);this.zi_link=$("<a/>").attr("id","zoom-in").attr("title","Zoom in").tooltip({placement:"bottom"}).click(function(){ad.zoom_in();ad.request_redraw()}).appendTo(this.nav_controls);this.load_chroms_deferred=this.load_chroms({low:0});this.chrom_select.bind("change",function(){ad.change_chrom(ad.chrom_select.val())});this.browser_content_div.click(function(ah){$(this).find("input").trigger("blur")});this.browser_content_div.bind("dblclick",function(ah){ad.zoom_in(ah.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(ah,ai){this.current_x=ai.offsetX}).bind("drag",function(ah,aj){var ak=aj.offsetX-this.current_x;this.current_x=aj.offsetX;var ai=Math.round(ak/ad.viewport_container.width()*(ad.max_high-ad.max_low));ad.move_delta(-ai)});this.overview_close.click(function(){ad.reset_overview()});this.viewport_container.bind("draginit",function(ah,ai){if(ah.clientX>ad.viewport_container.width()-16){return false}}).bind("dragstart",function(ah,ai){ai.original_low=ad.low;ai.current_height=ah.clientY;ai.current_x=ai.offsetX}).bind("drag",function(aj,al){var ah=$(this);var am=al.offsetX-al.current_x;var ai=ah.scrollTop()-(aj.clientY-al.current_height);ah.scrollTop(ai);al.current_height=aj.clientY;al.current_x=al.offsetX;var ak=Math.round(am/ad.viewport_container.width()*(ad.high-ad.low));ad.move_delta(ak)}).bind("mousewheel",function(aj,al,ai,ah){if(ai){ai*=50;var ak=Math.round(-ai/ad.viewport_container.width()*(ad.high-ad.low));ad.move_delta(ak)}});this.top_labeltrack.bind("dragstart",function(ah,ai){return $("<div />").css({height:ad.browser_content_div.height()+ad.top_labeltrack.height()+ad.nav_labeltrack.height()+1,top:"0px",position:"absolute","background-color":"#ccf",opacity:0.5,"z-index":1000}).appendTo($(this))}).bind("drag",function(al,am){$(am.proxy).css({left:Math.min(al.pageX,am.startX)-ad.container.offset().left,width:Math.abs(al.pageX-am.startX)});var ai=Math.min(al.pageX,am.startX)-ad.container.offset().left,ah=Math.max(al.pageX,am.startX)-ad.container.offset().left,ak=(ad.high-ad.low),aj=ad.viewport_container.width();ad.update_location(Math.round(ai/aj*ak)+ad.low,Math.round(ah/aj*ak)+ad.low)}).bind("dragend",function(am,an){var ai=Math.min(am.pageX,an.startX),ah=Math.max(am.pageX,an.startX),ak=(ad.high-ad.low),aj=ad.viewport_container.width(),al=ad.low;ad.low=Math.round(ai/aj*ak)+al;ad.high=Math.round(ah/aj*ak)+al;$(an.proxy).remove();ad.request_redraw()});this.add_label_track(new W(this,{content_div:this.top_labeltrack}));this.add_label_track(new W(this,{content_div:this.nav_labeltrack}));$(window).bind("resize",function(){if(this.resize_timer){clearTimeout(this.resize_timer)}this.resize_timer=setTimeout(function(){ad.resize_window()},500)});$(document).bind("redraw",function(){ad.redraw()});this.reset();$(window).trigger("resize")},get_base_color:function(ad){return this.config.values[ad.toLowerCase()+"_color"]||this.config.values.n_color}});o(Y.prototype,y.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(ae,ag,ad,ah){if(this.timer){clearTimeout(this.timer)}if(ah){var af=this;this.timer=setTimeout(function(){af.trigger("navigate",ae+":"+ag+"-"+ad)},500)}else{view.trigger("navigate",ae+":"+ag+"-"+ad)}},update_location:function(ad,af){this.location_span.text(commatize(ad)+" - "+commatize(af));this.nav_input.val(this.chrom+":"+commatize(ad)+"-"+commatize(af));var ae=view.chrom_select.val();if(ae!==""){this.trigger_navigate(ae,view.low,view.high,true)}},load_chroms:function(af){af.num=v;var ad=this,ae=$.Deferred();$.ajax({url:galaxy_config.root+"api/genomes/"+this.dbkey,data:af,dataType:"json",success:function(ah){if(ah.chrom_info.length===0){return}if(ah.reference){ad.add_label_track(new B(ad))}ad.chrom_data=ah.chrom_info;var ak='<option value="">Select Chrom/Contig</option>';for(var aj=0,ag=ad.chrom_data.length;aj<ag;aj++){var ai=ad.chrom_data[aj].chrom;ak+='<option value="'+ai+'">'+ai+"</option>"}if(ah.prev_chroms){ak+='<option value="previous">Previous '+v+"</option>"}if(ah.next_chroms){ak+='<option value="next">Next '+v+"</option>"}ad.chrom_select.html(ak);ad.chrom_start_index=ah.start_index;ae.resolve(ah.chrom_info)},error:function(){alert("Could not load chroms for this dbkey:",ad.dbkey)}});return ae},change_chrom:function(ai,ae,ak){var af=this;if(!af.chrom_data){af.load_chroms_deferred.then(function(){af.change_chrom(ai,ae,ak)});return}if(!ai||ai==="None"){return}if(ai==="previous"){af.load_chroms({low:this.chrom_start_index-v});return}if(ai==="next"){af.load_chroms({low:this.chrom_start_index+v});return}var aj=$.grep(af.chrom_data,function(al,am){return al.chrom===ai})[0];if(aj===undefined){af.load_chroms({chrom:ai},function(){af.change_chrom(ai,ae,ak)});return}else{if(ai!==af.chrom){af.chrom=ai;af.chrom_select.val(af.chrom);af.max_high=aj.len-1;af.reset();for(var ah=0,ad=af.drawables.length;ah<ad;ah++){var ag=af.drawables[ah];if(ag.init){ag.init()}}if(af.reference_track){af.reference_track.init()}}if(ae&&ak){af.low=Math.max(ae,0);af.high=Math.min(ak,af.max_high)}else{af.low=0;af.high=af.max_high}af.reset_overview();af.request_redraw()}},go_to:function(ah){ah=ah.replace(/,/g,"");ah=ah.replace(/:|\-/g," ");var ae=ah.split(/\s+/),ag=ae[0],af=(ae[1]?parseInt(ae[1],10):null),ad=(ae[2]?parseInt(ae[2],10):null);if(!ad){af=af-15;ad=af+15}this.change_chrom(ag,af,ad)},move_fraction:function(af){var ad=this;var ae=ad.high-ad.low;this.move_delta(af*ae)},move_delta:function(ag){var ad=this;var af=ad.high-ad.low;if(ad.low-ag<ad.max_low){ad.low=ad.max_low;ad.high=ad.max_low+af}else{if(ad.high-ag>ad.max_high){ad.high=ad.max_high;ad.low=ad.max_high-af}else{ad.high-=ag;ad.low-=ag}}ad.request_redraw({data_fetch:false});if(this.redraw_on_move_fn){clearTimeout(this.redraw_on_move_fn)}this.redraw_on_move_fn=setTimeout(function(){ad.request_redraw()},200);var ae=ad.chrom_select.val();this.trigger_navigate(ae,ad.low,ad.high,true)},add_drawable:function(ad){y.prototype.add_drawable.call(this,ad);ad.init();this.changed();this.update_intro_div()},add_label_track:function(ad){ad.view=this;ad.init();this.label_tracks.push(ad)},remove_drawable:function(af,ae){y.prototype.remove_drawable.call(this,af);if(ae){var ad=this;af.container_div.hide(0,function(){$(this).remove();ad.update_intro_div()})}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},request_redraw:function(ae,af){var ad=this,ag=(af?[af]:ad.drawables);ac.each(ag,function(ah){var ai=ac.find(ad.tracks_to_be_redrawn,function(aj){return aj[0]===ah});if(ai){ai[1]=ae}else{ad.tracks_to_be_redrawn.push([ah,ae])}});if(!this.requested_redraw){requestAnimationFrame(function(){ad._redraw()});this.requested_redraw=true}},_redraw:function(){this.requested_redraw=false;var ad=this.low,ah=this.high;if(ad<this.max_low){ad=this.max_low}if(ah>this.max_high){ah=this.max_high}var ae=this.high-this.low;if(this.high!==0&&ae<this.min_separation){ah=ad+this.min_separation}this.low=Math.floor(ad);this.high=Math.ceil(ah);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 ag=(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 af=13;this.overview_box.css({left:ag,width:Math.max(af,ai)}).show();if(ai<af){this.overview_box.css("left",ag-(af-ai)/2)}if(this.overview_highlight){this.overview_highlight.css({left:ag,width:ai})}ac.each(this.tracks_to_be_redrawn,function(al){var aj=al[0],ak=al[1];if(aj){aj._draw(ak)}});this.tracks_to_be_redrawn=[];ac.each(this.label_tracks,function(aj){aj._draw()})},zoom_in:function(ae,af){if(this.max_high===0||this.high-this.low<=this.min_separation){return}var ag=this.high-this.low,ah=ag/2+this.low,ad=(ag/this.zoom_factor)/2;if(ae){ah=ae/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(ah-ad);this.high=Math.round(ah+ad);this.changed();this.request_redraw()},zoom_out:function(){if(this.max_high===0){return}var ae=this.high-this.low,af=ae/2+this.low,ad=(ae*this.zoom_factor)/2;this.low=Math.round(af-ad);this.high=Math.round(af+ad);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(af){if(this.overview_drawable){if(this.overview_drawable.dataset.id===af.dataset.id){return}this.overview_viewport.find(".track").remove()}var ae=af.copy({content_div:this.overview_viewport}),ad=this;ae.header_div.hide();ae.is_overview=true;ad.overview_drawable=ae;this.overview_drawable.postdraw_actions=function(){ad.overview_highlight.show().height(ad.overview_drawable.content_div.height());ad.overview_viewport.height(ad.overview_drawable.content_div.height()+ad.overview_box.outerHeight());ad.overview_close.show();ad.resize_window()};ad.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 q=R.Tool.extend({defaults:{track:null},initialize:function(ad){if(ad.tool_state!==undefined){this.set("hidden",ad.tool_state.hidden)}this.remove_inputs(["data","hidden_data","conditional"])},state_dict:function(ad){return ac.extend(this.get_inputs_dict(),{hidden:!this.is_visible()})}});var t=Backbone.View.extend({events:{"change input":"update_value"},render:function(){var af=this.$el.addClass("param-row"),ag=this.model;var ad=$("<div>").addClass("param-label").text(ag.get("label")).appendTo(af);var ae=$("<div/>").addClass("param-input").html(ag.get("html")).appendTo(af);ae.find(":input").val(ag.get("value"));$("<div style='clear: both;'/>").appendTo(af)},update_value:function(ad){this.model.set_value($(ad.target).val())}});var ab=Backbone.View.extend({initialize:function(ad){this.model.on("change:hidden",this.set_visible,this)},render:function(){var ae=this;tool=this.model,parent_div=this.$el.addClass("dynamic-tool").hide();parent_div.bind("drag",function(ai){ai.stopPropagation()}).click(function(ai){ai.stopPropagation()}).bind("dblclick",function(ai){ai.stopPropagation()}).keydown(function(ai){ai.stopPropagation()});var af=$("<div class='tool-name'>").appendTo(parent_div).text(tool.get("name"));tool.get("inputs").each(function(aj){var ai=new t({model:aj});ai.render();parent_div.append(ai.$el)});parent_div.find("input").click(function(){$(this).select()});var ag=$("<div>").addClass("param-row").appendTo(parent_div);var ah=$("<input type='submit'>").attr("value","Run on complete dataset").appendTo(ag);var ad=$("<input type='submit'>").attr("value","Run on visible region").css("margin-left","3em").appendTo(ag);ad.click(function(){ae.run_on_region()});ah.click(function(){ae.run_on_dataset()});if(tool.is_visible()){this.$el.show()}},set_visible:function(){if(this.model.is_visible()){this.$el.show()}else{this.$el.hide()}},update_params:function(){for(var ad=0;ad<this.params.length;ad++){this.params[ad].update_value()}},run_on_dataset:function(){var ad=this.model;this.run({target_dataset_id:this.model.get("track").dataset.id,action:"rerun",tool_id:ad.id},null,function(ae){show_modal(ad.get("name")+" is Running",ad.get("name")+" is running on the complete dataset. Tool outputs are in dataset's history.",{Close:hide_modal})})},run_on_region:function(){var ae=this.model.get("track"),ah=this.model,aj=new w.GenomeRegion({chrom:ae.view.chrom,start:ae.view.low,end:ae.view.high}),ak={target_dataset_id:ae.dataset.id,action:"rerun",tool_id:ah.id,regions:[aj.toJSON()]},ai=ae,am=ak.tool_id+ai.tool_region_and_parameters_str(aj),ad;if(ai.container===view){var al=new P(view,view,{name:this.name});var ag=ai.container.replace_drawable(ai,al,false);al.container_div.insertBefore(ai.view.content_div.children()[ag]);al.add_drawable(ai);ai.container_div.appendTo(al.content_div);ad=al}else{ad=ai.container}var af=new ai.constructor(view,ad,{name:am,hda_ldda:"hda"});af.init_for_tool_data();af.change_mode(ai.mode);af.set_filters_manager(ai.filters_manager.copy(af));af.update_icons();ad.add_drawable(af);af.tiles_div.text("Starting job.");this.run(ak,af,function(an){af.set_dataset(new X.Dataset(an));af.tiles_div.text("Running job.");af.init()})},run:function(ad,af,ag){ad.inputs=this.model.get_inputs_dict();var ae=new j.ServerStateDeferred({ajax_settings:{url:galaxy_config.root+"api/tools",data:JSON.stringify(ad),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(ah){return ah!=="pending"}});$.when(ae.go()).then(function(ah){if(ah==="no converter"){af.container_div.addClass("error");af.content_div.text(J)}else{if(ah.error){af.container_div.addClass("error");af.content_div.text(x+ah.message)}else{ag(ah)}}})}});var C=function(ad,ae){L.Scaler.call(this,ae);this.filter=ad};C.prototype.gen_val=function(ad){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(ad[this.filter.index])-this.filter.low)/(this.filter.high-this.filter.low))};var F=function(ad){this.track=ad.track;this.params=ad.params;this.values={};this.restore_values((ad.saved_values?ad.saved_values:{}));this.onchange=ad.onchange};o(F.prototype,{set_param_default_value:function(ae,ad){var af=ac.find(this.params,function(ag){return ag.key===ae});if(af){af.default_value=ad}},set_param_value:function(ad,ae){var af=ac.find(this.params,function(ag){return ag.key===ad});if(af){if(typeof ae==="string"||ae instanceof String){if(ae.trim()===""){ae=af.default_value}else{if(af.type==="float"){ae=parseFloat(ae)}else{if(af.type==="int"){ae=parseInt(ae,10)}}}}}if(this.values[ad]!==ae){this.values[ad]=ae;return true}else{return false}},restore_values:function(ad){var ae=this;$.each(this.params,function(af,ag){if(ad[ag.key]!==undefined){ae.values[ag.key]=ad[ag.key]}else{ae.values[ag.key]=ag.default_value}})},build_form:function(){var ag=this;var ad=$("<div />");var af;function ae(al,ah){for(var ap=0;ap<al.length;ap++){af=al[ap];if(af.hidden){continue}var aj="param_"+ap;var au=ag.values[af.key];var aw=$("<div class='form-row' />").appendTo(ah);aw.append($("<label />").attr("for",aj).text(af.label+":"));if(af.type==="bool"){aw.append($('<input type="checkbox" />').attr("id",aj).attr("name",aj).attr("checked",au))}else{if(af.type==="text"){aw.append($('<input type="text"/>').attr("id",aj).val(au).click(function(){$(this).select()}))}else{if(af.type==="select"){var ar=$("<select />").attr("id",aj);for(var an=0;an<af.options.length;an++){$("<option/>").text(af.options[an].label).attr("value",af.options[an].value).appendTo(ar)}ar.val(au);aw.append(ar)}else{if(af.type==="color"){var av=$("<div/>").appendTo(aw),aq=$("<input />").attr("id",aj).attr("name",aj).val(au).css("float","left").appendTo(av).click(function(ay){$(".bs-tooltip").removeClass("in");var ax=$(this).siblings(".bs-tooltip").addClass("in");ax.css({left:$(this).position().left+$(this).width()+5,top:$(this).position().top-($(ax).height()/2)+($(this).height()/2)}).show();ax.click(function(az){az.stopPropagation()});$(document).bind("click.color-picker",function(){ax.hide();$(document).unbind("click.color-picker")});ay.stopPropagation()}),ao=$("<a href='javascript:void(0)'/>").addClass("icon-button arrow-circle").appendTo(av).attr("title","Set new random color").tooltip(),at=$("<div class='bs-tooltip right' style='position: absolute;' />").appendTo(av).hide(),ak=$("<div class='tooltip-inner' style='text-align: inherit'></div>").appendTo(at),ai=$("<div class='tooltip-arrow'></div>").appendTo(at),am=$.farbtastic(ak,{width:100,height:100,callback:aq,color:au});av.append($("<div/>").css("clear","both"));(function(ax){ao.click(function(){ax.setColor(j.get_random_color())})})(am)}else{aw.append($("<input />").attr("id",aj).attr("name",aj).val(au))}}}}if(af.help){aw.append($("<div class='help'/>").text(af.help))}}}ae(this.params,ad);return ad},update_from_form:function(ad){var af=this;var ae=false;$.each(this.params,function(ag,ai){if(!ai.hidden){var aj="param_"+ag;var ah=ad.find("#"+aj).val();if(ai.type==="bool"){ah=ad.find("#"+aj).is(":checked")}ae=af.set_param_value(ai.key,ah)||ae}});if(ae){this.onchange();this.track.changed()}}});var b=function(ad,ah,af,ae,ag){this.track=ad;this.region=ah;this.low=ah.get("start");this.high=ah.get("end");this.resolution=af;this.html_elt=$("<div class='track-tile'/>").append(ae).height($(ae).attr("height"));this.data=ag;this.stale=false};b.prototype.predisplay_actions=function(){};var M=function(ad,ah,af,ae,ag){b.call(this,ad,ah,af,ae,ag)};M.prototype.predisplay_actions=function(){};var O=function(ag,ao,ah,af,aj,aq,ak,ar,ae,an){b.call(this,ag,ao,ah,af,aj);this.mode=ak;this.all_slotted=ae;this.feature_mapper=an;this.has_icons=false;if(ar){this.has_icons=true;var al=this;af=this.html_elt.children()[0],message_div=$("<div/>").addClass("tile-message").css({height:D-1,width:af.width}).prependTo(this.html_elt);var am=new w.GenomeRegion({chrom:ag.view.chrom,start:this.low,end:this.high}),ap=aj.length,ai=$("<a href='javascript:void(0);'/>").addClass("icon more-down").attr("title","For speed, only the first "+ap+" features in this region were obtained from server. Click to get more data including depth").tooltip().appendTo(message_div),ad=$("<a href='javascript:void(0);'/>").addClass("icon more-across").attr("title","For speed, only the first "+ap+" features in this region were obtained from server. Click to get more data excluding depth").tooltip().appendTo(message_div);ai.click(function(){al.stale=true;ag.data_manager.get_more_data(am,ag.mode,al.resolution,{},ag.data_manager.DEEP_DATA_REQ);$(".bs-tooltip").hide();ag.request_draw()}).dblclick(function(at){at.stopPropagation()});ad.click(function(){al.stale=true;ag.data_manager.get_more_data(am,ag.mode,al.resolution,{},ag.data_manager.BROAD_DATA_REQ);$(".bs-tooltip").hide();ag.request_draw()}).dblclick(function(at){at.stopPropagation()})}};o(O.prototype,b.prototype);O.prototype.predisplay_actions=function(){var ae=this,ad={};if(ae.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(ap){if(!this.hovered){return}var ak=$(this).offset(),ao=ap.pageX-ak.left,an=ap.pageY-ak.top,au=ae.feature_mapper.get_feature_data(ao,an),al=(au?au[0]:null);$(this).parents(".track-content").children(".overlay").children(".feature-popup").each(function(){if(!al||$(this).attr("id")!==al.toString()){$(this).remove()}});if(au){var ag=ad[al];if(!ag){var al=au[0],aq={name:au[3],start:au[1],end:au[2],strand:au[4]},aj=ae.track.filters_manager.filters,ai;for(var am=0;am<aj.length;am++){ai=aj[am];aq[ai.name]=au[ai.index]}var ag=$("<div/>").attr("id",al).addClass("feature-popup"),av=$("<table/>"),at,ar,aw;for(at in aq){ar=aq[at];aw=$("<tr/>").appendTo(av);$("<th/>").appendTo(aw).text(at);$("<td/>").attr("align","left").appendTo(aw).text(typeof(ar)==="number"?V(ar,2):ar)}ag.append($("<div class='feature-popup-inner'>").append(av));ad[al]=ag}ag.appendTo($(this).parents(".track-content").children(".overlay"));var ah=ao+parseInt(ae.html_elt.css("left"))-ag.width()/2,af=an+parseInt(ae.html_elt.css("top"))+7;ag.css("left",ah+"px").css("top",af+"px")}else{if(!ap.isPropagationStopped()){ap.stopPropagation();$(this).siblings().each(function(){$(this).trigger(ap)})}}}).mouseleave(function(){$(this).parents(".track-content").children(".overlay").children(".feature-popup").remove()})};var f=function(ae,ad,af){o(af,{drag_handle_class:"draghandle"});p.call(this,ae,ad,af);this.dataset=null;if(af.dataset){this.dataset=(af.dataset instanceof Backbone.Model?af.dataset:new X.Dataset(af.dataset))}this.dataset_check_type="converted_datasets_state";this.data_url_extra_params={};this.data_query_wait=("data_query_wait" in af?af.data_query_wait:K);this.data_manager=("data_manager" in af?af.data_manager:new w.GenomeDataManager({dataset:this.dataset,genome:new w.Genome({key:ae.dbkey,chroms_info:{chrom_info:ae.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 af)||af.resize){this.add_resize_handle()}}};o(f.prototype,p.prototype,{action_icons_def:[{name:"mode_icon",title:"Set display mode",css_class:"chevron-expand",on_click_fn:function(){}},p.prototype.action_icons_def[0],{name:"overview_icon",title:"Set as overview",css_class:"overview-icon",on_click_fn:function(ad){ad.view.set_overview(ad)}},p.prototype.action_icons_def[1],{name:"filters_icon",title:"Filters",css_class:"filters-icon",on_click_fn:function(ad){if(ad.filters_manager.visible()){ad.filters_manager.clear_filters()}else{ad.filters_manager.init_filters()}ad.filters_manager.toggle()}},{name:"tools_icon",title:"Tool",css_class:"hammer",on_click_fn:function(ad){ad.tool.toggle();if(ad.tool.is_visible()){ad.set_name(ad.name+ad.tool_region_and_parameters_str())}else{ad.revert_name()}$(".bs-tooltip").remove()}},{name:"param_space_viz_icon",title:"Tool parameter space visualization",css_class:"arrow-split",on_click_fn:function(ad){var ag='<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>',af=ac.template(ag,{track:ad});var ai=function(){hide_modal();$(window).unbind("keypress.check_enter_esc")},ae=function(){var ak=$('select[name="regions"] option:selected').val(),am,aj=new w.GenomeRegion({chrom:view.chrom,start:view.low,end:view.high}),al=ac.map($(".bookmark"),function(an){return new w.GenomeRegion({from_str:$(an).children(".position").text()})});if(ak==="cur"){am=[aj]}else{if(ak==="bookmarks"){am=al}else{am=[aj].concat(al)}}hide_modal();window.location.href=galaxy_config.root+"visualization/sweepster?"+$.param({dataset_id:ad.dataset.id,hda_ldda:ad.dataset.get("hda_ldda"),regions:JSON.stringify(new Backbone.Collection(am).toJSON())})},ah=function(aj){if((aj.keyCode||aj.which)===27){ai()}else{if((aj.keyCode||aj.which)===13){ae()}}};show_modal("Visualize tool parameter space and output from different parameter settings?",af,{No:ai,Yes:ae})}},p.prototype.action_icons_def[2]],can_draw:function(){return this.dataset&&p.prototype.can_draw.call(this)},build_container_div:function(){return $("<div/>").addClass("track").attr("id","track_"+this.id).css("position","relative")},build_header_div:function(){var ad=$("<div class='track-header'/>");if(this.view.editor){this.drag_div=$("<div/>").addClass(this.drag_handle_class).appendTo(ad)}this.name_div=$("<div/>").addClass("track-name").appendTo(ad).text(this.name).attr("id",this.name.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9\-]/g,"").toLowerCase());return ad},set_dataset:function(ad){this.dataset=ad;this.data_manager.set("dataset",ad)},on_resize:function(){this.request_draw({clear_tile_cache:true})},add_resize_handle:function(){var ad=this;var ag=false;var af=false;var ae=$("<div class='track-resize'>");$(ad.container_div).hover(function(){if(ad.content_visible){ag=true;ae.show()}},function(){ag=false;if(!af){ae.hide()}});ae.hide().bind("dragstart",function(ah,ai){af=true;ai.original_height=$(ad.content_div).height()}).bind("drag",function(ai,aj){var ah=Math.min(Math.max(aj.original_height+aj.deltaY,ad.min_height_px),ad.max_height_px);$(ad.tiles_div).css("height",ah);ad.visible_height_px=(ad.max_height_px===ah?0:ah);ad.on_resize()}).bind("dragend",function(ah,ai){ad.tile_cache.clear();af=false;if(!ag){ae.hide()}ad.config.values.height=ad.visible_height_px;ad.changed()}).appendTo(ad.container_div)},set_display_modes:function(ag,aj){this.display_modes=ag;this.mode=(aj?aj:(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 ae=this,ah={};for(var af=0,ad=ae.display_modes.length;af<ad;af++){var ai=ae.display_modes[af];ah[ai]=function(ak){return function(){ae.change_mode(ak);ae.icons_div.show();ae.container_div.mouseleave(function(){ae.icons_div.hide()})}}(ai)}make_popupmenu(this.action_icons.mode_icon,ah)},build_action_icons:function(){p.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 W){return"LabelTrack"}else{if(this instanceof B){return"ReferenceTrack"}else{if(this instanceof g){return"LineTrack"}else{if(this instanceof T){return"ReadTrack"}else{if(this instanceof Z){return"VariantTrack"}else{if(this instanceof e){return"CompositeTrack"}else{if(this instanceof c){return"FeatureTrack"}}}}}}}return""},init:function(af){var ae=this;ae.enabled=false;ae.tile_cache.clear();ae.data_manager.clear();ae.tiles_div.css("height","auto");ae.tiles_div.text("").children().remove();ae.container_div.removeClass("nodata error pending");if(!ae.dataset.id){return}var ad=$.Deferred(),ag={hda_ldda:ae.dataset.get("hda_ldda"),data_type:this.dataset_check_type,chrom:ae.view.chrom,retry:af};$.getJSON(this.dataset.url(),ag,function(ah){if(!ah||ah==="error"||ah.kind==="error"){ae.container_div.addClass("error");ae.tiles_div.text(m);if(ah.message){ae.tiles_div.append($("<a href='javascript:void(0);'></a>").text("View error").click(function(){show_modal("Trackster Error","<pre>"+ah.message+"</pre>",{Close:hide_modal})}));ae.tiles_div.append($("<span/>").text(" "));ae.tiles_div.append($("<a href='javascript:void(0);'></a>").text("Try again").click(function(){ae.init(true)}))}}else{if(ah==="no converter"){ae.container_div.addClass("error");ae.tiles_div.text(J)}else{if(ah==="no data"||(ah.data!==undefined&&(ah.data===null||ah.data.length===0))){ae.container_div.addClass("nodata");ae.tiles_div.text(E)}else{if(ah==="pending"){ae.container_div.addClass("pending");ae.tiles_div.html(u);setTimeout(function(){ae.init()},ae.data_query_wait)}else{if(ah==="data"||ah.status==="data"){if(ah.valid_chroms){ae.valid_chroms=ah.valid_chroms;ae.update_icons()}ae.tiles_div.text(U);if(ae.view.chrom){ae.tiles_div.text("");ae.tiles_div.css("height",ae.visible_height_px+"px");ae.enabled=true;$.when.apply($,ae.predraw_init()).done(function(){ad.resolve();ae.container_div.removeClass("nodata error pending");ae.request_draw()})}else{ad.resolve()}}}}}}});this.update_icons();return ad},predraw_init:function(){var ad=this;return $.getJSON(ad.dataset.url(),{data_type:"data",stats:true,chrom:ad.view.chrom,low:0,high:ad.view.max_high,hda_ldda:ad.dataset.get("hda_ldda")},function(ae){ad.container_div.addClass("line-track");var ag=ae.data;if(ag&&ag.min&&ag.max){var af=ag.min,ah=ag.max;af=Math.floor(Math.min(0,Math.max(af,ag.mean-2*ag.sd)));ah=Math.ceil(Math.max(0,Math.min(ah,ag.mean+2*ag.sd)));ad.config.set_param_default_value("min_value",af);ad.config.set_param_default_value("max_value",ah);ad.prefs.min_value=af;ad.prefs.max_value=ah}})},get_drawables:function(){return this}});var N=function(af,ae,ah){f.call(this,af,ae,ah);var ad=this;k(ad.container_div,ad.drag_handle_class,".group",ad);this.filters_manager=new h.FiltersManager(this,("filters" in ah?ah.filters:null));this.data_manager.set("filters_manager",this.filters_manager);this.filters_available=false;this.tool=(ah.tool?new q(ac.extend(ah.tool,{track:this,tool_state:ah.tool_state})):null);this.tile_cache=new w.Cache(Q);this.left_offset=0;if(this.header_div){this.set_filters_manager(this.filters_manager);if(this.tool){var ag=new ab({model:this.tool});ag.render();this.dynamic_tool_div=ag.$el;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(ah.mode){this.change_mode(ah.mode)}};o(N.prototype,p.prototype,f.prototype,{action_icons_def:f.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(ad){$(".bs-tooltip").remove();ad.slotters[ad.view.resolution_px_b].max_rows*=2;ad.request_draw({clear_tile_cache:true})},hide:true}]),copy:function(ad){var ae=this.to_dict();o(ae,{data_manager:this.data_manager});var af=new this.constructor(this.view,ad,ae);af.change_mode(this.mode);af.enabled=this.enabled;return af},set_filters_manager:function(ad){this.filters_manager=ad;this.header_div.after(this.filters_manager.parent_div)},to_dict:function(){return{track_type:this.get_type(),name:this.name,dataset:{id:this.dataset.id,hda_ldda:this.dataset.get("hda_ldda")},prefs:this.prefs,mode:this.mode,filters:this.filters_manager.to_dict(),tool_state:(this.tool?this.tool.state_dict():{})}},set_min_max:function(){var ad=this;return $.getJSON(ad.dataset.url(),{data_type:"data",stats:true,chrom:ad.view.chrom,low:0,high:ad.view.max_high,hda_ldda:ad.dataset.get("hda_ldda")},function(ae){var ag=ae.data;if(isNaN(parseFloat(ad.prefs.min_value))||isNaN(parseFloat(ad.prefs.max_value))){var af=ag.min,ah=ag.max;af=Math.floor(Math.min(0,Math.max(af,ag.mean-2*ag.sd)));ah=Math.ceil(Math.max(0,Math.min(ah,ag.mean+2*ag.sd)));ad.prefs.min_value=af;ad.prefs.max_value=ah}})},change_mode:function(ae){var ad=this;ad.mode=ae;ad.config.values.mode=ae;if(ae==="Auto"){this.data_manager.clear()}ad.request_draw({clear_tile_cache:true});this.action_icons.mode_icon.attr("title","Set display mode (now: "+ad.mode+")");return ad},update_icons:function(){var ad=this;if(ad.filters_available){ad.action_icons.filters_icon.show()}else{ad.action_icons.filters_icon.hide()}if(ad.tool){ad.action_icons.tools_icon.show();ad.action_icons.param_space_viz_icon.show()}else{ad.action_icons.tools_icon.hide();ad.action_icons.param_space_viz_icon.hide()}},_gen_tile_cache_key:function(ae,ad){return ae+"_"+ad},request_draw:function(ad){if(ad&&ad.clear_tile_cache){this.tile_cache.clear()}this.view.request_redraw(ad,this)},before_draw:function(){this.max_height_px=0},_draw:function(aq){if(!this.can_draw()){return}var an=aq&&aq.clear_after,al=this.view.low,ah=this.view.high,ak=ah-al,ae=this.view.container.width(),ap=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;ap=1/ag}this.before_draw();this.tiles_div.children().addClass("remove");var ad=Math.floor(al/(ag*S)),am,ai,aj=[],ao=[];while((ad*S*ag)<ah){am=this._get_tile_bounds(ad,ag);ai=this.draw_helper(am,ag,ap,aq);aj.push(ai);$.when(ai).then(function(ar){ao.push(ar)});ad+=1}if(!an){this.tiles_div.children(".remove").removeClass("remove").remove()}var af=this;$.when.apply($,aj).then(function(){af.tiles_div.children(".remove").remove();ao=ac.filter(ao,function(ar){return ar!==null});if(ao.length!==0){af.postdraw_actions(ao,ae,ap,an)}})},_add_yaxis_label:function(ag,ai){var ae=this,ah=(ag==="max"?"top":"bottom"),aj=(ag==="max"?"max":"min"),ad=(ag==="max"?"max_value":"min_value"),ai=ai||function(){ae.request_draw({clear_tile_cache:true})},af=this.container_div.find(".yaxislabel."+ah);if(af.length!==0){af.text(ae.prefs[ad])}else{af=$("<div/>").text(ae.prefs[ad]).make_text_editable({num_cols:12,on_finish:function(ak){$(".bs-tooltip").remove();ae.config.set_param_value(ad,ak);ai()},help_text:"Set "+aj+" value"}).addClass("yaxislabel "+ah).css("color",this.prefs.label_color);this.container_div.prepend(af)}},postdraw_actions:function(ag,ah,aj,ad){var af=ac.filter(ag,function(ak){return(ak instanceof M)});if(af.length>0){this.max_height_px=0;var ae=this;ac.each(ag,function(ak){if(!(ak instanceof M)){ak.html_elt.remove();ae.draw_helper(ak.region,ak.resolution,aj,{force:true,mode:"Coverage"})}});ae._add_yaxis_label("max")}else{this.container_div.find(".yaxislabel").remove();var ai=ac.find(ag,function(ak){return ak.has_icons});if(ai){ac.each(ag,function(ak){if(!ak.has_icons){ak.html_elt.css("padding-top",D)}})}}},get_mode:function(ad){return this.mode},update_auto_mode:function(ad){},_get_drawables:function(){return[this]},draw_helper:function(am,ag,ap,aq){if(!aq){aq={}}var ae=aq.force,ao=!(aq.data_fetch===false),aj=aq.mode||this.mode,af=this,ah=this._get_drawables(),an=this._gen_tile_cache_key(ap,am),ai=function(ar){return(ar&&"track" in ar)};var ak=(ae?undefined:af.tile_cache.get_elt(an));if(ak){if(ai(ak)){af.show_tile(ak,ap)}return ak}if(!ao){return null}var al=function(){var ar=(ac.find(A,function(au){return au===aj})?"Coverage":aj);var at=ac.map(ah,function(au){return au.data_manager.get_data(am,ar,ag,af.data_url_extra_params)});if(view.reference_track){at.push(view.reference_track.data_manager.get_data(am,aj,ag,view.reference_track.data_url_extra_params))}return at};var ad=$.Deferred();af.tile_cache.set_elt(an,ad);$.when.apply($,al()).then(function(){var ar=al(),ax=ar,aD;if(view.reference_track){aD=view.reference_track.data_manager.subset_entry(ar.pop(),am)}var ay=[],av=[];ac.each(ah,function(aI,aF){var aH=aI.mode,aG=ax[aF];if(aH==="Auto"){aH=aI.get_mode(aG);aI.update_auto_mode(aH)}ay.push(aH);av.push(aI.get_canvas_height(aG,aH,ap,at))});var aw=af.view.canvas_manager.new_canvas(),az=am.get("start"),aE=am.get("end"),au=0,at=Math.ceil((aE-az)*ap)+af.left_offset,aB=ac.max(av),aA;aw.width=at;aw.height=(aq.height||aB);var aC=aw.getContext("2d");aC.translate(af.left_offset,0);if(ah.length>1){aC.globalAlpha=0.5;aC.globalCompositeOperation="source-over"}ac.each(ah,function(aG,aF){aA=aG.draw_tile(ax[aF],aC,ay[aF],ag,am,ap,aD)});if(aA!==undefined){af.tile_cache.set_elt(an,aA);af.show_tile(aA,ap)}ad.resolve(aA)});return ad},get_canvas_height:function(ad,af,ag,ae){return this.visible_height_px},_draw_line_track_tile:function(ad,af,aj,ah,ai,ak){var ag=af.canvas,ae=new L.LinePainter(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj);ae.draw(af,ag.width,ag.height,ak);return new M(this,ai,ah,ag,ad.data)},draw_tile:function(ad,ae,ai,ag,ah,aj,af){},show_tile:function(af,ai){var ae=this,ad=af.html_elt;af.predisplay_actions();var ah=(af.low-(this.is_overview?this.view.max_low:this.view.low))*ai;if(this.left_offset){ah-=this.left_offset}ad.css({position:"absolute",top:0,left:ah});if(ad.hasClass("remove")){ad.removeClass("remove")}else{this.tiles_div.append(ad)}af.html_elt.height("auto");this.max_height_px=Math.max(this.max_height_px,af.html_elt.height());af.html_elt.parent().children().css("height",this.max_height_px+"px");var ag=this.max_height_px;if(this.visible_height_px!==0){ag=Math.min(this.max_height_px,this.visible_height_px)}this.tiles_div.css("height",ag+"px")},_get_tile_bounds:function(ad,ae){var ag=Math.floor(ad*S*ae),ah=Math.ceil(S*ae),af=(ag+ah<=this.view.max_high?ag+ah:this.view.max_high);return new w.GenomeRegion({chrom:this.view.chrom,start:ag,end:af})},tool_region_and_parameters_str:function(ag){var ad=this,af=(ag!==undefined?ag.toString():"all"),ae=ac.values(ad.tool.get_inputs_dict()).join(", ");return" - region=["+af+"], parameters=["+ae+"]"},data_and_mode_compatible:function(ad,ae){if(ae==="Auto"){return true}else{if(ae==="Coverage"){return ad.dataset_type==="bigwig"}else{if(ad.extra_info==="no_detail"){return false}else{return true}}}},can_subset:function(ad){if(ad.dataset_type==="bigwig"||ad.message||ad.extra_info==="no_detail"){return false}return true},init_for_tool_data:function(){this.data_manager.set("data_type","raw_data");this.data_query_wait=1000;this.dataset_check_type="state"}});var W=function(ae,ad){var af={resize:false};f.call(this,ae,ad,af);this.container_div.addClass("label-track")};o(W.prototype,f.prototype,{build_header_div:function(){},init:function(){this.enabled=true},predraw_init:function(){},_draw:function(ah){var af=this.view,ag=af.high-af.low,ak=Math.floor(Math.pow(10,Math.floor(Math.log(ag)/Math.log(10)))),ad=Math.floor(af.low/ak)*ak,ai=this.view.container.width(),ae=$("<div style='position: relative; height: 1.3em;'></div>");while(ad<af.high){var aj=(ad-af.low)/ag*ai;ae.append($("<div class='label'>"+commatize(ad)+"</div>").css({position:"absolute",left:aj-1}));ad+=ak}this.content_div.children(":first").remove();this.content_div.append(ae)}});var e=function(ae,ad,ah){this.display_modes=A;N.call(this,ae,ad,ah);this.drawables=[];if("drawables" in ah){var ag;for(var af=0;af<ah.drawables.length;af++){ag=ah.drawables[af];this.drawables[af]=n(ag,ae,null);if(ag.left_offset>this.left_offset){this.left_offset=ag.left_offset}}this.enabled=true}ac.each(this.drawables,function(ai){if(ai instanceof c||ai instanceof T){ai.change_mode("Coverage")}});this.update_icons();this.obj_type="CompositeTrack"};o(e.prototype,N.prototype,{action_icons_def:[{name:"composite_icon",title:"Show individual tracks",css_class:"layers-stack",on_click_fn:function(ad){$(".bs-tooltip").remove();ad.show_group()}}].concat(N.prototype.action_icons_def),to_dict:y.prototype.to_dict,add_drawable:y.prototype.add_drawable,unpack_drawables:y.prototype.unpack_drawables,change_mode:function(ad){N.prototype.change_mode.call(this,ad);for(var ae=0;ae<this.drawables.length;ae++){this.drawables[ae].change_mode(ad)}},init:function(){var af=[];for(var ae=0;ae<this.drawables.length;ae++){af.push(this.drawables[ae].init())}var ad=this;$.when.apply($,af).then(function(){ad.enabled=true;ad.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:p.prototype.can_draw,_get_drawables:function(){return this.drawables},show_group:function(){var ag=new P(this.view,this.container,{name:this.name}),ad;for(var af=0;af<this.drawables.length;af++){ad=this.drawables[af];ad.update_icons();ag.add_drawable(ad);ad.container=ag;ag.content_div.append(ad.container_div)}var ae=this.container.replace_drawable(this,ag,true);ag.request_draw({clear_tile_cache:true})},before_draw:function(){N.prototype.before_draw.call(this);var ae=ac.min(ac.map(this.drawables,function(af){return af.prefs.min_value})),ad=ac.max(ac.map(this.drawables,function(af){return af.prefs.max_value}));this.prefs.min_value=ae;this.prefs.max_value=ad;ac.each(this.drawables,function(af){af.prefs.min_value=ae;af.prefs.max_value=ad})},update_all_min_max:function(){var ad=this;ac.each(this.drawables,function(ae){ae.prefs.min_value=ad.prefs.min_value;ae.prefs.max_value=ad.prefs.max_value});this.request_draw({clear_tile_cache:true})},postdraw_actions:function(aj,ad,am,ai){N.prototype.postdraw_actions.call(this,aj,ad,am,ai);var ah=-1;for(var af=0;af<aj.length;af++){var ak=aj[af].html_elt.find("canvas").height();if(ak>ah){ah=ak}}for(var af=0;af<aj.length;af++){var ag=aj[af];if(ag.html_elt.find("canvas").height()!==ah){this.draw_helper(ag.region,ag.resolution,am,{force:true,height:ah});ag.html_elt.remove()}}var ae=this,al=function(){ae.update_all_min_max()};this._add_yaxis_label("min",al);this._add_yaxis_label("max",al)}});var B=function(ad){N.call(this,ad,{content_div:ad.top_labeltrack},{resize:false});ad.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=galaxy_config.root+"api/genomes//"+this.view.dbkey;this.data_url_extra_params={reference:true};this.data_manager=new w.GenomeReferenceDataManager({data_url:this.data_url,can_subset:this.can_subset});this.hide_contents()};o(B.prototype,p.prototype,N.prototype,{build_header_div:function(){},init:function(){this.data_manager.clear();this.enabled=true},predraw_init:function(){},can_draw:p.prototype.can_draw,draw_helper:function(af,ae,ag,ad){if(ag>this.view.canvas_manager.char_width_px){this.tiles_div.show();return N.prototype.draw_helper.call(this,af,ae,ag,ad)}else{this.tiles_div.hide();return null}},can_subset:function(ad){return true},draw_tile:function(ag,am,ah,ae,aj,an){var af=this.data_manager.subset_entry(ag,aj),al=af.data;var ad=am.canvas;am.font=am.canvas.manager.default_font;am.textAlign="center";for(var ai=0,ak=al.length;ai<ak;ai++){am.fillStyle=this.view.get_base_color(al[ai]);am.fillText(al[ai],Math.floor(ai*an),10)}return new b(this,aj,ae,ad,af)}});var g=function(af,ae,ag){var ad=this;this.display_modes=A;this.mode="Histogram";N.call(this,af,ae,ag);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:j.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:ag.prefs,onchange:function(){ad.set_name(ad.prefs.name);ad.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};o(g.prototype,p.prototype,N.prototype,{before_draw:function(){},draw_tile:function(ad,ae,ah,af,ag,ai){return this._draw_line_track_tile(ad,ae,ah,af,ag,ai)},can_subset:function(ad){return(ad.data[1][0]-ad.data[0][0]===1)},postdraw_actions:function(ae,af,ag,ad){this._add_yaxis_label("max");this._add_yaxis_label("min")}});var r=function(af,ae,ag){var ad=this;this.display_modes=["Heatmap"];this.mode="Heatmap";N.call(this,af,ae,ag);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:ag.prefs,onchange:function(){ad.set_name(ad.prefs.name);this.request_redraw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height};o(r.prototype,p.prototype,N.prototype,{draw_tile:function(ad,af,aj,ah,ai,ak){var ag=af.canvas,ae=new L.DiagonalHeatmapPainter(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj);ae.draw(af,ag.width,ag.height,ak);return new b(this,ai,ah,ag,ad.data)}});var c=function(ag,af,ai){var ae=this;this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ag,af,ai);var ah=j.get_random_color(),ad=j.get_random_color([ah,"#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:ah},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ad},{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:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",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:ai.prefs,onchange:function(){ae.set_name(ae.prefs.name);ae.set_painter_from_config();ae.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.visible_height_px=this.config.values.height;this.container_div.addClass("feature-track");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()};o(c.prototype,p.prototype,N.prototype,{set_painter_from_config:function(){if(this.config.values.connector_style==="arcs"){this.painter=L.ArcLinkedFeaturePainter}else{this.painter=L.LinkedFeaturePainter}},postdraw_actions:function(an,af,ao,am){N.prototype.postdraw_actions.call(this,an,af,ao,am);var ah=this,ai;if(ah.filters_manager){var ag=ah.filters_manager.filters;for(var ak=0;ak<ag.length;ak++){ag[ak].update_ui_elt()}var aj=false,al,ae;for(ai=0;ai<an.length;ai++){if(an[ai].data.length){al=an[ai].data[0];for(var ak=0;ak<ag.length;ak++){ae=ag[ak];if(ae.applies_to(al)&&ae.min!==ae.max){aj=true;break}}}}if(ah.filters_available!==aj){ah.filters_available=aj;if(!ah.filters_available){ah.filters_manager.hide()}ah.update_icons()}}if(an[0] instanceof O){var ad=true;for(ai=0;ai<an.length;ai++){if(!an[ai].all_slotted){ad=false;break}}if(!ad){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(ad){var ad;if(this.mode==="Auto"){if(ad==="no_detail"){ad="feature spans"}this.action_icons.mode_icon.attr("title","Set display mode (now: Auto/"+ad+")")}},incremental_slots:function(ah,ad,ag){var ae=this.view.canvas_manager.dummy_context,af=this.slotters[ah];if(!af||(af.mode!==ag)){af=new (s.FeatureSlotter)(ah,ag,z,function(ai){return ae.measureText(ai)});this.slotters[ah]=af}return af.slot_features(ad)},get_mode:function(ad){if(ad.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(ad,ah,ai,ae){if(ah==="Coverage"||ad.dataset_type==="bigwig"){return this.summary_draw_height}else{var ag=this.incremental_slots(ai,ad.data,ah);var af=new (this.painter)(null,null,null,this.prefs,ah);return Math.max(aa,af.get_required_height(ag,ae))}},draw_tile:function(an,ar,ap,at,ag,ak,af){var aq=this,ae=ar.canvas,az=ag.get("start"),ad=ag.get("end"),ah=this.left_offset;if(an.dataset_type==="bigwig"){return this._draw_line_track_tile(an,ar,ap,at,ag,ak)}var aj=[],ao=this.slotters[ak].slots;all_slotted=true;if(an.data){var al=this.filters_manager.filters;for(var au=0,aw=an.data.length;au<aw;au++){var ai=an.data[au];var av=false;var am;for(var ay=0,aD=al.length;ay<aD;ay++){am=al[ay];am.update_attrs(ai);if(!am.keep(ai)){av=true;break}}if(!av){aj.push(ai);if(!(ai[0] in ao)){all_slotted=false}}}}var aC=(this.filters_manager.alpha_filter?new C(this.filters_manager.alpha_filter):null),aA=(this.filters_manager.height_filter?new C(this.filters_manager.height_filter):null),aB=new (this.painter)(aj,az,ad,this.prefs,ap,aC,aA,af,function(aE){return aq.view.get_base_color(aE)});var ax=null;ar.fillStyle=this.prefs.block_color;ar.font=ar.canvas.manager.default_font;ar.textAlign="right";if(an.data){ax=aB.draw(ar,ae.width,ae.height,ak,ao);ax.translation=-ah}return new O(aq,ag,at,ae,an.data,ak,ap,an.message,all_slotted,ax)}});var Z=function(ae,ad,af){this.display_modes=["Auto","Coverage","Dense","Squish","Pack"];N.call(this,ae,ad,af);this.config=new F({track:this,params:[{key:"name",label:"Name",type:"text",default_value:this.name},{key:"color",label:"Histogram color",type:"color",default_value:j.get_random_color()},{key:"show_sample_data",label:"Show sample data",type:"bool",default_value:true},{key:"show_labels",label:"Show summary and sample labels",type:"bool",default_value:true},{key:"summary_height",label:"Locus summary height",type:"float",default_value:20},{key:"mode",type:"string",default_value:this.mode,hidden:true}],saved_values:af.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=L.VariantPainter;this.summary_draw_height=30;this.left_offset=30};o(Z.prototype,p.prototype,N.prototype,{draw_tile:function(ad,ag,aj,ah,ai,ak){if(ad.dataset_type==="bigwig"){return this._draw_line_track_tile(ad,ag,"Histogram",ah,ai,ak)}else{var af=this.view,ae=new (this.painter)(ad.data,ai.get("start"),ai.get("end"),this.prefs,aj,function(al){return af.get_base_color(al)});ae.draw(ag,ag.canvas.width,ag.canvas.height,ak);return new b(this,ai,ah,ag.canvas,ad.data)}},get_canvas_height:function(ad,ah,ai,af){if(ad.dataset_type==="bigwig"){return this.summary_draw_height}else{var ag=new (this.painter)(null,null,null,this.prefs,ah);var ae=(this.dataset.get_metadata("sample_names")?this.dataset.get_metadata("sample_names").length:0);if(ae===0&&ad.data.length!==0){ae=ad.data[0][7].match(/,/g);if(ae===null){ae=1}else{ae=ae.length+1}}return ag.get_required_height(ae)}},predraw_init:function(){var ad=[f.prototype.predraw_init.call(this)];if(!this.dataset.get_metadata("sample_names")){ad.push(this.dataset.fetch())}return ad},postdraw_actions:function(ag,ah,aj,ae){N.prototype.postdraw_actions.call(this,ag,ah,aj,ae);var af=ac.filter(ag,function(ak){return(ak instanceof M)});if(af.length===0&&this.prefs.show_labels){var ad;if(this.container_div.find(".yaxislabel.variant").length===0){ad=this.prefs.summary_height/2;this.tiles_div.prepend($("<div/>").text("Summary").addClass("yaxislabel variant top").css({"font-size":ad+"px",top:(this.prefs.summary_height-ad)/2+"px"}));if(this.prefs.show_sample_data){var ai=this.dataset.get("metadata").get("sample_names").join("<br/>");this.tiles_div.prepend($("<div/>").html(ai).addClass("yaxislabel variant top sample").css({top:this.prefs.summary_height+2,}))}}ad=(this.mode==="Squish"?5:10)+"px";$(this.tiles_div).find(".sample").css({"font-size":ad,"line-height":ad});$(this.tiles_div).find(".yaxislabel").css("color",this.prefs.label_color)}else{this.container_div.find(".yaxislabel.variant").remove()}}});var T=function(af,ae,ah){c.call(this,af,ae,ah);var ag=j.get_random_color(),ad=j.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 and sense strand color",type:"color",default_value:ag},{key:"reverse_strand_color",label:"Antisense strand color",type:"color",default_value:ad},{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:"mode",type:"string",default_value:this.mode,hidden:true},{key:"min_value",label:"Histogram minimum",type:"float",default_value:null,help:"clear value to set automatically"},{key:"max_value",label:"Histogram maximum",type:"float",default_value:null,help:"clear value to set automatically"}],saved_values:ah.prefs,onchange:function(){this.track.set_name(this.track.prefs.name);this.track.request_draw({clear_tile_cache:true})}});this.prefs=this.config.values;this.painter=(af.reference_track?L.RefBasedReadPainter:L.ReadPainter);this.update_icons()};o(T.prototype,p.prototype,N.prototype,c.prototype);var d={CompositeTrack:e,DrawableGroup:P,DiagonalHeatmapTrack:r,FeatureTrack:c,LineTrack:g,ReadTrack:T,VariantTrack:Z,VcfTrack:Z};var n=function(af,ae,ad){if("copy" in af){return af.copy(ad)}else{var ag=af.obj_type;if(!ag){ag=af.track_type}return new d[ag](ae,ad,af)}};return{TracksterView:Y,DrawableGroup:P,LineTrack:g,FeatureTrack:c,DiagonalHeatmapTrack:r,ReadTrack:T,VariantTrack:Z,CompositeTrack:e,object_from_template:n}});
\ No newline at end of file
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d static/scripts/utils/localization.js
--- /dev/null
+++ b/static/scripts/utils/localization.js
@@ -0,0 +1,82 @@
+// =============================================================================
+/** @class string localizer (and global short form alias)
+ *
+ * @example
+ * // set with either:
+ * GalaxyLocalization.setLocalizedString( original, localized )
+ * GalaxyLocalization.setLocalizedString({ original1 : localized1, original2 : localized2 })
+ * // get with either:
+ * GalaxyLocalization.localize( string )
+ * _l( string )
+ *
+ * @constructs
+ */
+//TODO: move to Galaxy.Localization (maybe galaxy.base.js)
+var GalaxyLocalization = jQuery.extend( {}, {
+ /** shortened, alias reference to GalaxyLocalization.localize */
+ ALIAS_NAME : '_l',
+ /** map of available localized strings (english -> localized) */
+ localizedStrings : {},
+
+ /** Set a single English string -> localized string association, or set an entire map of those associations
+ * @param {String or Object} str_or_obj english (key) string or a map of english -> localized strings
+ * @param {String} localized string if str_or_obj was a string
+ */
+ setLocalizedString : function( str_or_obj, localizedString ){
+ //console.debug( this + '.setLocalizedString:', str_or_obj, localizedString );
+ var self = this;
+
+ // DRY non-duplicate assignment function
+ var setStringIfNotDuplicate = function( original, localized ){
+ // do not set if identical - strcmp expensive but should only happen once per page per word
+ if( original !== localized ){
+ self.localizedStrings[ original ] = localized;
+ }
+ };
+
+ if( jQuery.type( str_or_obj ) === "string" ){
+ setStringIfNotDuplicate( str_or_obj, localizedString );
+
+ } else if( jQuery.type( str_or_obj ) === "object" ){
+ jQuery.each( str_or_obj, function( key, val ){
+ //console.debug( 'key=>val', key, '=>', val );
+ // could recurse here but no reason
+ setStringIfNotDuplicate( key, val );
+ });
+
+ } else {
+ throw( 'Localization.setLocalizedString needs either a string or object as the first argument,' +
+ ' given: ' + str_or_obj );
+ }
+ },
+
+ /** Attempt to get a localized string for strToLocalize. If not found, return the original strToLocalize.
+ * @param {String} strToLocalize the string to localize
+ * @returns either the localized string if found or strToLocalize if not found
+ */
+ localize : function( strToLocalize ){
+ //console.debug( this + '.localize:', strToLocalize );
+
+ //// uncomment this section to cache strings that need to be localized but haven't been
+ //if( !_.has( this.localizedStrings, strToLocalize ) ){
+ // //console.debug( 'localization NOT found:', strToLocalize );
+ // if( !this.nonLocalized ){ this.nonLocalized = {}; }
+ // this.nonLocalized[ strToLocalize ] = false;
+ //}
+
+ // return the localized version if it's there, the strToLocalize if not
+ return this.localizedStrings[ strToLocalize ] || strToLocalize;
+ },
+
+ /** Add the localization function alias (GalaxyLocalization.ALIAS_NAME) to the given namespace.
+ * @param {Object} namespace the object/namespace to add the alias to
+ */
+ addAliasToNamespace : function( namespace ){
+ namespace[ GalaxyLocalization.ALIAS_NAME ] = function( str ){ return GalaxyLocalization.localize( str ); };
+ },
+
+ /** String representation. */
+ toString : function(){ return 'GalaxyLocalization'; }
+});
+
+GalaxyLocalization.addAliasToNamespace( window );
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -8,7 +8,7 @@
<!-- quota meter -->
${h.templates( "helpers-common-templates", "template-user-quotaMeter-quota", "template-user-quotaMeter-usage" )}
-${h.js( "mvc/base-mvc", "mvc/user/user-model", "mvc/user/user-quotameter" )}
+${h.js( "mvc/base-mvc", "utils/localization", "mvc/user/user-model", "mvc/user/user-quotameter" )}
</%def><%def name="get_user_json()">
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d templates/webapps/galaxy/root/history.mako
--- a/templates/webapps/galaxy/root/history.mako
+++ b/templates/webapps/galaxy/root/history.mako
@@ -4,50 +4,7 @@
${_('Galaxy History')}
</%def>
-## ---------------------------------------------------------------------------------------------------------------------
-<%def name="create_localization_json( strings_to_localize )">
- ## converts strings_to_localize (a list of strings) into a JSON dictionary of { string : localized string }
-${ h.to_json_string( dict([ ( string, _(string) ) for string in strings_to_localize ]) ) }
-## ?? add: if string != _(string)
-</%def>
-
-<%def name="get_page_localized_strings()">
- ## a list of localized strings used in the backbone views, etc. (to be loaded and cached)
- ##! change on per page basis
- <%
- strings_to_localize = [
- # not needed?: "Galaxy History",
- 'refresh',
- 'collapse all',
- 'hide deleted',
- 'hide hidden',
- 'You are currently viewing a deleted history!',
- "Your history is empty. Click 'Get Data' on the left pane to start",
-
- # from history_common.mako
- 'Download',
- 'Display Data',
- 'View data',
- 'Edit attributes',
- 'Delete',
- 'Job is waiting to run',
- 'View Details',
- 'Job is currently running',
- #'Run this job again',
- 'Metadata is being Auto-Detected.',
- 'No data: ',
- 'format: ',
- 'database: ',
- #TODO localized data.dbkey??
- 'Info: ',
- #TODO localized display_app.display_name??
- # _( link_app.name )
- # localized peek...ugh
- 'Error: unknown dataset state',
- ]
- return strings_to_localize
- %>
-</%def>
+<%namespace file="/utils/localization.mako" import="localize_js_strings" />
## ---------------------------------------------------------------------------------------------------------------------
## all the possible history urls (primarily from web controllers at this point)
@@ -156,6 +113,7 @@
"libs/jquery/jstorage",
"libs/jquery/jquery.autocomplete", "galaxy.autocom_tagging",
"mvc/base-mvc",
+ "utils/localization"
)}
${h.templates(
@@ -180,6 +138,37 @@
"mvc/dataset/hda-model", "mvc/dataset/hda-base", "mvc/dataset/hda-edit",
"mvc/history/history-model", "mvc/history/history-panel"
)}
+
+${localize_js_strings([
+ # not needed?: "Galaxy History",
+ 'refresh',
+ 'collapse all',
+ 'hide deleted',
+ 'hide hidden',
+ 'You are currently viewing a deleted history!',
+ "Your history is empty. Click 'Get Data' on the left pane to start",
+
+ # from history_common.mako
+ 'Download',
+ 'Display Data',
+ 'View data',
+ 'Edit attributes',
+ 'Delete',
+ 'Job is waiting to run',
+ 'View Details',
+ 'Job is currently running',
+ #'Run this job again',
+ 'Metadata is being Auto-Detected.',
+ 'No data: ',
+ 'format: ',
+ 'database: ',
+ #TODO localized data.dbkey??
+ 'Info: ',
+ #TODO localized display_app.display_name??
+ # _( link_app.name )
+ # localized peek...ugh
+ 'Error: unknown dataset state',
+])}
<script type="text/javascript">
function galaxyPageSetUp(){
@@ -191,19 +180,11 @@
top.Galaxy.mainWindow = top.Galaxy.mainWindow || top.frames.galaxy_main;
top.Galaxy.toolWindow = top.Galaxy.toolWindow || top.frames.galaxy_tools;
top.Galaxy.historyWindow = top.Galaxy.historyWindow || top.frames.galaxy_history;
-
- //modals
- top.Galaxy.show_modal = top.show_modal;
- top.Galaxy.hide_modal = top.hide_modal;
}
- top.Galaxy.localization = GalaxyLocalization;
window.Galaxy = top.Galaxy;
}
-// set js localizable strings
-GalaxyLocalization.setLocalizedString( ${ create_localization_json( get_page_localized_strings() ) } );
-
// add needed controller urls to galaxy_config
galaxy_config['hda'] = ${get_hda_url_templates()};
galaxy_config['history'] = ${get_history_url_templates()};
diff -r 380f30568086d773d6153a17f3fd1d85a7b42626 -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d templates/webapps/galaxy/root/index.mako
--- a/templates/webapps/galaxy/root/index.mako
+++ b/templates/webapps/galaxy/root/index.mako
@@ -165,7 +165,8 @@
%><div style="position: absolute; width: 100%; height: 100%">
- <iframe name="galaxy_main" id="galaxy_main" frameborder="0" style="position: absolute; width: 100%; height: 100%;" src="${center_url}"></iframe>
+ <iframe name="galaxy_main" id="galaxy_main" frameborder="0"
+ style="position: absolute; width: 100%; height: 100%;" src="${center_url}"></iframe></div></%def>
@@ -187,6 +188,9 @@
</div></div><div class="unified-panel-body" style="overflow: hidden;">
- <iframe name="galaxy_history" width="100%" height="100%" frameborder="0" style="position: absolute; margin: 0; border: 0 none; height: 100%;" src="${h.url_for( controller='root', action='history' )}"></iframe>
+ <iframe name="galaxy_history" width="100%" height="100%" frameborder="0"
+ style="position: absolute; margin: 0; border: 0 none; height: 100%;"
+ src="${h.url_for( controller='root', action='history' )}">
+ </iframe></div></%def>
https://bitbucket.org/galaxy/galaxy-central/commits/4e86427c63f6/
Changeset: 4e86427c63f6
User: carlfeberhard
Date: 2013-09-05 18:10:11
Summary: JS Localization: add packed version of separated file
Affected #: 1 file
diff -r 4f5276b1cfafe76fb590ffdcf7d54cdac495b47d -r 4e86427c63f63b1d9a3278ea0adfbe0e89906c83 static/scripts/packed/utils/localization.js
--- /dev/null
+++ b/static/scripts/packed/utils/localization.js
@@ -0,0 +1,1 @@
+var GalaxyLocalization=jQuery.extend({},{ALIAS_NAME:"_l",localizedStrings:{},setLocalizedString:function(b,a){var c=this;var d=function(f,e){if(f!==e){c.localizedStrings[f]=e}};if(jQuery.type(b)==="string"){d(b,a)}else{if(jQuery.type(b)==="object"){jQuery.each(b,function(e,f){d(e,f)})}else{throw ("Localization.setLocalizedString needs either a string or object as the first argument, given: "+b)}}},localize:function(a){return this.localizedStrings[a]||a},addAliasToNamespace:function(a){a[GalaxyLocalization.ALIAS_NAME]=function(b){return GalaxyLocalization.localize(b)}},toString:function(){return"GalaxyLocalization"}});GalaxyLocalization.addAliasToNamespace(window);
\ No newline at end of file
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/9fe9aa6ac504/
Changeset: 9fe9aa6ac504
Branch: stable
User: Dave Bouvier
Date: 2013-09-04 20:30:49
Summary: Fix for duplicate records created when a repository is installed from the tool shed, and the same repository had previously been installed and uninstalled.
Affected #: 1 file
diff -r ee6d553f7847ec47cca0cf205c767d1407eccbab -r 9fe9aa6ac504bc7703ba5d465e68170d79e89905 lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -189,6 +189,10 @@
log.debug( debug_msg )
suc.reset_previously_installed_repository( trans, installed_tool_shed_repository )
can_update = True
+ reinstalling = True
+ # Set changeset_revision here so suc.create_or_update_tool_shed_repository will find the previously installed
+ # and uninstalled repository instead of creating a new record.
+ changeset_revision = installed_tool_shed_repository.installed_changeset_revision
else:
# A tool shed repository is being installed into a Galaxy instance for the first time, or we're attempting to install it or reinstall it resulted
# in an error. In the latter case, the repository record in the database has no metadata and it's status has been set to 'New'. In either case,
https://bitbucket.org/galaxy/galaxy-central/commits/380f30568086/
Changeset: 380f30568086
User: Dave Bouvier
Date: 2013-09-04 20:34:57
Summary: Merge in bugfix from stable.
Affected #: 1 file
diff -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae -r 380f30568086d773d6153a17f3fd1d85a7b42626 lib/tool_shed/util/repository_dependency_util.py
--- a/lib/tool_shed/util/repository_dependency_util.py
+++ b/lib/tool_shed/util/repository_dependency_util.py
@@ -189,6 +189,10 @@
log.debug( debug_msg )
suc.reset_previously_installed_repository( trans, installed_tool_shed_repository )
can_update = True
+ reinstalling = True
+ # Set changeset_revision here so suc.create_or_update_tool_shed_repository will find the previously installed
+ # and uninstalled repository instead of creating a new record.
+ changeset_revision = installed_tool_shed_repository.installed_changeset_revision
else:
# A tool shed repository is being installed into a Galaxy instance for the first time, or we're attempting to install it or reinstall it resulted
# in an error. In the latter case, the repository record in the database has no metadata and it's status has been set to 'New'. In either case,
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/4a4a84d35bc5/
Changeset: 4a4a84d35bc5
User: Dave Bouvier
Date: 2013-09-03 18:20:11
Summary: Update functional tests to reflect changes in how text is sanitized.
Affected #: 2 files
diff -r 6e291fa55e10aa235196ac1c9f4c4dcb0afeaf6d -r 4a4a84d35bc56b45152b6efbed7496de68424fe8 test/tool_shed/functional/test_0000_basic_repository_features.py
--- a/test/tool_shed/functional/test_0000_basic_repository_features.py
+++ b/test/tool_shed/functional/test_0000_basic_repository_features.py
@@ -151,7 +151,7 @@
commit_message="Uploaded filtering.txt",
strings_displayed=[],
strings_not_displayed=[] )
- self.display_manage_repository_page( repository, strings_displayed=[ 'Readme&nbsp;file&nbsp;for&nbsp;filtering&nbsp;1.1.0' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'Readme file for filtering 1.1.0' ] )
def test_0055_upload_filtering_test_data( self ):
'''Upload filtering test data.'''
@@ -219,19 +219,19 @@
commit_message="Uploaded readme.txt",
strings_displayed=[],
strings_not_displayed=[] )
- self.display_manage_repository_page( repository, strings_displayed=[ 'This&nbsp;is&nbsp;a&nbsp;readme&nbsp;file.' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'This is a readme file.' ] )
# Verify that there is a different readme file for each metadata revision.
metadata_revisions = self.get_repository_metadata_revisions( repository )
self.display_manage_repository_page( repository,
- strings_displayed=[ 'Readme&nbsp;file&nbsp;for&nbsp;filtering&nbsp;1.1.0',
- 'This&nbsp;is&nbsp;a&nbsp;readme&nbsp;file.' ] )
+ strings_displayed=[ 'Readme file for filtering 1.1.0',
+ 'This is a readme file.' ] )
def test_0075_delete_readme_txt_file( self ):
'''Delete the readme.txt file.'''
repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.delete_files_from_repository( repository, filenames=[ 'readme.txt' ] )
self.check_count_of_metadata_revisions_associated_with_repository( repository, metadata_count=2 )
- self.display_manage_repository_page( repository, strings_displayed=[ 'Readme&nbsp;file&nbsp;for&nbsp;filtering&nbsp;1.1.0' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'Readme file for filtering 1.1.0' ] )
def test_0080_search_for_valid_filter_tool( self ):
'''Search for the filtering tool by tool ID, name, and version.'''
@@ -335,7 +335,7 @@
commit_message="Uploaded new readme.txt with invalid ascii characters.",
strings_displayed=[],
strings_not_displayed=[] )
- self.display_manage_repository_page( repository, strings_displayed=[ 'These&nbsp;characters&nbsp;should&nbsp;not' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'These characters should not' ] )
def test_0130_verify_handling_of_invalid_characters( self ):
'''Load the above changeset in the change log and confirm that there is no server error displayed.'''
@@ -353,5 +353,5 @@
# Check for the changeset revision, repository name, owner username, 'repos' in the clone url, and the captured
# unicode decoding error message.
strings_displayed = [ 'Changeset %d:%s' % ( revision_number, revision_hash ), 'filtering_0000', 'user1', 'repos', 'added:',
- '+These&nbsp;characters&nbsp;should&nbsp;not' ]
+ '+These characters should not' ]
self.load_changeset_in_tool_shed( repository_id, changeset_revision, strings_displayed=strings_displayed )
\ No newline at end of file
diff -r 6e291fa55e10aa235196ac1c9f4c4dcb0afeaf6d -r 4a4a84d35bc56b45152b6efbed7496de68424fe8 test/tool_shed/functional/test_0410_repository_component_review_access_control.py
--- a/test/tool_shed/functional/test_0410_repository_component_review_access_control.py
+++ b/test/tool_shed/functional/test_0410_repository_component_review_access_control.py
@@ -186,10 +186,10 @@
self.login( email=common.test_user_3_email, username=common.test_user_3_name )
repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
user = test_db_util.get_user( common.test_user_2_email )
- strings_displayed = [ 'A&nbsp;good&nbsp;set&nbsp;of&nbsp;functional&nbsp;tests.',
- 'Clear&nbsp;and&nbsp;concise&nbsp;readme&nbsp;file',
- 'a&nbsp;true&nbsp;pleasure&nbsp;to&nbsp;read.',
- 'Excellent&nbsp;tool,&nbsp;easy&nbsp;to&nbsp;use.' ]
+ strings_displayed = [ 'A good set of functional tests.',
+ 'Clear and concise readme file',
+ 'a true pleasure to read.',
+ 'Excellent tool, easy to use.' ]
changeset_revision = self.get_repository_tip( repository )
review = test_db_util.get_repository_review_by_user_id_changeset_revision( user.id, repository.id, changeset_revision )
self.browse_component_review( review, strings_displayed=strings_displayed )
https://bitbucket.org/galaxy/galaxy-central/commits/b9da077a79c3/
Changeset: b9da077a79c3
User: Dave Bouvier
Date: 2013-09-03 18:22:29
Summary: Tool dependency definitions: Add <actions_group> tag and support for filtering contained <actions> tags by architecture and operating system.
Affected #: 4 files
diff -r 4a4a84d35bc56b45152b6efbed7496de68424fe8 -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/fabric_util.py
@@ -217,13 +217,25 @@
# Eliminate the download_by_url action so remaining actions can be processed correctly.
filtered_actions = actions[ 1: ]
url = action_dict[ 'url' ]
+ is_binary = action_dict.get( 'is_binary', False )
+ log.debug( 'Attempting to download via url: %s', url )
if 'target_filename' in action_dict:
- # Sometimes compressed archives extracts their content to a folder other than the default defined file name. Using this
+ # Sometimes compressed archives extract their content to a folder other than the default defined file name. Using this
# attribute will ensure that the file name is set appropriately and can be located after download, decompression and extraction.
downloaded_filename = action_dict[ 'target_filename' ]
else:
downloaded_filename = os.path.split( url )[ -1 ]
dir = td_common_util.url_download( work_dir, downloaded_filename, url, extract=True )
+ if is_binary:
+ log_file = os.path.join( install_dir, INSTALLATION_LOG )
+ log.debug( 'log_file: %s' % log_file )
+ if os.path.exists( log_file ):
+ logfile = open( log_file, 'ab' )
+ else:
+ logfile = open( log_file, 'wb' )
+ logfile.write( 'Successfully downloaded from url: %s\n' % action_dict[ 'url' ] )
+ logfile.close()
+ log.debug( 'Successfully downloaded from url: %s' % action_dict[ 'url' ] )
elif action_type == 'shell_command':
# <action type="shell_command">git clone --recursive git://github.com/ekg/freebayes.git</action>
# Eliminate the shell_command clone action so remaining actions can be processed correctly.
diff -r 4a4a84d35bc56b45152b6efbed7496de68424fe8 -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
--- a/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
+++ b/lib/tool_shed/galaxy_install/tool_dependencies/install_util.py
@@ -333,13 +333,174 @@
type='package',
status=app.model.ToolDependency.installation_status.INSTALLING,
set_status=True )
+ # Get the information that defines the current platform.
+ platform_info_dict = tool_dependency_util.get_platform_info_dict()
if package_install_version == '1.0':
- # Handle tool dependency installation using a fabric method included in the Galaxy framework.
- for actions_elem in package_elem:
- install_via_fabric( app, tool_dependency, actions_elem, install_dir, package_name=package_name )
- sa_session.refresh( tool_dependency )
- if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR:
- print package_name, 'version', package_version, 'installed in', install_dir
+ # Handle tool dependency installation using a fabric method included in the Galaxy framework. The first thing we do
+ # is check the installation architecture to see if we have a precompiled binary that works on the target system.
+ binary_installed = False
+ actions_elem_tuples = []
+ # Build a list of grouped and ungrouped <actions> tagsets to be processed in the order they are defined in the
+ # tool_dependencies.xml file.
+ for elem in package_elem:
+ # Default to not treating actions as grouped.
+ grouped = False
+ # Skip any element that is not <actions> or <actions_group>. This will also skip comments and <readme> tags.
+ if elem.tag not in [ 'actions', 'actions_group' ]:
+ continue
+ if elem.tag == 'actions':
+ # We have an <actions> tag that should not be matched against a specific combination of architecture and operating system.
+ grouped = False
+ actions_elem_tuples.append( ( grouped, elem ) )
+ else:
+ # Record the number of <actions> elements, in order to filter out any <action> elements that precede <actions>
+ # elements.
+ actions_elem_count = len( elem.findall( 'actions' ) )
+ # Record the number of <actions> elements that have architecture and os specified, in order to filter out any
+ # platform-independent <actions> elements that come before platform-specific <actions> elements. This call to
+ # elem.findall is filtered by tags that have both the os and architecture specified.
+ # For more details, see http://docs.python.org/2/library/xml.etree.elementtree.html Section 19.7.2.1.
+ platform_actions_element_count = len( elem.findall( 'actions[@architecture][@os]' ) )
+ platform_actions_elements_processed = 0
+ actions_elems_processed = 0
+ # We have an actions_group element, and its child <actions> elements should therefore be compared with the current
+ # operating system and processor architecture.
+ grouped = True
+ # The tagsets that will go into the actions_elem_list are those that install a precompiled binary if the
+ # architecture and operating system match its defined attributes. If precompiled binary is not installed
+ # the first <actions> tag following those that have the os and architecture attributes will be processed
+ # in order to install and compile the source.
+ actions_elem_list = []
+ # The tagsets that will go into the after_install_actions list are <action> tags instead of <actions> tags. These
+ # will only be processed if they are at the end of the <actions_group> tagset. See below for details.
+ after_install_actions = []
+ platform_independent_actions = []
+ # Loop through the <actions_group> element and build the actions_elem_list and the after_install_actions list.
+ for child_element in elem:
+ if child_element.tag == 'actions':
+ actions_elems_processed += 1
+ system = child_element.get( 'os' )
+ architecture = child_element.get( 'architecture' )
+ # Skip <actions> tags that have only one of architecture or os specified, in order for the count in
+ # platform_actions_elements_processed to remain accurate.
+ if ( system and not architecture ) or ( architecture and not system ):
+ log.debug( 'Error: Both architecture and os attributes must be specified in an <actions> tag.' )
+ continue
+ # Since we are inside an <actions_group> tagset, compare it with our current platform information and filter
+ # the <actions> tagsets that don't match. Require both the os and architecture attributes to be defined in
+ # order to find a match.
+ if system and architecture:
+ platform_actions_elements_processed += 1
+ # If either the os or architecture do not match the platform, this <actions> tag will not be considered
+ # a match. Skip it and proceed with checking the next one.
+ if platform_info_dict[ 'os' ] != system or platform_info_dict[ 'architecture' ] != architecture:
+ continue
+ else:
+ # <actions> tags without both os and architecture attributes are only allowed to be specified after
+ # platform-specific <actions> tags. If we find a platform-independent <actions> tag before all
+ # platform-specific <actions> tags have been processed, log a message stating this and skip to the
+ # next <actions> tag.
+ if platform_actions_elements_processed < platform_actions_element_count:
+ message = 'Error: <actions> tags without os and architecture attributes are only allowed '
+ message += 'after <actions> tags with os and architecture attributes specified. Skipping '
+ message += 'current <actions> tag.'
+ log.debug( message )
+ continue
+ # If we reach this point, it means one of two things: 1) The system and architecture attributes are not
+ # defined in this <actions> tag, or 2) The system and architecture attributes are defined, and they are
+ # an exact match for the current platform. Append the child element to the list of elements to process.
+ actions_elem_list.append( child_element )
+ elif child_element.tag == 'action':
+ # Any <action> tags within an <actions_group> tagset must come after all <actions> tags.
+ if actions_elems_processed == actions_elem_count:
+ # If all <actions> elements have been processed, then this <action> element can be appended to the
+ # list of actions to execute within this group.
+ after_install_actions.append( child_element )
+ else:
+ # If any <actions> elements remain to be processed, then log a message stating that <action>
+ # elements are not allowed to precede any <actions> elements within an <actions_group> tagset.
+ message = 'Error: <action> tags are only allowed at the end of an <actions_group> '
+ message += 'tagset, after all <actions> tags. '
+ message += 'Skipping <%s> element with type %s.' % ( child_element.tag, child_element.get( 'type' ) )
+ log.debug( message )
+ continue
+ if after_install_actions:
+ actions_elem_list.extend( after_install_actions )
+ actions_elem_tuples.append( ( grouped, actions_elem_list ) )
+ # At this point we have a list of <actions> elems that are either defined within an <actions_group> tagset, and filtered by
+ # the current platform, or not defined within an <actions_group> tagset, and not filtered.
+ for grouped, actions_elems in actions_elem_tuples:
+ if grouped:
+ # Platform matching is only performed inside <actions_group> tagsets, os and architecture attributes are otherwise ignored.
+ for actions_elem in actions_elems:
+ system = actions_elem.get( 'os' )
+ architecture = actions_elem.get( 'architecture' )
+ # If this <actions> element has the os and architecture attributes defined, then we only want to process
+ # until a successful installation is achieved.
+ if system and architecture:
+ # If an <actions> tag has been defined that matches our current platform, and the recipe specified
+ # within that <actions> tag has been successfully processed, skip any remaining platform-specific
+ # <actions> tags.
+ if binary_installed:
+ continue
+ # No platform-specific <actions> recipe has yet resulted in a successful installation.
+ install_via_fabric( app,
+ tool_dependency,
+ install_dir,
+ package_name=package_name,
+ actions_elem=actions_elem,
+ action_elem=None )
+ sa_session.refresh( tool_dependency )
+ if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR:
+ # If an <actions> tag was found that matches the current platform, and the install_via_fabric method
+ # did not result in an error state, set binary_installed to True in order to skip any remaining
+ # platform-specific <actions> tags.
+ if not binary_installed:
+ binary_installed = True
+ else:
+ # Otherwise, move on to the next matching <actions> tag, or any defined <actions> tags that do not
+ # contain platform-dependent recipes.
+ if binary_installed:
+ binary_installed = False
+ print 'Encountered an error downloading binary for %s version %s: %s' % \
+ ( package_name, package_version, tool_dependency.error_message )
+ else:
+ # If no <actions> tags have been defined that match our current platform, or none of the matching
+ # <actions> tags resulted in a successful tool dependency status, proceed with one and only one
+ # <actions> tag that is not defined to be platform-specific.
+ if not binary_installed:
+ log.debug( 'Platform-specific recipe failed or not found. Proceeding with platform-independent install recipe.' )
+ install_via_fabric( app,
+ tool_dependency,
+ install_dir,
+ package_name=package_name,
+ actions_elem=actions_elem,
+ action_elem=None )
+ break
+ # Perform any final actions that have been defined within the actions_group tagset, but outside of
+ # an <actions> tag, such as a set_environment entry, or a download_file or download_by_url command to
+ # retrieve extra data for this tool dependency. Only do this if the tool dependency is not in an error
+ # state, otherwise skip this action.
+ if actions_elem.tag == 'action' and tool_dependency.status != app.model.ToolDependency.installation_status.ERROR:
+ install_via_fabric( app,
+ tool_dependency,
+ install_dir,
+ package_name=package_name,
+ actions_elem=None,
+ action_elem=actions_elem )
+ else:
+ # <actions> tags outside of an <actions_group> tag shall not check os or architecture, and if the attributes are
+ # defined, they will be ignored. All <actions> tags outside of an <actions_group> tagset shall always be processed.
+ # This is the default and original behavior of the install_package method.
+ install_via_fabric( app,
+ tool_dependency,
+ install_dir,
+ package_name=package_name,
+ actions_elem=actions_elems,
+ action_elem=None )
+ sa_session.refresh( tool_dependency )
+ if tool_dependency.status != app.model.ToolDependency.installation_status.ERROR:
+ print package_name, 'version', package_version, 'installed in', install_dir
else:
raise NotImplementedError( 'Only install version 1.0 is currently supported (i.e., change your tag to be <install version="1.0">).' )
elif package_elem.tag == 'readme':
@@ -356,7 +517,7 @@
# print 'Installing tool dependencies via fabric script ', proprietary_fabfile_path
return tool_dependency
-def install_via_fabric( app, tool_dependency, actions_elem, install_dir, package_name=None, proprietary_fabfile_path=None, **kwd ):
+def install_via_fabric( app, tool_dependency, install_dir, package_name=None, proprietary_fabfile_path=None, actions_elem=None, action_elem=None, **kwd ):
"""Parse a tool_dependency.xml file's <actions> tag set to gather information for the installation via fabric."""
sa_session = app.model.context.current
@@ -372,8 +533,21 @@
actions = []
all_env_shell_file_paths = []
env_var_dicts = []
- # Make sure to skip all comments, since they are now included in the XML tree.
- for action_elem in actions_elem.findall( 'action' ):
+ if actions_elem is not None:
+ elems = actions_elem
+ if elems.get( 'architecture' ) is not None:
+ is_binary_download = True
+ else:
+ is_binary_download = False
+ elif action_elem:
+ # We were provided with a single <action> element to perform certain actions after a platform-specific tarball was downloaded.
+ elems = [ action_elem ]
+ else:
+ elems = []
+ for action_elem in elems:
+ # Make sure to skip all comments, since they are now included in the XML tree.
+ if action_elem.tag != 'action':
+ continue
action_dict = {}
action_type = action_elem.get( 'type', 'shell_command' )
if action_type == 'download_binary':
@@ -420,6 +594,8 @@
raise Exception( "Unsupported template language '%s' in tool dependency definition." % str( language ) )
elif action_type == 'download_by_url':
# <action type="download_by_url">http://sourceforge.net/projects/samtools/files/samtools/0.1.18/samtools-0.1…</action>
+ if is_binary_download:
+ action_dict[ 'is_binary' ] = True
if action_elem.text:
action_dict[ 'url' ] = action_elem.text
target_filename = action_elem.get( 'target_filename', None )
diff -r 4a4a84d35bc56b45152b6efbed7496de68424fe8 -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae lib/tool_shed/util/common_install_util.py
--- a/lib/tool_shed/util/common_install_util.py
+++ b/lib/tool_shed/util/common_install_util.py
@@ -370,7 +370,7 @@
tool_dependency = install_package( app, elem, tool_shed_repository, tool_dependencies=tool_dependencies )
except Exception, e:
error_message = "Error installing tool dependency %s version %s: %s" % ( str( package_name ), str( package_version ), str( e ) )
- log.debug( error_message )
+ log.exception( error_message )
if tool_dependency:
tool_dependency.status = app.model.ToolDependency.installation_status.ERROR
tool_dependency.error_message = error_message
diff -r 4a4a84d35bc56b45152b6efbed7496de68424fe8 -r b9da077a79c3ce0323bd8f8e5aed3e311d1fd8ae lib/tool_shed/util/tool_dependency_util.py
--- a/lib/tool_shed/util/tool_dependency_util.py
+++ b/lib/tool_shed/util/tool_dependency_util.py
@@ -160,10 +160,10 @@
def get_download_url_for_platform( url_templates, platform_info_dict ):
'''
- Compare the dict returned by get_platform_info() with the values specified in the base_url element. Return
+ Compare the dict returned by get_platform_info() with the values specified in the url_template element. Return
true if and only if all defined attributes match the corresponding dict entries. If an entry is not
- defined in the base_url element, it is assumed to be irrelevant at this stage. For example,
- <base_url os="darwin">http://hgdownload.cse.ucsc.edu/admin/exe/macOSX.${architecture}/faToTwoBit</base_url>
+ defined in the url_template element, it is assumed to be irrelevant at this stage. For example,
+ <url_template os="darwin">http://hgdownload.cse.ucsc.edu/admin/exe/macOSX.${architecture}/faToTwoBit</url_template>
where the OS must be 'darwin', but the architecture is filled in later using string.Template.
'''
os_ok = False
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: Convert markupsafe object to unicode before rendering in the tool shed.
by commits-noreply@bitbucket.org 03 Sep '13
by commits-noreply@bitbucket.org 03 Sep '13
03 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/6e291fa55e10/
Changeset: 6e291fa55e10
User: greg
Date: 2013-09-03 17:10:50
Summary: Convert markupsafe object to unicode before rendering in the tool shed.
Affected #: 1 file
diff -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b -r 6e291fa55e10aa235196ac1c9f4c4dcb0afeaf6d lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -1468,7 +1468,7 @@
text = unicodify( text )
except UnicodeDecodeError, e:
return "Error decoding string: %s" % str( e )
- text = markupsafe.escape( text )
+ text = unicode( markupsafe.escape( text ) )
text = text.replace( '\n', '<br/>' )
text = text.replace( ' ', ' ' )
text = text.replace( ' ', ' ' )
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 rendering various files in the tool shed. Specific files should now correctly and safely render as html or rst.
by commits-noreply@bitbucket.org 03 Sep '13
by commits-noreply@bitbucket.org 03 Sep '13
03 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/535d8ed52369/
Changeset: 535d8ed52369
User: greg
Date: 2013-09-03 16:44:53
Summary: Fix for rendering various files in the tool shed. Specific files should now correctly and safely render as html or rst.
Affected #: 13 files
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b 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
@@ -164,14 +164,9 @@
message += "Choose <b>Uninstall this tool dependency</b> from the <b>Repository Actions</b> menu, correct problems "
message += "if necessary, and try installing the dependency again."
status = "error"
- tool_shed_repository = tool_dependency.tool_shed_repository
- tool_dependency.name = suc.to_safe_string( tool_dependency.name )
- tool_dependency.version = suc.to_safe_string( tool_dependency.version )
- tool_dependency.type = suc.to_safe_string( tool_dependency.type )
- tool_dependency.status = suc.to_safe_string( tool_dependency.status )
- tool_dependency.error_message = suc.to_safe_string( tool_dependency.error_message )
+ repository = tool_dependency.tool_shed_repository
return trans.fill_template( '/admin/tool_shed_repository/browse_tool_dependency.mako',
- repository=tool_shed_repository,
+ repository=repository,
tool_dependency=tool_dependency,
message=message,
status=status )
@@ -445,7 +440,7 @@
tool_dependencies=tool_dependencies )
for installed_tool_dependency in installed_tool_dependencies:
if installed_tool_dependency.status == trans.app.model.ToolDependency.installation_status.ERROR:
- message += ' %s' % suc.to_safe_string( installed_tool_dependency.error_message )
+ message += ' %s' % suc.to_html_string( installed_tool_dependency.error_message )
tool_dependency_ids = [ trans.security.encode_id( td.id ) for td in tool_dependencies ]
if message:
status = 'error'
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b lib/galaxy/webapps/tool_shed/controllers/repository.py
--- a/lib/galaxy/webapps/tool_shed/controllers/repository.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/repository.py
@@ -1566,7 +1566,9 @@
changeset_revision = kwd[ 'changeset_revision' ]
repository = suc.get_repository_by_name_and_owner( trans.app, repository_name, repository_owner )
if repository:
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, trans.security.encode_id( repository.id ), changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ trans.security.encode_id( repository.id ),
+ changeset_revision )
if repository_metadata:
metadata = repository_metadata.metadata
if metadata:
@@ -2791,7 +2793,7 @@
anchors = modified + added + removed + deleted + unknown + ignored + clean
diffs = []
for diff in patch.diff( repo, node1=ctx_parent.node(), node2=ctx.node() ):
- diffs.append( suc.to_safe_string( diff, to_html=True ) )
+ diffs.append( suc.to_html_string( diff ) )
metadata = self.get_metadata( trans, id, ctx_str )
# For rendering the prev button.
if ctx_parent:
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b lib/tool_shed/util/readme_util.py
--- a/lib/tool_shed/util/readme_util.py
+++ b/lib/tool_shed/util/readme_util.py
@@ -1,6 +1,7 @@
import logging
import os
from galaxy.util import json
+from galaxy.util import unicodify
import tool_shed.util.shed_util_common as suc
from tool_shed.util import common_util
@@ -19,9 +20,9 @@
full_path_to_readme_file = os.path.abspath( relative_path_to_readme_file )
try:
f = open( full_path_to_readme_file, 'r' )
- text = f.read()
+ text = unicodify( f.read() )
f.close()
- readme_files_dict[ readme_file_name ] = suc.translate_string( text, to_html=False )
+ readme_files_dict[ readme_file_name ] = suc.size_string( text )
except Exception, e:
log.debug( "Error reading README file '%s' defined in metadata: %s" % ( str( relative_path_to_readme_file ), str( e ) ) )
return readme_files_dict
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b lib/tool_shed/util/shed_util_common.py
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -38,8 +38,6 @@
INITIAL_CHANGELOG_HASH = '000000000000'
MAX_CONTENT_SIZE = 1048576
MAX_DISPLAY_SIZE = 32768
-VALID_CHARS = set( string.letters + string.digits + "'\"-=_.()/+*^,:?!#[]%\\$@;{}&<>|" )
-
DATATYPES_CONFIG_FILENAME = 'datatypes_conf.xml'
REPOSITORY_DATA_MANAGER_CONFIG_FILENAME = 'data_manager_conf.xml'
REPOSITORY_DEPENDENCY_DEFINITION_FILENAME = 'repository_dependencies.xml'
@@ -902,31 +900,34 @@
return repository
def get_repository_file_contents( file_path ):
- """Return the display-safe contents of a repository file."""
+ """Return the display-safe contents of a repository file for display in a browser."""
if checkers.is_gzip( file_path ):
- safe_str = to_safe_string( '\ngzip compressed file\n' )
+ return '<br/>gzip compressed file<br/>'
elif checkers.is_bz2( file_path ):
- safe_str = to_safe_string( '\nbz2 compressed file\n' )
+ return '<br/>bz2 compressed file<br/>'
elif checkers.check_zip( file_path ):
- safe_str = to_safe_string( '\nzip compressed file\n' )
+ return '<br/>zip compressed file<br/>'
elif checkers.check_binary( file_path ):
- safe_str = to_safe_string( '\nBinary file\n' )
+ return '<br/>Binary file<br/>'
else:
safe_str = ''
for i, line in enumerate( open( file_path ) ):
- safe_str = '%s%s' % ( safe_str, to_safe_string( line ) )
+ safe_str = '%s%s' % ( safe_str, to_html_string( line ) )
# Stop reading after string is larger than MAX_CONTENT_SIZE.
if len( safe_str ) > MAX_CONTENT_SIZE:
large_str = \
- to_safe_string( '\nFile contents truncated because file size is larger than maximum viewing size of %s\n' % util.nice_size( MAX_CONTENT_SIZE ) )
+ '<br/>File contents truncated because file size is larger than maximum viewing size of %s<br/>' % \
+ util.nice_size( MAX_CONTENT_SIZE )
safe_str = '%s%s' % ( safe_str, large_str )
break
if len( safe_str ) > MAX_DISPLAY_SIZE:
- # Eliminate the middle of the file to display a file no larger than MAX_DISPLAY_SIZE. This may not be ideal if the file is larger than MAX_CONTENT_SIZE.
+ # Eliminate the middle of the file to display a file no larger than MAX_DISPLAY_SIZE. This may not be ideal if the file is larger
+ # than MAX_CONTENT_SIZE.
join_by_str = \
- to_safe_string( "\n\n...some text eliminated here because file size is larger than maximum viewing size of %s...\n\n" % util.nice_size( MAX_DISPLAY_SIZE ) )
+ "<br/><br/>...some text eliminated here because file size is larger than maximum viewing size of %s...<br/><br/>" % \
+ util.nice_size( MAX_DISPLAY_SIZE )
safe_str = util.shrink_string_by_size( safe_str, MAX_DISPLAY_SIZE, join_by=join_by_str, left_larger=True, beginning_on_size_error=True )
- return safe_str
+ return safe_str
def get_repository_files( trans, folder_path ):
"""Return the file hierarchy of a tool shed repository."""
@@ -1438,6 +1439,13 @@
return required_rd_tup[ 4 ]
return False
+def size_string( raw_text, size=MAX_DISPLAY_SIZE ):
+ """Return a subset of a string (up to MAX_DISPLAY_SIZE) translated to a safe string for display in a browser."""
+ if raw_text and len( raw_text ) >= size:
+ large_str = '\nFile contents truncated because file size is larger than maximum viewing size of %s\n' % util.nice_size( size )
+ raw_text = '%s%s' % ( raw_text[ 0:size ], large_str )
+ return raw_text or ''
+
def stringify( list ):
if list:
return ','.join( list )
@@ -1453,40 +1461,17 @@
file_name = fpath
return file_name
-def to_safe_string( text, to_html=True ):
+def to_html_string( text ):
"""Translates the characters in text to an html string"""
if text:
- if to_html:
- try:
- escaped_text = unicodify( text )
- escaped_text = escaped_text.encode( 'ascii', 'ignore' )
- escaped_text = str( markupsafe.escape( escaped_text ) )
- except UnicodeDecodeError, e:
- escaped_text = "Error decoding string: %s" % str( e )
- else:
- escaped_text = str( text )
- translated = []
- for c in escaped_text:
- if c in VALID_CHARS:
- translated.append( c )
- elif c in [ '\n' ]:
- if to_html:
- translated.append( '<br/>' )
- else:
- translated.append( c )
- elif c in [ '\r' ]:
- continue
- elif c in [ ' ', ' ' ]:
- if to_html:
- if c == ' ':
- translated.append( ' ' )
- else:
- translated.append( ' ' )
- else:
- translated.append( c )
- else:
- translated.append( '' )
- return ''.join( translated )
+ try:
+ text = unicodify( text )
+ except UnicodeDecodeError, e:
+ return "Error decoding string: %s" % str( e )
+ text = markupsafe.escape( text )
+ text = text.replace( '\n', '<br/>' )
+ text = text.replace( ' ', ' ' )
+ text = text.replace( ' ', ' ' )
return text
def tool_shed_from_repository_clone_url( repository_clone_url ):
@@ -1497,18 +1482,6 @@
"""Determine if a tool shed is the current tool shed."""
return toolshed_base_url.rstrip( '/' ) == str( url_for( '/', qualified=True ) ).rstrip( '/' )
-def translate_string( raw_text, to_html=True ):
- """Return a subset of a string (up to MAX_DISPLAY_SIZE) translated to a safe string for display in a browser."""
- if raw_text:
- if len( raw_text ) <= MAX_DISPLAY_SIZE:
- translated_string = to_safe_string( raw_text, to_html=to_html )
- else:
- large_str = '\nFile contents truncated because file size is larger than maximum viewing size of %s\n' % util.nice_size( MAX_DISPLAY_SIZE )
- translated_string = to_safe_string( '%s%s' % ( raw_text[ 0:MAX_DISPLAY_SIZE ], large_str ), to_html=to_html )
- else:
- translated_string = ''
- return translated_string
-
def update_in_shed_tool_config( app, repository ):
"""
A tool shed repository is being updated so change the shed_tool_conf file. Parse the config file to generate the entire list
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b templates/webapps/tool_shed/repository/common.mako
--- a/templates/webapps/tool_shed/repository/common.mako
+++ b/templates/webapps/tool_shed/repository/common.mako
@@ -580,7 +580,7 @@
<%def name="render_readme( readme, pad, parent, row_counter )"><%
- from tool_shed.util.shed_util_common import to_safe_string
+ from tool_shed.util.shed_util_common import to_html_string
from galaxy.util import rst_to_html
encoded_id = trans.security.encode_id( readme.id )
render_rst = readme.name.endswith( '.rst' )
@@ -605,7 +605,7 @@
%if render_rst:
<tr><td>${ rst_to_html( readme.text ) }</td></tr>
%else:
- <tr><td>${readme.name}<br/>${ to_safe_string( readme.text, to_html=True ) }</td></tr>
+ <tr><td>${readme.name}<br/>${ to_html_string( readme.text ) }</td></tr>
%endif
</table></td>
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b templates/webapps/tool_shed/repository/manage_repository.mako
--- a/templates/webapps/tool_shed/repository/manage_repository.mako
+++ b/templates/webapps/tool_shed/repository/manage_repository.mako
@@ -355,7 +355,7 @@
%><tr><td>${render_star_rating( name, review.rating, disabled=True )}</td>
- <td>${render_review_comment( to_safe_string( review.comment, to_html=True ) )}</td>
+ <td>${render_review_comment( to_html_string( review.comment ) )}</td><td>${time_ago( review.update_time )}</td><td>${review.user.username | h}</td></tr>
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b templates/webapps/tool_shed/repository/view_repository.mako
--- a/templates/webapps/tool_shed/repository/view_repository.mako
+++ b/templates/webapps/tool_shed/repository/view_repository.mako
@@ -6,7 +6,7 @@
<%
from galaxy.web.framework.helpers import time_ago
- from tool_shed.util.shed_util_common import to_safe_string
+ from tool_shed.util.shed_util_common import to_html_string
is_new = repository.is_new( trans.app )
is_deprecated = repository.deprecated
@@ -106,7 +106,7 @@
${repository.description | h}
</div>
%if repository.long_description:
- ${render_long_description( to_safe_string( repository.long_description, to_html=True ) )}
+ ${render_long_description( to_html_string( repository.long_description ) )}
%endif
<div class="form-row"><label>Revision:</label>
@@ -214,7 +214,7 @@
%><tr><td>${render_star_rating( name, review.rating, disabled=True )}</td>
- <td>${render_review_comment( to_safe_string( review.comment, to_html=True ) )}</td>
+ <td>${render_review_comment( to_html_string( review.comment ) )}</td><td>${time_ago( review.update_time )}</td><td>${review.user.username}</td></tr>
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b templates/webapps/tool_shed/repository_review/browse_review.mako
--- a/templates/webapps/tool_shed/repository_review/browse_review.mako
+++ b/templates/webapps/tool_shed/repository_review/browse_review.mako
@@ -6,7 +6,7 @@
<%
from galaxy.web.form_builder import CheckboxField
from tool_shed.util.container_util import STRSEP
- from tool_shed.util.shed_util_common import to_safe_string
+ from tool_shed.util.shed_util_common import to_html_string
%><%def name="stylesheets()">
@@ -84,7 +84,7 @@
<tr><td><div overflow-wrap:normal;overflow:hidden;word-break:keep-all;word-wrap:break-word;line-break:strict;>
- ${ to_safe_string( component_review.comment, to_html=True ) }
+ ${ to_html_string( component_review.comment ) }
</div></td></tr>
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b test/tool_shed/base/twilltestcase.py
--- a/test/tool_shed/base/twilltestcase.py
+++ b/test/tool_shed/base/twilltestcase.py
@@ -374,7 +374,7 @@
def display_installed_repository_manage_page( self, installed_repository, strings_displayed=[], strings_not_displayed=[] ):
url = '/admin_toolshed/manage_repository?id=%s' % self.security.encode_id( installed_repository.id )
self.visit_galaxy_url( url )
- strings_displayed.append( installed_repository.installed_changeset_revision )
+ strings_displayed.append( str( installed_repository.installed_changeset_revision ) )
self.check_for_strings( strings_displayed, strings_not_displayed )
def display_installed_workflow_image( self, repository, workflow_name, strings_displayed=[], strings_not_displayed=[] ):
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b test/tool_shed/functional/test_0000_basic_repository_features.py
--- a/test/tool_shed/functional/test_0000_basic_repository_features.py
+++ b/test/tool_shed/functional/test_0000_basic_repository_features.py
@@ -151,7 +151,7 @@
commit_message="Uploaded filtering.txt",
strings_displayed=[],
strings_not_displayed=[] )
- self.display_manage_repository_page( repository, strings_displayed=[ 'Readme file for filtering 1.1.0' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'Readme&nbsp;file&nbsp;for&nbsp;filtering&nbsp;1.1.0' ] )
def test_0055_upload_filtering_test_data( self ):
'''Upload filtering test data.'''
@@ -219,19 +219,19 @@
commit_message="Uploaded readme.txt",
strings_displayed=[],
strings_not_displayed=[] )
- self.display_manage_repository_page( repository, strings_displayed=[ 'This is a readme file.' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'This&nbsp;is&nbsp;a&nbsp;readme&nbsp;file.' ] )
# Verify that there is a different readme file for each metadata revision.
metadata_revisions = self.get_repository_metadata_revisions( repository )
self.display_manage_repository_page( repository,
- strings_displayed=[ 'Readme file for filtering 1.1.0',
- 'This is a readme file.' ] )
+ strings_displayed=[ 'Readme&nbsp;file&nbsp;for&nbsp;filtering&nbsp;1.1.0',
+ 'This&nbsp;is&nbsp;a&nbsp;readme&nbsp;file.' ] )
def test_0075_delete_readme_txt_file( self ):
'''Delete the readme.txt file.'''
repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
self.delete_files_from_repository( repository, filenames=[ 'readme.txt' ] )
self.check_count_of_metadata_revisions_associated_with_repository( repository, metadata_count=2 )
- self.display_manage_repository_page( repository, strings_displayed=[ 'Readme file for filtering 1.1.0' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'Readme&nbsp;file&nbsp;for&nbsp;filtering&nbsp;1.1.0' ] )
def test_0080_search_for_valid_filter_tool( self ):
'''Search for the filtering tool by tool ID, name, and version.'''
@@ -335,7 +335,7 @@
commit_message="Uploaded new readme.txt with invalid ascii characters.",
strings_displayed=[],
strings_not_displayed=[] )
- self.display_manage_repository_page( repository, strings_displayed=[ 'These characters should not' ] )
+ self.display_manage_repository_page( repository, strings_displayed=[ 'These&nbsp;characters&nbsp;should&nbsp;not' ] )
def test_0130_verify_handling_of_invalid_characters( self ):
'''Load the above changeset in the change log and confirm that there is no server error displayed.'''
@@ -353,5 +353,5 @@
# Check for the changeset revision, repository name, owner username, 'repos' in the clone url, and the captured
# unicode decoding error message.
strings_displayed = [ 'Changeset %d:%s' % ( revision_number, revision_hash ), 'filtering_0000', 'user1', 'repos', 'added:',
- '+These characters should not' ]
+ '+These&nbsp;characters&nbsp;should&nbsp;not' ]
self.load_changeset_in_tool_shed( repository_id, changeset_revision, strings_displayed=strings_displayed )
\ No newline at end of file
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b test/tool_shed/functional/test_0410_repository_component_review_access_control.py
--- a/test/tool_shed/functional/test_0410_repository_component_review_access_control.py
+++ b/test/tool_shed/functional/test_0410_repository_component_review_access_control.py
@@ -186,10 +186,10 @@
self.login( email=common.test_user_3_email, username=common.test_user_3_name )
repository = test_db_util.get_repository_by_name_and_owner( repository_name, common.test_user_1_name )
user = test_db_util.get_user( common.test_user_2_email )
- strings_displayed = [ 'A good set of functional tests.',
- 'Clear and concise readme file',
- 'a true pleasure to read.',
- 'Excellent tool, easy to use.' ]
+ strings_displayed = [ 'A&nbsp;good&nbsp;set&nbsp;of&nbsp;functional&nbsp;tests.',
+ 'Clear&nbsp;and&nbsp;concise&nbsp;readme&nbsp;file',
+ 'a&nbsp;true&nbsp;pleasure&nbsp;to&nbsp;read.',
+ 'Excellent&nbsp;tool,&nbsp;easy&nbsp;to&nbsp;use.' ]
changeset_revision = self.get_repository_tip( repository )
review = test_db_util.get_repository_review_by_user_id_changeset_revision( user.id, repository.id, changeset_revision )
self.browse_component_review( review, strings_displayed=strings_displayed )
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b test/tool_shed/functional/test_1000_install_basic_repository.py
--- a/test/tool_shed/functional/test_1000_install_basic_repository.py
+++ b/test/tool_shed/functional/test_1000_install_basic_repository.py
@@ -99,7 +99,7 @@
"Galaxy's filtering tool",
'user1',
self.url.replace( 'http://', '' ),
- installed_repository.installed_changeset_revision ]
+ str( installed_repository.installed_changeset_revision ) ]
self.display_galaxy_browse_repositories_page( strings_displayed=strings_displayed )
strings_displayed.extend( [ 'Installed tool shed repository', 'Valid tools', 'Filter1' ] )
self.display_installed_repository_manage_page( installed_repository, strings_displayed=strings_displayed )
@@ -119,7 +119,7 @@
"Galaxy's filtering tool",
'user1',
self.url.replace( 'http://', '' ),
- installed_repository.installed_changeset_revision ]
+ str( installed_repository.installed_changeset_revision ) ]
self.display_installed_repository_manage_page( installed_repository, strings_displayed=strings_displayed )
self.display_galaxy_browse_repositories_page( strings_displayed=strings_displayed )
diff -r 76d580b93d86940350bb810cab0c8ef088a2197c -r 535d8ed52369a8bf02ce5e382b488bf94a6f257b test/tool_shed/functional/test_1200_uninstall_and_reinstall_basic_repository.py
--- a/test/tool_shed/functional/test_1200_uninstall_and_reinstall_basic_repository.py
+++ b/test/tool_shed/functional/test_1200_uninstall_and_reinstall_basic_repository.py
@@ -99,7 +99,7 @@
"Galaxy's filtering tool for test 0000",
'user1',
self.url.replace( 'http://', '' ),
- installed_repository.installed_changeset_revision ]
+ str( installed_repository.installed_changeset_revision ) ]
self.display_galaxy_browse_repositories_page( strings_displayed=strings_displayed )
strings_displayed.extend( [ 'Installed tool shed repository', 'Valid tools', 'Filter1' ] )
self.display_installed_repository_manage_page( installed_repository, strings_displayed=strings_displayed )
@@ -120,7 +120,7 @@
"Galaxy's filtering tool for test 0000",
'user1',
self.url.replace( 'http://', '' ),
- installed_repository.installed_changeset_revision ]
+ str( installed_repository.installed_changeset_revision ) ]
self.display_galaxy_browse_repositories_page( strings_displayed=strings_displayed )
strings_displayed.extend( [ 'Installed tool shed repository', 'Valid tools', 'Filter1' ] )
self.display_installed_repository_manage_page( installed_repository, strings_displayed=strings_displayed )
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: james_taylor: Adding a CITATION file, http://software-carpentry.org/blog/2013/09/introducing-citation-files.html
by commits-noreply@bitbucket.org 03 Sep '13
by commits-noreply@bitbucket.org 03 Sep '13
03 Sep '13
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/commits/76d580b93d86/
Changeset: 76d580b93d86
User: james_taylor
Date: 2013-09-02 21:02:33
Summary: Adding a CITATION file, http://software-carpentry.org/blog/2013/09/introducing-citation-files.html
Affected #: 1 file
diff -r 0470feeb593f9797fa9fd19dfdac4751a7ca788b -r 76d580b93d86940350bb810cab0c8ef088a2197c CITATION
--- /dev/null
+++ b/CITATION
@@ -0,0 +1,54 @@
+If you use or extend Galaxy in your published work, please cite each of the
+following publications:
+
+- Goecks, J, Nekrutenko, A, Taylor, J and The Galaxy Team. "Galaxy: a
+ comprehensive approach for supporting accessible, reproducible, and
+ transparent computational research in the life sciences."
+ Genome Biol. 2010 Aug 25;11(8):R86.
+
+- Blankenberg D, Von Kuster G, Coraor N, Ananda G, Lazarus R, Mangan M,
+ Nekrutenko A, Taylor J. "Galaxy: a web-based genome analysis tool for
+ experimentalists". Current Protocols in Molecular Biology.
+ 2010 Jan; Chapter 19:Unit 19.10.1-21.
+
+- Giardine B, Riemer C, Hardison RC, Burhans R, Elnitski L, Shah P, Zhang Y,
+ Blankenberg D, Albert I, Taylor J, Miller W, Kent WJ, Nekrutenko A. "Galaxy:
+ a platform for interactive large-scale genome analysis."
+ Genome Research. 2005 Oct; 15(10):1451-5.
+
+See also: http://wiki.galaxyproject.org/CitingGalaxy
+
+
+
+BibTeX format:
+
+@article{goecks2010galaxy,
+ title={Galaxy: a comprehensive approach for supporting accessible, reproducible, and transparent computational research in the life sciences},
+ author={Goecks, Jeremy and Nekrutenko, Anton and Taylor, James and The Galaxy Team},
+ journal={Genome Biol},
+ volume={11},
+ number={8},
+ pages={R86},
+ year={2010}
+}
+
+@article{blankenberg2010galaxy,
+ title={Galaxy: A Web-Based Genome Analysis Tool for Experimentalists},
+ author={Blankenberg, Daniel and Kuster, Gregory Von and Coraor, Nathaniel and Ananda, Guruprasad and Lazarus, Ross and Mangan, Mary and Nekrutenko, Anton and Taylor, James},
+ journal={Current protocols in molecular biology},
+ pages={19--10},
+ year={2010},
+ publisher={John Wiley \& Sons, Inc.}
+}
+
+@article{giardine2005galaxy,
+ title={Galaxy: a platform for interactive large-scale genome analysis},
+ author={Giardine, Belinda and Riemer, Cathy and Hardison, Ross C and Burhans, Richard and Elnitski, Laura and Shah, Prachi and Zhang, Yi and Blankenberg, Daniel and Albert, Istvan and Taylor, James and Miller, Webb C and Kent, W James and Nekrutenko, Anton},
+ journal={Genome research},
+ volume={15},
+ number={10},
+ pages={1451--1455},
+ year={2005},
+ publisher={Cold Spring Harbor Lab}
+}
+
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