galaxy-commits
Threads by month
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 15302 discussions
galaxy-dist commit 5401c7d2e13b: Bug fix for verifying a tool suite uploaded to the tool shed.
by commits-noreply@bitbucket.org 30 Jul '10
by commits-noreply@bitbucket.org 30 Jul '10
30 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1280263037 14400
# Node ID 5401c7d2e13bbd214e1a424e71c4fbcbac7cf919
# Parent eacdaf59c8dea773a8525966a8c6b65753ab777c
Bug fix for verifying a tool suite uploaded to the tool shed.
--- a/lib/galaxy/webapps/community/datatypes/__init__.py
+++ b/lib/galaxy/webapps/community/datatypes/__init__.py
@@ -148,7 +148,7 @@ class ToolSuite( Tool ):
tar = tarfile.open( f.name )
except tarfile.ReadError:
raise DatatypeVerificationError( 'The archive is not a readable tar file.' )
- suite_config = filter( lambda x: x.lower() == 'suite_config.xml', tar.getnames() )
+ suite_config = filter( lambda x: x.lower().find( 'suite_config.xml' ) >=0, tar.getnames() )
if not suite_config:
raise DatatypeVerificationError( 'The archive does not contain the required suite_config.xml config file. If you are uploading a single tool archive, set the upload type to "Tool".' )
suite_config = suite_config[ 0 ]
1
0
galaxy-dist commit f94f1f2fa4be: Fixes for generating viewports.
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Dan Blankenberg <dan(a)bx.psu.edu>
# Date 1279901436 14400
# Node ID f94f1f2fa4be20f8f90ffa9482a754f69256f449
# Parent cecc290755014c02aa21906d433a3d39f2d657d5
Fixes for generating viewports.
Now, a maximum of 1MB is read from a line to determine the viewport; if a line greater than 10MB is encountered, then no viewport will be generated.
Additional fixes for certain cases when viewport was not determined properly for for WIG tracks and GFF.
--- a/lib/galaxy/datatypes/interval.py
+++ b/lib/galaxy/datatypes/interval.py
@@ -38,6 +38,10 @@ for key, value in alias_spec.items():
for elem in value:
alias_helper[elem] = key
+#Constants for configuring viewport generation
+VIEWPORT_READLINE_BUFFER_SIZE = 1048576 #1MB
+VIEWPORT_MAX_READS_PER_LINE = 10 # If a line is greater than VIEWPORT_MAX_READS_PER_LINE * VIEWPORT_READLINE_BUFFER_SIZE bytes in size, then we will not generate a viewport for that dataset
+
class Interval( Tabular ):
"""Tab delimited data containing interval information"""
file_ext = "interval"
@@ -146,33 +150,55 @@ class Interval( Tabular ):
and dataset.metadata.endCol
except:
return False
- def get_estimated_display_viewport( self, dataset ):
+ def get_estimated_display_viewport( self, dataset, chrom_col = None, start_col = None, end_col = None ):
"""Return a chrom, start, stop tuple for viewing a file."""
+ viewport_feature_count = 100 # viewport should check at least 100 features; excludes comment lines
+ max_line_count = max( viewport_feature_count, 500 ) # maximum number of lines to check; includes comment lines
if self.displayable( dataset ):
try:
- c, s, e = dataset.metadata.chromCol, dataset.metadata.startCol, dataset.metadata.endCol
- c, s, e = int(c)-1, int(s)-1, int(e)-1
- try:
- skipme = int(dataset.metadata.comment_lines)
- except:
- skipme = 0
- peek = []
- for idx, line in enumerate(file(dataset.file_name)):
- if line[0] != '#':
- peek.append( line.rstrip( '\n\r' ).split() )
- if idx > 100 and idx > skipme: # viewport should have at least 100 features
- break
- chr, start, stop = peek[skipme][c], int( peek[skipme][s] ), int( peek[skipme][e] )
- for p in peek[(skipme+1):]:
- if p[0] == chr:
- start = min( start, int( p[s] ) )
- stop = max( stop, int( p[e] ) )
- except Exception, exc:
- log.exception( str(exc) )
- return ( None, None, None )
- return (chr, str( start ), str( stop ))
- else:
- return ( None, None, None )
+ chrom = None
+ start = sys.maxint
+ end = 0
+ if chrom_col is None:
+ chrom_col = int( dataset.metadata.chromCol ) - 1
+ if start_col is None:
+ start_col = int( dataset.metadata.startCol ) - 1
+ if end_col is None:
+ end_col = int( dataset.metadata.endCol ) - 1
+ max_col = max( chrom_col, start_col, end_col )
+ fh = open( dataset.file_name )
+ while True:
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ if not line.startswith( '#' ):
+ try:
+ fields = line.rstrip().split( '\t' )
+ if len( fields ) > max_col:
+ if chrom is None or chrom == fields[ chrom_col ]:
+ start = min( start, int( fields[ start_col ] ) )
+ end = max( end, int( fields[ end_col ] ) )
+ chrom = fields[ chrom_col ] #set chrom last, in case start and end are not integers
+ viewport_feature_count -= 1
+ except Exception:
+ #most likely a non-integer field has been encountered for start / stop
+ continue
+ #make sure we are at the next new line
+ readline_count = VIEWPORT_MAX_READS_PER_LINE
+ while line.rstrip( '\n\r' ) == line:
+ assert readline_count > 0, Exception( 'Viewport readline count exceeded for dataset %s.' % dataset.id )
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ readline_count -= 1
+ max_line_count -= 1
+ if not viewport_feature_count or not max_line_count:
+ #exceeded viewport or total line count to check
+ break
+ if chrom is not None:
+ return ( chrom, str( start ), str( end ) ) #Necessary to return strings?
+ except Exception, e:
+ #unexpected error, possibly missing metadata
+ log.exception( str( e ) )
+ return ( None, None, None ) #could not determine viewport
def as_ucsc_display_file( self, dataset, **kwd ):
"""Returns file contents with only the bed data"""
fd, temp_name = tempfile.mkstemp()
@@ -336,49 +362,11 @@ class BedGraph( Interval ):
"""
return open( dataset.file_name )
- def get_estimated_display_viewport( self, dataset ):
+ def get_estimated_display_viewport( self, dataset, chrom_col = 0, start_col = 1, end_col = 2 ):
"""
Set viewport based on dataset's first 100 lines.
"""
- if self.displayable( dataset ):
- try:
- # Set seqid, start, stop.
- seqid = None
- start = 2147483647 # Maximum value of a signed 32 bit integer ( 2**31 - 1 )
- stop = 0
- for i, line in enumerate( file( dataset.file_name ) ):
- line = line.rstrip( '\r\n' )
- if not line:
- continue
- elems = line.split('\t')
- if len( elems ) == 4:
- # Update seq id, start, end.
- if not seqid:
- # We can only set the viewport for a single chromosome
- seqid = elems[0]
- if seqid == elems[0]:
- # Make sure we have not spanned chromosomes
- start = min( start, int( elems[1] ) )
- stop = max( stop, int( elems[2] ) )
- else:
- # We've spanned a chromosome
- break
- else:
- continue
- # Only look through 100 lines.
- if i > 100:
- break
-
- # Set valid values for start, stop if necessary.
- if start == 2147483647:
- start = 0
- if stop == 0:
- stop = 1
- return ( seqid, str( start ), str( stop ) )
- except Exception, exc:
- log.exception( str( exc ) )
- return ( None, None, None )
- return ( None, None, None )
+ return Interval.get_estimated_display_viewport( self, dataset, chrom_col = chrom_col, start_col = start_col, end_col = end_col )
class Bed( Interval ):
"""Tab delimited data in BED format"""
@@ -644,61 +632,75 @@ class Gff( Tabular, _RemoteCallMixin ):
Return a chrom, start, stop tuple for viewing a file. There are slight differences between gff 2 and gff 3
formats. This function should correctly handle both...
"""
+ viewport_feature_count = 100 # viewport should check at least 100 features; excludes comment lines
+ max_line_count = max( viewport_feature_count, 500 ) # maximum number of lines to check; includes comment lines
if self.displayable( dataset ):
try:
- seqid = ''
- start = 2147483647 # Maximum value of a signed 32 bit integer ( 2**31 - 1 )
+ seqid = None
+ start = sys.maxint
stop = 0
- for i, line in enumerate( file( dataset.file_name ) ):
- line = line.rstrip( '\r\n' )
- if not line:
- continue
- if line.startswith( '##sequence-region' ): # ##sequence-region IV 6000000 6030000
- elems = line.split()
- if len( elems ) > 3:
- # line looks like:
- # ##sequence-region ctg123 1 1497228
- seqid = elems[1] # IV
- start = elems[2] # 6000000
- stop = elems[3] # 6030000
- break
- elif len( elems ) == 2 and elems[1].find( '..' ) > 0:
- # line looks like this:
- # ##sequence-region X:120000..140000
- elems = elems[1].split( ':' )
- seqid = elems[0]
- start = elems[1].split( '..' )[0]
- stop = elems[1].split( '..' )[1]
- break
- else:
- log.exception( "line (%s) uses an unsupported ##sequence-region definition." % str( line ) )
- break
- # Allow UCSC style browser and track info in the GFF file
- if line.startswith("browser position"):
- pos_info = line.split()[-1]
- seqid, startend = pos_info.split(":")
- start, end = startend.split("-")
+ fh = open( dataset.file_name )
+ while True:
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ try:
+ if line.startswith( '##sequence-region' ): # ##sequence-region IV 6000000 6030000
+ elems = line.rstrip( '\n\r' ).split()
+ if len( elems ) > 3:
+ # line looks like:
+ # ##sequence-region ctg123 1 1497228
+ seqid = elems[1] # IV
+ start = int( elems[2] )# 6000000
+ stop = int( elems[3] ) # 6030000
+ break #use location declared in file
+ elif len( elems ) == 2 and elems[1].find( '..' ) > 0:
+ # line looks like this:
+ # ##sequence-region X:120000..140000
+ elems = elems[1].split( ':' )
+ seqid = elems[0]
+ start = int( elems[1].split( '..' )[0] )
+ stop = int( elems[1].split( '..' )[1] )
+ break #use location declared in file
+ else:
+ log.exception( "line (%s) uses an unsupported ##sequence-region definition." % str( line ) )
+ #break #no break, if bad definition, we try another method
+ elif line.startswith("browser position"):
+ # Allow UCSC style browser and track info in the GFF file
+ pos_info = line.split()[-1]
+ seqid, startend = pos_info.split(":")
+ start, stop = map( int, startend.split("-") )
+ break #use location declared in file
+ elif True not in map( line.startswith, ( '#', 'track', 'browser' ) ):# line.startswith() does not accept iterator in python2.4
+ viewport_feature_count -= 1
+ elems = line.rstrip( '\n\r' ).split( '\t' )
+ if len( elems ) > 3:
+ if not seqid:
+ # We can only set the viewport for a single chromosome
+ seqid = elems[0]
+ if seqid == elems[0]:
+ # Make sure we have not spanned chromosomes
+ start = min( start, int( elems[3] ) )
+ stop = max( stop, int( elems[4] ) )
+ except:
+ #most likely start/stop is not an int or not enough fields
+ pass
+ #make sure we are at the next new line
+ readline_count = VIEWPORT_MAX_READS_PER_LINE
+ while line.rstrip( '\n\r' ) == line:
+ assert readline_count > 0, Exception( 'Viewport readline count exceeded for dataset %s.' % dataset.id )
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ readline_count -= 1
+ max_line_count -= 1
+ if not viewport_feature_count or not max_line_count:
+ #exceeded viewport or total line count to check
break
- if not line.startswith(('#', 'track', 'browser')) :
- elems = line.split( '\t' )
- if not seqid:
- # We can only set the viewport for a single chromosome
- seqid = elems[0]
- if seqid == elems[0]:
- # Make sure we have not spanned chromosomes
- start = min( start, int( elems[3] ) )
- stop = max( stop, int( elems[4] ) )
- else:
- # We've spanned a chromosome
- break
- if i > 10:
- break
+ if seqid is not None:
+ return ( seqid, str( start ), str( stop ) ) #Necessary to return strings?
except Exception, e:
+ #unexpected error
log.exception( str( e ) )
- return ( None, None, None )
- return ( seqid, str( start ), str( stop ) )
- else:
- return ( None, None, None )
+ return ( None, None, None ) #could not determine viewport
def ucsc_links( self, dataset, type, app, base_url ):
ret_val = []
seqid, start, stop = self.get_estimated_display_viewport( dataset )
@@ -963,44 +965,67 @@ class Wiggle( Tabular, _RemoteCallMixin
Tabular.__init__( self, **kwd )
self.add_display_app( 'ucsc', 'display at UCSC', 'as_ucsc_display_file', 'ucsc_links' )
self.add_display_app( 'gbrowse', 'display in Gbrowse', 'as_gbrowse_display_file', 'gbrowse_links' )
-
def get_estimated_display_viewport( self, dataset ):
+ """Return a chrom, start, stop tuple for viewing a file."""
+ viewport_feature_count = 100 # viewport should check at least 100 features; excludes comment lines
+ max_line_count = max( viewport_feature_count, 500 ) # maximum number of lines to check; includes comment lines
if self.displayable( dataset ):
- num_check_lines = 100 # only check up to this many non empty lines
- vstart = None
- vend = 0
- vwig_chr = '?'
- value = None
- for i, line in enumerate( file( dataset.file_name ) ):
- line = line.rstrip( '\r\n' )
- if line:
- if line.startswith( "browser" ):
- chr_info = line.split()[-1]
- wig_chr, coords = chr_info.split( ":" )
- start, end = coords.split( "-" )
- value = ( wig_chr, start, end )
+ try:
+ chrom = None
+ start = sys.maxint
+ end = 0
+ span = 1
+ step = None
+ fh = open( dataset.file_name )
+ while True:
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ try:
+ if line.startswith( "browser" ):
+ chr_info = line.rstrip( '\n\r' ).split()[-1]
+ chrom, coords = chr_info.split( ":" )
+ start, end = map( int, coords.split( "-" ) )
+ break # use the browser line
+ # variableStep chrom=chr20
+ if line and ( line.lower().startswith( "variablestep" ) or line.lower().startswith( "fixedstep" ) ):
+ if chrom is not None: break #different chrom or different section of the chrom
+ chrom = line.rstrip( '\n\r' ).split("chrom=")[1].split()[0]
+ if 'span=' in line:
+ span = int( line.rstrip( '\n\r' ).split("span=")[1].split()[0] )
+ if 'step=' in line:
+ step = int( line.rstrip( '\n\r' ).split("step=")[1].split()[0] )
+ start = int( line.rstrip( '\n\r' ).split("start=")[1].split()[0] )
+ else:
+ fields = line.rstrip( '\n\r' ).split()
+ if fields:
+ if step is not None:
+ if not end:
+ end = start + span
+ else:
+ end += step
+ else:
+ start = min( int( fields[0] ), start )
+ end = max( end, int( fields[0] ) + span )
+ viewport_feature_count -= 1
+ except:
+ pass
+ #make sure we are at the next new line
+ readline_count = VIEWPORT_MAX_READS_PER_LINE
+ while line.rstrip( '\n\r' ) == line:
+ assert readline_count > 0, Exception( 'Viewport readline count exceeded for dataset %s.' % dataset.id )
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ readline_count -= 1
+ max_line_count -= 1
+ if not viewport_feature_count or not max_line_count:
+ #exceeded viewport or total line count to check
break
- # variableStep chrom=chr20
- if line and (line.lower().startswith( "variablestep" ) or line.lower().startswith( "fixedstep" )):
- c = line.split("chr")[-1]
- c = c.split()[0]
- vwig_chr = 'chr%s' % c
- else:
- try:
- offset = line.split()[0]
- offset = int(offset)
- vend = max(vend,offset)
- if not vstart:
- vstart = offset # first
- except:
- pass
- if i > num_check_lines:
- break
- if value == None:
- value = (vwig_chr, vstart, vend)
- return value
- else:
- return ( None, None, None )
+ if chrom is not None:
+ return ( chrom, str( start ), str( end ) ) #Necessary to return strings?
+ except Exception, e:
+ #unexpected error
+ log.exception( str( e ) )
+ return ( None, None, None ) #could not determine viewport
def gbrowse_links( self, dataset, type, app, base_url ):
ret_val = []
chrom, start, stop = self.get_estimated_display_viewport( dataset )
@@ -1119,44 +1144,61 @@ class CustomTrack ( Tabular ):
def display_peek( self, dataset ):
"""Returns formated html of peek"""
return Tabular.make_html_table( self, dataset, skipchars=['track', '#'] )
- def get_estimated_display_viewport( self, dataset ):
+ def get_estimated_display_viewport( self, dataset, chrom_col = None, start_col = None, end_col = None ):
+ """Return a chrom, start, stop tuple for viewing a file."""
+ #FIXME: only BED and WIG custom tracks are currently supported
+ #As per previously existing behavior, viewport will only be over the first intervals
+ max_line_count = 100 # maximum number of lines to check; includes comment lines
+ variable_step_wig = False
+ chrom = None
+ span = 1
if self.displayable( dataset ):
try:
- wiggle_format = False
- for line in open(dataset.file_name):
- if (line.startswith("chr") or line.startswith("scaffold")):
- line = line.rstrip( '\n\r' )
- start = line.split("\t")[1].replace(",","")
- end = line.split("\t")[2].replace(",","")
-
- if int(start) < int(end):
- value = ( line.split("\t")[0], start, end )
- else:
- value = ( line.split("\t")[0], end, start )
-
+ fh = open( dataset.file_name )
+ while True:
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ if not line.startswith( '#' ):
+ try:
+ if variable_step_wig:
+ fields = line.rstrip().split()
+ if len( fields ) == 2:
+ start = int( fields[ 0 ] )
+ return ( chrom, str( start ), str( start + span ) )
+ elif line and ( line.lower().startswith( "variablestep" ) or line.lower().startswith( "fixedstep" ) ):
+ chrom = line.rstrip( '\n\r' ).split("chrom=")[1].split()[0]
+ if 'span=' in line:
+ span = int( line.rstrip( '\n\r' ).split("span=")[1].split()[0] )
+ if 'start=' in line:
+ start = int( line.rstrip( '\n\r' ).split("start=")[1].split()[0] )
+ return ( chrom, str( start ), str( start + span ) )
+ else:
+ variable_step_wig = True
+ else:
+ fields = line.rstrip().split( '\t' )
+ if len( fields ) >= 3:
+ chrom = fields[ 0 ]
+ start = int( fields[ 1 ] )
+ end = int( fields[ 2 ] )
+ return ( chrom, str( start ), str( end ) )
+ except Exception:
+ #most likely a non-integer field has been encountered for start / stop
+ continue
+ #make sure we are at the next new line
+ readline_count = VIEWPORT_MAX_READS_PER_LINE
+ while line.rstrip( '\n\r' ) == line:
+ assert readline_count > 0, Exception( 'Viewport readline count exceeded for dataset %s.' % dataset.id )
+ line = fh.readline( VIEWPORT_READLINE_BUFFER_SIZE )
+ if not line: break #EOF
+ readline_count -= 1
+ max_line_count -= 1
+ if not max_line_count:
+ #exceeded viewport or total line count to check
break
-
- elif (line.startswith('variableStep')):
- # wiggle format
- wiggle_format = True
- wig_chr = line.split()[1].split('=')[1]
- if not wig_chr.startswith("chr"):
- value = ('', '', '')
- break
- elif wiggle_format:
- # wiggle format
- if line.split("\t")[0].isdigit():
- start = line.split("\t")[0]
- end = str(int(start) + 1)
- value = (wig_chr, start, end)
- else:
- value = (wig_chr, '', '')
- break
- return value #returns the co-ordinates of the 1st track/dataset
- except:
- return ( None, None, None )
- else:
- return ( None, None, None )
+ except Exception, e:
+ #unexpected error
+ log.exception( str( e ) )
+ return ( None, None, None ) #could not determine viewport
def ucsc_links( self, dataset, type, app, base_url ):
ret_val = []
chrom, start, stop = self.get_estimated_display_viewport(dataset)
1
0
galaxy-dist commit cecc29075501: Galaxy Tool Shed enhancements
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1279831412 14400
# Node ID cecc290755014c02aa21906d433a3d39f2d657d5
# Parent db1ae0bc8995cb30deef73ce9d14ef175c512f90
Galaxy Tool Shed enhancements
1. Rename Galaxy Community Space to Galaxy Tool Shed
2. Add the ability to upload an archive consisting of a suite of tools in addition to a single tool archive.
3. Miscellaneous code cleanup including elimination of all sniffer related code.
--- a/templates/webapps/community/tool/edit_tool.mako
+++ b/templates/webapps/community/tool/edit_tool.mako
@@ -93,7 +93,7 @@
%if can_edit:
<form id="edit_tool" name="edit_tool" action="${h.url_for( controller='common', action='edit_tool' )}" method="post">
- %if tool.is_rejected():
+ %if tool.is_rejected:
<div class="toolForm"><div class="toolFormTitle">Reason for rejection</div><div class="toolFormBody">
@@ -169,7 +169,7 @@
</div></div><p/>
- %if tool.is_new() or tool.is_rejected():
+ %if tool.is_new or tool.is_rejected:
<div class="toolForm"><div class="toolFormTitle">Get approval for publishing</div><div class="toolFormBody">
--- a/lib/galaxy/webapps/community/security/__init__.py
+++ b/lib/galaxy/webapps/community/security/__init__.py
@@ -1,5 +1,5 @@
"""
-Galaxy Community Space Security
+Galaxy Tool Shed Security
"""
import logging, socket, operator
from datetime import datetime, timedelta
@@ -167,14 +167,14 @@ class CommunityRBACAgent( RBACAgent ):
def can_approve_or_reject( self, user, user_is_admin, cntrller, item ):
# The current user can approve or reject the item if the user
# is an admin, and the item's state is WAITING.
- return user and user_is_admin and cntrller=='admin' and item.is_waiting()
+ return user and user_is_admin and cntrller=='admin' and item.is_waiting
def can_delete( self, user, user_is_admin, cntrller, item ):
# The current user can delete the item if they are an admin or if they uploaded the
# item and in either case the item's state is not DELETED.
if user and user_is_admin and cntrller == 'admin':
- can_delete = not item.is_deleted()
+ can_delete = not item.is_deleted
elif cntrller in [ 'tool' ]:
- can_delete = user==item.user and not item.is_deleted()
+ can_delete = user==item.user and not item.is_deleted
else:
can_delete = False
return can_delete
@@ -184,7 +184,7 @@ class CommunityRBACAgent( RBACAgent ):
if user and user_is_admin and cntrller == 'admin':
return True
elif cntrller in [ 'tool' ]:
- can_download = not( item.is_new() or item.is_waiting() )
+ can_download = not( item.is_new or item.is_waiting )
else:
can_download = False
return can_download
@@ -194,7 +194,7 @@ class CommunityRBACAgent( RBACAgent ):
if user and user_is_admin and cntrller == 'admin':
return True
if cntrller in [ 'tool' ]:
- return user and user==item.user and ( item.is_new() or item.is_rejected() )
+ return user and user==item.user and ( item.is_new or item.is_rejected )
return False
def can_purge( self, user, user_is_admin, cntrller ):
# The current user can purge the item if they are an admin.
@@ -206,7 +206,7 @@ class CommunityRBACAgent( RBACAgent ):
versions = get_versions( item )
state_ok = True
for version in versions:
- if version.is_new() or version.is_waiting():
+ if version.is_new or version.is_waiting:
state_ok = False
break
return state_ok
@@ -215,7 +215,7 @@ class CommunityRBACAgent( RBACAgent ):
# or if the item's state is APPROVED.
if user and user_is_admin and cntrller == 'admin':
return True
- if cntrller in [ 'tool' ] and item.is_approved():
+ if cntrller in [ 'tool' ] and item.is_approved:
return True
return user and user==item.user
def get_all_action_permissions( self, user, user_is_admin, cntrller, item ):
@@ -236,7 +236,7 @@ class CommunityRBACAgent( RBACAgent ):
elif cntrller in [ 'tool' ]:
visible_versions = []
for version in get_versions( item ):
- if version.is_approved() or version.is_archived() or version.user == user:
+ if version.is_approved or version.is_archived or version.user == user:
visible_versions.append( version )
else:
visible_versions = []
--- a/templates/webapps/community/tool/view_tool.mako
+++ b/templates/webapps/community/tool/view_tool.mako
@@ -85,7 +85,7 @@
%endif
%if can_view:
- %if tool.is_rejected():
+ %if tool.is_rejected:
<div class="toolForm"><div class="toolFormTitle">Reason for rejection</div><div class="toolFormBody">
@@ -168,7 +168,7 @@
<div class="toolFormBody"><div class="form-row"><ul class="toolFile">
- <li><a href="${h.url_for( controller='tool', action='download_tool', id=trans.app.security.encode_id( tool.id ) )}">${tool.download_file_name}</a></li>
+ <li><a href="${h.url_for( controller='common', action='download_tool', id=trans.app.security.encode_id( tool.id ), cntrller=cntrller )}">${tool.download_file_name}</a></li><ul class="fileBrowser">
%for name in tool_file_contents:
<li><a href="${h.url_for( controller='tool', action='view_tool_file', id=trans.app.security.encode_id( tool.id ), file_name=quote_plus( name ) )}">${name}</a></li>
--- a/lib/galaxy/webapps/community/controllers/common.py
+++ b/lib/galaxy/webapps/community/controllers/common.py
@@ -14,6 +14,11 @@ class ToolListGrid( grids.Grid ):
class NameColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
return tool.name
+ class TypeColumn( grids.GridColumn ):
+ def get_value( self, trans, grid, tool ):
+ if tool.is_suite:
+ return 'Suite'
+ return 'Tool'
class VersionColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
return tool.version
@@ -60,6 +65,10 @@ class ToolListGrid( grids.Grid ):
model_class=model.Tool,
attach_popup=False
),
+ TypeColumn( "Type",
+ key="suite",
+ model_class=model.Tool,
+ attach_popup=False ),
VersionColumn( "Version",
key="version",
model_class=model.Tool,
@@ -229,7 +238,7 @@ class CommonController( BaseController )
in_categories.append( ( category.id, category.name ) )
else:
out_categories.append( ( category.id, category.name ) )
- if tool.is_rejected():
+ if tool.is_rejected:
# Include the comments regarding the reason for rejection
reason_for_rejection = get_most_recent_event( tool ).comment
else:
@@ -283,7 +292,7 @@ class CommonController( BaseController )
visible_versions = trans.app.security_agent.get_visible_versions( trans.user, trans.user_is_admin(), cntrller, tool )
categories = [ tca.category for tca in tool.categories ]
tool_file_contents = tarfile.open( tool.file_name, 'r' ).getnames()
- if tool.is_rejected():
+ if tool.is_rejected:
# Include the comments regarding the reason for rejection
reason_for_rejection = get_most_recent_event( tool ).comment
else:
--- /dev/null
+++ b/lib/galaxy/webapps/community/model/migrate/versions/0002_add_tool_suite_column.py
@@ -0,0 +1,48 @@
+"""
+Migration script to add the suite column to the tool table.
+"""
+
+from sqlalchemy import *
+from sqlalchemy.orm import *
+from migrate import *
+from migrate.changeset import *
+
+import logging
+log = logging.getLogger( __name__ )
+
+metadata = MetaData( migrate_engine )
+db_session = scoped_session( sessionmaker( bind=migrate_engine, autoflush=False, autocommit=True ) )
+
+def upgrade():
+ print __doc__
+ metadata.reflect()
+
+ # Create and initialize imported column in job table.
+ Tool_table = Table( "tool", metadata, autoload=True )
+ c = Column( "suite", Boolean, default=False, index=True )
+ try:
+ # Create
+ c.create( Tool_table )
+ assert c is Tool_table.c.suite
+
+ # Initialize.
+ if migrate_engine.name == 'mysql' or migrate_engine.name == 'sqlite':
+ default_false = "0"
+ elif migrate_engine.name == 'postgres':
+ default_false = "false"
+ db_session.execute( "UPDATE tool SET suite=%s" % default_false )
+
+ except Exception, e:
+ print "Adding suite column to the tool table failed: %s" % str( e )
+ log.debug( "Adding suite column to the tool table failed: %s" % str( e ) )
+
+def downgrade():
+ metadata.reflect()
+
+ # Drop imported column from job table.
+ Tool_table = Table( "tool", metadata, autoload=True )
+ try:
+ Tool_table.c.suite.drop()
+ except Exception, e:
+ print "Dropping column suite from the tool table failed: %s" % str( e )
+ log.debug( "Dropping column suite from the tool table failed: %s" % str( e ) )
--- a/lib/galaxy/webapps/community/controllers/upload.py
+++ b/lib/galaxy/webapps/community/controllers/upload.py
@@ -2,6 +2,7 @@ import sys, os, shutil, logging, urllib2
from galaxy.web.base.controller import *
from galaxy.web.framework.helpers import time_ago, iff, grids
from galaxy.model.orm import *
+from galaxy.web.form_builder import SelectField
from galaxy.webapps.community import datatypes
from common import get_categories, get_category, get_versions
@@ -25,12 +26,13 @@ class UploadController( BaseController )
replace_id = params.get( 'replace_id', None )
replace_version = None
uploaded_file = None
+ upload_type = params.get( 'upload_type', 'tool' )
categories = get_categories( trans )
if not categories:
return trans.response.send_redirect( web.url_for( controller='tool',
action='browse_tools',
cntrller='tool',
- message='No categories have been configured in this instance of the Galaxy Community. An administrator needs to create some via the Administrator control panel before anything can be uploaded',
+ message='No categories have been configured in this instance of the Galaxy Tool Shed. An administrator needs to create some via the Administrator control panel before anything can be uploaded',
status='error' ) )
if params.get( 'upload_button', False ):
url_paste = params.get( 'url', '' ).strip()
@@ -50,8 +52,6 @@ class UploadController( BaseController )
elif file_data not in ( '', None ):
uploaded_file = file_data.file
if uploaded_file:
- # TODO: tool should no longer be the default when we upload histories and workflows
- upload_type = params.get( 'upload_type', 'tool' )
datatype = trans.app.datatypes_registry.get_datatype_by_extension( upload_type )
if datatype is None:
message = 'An unknown file type was selected. This should not be possible, please report the error.'
@@ -62,6 +62,7 @@ class UploadController( BaseController )
meta = datatype.verify( uploaded_file )
meta.user = trans.user
meta.guid = trans.app.security.get_new_guid()
+ meta.suite = upload_type == 'toolsuite'
obj = datatype.create_model_object( meta )
trans.sa_session.add( obj )
if isinstance( obj, trans.app.model.Tool ):
@@ -71,25 +72,32 @@ class UploadController( BaseController )
if replace_id:
replace_version = trans.sa_session.query( trans.app.model.Tool ).get( trans.security.decode_id( replace_id ) )
if existing and not replace_id:
- raise UploadError( 'A tool with the same ID already exists. If you are trying to update this tool to a new version, please use the upload form on the "Edit Tool" page. Otherwise, please choose a new ID.' )
+ raise UploadError( 'A %s with the same Id already exists. If you are trying to update this %s to a new version, use the upload form on the "Edit Tool" page. Otherwise, change the Id in the %s config.' % \
+ ( obj.label, obj.label, obj.label ) )
elif replace_id and not existing:
- raise UploadError( 'Tool ids must match when uploading a new version of a tool. The new tool id does not match the old tool id (%s). Check the tool XML files.' % str( replace_version.tool_id ) )
+ raise UploadError( 'The new %s id (%s) does not match the old %s id (%s). Check the %s config files.' % \
+ ( obj.label, str( meta.id ), obj.label, str( replace_version.tool_id ), obj.label ) )
elif existing and replace_id:
if replace_version.newer_version:
# If the user has picked an old version, switch to the newest version
replace_version = get_versions( replace_version )[0]
if replace_version.tool_id != meta.id:
- raise UploadError( 'Tool ids must match when uploading a new version of a tool. The new tool id (%s) does not match the old tool id (%s). Check the tool XML files.' % ( str( meta.id ), str( replace_version.tool_id ) ) )
+ raise UploadError( 'The new %s id (%s) does not match the old %s id (%s). Check the %s config files.' % \
+ ( obj.label, str( meta.id ), obj.label, str( replace_version.tool_id ), obj.label ) )
for old_version in get_versions( replace_version ):
if old_version.version == meta.version:
- raise UploadError( 'The new version (%s) matches an old version. Check your version in the tool XML file.' % str( meta.version ) )
- if old_version.is_new():
- raise UploadError( 'There is an existing version of this tool which has not yet been submitted for approval, so either <a href="%s">submit or delete it</a> before uploading a new version.' % url_for( controller='common',
- action='view_tool',
- cntrller='tool',
- id=trans.security.encode_id( old_version.id ) ) )
- if old_version.is_waiting():
- raise UploadError( 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.' )
+ raise UploadError( 'The new version (%s) matches an old version. Check your version in the %s config file.' % \
+ ( str( meta.version ), obj.label ) )
+ if old_version.is_new:
+ raise UploadError( 'There is an existing version of this %s which has not yet been submitted for approval, so either <a href="%s">submit it or delete it</a> before uploading a new version.' % \
+ ( obj.label,
+ url_for( controller='common',
+ action='view_tool',
+ cntrller='tool',
+ id=trans.security.encode_id( old_version.id ) ) ) )
+ if old_version.is_waiting:
+ raise UploadError( 'There is an existing version of this %s which is waiting for administrative approval, so contact an administrator for help.' % \
+ obj.label )
# Defer setting the id since the newer version id doesn't exist until the new Tool object is flushed
if category_ids:
for category_id in category_ids:
@@ -128,10 +136,10 @@ class UploadController( BaseController )
replace_version = trans.sa_session.query( trans.app.model.Tool ).get( int( trans.app.security.decode_id( replace_id ) ) )
old_version = None
for old_version in get_versions( replace_version ):
- if old_version.is_new():
+ if old_version.is_new:
message = 'There is an existing version of this tool which has not been submitted for approval, so either submit or delete it before uploading a new version.'
break
- if old_version.is_waiting():
+ if old_version.is_waiting:
message = 'There is an existing version of this tool which is waiting for administrative approval, so contact an administrator for help.'
break
else:
@@ -143,13 +151,23 @@ class UploadController( BaseController )
id=trans.app.security.encode_id( old_version.id ),
message=message,
status='error' ) )
- selected_upload_type = params.get( 'type', 'tool' )
selected_categories = [ trans.security.decode_id( id ) for id in category_ids ]
+ datatype_labels=trans.app.datatypes_registry.get_datatype_labels()
+ type_ids = [ tup[0] for tup in datatype_labels ]
+ upload_type_select_list = SelectField( 'upload_type',
+ refresh_on_change=True,
+ refresh_on_change_values=type_ids )
+ for type_id, type_label in datatype_labels:
+ if type_id == upload_type:
+ upload_type_select_list.add_option( type_label, type_id, selected = True )
+ else:
+ upload_type_select_list.add_option( type_label, type_id, selected = False )
return trans.fill_template( '/webapps/community/upload/upload.mako',
message=message,
status=status,
- selected_upload_type=selected_upload_type,
- upload_types=trans.app.datatypes_registry.get_datatypes_for_select_list(),
+ selected_upload_type=upload_type,
+ upload_type_select_list=upload_type_select_list,
+ datatype_labels=trans.app.datatypes_registry.get_datatype_labels(),
replace_id=replace_id,
selected_categories=selected_categories,
categories=get_categories( trans ) )
--- a/community_datatypes_conf.xml.sample
+++ b/community_datatypes_conf.xml.sample
@@ -2,8 +2,6 @@
<datatypes><registration><datatype extension="tool" type="galaxy.webapps.community.datatypes:Tool" model="galaxy.webapps.community.model:Tool"/>
+ <datatype extension="toolsuite" type="galaxy.webapps.community.datatypes:ToolSuite" model="galaxy.webapps.community.model:Tool"/></registration>
- <sniffers>
- <sniffer type="galaxy.webapps.community.datatypes:Tool"/>
- </sniffers></datatypes>
--- a/templates/webapps/community/upload/upload.mako
+++ b/templates/webapps/community/upload/upload.mako
@@ -9,16 +9,43 @@
%><%inherit file="${inherit(context)}"/>
-<%def name="title()">Upload</%def>
+<%def name="javascripts()">
+ ${parent.javascripts()}
+ <script type="text/javascript">
+ $( function() {
+ $( "select[refresh_on_change='true']").change( function() {
+ $( "#upload_form" ).submit();
+ });
+ });
+ </script>
+</%def>
-<h2>Upload</h2>
+<%def name="title()">
+ %if selected_upload_type == 'tool':
+ Upload a tool archive
+ %elif selected_upload_type == 'toolsuite':
+ Upload a tool suite archive
+ %endif
+</%def>
+
+<h2>
+ %if selected_upload_type == 'tool':
+ Upload a tool archive
+ %elif selected_upload_type == 'toolsuite':
+ Upload a tool suite archive
+ %endif
+</h2>
%if message:
${render_msg( message, status )}
%endif
<div class="toolForm">
- <div class="toolFormTitle">Upload</div>
+ %if selected_upload_type == 'tool':
+ <div class="toolFormTitle">Upload a single tool archive</div>
+ %else:
+ <div class="toolFormTitle">Upload a tool suite archive</div>
+ %endif
<div class="toolFormBody">
## TODO: nginx
<form id="upload_form" name="upload_form" action="${h.url_for( controller='upload', action='upload' )}" enctype="multipart/form-data" method="post">
@@ -28,18 +55,14 @@
<div class="form-row"><label>Upload Type</label><div class="form-row-input">
- <select name="upload_type">
- %for type_id, type_name in upload_types:
- %if type_id == selected_upload_type:
- <option value="${type_id}" selected>${type_name}</option>
- %else:
- <option value="${type_id}">${type_name}</option>
- %endif
- %endfor
- </select>
+ ${upload_type_select_list.get_html()}
</div><div class="toolParamHelp" style="clear: both;">
- Need help creating a tool file? See the <a href="${h.url_for( controller='tool', action='help' )}">Tool Help</a> page.
+ %if selected_upload_type == 'tool':
+ Need help creating a single tool archive? See details below.
+ %elif selected_upload_type == 'toolsuite':
+ Need help creating a tool suite archive? See details below.
+ %endif
</div><div style="clear: both"></div></div>
@@ -77,3 +100,151 @@
</form></div></div>
+<p/>
+<div class="toolFormTitle">Creating an archive containing a tool or a suite of tools</div>
+<p>
+ A tool or tool suite archive is a tar-format file (bzipped or gzipped tar are valid)
+ containing all the files necessary to load the tool(s) into a Galaxy instance.
+</p>
+%if selected_upload_type == 'toolsuite':
+ <h3>Tool Suite Archive</h3>
+ <p>
+ A tools suite must include a file named <code>suite_config.xml</code> which provides information about the id, name,
+ version and description of the tool suite, as well as the id, name, version and description of each tool
+ in the suite. Here is an example <code>suite_config.xml</code> file.
+ </p>
+ <p>
+<pre>
+ <suite id="lastz_toolsuite" name="Suite of Lastz tools" version="1.0.0">
+ <description>This suite contains all of my Lastz tools for Galaxy</description>
+ <tool id="lastz_wrapper_2" name="Lastz" version="1.1.0">
+ <description> map short reads against reference sequence</description>
+ </tool>
+ <tool id="lastz_paired_reads_wrapper" name="Lastz paired reads" version="1.0.0">
+ <description> map short paired reads against reference sequence</description>
+ </tool>
+ </suite>
+</pre>
+ </p>
+ </p>
+ <p>
+ New versions of the suite can be uploaded, replacing an older version of the suite, but the version attribute
+ of the <suite> tag must be altered the same way that the version attribute of a single tool config must be altered
+ if uploading a new version of a tool.
+ </p>
+ <p>
+ The id, name and version attributes of each <tool> tag in the <code>suite_config.xml</code> file must exactly match the same
+ attributes in each associated tool config in the archive or you will not be allowed to upload the archive.
+ </p>
+ <p>
+ In addition to the <code>suite_config.xml</code> file, the archive must include all
+ <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">tool config files</a>,
+ executables, functional test data (if your tool config includes functional tests) and other files needed for each
+ of the tools in your suite to function within Galaxy. See the information about single tool archives below for
+ additional hints to enable ease-of-use when others download your suite of tools.
+ </p>
+ <p>
+ For example, to package the above Lastz suite of tools:
+<pre>
+ user@host:~% tar jcvf ~/Desktop/galaxy_lastz_toolsuite.tar.bz2 lastzsuite
+ lastzsuite/
+ lastzsuite/README
+ lastzsuite/suite_config.xml
+ lastzsuite/lastz_paired_reads_wrapper.py
+ lastzsuite/lastz_paired_reads_wrapper.xml
+ lastzsuite/lastz_wrapper.py
+ lastzsuite/lastz_wrapper.xml
+ lastzsuite/lastz-distrib-1.02.00/
+ lastzsuite/lastz-distrib-1.02.00/src/
+ lastzsuite/lastz-distrib-1.02.00/src/Makefile
+ lastzsuite/lastz-distrib-1.02.00/src/version.mak
+ lastzsuite/lastz-distrib-1.02.00/src/lastz.c
+ lastzsuite/lastz-distrib-1.02.00/src/lastz.h
+ ...
+</pre>
+ ~/Desktop/galaxy_lastz_tool.tar.bz2 is now ready to be uploaded.
+ </p>
+%endif
+<h3>Single Tool Archive</h3>
+<p>
+ A single tool archive must include a
+ <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">tool config file</a>
+ and will probably also include a tool script. If any steps are necessary to install your tool beyond the basic
+ instructions below, include a README file to provide details. If the tool (or parts of it) are written in C,
+ the source code can be included (or put links to the source in the README). Do not include pre-compiled binaries
+ without source since Galaxy is run on a wide variety of platforms. Also, if you are only wrapping or providing a
+ Galaxy config for a tool that is not your own, be sure the license allows for redistribution before including any
+ part of that tool in the archive.
+</p>
+<p>
+ There are no requirements about the directory structure inside the archive, but for ease of use it's generally
+ a good idea to put everything inside a sub-directory, instead of directly at the top level.
+</p>
+<p>
+ For example, to package the Lastz tool's config file, Galaxy wrapper, and the C source:
+<pre>
+ user@host:~% tar jcvf ~/Desktop/galaxy_lastz_tool.tar.bz2 lastz
+ lastz/
+ lastz/README
+ lastz/lastz_wrapper.py
+ lastz/lastz_wrapper.xml
+ lastz/lastz-distrib-1.02.00/
+ lastz/lastz-distrib-1.02.00/src/
+ lastz/lastz-distrib-1.02.00/src/Makefile
+ lastz/lastz-distrib-1.02.00/src/version.mak
+ lastz/lastz-distrib-1.02.00/src/lastz.c
+ lastz/lastz-distrib-1.02.00/src/lastz.h
+ ...
+</pre>
+ ~/Desktop/galaxy_lastz_tool.tar.bz2 is now ready to be uploaded.
+</p>
+<h3>Editing Information, Categories, and Submitting For Approval</h3>
+<p>
+ Simply uploading a tool to the Galaxy too shed will not allow other users to find and download your tool. It will
+ need to be approved by an administrator before it appears in the tool list.
+</p>
+<p>
+ After your archive has successfully uploaded, you will be redirected to the Edit Tool page. Provide a detailed
+ description of what the tool does - this will be used by administrators to understand the tool before approving it
+ for display on the site. Once approved, this information will be displayed to users who view your tool. In addition,
+ the site administrators will have configured a number of categories with which you can associate your tool to make it
+ easy to find by users looking to solve specific problems. Associate as many categories as are relevant to your tool.
+ You may change the description and associated categories as often as you'd like until you click the "<strong>Submit for
+ approval</strong>" button. Once submitted, the tool will be approved or rejected by an administrator. If the tool is
+ rejected, you will see information about why it was rejected, and you can make appropriate changes to the archive and
+ re-submit it for approval. When it is approved, your archive will be visible to everyone. At that point, the description
+ and associated categories can only be changed by an administrator.
+</p>
+<p>
+ When the tool has been approved or rejected, you may upload a new version by browsing to the tool's "View Tool" page,
+ clicking the "Tool actions" menu in the upper right corner of the page, and selecting "Upload a new version" from the
+ menu.
+</p>
+<hr/>
+<h3>Downloading and Installing Tools</h3>
+<p>
+ A tool's download link will send you the tool archive. Once downloaded, unpack the tool on your local Galaxy instance's server:
+<pre>
+ user@host:~% tar xvf galaxy_lastz_tool.tar
+ ...
+ user@host:~% tar zxvf galaxy_lastz_tool.tar.gz
+ ...
+ user@host:~% tar jxvf galaxy_lastz_tool.tar.bz2
+ ...
+</pre>
+ If the archive includes a README file, consult it for installation instructions. If not, follow these basic steps:
+ <ol>
+ <li>Create a directory under <code>galaxy_dist/tools/</code> to house downloaded tool(s).</li>
+ <li>In the new directory, place the XML and any script file(s) which were contained in the archive.</li>
+ <li>
+ If the tool includes binaries, you'll need to copy them to a directory on your <code>$PATH</code>. If the tool depends on
+ C binaries but does not come with them (only source), you'll need to compile the source first.
+ </li>
+ <li>Add the tool to <code>galaxy_dist/tool_conf.xml</code>.</li>
+ <li>Restart your Galaxy server process.</li>
+ </ol>
+</p>
+<p>
+ In the near future, we plan to implement a more direct method to install tools via the Galaxy administrator user interface instead
+ of placing files on the filesystem and manually managing the <code>tool_conf.xml</code> file.
+</p>
--- a/templates/webapps/community/admin/index.mako
+++ b/templates/webapps/community/admin/index.mako
@@ -1,7 +1,7 @@
<%inherit file="/webapps/community/base_panels.mako"/>
## Default title
-<%def name="title()">Galaxy Community Space Administration</%def>
+<%def name="title()">Galaxy Tool Shed Administration</%def><%def name="stylesheets()">
${parent.stylesheets()}
--- a/templates/webapps/community/tool/help.mako
+++ b/templates/webapps/community/tool/help.mako
@@ -17,35 +17,87 @@
${render_msg( message, status )}
%endif
-<h3>Uploading Tools</h3>
-
-<p><strong>Tool File Format</strong></p>
+<p/>
+<div class="toolFormTitle">Creating an archive containing a tool or a suite of tools</div><p>
-
- A tool file is a tar-format (bzipped or gzipped tar are valid) archive
- containing all the files necessary to load the tool in Galaxy. At the very
- least, it must contain a
- <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">Tool XML File</a>,
- and will probably also include a tool script. If any steps are necessary
- to install your tool beyond the basic instructions below, please include a
- README file which details these steps. If the tool (or parts of it) are
- written in C, the source code can be included (or put links to the source
- in the README). Please do not include precompiled binaries without source,
- since Galaxy is run on a wide variety of platforms. Also, if you are only
- wrapping or providing a Galaxy config for a tool that is not your own,
- please be sure the license allows for redistribution before including any
- part of that tool in the tar archive!
+ A tool or tool suite archive is a tar-format file (bzipped or gzipped tar are valid)
+ containing all the files necessary to load the tool(s) into a Galaxy instance.
+</p>
+<h3>Tool Suite Archive</h3>
+<p>
+ A tools suite must include a file named <code>suite_config.xml</code> which provides information about the id, name,
+ version and description of the tool suite, as well as the id, name, version and description of each tool
+ in the suite. Here is an example <code>suite_config.xml</code> file.
</p><p>
- There are no requirements about the directory structure inside the tar
- archive, but for ease of use, it's generally a good idea to put everything
- inside of a subdirectory, instead of directly at the top level.
+<pre>
+ <suite id="lastz_toolsuite" name="Suite of Lastz tools" version="1.0.0">
+ <description>This suite contains all of my Lastz tools for Galaxy</description>
+ <tool id="lastz_wrapper_2" name="Lastz" version="1.1.0">
+ <description> map short reads against reference sequence</description>
+ </tool>
+ <tool id="lastz_paired_reads_wrapper" name="Lastz paired reads" version="1.0.0">
+ <description> map short paired reads against reference sequence</description>
+ </tool>
+ </suite>
+</pre></p>
-
-<p><strong>Tool File Example</strong></p>
+</p><p>
- To package up the LASTZ tool's config file, Galaxy wrapper, and the C source:
- <pre>
+ New versions of the suite can be uploaded, replacing an older version of the suite, but the version attribute
+ of the <suite> tag must be altered the same way that the version attribute of a single tool config must be altered
+ if uploading a new version of a tool.
+</p>
+<p>
+ The id, name and version attributes of each <tool> tag in the <code>suite_config.xml</code> file must exactly match the same
+ attributes in each associated tool config in the archive or you will not be allowed to upload the archive.
+</p>
+<p>
+ In addition to the <code>suite_config.xml</code> file, the archive must include all
+ <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">tool config files</a>,
+ executables, functional test data (if your tool config includes functional tests) and other files needed for each
+ of the tools in your suite to function within Galaxy. See the information about single tool archives below for
+ additional hints to enable ease-of-use when others download your suite of tools.
+</p>
+<p>
+ For example, to package the above Lastz suite of tools:
+<pre>
+ user@host:~% tar jcvf ~/Desktop/galaxy_lastz_toolsuite.tar.bz2 lastzsuite
+ lastzsuite/
+ lastzsuite/README
+ lastzsuite/suite_config.xml
+ lastzsuite/lastz_paired_reads_wrapper.py
+ lastzsuite/lastz_paired_reads_wrapper.xml
+ lastzsuite/lastz_wrapper.py
+ lastzsuite/lastz_wrapper.xml
+ lastzsuite/lastz-distrib-1.02.00/
+ lastzsuite/lastz-distrib-1.02.00/src/
+ lastzsuite/lastz-distrib-1.02.00/src/Makefile
+ lastzsuite/lastz-distrib-1.02.00/src/version.mak
+ lastzsuite/lastz-distrib-1.02.00/src/lastz.c
+ lastzsuite/lastz-distrib-1.02.00/src/lastz.h
+ ...
+</pre>
+ ~/Desktop/galaxy_lastz_tool.tar.bz2 is now ready to be uploaded.
+</p>
+<h3>Single Tool Archive</h3>
+<p>
+ A single tool archive must include a
+ <a href="http://bitbucket.org/galaxy/galaxy-central/wiki/ToolConfigSyntax" target="_blank">tool config file</a>
+ and will probably also include a tool script. If any steps are necessary to install your tool beyond the basic
+ instructions below, include a README file to provide details. If the tool (or parts of it) are written in C,
+ the source code can be included (or put links to the source in the README). Do not include pre-compiled binaries
+ without source since Galaxy is run on a wide variety of platforms. Also, if you are only wrapping or providing a
+ Galaxy config for a tool that is not your own, be sure the license allows for redistribution before including any
+ part of that tool in the archive.
+</p>
+<p>
+ There are no requirements about the directory structure inside the archive, but for ease of use it's generally
+ a good idea to put everything inside a sub-directory, instead of directly at the top level.
+</p>
+<p>
+ For example, to package the Lastz tool's config file, Galaxy wrapper, and the C source:
+<pre>
user@host:~% tar jcvf ~/Desktop/galaxy_lastz_tool.tar.bz2 lastz
lastz/
lastz/README
@@ -58,68 +110,57 @@
lastz/lastz-distrib-1.02.00/src/lastz.c
lastz/lastz-distrib-1.02.00/src/lastz.h
...
- </pre>
- <code>~/Desktop/galaxy_lastz_tool.tar.bz2</code> is now ready to be uploaded.
+</pre>
+ ~/Desktop/galaxy_lastz_tool.tar.bz2 is now ready to be uploaded.
+</p>
+<h3>Editing Information, Categories, and Submitting For Approval</h3>
+<p>
+ Simply uploading a tool to the Galaxy too shed will not allow other users to find and download your tool. It will
+ need to be approved by an administrator before it appears in the tool list.
+</p>
+<p>
+ After your archive has successfully uploaded, you will be redirected to the Edit Tool page. Provide a detailed
+ description of what the tool does - this will be used by administrators to understand the tool before approving it
+ for display on the site. Once approved, this information will be displayed to users who view your tool. In addition,
+ the site administrators will have configured a number of categories with which you can associate your tool to make it
+ easy to find by users looking to solve specific problems. Associate as many categories as are relevant to your tool.
+ You may change the description and associated categories as often as you'd like until you click the "<strong>Submit for
+ approval</strong>" button. Once submitted, the tool will be approved or rejected by an administrator. If the tool is
+ rejected, you will see information about why it was rejected, and you can make appropriate changes to the archive and
+ re-submit it for approval. When it is approved, your archive will be visible to everyone. At that point, the description
+ and associated categories can only be changed by an administrator.
+</p>
+<p>
+ When the tool has been approved or rejected, you may upload a new version by browsing to the tool's "View Tool" page,
+ clicking the "Tool actions" menu in the upper right corner of the page, and selecting "Upload a new version" from the
+ menu.
+</p>
+<hr/>
+<h3>Downloading and Installing Tools</h3>
+<p>
+ A tool's download link will send you the tool archive. Once downloaded, unpack the tool on your local Galaxy instance's server:
+<pre>
+ user@host:~% tar xvf galaxy_lastz_tool.tar
+ ...
+ user@host:~% tar zxvf galaxy_lastz_tool.tar.gz
+ ...
+ user@host:~% tar jxvf galaxy_lastz_tool.tar.bz2
+ ...
+</pre>
+ If the archive includes a README file, consult it for installation instructions. If not, follow these basic steps:
+ <ol>
+ <li>Create a directory under <code>galaxy_dist/tools/</code> to house downloaded tool(s).</li>
+ <li>In the new directory, place the XML and any script file(s) which were contained in the archive.</li>
+ <li>
+ If the tool includes binaries, you'll need to copy them to a directory on your <code>$PATH</code>. If the tool depends on
+ C binaries but does not come with them (only source), you'll need to compile the source first.
+ </li>
+ <li>Add the tool to <code>galaxy_dist/tool_conf.xml</code>.</li>
+ <li>Restart your Galaxy server process.</li>
+ </ol>
+</p>
+<p>
+ In the near future, we plan to implement a more direct method to install tools via the Galaxy administrator user interface instead
+ of placing files on the filesystem and manually managing the <code>tool_conf.xml</code> file.
</p>
-<p><strong>Editing Information, Categories, and Submitting For Approval</strong></p>
-
-<p>
- Simply uploading a tool to the Community will not allow other users to find
- and download your tool. It will need to be approved by an administrator
- before it appears in the tool list.
-</p>
-<p>
- After the tool has successfully uploaded, you will be redirected to the
- Edit Tool page. Please provide a detailed description of what the tool
- does - this will be used by administrators to understand the tool before
- approving it for display on the site. Once approved, this information will
- be displayed to users who view your tool. In addition, the site
- administrators will have configured a number of categories with which you
- can associate your tool to make it easily findable by users looking to
- solve specific problems. Please associate as many categories as are
- relevant to your tool. You may change the description and associated
- categories as often as you'd like until you click the "<strong>Submit for
- approval</strong>" button. Once submitted, the tool will be approved or
- rejected by an administrator. Once approved, it will be visible to
- everyone. At that point, the description and associated categories can
- only be changed by an administrator.
-</p>
-<p>
- Once the tool has been approved or rejected, you may upload a new version
- by browsing to the tool's "View Tool" page, clicking the context menu to
- the right of the tool's name, and selecting "Upload a new version."
-</p>
-
-<hr/>
-
-<h3>Downloading and Installing Tools</h3>
-
-<p>
- A tool's download link will send you the tool tar archive. Once
- downloaded, unpack the tool on your local Galaxy instance's server:
- <pre>
- user@host:~% tar xvf galaxy_tool.tar
- ...
- user@host:~% tar zxvf galaxy_tool.tar.gz
- ...
- user@host:~% tar jxvf galaxy_tool.tar.bz2
- ...
- </pre>
- If the tar archive includes a README file, consult it for installation
- instructions. If not, follow these basic steps:
- <ol>
- <li>Create a directory under <code>galaxy_dist/tools/</code> to house downloaded tool(s).</li>
- <li>In the new directory, place the XML and any script file(s) which were contained in the tar archive.</li>
- <li>If the tool includes binaries, you'll need to copy them to a directory on your <code>$PATH</code>. If the tool depends on C binaries but does not come with them (only source), you'll need to compile the source first.</li>
- <li>Add the tool to <code>galaxy_dist/tool_conf.xml</code>.</li>
- <li>Restart the Galaxy server process.</li>
- </ol>
-</p>
-
-<p>
- We plan to implement a more direct method to install tools via the Galaxy
- administrator user interface instead of placing files on the filesystem and
- managing the <code>tool_conf.xml</code> file by hand. In the meantime,
- this is the process.
-</p>
--- a/lib/galaxy/webapps/community/model/__init__.py
+++ b/lib/galaxy/webapps/community/model/__init__.py
@@ -1,5 +1,5 @@
"""
-Galaxy Community Space data model classes
+Galaxy Tool Shed data model classes
Naming: try to use class names that have a distinct plural form so that
the relationship cardinalities are obvious (e.g. prefer Dataset to Data)
@@ -95,7 +95,7 @@ class Tool( object ):
REJECTED = 'rejected',
ARCHIVED = 'archived' )
def __init__( self, guid=None, tool_id=None, name=None, description=None, user_description=None,
- category=None, version=None, user_id=None, external_filename=None ):
+ category=None, version=None, user_id=None, external_filename=None, suite=False ):
self.guid = guid
self.tool_id = tool_id
self.name = name or "Unnamed tool"
@@ -106,6 +106,7 @@ class Tool( object ):
self.external_filename = external_filename
self.deleted = False
self.__extension = None
+ self.suite = suite
def get_file_name( self ):
if not self.external_filename:
assert self.id is not None, "ID must be set before filename used (commit the object)"
@@ -133,6 +134,8 @@ class Tool( object ):
self.description = datatype_bunch.description
self.version = datatype_bunch.version
self.user_id = datatype_bunch.user.id
+ self.suite = datatype_bunch.suite
+ @property
def state( self ):
if self.events:
# Sort the events in ascending order by update_time
@@ -150,35 +153,47 @@ class Tool( object ):
else:
return ''
return 'No comment'
+ # Tool states
+ @property
def is_new( self ):
- return self.state() == self.states.NEW
+ return self.state == self.states.NEW
+ @property
def is_error( self ):
- return self.state() == self.states.ERROR
+ return self.state == self.states.ERROR
+ @property
def is_deleted( self ):
- return self.state() == self.states.DELETED
+ return self.state == self.states.DELETED
+ @property
def is_waiting( self ):
- return self.state() == self.states.WAITING
+ return self.state == self.states.WAITING
+ @property
def is_approved( self ):
- return self.state() == self.states.APPROVED
+ return self.state == self.states.APPROVED
+ @property
def is_rejected( self ):
- return self.state() == self.states.REJECTED
+ return self.state == self.states.REJECTED
+ @property
def is_archived( self ):
- return self.state() == self.states.ARCHIVED
+ return self.state == self.states.ARCHIVED
def get_state_message( self ):
- if self.is_new():
- return '<font color="red"><b><i>This is an unsubmitted version of this tool</i></b></font>'
- if self.is_error():
- return '<font color="red"><b><i>This tool is in an error state</i></b></font>'
- if self.is_deleted():
- return '<font color="red"><b><i>This is a deleted version of this tool</i></b></font>'
- if self.is_waiting():
- return '<font color="red"><b><i>This version of this tool is awaiting administrative approval</i></b></font>'
- if self.is_approved():
- return '<b><i>This is the latest approved version of this tool</i></b>'
- if self.is_rejected():
- return '<font color="red"><b><i>This version of this tool has been rejected by an administrator</i></b></font>'
- if self.is_archived():
- return '<font color="red"><b><i>This is an archived version of this tool</i></b></font>'
+ if self.is_suite:
+ label = 'tool suite'
+ else:
+ label = 'tool'
+ if self.is_new:
+ return '<font color="red"><b><i>This is an unsubmitted version of this %s</i></b></font>' % label
+ if self.is_error:
+ return '<font color="red"><b><i>This %s is in an error state</i></b></font>' % label
+ if self.is_deleted:
+ return '<font color="red"><b><i>This is a deleted version of this %s</i></b></font>' % label
+ if self.is_waiting:
+ return '<font color="red"><b><i>This version of this %s is awaiting administrative approval</i></b></font>' % label
+ if self.is_approved:
+ return '<b><i>This is the latest approved version of this %s</i></b>' % label
+ if self.is_rejected:
+ return '<font color="red"><b><i>This version of this %s has been rejected by an administrator</i></b></font>' % label
+ if self.is_archived:
+ return '<font color="red"><b><i>This is an archived version of this %s</i></b></font>' % label
@property
def extension( self ):
# if instantiated via a query, this unmapped property won't exist
@@ -202,6 +217,15 @@ class Tool( object ):
self.__extension = 'tar'
return self.__extension
@property
+ def is_suite( self ):
+ return self.suite
+ @property
+ def label( self ):
+ if self.is_suite:
+ return 'tool suite'
+ else:
+ return 'tool'
+ @property
def download_file_name( self ):
return '%s_%s.%s' % ( self.tool_id, self.version, self.extension )
@property
--- a/templates/webapps/community/base_panels.mako
+++ b/templates/webapps/community/base_panels.mako
@@ -1,7 +1,7 @@
<%inherit file="/base_panels.mako"/>
## Default title
-<%def name="title()">Galaxy Community Space</%def>
+<%def name="title()">Galaxy Tool Shed</%def>
## Masthead
<%def name="masthead()">
@@ -94,7 +94,7 @@
<div class="title" style="position: absolute; top: 0; left: 0;"><a href="${app.config.get( 'logo_url', '/' )}"><img border="0" src="${h.url_for('/static/images/galaxyIcon_noText.png')}" style="width: 26px; vertical-align: top;">
- Galaxy Community
+ Galaxy Tool Shed
%if app.config.brand:
<span class='brand'>/ ${app.config.brand}</span>
%endif
--- a/lib/galaxy/webapps/community/model/mapping.py
+++ b/lib/galaxy/webapps/community/model/mapping.py
@@ -113,7 +113,8 @@ Tool.table = Table( "tool", metadata,
Column( "version", TrimmedString( 255 ) ),
Column( "user_id", Integer, ForeignKey( "galaxy_user.id" ), index=True ),
Column( "external_filename" , TEXT ),
- Column( "deleted", Boolean, index=True, default=False ) )
+ Column( "deleted", Boolean, index=True, default=False ),
+ Column( "suite", Boolean, default=False, index=True ) )
Category.table = Table( "category", metadata,
Column( "id", Integer, primary_key=True ),
--- a/lib/galaxy/webapps/community/controllers/tool.py
+++ b/lib/galaxy/webapps/community/controllers/tool.py
@@ -15,7 +15,7 @@ class ApprovedToolListGrid( ToolListGrid
class MyToolsListGrid( ToolListGrid ):
class StateColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- state = tool.state()
+ state = tool.state
if state == 'approved':
state_color = 'ok'
elif state == 'rejected':
@@ -64,7 +64,7 @@ class ToolCategoryListGrid( CategoryList
viewable_tools = 0
for tca in category.tools:
tool = tca.tool
- if tool.is_approved():
+ if tool.is_approved:
viewable_tools += 1
return viewable_tools
return 0
--- a/lib/galaxy/webapps/community/datatypes/__init__.py
+++ b/lib/galaxy/webapps/community/datatypes/__init__.py
@@ -17,7 +17,6 @@ class DatatypeVerificationError( Excepti
class Registry( object ):
def __init__( self, root_dir=None, config=None ):
self.datatypes_by_extension = {}
- self.sniff_order = []
if root_dir and config:
# Parse datatypes_conf.xml
tree = galaxy.util.parse_xml( config )
@@ -50,98 +49,143 @@ class Registry( object ):
log.debug( 'Added model class: %s to datatype: %s' % ( model_class, dtype ) )
except Exception, e:
log.warning( 'Error loading datatype "%s", problem: %s' % ( extension, str( e ) ) )
- # Load datatype sniffers from the config
- sniff_order = []
- sniffers = root.find( 'sniffers' )
- for elem in sniffers.findall( 'sniffer' ):
- dtype = elem.get( 'type', None )
- if dtype:
- sniff_order.append( dtype )
- for dtype in sniff_order:
- try:
- fields = dtype.split( ":" )
- datatype_module = fields[0]
- datatype_class = fields[1]
- fields = datatype_module.split( "." )
- module = __import__( fields.pop(0) )
- for mod in fields:
- module = getattr( module, mod )
- aclass = getattr( module, datatype_class )()
- included = False
- for atype in self.sniff_order:
- if not issubclass( atype.__class__, aclass.__class__ ) and isinstance( atype, aclass.__class__ ):
- included = True
- break
- if not included:
- self.sniff_order.append( aclass )
- log.debug( 'Loaded sniffer for datatype: %s' % dtype )
- except Exception, exc:
- log.warning( 'Error appending datatype %s to sniff_order, problem: %s' % ( dtype, str( exc ) ) )
def get_datatype_by_extension( self, ext ):
return self.datatypes_by_extension.get( ext, None )
- def get_datatypes_for_select_list( self ):
+ def get_datatype_labels( self ):
rval = []
for ext, datatype in self.datatypes_by_extension.items():
- rval.append( ( ext, datatype.select_name ) )
+ rval.append( ( ext, datatype.label ) )
return rval
- def sniff( self, fname ):
- for datatype in sniff_order:
- try:
- datatype.sniff( fname )
- return datatype.file_ext
- except:
- pass
class Tool( object ):
- select_name = 'Tool'
def __init__( self, model_object=None ):
self.model_object = model_object
- def verify( self, file ):
- msg = ''
+ self.label = 'Tool'
+ def verify( self, f, xml_files=[], tool_tags={} ):
+ # xml_files and tool_tags will only be received if we're called from the ToolSuite.verify() method.
try:
- tar = tarfile.open( file.name )
+ tar = tarfile.open( f.name )
except tarfile.ReadError:
- raise DatatypeVerificationError( 'The tool file is not a readable tar file' )
- xml_names = filter( lambda x: x.lower().endswith( '.xml' ), tar.getnames() )
- if not xml_names:
- raise DatatypeVerificationError( 'The tool file does not contain an XML file' )
- for xml_name in xml_names:
+ raise DatatypeVerificationError( 'The archive is not a readable tar file.' )
+ if not xml_files:
+ # Make sure we're not uploading a tool suite
+ if filter( lambda x: x.lower() == 'tool_suite.xml', tar.getnames() ):
+ raise DatatypeVerificationError( 'The archive includes a tool_suite.xml file, so set the upload type to "Tool Suite".' )
+ xml_files = filter( lambda x: x.lower().endswith( '.xml' ), tar.getnames() )
+ if not xml_files:
+ raise DatatypeVerificationError( 'The archive does not contain any xml config files.' )
+ for xml_file in xml_files:
try:
- tree = ElementTree.parse( tar.extractfile( xml_name ) )
+ tree = ElementTree.parse( tar.extractfile( xml_file ) )
root = tree.getroot()
except:
log.exception( 'fail:' )
continue
if root.tag == 'tool':
- rval = Bunch()
- try:
- rval.id = root.attrib['id']
- rval.name = root.attrib['name']
- rval.version = root.attrib['version']
- except KeyError, e:
- raise DatatypeVerificationError( 'Tool XML file does not conform to the specification. Missing required <tool> tag attribute: %s' % e )
- rval.description = ''
- desc_tag = root.find( 'description' )
- if desc_tag is not None:
- description = desc_tag.text
- if description:
- rval.description = description.strip()
- rval.message = 'Tool: %s %s, Version: %s, ID: %s' % ( str( rval.name ), str( rval.description ), str( rval.version ), str( rval.id ) )
- return rval
- else:
- raise DatatypeVerificationError( 'Unable to find a properly formatted tool XML file' )
+ if tool_tags:
+ # We are verifying the tools inside a tool suite, so the current tag should have been found in the suite_config.xml
+ # file parsed in the ToolSuite verify() method. The tool_tags dictionary should include a key matching the current
+ # tool Id, and a tuple value matching the tool name and version.
+ if root.attrib[ 'id' ] not in tool_tags:
+ raise DatatypeVerificationError( 'Tool Id (%s) is not included in the suite_config.xml file.' % \
+ ( str( root.attrib[ 'id' ] ) ) )
+ tup = tool_tags[ root.attrib[ 'id' ] ]
+ if root.attrib[ 'name' ] != tup[ 0 ]:
+ raise DatatypeVerificationError( 'Tool name (%s) differs between suite_config.xml and the tool config file for tool Id (%s).' % \
+ ( str( root.attrib[ 'name' ] ), str( root.attrib[ 'id' ] ) ) )
+ if root.attrib[ 'version' ] != tup[ 1 ]:
+ raise DatatypeVerificationError( 'Tool version (%s) differs between suite_config.xml and the tool config file for tool Id (%s).' % \
+ ( str( root.attrib[ 'version' ] ), str( root.attrib[ 'id' ] ) ) )
+ else:
+ # We are not verifying a tool suite, so we'll create a bunch for returning to the caller.
+ tool_bunch = Bunch()
+ try:
+ tool_bunch.id = root.attrib['id']
+ tool_bunch.name = root.attrib['name']
+ tool_bunch.version = root.attrib['version']
+ except KeyError, e:
+ raise DatatypeVerificationError( 'Tool XML file does not conform to the specification. Missing required <tool> tag attribute: %s' % str( e ) )
+ tool_bunch.description = ''
+ desc_tag = root.find( 'description' )
+ if desc_tag is not None:
+ description = desc_tag.text
+ if description:
+ tool_bunch.description = description.strip()
+ tool_bunch.message = 'Tool: %s %s, Version: %s, Id: %s' % \
+ ( str( tool_bunch.name ), str( tool_bunch.description ), str( tool_bunch.version ), str( tool_bunch.id ) )
+ return tool_bunch
+ else:
+ # TODO: should we verify files that are not tool configs?
+ log.debug( "The file named (%s) is not a tool config, so skipping verification." % str( xml_file ) )
def create_model_object( self, datatype_bunch ):
if self.model_object is None:
- raise Exception( 'No model object configured for %s, please check the datatype configuration file' % self.__class__.__name__ )
+ raise Exception( 'No model object configured for %s, check the datatype configuration file' % self.__class__.__name__ )
if datatype_bunch is None:
# TODO: do it automatically
raise Exception( 'Unable to create %s model object without passing in data' % self.__class__.__name__ )
o = self.model_object()
o.create_from_datatype( datatype_bunch )
return o
- def sniff( self, fname ):
+
+class ToolSuite( Tool ):
+ def __init__( self, model_object=None ):
+ self.model_object = model_object
+ self.label = 'Tool Suite'
+ def verify( self, f ):
+ """
+ A sample tool suite config:
+ <suite id="onto_toolkit" name="ONTO Toolkit" version="1.0">
+ <description>ONTO-Toolkit is a collection of Galaxy tools which support the manipulation of bio-ontologies.</description>
+ <tool id="get_ancestor_terms" name="Get the ancestor terms of a given OBO term" version="1.0.0">
+ <description>Collects the ancestor terms from a given term in the given OBO ontology</description>
+ </tool>
+ <tool id="get_child_terms" name="Get the child terms of a given OBO term" version="1.0.0">
+ <description>Collects the child terms from a given term in the given OBO ontology</description>
+ </tool>
+ </suite>
+ """
try:
- self.verify( open( fname, 'r' ) )
- return True
+ tar = tarfile.open( f.name )
+ except tarfile.ReadError:
+ raise DatatypeVerificationError( 'The archive is not a readable tar file.' )
+ suite_config = filter( lambda x: x.lower() == 'tool_suite.xml', tar.getnames() )
+ if not suite_config:
+ raise DatatypeVerificationError( 'The archive does not contain the required tool_suite.xml config file. If you are uploading a single tool archive, set the upload type to "Tool".' )
+ suite_config = suite_config[ 0 ]
+ # Parse and verify suite_config
+ archive_ok = False
+ try:
+ tree = ElementTree.parse( tar.extractfile( suite_config ) )
+ root = tree.getroot()
+ archive_ok = True
except:
- return False
+ log.exception( 'fail:' )
+ if archive_ok and root.tag == 'suite':
+ suite_bunch = Bunch()
+ try:
+ suite_bunch.id = root.attrib['id']
+ suite_bunch.name = root.attrib['name']
+ suite_bunch.version = root.attrib['version']
+ except KeyError, e:
+ raise DatatypeVerificationError( 'The file named tool-suite.xml does not conform to the specification. Missing required <suite> tag attribute: %s' % str( e ) )
+ suite_bunch.description = ''
+ desc_tag = root.find( 'description' )
+ if desc_tag is not None:
+ description = desc_tag.text
+ if description:
+ suite_bunch.description = description.strip()
+ suite_bunch.message = 'Tool suite: %s %s, Version: %s, Id: %s' % \
+ ( str( suite_bunch.name ), str( suite_bunch.description ), str( suite_bunch.version ), str( suite_bunch.id ) )
+ # Create a dictionary of the tools in the suite where the keys are tool_ids and the
+ # values are tuples of tool name and version
+ tool_tags = {}
+ for elem in root.findall( 'tool' ):
+ tool_tags[ elem.attrib['id'] ] = ( elem.attrib['name'], elem.attrib['version'] )
+ else:
+ raise DatatypeVerificationError( "The file named %s is not a valid tool suite config." % str( suite_config ) )
+ # Verify all included tool config files
+ xml_files = filter( lambda x: x.lower().endswith( '.xml' ) and x.lower() != 'tool_suite.xml', tar.getnames() )
+ if not xml_files:
+ raise DatatypeVerificationError( 'The archive does not contain any tool config (xml) files.' )
+ Tool.verify( self, f, xml_files=xml_files, tool_tags=tool_tags )
+ return suite_bunch
--- a/lib/galaxy/webapps/community/controllers/admin.py
+++ b/lib/galaxy/webapps/community/controllers/admin.py
@@ -299,7 +299,7 @@ class GroupListGrid( grids.Grid ):
class AdminToolListGrid( ToolListGrid ):
class StateColumn( grids.TextColumn ):
def get_value( self, trans, grid, tool ):
- state = tool.state()
+ state = tool.state
if state == 'approved':
state_color = 'ok'
elif state == 'rejected':
@@ -441,7 +441,7 @@ class AdminController( BaseController, A
# Called from the ToolStateColumn link
tool_id = kwd.get( 'id', None )
tool = get_tool( trans, tool_id )
- kwd[ 'f-state' ] = tool.state()
+ kwd[ 'f-state' ] = tool.state
elif operation == "tools_by_category":
# Eliminate the current filters if any exist.
for k, v in kwd.items():
@@ -547,7 +547,7 @@ class AdminController( BaseController, A
# If we're approving a tool, all previously approved versions must be set to archived
for version in get_versions( tool ):
# TODO: get latest approved version instead of all versions
- if version != tool and version.is_approved():
+ if version != tool and version.is_approved:
# Create an event with state ARCHIVED for the previously approved version of this tool
self.__create_tool_event( trans,
version,
@@ -799,30 +799,30 @@ def get_tools_by_state( trans, state ):
ids = []
if state == trans.model.Tool.states.NEW:
for tool in get_tools( trans ):
- if tool.is_new():
+ if tool.is_new:
ids.append( tool.id )
elif state == trans.model.Tool.states.ERROR:
for tool in get_tools( trans ):
- if tool.is_error():
+ if tool.is_error:
ids.append( tool.id )
elif state == trans.model.Tool.states.DELETED:
for tool in get_tools( trans ):
- if tool.is_deleted():
+ if tool.is_deleted:
ids.append( tool.id )
elif state == trans.model.Tool.states.WAITING:
for tool in get_tools( trans ):
- if tool.is_waiting():
+ if tool.is_waiting:
ids.append( tool.id )
elif state == trans.model.Tool.states.APPROVED:
for tool in get_tools( trans ):
- if tool.is_approved():
+ if tool.is_approved:
ids.append( tool.id )
elif state == trans.model.Tool.states.REJECTED:
for tool in get_tools( trans ):
- if tool.is_rejected():
+ if tool.is_rejected:
ids.append( tool.id )
elif state == trans.model.Tool.states.ARCHIVED:
for tool in get_tools( trans ):
- if tool.is_archived():
+ if tool.is_archived:
ids.append( tool.id )
return ids
1
0
galaxy-dist commit 1acae496c220: Added sam_indel_filter tool test files
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kelly Vincent <kpvincent(a)bx.psu.edu>
# Date 1279744462 14400
# Node ID 1acae496c2200747aa79e7ac52cce74f5a3a3c83
# Parent 1dc82a345db24860b31b73624030fa2644c18d38
Added sam_indel_filter tool test files
--- a/test-data/sam_indel_filter_in2.sam
+++ b/test-data/sam_indel_filter_in2.sam
@@ -1,12 +1,16 @@
-081017-and-081020:1:6:774:1836 0 PHIX174 4973 37 26M1I9M * 0 0 GCTTAAAGCTACCAGTTATATGGCTGTTTGGTTTTT IIIIIIIIIIIIIIIIIIIIII@III/IE;%II;I= XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:33C1
-081017-and-081020:1:6:1193:793 0 PHIX174 4971 37 27M1I8M * 0 0 CCGCTTAAAGCTACCAGTTATATGGCTGGTTGTTTT IIIIIIIIIIIIIII7IIIDIIIIIIII,=(>%II? XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
+081017-and-081020:1:6:774:1836 0 PHIX174 4973 37 26M1I9M * 0 0 GCTTAAAGCTACCAGTTATATGGCTGTTTGGTTTTT IIIIIIIIIIIIIIIIIIIIII@IIIDIE;%II;I= XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:33C1
+081017-and-081020:1:6:1193:793 0 PHIX174 4971 37 27M1I8M * 0 0 CCGCTTAAAGCTACCAGTTATATGGCTGGTTGTTTT IIIIIIIIIIIIIII7IIIDIIIIIIII&=(>%II? XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
081017-and-081020:1:8:753:970 0 PHIX174 2974 37 29M1I6M * 0 0 GTGGCGCCATGTCTAAATTGTTTGGAGGCGGGTCAA IIIIIIIIIIIIIIII4IIIIII3I&IIIII*%%&' XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:35
-081017-and-081020:1:17:361:871 0 PHIX174 4739 37 30M1I5M * 0 0 TGAGTATGGTACAGCTAATGGCCGTCTTTATTTTCC IIIIIIIIIIIIIIIIIIIGIIIII%II&'III%/# XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:28C6
-081017-and-081020:1:18:1164:1678 0 PHIX174 4971 37 27M1I8M * 0 0 CCGCTTAAAGCTACCAGTTATATGGCTGGTTGTTTT IIIIIIIIIIIIIIIIIIIII;IIII1I0I)II.I- XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
-081017-and-081020:1:20:754:1256 16 PHIX174 4772 37 4M1I31M * 0 0 CCCTGGCGGTGCATTTTATGCGGACACTTCCTACAG &II(IIIII3IIIII7II,IIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:2A32
-081017-and-081020:1:24:1326:917 0 PHIX174 188 37 25M1D11M * 0 0 TTCGCCATCAACTAACGATTCTGTCAAACCTGACGC IIIIIIIIIIIIIIIIIIIIIIIIII2/&II>'IEI XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:25^A3A7
-081017-and-081020:1:25:1466:511 16 PHIX174 1179 37 21M1D15M * 0 0 CTATTGACTCTACTGTAGACATTTTACTTTTTATGT :I<=IIIIII5IIGI5IIIIIIIIIIIIIIIIIIII XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:21^T15
-081017-and-081020:1:27:1267:1275 0 PHIX174 3716 37 28M1D8M * 0 0 TCATCAGCAAACGCAGAATCAGCGGTATGCTCTTCT IIIIIIIIIIIIIIIII;IIIIIII87III%I(@I. XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:28^G8
-081017-and-081020:1:94:1649:147 16 PHIX174 2755 37 15M2D21M * 0 0 TATACCGTCAAGGACTGTGACTATTGACGTCCTTCC 4IIIIII@I7IIIIIIIIIIIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:2 MD:Z:15^TG21
-081017-and-081020:1:95:74:43 0 PHIX174 4038 37 29M1I6M * 0 0 ATCGAGGCTCTTAAACCTGCTATTGAGGCTTTTTGG IIIIIIIIIIIIIIIIICI;8I,I>IIIIII1I%5& XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
+081017-and-081020:1:11:761:901 4 * 0 0 * * 0 0 GACCTGTGATCCATCGTGATGT CBBAB/$3BB<AB/,CBCABCA
+081017-and-081020:1:17:361:871 0 PHIX174 4739 37 30M1I5M * 0 0 TGAGTATGGTACAGCTAATGGCCGTCTTTATTTTCC IIIIIIIIIIIIIIIIIIIGIIIII%II&I'II%/# XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:28C6
+081017-and-081020:1:18:1164:1678 0 PHIX174 4971 37 27M1I8M * 0 0 CCGCTTAAAGCTACCAGTTATATGGCTGGTTGTTTT IIIIIIIIIIIIIIIIIIIII;IIII1#I)II.I-I XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
+081017-and-081020:1:20:754:1256 16 PHIX174 4772 37 4M1I31M * 0 0 CCCTGGCGGTGCATTTTATGCGGACACTTCCTACAG &IIII(III3IIIII7II,IIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:2A32
+081017-and-081020:1:24:1326:917 0 PHIX174 188 37 25M1D11M * 0 0 TTCGCCATCAACTAACGATTCTGTCAAACCTGACGC IIIIIIIIIIIIIIIIIIIIIIIIIIA/&II>'IEI XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:25^A3A7
+081017-and-081020:1:24:1567:1780 0 PHIX174 3716 37 28M1D8M * 0 0 TCATCAGCAAACGCAGAATCAGCGGTATGCTCTTCT IIIIIIIIIIIIIIIII;IIIIIII87IFII%I(@I. XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:28^G8
+081017-and-081020:1:25:1466:511 16 PHIX174 1179 37 21M1D15M * 0 0 CTATTGACTCTACTGTAGACATTTTACTTTTTATGT :I<=IIIIII5IIGI5IIIIAIIIIIIIIIIIIIII XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:21^T15
+081017-and-081020:1:27:1267:1275 0 PHIX174 3716 37 28M1D8M * 0 0 TCATCAGCAAACGCAGAATCAGCGGTATGCTCTTCT IIIIIIIIIIIIIIIII;IIIIIII87!II%I(@I. XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:28^G8
+081017-and-081020:1:56:7924:8122 4 * 0 0 * * 0 0 GACCTGTGATCCATCGTGATGT CBBAB/$3BB<AB/,CBCABCA
+081017-and-081020:1:94:1649:147 16 PHIX174 2755 37 15M2D21M * 0 0 TATACCGTCAAGGACTGTGACTATTGACGTCCTTCC 4IIIIII@I7IIIIDEIIIIIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:2 MD:Z:15^TG21
+081017-and-081020:1:95:74:43 0 PHIX174 4038 37 29M3I4M * 0 0 ATCGAGGCTCTTAAACCTGCTATTGAGGCCCTTTTT IIIIIIIIIIIIIIIIICI;8I,I>II#####I1I% XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
+081017-and-081020:1:95:182:353 4 * 0 0 * * 0 0 GACCTGTGATCCATCGTGATGT CBBAB/$3BB<AB/,CBCABCA
081017-and-081020:1:95:58:307 16 PHIX174 3859 37 2M1I33M * 0 0 ACAAATGTCTGGAAAGACGGTAAAGCTGATGGTATT I&*IIIIIIII;IIIBIII>IICIIIIIIFII:III XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:5T29
--- a/test-data/sam_indel_filter_out1.sam
+++ b/test-data/sam_indel_filter_out1.sam
@@ -1,3 +1,4 @@
-1378_28_770 89 chr11.nib:1-134452384 72131356 37 17M1I5M = 72131356 0 CACACTGTGACAGACAGCGCAGC 00/02!!0//1200210AA44/1 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
-1378_69_800 16 chr11.nib:1-125234658 241 255 15M1D8M * 0 0 CGTGGCCGGCGGGCCGAAGGCAT IIIIIIIIIICCCCIII?IIIII
-1378_72_1612 151 chrY.nib:1-124295114 190342418 37 19M1I3M = 190342418 0 TCTAACTTAGCCTCATAATAGCT /<<!"0/4//7//00/BC0121/ XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_28_770 89 chr11.nib:1-134452384 72131356 37 16M1I5M = 72131356 0 CACACTGTGACAGACAGCGCAGC 00/02!!0//1200210AA44/1 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_56_324 153 chr2.nib:1-242951149 80324999 37 7M1I14M = 80324999 0 TTTAGCCCGAAATGCCTAGAGCA 4;?AA@@IE@GGI0110////00 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_69_800 16 chr11.nib:1-125234658 241 255 14M1D8M * 0 0 CGTGGCCGGCGGGCCGAAGGCAT IIIIIIIIIICCCCIII?!IIII
+1378_72_1612 151 chrY.nib:1-124295114 190342418 37 18M1I3M = 190342418 0 TCTAACTTAGCCTCATAATAGCT /<<!"0/4//7//@@?BCIIIII XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
--- a/test-data/sam_indel_filter_out3.sam
+++ b/test-data/sam_indel_filter_out3.sam
@@ -1,10 +1,7 @@
-081017-and-081020:1:6:774:1836 0 PHIX174 4973 37 26M1I9M * 0 0 GCTTAAAGCTACCAGTTATATGGCTGTTTGGTTTTT IIIIIIIIIIIIIIIIIIIIII@III/IE;%II;I= XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:33C1
-081017-and-081020:1:6:1193:793 0 PHIX174 4971 37 27M1I8M * 0 0 CCGCTTAAAGCTACCAGTTATATGGCTGGTTGTTTT IIIIIIIIIIIIIII7IIIDIIIIIIII,=(>%II? XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
+081017-and-081020:1:6:774:1836 0 PHIX174 4973 37 26M1I9M * 0 0 GCTTAAAGCTACCAGTTATATGGCTGTTTGGTTTTT IIIIIIIIIIIIIIIIIIIIII@IIIDIE;%II;I= XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:33C1
081017-and-081020:1:8:753:970 0 PHIX174 2974 37 29M1I6M * 0 0 GTGGCGCCATGTCTAAATTGTTTGGAGGCGGGTCAA IIIIIIIIIIIIIIII4IIIIII3I&IIIII*%%&' XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:35
-081017-and-081020:1:18:1164:1678 0 PHIX174 4971 37 27M1I8M * 0 0 CCGCTTAAAGCTACCAGTTATATGGCTGGTTGTTTT IIIIIIIIIIIIIIIIIIIII;IIII1I0I)II.I- XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
-081017-and-081020:1:20:754:1256 16 PHIX174 4772 37 4M1I31M * 0 0 CCCTGGCGGTGCATTTTATGCGGACACTTCCTACAG &II(IIIII3IIIII7II,IIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:2A32
-081017-and-081020:1:24:1326:917 0 PHIX174 188 37 25M1D11M * 0 0 TTCGCCATCAACTAACGATTCTGTCAAACCTGACGC IIIIIIIIIIIIIIIIIIIIIIIIII2/&II>'IEI XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:25^A3A7
-081017-and-081020:1:25:1466:511 16 PHIX174 1179 37 21M1D15M * 0 0 CTATTGACTCTACTGTAGACATTTTACTTTTTATGT :I<=IIIIII5IIGI5IIIIIIIIIIIIIIIIIIII XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:21^T15
-081017-and-081020:1:27:1267:1275 0 PHIX174 3716 37 28M1D8M * 0 0 TCATCAGCAAACGCAGAATCAGCGGTATGCTCTTCT IIIIIIIIIIIIIIIII;IIIIIII87III%I(@I. XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:28^G8
-081017-and-081020:1:94:1649:147 16 PHIX174 2755 37 15M2D21M * 0 0 TATACCGTCAAGGACTGTGACTATTGACGTCCTTCC 4IIIIII@I7IIIIIIIIIIIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:2 MD:Z:15^TG21
-081017-and-081020:1:95:74:43 0 PHIX174 4038 37 29M1I6M * 0 0 ATCGAGGCTCTTAAACCTGCTATTGAGGCTTTTTGG IIIIIIIIIIIIIIIIICI;8I,I>IIIIII1I%5& XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:31G3
+081017-and-081020:1:20:754:1256 16 PHIX174 4772 37 4M1I31M * 0 0 CCCTGGCGGTGCATTTTATGCGGACACTTCCTACAG &IIII(III3IIIII7II,IIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:2A32
+081017-and-081020:1:24:1326:917 0 PHIX174 188 37 25M1D11M * 0 0 TTCGCCATCAACTAACGATTCTGTCAAACCTGACGC IIIIIIIIIIIIIIIIIIIIIIIIIIA/&II>'IEI XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:25^A3A7
+081017-and-081020:1:24:1567:1780 0 PHIX174 3716 37 28M1D8M * 0 0 TCATCAGCAAACGCAGAATCAGCGGTATGCTCTTCT IIIIIIIIIIIIIIIII;IIIIIII87IFII%I(@I. XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:28^G8
+081017-and-081020:1:25:1466:511 16 PHIX174 1179 37 21M1D15M * 0 0 CTATTGACTCTACTGTAGACATTTTACTTTTTATGT :I<=IIIIII5IIGI5IIIIAIIIIIIIIIIIIIII XT:A:U NM:i:1 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:1 MD:Z:21^T15
+081017-and-081020:1:94:1649:147 16 PHIX174 2755 37 15M2D21M * 0 0 TATACCGTCAAGGACTGTGACTATTGACGTCCTTCC 4IIIIII@I7IIIIDEIIIIIIIIIIIIIIIIIIII XT:A:U NM:i:2 X0:i:1 X1:i:0 XM:i:0 XO:i:1 XG:i:2 MD:Z:15^TG21
--- a/test-data/sam_indel_filter_out2.sam
+++ b/test-data/sam_indel_filter_out2.sam
@@ -1,1 +1,1 @@
-1378_69_800 16 chr11.nib:1-125234658 241 255 15M1D8M * 0 0 CGTGGCCGGCGGGCCGAAGGCAT IIIIIIIIIICCCCIII?IIIII
+1378_56_324 153 chr2.nib:1-242951149 80324999 37 7M1I14M = 80324999 0 TTTAGCCCGAAATGCCTAGAGCA 4;?AA@@IE@GGI0110////00 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
--- a/test-data/sam_indel_filter_in1.sam
+++ b/test-data/sam_indel_filter_in1.sam
@@ -1,15 +1,17 @@
-1378_28_770 89 chr11.nib:1-134452384 72131356 37 17M1I5M = 72131356 0 CACACTGTGACAGACAGCGCAGC 00/02!!0//1200210AA44/1 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_28_770 89 chr11.nib:1-134452384 72131356 37 16M1I5M = 72131356 0 CACACTGTGACAGACAGCGCAGC 00/02!!0//1200210AA44/1 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
1378_28_770 181 chr11.nib:1-134452384 72131356 0 13M2I6M1D5M = 72131356 0 TTGGTGCGCGCGGTTGAGGGTTGG $$(#%%#$%#%####$%%##$###
1378_33_1945 113 chr2.nib:1-242951149 181247988 0 23M chr12.nib:1-132349534 41710908 0 GAGAGAGAGAGAGAGAGAGAGAG PQRVUMNXYRPUXYXWXSOSZ]M XT:A:R CM:i:0 SM:i:0 AM:i:0 X0:i:163148 XM:i:0 XO:i:0 XG:i:0 MD:Z:23
1378_33_1945 177 chr12.nib:1-132349534 41710908 0 23M chr2.nib:1-242951149 181247988 0 AGAGAGAGAGAGAGAGAGAGAGA SQQWZYURVYWX]]YXTSY]]ZM XT:A:R CM:i:0 SM:i:0 AM:i:0 X0:i:163148 XM:i:0 XO:i:0 XG:i:0 MD:Z:23
1378_35_263 115 chr16.nib:1-88827254 19671878 0 23M = 19671877 -1 AGAGAGAGAGAGAGAGAGAGTCT 77543:<55#"4!&=964518A> XT:A:R CM:i:2 SM:i:0 AM:i:0 X0:i:4 X1:i:137 XM:i:2 XO:i:0 XG:i:0 MD:Z:23
1378_35_263 179 chr16.nib:1-88827254 19671877 0 13M1I4M1I5M = 19671878 1 GAGAGAGAGAGAGAGAGAGAGTC LE7402DD34FL:27AKE>;432 XT:A:R CM:i:0 SM:i:0 AM:i:0 X0:i:265 XM:i:0 XO:i:0 XG:i:0 MD:Z:23
+1378_35_469 4 * 0 0 * * 0 0 TTAAGGGGAACGTGTGGGCTATTTAGGCTTTATG BBB=?BBA?>;?=B=AA=;A@B>=;;>:A=?:?9
1378_51_1671 117 chr2.nib:1-242951149 190342418 0 24M = 190342418 0 CTGGCGTTCTCGGCGTGGATGGGT #####$$##$#%#%%###%$#$##
-1378_51_1671 153 chr2.nib:1-242951149 190342418 37 16M1I6M = 190342418 0 TCTAACTTAGCCTCATAATAGCT /<<!"0///////00/!!0121/ XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_51_1671 153 chr2.nib:1-242951149 190342418 37 15M1I6M = 190342418 0 TCTAACTTAGCCTCATAATAGCT /<<!"0///////00/!!0121/ XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
1378_56_324 117 chr2.nib:1-242951149 80324999 0 24M = 80324999 0 TCCAGTCGCGTTGTTAGGTTCGGA #$#$$$#####%##%%###**#+/
-1378_56_324 153 chr2.nib:1-242951149 80324999 37 8M1I14M = 80324999 0 TTTAGCCCGAAATGCCTAGAGCA 4;6//11!"11100110////00 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_56_324 153 chr2.nib:1-242951149 80324999 37 7M1I14M = 80324999 0 TTTAGCCCGAAATGCCTAGAGCA 4;?AA@@IE@GGI0110////00 XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
1378_67_1795 81 chr16.nib:1-88827254 26739130 0 23M chrY.nib:1-57772954 57401793 0 TGGCATTCCTGTAGGCAGAGAGG AZWWZS]!"QNXZ]VQ]]]/2]] XT:A:R CM:i:2 SM:i:0 AM:i:0 X0:i:3 X1:i:0 XM:i:2 XO:i:0 XG:i:0 MD:Z:23
1378_67_1795 161 chrY.nib:1-57772954 57401793 37 23M chr16.nib:1-88827254 26739130 0 GATCACCCAGGTGATGTAACTCC ]WV]]]]WW]]]]]]]]]]PU]] XT:A:U CM:i:0 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:0 XO:i:0 XG:i:0 MD:Z:23
-1378_69_800 16 chr11.nib:1-125234658 241 255 15M1D8M * 0 0 CGTGGCCGGCGGGCCGAAGGCAT IIIIIIIIIICCCCIII?IIIII
+1378_68_1186 4 * 0 0 * * 0 0 GTTAATAGGGTGATAGA AB/BC==CC%ACBC/CB
+1378_69_800 16 chr11.nib:1-125234658 241 255 14M1D8M * 0 0 CGTGGCCGGCGGGCCGAAGGCAT IIIIIIIIIICCCCIII?!IIII
1378_69_1777 170 chrX.nib:1-59090954 59090793 37 23M chr16.nib:1-88827254 26739130 0 TATCAATAAGGTGATGTAACTCG ]WV]ABAWW]]]]]P]P//GU]] XT:A:U CM:i:0 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:0 XO:i:0 XG:i:0 MD:Z:23
-1378_72_1612 151 chrY.nib:1-124295114 190342418 37 19M1I3M = 190342418 0 TCTAACTTAGCCTCATAATAGCT /<<!"0/4//7//00/BC0121/ XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
+1378_72_1612 151 chrY.nib:1-124295114 190342418 37 18M1I3M = 190342418 0 TCTAACTTAGCCTCATAATAGCT /<<!"0/4//7//@@?BCIIIII XT:A:U CM:i:2 SM:i:37 AM:i:0 X0:i:1 X1:i:0 XM:i:1 XO:i:1 XG:i:1 MD:Z:22
1
0
galaxy-dist commit db1ae0bc8995: Attempt to reduce costly queries in the job runner, especially when tracking jobs in the database.
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1279818642 14400
# Node ID db1ae0bc8995cb30deef73ce9d14ef175c512f90
# Parent 79d38503db4d860f9c9d62560c156fb0a2122b1b
Attempt to reduce costly queries in the job runner, especially when tracking jobs in the database.
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -18,7 +18,7 @@ from Queue import Queue, Empty
log = logging.getLogger( __name__ )
# States for running a job. These are NOT the same as data states
-JOB_WAIT, JOB_ERROR, JOB_INPUT_ERROR, JOB_INPUT_DELETED, JOB_OK, JOB_READY, JOB_DELETED, JOB_ADMIN_DELETED = 'wait', 'error', 'input_error', 'input_deleted', 'ok', 'ready', 'deleted', 'admin_deleted'
+JOB_WAIT, JOB_INPUT_ERROR, JOB_INPUT_DELETED, JOB_READY, JOB_DELETED, JOB_ADMIN_DELETED = 'wait', 'input_error', 'input_deleted', 'ready', 'deleted', 'admin_deleted'
# This file, if created in the job's working directory, will be used for
# setting advanced metadata properties on the job and its associated outputs.
@@ -106,14 +106,14 @@ class JobQueue( object ):
for job in self.sa_session.query( model.Job ).filter( model.Job.state == model.Job.states.NEW ):
if job.tool_id not in self.app.toolbox.tools_by_id:
log.warning( "Tool '%s' removed from tool config, unable to recover job: %s" % ( job.tool_id, job.id ) )
- JobWrapper( job, None, self ).fail( 'This tool was disabled before the job completed. Please contact your Galaxy administrator, or' )
+ JobWrapper( job, self ).fail( 'This tool was disabled before the job completed. Please contact your Galaxy administrator, or' )
else:
log.debug( "no runner: %s is still in new state, adding to the jobs queue" %job.id )
self.queue.put( ( job.id, job.tool_id ) )
for job in self.sa_session.query( model.Job ).filter( ( model.Job.state == model.Job.states.RUNNING ) | ( model.Job.state == model.Job.states.QUEUED ) ):
if job.tool_id not in self.app.toolbox.tools_by_id:
log.warning( "Tool '%s' removed from tool config, unable to recover job: %s" % ( job.tool_id, job.id ) )
- JobWrapper( job, None, self ).fail( 'This tool was disabled before the job completed. Please contact your Galaxy administrator, or' )
+ JobWrapper( job, self ).fail( 'This tool was disabled before the job completed. Please contact your Galaxy administrator, or' )
elif job.job_runner_name is None:
log.debug( "no runner: %s is still in queued state, adding to the jobs queue" %job.id )
if self.track_jobs_in_database:
@@ -121,7 +121,7 @@ class JobQueue( object ):
else:
self.queue.put( ( job.id, job.tool_id ) )
else:
- job_wrapper = JobWrapper( job, self.app.toolbox.tools_by_id[ job.tool_id ], self )
+ job_wrapper = JobWrapper( job, self )
self.dispatcher.recover( job, job_wrapper )
if self.sa_session.dirty:
self.sa_session.flush()
@@ -154,11 +154,12 @@ class JobQueue( object ):
# Pull all new jobs from the queue at once
new_jobs = []
if self.track_jobs_in_database:
- for j in self.sa_session.query( model.Job ) \
+ # Clear the session so we get fresh states for job and all datasets
+ self.sa_session.expunge_all()
+ # Fetch all new jobs
+ new_jobs = self.sa_session.query( model.Job ) \
.options( lazyload( "external_output_metadata" ), lazyload( "parameters" ) ) \
- .filter( model.Job.state == model.Job.states.NEW ):
- job = JobWrapper( j, self.app.toolbox.tools_by_id[ j.tool_id ], self )
- new_jobs.append( job )
+ .filter( model.Job.state == model.Job.states.NEW ).all()
else:
try:
while 1:
@@ -168,8 +169,7 @@ class JobQueue( object ):
# Unpack the message
job_id, tool_id = message
# Create a job wrapper from it
- job_entity = self.sa_session.query( model.Job ).get( job_id )
- job = JobWrapper( job_entity, self.app.toolbox.tools_by_id[ tool_id ], self )
+ job = self.sa_session.query( model.Job ).get( job_id )
# Append to watch queue
new_jobs.append( job )
except Empty:
@@ -179,52 +179,43 @@ class JobQueue( object ):
new_waiting = []
for job in ( new_jobs + self.waiting ):
try:
- # Clear the session for each job so we get fresh states for
- # job and all datasets
- self.sa_session.expunge_all()
- # Get the real job entity corresponding to the wrapper (if we
- # are tracking in the database this is probably cached in
- # the session from the origianl query above)
- job_entity = self.sa_session.query( model.Job ).get( job.job_id )
+ # Since we don't expunge when not tracking jobs in the
+ # database, refresh the job here so it's not stale.
+ if not self.track_jobs_in_database:
+ self.sa_session.refresh( job )
# Check the job's dependencies, requeue if they're not done
- job_state = self.__check_if_ready_to_run( job, job_entity )
- if job_state == JOB_WAIT:
+ job_state = self.__check_if_ready_to_run( job )
+ if job_state == JOB_WAIT:
if not self.track_jobs_in_database:
new_waiting.append( job )
- elif job_state == JOB_ERROR:
- log.info( "job %d ended with an error" % job.job_id )
elif job_state == JOB_INPUT_ERROR:
- log.info( "job %d unable to run: one or more inputs in error state" % job.job_id )
+ log.info( "job %d unable to run: one or more inputs in error state" % job.id )
elif job_state == JOB_INPUT_DELETED:
- log.info( "job %d unable to run: one or more inputs deleted" % job.job_id )
+ log.info( "job %d unable to run: one or more inputs deleted" % job.id )
elif job_state == JOB_READY:
if self.job_lock:
- log.info("Job dispatch attempted for %s, but prevented by administrative lock." % job.job_id)
+ log.info( "Job dispatch attempted for %s, but prevented by administrative lock." % job.id )
if not self.track_jobs_in_database:
new_waiting.append( job )
else:
- self.dispatcher.put( job )
- log.debug( "job %d dispatched" % job.job_id)
+ self.dispatcher.put( JobWrapper( job, self ) )
+ log.info( "job %d dispatched" % job.id )
elif job_state == JOB_DELETED:
- msg = "job %d deleted by user while still queued" % job.job_id
- job.info = msg
- log.debug( msg )
+ log.info( "job %d deleted by user while still queued" % job.id )
elif job_state == JOB_ADMIN_DELETED:
- job.fail( job_entity.info )
- log.info( "job %d deleted by admin while still queued" % job.job_id )
+ job.info( "job %d deleted by admin while still queued" % job.id )
else:
- msg = "unknown job state '%s' for job %d" % ( job_state, job.job_id )
- job.info = msg
- log.error( msg )
+ log.error( "unknown job state '%s' for job %d" % ( job_state, job.id ) )
+ if not self.track_jobs_in_database:
+ new_waiting.append( job )
except Exception, e:
- job.info = "failure running job %d: %s" % ( job.job_id, str( e ) )
- log.exception( "failure running job %d" % job.job_id )
+ log.exception( "failure running job %d" % job.id )
# Update the waiting list
self.waiting = new_waiting
# Done with the session
self.sa_session.remove()
- def __check_if_ready_to_run( self, job_wrapper, job ):
+ def __check_if_ready_to_run( self, job ):
"""
Check if a job is ready to run by verifying that each of its input
datasets is ready (specifically in the OK state). If any input dataset
@@ -244,11 +235,11 @@ class JobQueue( object ):
continue
# don't run jobs for which the input dataset was deleted
if idata.deleted:
- job_wrapper.fail( "input data %d (file: %s) was deleted before the job started" % ( idata.hid, idata.file_name ) )
+ JobWrapper( job, self ).fail( "input data %d (file: %s) was deleted before the job started" % ( idata.hid, idata.file_name ) )
return JOB_INPUT_DELETED
# an error in the input data causes us to bail immediately
elif idata.state == idata.states.ERROR:
- job_wrapper.fail( "input data %d is in error state" % ( idata.hid ) )
+ JobWrapper( job, self ).fail( "input data %d is in error state" % ( idata.hid ) )
return JOB_INPUT_ERROR
elif idata.state != idata.states.OK and not ( idata.state == idata.states.SETTING_METADATA and job.tool_id is not None and job.tool_id == self.app.datatypes_registry.set_external_metadata_tool.id ):
# need to requeue
@@ -280,11 +271,11 @@ class JobWrapper( object ):
Wraps a 'model.Job' with convience methods for running processes and
state management.
"""
- def __init__(self, job, tool, queue ):
+ def __init__( self, job, queue ):
self.job_id = job.id
self.session_id = job.session_id
self.user_id = job.user_id
- self.tool = tool
+ self.tool = queue.app.toolbox.tools_by_id.get( job.tool_id, None )
self.queue = queue
self.app = queue.app
self.sa_session = self.app.model.context
--- a/lib/galaxy/tools/actions/__init__.py
+++ b/lib/galaxy/tools/actions/__init__.py
@@ -5,7 +5,6 @@ from galaxy.tools.parameters.grouping im
from galaxy.util.template import fill_template
from galaxy.util.none_like import NoneDataset
from galaxy.web import url_for
-from galaxy.jobs import JOB_OK
import galaxy.tools
from types import *
@@ -353,7 +352,7 @@ class DefaultToolAction( object ):
assert GALAXY_URL is not None, "GALAXY_URL parameter missing in tool config."
redirect_url += "&GALAXY_URL=%s" % GALAXY_URL
# Job should not be queued, so set state to ok
- job.state = JOB_OK
+ job.state = trans.app.model.Job.states.OK
job.info = "Redirected to: %s" % redirect_url
trans.sa_session.add( job )
trans.sa_session.flush()
1
0
galaxy-dist commit ebc01826650f: Fix tool_form.mako which I broke in 4045:8ffcaf3d9a0c
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Nate Coraor <nate(a)bx.psu.edu>
# Date 1279745173 14400
# Node ID ebc01826650f07ee5a5d1a8ef61e7c2dccc56494
# Parent 1acae496c2200747aa79e7ac52cce74f5a3a3c83
Fix tool_form.mako which I broke in 4045:8ffcaf3d9a0c
--- a/templates/tool_form.mako
+++ b/templates/tool_form.mako
@@ -215,7 +215,7 @@ function checkUncheckAll( name, check )
<div class="toolFormTitle">${tool.name}</div>
%endif
<div class="toolFormBody">
- <form id="tool_form" name="tool_form" action="${tool_url}" enctype="${tool.enctype}" target="${tool.target}" method="${tool.method}"><input type="hidden" name="tool_id" value="${tool.id}"><input type="hidden" name="tool_state" value="${util.object_to_string( tool_state.encode( tool, app ) )}">
+ <form id="tool_form" name="tool_form" action="${tool_url}" enctype="${tool.enctype}" target="${tool.target}" method="${tool.method}"><input type="hidden" name="tool_id" value="${tool.id}"><input type="hidden" name="tool_state" value="${util.object_to_string( tool_state.encode( tool, app ) )}">
%if tool.display_by_page[tool_state.page]:
1
0
galaxy-dist commit 79d38503db4d: First selenium test for trackster
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1279808223 14400
# Node ID 79d38503db4d860f9c9d62560c156fb0a2122b1b
# Parent 3ce0b7c2b0083ad37fb6b11679632675a8aea043
First selenium test for trackster
--- /dev/null
+++ b/test/selenium/visualization/Trackster.html
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head profile="http://selenium-ide.openqa.org/profiles/test-case">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<link rel="selenium.base" href="http://localhost:8000/" />
+<title>New Browser</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">New Browser</td></tr>
+</thead><tbody>
+<tr>
+ <td>open</td>
+ <td>/visualization/list</td>
+ <td></td>
+</tr>
+<tr>
+ <td>clickAndWait</td>
+ <td>link=New Track Browser</td>
+ <td></td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>new-title</td>
+ <td>Test</td>
+</tr>
+<tr>
+ <td>type</td>
+ <td>new-dbkey</td>
+ <td>Human Mar. 2006 (NCBI36/hg18) (hg18)</td>
+</tr>
+<tr>
+ <td>click</td>
+ <td>//div[@id='overlay']/table/tbody/tr/td/div/div/div[3]/div[1]/button[2]</td>
+ <td></td>
+</tr>
+<tr>
+ <td>verifyTextPresent</td>
+ <td>Test (hg18)</td>
+ <td></td>
+</tr>
+<tr>
+ <td>select</td>
+ <td>chrom</td>
+ <td>label=chr21</td>
+</tr>
+<tr>
+ <td>verifyValue</td>
+ <td>//div[@id='center']/div[3]/div[2]/div[2]/form/input[1]</td>
+ <td>0</td>
+</tr>
+<tr>
+ <td>verifyValue</td>
+ <td>//div[@id='center']/div[3]/div[2]/div[2]/form/input[2]</td>
+ <td>46,944,323</td>
+</tr>
+
+</tbody></table>
+</body>
+</html>
1
0
galaxy-dist commit 3ce0b7c2b008: Add patch to from Assaf Gordon to include job runner and job runner id on the job info page of the reports.
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1279804702 14400
# Node ID 3ce0b7c2b0083ad37fb6b11679632675a8aea043
# Parent ebc01826650f07ee5a5d1a8ef61e7c2dccc56494
Add patch to from Assaf Gordon to include job runner and job runner id on the job info page of the reports.
--- a/templates/webapps/reports/job_info.mako
+++ b/templates/webapps/reports/job_info.mako
@@ -29,18 +29,22 @@
<td>${job.session_id}</td></tr><tr class="header">
- <td colspan="3">Tool</td>
- <td colspan="2">User</td>
+ <td colspan="2">Tool</td>
+ <td>User</td>
+ <td>Runner</td>
+ <td>Runner Id</td></tr><tr>
- <td colspan="3">${job.tool_id}</td>
- <td colspan="2">
+ <td colspan="2">${job.tool_id}</td>
+ <td>
%if job.user and job.user.email:
${job.user.email}
%else:
anonymous
%endif
</td>
+ <td>${job.job_runner_name}</td>
+ <td>${job.job_runner_external_id}</td></tr><tr class="header"><td colspan="5">Remote Host</td>
1
0
galaxy-dist commit a37b8a979f7d: Add job.stdout to Job Info page in reports webapp ( patch from Assaf Gordon ), and change the previously displayed job.update_time to now be "Time To Finish", which is the total execution time of the job displayed in hh:mm:ss.
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Greg Von Kuster <greg(a)bx.psu.edu>
# Date 1279734781 14400
# Node ID a37b8a979f7d0d040527413695c5828d22ca5e54
# Parent 8ffcaf3d9a0c16d080801f3f81104e829403da41
Add job.stdout to Job Info page in reports webapp ( patch from Assaf Gordon ), and change the previously displayed job.update_time to now be "Time To Finish", which is the total execution time of the job displayed in hh:mm:ss.
--- a/templates/webapps/reports/job_info.mako
+++ b/templates/webapps/reports/job_info.mako
@@ -1,6 +1,8 @@
<%inherit file="/base.mako"/><%namespace file="/message.mako" import="render_msg" />
+<% import datetime %>
+
%if message:
${render_msg( message, 'done' )}
%endif
@@ -13,14 +15,17 @@
<td>State</td><td>Job Id</td><td>Create Time</td>
- <td>Update Time</td>
+ <td>Time To Finish</td><td>Session Id</td></tr><tr><td><div class="count-box state-color-${job.state}">${job.state}</div></td><td>${job.id}</td><td>${job.create_time}</td>
- <td>${job.update_time}</td>
+ <td>
+ <% execute_time = job.update_time - job.create_time %>
+ ${datetime.timedelta( seconds=execute_time.seconds )}
+ </td><td>${job.session_id}</td></tr><tr class="header">
@@ -56,6 +61,12 @@
<td colspan="5">${job.command_line}</td></tr><tr class="header">
+ <td colspan="5">Stdout</td>
+ </tr>
+ <tr>
+ <td colspan="5"><pre>${job.stdout}</pre></td>
+ </tr>
+ <tr class="header"><td colspan="5">Stderr</td></tr><tr>
1
0
galaxy-dist commit 7e63649e96b5: trackster: remove mousewheel zoom (since scrolling window is more important), fix overview drag bug
by commits-noreply@bitbucket.org 23 Jul '10
by commits-noreply@bitbucket.org 23 Jul '10
23 Jul '10
# HG changeset patch -- Bitbucket.org
# Project galaxy-dist
# URL http://bitbucket.org/galaxy/galaxy-dist/overview
# User Kanwei Li <kanwei(a)gmail.com>
# Date 1279651656 14400
# Node ID 7e63649e96b5788bdd72e3d639fca1e8153c2775
# Parent 84671d8f46845b7a5bcfcc8028e68eaf241a5058
trackster: remove mousewheel zoom (since scrolling window is more important), fix overview drag bug
--- a/static/scripts/trackster.js
+++ b/static/scripts/trackster.js
@@ -91,9 +91,8 @@ var View = function( container, chrom, t
// Create DOM elements
var parent_element = this.container,
view = this;
-
+ this.top_labeltrack = $("<div/>").addClass("top-labeltrack").appendTo(parent_element);
this.content_div = $("<div/>").addClass("content").css("position", "relative").appendTo(parent_element);
- this.top_labeltrack = $("<div/>").addClass("top-labeltrack").appendTo(this.content_div);
this.viewport_container = $("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);
this.viewport = $("<div/>").addClass("viewport").appendTo(this.viewport_container);
@@ -136,7 +135,7 @@ var View = function( container, chrom, t
var found = $.grep(view.chrom_data, function(v, i) {
return v.chrom === view.chrom;
})[0];
- view.max_high = found.len;
+ view.max_high = (found.len !== undefined ? found.len : 0);
view.reset();
view.redraw(true);
@@ -154,6 +153,7 @@ var View = function( container, chrom, t
}
});
+ /*
this.content_div.bind("mousewheel", function( e, delta ) {
if (Math.abs(delta) < 0.5) {
return;
@@ -165,6 +165,7 @@ var View = function( container, chrom, t
}
e.preventDefault();
});
+ */
this.content_div.bind("dblclick", function( e ) {
view.zoom_in(e.pageX, this.viewport_container);
@@ -177,8 +178,8 @@ var View = function( container, chrom, t
var delta = e.offsetX - this.current_x;
this.current_x = e.offsetX;
- var delta_chrom = Math.round(delta / view.viewport_container.width() * (view.high - view.low) );
- view.move_delta(-2*delta_chrom);
+ var delta_chrom = Math.round(delta / view.viewport_container.width() * (view.max_high - view.max_low) );
+ view.move_delta(-delta_chrom);
});
this.viewport_container.bind( "dragstart", function( e ) {
--- a/static/scripts/packed/trackster.js
+++ b/static/scripts/packed/trackster.js
@@ -1,1 +1,1 @@
-var DENSITY=200,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset. ",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=30,CACHED_DATA=5,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),PX_PER_CHAR=CONTEXT.measureText("A").width,RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONT
EXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(a,c,e,d,b){this.container=a;this.vis_id=d;this.dbkey=b;this.title=e;this.chrom=c;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init();this.reset()};$.extend(View.prototype,{in
it:function(){var b=this.container,a=this;this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(b);this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(this.content_div);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.viewport=$("<div/>").addClass("viewport").appendTo(this.viewport_container);this.nav_container=$("<div/>").addClass("nav-container").appendTo(b);this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.nav_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.nav);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_form=$("<form/>"
).attr("action",function(){void (0)}).appendTo(this.nav_controls);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.chrom_form);this.low_input=$("<input/>").addClass("low").css("width","10em").appendTo(this.chrom_form);$("<span/>").text(" - ").appendTo(this.chrom_form);this.high_input=$("<input/>").addClass("high").css("width","10em").appendTo(this.chrom_form);if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.chrom_form)}this.zi_link=$("<a/>").click(function(){a.zoom_in();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom.png" />').appendTo(this.chrom_form);this.zo_link=$("<a/>").click(function(){a.zoom_out();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom-out.png" />').appendTo(this.chrom_form);$.ajax({url:chrom_url,data:(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:
this.dbkey}),dataType:"json",success:function(c){if(c.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=c.chrom_info;var e='<option value="">Select Chrom/Contig</option>';for(i in a.chrom_data){var d=a.chrom_data[i]["chrom"];e+='<option value="'+d+'">'+d+"</option>"}a.chrom_select.html(e);a.chrom_select.bind("change",function(){a.chrom=a.chrom_select.val();var g=$.grep(a.chrom_data,function(j,k){return j.chrom===a.chrom})[0];a.max_high=g.len;a.reset();a.redraw(true);for(var h in a.tracks){var f=a.tracks[h];if(f.init){f.init()}}a.redraw()})},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}});this.content_div.bind("mousewheel",function(c,d){if(Math.abs(d)<0.5){return}if(d>0){a.zoom_in(c.pageX,this.viewport_container)}else{a.zoom_out()}c.preventDefault()});this.content_div.bind("dblclick",function(c){a.zoom_in(c.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(c){this.current_x=c.offsetX}).bind("drag",function(c
){var f=c.offsetX-this.current_x;this.current_x=c.offsetX;var d=Math.round(f/a.viewport_container.width()*(a.high-a.low));a.move_delta(-2*d)});this.viewport_container.bind("dragstart",function(c){this.original_low=a.low;this.current_height=c.clientY;this.current_x=c.offsetX}).bind("drag",function(f){var c=$(this);var h=f.offsetX-this.current_x;var d=c.scrollTop()-(f.clientY-this.current_height);if(d<c.get(0).scrollHeight-c.height()){c.scrollTop(d)}this.current_height=f.clientY;this.current_x=f.offsetX;var g=Math.round(h/a.viewport_container.width()*(a.high-a.low));a.move_delta(g)});this.top_labeltrack.bind("dragstart",function(c){this.drag_origin_x=c.clientX;this.drag_origin_pos=c.clientX/a.viewport_container.width()*(a.high-a.low)+a.low;this.drag_div=$("<div />").css({height:a.content_div.height(),top:"0px",position:"absolute","background-color":"#cfc",border:"1px solid #6a6",opacity:0.5}).appendTo($(this))}).bind("drag",function(h){var d=Math.min(h.clientX,this.drag_origin
_x),c=Math.max(h.clientX,this.drag_origin_x),g=(a.high-a.low),f=a.viewport_container.width();a.low_input.val(commatize(Math.round(d/f*g)+a.low));a.high_input.val(commatize(Math.round(c/f*g)+a.low));this.drag_div.css({left:d+"px",width:(c-d)+"px"})}).bind("dragend",function(j){var d=Math.min(j.clientX,this.drag_origin_x),c=Math.max(j.clientX,this.drag_origin_x),g=(a.high-a.low),f=a.viewport_container.width(),h=a.low;a.low=Math.round(d/f*g)+h;a.high=Math.round(c/f*g)+h;this.drag_div.remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack))},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"
+a.track_id);this.track_id_counter+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)]},update_options:function(){this.has_changes=true;var b=$("ul#sortable-ul").sortable("toArray");for(var c in b){var e=b[c].split("_li")[0].split("track_")[1];this.viewport.append($("#track_"+e))}for(var d in view.tracks){var a=view.tracks[d];if(a&&a.update_options){a.update_options(d)}}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(f){var d=this.high-this.low,b=this.low,e=this.high;if(b<this.max_low){b=this.max_low}if(e>this.max_high){e=this.max_high}if(this.high!==0&&d<this.min_separation){e=b+this.min_separation}this.low=Math.floor(b);this.high=Math.ceil(e);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.L
N10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));this.overview_box.css({left:(this.low/(this.max_high-this.max_low))*this.overview_viewport.width(),width:Math.max(12,(this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())}).show();this.low_input.val(commatize(this.low));this.high_input.val(commatize(this.high));if(!f){for(var c=0,a=this.tracks.length;c<a;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(var c=0,a=this.label_tracks.length;c<a;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b
/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);this.high=Math.round(c+a);this.redraw()}});var Track=function(b,a,c){this.name=b;this.parent_element=c;this.view=a;this.init_global()};$.extend(Track.prototype,{init_global:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div />").addClass("track").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"||d.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(d.message){var f=a.view.tracks.indexOf(a);var e=$("<a href='javascript:void(0);'></a>").attr("id",f+"_erro
r");e.text("Click to view error");$("#"+f+"_error").live("click",function(){show_modal("Trackster Error","<pre>"+d.message+"</pre>",{Close:hide_modal})});a.content_div.append(e)}}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(d.data!==undefined&&(d.data===null||d.data.length===0)){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){this.left_offset=200};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var j=this.view.low,e=this.view.high,f=e-j,d=this.view.resolution;var l=$("<div style='position: relative;'></div>"),m=this.content_div.width()/f,h;this.conten
t_div.children(":first").remove();this.content_div.append(l),this.max_height=0;var a=Math.floor(j/d/DENSITY);while((a*DENSITY*d)<e){var k=this.content_div.width()+"_"+m+"_"+a;var c=this.tile_cache.get(k);if(c){var g=a*DENSITY*d;var b=(g-j)*m;if(this.left_offset){b-=this.left_offset}c.css({left:b});l.append(c);this.max_height=Math.max(this.max_height,c.height());this.content_div.css("height",this.max_height+"px")}else{this.delayed_draw(this,k,j,e,a,d,l,m)}a+=1}},delayed_draw:function(c,e,a,f,b,d,g,h){setTimeout(function(){if(!(a>c.view.high||f<c.view.low)){tile_element=c.draw_tile(d,b,g,h);if(tile_element){c.tile_cache.set(e,tile_element);c.max_height=Math.max(c.max_height,tile_element.height());c.content_div.css("height",c.max_height+"px")}}},50)}});var LabelTrack=function(a,b){Track.call(this,null,a,b);this.track_type="LabelTrack";this.hidden=true;this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.h
igh-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: relative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";Track.call(this,null,a,a.nav_labeltrack);TiledTrack.call(this);this.hidden=true;this.height_px=12;this.container_div.addClass("reference-track");this.dummy_canvas=$("<canvas></canvas>").get(0).getContext("2d");this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:reference_url,dataType:"json"
,data:{chrom:this.view.chrom,low:a,high:f,dbkey:this.view.dbkey},success:function(g){c.data_cache.set(e,g);delete c.data_queue[e];c.draw()},error:function(h,g,j){console.log(h,g,j)}})}},draw_tile:function(f,b,k,o){var g=b*DENSITY*f,d=DENSITY*f,e=$("<canvas class='tile'></canvas>"),n=e.get(0).getContext("2d"),j=f+"_"+b;if(o>PX_PER_CHAR){if(this.data_cache.get(j)===undefined){this.get_data(f,b);return}var m=this.data_cache.get(j);if(m===null){return}e.get(0).width=Math.ceil(d*o+this.left_offset);e.get(0).height=this.height_px;e.css({position:"absolute",top:0,left:(g-this.view.low)*o+this.left_offset});for(var h=0,l=m.length;h<l;h++){var a=Math.round(h*o);n.fillText(m[h],a+this.left_offset,10)}k.append(e);return e}}});var LineTrack=function(d,b,a,c){this.track_type="LineTrack";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=100;this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={min_val
ue:undefined,max_value:undefined,mode:"Line"};if(c.min_value!==undefined){this.prefs.min_value=c.min_value}if(c.max_value!==undefined){this.prefs.max_value=c.max_value}if(c.mode!==undefined){this.prefs.mode=c.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");data=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=data.min;a.prefs.max_value=data.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=data.total_frequency;$("#linetrack_"+b+"_minval").remove();$("#linetrack_"+b+"_maxval").remove();var e=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.
min_value);var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);d.css({position:"relative",top:"25px",left:"10px"});d.prependTo(a.container_div);e.css({position:"relative",top:a.height_px+55+"px",left:"10px"});e.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){data=g.data;c.data_cache.set(e,data);delete c.data_queue[e];c.draw()},error:function(h,g,j){console.log(h,g,j)}})}},draw_tile:function(p,r,c,e){if(this.vertical_range===undefined){return}var s=r*DENSITY*p,a=DENSITY*p,b=$("<canvas class='tile'></canvas>"),v=p+"_"+r;if(this.data_cache.get(v)===undefined){this.get_data(p,r);return}var j=this.data_cache.get(v);if(j===null){return}b.css({position:"absolute",top:0,left:(s-th
is.view.low)*e});b.get(0).width=Math.ceil(a*e+this.left_offset);b.get(0).height=this.height_px;var o=b.get(0).getContext("2d"),k=false,l=this.prefs.min_value,g=this.prefs.max_value,n=this.vertical_range,t=this.total_frequency,d=this.height_px,m=this.prefs.mode;o.beginPath();if(data.length>1){var f=Math.ceil((data[1][0]-data[0][0])*e)}else{var f=10}var u,h;for(var q=0;q<data.length;q++){u=(data[q][0]-s)*e;h=data[q][1];if(m=="Intensity"){if(h===null){continue}if(h<=l){h=l}else{if(h>=g){h=g}}h=255-Math.floor((h-l)/n*255);o.fillStyle="rgb("+h+","+h+","+h+")";o.fillRect(u,0,f,this.height_px)}else{if(h===null){if(k&&m==="Filled"){o.lineTo(u,d)}k=false;continue}else{if(h<=l){h=l}else{if(h>=g){h=g}}h=Math.round(d-(h-l)/n*d);if(k){o.lineTo(u,h)}else{k=true;if(m==="Filled"){o.moveTo(u,d);o.lineTo(u,h)}else{o.moveTo(u,h)}}}}}if(m==="Filled"){if(k){o.lineTo(u,d)}o.fill()}else{o.stroke()}c.append(b);return b},gen_options:function(o){var a=$("<div />").addClass("form-row");var h="track_"+
o+"_minval",m=$("<label></label>").attr("for",h).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),n=$("<input></input>").attr("id",h).val(b),l="track_"+o+"_maxval",g=$("<label></label>").attr("for",l).text("Max value:"),k=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",l).val(k),e="track_"+o+"_mode",d=$("<label></label>").attr("for",e).text("Display mode:"),j=(this.prefs.mode===undefined?"Line":this.prefs.mode),c=$('<select id="'+e+'"><option value="Line" id="mode_Line">Line</option><option value="Filled" id="mode_Filled">Filled</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');c.children("#mode_"+j).attr("selected","selected");return a.append(m).append(n).append(g).append(f).append(d).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_mode option:selected").val();if(a!==this.prefs.min_value||c
!==this.prefs.max_value||b!==this.prefs.mode){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.mode=b;this.vertical_range=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(d,b,a,c){this.track_type="FeatureTrack";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=0;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.default_font="9px Monaco, Lucida Console, monospace";this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black",show_counts:false};if(c.block_color!==undefined){this.pref
s.block_color=c.block_color}if(c.label_color!==undefined){this.prefs.label_color=c.label_color}if(c.show_counts!==undefined){this.prefs.show_counts=c.show_counts}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.max_low+"_"+a.view.max_high;a.mode="Auto";if(a.mode_div){a.mode_div.remove()}this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution},function(d){a.mode_div=$("<div class='right-float menubutton popup' />").text("Display Mode");a.header_div.append(a.mode_div);a.mode="Auto";var c=function(e){a.mode_div.text(e);a.mode=e;a.tile_cache.clear();a.draw()};make_popupmenu(a.mode_div,{Auto:function(){c("Auto")},Dense:function(){c("Dense")},Squish:function(){c("Squish")},Pack:function(){c("Pack")}});a.data_cache.set(b,d);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,h
igh:d,dataset_id:b.dataset_id,resolution:this.view.resolution,mode:this.mode},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incremental_slots:function(a,h,c,r){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.inc_slots[a].mode=r;this.s_e_by_tile[a]={}}var n=this.inc_slots[a].w_scale,z=[],l=0,b=$("<canvas></canvas>").get(0).getContext("2d"),o=this.view.max_low;var B=[];if(this.inc_slots[a].mode!==r){delete this.inc_slots[a];this.inc_slots[a]={mode:r,w_scale:n};delete this.s_e_by_tile[a];this.s_e_by_tile[a]={}}for(var w=0,x=h.length;w<x;w++){var g=h[w],m=g[0];if(this.inc_slots[a][m]!==undefined){l=Math.max(l,this.inc_slots[a][m]);B.push(this.inc_slots[a][m])}else{z.push(w)}}for(var w=0,x=z.length;w<x;w++){var g=h[z[w]],m=g[0],s=g[1],d=g[2],q=g[3],e=Math.floor((s-o)*n),f=Math.ceil((d-o)*n);if(q!==undefined&&!c){var t=b.measureText(q).width;if(e-t<0){f+=t}else{e-=t}}var v=0;while(true){var p=true;if(this.s_e_by_tile[a][v]!==u
ndefined){for(var u=0,A=this.s_e_by_tile[a][v].length;u<A;u++){var y=this.s_e_by_tile[a][v][u];if(f>y[0]&&e<y[1]){p=false;break}}}if(p){if(this.s_e_by_tile[a][v]===undefined){this.s_e_by_tile[a][v]=[]}this.s_e_by_tile[a][v].push([e,f]);this.inc_slots[a][m]=v;l=Math.max(l,v);break}v++}}return l},rect_or_text:function(n,o,f,m,b,d,k,e,h){n.textAlign="center";var j=Math.round(o/2);if((this.mode==="Pack"||this.mode==="Auto")&&d!==undefined&&o>PX_PER_CHAR){n.fillStyle=this.prefs.block_color;n.fillRect(k,h+1,e,9);n.fillStyle="#eee";for(var g=0,l=d.length;g<l;g++){if(b+g>=f&&b+g<=m){var a=Math.floor(Math.max(0,(b+g-f)*o));n.fillText(d[g],a+this.left_offset+j,h+9)}}}else{n.fillStyle=this.prefs.block_color;n.fillRect(k,h+4,e,3)}},draw_tile:function(X,h,n,ak){var E=h*DENSITY*X,ad=(h+1)*DENSITY*X,D=DENSITY*X;var ae=E+"_"+ad;var z=this.data_cache.get(ae);if(z===undefined){this.data_queue[[E,ad]]=true;this.get_data(E,ad);return}var a=Math.ceil(D*ak),L=$("<canvas class='tile'></canvas>"),Z
=this.prefs.label_color,f=this.prefs.block_color,m=this.mode,V=(m==="Squish")||(m==="Dense")&&(m!=="Pack")||(m==="Auto"&&(z.extra_info==="no_detail")),P=this.left_offset,aj,s,al;if(z.dataset_type==="summary_tree"){s=30}else{if(m==="Dense"){s=15;al=10}else{al=(V?this.vertical_nodetail_px:this.vertical_detail_px);s=this.incremental_slots(this.view.zoom_res,z.data,V,m)*al+15;aj=this.inc_slots[this.view.zoom_res]}}L.css({position:"absolute",top:0,left:(E-this.view.low)*ak-P});L.get(0).width=a+P;L.get(0).height=s;n.parent().css("height",Math.max(this.height_px,s)+"px");var A=L.get(0).getContext("2d");A.fillStyle=f;A.font=this.default_font;A.textAlign="right";if(z.dataset_type=="summary_tree"){var K,H=55,ac=255-H,g=ac*2/3,R=z.data,C=z.max,l=z.avg;if(R.length>2){var b=Math.ceil((R[1][0]-R[0][0])*ak)}else{var b=50}for(var ag=0,w=R.length;ag<w;ag++){var T=Math.ceil((R[ag][0]-E)*ak);var S=R[ag][1];if(!S){continue}K=Math.floor(ac-(S/C)*ac);A.fillStyle="rgb("+K+","+K+","+K+")";A.fillRec
t(T+P,0,b,20);if(this.prefs.show_counts){if(K>g){A.fillStyle="black"}else{A.fillStyle="#ddd"}A.textAlign="center";A.fillText(R[ag][1],T+P+(b/2),12)}}n.append(L);return L}var ai=z.data;var af=0;for(var ag=0,w=ai.length;ag<w;ag++){var M=ai[ag],J=M[0],ah=M[1],U=M[2],F=M[3];if(ah<=ad&&U>=E){var W=Math.floor(Math.max(0,(ah-E)*ak)),B=Math.ceil(Math.min(a,Math.max(0,(U-E)*ak))),Q=(m==="Dense"?0:aj[J]*al);if(z.dataset_type==="bai"){A.fillStyle=f;if(M[4] instanceof Array){var t=Math.floor(Math.max(0,(M[4][0]-E)*ak)),I=Math.ceil(Math.min(a,Math.max(0,(M[4][1]-E)*ak))),r=Math.floor(Math.max(0,(M[5][0]-E)*ak)),p=Math.ceil(Math.min(a,Math.max(0,(M[5][1]-E)*ak)));if(M[4][1]>=E&&M[4][0]<=ad){this.rect_or_text(A,ak,E,ad,M[4][0],M[4][2],t+P,I-t,Q)}if(M[5][1]>=E&&M[5][0]<=ad){this.rect_or_text(A,ak,E,ad,M[5][0],M[5][2],r+P,p-r,Q)}if(r>I){A.fillStyle="#999";A.fillRect(I+P,Q+5,r-I,1)}}else{A.fillStyle=f;this.rect_or_text(A,ak,E,ad,ah,F,W+P,B-W,Q)}if(m!=="Dense"&&!V&&ah>E){A.fillStyle=this.prefs
.label_color;if(h===0&&W-A.measureText(F).width<0){A.textAlign="left";A.fillText(J,B+2+P,Q+8)}else{A.textAlign="right";A.fillText(J,W-2+P,Q+8)}A.fillStyle=f}}else{if(z.dataset_type==="interval_index"){if(V){A.fillRect(W+P,Q+5,B-W,1)}else{var v=M[4],O=M[5],Y=M[6],e=M[7];var u,aa,G=null,am=null;if(O&&Y){G=Math.floor(Math.max(0,(O-E)*ak));am=Math.ceil(Math.min(a,Math.max(0,(Y-E)*ak)))}if(m!=="Dense"&&F!==undefined&&ah>E){A.fillStyle=Z;if(h===0&&W-A.measureText(F).width<0){A.textAlign="left";A.fillText(F,B+2+P,Q+8)}else{A.textAlign="right";A.fillText(F,W-2+P,Q+8)}A.fillStyle=f}if(e){if(v){if(v=="+"){A.fillStyle=RIGHT_STRAND}else{if(v=="-"){A.fillStyle=LEFT_STRAND}}A.fillRect(W+P,Q,B-W,10);A.fillStyle=f}for(var ae=0,d=e.length;ae<d;ae++){var o=e[ae],c=Math.floor(Math.max(0,(o[0]-E)*ak)),N=Math.ceil(Math.min(a,Math.max((o[1]-E)*ak)));if(c>N){continue}u=5;aa=3;A.fillRect(c+P,Q+aa,N-c,u);if(G!==undefined&&!(c>am||N<G)){u=9;aa=1;var ab=Math.max(c,G),q=Math.min(N,am);A.fillRect(ab+P,Q
+aa,q-ab,u)}}}else{u=9;aa=1;A.fillRect(W+P,Q+aa,B-W,u);if(M.strand){if(M.strand=="+"){A.fillStyle=RIGHT_STRAND_INV}else{if(M.strand=="-"){A.fillStyle=LEFT_STRAND_INV}}A.fillRect(W+P,Q,B-W,10);A.fillStyle=prefs.block_color}}}}}af++}}n.append(L);return L},gen_options:function(j){var a=$("<div />").addClass("form-row");var e="track_"+j+"_block_color",l=$("<label />").attr("for",e).text("Block color:"),m=$("<input />").attr("id",e).attr("name",e).val(this.prefs.block_color),k="track_"+j+"_label_color",g=$("<label />").attr("for",k).text("Text color:"),h=$("<input />").attr("id",k).attr("name",k).val(this.prefs.label_color),f="track_"+j+"_show_count",c=$("<label />").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div />").append(b).append(c);return a.append(l).append(m).append(g).append(h).append(d)},update_options:function(e){var b=$("#track_"+e+"_block_
color").val(),d=$("#track_"+e+"_label_color").val(),c=$("#track_"+e+"_mode option:selected").val(),a=$("#track_"+e+"_show_count").attr("checked");if(b!==this.prefs.block_color||d!==this.prefs.label_color||a!==this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=d;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(d,b,a,c){FeatureTrack.call(this,d,b,a,c);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
+var DENSITY=200,FEATURE_LEVELS=10,DATA_ERROR="There was an error in indexing this dataset. ",DATA_NOCONVERTER="A converter for this dataset is not installed. Please check your datatypes_conf.xml file.",DATA_NONE="No data for this chrom/contig.",DATA_PENDING="Currently indexing... please wait",DATA_LOADING="Loading data...",CACHED_TILES_FEATURE=10,CACHED_TILES_LINE=30,CACHED_DATA=5,CONTEXT=$("<canvas></canvas>").get(0).getContext("2d"),PX_PER_CHAR=CONTEXT.measureText("A").width,RIGHT_STRAND,LEFT_STRAND;var right_img=new Image();right_img.src=image_path+"/visualization/strand_right.png";right_img.onload=function(){RIGHT_STRAND=CONTEXT.createPattern(right_img,"repeat")};var left_img=new Image();left_img.src=image_path+"/visualization/strand_left.png";left_img.onload=function(){LEFT_STRAND=CONTEXT.createPattern(left_img,"repeat")};var right_img_inv=new Image();right_img_inv.src=image_path+"/visualization/strand_right_inv.png";right_img_inv.onload=function(){RIGHT_STRAND_INV=CONT
EXT.createPattern(right_img_inv,"repeat")};var left_img_inv=new Image();left_img_inv.src=image_path+"/visualization/strand_left_inv.png";left_img_inv.onload=function(){LEFT_STRAND_INV=CONTEXT.createPattern(left_img_inv,"repeat")};var Cache=function(a){this.num_elements=a;this.clear()};$.extend(Cache.prototype,{get:function(b){var a=this.key_ary.indexOf(b);if(a!=-1){this.key_ary.splice(a,1);this.key_ary.push(b)}return this.obj_cache[b]},set:function(b,c){if(!this.obj_cache[b]){if(this.key_ary.length>=this.num_elements){var a=this.key_ary.shift();delete this.obj_cache[a]}this.key_ary.push(b)}this.obj_cache[b]=c;return c},clear:function(){this.obj_cache={};this.key_ary=[]}});var View=function(a,c,e,d,b){this.container=a;this.vis_id=d;this.dbkey=b;this.title=e;this.chrom=c;this.tracks=[];this.label_tracks=[];this.max_low=0;this.max_high=0;this.track_id_counter=0;this.zoom_factor=3;this.min_separation=30;this.has_changes=false;this.init();this.reset()};$.extend(View.prototype,{in
it:function(){var b=this.container,a=this;this.top_labeltrack=$("<div/>").addClass("top-labeltrack").appendTo(b);this.content_div=$("<div/>").addClass("content").css("position","relative").appendTo(b);this.viewport_container=$("<div/>").addClass("viewport-container").addClass("viewport-container").appendTo(this.content_div);this.viewport=$("<div/>").addClass("viewport").appendTo(this.viewport_container);this.nav_container=$("<div/>").addClass("nav-container").appendTo(b);this.nav_labeltrack=$("<div/>").addClass("nav-labeltrack").appendTo(this.nav_container);this.nav=$("<div/>").addClass("nav").appendTo(this.nav_container);this.overview=$("<div/>").addClass("overview").appendTo(this.nav);this.overview_viewport=$("<div/>").addClass("overview-viewport").appendTo(this.overview);this.overview_box=$("<div/>").addClass("overview-box").appendTo(this.overview_viewport);this.nav_controls=$("<div/>").addClass("nav-controls").appendTo(this.nav);this.chrom_form=$("<form/>").attr("action"
,function(){void (0)}).appendTo(this.nav_controls);this.chrom_select=$("<select/>").attr({name:"chrom"}).css("width","15em").addClass("no-autocomplete").append("<option value=''>Loading</option>").appendTo(this.chrom_form);this.low_input=$("<input/>").addClass("low").css("width","10em").appendTo(this.chrom_form);$("<span/>").text(" - ").appendTo(this.chrom_form);this.high_input=$("<input/>").addClass("high").css("width","10em").appendTo(this.chrom_form);if(this.vis_id!==undefined){this.hidden_input=$("<input/>").attr("type","hidden").val(this.vis_id).appendTo(this.chrom_form)}this.zi_link=$("<a/>").click(function(){a.zoom_in();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom.png" />').appendTo(this.chrom_form);this.zo_link=$("<a/>").click(function(){a.zoom_out();a.redraw()}).html('<img src="'+image_path+'/fugue/magnifier-zoom-out.png" />').appendTo(this.chrom_form);$.ajax({url:chrom_url,data:(this.vis_id!==undefined?{vis_id:this.vis_id}:{dbkey:this.dbkey}),da
taType:"json",success:function(c){if(c.reference){a.add_label_track(new ReferenceTrack(a))}a.chrom_data=c.chrom_info;var e='<option value="">Select Chrom/Contig</option>';for(i in a.chrom_data){var d=a.chrom_data[i]["chrom"];e+='<option value="'+d+'">'+d+"</option>"}a.chrom_select.html(e);a.chrom_select.bind("change",function(){a.chrom=a.chrom_select.val();var g=$.grep(a.chrom_data,function(j,k){return j.chrom===a.chrom})[0];a.max_high=(g.len!==undefined?g.len:0);a.reset();a.redraw(true);for(var h in a.tracks){var f=a.tracks[h];if(f.init){f.init()}}a.redraw()})},error:function(){alert("Could not load chroms for this dbkey:",a.dbkey)}});this.content_div.bind("dblclick",function(c){a.zoom_in(c.pageX,this.viewport_container)});this.overview_box.bind("dragstart",function(c){this.current_x=c.offsetX}).bind("drag",function(c){var f=c.offsetX-this.current_x;this.current_x=c.offsetX;var d=Math.round(f/a.viewport_container.width()*(a.max_high-a.max_low));a.move_delta(-d)});this.viewp
ort_container.bind("dragstart",function(c){this.original_low=a.low;this.current_height=c.clientY;this.current_x=c.offsetX}).bind("drag",function(f){var c=$(this);var h=f.offsetX-this.current_x;var d=c.scrollTop()-(f.clientY-this.current_height);if(d<c.get(0).scrollHeight-c.height()){c.scrollTop(d)}this.current_height=f.clientY;this.current_x=f.offsetX;var g=Math.round(h/a.viewport_container.width()*(a.high-a.low));a.move_delta(g)});this.top_labeltrack.bind("dragstart",function(c){this.drag_origin_x=c.clientX;this.drag_origin_pos=c.clientX/a.viewport_container.width()*(a.high-a.low)+a.low;this.drag_div=$("<div />").css({height:a.content_div.height(),top:"0px",position:"absolute","background-color":"#cfc",border:"1px solid #6a6",opacity:0.5}).appendTo($(this))}).bind("drag",function(h){var d=Math.min(h.clientX,this.drag_origin_x),c=Math.max(h.clientX,this.drag_origin_x),g=(a.high-a.low),f=a.viewport_container.width();a.low_input.val(commatize(Math.round(d/f*g)+a.low));a.high_i
nput.val(commatize(Math.round(c/f*g)+a.low));this.drag_div.css({left:d+"px",width:(c-d)+"px"})}).bind("dragend",function(j){var d=Math.min(j.clientX,this.drag_origin_x),c=Math.max(j.clientX,this.drag_origin_x),g=(a.high-a.low),f=a.viewport_container.width(),h=a.low;a.low=Math.round(d/f*g)+h;a.high=Math.round(c/f*g)+h;this.drag_div.remove();a.redraw()});this.add_label_track(new LabelTrack(this,this.top_labeltrack));this.add_label_track(new LabelTrack(this,this.nav_labeltrack))},move_delta:function(c){var a=this;var b=a.high-a.low;if(a.low-c<a.max_low){a.low=a.max_low;a.high=a.max_low+b}else{if(a.high-c>a.max_high){a.high=a.max_high;a.low=a.max_high-b}else{a.high-=c;a.low-=c}}a.redraw()},add_track:function(a){a.view=this;a.track_id=this.track_id_counter;this.tracks.push(a);if(a.init){a.init()}a.container_div.attr("id","track_"+a.track_id);this.track_id_counter+=1},add_label_track:function(a){a.view=this;this.label_tracks.push(a)},remove_track:function(a){this.has_changes=true;
a.container_div.fadeOut("slow",function(){$(this).remove()});delete this.tracks[this.tracks.indexOf(a)]},update_options:function(){this.has_changes=true;var b=$("ul#sortable-ul").sortable("toArray");for(var c in b){var e=b[c].split("_li")[0].split("track_")[1];this.viewport.append($("#track_"+e))}for(var d in view.tracks){var a=view.tracks[d];if(a&&a.update_options){a.update_options(d)}}},reset:function(){this.low=this.max_low;this.high=this.max_high;this.viewport_container.find(".yaxislabel").remove()},redraw:function(f){var d=this.high-this.low,b=this.low,e=this.high;if(b<this.max_low){b=this.max_low}if(e>this.max_high){e=this.max_high}if(this.high!==0&&d<this.min_separation){e=b+this.min_separation}this.low=Math.floor(b);this.high=Math.ceil(e);this.resolution=Math.pow(10,Math.ceil(Math.log((this.high-this.low)/200)/Math.LN10));this.zoom_res=Math.pow(FEATURE_LEVELS,Math.max(0,Math.ceil(Math.log(this.resolution,FEATURE_LEVELS)/Math.log(FEATURE_LEVELS))));this.overview_box.c
ss({left:(this.low/(this.max_high-this.max_low))*this.overview_viewport.width(),width:Math.max(12,(this.high-this.low)/(this.max_high-this.max_low)*this.overview_viewport.width())}).show();this.low_input.val(commatize(this.low));this.high_input.val(commatize(this.high));if(!f){for(var c=0,a=this.tracks.length;c<a;c++){if(this.tracks[c]&&this.tracks[c].enabled){this.tracks[c].draw()}}for(var c=0,a=this.label_tracks.length;c<a;c++){this.label_tracks[c].draw()}}},zoom_in:function(b,c){if(this.max_high===0||this.high-this.low<this.min_separation){return}var d=this.high-this.low,e=d/2+this.low,a=(d/this.zoom_factor)/2;if(b){e=b/this.viewport_container.width()*(this.high-this.low)+this.low}this.low=Math.round(e-a);this.high=Math.round(e+a);this.redraw()},zoom_out:function(){if(this.max_high===0){return}var b=this.high-this.low,c=b/2+this.low,a=(b*this.zoom_factor)/2;this.low=Math.round(c-a);this.high=Math.round(c+a);this.redraw()}});var Track=function(b,a,c){this.name=b;this.paren
t_element=c;this.view=a;this.init_global()};$.extend(Track.prototype,{init_global:function(){this.header_div=$("<div class='track-header'>").text(this.name);this.content_div=$("<div class='track-content'>");this.container_div=$("<div />").addClass("track").append(this.header_div).append(this.content_div);this.parent_element.append(this.container_div)},init_each:function(c,b){var a=this;a.enabled=false;a.data_queue={};a.tile_cache.clear();a.data_cache.clear();if(!a.content_div.text()){a.content_div.text(DATA_LOADING)}a.container_div.removeClass("nodata error pending");if(a.view.chrom){$.getJSON(data_url,c,function(d){if(!d||d==="error"||d.kind==="error"){a.container_div.addClass("error");a.content_div.text(DATA_ERROR);if(d.message){var f=a.view.tracks.indexOf(a);var e=$("<a href='javascript:void(0);'></a>").attr("id",f+"_error");e.text("Click to view error");$("#"+f+"_error").live("click",function(){show_modal("Trackster Error","<pre>"+d.message+"</pre>",{Close:hide_modal})})
;a.content_div.append(e)}}else{if(d==="no converter"){a.container_div.addClass("error");a.content_div.text(DATA_NOCONVERTER)}else{if(d.data!==undefined&&(d.data===null||d.data.length===0)){a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}else{if(d==="pending"){a.container_div.addClass("pending");a.content_div.text(DATA_PENDING);setTimeout(function(){a.init()},5000)}else{a.content_div.text("");a.content_div.css("height",a.height_px+"px");a.enabled=true;b(d);a.draw()}}}}})}else{a.container_div.addClass("nodata");a.content_div.text(DATA_NONE)}}});var TiledTrack=function(){this.left_offset=200};$.extend(TiledTrack.prototype,Track.prototype,{draw:function(){var j=this.view.low,e=this.view.high,f=e-j,d=this.view.resolution;var l=$("<div style='position: relative;'></div>"),m=this.content_div.width()/f,h;this.content_div.children(":first").remove();this.content_div.append(l),this.max_height=0;var a=Math.floor(j/d/DENSITY);while((a*DENSITY*d)<e){var k=this.content_di
v.width()+"_"+m+"_"+a;var c=this.tile_cache.get(k);if(c){var g=a*DENSITY*d;var b=(g-j)*m;if(this.left_offset){b-=this.left_offset}c.css({left:b});l.append(c);this.max_height=Math.max(this.max_height,c.height());this.content_div.css("height",this.max_height+"px")}else{this.delayed_draw(this,k,j,e,a,d,l,m)}a+=1}},delayed_draw:function(c,e,a,f,b,d,g,h){setTimeout(function(){if(!(a>c.view.high||f<c.view.low)){tile_element=c.draw_tile(d,b,g,h);if(tile_element){c.tile_cache.set(e,tile_element);c.max_height=Math.max(c.max_height,tile_element.height());c.content_div.css("height",c.max_height+"px")}}},50)}});var LabelTrack=function(a,b){Track.call(this,null,a,b);this.track_type="LabelTrack";this.hidden=true;this.container_div.addClass("label-track")};$.extend(LabelTrack.prototype,Track.prototype,{draw:function(){var c=this.view,d=c.high-c.low,g=Math.floor(Math.pow(10,Math.floor(Math.log(d)/Math.log(10)))),a=Math.floor(c.low/g)*g,e=this.content_div.width(),b=$("<div style='position: r
elative; height: 1.3em;'></div>");while(a<c.high){var f=(a-c.low)/d*e;b.append($("<div class='label'>"+commatize(a)+"</div>").css({position:"absolute",left:f-1}));a+=g}this.content_div.children(":first").remove();this.content_div.append(b)}});var ReferenceTrack=function(a){this.track_type="ReferenceTrack";Track.call(this,null,a,a.nav_labeltrack);TiledTrack.call(this);this.hidden=true;this.height_px=12;this.container_div.addClass("reference-track");this.dummy_canvas=$("<canvas></canvas>").get(0).getContext("2d");this.data_queue={};this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE)};$.extend(ReferenceTrack.prototype,TiledTrack.prototype,{get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:reference_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dbkey:this.view.dbkey},success:function(g){c.data_cache.set(e,g);delete c.data_queue[e];c.draw()},error:functio
n(h,g,j){console.log(h,g,j)}})}},draw_tile:function(f,b,k,o){var g=b*DENSITY*f,d=DENSITY*f,e=$("<canvas class='tile'></canvas>"),n=e.get(0).getContext("2d"),j=f+"_"+b;if(o>PX_PER_CHAR){if(this.data_cache.get(j)===undefined){this.get_data(f,b);return}var m=this.data_cache.get(j);if(m===null){return}e.get(0).width=Math.ceil(d*o+this.left_offset);e.get(0).height=this.height_px;e.css({position:"absolute",top:0,left:(g-this.view.low)*o+this.left_offset});for(var h=0,l=m.length;h<l;h++){var a=Math.round(h*o);n.fillText(m[h],a+this.left_offset,10)}k.append(e);return e}}});var LineTrack=function(d,b,a,c){this.track_type="LineTrack";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=100;this.dataset_id=a;this.data_cache=new Cache(CACHED_DATA);this.tile_cache=new Cache(CACHED_TILES_LINE);this.prefs={min_value:undefined,max_value:undefined,mode:"Line"};if(c.min_value!==undefined){this.prefs.min_value=c.min_value}if(c.max_value!==undefined){this.prefs.max_val
ue=c.max_value}if(c.mode!==undefined){this.prefs.mode=c.mode}};$.extend(LineTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.tracks.indexOf(a);a.vertical_range=undefined;this.init_each({stats:true,chrom:a.view.chrom,low:null,high:null,dataset_id:a.dataset_id},function(c){a.container_div.addClass("line-track");data=c.data;if(isNaN(parseFloat(a.prefs.min_value))||isNaN(parseFloat(a.prefs.max_value))){a.prefs.min_value=data.min;a.prefs.max_value=data.max;$("#track_"+b+"_minval").val(a.prefs.min_value);$("#track_"+b+"_maxval").val(a.prefs.max_value)}a.vertical_range=a.prefs.max_value-a.prefs.min_value;a.total_frequency=data.total_frequency;$("#linetrack_"+b+"_minval").remove();$("#linetrack_"+b+"_maxval").remove();var e=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_minval").text(a.prefs.min_value);var d=$("<div />").addClass("yaxislabel").attr("id","linetrack_"+b+"_maxval").text(a.prefs.max_value);d.css({position:"relative",top:"25px",le
ft:"10px"});d.prependTo(a.container_div);e.css({position:"relative",top:a.height_px+55+"px",left:"10px"});e.prependTo(a.container_div)})},get_data:function(d,b){var c=this,a=b*DENSITY*d,f=(b+1)*DENSITY*d,e=d+"_"+b;if(!c.data_queue[e]){c.data_queue[e]=true;$.ajax({url:data_url,dataType:"json",data:{chrom:this.view.chrom,low:a,high:f,dataset_id:this.dataset_id,resolution:this.view.resolution},success:function(g){data=g.data;c.data_cache.set(e,data);delete c.data_queue[e];c.draw()},error:function(h,g,j){console.log(h,g,j)}})}},draw_tile:function(p,r,c,e){if(this.vertical_range===undefined){return}var s=r*DENSITY*p,a=DENSITY*p,b=$("<canvas class='tile'></canvas>"),v=p+"_"+r;if(this.data_cache.get(v)===undefined){this.get_data(p,r);return}var j=this.data_cache.get(v);if(j===null){return}b.css({position:"absolute",top:0,left:(s-this.view.low)*e});b.get(0).width=Math.ceil(a*e+this.left_offset);b.get(0).height=this.height_px;var o=b.get(0).getContext("2d"),k=false,l=this.prefs.min_v
alue,g=this.prefs.max_value,n=this.vertical_range,t=this.total_frequency,d=this.height_px,m=this.prefs.mode;o.beginPath();if(data.length>1){var f=Math.ceil((data[1][0]-data[0][0])*e)}else{var f=10}var u,h;for(var q=0;q<data.length;q++){u=(data[q][0]-s)*e;h=data[q][1];if(m=="Intensity"){if(h===null){continue}if(h<=l){h=l}else{if(h>=g){h=g}}h=255-Math.floor((h-l)/n*255);o.fillStyle="rgb("+h+","+h+","+h+")";o.fillRect(u,0,f,this.height_px)}else{if(h===null){if(k&&m==="Filled"){o.lineTo(u,d)}k=false;continue}else{if(h<=l){h=l}else{if(h>=g){h=g}}h=Math.round(d-(h-l)/n*d);if(k){o.lineTo(u,h)}else{k=true;if(m==="Filled"){o.moveTo(u,d);o.lineTo(u,h)}else{o.moveTo(u,h)}}}}}if(m==="Filled"){if(k){o.lineTo(u,d)}o.fill()}else{o.stroke()}c.append(b);return b},gen_options:function(o){var a=$("<div />").addClass("form-row");var h="track_"+o+"_minval",m=$("<label></label>").attr("for",h).text("Min value:"),b=(this.prefs.min_value===undefined?"":this.prefs.min_value),n=$("<input></input>").a
ttr("id",h).val(b),l="track_"+o+"_maxval",g=$("<label></label>").attr("for",l).text("Max value:"),k=(this.prefs.max_value===undefined?"":this.prefs.max_value),f=$("<input></input>").attr("id",l).val(k),e="track_"+o+"_mode",d=$("<label></label>").attr("for",e).text("Display mode:"),j=(this.prefs.mode===undefined?"Line":this.prefs.mode),c=$('<select id="'+e+'"><option value="Line" id="mode_Line">Line</option><option value="Filled" id="mode_Filled">Filled</option><option value="Intensity" id="mode_Intensity">Intensity</option></select>');c.children("#mode_"+j).attr("selected","selected");return a.append(m).append(n).append(g).append(f).append(d).append(c)},update_options:function(d){var a=$("#track_"+d+"_minval").val(),c=$("#track_"+d+"_maxval").val(),b=$("#track_"+d+"_mode option:selected").val();if(a!==this.prefs.min_value||c!==this.prefs.max_value||b!==this.prefs.mode){this.prefs.min_value=parseFloat(a);this.prefs.max_value=parseFloat(c);this.prefs.mode=b;this.vertical_range
=this.prefs.max_value-this.prefs.min_value;$("#linetrack_"+d+"_minval").text(this.prefs.min_value);$("#linetrack_"+d+"_maxval").text(this.prefs.max_value);this.tile_cache.clear();this.draw()}}});var FeatureTrack=function(d,b,a,c){this.track_type="FeatureTrack";Track.call(this,d,b,b.viewport_container);TiledTrack.call(this);this.height_px=0;this.container_div.addClass("feature-track");this.dataset_id=a;this.zo_slots={};this.show_labels_scale=0.001;this.showing_details=false;this.vertical_detail_px=10;this.vertical_nodetail_px=3;this.default_font="9px Monaco, Lucida Console, monospace";this.inc_slots={};this.data_queue={};this.s_e_by_tile={};this.tile_cache=new Cache(CACHED_TILES_FEATURE);this.data_cache=new Cache(20);this.prefs={block_color:"black",label_color:"black",show_counts:false};if(c.block_color!==undefined){this.prefs.block_color=c.block_color}if(c.label_color!==undefined){this.prefs.label_color=c.label_color}if(c.show_counts!==undefined){this.prefs.show_counts=c.sho
w_counts}};$.extend(FeatureTrack.prototype,TiledTrack.prototype,{init:function(){var a=this,b=a.view.max_low+"_"+a.view.max_high;a.mode="Auto";if(a.mode_div){a.mode_div.remove()}this.init_each({low:a.view.max_low,high:a.view.max_high,dataset_id:a.dataset_id,chrom:a.view.chrom,resolution:this.view.resolution},function(d){a.mode_div=$("<div class='right-float menubutton popup' />").text("Display Mode");a.header_div.append(a.mode_div);a.mode="Auto";var c=function(e){a.mode_div.text(e);a.mode=e;a.tile_cache.clear();a.draw()};make_popupmenu(a.mode_div,{Auto:function(){c("Auto")},Dense:function(){c("Dense")},Squish:function(){c("Squish")},Pack:function(){c("Pack")}});a.data_cache.set(b,d);a.draw()})},get_data:function(a,d){var b=this,c=a+"_"+d;if(!b.data_queue[c]){b.data_queue[c]=true;$.getJSON(data_url,{chrom:b.view.chrom,low:a,high:d,dataset_id:b.dataset_id,resolution:this.view.resolution,mode:this.mode},function(e){b.data_cache.set(c,e);delete b.data_queue[c];b.draw()})}},incre
mental_slots:function(a,h,c,r){if(!this.inc_slots[a]){this.inc_slots[a]={};this.inc_slots[a].w_scale=1/a;this.inc_slots[a].mode=r;this.s_e_by_tile[a]={}}var n=this.inc_slots[a].w_scale,z=[],l=0,b=$("<canvas></canvas>").get(0).getContext("2d"),o=this.view.max_low;var B=[];if(this.inc_slots[a].mode!==r){delete this.inc_slots[a];this.inc_slots[a]={mode:r,w_scale:n};delete this.s_e_by_tile[a];this.s_e_by_tile[a]={}}for(var w=0,x=h.length;w<x;w++){var g=h[w],m=g[0];if(this.inc_slots[a][m]!==undefined){l=Math.max(l,this.inc_slots[a][m]);B.push(this.inc_slots[a][m])}else{z.push(w)}}for(var w=0,x=z.length;w<x;w++){var g=h[z[w]],m=g[0],s=g[1],d=g[2],q=g[3],e=Math.floor((s-o)*n),f=Math.ceil((d-o)*n);if(q!==undefined&&!c){var t=b.measureText(q).width;if(e-t<0){f+=t}else{e-=t}}var v=0;while(true){var p=true;if(this.s_e_by_tile[a][v]!==undefined){for(var u=0,A=this.s_e_by_tile[a][v].length;u<A;u++){var y=this.s_e_by_tile[a][v][u];if(f>y[0]&&e<y[1]){p=false;break}}}if(p){if(this.s_e_by_ti
le[a][v]===undefined){this.s_e_by_tile[a][v]=[]}this.s_e_by_tile[a][v].push([e,f]);this.inc_slots[a][m]=v;l=Math.max(l,v);break}v++}}return l},rect_or_text:function(n,o,f,m,b,d,k,e,h){n.textAlign="center";var j=Math.round(o/2);if((this.mode==="Pack"||this.mode==="Auto")&&d!==undefined&&o>PX_PER_CHAR){n.fillStyle=this.prefs.block_color;n.fillRect(k,h+1,e,9);n.fillStyle="#eee";for(var g=0,l=d.length;g<l;g++){if(b+g>=f&&b+g<=m){var a=Math.floor(Math.max(0,(b+g-f)*o));n.fillText(d[g],a+this.left_offset+j,h+9)}}}else{n.fillStyle=this.prefs.block_color;n.fillRect(k,h+4,e,3)}},draw_tile:function(X,h,n,ak){var E=h*DENSITY*X,ad=(h+1)*DENSITY*X,D=DENSITY*X;var ae=E+"_"+ad;var z=this.data_cache.get(ae);if(z===undefined){this.data_queue[[E,ad]]=true;this.get_data(E,ad);return}var a=Math.ceil(D*ak),L=$("<canvas class='tile'></canvas>"),Z=this.prefs.label_color,f=this.prefs.block_color,m=this.mode,V=(m==="Squish")||(m==="Dense")&&(m!=="Pack")||(m==="Auto"&&(z.extra_info==="no_detail")),P=
this.left_offset,aj,s,al;if(z.dataset_type==="summary_tree"){s=30}else{if(m==="Dense"){s=15;al=10}else{al=(V?this.vertical_nodetail_px:this.vertical_detail_px);s=this.incremental_slots(this.view.zoom_res,z.data,V,m)*al+15;aj=this.inc_slots[this.view.zoom_res]}}L.css({position:"absolute",top:0,left:(E-this.view.low)*ak-P});L.get(0).width=a+P;L.get(0).height=s;n.parent().css("height",Math.max(this.height_px,s)+"px");var A=L.get(0).getContext("2d");A.fillStyle=f;A.font=this.default_font;A.textAlign="right";if(z.dataset_type=="summary_tree"){var K,H=55,ac=255-H,g=ac*2/3,R=z.data,C=z.max,l=z.avg;if(R.length>2){var b=Math.ceil((R[1][0]-R[0][0])*ak)}else{var b=50}for(var ag=0,w=R.length;ag<w;ag++){var T=Math.ceil((R[ag][0]-E)*ak);var S=R[ag][1];if(!S){continue}K=Math.floor(ac-(S/C)*ac);A.fillStyle="rgb("+K+","+K+","+K+")";A.fillRect(T+P,0,b,20);if(this.prefs.show_counts){if(K>g){A.fillStyle="black"}else{A.fillStyle="#ddd"}A.textAlign="center";A.fillText(R[ag][1],T+P+(b/2),12)}}n.ap
pend(L);return L}var ai=z.data;var af=0;for(var ag=0,w=ai.length;ag<w;ag++){var M=ai[ag],J=M[0],ah=M[1],U=M[2],F=M[3];if(ah<=ad&&U>=E){var W=Math.floor(Math.max(0,(ah-E)*ak)),B=Math.ceil(Math.min(a,Math.max(0,(U-E)*ak))),Q=(m==="Dense"?0:aj[J]*al);if(z.dataset_type==="bai"){A.fillStyle=f;if(M[4] instanceof Array){var t=Math.floor(Math.max(0,(M[4][0]-E)*ak)),I=Math.ceil(Math.min(a,Math.max(0,(M[4][1]-E)*ak))),r=Math.floor(Math.max(0,(M[5][0]-E)*ak)),p=Math.ceil(Math.min(a,Math.max(0,(M[5][1]-E)*ak)));if(M[4][1]>=E&&M[4][0]<=ad){this.rect_or_text(A,ak,E,ad,M[4][0],M[4][2],t+P,I-t,Q)}if(M[5][1]>=E&&M[5][0]<=ad){this.rect_or_text(A,ak,E,ad,M[5][0],M[5][2],r+P,p-r,Q)}if(r>I){A.fillStyle="#999";A.fillRect(I+P,Q+5,r-I,1)}}else{A.fillStyle=f;this.rect_or_text(A,ak,E,ad,ah,F,W+P,B-W,Q)}if(m!=="Dense"&&!V&&ah>E){A.fillStyle=this.prefs.label_color;if(h===0&&W-A.measureText(F).width<0){A.textAlign="left";A.fillText(J,B+2+P,Q+8)}else{A.textAlign="right";A.fillText(J,W-2+P,Q+8)}A.fillStyl
e=f}}else{if(z.dataset_type==="interval_index"){if(V){A.fillRect(W+P,Q+5,B-W,1)}else{var v=M[4],O=M[5],Y=M[6],e=M[7];var u,aa,G=null,am=null;if(O&&Y){G=Math.floor(Math.max(0,(O-E)*ak));am=Math.ceil(Math.min(a,Math.max(0,(Y-E)*ak)))}if(m!=="Dense"&&F!==undefined&&ah>E){A.fillStyle=Z;if(h===0&&W-A.measureText(F).width<0){A.textAlign="left";A.fillText(F,B+2+P,Q+8)}else{A.textAlign="right";A.fillText(F,W-2+P,Q+8)}A.fillStyle=f}if(e){if(v){if(v=="+"){A.fillStyle=RIGHT_STRAND}else{if(v=="-"){A.fillStyle=LEFT_STRAND}}A.fillRect(W+P,Q,B-W,10);A.fillStyle=f}for(var ae=0,d=e.length;ae<d;ae++){var o=e[ae],c=Math.floor(Math.max(0,(o[0]-E)*ak)),N=Math.ceil(Math.min(a,Math.max((o[1]-E)*ak)));if(c>N){continue}u=5;aa=3;A.fillRect(c+P,Q+aa,N-c,u);if(G!==undefined&&!(c>am||N<G)){u=9;aa=1;var ab=Math.max(c,G),q=Math.min(N,am);A.fillRect(ab+P,Q+aa,q-ab,u)}}}else{u=9;aa=1;A.fillRect(W+P,Q+aa,B-W,u);if(M.strand){if(M.strand=="+"){A.fillStyle=RIGHT_STRAND_INV}else{if(M.strand=="-"){A.fillStyle=LEF
T_STRAND_INV}}A.fillRect(W+P,Q,B-W,10);A.fillStyle=prefs.block_color}}}}}af++}}n.append(L);return L},gen_options:function(j){var a=$("<div />").addClass("form-row");var e="track_"+j+"_block_color",l=$("<label />").attr("for",e).text("Block color:"),m=$("<input />").attr("id",e).attr("name",e).val(this.prefs.block_color),k="track_"+j+"_label_color",g=$("<label />").attr("for",k).text("Text color:"),h=$("<input />").attr("id",k).attr("name",k).val(this.prefs.label_color),f="track_"+j+"_show_count",c=$("<label />").attr("for",f).text("Show summary counts"),b=$('<input type="checkbox" style="float:left;"></input>').attr("id",f).attr("name",f).attr("checked",this.prefs.show_counts),d=$("<div />").append(b).append(c);return a.append(l).append(m).append(g).append(h).append(d)},update_options:function(e){var b=$("#track_"+e+"_block_color").val(),d=$("#track_"+e+"_label_color").val(),c=$("#track_"+e+"_mode option:selected").val(),a=$("#track_"+e+"_show_count").attr("checked");if(b!==
this.prefs.block_color||d!==this.prefs.label_color||a!==this.prefs.show_counts){this.prefs.block_color=b;this.prefs.label_color=d;this.prefs.show_counts=a;this.tile_cache.clear();this.draw()}}});var ReadTrack=function(d,b,a,c){FeatureTrack.call(this,d,b,a,c);this.track_type="ReadTrack";this.vertical_detail_px=10;this.vertical_nodetail_px=5};$.extend(ReadTrack.prototype,TiledTrack.prototype,FeatureTrack.prototype,{});
1
0