diff --git a/job_conf.xml.sample_advanced b/job_conf.xml.sample_advanced
index 2637c7ce319..8c9741241bb 100644
--- a/job_conf.xml.sample_advanced
+++ b/job_conf.xml.sample_advanced
@@ -6,7 +6,19 @@
-->
-
+
+
+ ok
+ 0
+ ok
+ 0
+
+
+
+ /sge/lib/libdrmaa.so
+
@@ -14,6 +26,7 @@
+
+
+
+
+
diff --git a/lib/galaxy/jobs/__init__.py b/lib/galaxy/jobs/__init__.py
index eb81d47df39..6b5c30df296 100644
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -86,6 +86,7 @@ class JobConfiguration( object ):
self.app = app
self.runner_plugins = []
self.handlers = {}
+ self.handler_runner_plugins = {}
self.default_handler_id = None
self.destinations = {}
self.destination_tags = {}
@@ -138,6 +139,10 @@ class JobConfiguration( object ):
else:
log.debug("Read definition for handler '%s'" % id)
self.handlers[id] = (id,)
+ for plugin in handler.findall('plugin'):
+ if id not in self.handler_runner_plugins:
+ self.handler_runner_plugins[id] = []
+ self.handler_runner_plugins[id].append( plugin.get('id') )
if handler.get('tags', None) is not None:
for tag in [ x.strip() for x in handler.get('tags').split(',') ]:
if tag in self.handlers:
@@ -420,13 +425,19 @@ class JobConfiguration( object ):
"""
return self.destinations.get(id_or_tag, None)
- def get_job_runner_plugins(self):
+ def get_job_runner_plugins(self, handler_id):
"""Load all configured job runner plugins
:returns: list of job runner plugins
"""
rval = {}
- for runner in self.runner_plugins:
+ if handler_id in self.handler_runner_plugins:
+ plugins_to_load = [ rp for rp in self.runner_plugins if rp['id'] in self.handler_runner_plugins[handler_id] ]
+ log.info( "Handler '%s' will load specified runner plugins: %s", handler_id, ', '.join( [ rp['id'] for rp in plugins_to_load ] ) )
+ else:
+ plugins_to_load = self.runner_plugins
+ log.info( "Handler '%s' will load all configured runner plugins", handler_id )
+ for runner in plugins_to_load:
class_names = []
module = None
id = runner['id']
@@ -477,7 +488,7 @@ class JobConfiguration( object ):
try:
rval[id] = runner_class( self.app, runner[ 'workers' ], **runner.get( 'kwds', {} ) )
except TypeError:
- log.warning( "Job runner '%s:%s' has not been converted to a new-style runner" % ( module_name, class_name ) )
+ log.exception( "Job runner '%s:%s' has not been converted to a new-style runner or encountered TypeError on load" % ( module_name, class_name ) )
rval[id] = runner_class( self.app )
log.debug( "Loaded job runner '%s:%s' as '%s'" % ( module_name, class_name, id ) )
return rval
diff --git a/lib/galaxy/jobs/handler.py b/lib/galaxy/jobs/handler.py
index ae6f2ac3d38..5a262ec4633 100644
--- a/lib/galaxy/jobs/handler.py
+++ b/lib/galaxy/jobs/handler.py
@@ -565,7 +565,7 @@ class JobHandlerStopQueue( object ):
class DefaultJobDispatcher( object ):
def __init__( self, app ):
self.app = app
- self.job_runners = self.app.job_config.get_job_runner_plugins()
+ self.job_runners = self.app.job_config.get_job_runner_plugins( self.app.config.server_name )
# Once plugins are loaded, all job destinations that were created from
# URLs can have their URL params converted to the destination's param
# dict by the plugin.
diff --git a/lib/galaxy/jobs/runners/__init__.py b/lib/galaxy/jobs/runners/__init__.py
index 2b412a6db31..334b20c4850 100644
--- a/lib/galaxy/jobs/runners/__init__.py
+++ b/lib/galaxy/jobs/runners/__init__.py
@@ -22,13 +22,39 @@ log = logging.getLogger( __name__ )
STOP_SIGNAL = object()
+
+class RunnerParams( object ):
+
+ def __init__( self, specs = None, params = None ):
+ self.specs = specs or dict()
+ self.params = params or dict()
+ for name, value in self.params.items():
+ assert name in self.specs, 'Invalid job runner parameter for this plugin: %s' % name
+ if 'map' in self.specs[ name ]:
+ try:
+ self.params[ name ] = self.specs[ name ][ 'map' ]( value )
+ except Exception, e:
+ raise Exception( 'Job runner parameter "%s" value "%s" could not be converted to the correct type: %s' % ( name, value, e ) )
+ if 'valid' in self.specs[ name ]:
+ assert self.specs[ name ][ 'valid' ]( value ), 'Job runner parameter %s failed validation' % name
+
+ def __getattr__( self, name ):
+ return self.params.get( name, self.specs[ name ][ 'default' ] )
+
+
class BaseJobRunner( object ):
- def __init__( self, app, nworkers ):
+ def __init__( self, app, nworkers, **kwargs ):
"""Start the job runner
"""
self.app = app
self.sa_session = app.model.context
self.nworkers = nworkers
+ runner_param_specs = dict( recheck_missing_job_retries = dict( map = int, valid = lambda x: x >= 0, default = 0 ) )
+ if 'runner_param_specs' in kwargs:
+ runner_param_specs.update( kwargs.pop( 'runner_param_specs' ) )
+ if kwargs:
+ log.debug( 'Loading %s with params: %s', self.runner_name, kwargs )
+ self.runner_params = RunnerParams( specs = runner_param_specs, params = kwargs )
def _init_worker_threads(self):
"""Start ``nworkers`` worker threads.
@@ -115,7 +141,7 @@ class BaseJobRunner( object ):
job_wrapper.cleanup()
return False
elif job_state != model.Job.states.QUEUED:
- log.info( "(%d) Job is in state %s, skipping execution" % ( job_id, job_state ) )
+ log.info( "(%s) Job is in state %s, skipping execution" % ( job_id, job_state ) )
# cleanup may not be safe in all states
return False
@@ -226,6 +252,10 @@ class BaseJobRunner( object ):
options.update(**kwds)
return job_script(**options)
+ def _complete_terminal_job( self, ajs, **kwargs ):
+ if ajs.job_wrapper.get_state() != model.Job.states.DELETED:
+ self.work_queue.put( ( self.finish_job, ajs ) )
+
class AsynchronousJobState( object ):
"""
@@ -287,8 +317,8 @@ class AsynchronousJobRunner( BaseJobRunner ):
to the correct methods (queue, finish, cleanup) at appropriate times..
"""
- def __init__( self, app, nworkers ):
- super( AsynchronousJobRunner, self ).__init__( app, nworkers )
+ def __init__( self, app, nworkers, **kwargs ):
+ super( AsynchronousJobRunner, self ).__init__( app, nworkers, **kwargs )
# 'watched' and 'queue' are both used to keep track of jobs to watch.
# 'queue' is used to add new watched jobs, and can be called from
# any thread (usually by the 'queue_job' method). 'watched' must only
diff --git a/lib/galaxy/jobs/runners/drmaa.py b/lib/galaxy/jobs/runners/drmaa.py
index 5e111ca4710..dfda8b23f25 100644
--- a/lib/galaxy/jobs/runners/drmaa.py
+++ b/lib/galaxy/jobs/runners/drmaa.py
@@ -16,27 +16,12 @@ from galaxy.jobs import JobDestination
from galaxy.jobs.runners import AsynchronousJobState, AsynchronousJobRunner
eggs.require( "drmaa" )
-# We foolishly named this file the same as the name exported by the drmaa
-# library... 'import drmaa' imports itself.
-drmaa = __import__( "drmaa" )
log = logging.getLogger( __name__ )
__all__ = [ 'DRMAAJobRunner' ]
-drmaa_state = {
- drmaa.JobState.UNDETERMINED: 'process status cannot be determined',
- drmaa.JobState.QUEUED_ACTIVE: 'job is queued and active',
- drmaa.JobState.SYSTEM_ON_HOLD: 'job is queued and in system hold',
- drmaa.JobState.USER_ON_HOLD: 'job is queued and in user hold',
- drmaa.JobState.USER_SYSTEM_ON_HOLD: 'job is queued and in user and system hold',
- drmaa.JobState.RUNNING: 'job is running',
- drmaa.JobState.SYSTEM_SUSPENDED: 'job is system suspended',
- drmaa.JobState.USER_SUSPENDED: 'job is user suspended',
- drmaa.JobState.DONE: 'job finished normally',
- drmaa.JobState.FAILED: 'job finished, but failed',
-}
-
+drmaa = None
DRMAA_jobTemplate_attributes = [ 'args', 'remoteCommand', 'outputPath', 'errorPath', 'nativeSpecification',
'jobName', 'email', 'project' ]
@@ -48,8 +33,50 @@ class DRMAAJobRunner( AsynchronousJobRunner ):
"""
runner_name = "DRMAARunner"
- def __init__( self, app, nworkers ):
+ def __init__( self, app, nworkers, **kwargs ):
"""Start the job runner"""
+
+ global drmaa
+
+ runner_param_specs = dict(
+ drmaa_library_path = dict( map = str, default = os.environ.get( 'DRMAA_LIBRARY_PATH', None ) ),
+ invalidjobexception_state = dict( map = str, valid = lambda x: x in ( model.Job.states.OK, model.Job.states.ERROR ), default = model.Job.states.OK ),
+ invalidjobexception_retries = dict( map = int, valid = lambda x: int >= 0, default = 0 ),
+ internalexception_state = dict( map = str, valid = lambda x: x in ( model.Job.states.OK, model.Job.states.ERROR ), default = model.Job.states.OK ),
+ internalexception_retries = dict( map = int, valid = lambda x: int >= 0, default = 0 ) )
+
+ if 'runner_param_specs' not in kwargs:
+ kwargs[ 'runner_param_specs' ] = dict()
+ kwargs[ 'runner_param_specs' ].update( runner_param_specs )
+
+ super( DRMAAJobRunner, self ).__init__( app, nworkers, **kwargs )
+
+ # This allows multiple drmaa runners (although only one per handler) in the same job config file
+ if 'drmaa_library_path' in kwargs:
+ log.info( 'Overriding DRMAA_LIBRARY_PATH due to runner plugin parameter: %s', self.runner_params.drmaa_library_path )
+ os.environ['DRMAA_LIBRARY_PATH'] = self.runner_params.drmaa_library_path
+
+ # We foolishly named this file the same as the name exported by the drmaa
+ # library... 'import drmaa' imports itself.
+ drmaa = __import__( "drmaa" )
+
+ # Subclasses may need access to state constants
+ self.drmaa_job_states = drmaa.JobState
+
+ # Descriptive state strings pulled from the drmaa lib itself
+ self.drmaa_job_state_strings = {
+ drmaa.JobState.UNDETERMINED: 'process status cannot be determined',
+ drmaa.JobState.QUEUED_ACTIVE: 'job is queued and active',
+ drmaa.JobState.SYSTEM_ON_HOLD: 'job is queued and in system hold',
+ drmaa.JobState.USER_ON_HOLD: 'job is queued and in user hold',
+ drmaa.JobState.USER_SYSTEM_ON_HOLD: 'job is queued and in user and system hold',
+ drmaa.JobState.RUNNING: 'job is running',
+ drmaa.JobState.SYSTEM_SUSPENDED: 'job is system suspended',
+ drmaa.JobState.USER_SUSPENDED: 'job is user suspended',
+ drmaa.JobState.DONE: 'job finished normally',
+ drmaa.JobState.FAILED: 'job finished, but failed',
+ }
+
self.ds = drmaa.Session()
self.ds.initialize()
@@ -58,7 +85,6 @@ class DRMAAJobRunner( AsynchronousJobRunner ):
self.external_killJob_script = app.config.drmaa_external_killjob_script
self.userid = None
- super( DRMAAJobRunner, self ).__init__( app, nworkers )
self._init_monitor_thread()
self._init_worker_threads()
@@ -137,8 +163,10 @@ class DRMAAJobRunner( AsynchronousJobRunner ):
job_wrapper.cleanup()
return
- log.debug( "(%s) submitting file %s" % ( galaxy_id_tag, ajs.job_file ) )
- log.debug( "(%s) command is: %s" % ( galaxy_id_tag, command_line ) )
+ log.debug( "(%s) submitting file %s", galaxy_id_tag, ajs.job_file )
+ log.debug( "(%s) command is: %s", galaxy_id_tag, command_line )
+ if native_spec:
+ log.debug( "(%s) native specification is: %s", galaxy_id_tag, native_spec )
# runJob will raise if there's a submit problem
if self.external_runJob_script is None:
@@ -175,6 +203,20 @@ class DRMAAJobRunner( AsynchronousJobRunner ):
# Add to our 'queue' of jobs to monitor
self.monitor_queue.put( ajs )
+ def _complete_terminal_job( self, ajs, drmaa_state, **kwargs ):
+ """
+ Handle a job upon its termination in the DRM. This method is meant to
+ be overridden by subclasses to improve post-mortem and reporting of
+ failures.
+ """
+ if drmaa_state == drmaa.JobState.FAILED:
+ if ajs.job_wrapper.get_state() != model.Job.states.DELETED:
+ ajs.stop_job = False
+ ajs.fail_message = "The cluster DRM system terminated this job"
+ self.work_queue.put( ( self.fail_job, ajs ) )
+ elif drmaa_state == drmaa.JobState.DONE:
+ super( DRMAAJobRunner, self )._complete_terminal_job( ajs )
+
def check_watched_items( self ):
"""
Called by the monitor thread to look at each watched job and deal
@@ -188,16 +230,27 @@ class DRMAAJobRunner( AsynchronousJobRunner ):
try:
assert external_job_id not in ( None, 'None' ), '(%s/%s) Invalid job id' % ( galaxy_id_tag, external_job_id )
state = self.ds.jobStatus( external_job_id )
- # InternalException was reported to be necessary on some DRMs, but
- # this could cause failures to be detected as completion! Please
- # report if you experience problems with this.
- except ( drmaa.InvalidJobException, drmaa.InternalException ), e:
- # we should only get here if an orphaned job was put into the queue at app startup
- log.info( "(%s/%s) job left DRM queue with following message: %s" % ( galaxy_id_tag, external_job_id, e ) )
- self.work_queue.put( ( self.finish_job, ajs ) )
+ except ( drmaa.InternalException, drmaa.InvalidJobException ), e:
+ ecn = e.__class__.__name__
+ retry_param = ecn.lower() + '_retries'
+ state_param = ecn.lower() + '_state'
+ retries = getattr( ajs, retry_param, 0 )
+ if self.runner_params[ retry_param ] > 0:
+ if retries < self.runner_params[ retry_param ]:
+ # will retry check on next iteration
+ setattr( ajs, retry_param, retries + 1 )
+ continue
+ if self.runner_params[ state_param ] == model.Job.states.OK:
+ log.info( "(%s/%s) job left DRM queue with following message: %s", galaxy_id_tag, external_job_id, e )
+ self.work_queue.put( ( self.finish_job, ajs ) )
+ elif self.runner_params[ state_param ] == model.Job.states.ERROR:
+ log.info( "(%s/%s) job check resulted in %s after %s tries: %s", galaxy_id_tag, external_job_id, ecn, retries, e )
+ self.work_queue.put( ( self.fail_job, ajs ) )
+ else:
+ raise Exception( "%s is set to an invalid value (%s), this should not be possible. See galaxy.jobs.drmaa.__init__()", state_param, self.runner_params[ state_param ] )
continue
except drmaa.DrmCommunicationException, e:
- log.warning( "(%s/%s) unable to communicate with DRM: %s" % ( galaxy_id_tag, external_job_id, e ))
+ log.warning( "(%s/%s) unable to communicate with DRM: %s", galaxy_id_tag, external_job_id, e )
new_watched.append( ajs )
continue
except Exception, e:
@@ -208,19 +261,12 @@ class DRMAAJobRunner( AsynchronousJobRunner ):
self.work_queue.put( ( self.fail_job, ajs ) )
continue
if state != old_state:
- log.debug( "(%s/%s) state change: %s" % ( galaxy_id_tag, external_job_id, drmaa_state[state] ) )
+ log.debug( "(%s/%s) state change: %s" % ( galaxy_id_tag, external_job_id, self.drmaa_job_state_strings[state] ) )
if state == drmaa.JobState.RUNNING and not ajs.running:
ajs.running = True
ajs.job_wrapper.change_state( model.Job.states.RUNNING )
- if state == drmaa.JobState.FAILED:
- if ajs.job_wrapper.get_state() != model.Job.states.DELETED:
- ajs.stop_job = False
- ajs.fail_message = "The cluster DRM system terminated this job"
- self.work_queue.put( ( self.fail_job, ajs ) )
- continue
- if state == drmaa.JobState.DONE:
- if ajs.job_wrapper.get_state() != model.Job.states.DELETED:
- self.work_queue.put( ( self.finish_job, ajs ) )
+ if state in ( drmaa.JobState.FAILED, drmaa.JobState.DONE ):
+ self._complete_terminal_job( ajs, drmaa_state = state )
continue
ajs.old_state = state
new_watched.append( ajs )
diff --git a/lib/galaxy/jobs/runners/slurm.py b/lib/galaxy/jobs/runners/slurm.py
new file mode 100644
index 00000000000..51b7df56c79
--- /dev/null
+++ b/lib/galaxy/jobs/runners/slurm.py
@@ -0,0 +1,57 @@
+"""
+SLURM job control via the DRMAA API.
+"""
+
+import time
+import logging
+import subprocess
+
+from galaxy import model
+from galaxy.jobs.runners.drmaa import DRMAAJobRunner
+
+log = logging.getLogger( __name__ )
+
+__all__ = [ 'SlurmJobRunner' ]
+
+
+class SlurmJobRunner( DRMAAJobRunner ):
+ runner_name = "SlurmRunner"
+
+ def _complete_terminal_job( self, ajs, drmaa_state, **kwargs ):
+ def __get_jobinfo():
+ scontrol_out = subprocess.check_output( ( 'scontrol', '-o', 'show', 'job', ajs.job_id ) )
+ return dict( [ out_param.split( '=', 1 ) for out_param in scontrol_out.split() ] )
+ if drmaa_state == self.drmaa_job_states.FAILED:
+ try:
+ job_info = __get_jobinfo()
+ sleep = 1
+ while job_info['JobState'] == 'COMPLETING':
+ log.debug( '(%s/%s) Waiting %s seconds for failed job to exit COMPLETING state for post-mortem', ajs.job_wrapper.get_id_tag(), ajs.job_id, sleep )
+ time.sleep( sleep )
+ sleep *= 2
+ if sleep > 64:
+ ajs.fail_message = "This job failed and the system timed out while trying to determine the cause of the failure."
+ break
+ job_info = __get_jobinfo()
+ if job_info['JobState'] == 'TIMEOUT':
+ ajs.fail_message = "This job was terminated because it ran longer than the maximum allowed job run time."
+ elif job_info['JobState'] == 'NODE_FAIL':
+ log.warning( '(%s/%s) Job failed due to node failure, attempting resubmission', ajs.job_wrapper.get_id_tag(), ajs.job_id )
+ ajs.job_wrapper.change_state( model.Job.states.QUEUED, info = 'Job was resubmitted due to node failure' )
+ try:
+ self.queue_job( ajs.job_wrapper )
+ return
+ except:
+ ajs.fail_message = "This job failed due to a cluster node failure, and an attempt to resubmit the job failed."
+ elif job_info['JobState'] == 'CANCELLED':
+ ajs.fail_message = "This job failed because it was cancelled by an administrator."
+ else:
+ ajs.fail_message = "This job failed for reasons that could not be determined."
+ ajs.fail_message += '\nPlease click the bug icon to report this problem if you need help.'
+ ajs.stop_job = False
+ self.work_queue.put( ( self.fail_job, ajs ) )
+ except Exception, e:
+ log.exception( '(%s/%s) Unable to inspect failed slurm job using scontrol, job will be unconditionally failed: %s', ajs.job_wrapper.get_id_tag(), ajs.job_id, e )
+ super( SlurmJobRunner, self )._complete_terminal_job( ajs, drmaa_state = drmaa_state )
+ elif drmaa_state == self.drmaa_job_states.DONE:
+ super( SlurmJobRunner, self )._complete_terminal_job( ajs, drmaa_state = drmaa_state )
diff --git a/lib/galaxy/model/__init__.py b/lib/galaxy/model/__init__.py
index 7075562f274..7c4dc29e196 100644
--- a/lib/galaxy/model/__init__.py
+++ b/lib/galaxy/model/__init__.py
@@ -18,6 +18,7 @@ import json
import socket
import time
from string import Template
+from itertools import ifilter
import galaxy.datatypes
import galaxy.datatypes.registry
@@ -42,6 +43,11 @@ datatypes_registry = galaxy.datatypes.registry.Registry()
# Default Value Required for unit tests
datatypes_registry.load_datatypes()
+# When constructing filters with in for a fixed set of ids, maximum
+# number of items to place in the IN statement. Different databases
+# are going to have different limits so it is likely best to not let
+# this be unlimited - filter in Python if over this limit.
+MAX_IN_FILTER_LENGTH = 100
class NoConverterException(Exception):
def __init__(self, value):
@@ -892,6 +898,33 @@ class History( object, Dictifiable, UsesAnnotations ):
rval = galaxy.datatypes.data.nice_size( rval )
return rval
+ def contents_iter( self, **kwds ):
+ """
+ Fetch filtered list of contents of history.
+ """
+ python_filter = None
+ db_session = object_session( self )
+ assert db_session != None
+ query = db_session.query( HistoryDatasetAssociation ).filter( HistoryDatasetAssociation.table.c.history_id == self.id )
+ query = query.order_by( HistoryDatasetAssociation.table.c.hid.asc() )
+ deleted = galaxy.util.string_as_bool_or_none( kwds.get( 'deleted', None ) )
+ if deleted is not None:
+ query = query.filter( HistoryDatasetAssociation.deleted == bool( kwds['deleted'] ) )
+ visible = galaxy.util.string_as_bool_or_none( kwds.get( 'visible', None ) )
+ if visible is not None:
+ query = query.filter( HistoryDatasetAssociation.visible == bool( kwds['visible'] ) )
+ if 'ids' in kwds:
+ ids = kwds['ids']
+ max_in_filter_length = kwds.get('max_in_filter_length', MAX_IN_FILTER_LENGTH)
+ if len(ids) < max_in_filter_length:
+ query = query.filter( HistoryDatasetAssociation.id.in_(ids) )
+ else:
+ python_filter = lambda hda: hda.id in ids
+ if python_filter:
+ return ifilter(python_filter, query)
+ else:
+ return query
+
def copy_tags_from(self,target_user,source_history):
for src_shta in source_history.tags:
new_shta = src_shta.copy()
diff --git a/lib/galaxy/webapps/galaxy/api/history_contents.py b/lib/galaxy/webapps/galaxy/api/history_contents.py
index 25a65e45c39..e77f05d9841 100644
--- a/lib/galaxy/webapps/galaxy/api/history_contents.py
+++ b/lib/galaxy/webapps/galaxy/api/history_contents.py
@@ -51,47 +51,28 @@ class HistoryContentsController( BaseAPIController, UsesHistoryDatasetAssociatio
else:
history = self.get_history( trans, history_id, check_ownership=True, check_accessible=True )
- # if ids, return _FULL_ data (as show) for each id passed
+ contents_kwds = {}
if ids:
- ids = ids.split( ',' )
- for index, hda in enumerate( history.datasets ):
- encoded_hda_id = trans.security.encode_id( hda.id )
- if encoded_hda_id in ids:
- #TODO: share code with show
- rval.append( self._detailed_hda_dict( trans, hda ) )
-
- # if no ids passed, return a _SUMMARY_ of _all_ datasets in the history
+ ids = map( lambda id: trans.security.decode_id( id ), ids.split( ',' ) )
+ contents_kwds[ 'ids' ] = ids
+ # If explicit ids given, always used detailed result.
+ details = 'all'
else:
+ contents_kwds[ 'deleted' ] = kwd.get( 'deleted', None )
+ contents_kwds[ 'visible' ] = kwd.get( 'visible', None )
# details param allows a mixed set of summary and detailed hdas
#TODO: this is getting convoluted due to backwards compat
details = kwd.get( 'details', None ) or []
if details and details != 'all':
details = util.listify( details )
- # by default return all datasets - even if deleted or hidden (defaulting the next switches to None)
- # if specified return those datasets that match the setting
- # backwards compat
- return_deleted = util.string_as_bool_or_none( kwd.get( 'deleted', None ) )
- return_visible = util.string_as_bool_or_none( kwd.get( 'visible', None ) )
-
- for hda in history.datasets:
- # if either return_ setting has been requested (!= None), skip hdas that don't match the request
- if return_deleted is not None:
- if( ( return_deleted and not hda.deleted )
- or ( not return_deleted and hda.deleted ) ):
- continue
- if return_visible is not None:
- if( ( return_visible and not hda.visible )
- or ( not return_visible and hda.visible ) ):
- continue
-
- encoded_hda_id = trans.security.encode_id( hda.id )
- if( ( encoded_hda_id in details )
- or ( details == 'all' ) ):
- rval.append( self._detailed_hda_dict( trans, hda ) )
- else:
- rval.append( self._summary_hda_dict( trans, history_id, hda ) )
-
+ for hda in history.contents_iter( **contents_kwds ):
+ encoded_hda_id = trans.security.encode_id( hda.id )
+ detailed = details == 'all' or ( encoded_hda_id in details )
+ if detailed:
+ rval.append( self._detailed_hda_dict( trans, hda ) )
+ else:
+ rval.append( self._summary_hda_dict( trans, history_id, hda ) )
except Exception, e:
# for errors that are not specific to one hda (history lookup or summary list)
rval = "Error in history API at listing contents: " + str( e )
diff --git a/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py b/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py
index 7d30c4cbbfb..795183b562e 100644
--- a/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py
+++ b/lib/galaxy/webapps/galaxy/api/tool_shed_repositories.py
@@ -19,11 +19,6 @@ import tool_shed.util.shed_util_common as suc
log = logging.getLogger( __name__ )
-def default_tool_shed_repository_value_mapper( trans, tool_shed_repository ):
- value_mapper={ 'id' : trans.security.encode_id( tool_shed_repository.id ),
- 'error_message' : tool_shed_repository.error_message or '' }
- return value_mapper
-
def get_message_for_no_shed_tool_config():
# This Galaxy instance is not configured with a shed-related tool panel configuration file.
message = 'The tool_config_file setting in universe_wsgi.ini must include at least one shed tool configuration file name with a '
@@ -48,8 +43,8 @@ class ToolShedRepositoriesController( BaseAPIController ):
:param id: the encoded id of the ToolShedRepository object
"""
# Example URL: http://localhost:8763/api/tool_shed_repositories/f2db41e1fa331b3e/exported_workflows
- # Since exported workflows are dictionaries with very few attributes that differentiate them from each other, we'll build the
- # list based on the following dictionary of those few attributes.
+ # Since exported workflows are dictionaries with very few attributes that differentiate them from each
+ # other, we'll build the list based on the following dictionary of those few attributes.
exported_workflows = []
repository = suc.get_tool_shed_repository_by_id( trans, id )
metadata = repository.metadata
@@ -58,17 +53,23 @@ class ToolShedRepositoriesController( BaseAPIController ):
else:
exported_workflow_tups = []
for index, exported_workflow_tup in enumerate( exported_workflow_tups ):
- # The exported_workflow_tup looks like ( relative_path, exported_workflow_dict ), where the value of relative_path is the location
- # on disk (relative to the root of the installed repository) where the exported_workflow_dict file (.ga file) is located.
+ # The exported_workflow_tup looks like ( relative_path, exported_workflow_dict ), where the value of
+ # relative_path is the location on disk (relative to the root of the installed repository) where the
+ # exported_workflow_dict file (.ga file) is located.
exported_workflow_dict = exported_workflow_tup[ 1 ]
annotation = exported_workflow_dict.get( 'annotation', '' )
format_version = exported_workflow_dict.get( 'format-version', '' )
workflow_name = exported_workflow_dict.get( 'name', '' )
- # Since we don't have an in-memory object with an id, we'll identify the exported workflow via it's location (i.e., index) in the list.
+ # Since we don't have an in-memory object with an id, we'll identify the exported workflow via it's
+ # location (i.e., index) in the list.
display_dict = dict( index=index, annotation=annotation, format_version=format_version, workflow_name=workflow_name )
exported_workflows.append( display_dict )
return exported_workflows
+ def __get_value_mapper( self, trans ):
+ value_mapper = { 'id' : trans.security.encode_id }
+ return value_mapper
+
@web.expose_api
def import_workflow( self, trans, payload, **kwd ):
"""
@@ -96,13 +97,11 @@ class ToolShedRepositoriesController( BaseAPIController ):
# Since we don't have an in-memory object with an id, we'll identify the exported workflow via it's location (i.e., index) in the list.
exported_workflow = exported_workflows[ int( index ) ]
workflow_name = exported_workflow[ 'workflow_name' ]
- workflow, status, message = workflow_util.import_workflow( trans, repository, workflow_name )
+ workflow, status, error_message = workflow_util.import_workflow( trans, repository, workflow_name )
if status == 'error':
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
- else:
- return workflow.to_dict( view='element' )
+ log.debug( error_message )
+ return {}
+ return workflow.to_dict( view='element' )
@web.expose_api
def import_workflows( self, trans, **kwd ):
@@ -125,11 +124,9 @@ class ToolShedRepositoriesController( BaseAPIController ):
imported_workflow_dicts = []
for exported_workflow_dict in exported_workflows:
workflow_name = exported_workflow_dict[ 'workflow_name' ]
- workflow, status, message = workflow_util.import_workflow( trans, repository, workflow_name )
+ workflow, status, error_message = workflow_util.import_workflow( trans, repository, workflow_name )
if status == 'error':
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ log.debug( error_message )
else:
imported_workflow_dicts.append( workflow.to_dict( view='element' ) )
return imported_workflow_dicts
@@ -142,22 +139,15 @@ class ToolShedRepositoriesController( BaseAPIController ):
"""
# Example URL: http://localhost:8763/api/tool_shed_repositories
tool_shed_repository_dicts = []
- try:
- query = trans.install_model.context.query( trans.app.install_model.ToolShedRepository ) \
- .order_by( trans.app.install_model.ToolShedRepository.table.c.name ) \
- .all()
- for tool_shed_repository in query:
- tool_shed_repository_dict = tool_shed_repository.to_dict( value_mapper=default_tool_shed_repository_value_mapper( trans, tool_shed_repository ) )
- tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories',
- action='show',
- id=trans.security.encode_id( tool_shed_repository.id ) )
- tool_shed_repository_dicts.append( tool_shed_repository_dict )
- return tool_shed_repository_dicts
- except Exception, e:
- message = "Error in the tool_shed_repositories API in index: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ for tool_shed_repository in trans.install_model.context.query( trans.app.install_model.ToolShedRepository ) \
+ .order_by( trans.app.install_model.ToolShedRepository.table.c.name ):
+ tool_shed_repository_dict = \
+ tool_shed_repository.to_dict( value_mapper=self.__get_value_mapper( trans ) )
+ tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories',
+ action='show',
+ id=trans.security.encode_id( tool_shed_repository.id ) )
+ tool_shed_repository_dicts.append( tool_shed_repository_dict )
+ return tool_shed_repository_dicts
@web.expose_api
def install_repository_revision( self, trans, payload, **kwd ):
@@ -208,8 +198,7 @@ class ToolShedRepositoriesController( BaseAPIController ):
# Make sure this Galaxy instance is configured with a shed-related tool panel configuration file.
if not suc.have_shed_tool_conf_for_install( trans ):
message = get_message_for_no_shed_tool_config()
- log.error( message, exc_info=True )
- trans.response.status = 500
+ log.debug( message )
return dict( status='error', error=message )
# Make sure the current user's API key proves he is an admin user in this Galaxy instance.
if not trans.user_is_admin():
@@ -225,18 +214,20 @@ class ToolShedRepositoriesController( BaseAPIController ):
except Exception, e:
message = "Error attempting to retrieve installation information from tool shed %s for revision %s of repository %s owned by %s: %s" % \
( str( tool_shed_url ), str( changeset_revision ), str( name ), str( owner ), str( e ) )
- log.error( message, exc_info=True )
- trans.response.status = 500
+ log.debug( message )
return dict( status='error', error=message )
if raw_text:
+ # If successful, the response from get_repository_revision_install_info will be 3
+ # dictionaries, a dictionary defining the Repository, a dictionary defining the
+ # Repository revision (RepositoryMetadata), and a dictionary including the additional
+ # information required to install the repository.
items = json.from_json_string( raw_text )
repository_revision_dict = items[ 1 ]
repo_info_dict = items[ 2 ]
else:
message = "Unable to retrieve installation information from tool shed %s for revision %s of repository %s owned by %s: %s" % \
( str( tool_shed_url ), str( changeset_revision ), str( name ), str( owner ), str( e ) )
- log.error( message, exc_info=True )
- trans.response.status = 500
+ log.debug( message )
return dict( status='error', error=message )
repo_info_dicts = [ repo_info_dict ]
# Make sure the tool shed returned everything we need for installing the repository.
@@ -345,7 +336,7 @@ class ToolShedRepositoriesController( BaseAPIController ):
tool_path,
install_tool_dependencies,
reinstalling=False )
- tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=default_tool_shed_repository_value_mapper( trans, tool_shed_repository ) )
+ tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=self.__get_value_mapper( trans ) )
tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories',
action='show',
id=trans.security.encode_id( tool_shed_repository.id ) )
@@ -394,8 +385,7 @@ class ToolShedRepositoriesController( BaseAPIController ):
if not suc.have_shed_tool_conf_for_install( trans ):
# This Galaxy instance is not configured with a shed-related tool panel configuration file.
message = get_message_for_no_shed_tool_config()
- log.error( message, exc_info=True )
- trans.response.status = 500
+ log.debug( message )
return dict( status='error', error=message )
if not trans.user_is_admin():
raise HTTPForbidden( detail='You are not authorized to install a tool shed repository into this Galaxy instance.' )
@@ -410,8 +400,7 @@ class ToolShedRepositoriesController( BaseAPIController ):
len( changeset_revisions ) != num_specified_repositories:
message = 'Error in tool_shed_repositories API in install_repository_revisions: the received parameters must be ordered '
message += 'lists so that positional values in tool_shed_urls, names, owners and changeset_revisions are associated.'
- log.error( message, exc_info=True )
- trans.response.status = 500
+ log.debug( message )
return dict( status='error', error=message )
# Get the information about the Galaxy components (e.g., tool pane section, tool config file, etc) that will contain information
# about each of the repositories being installed.
@@ -482,7 +471,7 @@ class ToolShedRepositoriesController( BaseAPIController ):
repair_dict = repository_util.repair_tool_shed_repository( trans,
repository,
encoding_util.tool_shed_encode( repo_info_dict ) )
- repository_dict = repository.to_dict( value_mapper=default_tool_shed_repository_value_mapper( trans, repository ) )
+ repository_dict = repository.to_dict( value_mapper=self.__get_value_mapper( trans ) )
repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories',
action='show',
id=trans.security.encode_id( repository.id ) )
@@ -502,39 +491,39 @@ class ToolShedRepositoriesController( BaseAPIController ):
:param key: the API key of the Galaxy admin user.
"""
- try:
- start_time = strftime( "%Y-%m-%d %H:%M:%S" )
- results = dict( start_time=start_time,
- successful_count=0,
- unsuccessful_count=0,
- repository_status=[] )
- # Make sure the current user's API key proves he is an admin user in this Galaxy instance.
- if not trans.user_is_admin():
- raise HTTPForbidden( detail='You are not authorized to reset metadata on repositories installed into this Galaxy instance.' )
- query = suc.get_query_for_setting_metadata_on_repositories( trans, my_writable=False, order=False )
- # Now reset metadata on all remaining repositories.
- for repository in query:
- repository_id = trans.security.encode_id( repository.id )
- try:
- invalid_file_tups, metadata_dict = metadata_util.reset_all_metadata_on_installed_repository( trans, repository_id )
- if invalid_file_tups:
- message = tool_util.generate_message_for_invalid_tools( trans, invalid_file_tups, repository, None, as_html=False )
- results[ 'unsuccessful_count' ] += 1
- else:
- message = "Successfully reset metadata on repository %s owned by %s" % ( str( repository.name ), str( repository.owner ) )
- results[ 'successful_count' ] += 1
- except Exception, e:
- message = "Error resetting metadata on repository %s owned by %s: %s" % ( str( repository.name ), str( repository.owner ), str( e ) )
+ start_time = strftime( "%Y-%m-%d %H:%M:%S" )
+ results = dict( start_time=start_time,
+ successful_count=0,
+ unsuccessful_count=0,
+ repository_status=[] )
+ # Make sure the current user's API key proves he is an admin user in this Galaxy instance.
+ if not trans.user_is_admin():
+ raise HTTPForbidden( detail='You are not authorized to reset metadata on repositories installed into this Galaxy instance.' )
+ query = suc.get_query_for_setting_metadata_on_repositories( trans, my_writable=False, order=False )
+ # Now reset metadata on all remaining repositories.
+ for repository in query:
+ repository_id = trans.security.encode_id( repository.id )
+ try:
+ invalid_file_tups, metadata_dict = metadata_util.reset_all_metadata_on_installed_repository( trans, repository_id )
+ if invalid_file_tups:
+ message = tool_util.generate_message_for_invalid_tools( trans,
+ invalid_file_tups,
+ repository,
+ None,
+ as_html=False )
results[ 'unsuccessful_count' ] += 1
- results[ 'repository_status' ].append( message )
- stop_time = strftime( "%Y-%m-%d %H:%M:%S" )
- results[ 'stop_time' ] = stop_time
- return json.to_json_string( results, sort_keys=True, indent=4 * ' ' )
- except Exception, e:
- message = "Error in the Galaxy tool_shed_repositories API in reset_metadata_on_installed_repositories: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ else:
+ message = "Successfully reset metadata on repository %s owned by %s" % \
+ ( str( repository.name ), str( repository.owner ) )
+ results[ 'successful_count' ] += 1
+ except Exception, e:
+ message = "Error resetting metadata on repository %s owned by %s: %s" % \
+ ( str( repository.name ), str( repository.owner ), str( e ) )
+ results[ 'unsuccessful_count' ] += 1
+ results[ 'repository_status' ].append( message )
+ stop_time = strftime( "%Y-%m-%d %H:%M:%S" )
+ results[ 'stop_time' ] = stop_time
+ return json.to_json_string( results, sort_keys=True, indent=4 * ' ' )
@web.expose_api
def show( self, trans, id, **kwd ):
@@ -545,15 +534,12 @@ class ToolShedRepositoriesController( BaseAPIController ):
:param id: the encoded id of the ToolShedRepository object
"""
# Example URL: http://localhost:8763/api/tool_shed_repositories/df7a1f0c02a5b08e
- try:
- tool_shed_repository = suc.get_tool_shed_repository_by_id( trans, id )
- tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=default_tool_shed_repository_value_mapper( trans, tool_shed_repository ) )
- tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories',
- action='show',
- id=trans.security.encode_id( tool_shed_repository.id ) )
- return tool_shed_repository_dict
- except Exception, e:
- message = "Error in tool_shed_repositories API in index: " + str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ tool_shed_repository = suc.get_tool_shed_repository_by_id( trans, id )
+ if tool_shed_repository is None:
+ log.debug( "Unable to locate tool_shed_repository record for id %s." % ( str( id ) ) )
+ return {}
+ tool_shed_repository_dict = tool_shed_repository.as_dict( value_mapper=self.__get_value_mapper( trans ) )
+ tool_shed_repository_dict[ 'url' ] = web.url_for( controller='tool_shed_repositories',
+ action='show',
+ id=trans.security.encode_id( tool_shed_repository.id ) )
+ return tool_shed_repository_dict
diff --git a/lib/galaxy/webapps/tool_shed/api/repositories.py b/lib/galaxy/webapps/tool_shed/api/repositories.py
index 726d744687f..61dffc14979 100644
--- a/lib/galaxy/webapps/tool_shed/api/repositories.py
+++ b/lib/galaxy/webapps/tool_shed/api/repositories.py
@@ -36,22 +36,27 @@ class RepositoriesController( BaseAPIController ):
:param name: the name of the Repository
:param owner: the owner of the Repository
- Returns the ordered list of changeset revision hash strings that are associated with installable revisions. As in the changelog, the
- list is ordered oldest to newest.
+ Returns the ordered list of changeset revision hash strings that are associated with installable revisions.
+ As in the changelog, the list is ordered oldest to newest.
"""
# Example URL: http://localhost:9009/api/repositories/get_installable_revisions?name=add_column&owner=test
- try:
+ if name and owner:
# Get the repository information.
repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
+ if repository is None:
+ error_message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: "
+ error_message += "cannot locate repository %s owned by %s." % ( str( name ), str( owner ) )
+ log.debug( error_message )
+ return []
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
ordered_installable_revisions = suc.get_ordered_metadata_changeset_revisions( repository, repo, downloadable=True )
return ordered_installable_revisions
- except Exception, e:
- message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ else:
+ error_message = "Error in the Tool Shed repositories API in get_ordered_installable_revisions: "
+ error_message += "invalid name %s or owner %s received." % ( str( name ), str( owner ) )
+ log.debug( error_message )
+ return []
@web.expose_api_anonymous
def get_repository_revision_install_info( self, trans, name, owner, changeset_revision, **kwd ):
@@ -106,49 +111,65 @@ class RepositoriesController( BaseAPIController ):
]
}
"""
- 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?name=add_column&owner=test&changeset_revision=3a08cc21466f
- try:
+ # Example URL:
+ # http:///api/repositories/get_repository_revision_install_info?name=&owner=&changeset_revision=
+ if name and owner and changeset_revision:
# Get the repository information.
repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
+ if repository is None:
+ log.debug( 'Cannot locate repository %s owned by %s' % ( str( name ), str( owner ) ) )
+ return {}, {}, {}
encoded_repository_id = trans.security.encode_id( repository.id )
- repository_dict = repository.to_dict( view='element', value_mapper=repository_value_mapper )
+ repository_dict = repository.to_dict( view='element',
+ value_mapper=self.__get_value_mapper( trans ) )
repository_dict[ 'url' ] = web.url_for( controller='repositories',
action='show',
id=encoded_repository_id )
# Get the repository_metadata information.
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ encoded_repository_id,
+ changeset_revision )
if not repository_metadata:
- # The changeset_revision column in the repository_metadata table has been updated with a new value value, so find the
- # changeset_revision to which we need to update.
+ # The changeset_revision column in the repository_metadata table has been updated with a new
+ # value value, so find the changeset_revision to which we need to update.
repo_dir = repository.repo_path( trans.app )
repo = hg.repository( suc.get_configured_ui(), repo_dir )
new_changeset_revision = suc.get_next_downloadable_changeset_revision( repository, repo, changeset_revision )
- repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, encoded_repository_id, new_changeset_revision )
+ repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans,
+ encoded_repository_id,
+ new_changeset_revision )
changeset_revision = new_changeset_revision
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=self.__get_value_mapper( trans, repository_metadata ) )
+ value_mapper=self.__get_value_mapper( trans ) )
repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
action='show',
id=encoded_repository_metadata_id )
# Get the repo_info_dict for installing the repository.
- repo_info_dict, includes_tools, includes_tool_dependencies, includes_tools_for_display_in_tool_panel, \
- has_repository_dependencies, has_repository_dependencies_only_if_compiling_contained_td = \
+ repo_info_dict, \
+ includes_tools, \
+ includes_tool_dependencies, \
+ includes_tools_for_display_in_tool_panel, \
+ has_repository_dependencies, \
+ has_repository_dependencies_only_if_compiling_contained_td = \
repository_util.get_repo_info_dict( trans, encoded_repository_id, changeset_revision )
return repository_dict, repository_metadata_dict, repo_info_dict
else:
- message = "Unable to locate repository_metadata record for repository id %d and changeset_revision %s" % ( repository.id, changeset_revision )
- log.error( message, exc_info=True )
- trans.response.status = 500
+ log.debug( "Unable to locate repository_metadata record for repository id %s and changeset_revision %s" % \
+ ( str( repository.id ), str( changeset_revision ) ) )
return repository_dict, {}, {}
- except Exception, e:
- message = "Error in the Tool Shed repositories API in get_repository_revision_install_info: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ else:
+ debug_msg = "Error in the Tool Shed repositories API in get_repository_revision_install_info: "
+ debug_msg += "Invalid name %s or owner %s or changeset_revision %s received." % \
+ ( str( name ), str( owner ), str( changeset_revision ) )
+ log.debug( debug_msg )
+ return {}, {}, {}
+
+ def __get_value_mapper( self, trans ):
+ value_mapper = { 'id' : trans.security.encode_id,
+ 'repository_id' : trans.security.encode_id }
+ return value_mapper
@web.expose_api
def import_capsule( self, trans, payload, **kwd ):
@@ -177,29 +198,27 @@ class RepositoriesController( BaseAPIController ):
uploaded_file=None,
capsule_file_name=None )
if os.path.getsize( os.path.abspath( capsule_file_name ) ) == 0:
- message = 'Your capsule file is empty.'
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ log.debug( 'Your capsule file %s is empty.' % str( capsule_file_name ) )
+ return {}
try:
# Open for reading with transparent compression.
tar_archive = tarfile.open( capsule_file_path, 'r:*' )
except tarfile.ReadError, e:
- message = 'Error opening file %s: %s' % ( str( capsule_file_name ), str( e ) )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ log.debug( 'Error opening capsule file %s: %s' % ( str( capsule_file_name ), str( e ) ) )
+ return {}
capsule_dict[ 'tar_archive' ] = tar_archive
capsule_dict[ 'capsule_file_name' ] = capsule_file_name
capsule_dict = import_util.extract_capsule_files( trans, **capsule_dict )
capsule_dict = import_util.validate_capsule( trans, **capsule_dict )
status = capsule_dict.get( 'status', 'error' )
if status == 'error':
- message = 'The capsule contents are invalid and cannpt be imported: %s' % str( capsule_dict.get( 'error_message', '' ) )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ log.debug( 'The capsule contents are invalid and cannpt be imported: %s' % \
+ str( capsule_dict.get( 'error_message', '' ) ) )
+ return {}
encoded_file_path = capsule_dict.get( 'encoded_file_path', None )
+ if encoded_file_path is None:
+ log.debug( 'The capsule_dict %s is missing the required encoded_file_path entry.' % str( capsule_dict ) )
+ return {}
file_path = encoding_util.tool_shed_decode( encoded_file_path )
export_info_file_path = os.path.join( file_path, 'export_info.xml' )
export_info_dict = import_util.get_export_info_dict( export_info_file_path )
@@ -216,12 +235,14 @@ class RepositoriesController( BaseAPIController ):
# Add the capsule_file_name and encoded_file_path to the repository_status_info_dict.
repository_status_info_dict[ 'capsule_file_name' ] = capsule_file_name
repository_status_info_dict[ 'encoded_file_path' ] = encoded_file_path
- import_results_tups = repository_maintenance_util.create_repository_and_import_archive( trans,
- repository_status_info_dict,
- import_results_tups )
+ import_results_tups = \
+ repository_maintenance_util.create_repository_and_import_archive( trans,
+ repository_status_info_dict,
+ import_results_tups )
import_util.check_status_and_reset_downloadable( trans, import_results_tups )
suc.remove_dir( file_path )
- # NOTE: the order of installation is defined in import_results_tups, but order will be lost when transferred to return_dict.
+ # NOTE: the order of installation is defined in import_results_tups, but order will be lost
+ # when transferred to return_dict.
return_dict = {}
for import_results_tup in import_results_tups:
ok, name_owner, message = import_results_tup
@@ -237,28 +258,19 @@ class RepositoriesController( BaseAPIController ):
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 )
- try:
- query = trans.sa_session.query( trans.app.model.Repository ) \
- .filter( trans.app.model.Repository.table.c.deleted == deleted ) \
- .order_by( trans.app.model.Repository.table.c.name ) \
- .all()
- for repository in query:
- 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 ) )
- repository_dicts.append( repository_dict )
- return repository_dicts
- except Exception, e:
- message = "Error in the Tool Shed repositories API in index: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ deleted = util.asbool( deleted )
+ for repository in trans.sa_session.query( trans.app.model.Repository ) \
+ .filter( trans.app.model.Repository.table.c.deleted == deleted ) \
+ .order_by( trans.app.model.Repository.table.c.name ):
+ repository_dict = repository.to_dict( view='collection',
+ value_mapper=self.__get_value_mapper( trans ) )
+ repository_dict[ 'url' ] = web.url_for( controller='repositories',
+ action='show',
+ id=trans.security.encode_id( repository.id ) )
+ repository_dicts.append( repository_dict )
+ return repository_dicts
@web.expose_api
def repository_ids_for_setting_metadata( self, trans, my_writable=False, **kwd ):
@@ -273,28 +285,22 @@ class RepositoriesController( BaseAPIController ):
in addition to those repositories of type tool_dependency_definition. This param is ignored
if the current user is not an admin user, in which case this same restriction is automatic.
"""
- try:
- if trans.user_is_admin():
- my_writable = util.asbool( my_writable )
- else:
- my_writable = True
- handled_repository_ids = []
- repository_ids = []
- query = suc.get_query_for_setting_metadata_on_repositories( trans, my_writable=my_writable, order=False )
- # Make sure repositories of type tool_dependency_definition are first in the list.
- for repository in query:
- if repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
- repository_ids.append( trans.security.encode_id( repository.id ) )
- # Now add all remaining repositories to the list.
- for repository in query:
- if repository.type != rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
- repository_ids.append( trans.security.encode_id( repository.id ) )
- return repository_ids
- except Exception, e:
- message = "Error in the Tool Shed repositories API in repository_ids_for_setting_metadata: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ if trans.user_is_admin():
+ my_writable = util.asbool( my_writable )
+ else:
+ my_writable = True
+ handled_repository_ids = []
+ repository_ids = []
+ query = suc.get_query_for_setting_metadata_on_repositories( trans, my_writable=my_writable, order=False )
+ # Make sure repositories of type tool_dependency_definition are first in the list.
+ for repository in query:
+ if repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
+ repository_ids.append( trans.security.encode_id( repository.id ) )
+ # Now add all remaining repositories to the list.
+ for repository in query:
+ if repository.type != rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
+ repository_ids.append( trans.security.encode_id( repository.id ) )
+ return repository_ids
@web.expose_api
def reset_metadata_on_repositories( self, trans, payload, **kwd ):
@@ -318,6 +324,7 @@ class RepositoriesController( BaseAPIController ):
:param skip_file (optional): A local file name that contains the encoded repository ids associated with repositories to skip.
This param can be used as an alternative to the above encoded_ids_to_skip.
"""
+
def handle_repository( trans, repository, results ):
log.debug( "Resetting metadata on repository %s" % str( repository.name ) )
repository_id = trans.security.encode_id( repository.id )
@@ -335,53 +342,48 @@ class RepositoriesController( BaseAPIController ):
status = '%s : %s' % ( str( repository.name ), message )
results[ 'repository_status' ].append( status )
return results
- try:
- start_time = strftime( "%Y-%m-%d %H:%M:%S" )
- results = dict( start_time=start_time,
- repository_status=[],
- successful_count=0,
- unsuccessful_count=0 )
- handled_repository_ids = []
- encoded_ids_to_skip = payload.get( 'encoded_ids_to_skip', [] )
- skip_file = payload.get( 'skip_file', None )
- if skip_file and os.path.exists( skip_file ) and not encoded_ids_to_skip:
- # Load the list of encoded_ids_to_skip from the skip_file.
- # Contents of file must be 1 encoded repository id per line.
- lines = open( skip_file, 'rb' ).readlines()
- for line in lines:
- if line.startswith( '#' ):
- # Skip comments.
- continue
- encoded_ids_to_skip.append( line.rstrip( '\n' ) )
- if trans.user_is_admin():
- my_writable = util.asbool( payload.get( 'my_writable', False ) )
- else:
- my_writable = True
- query = suc.get_query_for_setting_metadata_on_repositories( trans, my_writable=my_writable, order=False )
- # First reset metadata on all repositories of type repository_dependency_definition.
- for repository in query:
- encoded_id = trans.security.encode_id( repository.id )
- if encoded_id in encoded_ids_to_skip:
- log.debug( "Skipping repository with id %s because it is in encoded_ids_to_skip %s" % \
- ( str( repository.id ), str( encoded_ids_to_skip ) ) )
- elif repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
- results = handle_repository( trans, repository, results )
- # Now reset metadata on all remaining repositories.
- for repository in query:
- encoded_id = trans.security.encode_id( repository.id )
- if encoded_id in encoded_ids_to_skip:
- log.debug( "Skipping repository with id %s because it is in encoded_ids_to_skip %s" % \
- ( str( repository.id ), str( encoded_ids_to_skip ) ) )
- elif repository.type != rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
- results = handle_repository( trans, repository, results )
- stop_time = strftime( "%Y-%m-%d %H:%M:%S" )
- results[ 'stop_time' ] = stop_time
- return json.to_json_string( results, sort_keys=True, indent=4 * ' ' )
- except Exception, e:
- message = "Error in the Tool Shed repositories API in reset_metadata_on_repositories: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+
+ start_time = strftime( "%Y-%m-%d %H:%M:%S" )
+ results = dict( start_time=start_time,
+ repository_status=[],
+ successful_count=0,
+ unsuccessful_count=0 )
+ handled_repository_ids = []
+ encoded_ids_to_skip = payload.get( 'encoded_ids_to_skip', [] )
+ skip_file = payload.get( 'skip_file', None )
+ if skip_file and os.path.exists( skip_file ) and not encoded_ids_to_skip:
+ # Load the list of encoded_ids_to_skip from the skip_file.
+ # Contents of file must be 1 encoded repository id per line.
+ lines = open( skip_file, 'rb' ).readlines()
+ for line in lines:
+ if line.startswith( '#' ):
+ # Skip comments.
+ continue
+ encoded_ids_to_skip.append( line.rstrip( '\n' ) )
+ if trans.user_is_admin():
+ my_writable = util.asbool( payload.get( 'my_writable', False ) )
+ else:
+ my_writable = True
+ query = suc.get_query_for_setting_metadata_on_repositories( trans, my_writable=my_writable, order=False )
+ # First reset metadata on all repositories of type repository_dependency_definition.
+ for repository in query:
+ encoded_id = trans.security.encode_id( repository.id )
+ if encoded_id in encoded_ids_to_skip:
+ log.debug( "Skipping repository with id %s because it is in encoded_ids_to_skip %s" % \
+ ( str( repository.id ), str( encoded_ids_to_skip ) ) )
+ elif repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
+ results = handle_repository( trans, repository, results )
+ # Now reset metadata on all remaining repositories.
+ for repository in query:
+ encoded_id = trans.security.encode_id( repository.id )
+ if encoded_id in encoded_ids_to_skip:
+ log.debug( "Skipping repository with id %s because it is in encoded_ids_to_skip %s" % \
+ ( str( repository.id ), str( encoded_ids_to_skip ) ) )
+ elif repository.type != rt_util.TOOL_DEPENDENCY_DEFINITION and repository.id not in handled_repository_ids:
+ results = handle_repository( trans, repository, results )
+ stop_time = strftime( "%Y-%m-%d %H:%M:%S" )
+ results[ 'stop_time' ] = stop_time
+ return json.to_json_string( results, sort_keys=True, indent=4 * ' ' )
@web.expose_api
def reset_metadata_on_repository( self, trans, payload, **kwd ):
@@ -395,6 +397,7 @@ class RepositoriesController( BaseAPIController ):
The following parameters must be included in the payload.
:param repository_id: the encoded id of the repository on which metadata is to be reset.
"""
+
def handle_repository( trans, start_time, repository ):
results = dict( start_time=start_time,
repository_status=[] )
@@ -410,21 +413,16 @@ class RepositoriesController( BaseAPIController ):
status = '%s : %s' % ( str( repository.name ), message )
results[ 'repository_status' ].append( status )
return results
- try:
- repository_id = payload.get( 'repository_id', None )
- if repository_id is not None:
- repository = suc.get_repository_in_tool_shed( trans, repository_id )
- start_time = strftime( "%Y-%m-%d %H:%M:%S" )
- log.debug( "%s...resetting metadata on repository %s" % ( start_time, str( repository.name ) ) )
- results = handle_repository( trans, start_time, repository )
- stop_time = strftime( "%Y-%m-%d %H:%M:%S" )
- results[ 'stop_time' ] = stop_time
- return json.to_json_string( results, sort_keys=True, indent=4 * ' ' )
- except Exception, e:
- message = "Error in the Tool Shed repositories API in reset_metadata_on_repositories: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+
+ repository_id = payload.get( 'repository_id', None )
+ if repository_id is not None:
+ repository = suc.get_repository_in_tool_shed( trans, repository_id )
+ start_time = strftime( "%Y-%m-%d %H:%M:%S" )
+ log.debug( "%s...resetting metadata on repository %s" % ( start_time, str( repository.name ) ) )
+ results = handle_repository( trans, start_time, repository )
+ stop_time = strftime( "%Y-%m-%d %H:%M:%S" )
+ results[ 'stop_time' ] = stop_time
+ return json.to_json_string( results, sort_keys=True, indent=4 * ' ' )
@web.expose_api_anonymous
def show( self, trans, id, **kwd ):
@@ -434,27 +432,14 @@ class RepositoriesController( BaseAPIController ):
: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=value_mapper )
- repository_dict[ 'url' ] = web.url_for( controller='repositories',
- action='show',
- id=trans.security.encode_id( repository.id ) )
- return repository_dict
- except Exception, e:
- message = "Error in the Tool Shed repositories API in show: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
-
- def __get_value_mapper( self, trans, repository_metadata ):
- value_mapper = { 'id' : trans.security.encode_id,
- 'repository_id' : trans.security.encode_id }
- if repository_metadata.time_last_tested is not None:
- # For some reason the Dictifiable.to_dict() method in ~/galaxy/model/item_attrs.py requires
- # a function rather than a mapped value, so just pass the time_ago function here.
- value_mapper[ 'time_last_tested' ] = time_ago
- return value_mapper
+ repository = suc.get_repository_in_tool_shed( trans, id )
+ if repository is None:
+ log.debug( "Unable to locate repository record for id %s." % ( str( id ) ) )
+ return {}
+ repository_dict = repository.to_dict( view='element',
+ value_mapper=self.__get_value_mapper( trans ) )
+ repository_dict[ 'url' ] = web.url_for( controller='repositories',
+ action='show',
+ id=trans.security.encode_id( repository.id ) )
+ return repository_dict
diff --git a/lib/galaxy/webapps/tool_shed/api/repository_revisions.py b/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
index a93b51178cb..19c26cf1824 100644
--- a/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
+++ b/lib/galaxy/webapps/tool_shed/api/repository_revisions.py
@@ -1,6 +1,5 @@
import datetime
import logging
-from galaxy.web.framework.helpers import time_ago
from tool_shed.util import metadata_util
from galaxy import web
from galaxy import util
@@ -48,61 +47,29 @@ class RepositoryRevisionsController( BaseAPIController ):
if not changeset_revision:
raise HTTPBadRequest( detail="Missing required parameter 'changeset_revision'." )
export_repository_dependencies = payload.get( 'export_repository_dependencies', False )
- try:
- # We'll currently support only gzip-compressed tar archives.
- file_type = 'gz'
- export_repository_dependencies = util.string_as_bool( export_repository_dependencies )
- # Get the repository information.
- repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
- repository_id = trans.security.encode_id( repository.id )
- response = export_util.export_repository( trans,
- tool_shed_url,
- repository_id,
- str( repository.name ),
- changeset_revision,
- file_type,
- export_repository_dependencies,
- api=True )
- return response
- except Exception, e:
- message = "Error in the Tool Shed repository_revisions API in export: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ # We'll currently support only gzip-compressed tar archives.
+ file_type = 'gz'
+ export_repository_dependencies = util.asbool( export_repository_dependencies )
+ # Get the repository information.
+ repository = suc.get_repository_by_name_and_owner( trans.app, name, owner )
+ if repository is None:
+ error_message = 'Cannot locate repository with name %s and owner %s,' % ( str( name ), str( owner ) )
+ log.debug( error_message )
+ return None, error_message
+ repository_id = trans.security.encode_id( repository.id )
+ return export_util.export_repository( trans,
+ tool_shed_url,
+ repository_id,
+ str( repository.name ),
+ changeset_revision,
+ file_type,
+ export_repository_dependencies,
+ api=True )
- @web.expose_api_anonymous
- def repository_dependencies( self, trans, id, **kwd ):
- """
- GET /api/repository_revisions/{encoded repository_metadata id}/repository_dependencies
- Displays information about a repository_metadata record in the Tool Shed.
-
- :param id: the encoded id of the `RepositoryMetadata` object
- """
- # Example URL: http://localhost:9009/api/repository_revisions/repository_dependencies/bb125606ff9ea620
+ def __get_value_mapper( self, trans ):
value_mapper = { 'id' : trans.security.encode_id,
- 'user_id' : trans.security.encode_id }
- repository_dependencies_dicts = []
- try:
- repository_metadata = metadata_util.get_repository_metadata_by_id( trans, id )
- metadata = repository_metadata.metadata
- if metadata and 'repository_dependencies' in metadata:
- rd_tups = metadata[ 'repository_dependencies' ][ 'repository_dependencies' ]
- for rd_tup in rd_tups:
- tool_shed, name, owner, changeset_revision = rd_tup[ 0:4 ]
- repository_dependency = suc.get_repository_by_name_and_owner( trans.app, name, owner )
- repository_dependency_dict = repository_dependency.to_dict( view='element', value_mapper=value_mapper )
- # We have to add the changeset_revision of of the repository dependency.
- repository_dependency_dict[ 'changeset_revision' ] = changeset_revision
- repository_dependency_dict[ 'url' ] = web.url_for( controller='repositories',
- action='show',
- id=trans.security.encode_id( repository_dependency.id ) )
- repository_dependencies_dicts.append( repository_dependency_dict )
- return repository_dependencies_dicts
- except Exception, e:
- message = "Error in the Tool Shed repository_revisions API in repository_dependencies: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ 'repository_id' : trans.security.encode_id }
+ return value_mapper
@web.expose_api_anonymous
def index( self, trans, **kwd ):
@@ -117,59 +84,94 @@ class RepositoryRevisionsController( BaseAPIController ):
# Filter by downloadable if received.
downloadable = kwd.get( 'downloadable', None )
if downloadable is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.downloadable == util.string_as_bool( downloadable ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.downloadable == util.asbool( downloadable ) )
# Filter by malicious if received.
malicious = kwd.get( 'malicious', None )
if malicious is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.malicious == util.string_as_bool( malicious ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.malicious == util.asbool( malicious ) )
# Filter by tools_functionally_correct if received.
tools_functionally_correct = kwd.get( 'tools_functionally_correct', None )
if tools_functionally_correct is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.tools_functionally_correct == util.string_as_bool( tools_functionally_correct ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.tools_functionally_correct == util.asbool( tools_functionally_correct ) )
# Filter by missing_test_components if received.
missing_test_components = kwd.get( 'missing_test_components', None )
if missing_test_components is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.missing_test_components == util.string_as_bool( missing_test_components ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.missing_test_components == util.asbool( missing_test_components ) )
# Filter by do_not_test if received.
do_not_test = kwd.get( 'do_not_test', None )
if do_not_test is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.do_not_test == util.string_as_bool( do_not_test ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.do_not_test == util.asbool( do_not_test ) )
# Filter by includes_tools if received.
includes_tools = kwd.get( 'includes_tools', None )
if includes_tools is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.includes_tools == util.string_as_bool( includes_tools ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.includes_tools == util.asbool( includes_tools ) )
# Filter by test_install_error if received.
test_install_error = kwd.get( 'test_install_error', None )
if test_install_error is not None:
- clause_list.append( trans.model.RepositoryMetadata.table.c.test_install_error == util.string_as_bool( test_install_error ) )
+ clause_list.append( trans.model.RepositoryMetadata.table.c.test_install_error == util.asbool( test_install_error ) )
# Filter by skip_tool_test if received.
skip_tool_test = kwd.get( 'skip_tool_test', None )
if skip_tool_test is not None:
- skip_tool_test = util.string_as_bool( skip_tool_test )
+ skip_tool_test = util.asbool( skip_tool_test )
skipped_metadata_ids_subquery = select( [ trans.app.model.SkipToolTest.table.c.repository_metadata_id ] )
if skip_tool_test:
clause_list.append( trans.model.RepositoryMetadata.id.in_( skipped_metadata_ids_subquery ) )
else:
clause_list.append( not_( trans.model.RepositoryMetadata.id.in_( skipped_metadata_ids_subquery ) ) )
- # Generate and execute the query.
- try:
- query = trans.sa_session.query( trans.app.model.RepositoryMetadata ) \
- .filter( and_( *clause_list ) ) \
- .order_by( trans.app.model.RepositoryMetadata.table.c.repository_id.desc() ) \
- .all()
- for repository_metadata in query:
- repository_metadata_dict = repository_metadata.to_dict( view='collection',
- value_mapper=self.__get_value_mapper( trans, repository_metadata ) )
- repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
- action='show',
- id=trans.security.encode_id( repository_metadata.id ) )
- repository_metadata_dicts.append( repository_metadata_dict )
- return repository_metadata_dicts
- except Exception, e:
- message = "Error in the Tool Shed repository_revisions API in index: " + str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ for repository_metadata in trans.sa_session.query( trans.app.model.RepositoryMetadata ) \
+ .filter( and_( *clause_list ) ) \
+ .order_by( trans.app.model.RepositoryMetadata.table.c.repository_id.desc() ):
+ repository_metadata_dict = repository_metadata.to_dict( view='collection',
+ value_mapper=self.__get_value_mapper( trans ) )
+ repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
+ action='show',
+ id=trans.security.encode_id( repository_metadata.id ) )
+ repository_metadata_dicts.append( repository_metadata_dict )
+ return repository_metadata_dicts
+
+ @web.expose_api_anonymous
+ def repository_dependencies( self, trans, id, **kwd ):
+ """
+ GET /api/repository_revisions/{encoded repository_metadata id}/repository_dependencies
+ Displays information about a repository_metadata record in the Tool Shed.
+
+ :param id: the encoded id of the `RepositoryMetadata` object
+ """
+ # Example URL: http://localhost:9009/api/repository_revisions/repository_dependencies/bb125606ff9ea620
+ repository_dependencies_dicts = []
+ repository_metadata = metadata_util.get_repository_metadata_by_id( trans, id )
+ if repository_metadata is None:
+ log.debug( 'Invalid repository_metadata id received: %s' % str( id ) )
+ return repository_dependencies_dicts
+ metadata = repository_metadata.metadata
+ if metadata is None:
+ log.debug( 'The repository_metadata record with id %s has no metadata.' % str ( id ) )
+ return repository_dependencies_dicts
+ if 'repository_dependencies' in metadata:
+ rd_tups = metadata[ 'repository_dependencies' ][ 'repository_dependencies' ]
+ for rd_tup in rd_tups:
+ tool_shed, name, owner, changeset_revision = rd_tup[ 0:4 ]
+ repository_dependency = suc.get_repository_by_name_and_owner( trans.app, name, owner )
+ if repository_dependency is None:
+ log.dbug( 'Cannot locate repository dependency %s owned by %s.' % ( name, owner ) )
+ continue
+ repository_dependency_id = trans.security.encode_id( repository_dependency.id )
+ repository_dependency_repository_metadata = \
+ suc.get_repository_metadata_by_changeset_revision( trans, repository_dependency_id, changeset_revision )
+ if repository_dependency_repository_metadata is None:
+ log.debug( 'Cannot locate repository_metadata with id %s for repository dependency %s owned by %s.' % \
+ ( str( repository_dependency_id ), str( name ), str( owner ) ) )
+ continue
+ repository_dependency_repository_metadata_id = trans.security.encode_id( repository_dependency_repository_metadata.id )
+ repository_dependency_dict = repository_dependency.to_dict( view='element',
+ value_mapper=self.__get_value_mapper( trans ) )
+ # We have to add the changeset_revision of of the repository dependency.
+ repository_dependency_dict[ 'changeset_revision' ] = changeset_revision
+ repository_dependency_dict[ 'url' ] = web.url_for( controller='repositories',
+ action='show',
+ id=repository_dependency_repository_metadata_id )
+ repository_dependencies_dicts.append( repository_dependency_dict )
+ return repository_dependencies_dicts
@web.expose_api_anonymous
def show( self, trans, id, **kwd ):
@@ -180,19 +182,16 @@ class RepositoryRevisionsController( BaseAPIController ):
:param id: the encoded id of the `RepositoryMetadata` object
"""
# 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.to_dict( view='element',
- value_mapper=self.__get_value_mapper( trans, repository_metadata ) )
- repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
- action='show',
- id=trans.security.encode_id( repository_metadata.id ) )
- return repository_metadata_dict
- except Exception, e:
- message = "Error in the Tool Shed repository_revisions API in show: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ repository_metadata = metadata_util.get_repository_metadata_by_id( trans, id )
+ if repository_metadata is None:
+ log.debug( 'Cannot locate repository_metadata with id %s' % str( id ) )
+ return {}
+ repository_metadata_dict = repository_metadata.to_dict( view='element',
+ value_mapper=self.__get_value_mapper( trans ) )
+ repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
+ action='show',
+ id=trans.security.encode_id( repository_metadata.id ) )
+ return repository_metadata_dict
@web.expose_api
def update( self, trans, payload, **kwd ):
@@ -201,41 +200,32 @@ class RepositoryRevisionsController( BaseAPIController ):
Updates the value of specified columns of the repository_metadata table based on the key / value pairs in payload.
"""
repository_metadata_id = kwd.get( 'id', None )
- try:
- repository_metadata = metadata_util.get_repository_metadata_by_id( trans, repository_metadata_id )
- flush_needed = False
- for key, new_value in payload.items():
- if key == 'time_last_tested':
- repository_metadata.time_last_tested = datetime.datetime.utcnow()
- flush_needed = True
- elif hasattr( repository_metadata, key ):
- # log information when setting attributes associated with the Tool Shed's install and test framework.
- if key in [ 'do_not_test', 'includes_tools', 'missing_test_components', 'test_install_error',
- 'tools_functionally_correct' ]:
- log.debug( 'Setting repository_metadata table column %s to value %s for changeset_revision %s via the Tool Shed API.' % \
- ( str( key ), str( new_value ), str( repository_metadata.changeset_revision ) ) )
- setattr( repository_metadata, key, new_value )
- flush_needed = True
- if flush_needed:
- trans.sa_session.add( repository_metadata )
- trans.sa_session.flush()
- except Exception, e:
- message = "Error in the Tool Shed repository_revisions API in update: %s" % str( e )
- log.error( message, exc_info=True )
- trans.response.status = 500
- return message
+ if repository_metadata_id is None:
+ raise HTTPBadRequest( detail="Missing required parameter 'id'." )
+ repository_metadata = metadata_util.get_repository_metadata_by_id( trans, repository_metadata_id )
+ if repository_metadata is None:
+ log.debug( 'Cannot locate repository_metadata with id %s' % str( repository_metadata_id ) )
+ return {}
+ flush_needed = False
+ for key, new_value in payload.items():
+ if key == 'time_last_tested':
+ repository_metadata.time_last_tested = datetime.datetime.utcnow()
+ flush_needed = True
+ elif hasattr( repository_metadata, key ):
+ # log information when setting attributes associated with the Tool Shed's install and test framework.
+ if key in [ 'do_not_test', 'includes_tools', 'missing_test_components', 'test_install_error',
+ 'tools_functionally_correct' ]:
+ log.debug( 'Setting repository_metadata column %s to value %s for changeset_revision %s via the Tool Shed API.' % \
+ ( str( key ), str( new_value ), str( repository_metadata.changeset_revision ) ) )
+ setattr( repository_metadata, key, new_value )
+ flush_needed = True
+ if flush_needed:
+ trans.sa_session.add( repository_metadata )
+ trans.sa_session.flush()
+ trans.sa_session.refresh( repository_metadata )
repository_metadata_dict = repository_metadata.to_dict( view='element',
- value_mapper=self.__get_value_mapper( trans, repository_metadata ) )
+ value_mapper=self.__get_value_mapper( trans ) )
repository_metadata_dict[ 'url' ] = web.url_for( controller='repository_revisions',
action='show',
id=trans.security.encode_id( repository_metadata.id ) )
return repository_metadata_dict
-
- def __get_value_mapper( self, trans, repository_metadata ):
- value_mapper = { 'id' : trans.security.encode_id,
- 'repository_id' : trans.security.encode_id }
- if repository_metadata.time_last_tested is not None:
- # For some reason the Dictifiable.to_dict() method in ~/galaxy/model/item_attrs.py requires
- # a function rather than a mapped value, so just pass the time_ago function here.
- value_mapper[ 'time_last_tested' ] = time_ago
- return value_mapper
diff --git a/lib/galaxy/webapps/tool_shed/controllers/hg.py b/lib/galaxy/webapps/tool_shed/controllers/hg.py
index 4e1e5ffc8f6..c6fd4f8b71a 100644
--- a/lib/galaxy/webapps/tool_shed/controllers/hg.py
+++ b/lib/galaxy/webapps/tool_shed/controllers/hg.py
@@ -2,6 +2,7 @@ import os, logging
from galaxy import web
from galaxy.web.base.controller import BaseUIController
from tool_shed.util.shed_util_common import get_repository_by_name_and_owner
+from tool_shed.util.shed_util_common import update_repository
from tool_shed.util.metadata_util import set_repository_metadata
from galaxy import eggs
@@ -9,6 +10,8 @@ eggs.require('mercurial')
import mercurial.__version__
from mercurial.hgweb.hgwebdir_mod import hgwebdir
from mercurial.hgweb.request import wsgiapplication
+from mercurial import hg
+from mercurial import ui
log = logging.getLogger(__name__)
@@ -36,6 +39,11 @@ class HgController( BaseUIController ):
repository = get_repository_by_name_and_owner( trans.app, name, owner )
if repository:
if hg_version >= '2.2.3':
+ # Update the repository on disk to the tip revision, because the web upload form uses the on-disk working
+ # directory. If the repository is not updated on disk, pushing from the command line and then uploading
+ # via the web interface will result in a new head being created.
+ repo = hg.repository( ui.ui(), repository.repo_path( trans.app ) )
+ update_repository( repo, ctx_rev=None )
# Set metadata using the repository files on disk.
error_message, status = set_repository_metadata( trans, repository )
if status == 'ok' and error_message:
diff --git a/lib/tool_shed/galaxy_install/install_manager.py b/lib/tool_shed/galaxy_install/install_manager.py
index d01d2d2e100..2872d0591a1 100644
--- a/lib/tool_shed/galaxy_install/install_manager.py
+++ b/lib/tool_shed/galaxy_install/install_manager.py
@@ -567,14 +567,17 @@ class InstallManager( object ):
def order_repositories_for_installation( self, tool_shed_repositories, repository_dependencies_dict ):
"""
- Some repositories may have repository dependencies that are required to be installed before the dependent repository. This method will
- inspect the list of repositories about to be installed and make sure to order them appropriately. For each repository about to be installed,
- if required repositories are not contained in the list of repositories about to be installed, then they are not considered. Repository
- dependency definitions that contain circular dependencies should not result in an infinite loop, but obviously prior installation will not be
- handled for one or more of the repositories that require prior installation. This process is similar to the process used when installing tool
- shed repositories (i.e., the order_components_for_installation() method in ~/lib/tool_shed/galaxy_install/repository_util), but does not handle
- managing tool panel sections and other components since repository dependency definitions contained in tool shed repositories with migrated
- tools must never define a relationship to a repository dependency that contains a tool.
+ Some repositories may have repository dependencies that are required to be installed before the dependent
+ repository. This method will inspect the list of repositories about to be installed and make sure to order
+ them appropriately. For each repository about to be installed, if required repositories are not contained
+ in the list of repositories about to be installed, then they are not considered. Repository dependency
+ definitions that contain circular dependencies should not result in an infinite loop, but obviously prior
+ installation will not be handled for one or more of the repositories that require prior installation. This
+ process is similar to the process used when installing tool shed repositories (i.e., the
+ order_components_for_installation() method in ~/lib/tool_shed/galaxy_install/repository_util), but does not
+ handle managing tool panel sections and other components since repository dependency definitions contained
+ in tool shed repositories with migrated tools must never define a relationship to a repository dependency
+ that contains a tool.
"""
ordered_tool_shed_repositories = []
ordered_tsr_ids = []
diff --git a/lib/tool_shed/scripts/api/common.py b/lib/tool_shed/scripts/api/common.py
index 9ed77d7c5aa..460f2711078 100644
--- a/lib/tool_shed/scripts/api/common.py
+++ b/lib/tool_shed/scripts/api/common.py
@@ -8,28 +8,18 @@ new_path = [ os.path.join( os.path.dirname( __file__ ), '..', '..', '..', '..',
new_path.extend( sys.path[ 1: ] )
sys.path = new_path
+import tool_shed.util.shed_util_common as suc
+
from galaxy import eggs
import pkg_resources
-pkg_resources.require( "pycrypto" )
-from Crypto.Cipher import Blowfish
-from Crypto.Util.randpool import RandomPool
-from Crypto.Util import number
-
-def encode_id( config_id_secret, obj_id ):
- # Utility method to encode ID's
- id_cipher = Blowfish.new( config_id_secret )
- # Convert to string
- s = str( obj_id )
- # Pad to a multiple of 8 with leading "!"
- s = ( "!" * ( 8 - len(s) % 8 ) ) + s
- # Encrypt
- return id_cipher.encrypt( s ).encode( 'hex' )
-
def delete( api_key, url, data, return_formatted=True ):
- # Sends an API DELETE request and acts as a generic formatter for the JSON response - 'data' will become the JSON payload read by Galaxy.
+ """
+ Sends an API DELETE request and acts as a generic formatter for the JSON response. The
+ 'data' will become the JSON payload read by the Tool Shed.
+ """
try:
- url = make_url( api_key, url )
+ url = make_url( url, api_key=api_key, args=None )
req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = json.dumps( data ))
req.get_method = lambda: 'DELETE'
r = json.loads( urllib2.urlopen( req ).read() )
@@ -47,12 +37,13 @@ def delete( api_key, url, data, return_formatted=True ):
print r
def display( url, api_key=None, return_formatted=True ):
- # Sends an API GET request and acts as a generic formatter for the JSON response.
+ """Sends an API GET request and acts as a generic formatter for the JSON response."""
try:
r = get( url, api_key=api_key )
except urllib2.HTTPError, e:
print e
- print e.read( 1024 ) # Only return the first 1K of errors.
+ # Only return the first 1K of errors.
+ print e.read( 1024 )
sys.exit( 1 )
if type( r ) == unicode:
print 'error: %s' % r
@@ -84,16 +75,94 @@ def display( url, api_key=None, return_formatted=True ):
print 'response is unknown type: %s' % type( r )
def get( url, api_key=None ):
- # Do the actual GET.
- url = make_url( url, api_key=api_key )
+ """Do the GET."""
+ url = make_url( url, api_key=api_key, args=None )
try:
return json.loads( urllib2.urlopen( url ).read() )
except ValueError, e:
print "URL did not return JSON data"
- sys.exit(1)
+ sys.exit( 1 )
+
+def get_api_url( base, parts=[], params=None ):
+ """Compose and return a URL for the Tool Shed API."""
+ if 'api' in parts and parts.index( 'api' ) != 0:
+ parts.pop( parts.index( 'api' ) )
+ parts.insert( 0, 'api' )
+ elif 'api' not in parts:
+ parts.insert( 0, 'api' )
+ url = suc.url_join( base, *parts )
+ if params is not None:
+ try:
+ query_string = urllib.urlencode( params )
+ except Exception, e:
+ # The value of params must be a string.
+ query_string = params
+ url += '?%s' % query_string
+ return url
+
+def get_latest_downloadable_changeset_revision_via_api( url, name, owner ):
+ """
+ Return the latest downloadable changeset revision for the repository defined by the received
+ name and owner.
+ """
+ error_message = ''
+ parts = [ 'api', 'repositories', 'get_ordered_installable_revisions' ]
+ params = dict( name=name, owner=owner )
+ api_url = get_api_url( base=url, parts=parts, params=params )
+ changeset_revisions, error_message = json_from_url( api_url )
+ if changeset_revisions is None or error_message:
+ return None, error_message
+ if len( changeset_revisions ) >= 1:
+ return changeset_revisions[ -1 ], error_message
+ return suc.INITIAL_CHANGELOG_HASH, error_message
+
+def get_repository_dict( url, repository_dict ):
+ """
+ Send a request to the Tool Shed to get additional information about the repository defined
+ by the received repository_dict. Add the information to the repository_dict and return it.
+ """
+ error_message = ''
+ if not isinstance( repository_dict, dict ):
+ error_message = 'Invalid repository_dict received: %s' % str( repository_dict )
+ return None, error_message
+ repository_id = repository_dict.get( 'repository_id', None )
+ if repository_id is None:
+ error_message = 'Invalid repository_dict does not contain a repository_id entry: %s' % str( repository_dict )
+ return None, error_message
+ parts = [ 'api', 'repositories', repository_id ]
+ api_url = get_api_url( base=url, parts=parts )
+ extended_dict, error_message = json_from_url( api_url )
+ if extended_dict is None or error_message:
+ return None, error_message
+ name = extended_dict.get( 'name', None )
+ owner = extended_dict.get( 'owner', None )
+ if name is not None and owner is not None:
+ name = str( name )
+ owner = str( owner )
+ latest_changeset_revision, error_message = get_latest_downloadable_changeset_revision_via_api( url, name, owner )
+ if latest_changeset_revision is None or error_message:
+ return None, error_message
+ extended_dict[ 'latest_revision' ] = str( latest_changeset_revision )
+ return extended_dict, error_message
+ else:
+ error_message = 'Invalid extended_dict does not contain name or woner entries: %s' % str( extended_dict )
+ return None, error_message
+
+def json_from_url( url ):
+ """Send a request to the Tool Shed via the Tool Shed API and handle the response."""
+ error_message = ''
+ url_handle = urllib.urlopen( url )
+ url_contents = url_handle.read()
+ try:
+ parsed_json = simplejson.loads( url_contents )
+ except Exception, e:
+ error_message = str( url_contents )
+ print 'Error parsing JSON data in json_from_url(): ', str( e )
+ return None, error_message
+ return parsed_json, error_message
def make_url( url, api_key=None, args=None ):
- # Adds the API Key to the URL if it's not already there.
+ """Adds the API Key to the URL if it's not already there."""
if args is None:
args = []
argsep = '&'
@@ -105,20 +174,23 @@ def make_url( url, api_key=None, args=None ):
return url + argsep + '&'.join( [ '='.join( t ) for t in args ] )
def post( url, data, api_key=None ):
- # Do the actual POST.
- url = make_url( url, api_key=api_key )
+ """Do the POST."""
+ url = make_url( url, api_key=api_key, args=None )
req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = json.dumps( data ) )
return json.loads( urllib2.urlopen( req ).read() )
def put( url, data, api_key=None ):
- # Do the actual PUT.
- url = make_url( url, api_key=api_key )
+ """Do the PUT."""
+ url = make_url( url, api_key=api_key, args=None )
req = urllib2.Request( url, headers = { 'Content-Type': 'application/json' }, data = json.dumps( data ))
req.get_method = lambda: 'PUT'
return json.loads( urllib2.urlopen( req ).read() )
def submit( url, data, api_key=None, return_formatted=True ):
- # Sends an API POST request and acts as a generic formatter for the JSON response - 'data' will become the JSON payload read by Galaxy.
+ """
+ Sends an API POST request and acts as a generic formatter for the JSON response. The
+ 'data' will become the JSON payload read by the Tool Shed.
+ """
try:
r = post( url, data, api_key=api_key )
except urllib2.HTTPError, e:
@@ -133,7 +205,8 @@ def submit( url, data, api_key=None, return_formatted=True ):
print 'Response'
print '--------'
if type( r ) == list:
- # Currently the only implemented responses are lists of dicts, because submission creates some number of collection elements.
+ # Currently the only implemented responses are lists of dicts, because submission creates
+ # some number of collection elements.
for i in r:
if type( i ) == dict:
if 'url' in i:
@@ -150,9 +223,12 @@ def submit( url, data, api_key=None, return_formatted=True ):
print r
def update( api_key, url, data, return_formatted=True ):
- # Sends an API PUT request and acts as a generic formatter for the JSON response - 'data' will become the JSON payload read by Galaxy.
+ """
+ Sends an API PUT request and acts as a generic formatter for the JSON response. The
+ 'data' will become the JSON payload read by the Tool Shed.
+ """
try:
- r = put( api_key, url, data )
+ r = put( url, data, api_key=api_key )
except urllib2.HTTPError, e:
if return_formatted:
print e
diff --git a/lib/tool_shed/scripts/api/get_filtered_repository_revisions.py b/lib/tool_shed/scripts/api/get_filtered_repository_revisions.py
index 447b8ca62e7..3a4cdff9165 100644
--- a/lib/tool_shed/scripts/api/get_filtered_repository_revisions.py
+++ b/lib/tool_shed/scripts/api/get_filtered_repository_revisions.py
@@ -26,69 +26,19 @@ import sys
import urllib
sys.path.insert( 0, os.path.dirname( __file__ ) )
+
from common import get
+from common import get_api_url
+from common import get_repository_dict
+from common import json_from_url
+
+from galaxy.util import asbool
from galaxy.util.json import from_json_string
import tool_shed.util.shed_util_common as suc
-def get_api_url( base, parts=[], params=None ):
- if 'api' in parts and parts.index( 'api' ) != 0:
- parts.pop( parts.index( 'api' ) )
- parts.insert( 0, 'api' )
- elif 'api' not in parts:
- parts.insert( 0, 'api' )
- url = suc.url_join( base, *parts )
- if params:
- url += '?%s' % params
- return url
-
-def get_latest_downloadable_changeset_revision( url, name, owner ):
- error_message = ''
- parts = [ 'api', 'repositories', 'get_ordered_installable_revisions' ]
- params = urllib.urlencode( dict( name=name, owner=owner ) )
- api_url = get_api_url( base=url, parts=parts, params=params )
- changeset_revisions, error_message = json_from_url( api_url )
- if error_message:
- return None, error_message
- if changeset_revisions:
- return changeset_revisions[ -1 ], error_message
- else:
- return suc.INITIAL_CHANGELOG_HASH, error_message
-
-def get_repository_dict( url, repository_dict ):
- error_message = ''
- parts = [ 'api', 'repositories', repository_dict[ 'repository_id' ] ]
- api_url = get_api_url( base=url, parts=parts )
- extended_dict, error_message = json_from_url( api_url )
- if error_message:
- return None, error_message
- name = str( extended_dict[ 'name' ] )
- owner = str( extended_dict[ 'owner' ] )
- latest_changeset_revision, error_message = get_latest_downloadable_changeset_revision( url, name, owner )
- if error_message:
- print error_message
- extended_dict[ 'latest_revision' ] = str( latest_changeset_revision )
- return extended_dict, error_message
-
-def json_from_url( url ):
- error_message = ''
- url_handle = urllib.urlopen( url )
- url_contents = url_handle.read()
- try:
- parsed_json = from_json_string( url_contents )
- except Exception, e:
- error_message = str( url_contents )
- return None, error_message
- return parsed_json, error_message
-
-def string_as_bool( string ):
- if str( string ).lower() in [ 'true' ]:
- return True
- else:
- return False
-
def main( options ):
base_tool_shed_url = options.tool_shed_url.rstrip( '/' )
- latest_revision_only = string_as_bool( options.latest_revision_only )
+ latest_revision_only = asbool( options.latest_revision_only )
do_not_test = str( options.do_not_test )
downloadable = str( options.downloadable )
includes_tools = str( options.includes_tools )
@@ -108,30 +58,31 @@ def main( options ):
tools_functionally_correct=tools_functionally_correct ) )
api_url = get_api_url( base=base_tool_shed_url, parts=parts, params=params )
baseline_repository_dicts, error_message = json_from_url( api_url )
- if error_message:
+ if baseline_repository_dicts is None or error_message:
print error_message
- repository_dicts = []
- for baseline_repository_dict in baseline_repository_dicts:
- # We need to get some details from the tool shed API, such as repository name and owner, to pass on to the
- # module that will generate the install methods.
- repository_dict, error_message = get_repository_dict( base_tool_shed_url, baseline_repository_dict )
- if error_message:
- print 'Error getting additional details from the API: ', error_message
- repository_dicts.append( baseline_repository_dict )
- else:
- # Don't test empty repositories.
- changeset_revision = baseline_repository_dict[ 'changeset_revision' ]
- if changeset_revision != suc.INITIAL_CHANGELOG_HASH:
- # Merge the dictionary returned from /api/repository_revisions with the detailed repository_dict and
- # append it to the list of repository_dicts to install and test.
- if latest_revision_only:
- latest_revision = repository_dict[ 'latest_revision' ]
- if changeset_revision == latest_revision:
+ else:
+ repository_dicts = []
+ for baseline_repository_dict in baseline_repository_dicts:
+ # We need to get additional details from the tool shed API to pass on to the
+ # module that will generate the install methods.
+ repository_dict, error_message = get_repository_dict( base_tool_shed_url, baseline_repository_dict )
+ if error_message:
+ print 'Error getting additional details from the API: ', error_message
+ repository_dicts.append( baseline_repository_dict )
+ else:
+ # Don't test empty repositories.
+ changeset_revision = baseline_repository_dict.get( 'changeset_revision', suc.INITIAL_CHANGELOG_HASH )
+ if changeset_revision != suc.INITIAL_CHANGELOG_HASH:
+ # Merge the dictionary returned from /api/repository_revisions with the detailed repository_dict and
+ # append it to the list of repository_dicts to install and test.
+ if latest_revision_only:
+ latest_revision = repository_dict.get( 'latest_revision', suc.INITIAL_CHANGELOG_HASH )
+ if changeset_revision == latest_revision:
+ repository_dicts.append( dict( repository_dict.items() + baseline_repository_dict.items() ) )
+ else:
repository_dicts.append( dict( repository_dict.items() + baseline_repository_dict.items() ) )
- else:
- repository_dicts.append( dict( repository_dict.items() + baseline_repository_dict.items() ) )
- print '\n\n', repository_dicts
- print '\nThe url:\n\n', api_url, '\n\nreturned ', len( repository_dicts ), ' repository dictionaries...'
+ print '\n\n', repository_dicts
+ print '\nThe url:\n\n', api_url, '\n\nreturned ', len( repository_dicts ), ' repository dictionaries...'
if __name__ == '__main__':
parser = argparse.ArgumentParser( description='Get a filtered list of repository dictionaries.' )
diff --git a/lib/tool_shed/util/commit_util.py b/lib/tool_shed/util/commit_util.py
index acaa8bf7c36..1b319576d5f 100644
--- a/lib/tool_shed/util/commit_util.py
+++ b/lib/tool_shed/util/commit_util.py
@@ -313,6 +313,9 @@ def handle_repository_dependency_elem( trans, elem, unpopulate=False ):
if lastest_installable_changeset_revision != suc.INITIAL_CHANGELOG_HASH:
elem.attrib[ 'changeset_revision' ] = lastest_installable_changeset_revision
revised = True
+ else:
+ error_message = 'Invalid latest installable changeset_revision %s ' % str( lastest_installable_changeset_revision )
+ error_message += 'retrieved for repository %s owned by %s. ' % ( str( name ), str( owner ) )
else:
error_message = 'Unable to locate repository with name %s and owner %s. ' % ( str( name ), str( owner ) )
return revised, elem, error_message
diff --git a/lib/tool_shed/util/container_util.py b/lib/tool_shed/util/container_util.py
index 0dd81ff2f7b..7b7668bd2e0 100644
--- a/lib/tool_shed/util/container_util.py
+++ b/lib/tool_shed/util/container_util.py
@@ -744,7 +744,8 @@ def build_repository_containers_for_galaxy( trans, repository, datatypes, invali
lock.release()
return containers_dict
-def build_repository_containers_for_tool_shed( trans, repository, changeset_revision, repository_dependencies, repository_metadata, exclude=None ):
+def build_repository_containers_for_tool_shed( trans, repository, changeset_revision, repository_dependencies, repository_metadata,
+ exclude=None ):
"""Return a dictionary of containers for the received repository's dependencies and contents for display in the tool shed."""
if exclude is None:
exclude = []
@@ -806,11 +807,12 @@ def build_repository_containers_for_tool_shed( trans, repository, changeset_revi
containers_dict[ 'readme_files' ] = readme_files_root_folder
if 'repository_dependencies' not in exclude:
# Repository dependencies container.
- folder_id, repository_dependencies_root_folder = build_repository_dependencies_folder( trans=trans,
- folder_id=folder_id,
- repository_dependencies=repository_dependencies,
- label='Repository dependencies',
- installed=False )
+ folder_id, repository_dependencies_root_folder = \
+ build_repository_dependencies_folder( trans=trans,
+ folder_id=folder_id,
+ repository_dependencies=repository_dependencies,
+ label='Repository dependencies',
+ installed=False )
if repository_dependencies_root_folder:
containers_dict[ 'repository_dependencies' ] = repository_dependencies_root_folder
# Tool dependencies container.
@@ -868,11 +870,13 @@ def build_repository_containers_for_tool_shed( trans, repository, changeset_revi
if metadata:
if 'data_manager' not in exclude and 'data_manager' in metadata:
data_managers = metadata['data_manager'].get( 'data_managers', None )
- folder_id, data_managers_root_folder = build_data_managers_folder( trans, folder_id, data_managers, label="Data Managers" )
+ folder_id, data_managers_root_folder = \
+ build_data_managers_folder( trans, folder_id, data_managers, label="Data Managers" )
containers_dict[ 'valid_data_managers' ] = data_managers_root_folder
error_messages = metadata['data_manager'].get( 'error_messages', None )
data_managers = metadata['data_manager'].get( 'invalid_data_managers', None )
- folder_id, data_managers_root_folder = build_invalid_data_managers_folder( trans, folder_id, data_managers, error_messages, label="Invalid Data Managers" )
+ folder_id, data_managers_root_folder = \
+ build_invalid_data_managers_folder( trans, folder_id, data_managers, error_messages, label="Invalid Data Managers" )
containers_dict[ 'invalid_data_managers' ] = data_managers_root_folder
except Exception, e:
log.exception( "Exception in build_repository_containers_for_tool_shed: %s" % str( e ) )
@@ -890,15 +894,22 @@ def build_repository_dependencies_folder( trans, folder_id, repository_dependenc
folder_id += 1
# Create the Repository dependencies folder and add it to the root folder.
repository_dependencies_folder_key = repository_dependencies[ 'root_key' ]
- repository_dependencies_folder = Folder( id=folder_id, key=repository_dependencies_folder_key, label=label, parent=repository_dependencies_root_folder )
+ repository_dependencies_folder = Folder( id=folder_id,
+ key=repository_dependencies_folder_key,
+ label=label,
+ parent=repository_dependencies_root_folder )
del repository_dependencies[ 'root_key' ]
- # The received repository_dependencies is a dictionary with keys: 'root_key', 'description', and one or more repository_dependency keys.
- # We want the description value associated with the repository_dependencies_folder.
+ # The received repository_dependencies is a dictionary with keys: 'root_key', 'description', and one or more
+ # repository_dependency keys. We want the description value associated with the repository_dependencies_folder.
repository_dependencies_folder.description = repository_dependencies.get( 'description', None )
repository_dependencies_root_folder.folders.append( repository_dependencies_folder )
del repository_dependencies[ 'description' ]
repository_dependencies_folder, folder_id, repository_dependency_id = \
- populate_repository_dependencies_container( trans, repository_dependencies_folder, repository_dependencies, folder_id, repository_dependency_id )
+ populate_repository_dependencies_container( trans,
+ repository_dependencies_folder,
+ repository_dependencies,
+ folder_id,
+ repository_dependency_id )
repository_dependencies_folder = prune_repository_dependencies( repository_dependencies_folder )
else:
repository_dependencies_root_folder = None
@@ -985,11 +996,13 @@ def build_tools_folder( trans, folder_id, tool_dicts, repository, changeset_revi
tools_root_folder = None
return folder_id, tools_root_folder
-def build_tool_dependencies_folder( trans, folder_id, tool_dependencies, label='Tool dependencies', missing=False, new_install=False, reinstalling=False ):
+def build_tool_dependencies_folder( trans, folder_id, tool_dependencies, label='Tool dependencies', missing=False,
+ new_install=False, reinstalling=False ):
"""Return a folder hierarchy containing tool dependencies."""
- # When we're in Galaxy (not the tool shed) and the tool dependencies are not installed or are in an error state, they are considered missing. The tool
- # dependency status will be displayed only if a record exists for the tool dependency in the Galaxy database, but the tool dependency is not installed.
- # The value for new_install will be True only if the associated repository in being installed for the first time. This value is used in setting the
+ # When we're in Galaxy (not the tool shed) and the tool dependencies are not installed or are in an error state,
+ # they are considered missing. The tool dependency status will be displayed only if a record exists for the tool
+ # dependency in the Galaxy database, but the tool dependency is not installed. The value for new_install will be
+ # True only if the associated repository in being installed for the first time. This value is used in setting the
# container description.
if tool_dependencies:
tool_dependency_id = 0
@@ -1138,7 +1151,10 @@ def build_tool_test_results_folder( trans, folder_id, tool_test_results_dicts, l
else:
containing_folder = tool_test_results_root_folder
folder_id += 1
- test_environment_folder = Folder( id=folder_id, key='test_environment', label='Automated test environment', parent=containing_folder )
+ test_environment_folder = Folder( id=folder_id,
+ key='test_environment',
+ label='Automated test environment',
+ parent=containing_folder )
containing_folder.folders.append( test_environment_folder )
try:
architecture = test_environment_dict.get( 'architecture', '' )
@@ -1184,7 +1200,10 @@ def build_tool_test_results_folder( trans, folder_id, tool_test_results_dicts, l
passed_tests_dicts = tool_test_results_dict.get( 'passed_tests', [] )
if len( passed_tests_dicts ) > 0:
folder_id += 1
- passed_tests_folder = Folder( id=folder_id, key='passed_tests', label='Tests that passed successfully', parent=containing_folder )
+ passed_tests_folder = Folder( id=folder_id,
+ key='passed_tests',
+ label='Tests that passed successfully',
+ parent=containing_folder )
containing_folder.folders.append( passed_tests_folder )
passed_test_id = 0
for passed_tests_dict in passed_tests_dicts:
@@ -1395,7 +1414,8 @@ def build_tool_test_results_folder( trans, folder_id, tool_test_results_dicts, l
rd_tool_shed = str( repository_dependency_successful_installation_dict.get( 'tool_shed', '' ) )
rd_name = str( repository_dependency_successful_installation_dict.get( 'name', '' ) )
rd_owner = str( repository_dependency_successful_installation_dict.get( 'owner', '' ) )
- rd_changeset_revision = str( repository_dependency_successful_installation_dict.get( 'changeset_revision', '' ) )
+ rd_changeset_revision = \
+ str( repository_dependency_successful_installation_dict.get( 'changeset_revision', '' ) )
except Exception, e:
rd_tool_shed = 'unknown'
rd_name = 'unknown'
@@ -1495,7 +1515,8 @@ def can_display_tool_test_results( tool_test_results_dicts, exclude=None ):
# only the "test_environment" entry, but we want at least 1 of "passed_tests", "failed_tests",
# "installation_errors", "missing_test_components" "skipped_tests", "not_tested" or any other
# entry that may be added in the future.
- display_entries = [ 'failed_tests', 'installation_errors', 'missing_test_components', 'not_tested', 'passed_tests', 'skipped_tests' ]
+ display_entries = [ 'failed_tests', 'installation_errors', 'missing_test_components',
+ 'not_tested', 'passed_tests', 'skipped_tests' ]
for k, v in tool_test_results_dict.items():
if k in display_entries:
# We've discovered an entry that can be displayed, so see if it has a value since displaying
@@ -1506,8 +1527,9 @@ def can_display_tool_test_results( tool_test_results_dicts, exclude=None ):
def cast_empty_repository_dependency_folders( folder, repository_dependency_id ):
"""
- Change any empty folders contained within the repository dependencies container into a repository dependency since it has no repository dependencies
- of it's own. This method is not used (and may not be needed), but here it is just in case.
+ Change any empty folders contained within the repository dependencies container into a repository dependency
+ since it has no repository dependencies of it's own. This method is not used (and may not be needed), but here
+ it is just in case.
"""
if not folder.folders and not folder.repository_dependencies:
repository_dependency_id += 1
@@ -1519,10 +1541,14 @@ def cast_empty_repository_dependency_folders( folder, repository_dependency_id )
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,
- only_if_compiling_contained_td, 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, only_if_compiling_contained_td, 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 galaxy.util.asbool( prior_installation_required ):
@@ -1533,8 +1559,8 @@ def generate_repository_dependencies_folder_label_from_key( repository_name, rep
( 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,
- only_if_compiling_contained_td ):
+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,
@@ -1551,13 +1577,6 @@ def generate_repository_dependencies_key_for_repository( toolshed_base_url, repo
def generate_tool_dependencies_key( name, version, type ):
return '%s%s%s%s%s' % ( str( name ), STRSEP, str( version ), STRSEP, str( type ) )
-def get_folder( folder, key ):
- if folder.key == key:
- return folder
- for sub_folder in folder.folders:
- return get_folder( sub_folder, key )
- 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."""
# Default prior_installation_required and only_if_compiling_contained_td to False.
@@ -1610,7 +1629,15 @@ def get_components_from_key( key ):
# 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 ):
+def get_folder( folder, key ):
+ if folder.key == key:
+ return folder
+ for sub_folder in folder.folders:
+ return get_folder( sub_folder, key )
+ return None
+
+def handle_repository_dependencies_container_entry( trans, repository_dependencies_folder, rd_key, rd_value, folder_id,
+ repository_dependency_id, folder_keys ):
repository_components_tuple = get_components_from_key( rd_key )
components_list = suc.extract_components_from_tuple( repository_components_tuple )
toolshed, repository_name, repository_owner, changeset_revision = components_list[ 0:4 ]
@@ -1713,11 +1740,21 @@ def key_is_current_repositorys_key( repository_name, repository_owner, changeset
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()
+def populate_repository_dependencies_container( trans, repository_dependencies_folder, repository_dependencies, folder_id,
+ repository_dependency_id ):
+ folder_keys = []
+ for key in repository_dependencies.keys():
+ if key not in folder_keys:
+ folder_keys.append( key )
for key, value in repository_dependencies.items():
repository_dependencies_folder, folder_id, repository_dependency_id = \
- handle_repository_dependencies_container_entry( trans, repository_dependencies_folder, key, value, folder_id, repository_dependency_id, folder_keys )
+ handle_repository_dependencies_container_entry( trans,
+ repository_dependencies_folder,
+ key,
+ value,
+ folder_id,
+ repository_dependency_id,
+ folder_keys )
return repository_dependencies_folder, folder_id, repository_dependency_id
def print_folders( pad, folder ):
@@ -1731,19 +1768,22 @@ def print_folders( pad, folder ):
for sub_folder in folder.folders:
print_folders( pad+5, sub_folder )
+def prune_folder( folder, repository_dependency ):
+ listified_repository_dependency = repository_dependency.listify
+ if is_subfolder_of( folder, listified_repository_dependency ):
+ folder.repository_dependencies.remove( repository_dependency )
+
def prune_repository_dependencies( folder ):
"""
- Since the object used to generate a repository dependencies container is a dictionary and not an odict() (it must be json-serialize-able), the
- order in which the dictionary is processed to create the container sometimes results in repository dependency entries in a folder that also
- includes the repository dependency as a sub-folder (if the repository dependency has it's own repository dependency). This method will remove
- all repository dependencies from folder that are also sub-folders of folder.
+ Since the object used to generate a repository dependencies container is a dictionary and not an odict() (it must be
+ json-serialize-able), the order in which the dictionary is processed to create the container sometimes results in
+ repository dependency entries in a folder that also includes the repository dependency as a sub-folder (if the
+ repository dependency has it's own repository dependency). This method will remove all repository dependencies from
+ folder that are also sub-folders of folder.
"""
repository_dependencies = [ rd for rd in folder.repository_dependencies ]
for repository_dependency in repository_dependencies:
- listified_repository_dependency = repository_dependency.listify
- if is_subfolder_of( folder, listified_repository_dependency ):
- repository_dependencies.remove( repository_dependency )
- folder.repository_dependencies = repository_dependencies
+ prune_folder( folder, repository_dependency )
for sub_folder in folder.folders:
return prune_repository_dependencies( sub_folder )
return folder
diff --git a/lib/tool_shed/util/export_util.py b/lib/tool_shed/util/export_util.py
index 4572519fab8..cd997931401 100644
--- a/lib/tool_shed/util/export_util.py
+++ b/lib/tool_shed/util/export_util.py
@@ -55,7 +55,8 @@ def clean_tool_shed_url( base_url ):
base = base.rstrip( '/' )
return base
-def export_repository( trans, tool_shed_url, repository_id, repository_name, changeset_revision, file_type, export_repository_dependencies, api=False ):
+def export_repository( trans, tool_shed_url, repository_id, repository_name, changeset_revision, file_type,
+ export_repository_dependencies, api=False ):
repository = suc.get_repository_in_tool_shed( trans, repository_id )
repositories_archive_filename = generate_repository_archive_filename( tool_shed_url,
str( repository.name ),
@@ -67,7 +68,8 @@ def export_repository( trans, tool_shed_url, repository_id, repository_name, cha
if export_repository_dependencies:
repo_info_dicts = get_repo_info_dicts( trans, tool_shed_url, repository_id, changeset_revision )
repository_ids = get_repository_ids( trans, repo_info_dicts )
- ordered_repository_ids, ordered_repositories, ordered_changeset_revisions = order_components_for_import( trans, repository_ids, repo_info_dicts )
+ ordered_repository_ids, ordered_repositories, ordered_changeset_revisions = \
+ order_components_for_import( trans, repository_id, repository_ids, repo_info_dicts )
else:
ordered_repository_ids = []
ordered_repositories = []
@@ -193,8 +195,8 @@ def generate_export_elem( tool_shed_url, repository, changeset_revision, export_
def get_components_from_repo_info_dict( trans, repo_info_dict ):
"""
- Return the repository and the associated latest installable changeset_revision (including updates) for the repository defined by the received
- repo_info_dict.
+ Return the repository and the associated latest installable changeset_revision (including updates) for the
+ repository defined by the received repo_info_dict.
"""
for repository_name, repo_info_tup in repo_info_dict.items():
# There should only be one entry in the received repo_info_dict.
@@ -208,8 +210,9 @@ def get_components_from_repo_info_dict( trans, repo_info_dict ):
def get_repo_info_dict_for_import( encoded_repository_id, encoded_repository_ids, repo_info_dicts ):
"""
- The received encoded_repository_ids and repo_info_dicts are lists that contain associated elements at each location in the list. This method will return the element
- from repo_info_dicts associated with the received encoded_repository_id by determining it's location in the received encoded_repository_ids list.
+ The received encoded_repository_ids and repo_info_dicts are lists that contain associated elements at each
+ location in the list. This method will return the element from repo_info_dicts associated with the received
+ encoded_repository_id by determining it's location in the received encoded_repository_ids list.
"""
for index, repository_id in enumerate( encoded_repository_ids ):
if repository_id == encoded_repository_id:
@@ -218,6 +221,10 @@ def get_repo_info_dict_for_import( encoded_repository_id, encoded_repository_ids
return None
def get_repo_info_dicts( trans, tool_shed_url, repository_id, changeset_revision ):
+ """
+ Return a list of dictionaries defining repositories that are required by the repository associated with the
+ received repository_id.
+ """
repository = suc.get_repository_in_tool_shed( trans, repository_id )
repository_metadata = suc.get_repository_metadata_by_changeset_revision( trans, repository_id, changeset_revision )
# Get a dictionary of all repositories upon which the contents of the current repository_metadata record depend.
@@ -246,8 +253,9 @@ def get_repo_info_dicts( trans, tool_shed_url, repository_id, changeset_revision
def get_repository_attributes_and_sub_elements( repository, archive_name ):
"""
- Get the information about a repository to create and populate an XML tag set. The generated attributes will be contained within the
- tag, while the sub_elements will be tag sets contained within the tag set.
+ Get the information about a repository to create and populate an XML tag set. The generated attributes will
+ be contained within the tag, while the sub_elements will be tag sets contained within the
+ tag set.
"""
attributes = odict()
sub_elements = odict()
@@ -268,6 +276,7 @@ def get_repository_attributes_and_sub_elements( repository, archive_name ):
return attributes, sub_elements
def get_repository_ids( trans, repo_info_dicts ):
+ """Return a list of repository ids associated with each dictionary in the received repo_info_dicts."""
repository_ids = []
for repo_info_dict in repo_info_dicts:
for repository_name, repo_info_tup in repo_info_dict.items():
@@ -277,23 +286,36 @@ def get_repository_ids( trans, repo_info_dicts ):
repository_ids.append( trans.security.encode_id( repository.id ) )
return repository_ids
-def order_components_for_import( trans, repository_ids, repo_info_dicts ):
+def order_components_for_import( trans, primary_repository_id, repository_ids, repo_info_dicts ):
"""
- Some repositories may have repository dependencies that must be imported and have metadata set on them before the dependent repository is imported. This method
- will inspect the list of repositories about to be exported and make sure to order them appropriately for proper import. For each repository about to be exported,
- if required repositories are not contained in the list of repositories about to be exported, then they are not considered. Repository dependency definitions that
- contain circular dependencies should not result in an infinite loop, but obviously ordering the list will not be handled for one or more of the repositories that
- require prior import.
+ Some repositories may have repository dependencies that must be imported and have metadata set on
+ them before the dependent repository is imported. This method will inspect the list of repositories
+ about to be exported and make sure to order them appropriately for proper import. For each repository
+ about to be exported, if required repositories are not contained in the list of repositories about to
+ be exported, then they are not considered. Repository dependency definitions that contain circular
+ dependencies should not result in an infinite loop, but obviously ordering the list will not be handled
+ for one or more of the repositories that require prior import.
"""
+ # The received primary_repository_id is the id of the repository being exported, with the received list
+ # of repository_ids being only the ids of all of its repository dependencies. The primary repository will
+ # always be last in the returned lists.
ordered_repository_ids = []
ordered_repositories = []
ordered_changeset_revisions = []
- # Create a dictionary whose keys are the received repository_ids and whose values are a list of repository_ids, each of which is contained in the received list of
- # repository_ids and whose associated repository must be imported prior to the repository associated with the repository_id key.
+ # Create a dictionary whose keys are the received repository_ids and whose values are a list of
+ # repository_ids, each of which is contained in the received list of repository_ids and whose associated
+ # repository must be imported prior to the repository associated with the repository_id key.
prior_import_required_dict = suc.get_prior_import_or_install_required_dict( trans, repository_ids, repo_info_dicts )
processed_repository_ids = []
+ # Process the list of repository dependencies defined for the repository associated with the received
+ # primary_repository_id.
while len( processed_repository_ids ) != len( prior_import_required_dict.keys() ):
repository_id = suc.get_next_prior_import_or_install_required_dict_entry( prior_import_required_dict, processed_repository_ids )
+ if repository_id == primary_repository_id:
+ # Append the primary_repository_id without processing it since it must be returned last in the order.
+ # It will be processed below after all dependencies are processed.
+ processed_repository_ids.append( primary_repository_id )
+ continue
processed_repository_ids.append( repository_id )
if repository_id not in ordered_repository_ids:
prior_import_required_ids = prior_import_required_dict[ repository_id ]
@@ -312,4 +334,11 @@ def order_components_for_import( trans, repository_ids, repo_info_dicts ):
ordered_repository_ids.append( repository_id )
ordered_repositories.append( repository )
ordered_changeset_revisions.append( changeset_revision )
+ # Process the repository associated with the received primary_repository_id last.
+ repo_info_dict = get_repo_info_dict_for_import( primary_repository_id, repository_ids, repo_info_dicts )
+ repository, changeset_revision = get_components_from_repo_info_dict( trans, repo_info_dict )
+ if repository and changeset_revision:
+ ordered_repository_ids.append( repository_id )
+ ordered_repositories.append( repository )
+ ordered_changeset_revisions.append( changeset_revision )
return ordered_repository_ids, ordered_repositories, ordered_changeset_revisions
diff --git a/lib/tool_shed/util/repository_maintenance_util.py b/lib/tool_shed/util/repository_maintenance_util.py
index 7e52ab9749f..96c51fc9d58 100644
--- a/lib/tool_shed/util/repository_maintenance_util.py
+++ b/lib/tool_shed/util/repository_maintenance_util.py
@@ -154,6 +154,9 @@ def create_repository_and_import_archive( trans, repository_archive_dict, import
# Populate the new repository with the contents of exported repository archive.
results_dict = import_util.import_repository_archive( trans, repository, repository_archive_dict )
ok = results_dict.get( 'ok', False )
+ error_message = results_dict.get( 'error_message', '' )
+ if error_message:
+ results_message += error_message
import_results_tups.append( ( ok, ( str( name ), str( username ) ), results_message ) )
else:
# The repository either already exists in this Tool Shed or the current user is not authorized to create it.
diff --git a/lib/tool_shed/util/shed_util_common.py b/lib/tool_shed/util/shed_util_common.py
index f7b030fc093..bf83152e1cc 100644
--- a/lib/tool_shed/util/shed_util_common.py
+++ b/lib/tool_shed/util/shed_util_common.py
@@ -745,10 +745,11 @@ def get_next_downloadable_changeset_revision( repository, repo, after_changeset_
def get_next_prior_import_or_install_required_dict_entry( prior_required_dict, processed_tsr_ids ):
"""
- This method is used in the Tool Shed when exporting a repository and it's dependencies, and in Galaxy when a repository and it's dependencies
- are being installed. The order in which the prior_required_dict is processed is critical in order to ensure that the ultimate repository import
- or installation order is correctly defined. This method determines the next key / value pair from the received prior_required_dict that should
- be processed.
+ This method is used in the Tool Shed when exporting a repository and it's dependencies, and in Galaxy
+ when a repository and it's dependencies are being installed. The order in which the prior_required_dict
+ is processed is critical in order to ensure that the ultimate repository import or installation order is
+ correctly defined. This method determines the next key / value pair from the received prior_required_dict
+ that should be processed.
"""
# Return the first key / value pair that is not yet processed and whose value is an empty list.
for key, value in prior_required_dict.items():
@@ -756,7 +757,8 @@ def get_next_prior_import_or_install_required_dict_entry( prior_required_dict, p
continue
if not value:
return key
- # Return the first key / value pair that is not yet processed and whose ids in value are all included in processed_tsr_ids.
+ # Return the first key / value pair that is not yet processed and whose ids in value are all included
+ # in processed_tsr_ids.
for key, value in prior_required_dict.items():
if key in processed_tsr_ids:
continue
@@ -767,7 +769,8 @@ def get_next_prior_import_or_install_required_dict_entry( prior_required_dict, p
break
if all_contained:
return key
- # Return the first key / value pair that is not yet processed. Hopefully this is all that is necessary at this point.
+ # Return the first key / value pair that is not yet processed. Hopefully this is all that is necessary
+ # at this point.
for key, value in prior_required_dict.items():
if key in processed_tsr_ids:
continue
@@ -862,9 +865,10 @@ def get_prior_import_or_install_required_dict( trans, tsr_ids, repo_info_dicts )
def get_query_for_setting_metadata_on_repositories( trans, my_writable=False, order=True ):
"""
- Return a query containing repositories for resetting metadata. This method is called from both the Tool Shed and Galaxy. The
- my_writable parameter is ignored unless called from the Tool Shed, and the order parameter is used for displaying the list of
- repositories ordered alphabetically for display on a page. When called from wither the Tool Shed or Galaxy API, order is False.
+ Return a query containing repositories for resetting metadata. This method is called from both the
+ Tool Shed and Galaxy. The my_writable parameter is ignored unless called from the Tool Shed, and the
+ order parameter is used for displaying the list of repositories ordered alphabetically for display on
+ a page. When called from either the Tool Shed or Galaxy API, order is False.
"""
if trans.webapp.name == 'tool_shed':
# When called from the Tool Shed API, the metadata is reset on all repositories of type tool_dependency_definition in addition
@@ -873,7 +877,8 @@ def get_query_for_setting_metadata_on_repositories( trans, my_writable=False, or
username = trans.user.username
clause_list = []
for repository in trans.sa_session.query( trans.model.Repository ) \
- .filter( trans.model.Repository.table.c.deleted == False ):
+ .filter( and_( trans.model.Repository.table.c.deleted == False,
+ trans.model.Repository.table.c.deprecated == False ) ):
# Always reset metadata on all repositories of type tool_dependency_definition.
if repository.type == rt_util.TOOL_DEPENDENCY_DEFINITION:
clause_list.append( trans.model.Repository.table.c.id == repository.id )
@@ -900,12 +905,14 @@ def get_query_for_setting_metadata_on_repositories( trans, my_writable=False, or
else:
if order:
return trans.sa_session.query( trans.model.Repository ) \
- .filter( trans.model.Repository.table.c.deleted == False ) \
+ .filter( and_( trans.model.Repository.table.c.deleted == False,
+ trans.model.Repository.table.c.deprecated == False ) ) \
.order_by( trans.model.Repository.table.c.name,
trans.model.Repository.table.c.user_id )
else:
return trans.sa_session.query( trans.model.Repository ) \
- .filter( trans.model.Repository.table.c.deleted == False )
+ .filter( and_( trans.model.Repository.table.c.deleted == False,
+ trans.model.Repository.table.c.deprecated == False ) )
else:
# We're in Galaxy.
if order:
diff --git a/scripts/cleanup_datasets/pgcleanup.py b/scripts/cleanup_datasets/pgcleanup.py
index fb4a2a106be..03bc5a07eb2 100755
--- a/scripts/cleanup_datasets/pgcleanup.py
+++ b/scripts/cleanup_datasets/pgcleanup.py
@@ -105,7 +105,7 @@ class Cleanup(object):
url = make_url(self.config.database_connection)
log.info('Connecting to database with URL: %s' % url)
- args = url.translate_connect_args()
+ args = url.translate_connect_args( username='user' )
args.update(url.query)
assert url.get_dialect().name == 'postgresql', 'This script can only be used with PostgreSQL.'
diff --git a/scripts/functional_tests.py b/scripts/functional_tests.py
index 9cb9f281bec..995783004ef 100644
--- a/scripts/functional_tests.py
+++ b/scripts/functional_tests.py
@@ -313,6 +313,7 @@ def main():
file_path = os.path.join( galaxy_db_path, 'files' )
new_file_path = tempfile.mkdtemp( prefix='new_files_path_', dir=tempdir )
job_working_directory = tempfile.mkdtemp( prefix='job_working_directory_', dir=tempdir )
+ install_database_connection = os.environ.get( 'GALAXY_TEST_INSTALL_DBURI', None )
if 'GALAXY_TEST_DBURI' in os.environ:
database_connection = os.environ['GALAXY_TEST_DBURI']
else:
@@ -372,6 +373,8 @@ def main():
user_library_import_dir=user_library_import_dir,
master_api_key=master_api_key,
)
+ if install_database_connection is not None:
+ kwargs[ 'install_database_connection' ] = install_database_connection
if psu_production:
kwargs[ 'global_conf' ] = None
if not database_connection.startswith( 'sqlite://' ):
diff --git a/static/scripts/galaxy.library.js b/static/scripts/galaxy.library.js
index d133fb8cef3..1ff2f6e6063 100644
--- a/static/scripts/galaxy.library.js
+++ b/static/scripts/galaxy.library.js
@@ -90,7 +90,7 @@ define([
// === VIEWS ====
// MMMMMMMMMMMMMM
-// galaxy folder
+//main view for folder browsing
var FolderContentView = Backbone.View.extend({
// main element definition
el : '#center',
@@ -116,7 +116,7 @@ var FolderContentView = Backbone.View.extend({
// === TEMPLATES ====
// MMMMMMMMMMMMMMMMMM
- // set up
+ // main template for folder browsing
templateFolder : function (){
var tmpl_array = [];
@@ -162,7 +162,7 @@ var FolderContentView = Backbone.View.extend({
tmpl_array.push('