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
June 2012
- 1 participants
- 98 discussions
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/063a1d690724/
changeset: 063a1d690724
user: jgoecks
date: 2012-06-28 19:31:20
summary: Update backbone-relational lib.
affected #: 1 file
diff -r adc8114131fa700da3b5800d7ba4568bd665c9b5 -r 063a1d690724b3485f41c620f664f11c7390ceef static/scripts/libs/backbone-relational.js
--- a/static/scripts/libs/backbone-relational.js
+++ b/static/scripts/libs/backbone-relational.js
@@ -1,4 +1,4 @@
-/**
+/**
* Backbone-relational.js 0.5.0
* (c) 2011 Paul Uithol
*
@@ -19,15 +19,15 @@
exports = module.exports = Backbone;
}
else {
- var _ = window._;
+ _ = window._;
Backbone = window.Backbone;
exports = window;
}
-
+
Backbone.Relational = {
showWarnings: true
};
-
+
/**
* Semaphore mixin; can be used as both binary and counting.
**/
@@ -116,37 +116,87 @@
* Backbone.Store keeps track of all created (and destruction of) Backbone.RelationalModel.
* Handles lookup for relations.
*/
- Backbone.Store = function() {
+ Backbone.Store = function() {
this._collections = [];
this._reverseRelations = [];
+ this._subModels = [];
+ this._modelScopes = [ exports ];
};
_.extend( Backbone.Store.prototype, Backbone.Events, {
- _collections: null,
- _reverseRelations: null,
+ addModelScope: function( scope ) {
+ this._modelScopes.push( scope );
+ },
+
+ /**
+ * Add a set of subModelTypes to the store, that can be used to resolve the '_superModel'
+ * for a model later in 'setupSuperModel'.
+ *
+ * @param {Backbone.RelationalModel} subModelTypes
+ * @param {Backbone.RelationalModel} superModelType
+ */
+ addSubModels: function( subModelTypes, superModelType ) {
+ this._subModels.push({
+ 'superModelType': superModelType,
+ 'subModels': subModelTypes
+ });
+ },
+
+ /**
+ * Check if the given modelType is registered as another model's subModel. If so, add it to the super model's
+ * '_subModels', and set the modelType's '_superModel', '_subModelTypeName', and '_subModelTypeAttribute'.
+ *
+ * @param {Backbone.RelationalModel} modelType
+ */
+ setupSuperModel: function( modelType ) {
+ _.find( this._subModels, function( subModelDef ) {
+ return _.find( subModelDef.subModels, function( subModelTypeName, typeValue ) {
+ var subModelType = this.getObjectByName( subModelTypeName );
+
+ if ( modelType === subModelType ) {
+ // Set 'modelType' as a child of the found superModel
+ subModelDef.superModelType._subModels[ typeValue ] = modelType;
+
+ // Set '_superModel', '_subModelTypeValue', and '_subModelTypeAttribute' on 'modelType'.
+ modelType._superModel = subModelDef.superModelType;
+ modelType._subModelTypeValue = typeValue;
+ modelType._subModelTypeAttribute = subModelDef.superModelType.prototype.subModelTypeAttribute;
+ return true;
+ }
+ }, this );
+ }, this );
+ },
/**
* Add a reverse relation. Is added to the 'relations' property on model's prototype, and to
* existing instances of 'model' in the store as well.
- * @param {object} relation
+ * @param {Object} relation
* @param {Backbone.RelationalModel} relation.model
* @param {String} relation.type
* @param {String} relation.key
- * @param {String|object} relation.relatedModel
+ * @param {String|Object} relation.relatedModel
*/
addReverseRelation: function( relation ) {
var exists = _.any( this._reverseRelations, function( rel ) {
- return _.all( relation, function( val, key ) {
- return val === rel[ key ];
+ return _.all( relation, function( val, key ) {
+ return val === rel[ key ];
+ });
});
- });
if ( !exists && relation.model && relation.type ) {
this._reverseRelations.push( relation );
- if ( !relation.model.prototype.relations ) {
- relation.model.prototype.relations = [];
- }
- relation.model.prototype.relations.push( relation );
+ var addRelation = function( model, relation ) {
+ if ( !model.prototype.relations ) {
+ model.prototype.relations = [];
+ }
+ model.prototype.relations.push( relation );
+
+ _.each( model._subModels, function( subModel ) {
+ addRelation( subModel, relation );
+ }, this );
+ };
+
+ addRelation( relation.model, relation );
this.retroFitRelation( relation );
}
@@ -154,11 +204,15 @@
/**
* Add a 'relation' to all existing instances of 'relation.model' in the store
- * @param {object} relation
+ * @param {Object} relation
*/
retroFitRelation: function( relation ) {
var coll = this.getCollection( relation.model );
coll.each( function( model ) {
+ if ( !( model instanceof relation.model ) ) {
+ return;
+ }
+
new relation.type( model, relation );
}, this);
},
@@ -169,9 +223,17 @@
* @return {Backbone.Collection} A collection if found (or applicable for 'model'), or null
*/
getCollection: function( model ) {
- var coll = _.detect( this._collections, function( c ) {
- // Check if model is the type itself (a ref to the constructor), or is of type c.model
- return model === c.model || model.constructor === c.model;
+ if ( model instanceof Backbone.RelationalModel ) {
+ model = model.constructor;
+ }
+
+ var rootModel = model;
+ while ( rootModel._superModel ) {
+ rootModel = rootModel._superModel;
+ }
+
+ var coll = _.detect( this._collections, function( c ) {
+ return c.model === rootModel;
});
if ( !coll ) {
@@ -187,22 +249,32 @@
* @return {Object}
*/
getObjectByName: function( name ) {
- var type = _.reduce( name.split( '.' ), function( memo, val ) {
- return memo[ val ];
- }, exports);
- return type !== exports ? type: null;
+ var parts = name.split( '.' ),
+ type = null;
+
+ _.find( this._modelScopes, function( scope ) {
+ type = _.reduce( parts, function( memo, val ) {
+ return memo[ val ];
+ }, scope );
+
+ if ( type && type !== scope ) {
+ return true;
+ }
+ }, this );
+
+ return type;
},
_createCollection: function( type ) {
var coll;
- // If 'type' is an instance, take it's constructor
+ // If 'type' is an instance, take its constructor
if ( type instanceof Backbone.RelationalModel ) {
type = type.constructor;
}
// Type should inherit from Backbone.RelationalModel.
- if ( type.prototype instanceof Backbone.RelationalModel.prototype.constructor ) {
+ if ( type.prototype instanceof Backbone.RelationalModel ) {
coll = new Backbone.Collection();
coll.model = type;
@@ -213,7 +285,7 @@
},
/**
- * Find an id
+ * Find the attribute that is to be used as the `id` on a given object
* @param type
* @param {String|Number|Object|Backbone.RelationalModel} item
*/
@@ -240,7 +312,18 @@
find: function( type, item ) {
var id = this.resolveIdForItem( type, item );
var coll = this.getCollection( type );
- return coll && coll.get( id );
+
+ // Because the found object could be of any of the type's superModel
+ // types, only return it if it's actually of the type asked for.
+ if ( coll ) {
+ var obj = coll.get( id );
+
+ if ( obj instanceof type ) {
+ return obj;
+ }
+ }
+
+ return null;
},
/**
@@ -281,19 +364,19 @@
* are used to regulate addition and removal of models from relations.
*
* @param {Backbone.RelationalModel} instance
- * @param {object} options
+ * @param {Object} options
* @param {string} options.key
* @param {Backbone.RelationalModel.constructor} options.relatedModel
- * @param {Boolean|String} [options.includeInJSON=true] Serialize the given attribute for related model(s)' in toJSON, or just their ids.
+ * @param {Boolean|String} [options.includeInJSON=true] Serialize the given attribute for related model(s)' in toJSON, or just their ids.
* @param {Boolean} [options.createModels=true] Create objects from the contents of keys if the object is not found in Backbone.store.
- * @param {object} [options.reverseRelation] Specify a bi-directional relation. If provided, Relation will reciprocate
+ * @param {Object} [options.reverseRelation] Specify a bi-directional relation. If provided, Relation will reciprocate
* the relation to the 'relatedModel'. Required and optional properties match 'options', except that it also needs
* {Backbone.Relation|String} type ('HasOne' or 'HasMany').
*/
Backbone.Relation = function( instance, options ) {
this.instance = instance;
// Make sure 'options' is sane, and fill with defaults from subclasses and this object's prototype
- options = ( typeof options === 'object' && options ) || {};
+ options = _.isObject( options ) ? options : {};
this.reverseRelation = _.defaults( options.reverseRelation || {}, this.options.reverseRelation );
this.reverseRelation.type = !_.isString( this.reverseRelation.type ) ? this.reverseRelation.type :
Backbone[ this.reverseRelation.type ] || Backbone.Relational.store.getObjectByName( this.reverseRelation.type );
@@ -302,7 +385,7 @@
this.key = this.options.key;
this.keySource = this.options.keySource || this.key;
- this.keyDestination = this.options.keyDestination || this.options.keySource || this.key;
+ this.keyDestination = this.options.keyDestination || this.keySource || this.key;
// 'exports' should be the global object where 'relatedModel' can be found on if given as a string.
this.relatedModel = this.options.relatedModel;
@@ -340,7 +423,7 @@
_.bindAll( this, '_modelRemovedFromCollection', '_relatedModelAdded', '_relatedModelRemoved' );
- if( instance ) {
+ if ( instance ) {
this.initialize();
// When a model in the store is destroyed, check if it is 'this.instance'.
@@ -405,28 +488,28 @@
return false;
}
// Check if the type in 'relatedModel' inherits from Backbone.RelationalModel
- if ( !( m.prototype instanceof Backbone.RelationalModel.prototype.constructor ) ) {
+ if ( !( m.prototype instanceof Backbone.RelationalModel ) ) {
warn && console.warn( 'Relation=%o; model does not inherit from Backbone.RelationalModel (%o)', this, i );
return false;
}
// Check if the type in 'relatedModel' inherits from Backbone.RelationalModel
- if ( !( rm.prototype instanceof Backbone.RelationalModel.prototype.constructor ) ) {
+ if ( !( rm.prototype instanceof Backbone.RelationalModel ) ) {
warn && console.warn( 'Relation=%o; relatedModel does not inherit from Backbone.RelationalModel (%o)', this, rm );
return false;
}
// Check if this is not a HasMany, and the reverse relation is HasMany as well
- if ( this instanceof Backbone.HasMany && this.reverseRelation.type === Backbone.HasMany.prototype.constructor ) {
+ if ( this instanceof Backbone.HasMany && this.reverseRelation.type === Backbone.HasMany ) {
warn && console.warn( 'Relation=%o; relation is a HasMany, and the reverseRelation is HasMany as well.', this );
return false;
}
// Check if we're not attempting to create a duplicate relationship
- if( i && i._relations.length ) {
+ if ( i && i._relations.length ) {
var exists = _.any( i._relations, function( rel ) {
- var hasReverseRelation = this.reverseRelation.key && rel.reverseRelation.key;
- return rel.relatedModel === rm && rel.key === k &&
- ( !hasReverseRelation || this.reverseRelation.key === rel.reverseRelation.key );
- }, this );
+ var hasReverseRelation = this.reverseRelation.key && rel.reverseRelation.key;
+ return rel.relatedModel === rm && rel.key === k &&
+ ( !hasReverseRelation || this.reverseRelation.key === rel.reverseRelation.key );
+ }, this );
if ( exists ) {
warn && console.warn( 'Relation=%o between instance=%o.%s and relatedModel=%o.%s already exists',
@@ -451,12 +534,6 @@
this.instance.release();
},
- createModel: function( item ) {
- if ( this.options.createModels && typeof( item ) === 'object' ) {
- return new this.relatedModel( item );
- }
- },
-
/**
* Determine if a relation (on a different RelationalModel) is the reverse
* relation of the current one.
@@ -482,12 +559,12 @@
// Iterate over 'model', 'this.related.models' (if this.related is a Backbone.Collection), or wrap 'this.related' in an array.
var models = !_.isUndefined( model ) ? [ model ] : this.related && ( this.related.models || [ this.related ] );
_.each( models , function( related ) {
- _.each( related.getRelations(), function( relation ) {
- if ( this._isReverseRelation( relation ) ) {
- reverseRelations.push( relation );
- }
+ _.each( related.getRelations(), function( relation ) {
+ if ( this._isReverseRelation( relation ) ) {
+ reverseRelations.push( relation );
+ }
+ }, this );
}, this );
- }, this );
return reverseRelations;
},
@@ -501,7 +578,7 @@
sanitizeOptions: function( options ) {
options = options ? _.clone( options ) : {};
if ( options.silent ) {
- options = _.extend( {}, options, { silentChange: true } );
+ options.silentChange = true;
delete options.silent;
}
return options;
@@ -516,7 +593,7 @@
unsanitizeOptions: function( options ) {
options = options ? _.clone( options ) : {};
if ( options.silentChange ) {
- options = _.extend( {}, options, { silent: true } );
+ options.silent = true;
delete options.silentChange;
}
return options;
@@ -551,10 +628,9 @@
this.setRelated( model );
// Notify new 'related' object of the new relation.
- var dit = this;
- _.each( dit.getReverseRelations(), function( relation ) {
- relation.addRelated( dit.instance );
- } );
+ _.each( this.getReverseRelations(), function( relation ) {
+ relation.addRelated( this.instance );
+ }, this );
},
findRelated: function( options ) {
@@ -565,15 +641,7 @@
model = item;
}
else if ( item ) {
- // Try to find an instance of the appropriate 'relatedModel' in the store, or create it
- model = Backbone.Relational.store.find( this.relatedModel, item );
-
- if ( model && _.isObject( item ) ) {
- model.set( item, options );
- }
- else if ( !model ) {
- model = this.createModel( item );
- }
+ model = this.relatedModel.findOrCreate( item, { create: this.options.createModels } );
}
return model;
@@ -583,7 +651,7 @@
* If the key is changed, notify old & new reverse relations and initialize the new relation
*/
onChange: function( model, attr, options ) {
- // Don't accept recursive calls to onChange (like onChange->findRelated->createModel->initializeRelations->addRelated->onChange)
+ // Don't accept recursive calls to onChange (like onChange->findRelated->findOrCreate->initializeRelations->addRelated->onChange)
if ( this.isLocked() ) {
return;
}
@@ -691,10 +759,10 @@
// Handle a custom 'collectionType'
this.collectionType = this.options.collectionType;
- if ( _( this.collectionType ).isString() ) {
+ if ( _.isString( this.collectionType ) ) {
this.collectionType = Backbone.Relational.store.getObjectByName( this.collectionType );
}
- if ( !this.collectionType.prototype instanceof Backbone.Collection.prototype.constructor ){
+ if ( !this.collectionType.prototype instanceof Backbone.Collection ){
throw new Error( 'collectionType must inherit from Backbone.Collection' );
}
@@ -710,7 +778,7 @@
},
_getCollectionOptions: function() {
- return _.isFunction( this.options.collectionOptions ) ?
+ return _.isFunction( this.options.collectionOptions ) ?
this.options.collectionOptions( this.instance ) :
this.options.collectionOptions;
},
@@ -737,12 +805,12 @@
if ( this.options.collectionKey ) {
var key = this.options.collectionKey === true ? this.options.reverseRelation.key : this.options.collectionKey;
- if (collection[ key ] && collection[ key ] !== this.instance ) {
+ if ( collection[ key ] && collection[ key ] !== this.instance ) {
if ( Backbone.Relational.showWarnings && typeof console !== 'undefined' ) {
console.warn( 'Relation=%o; collectionKey=%s already exists on collection=%o', this, key, this.options.collectionKey );
}
}
- else if (key) {
+ else if ( key ) {
collection[ key ] = this.instance;
}
}
@@ -768,19 +836,18 @@
// Try to find instances of the appropriate 'relatedModel' in the store
_.each( this.keyContents, function( item ) {
- var model = Backbone.Relational.store.find( this.relatedModel, item );
+ var model = null;
+ if ( item instanceof this.relatedModel ) {
+ model = item;
+ }
+ else {
+ model = this.relatedModel.findOrCreate( item, { create: this.options.createModels } );
+ }
- if ( model && _.isObject( item ) ) {
- model.set( item, options );
- }
- else if ( !model ) {
- model = this.createModel( item );
- }
-
- if ( model && !this.related.getByCid( model ) && !this.related.get( model ) ) {
- models.push( model );
- }
- }, this );
+ if ( model && !this.related.getByCid( model ) && !this.related.get( model ) ) {
+ models.push( model );
+ }
+ }, this );
}
// Add all found 'models' in on go, so 'add' will only be called once (and thus 'sort', etc.)
@@ -816,7 +883,7 @@
if ( this.related instanceof Backbone.Collection ) {
coll = this.related;
- coll.reset( [], { silent: true } );
+ coll.remove( coll.models );
}
else {
coll = this._prepareCollection();
@@ -842,9 +909,9 @@
if ( !this.related.getByCid( model ) && !this.related.get( model ) ) {
// Check if this new model was specified in 'this.keyContents'
var item = _.any( this.keyContents, function( item ) {
- var id = Backbone.Relational.store.resolveIdForItem( this.relatedModel, item );
- return id && id === model.id;
- }, this );
+ var id = Backbone.Relational.store.resolveIdForItem( this.relatedModel, item );
+ return id && id === model.id;
+ }, this );
if ( item ) {
this.related.add( model, options );
@@ -860,7 +927,7 @@
//console.debug('handleAddition called; args=%o', arguments);
// Make sure the model is in fact a valid model before continuing.
// (it can be invalid as a result of failing validation in Backbone.Collection._prepareModel)
- if( !( model instanceof Backbone.Model ) ) {
+ if ( !( model instanceof Backbone.Model ) ) {
return;
}
@@ -883,7 +950,7 @@
*/
handleRemoval: function( model, coll, options ) {
//console.debug('handleRemoval called; args=%o', arguments);
- if( !( model instanceof Backbone.Model ) ) {
+ if ( !( model instanceof Backbone.Model ) ) {
return;
}
@@ -940,6 +1007,9 @@
_deferProcessing: false,
_queue: null,
+ subModelTypeAttribute: 'type',
+ subModelTypes: null,
+
constructor: function( attributes, options ) {
// Nasty hack, for cases like 'model.get( <HasMany key> ).add( item )'.
// Defer 'processQueue', so that when 'Relation.createModels' is used we:
@@ -971,7 +1041,7 @@
this._queue.block();
Backbone.Relational.eventQueue.block();
- Backbone.Model.prototype.constructor.apply( this, arguments );
+ Backbone.Model.apply( this, arguments );
// Try to run the global queue holding external events
Backbone.Relational.eventQueue.unblock();
@@ -1004,7 +1074,7 @@
_.each( this.relations, function( rel ) {
var type = !_.isString( rel.type ) ? rel.type : Backbone[ rel.type ] || Backbone.Relational.store.getObjectByName( rel.type );
- if ( type && type.prototype instanceof Backbone.Relation.prototype.constructor ) {
+ if ( type && type.prototype instanceof Backbone.Relation ) {
new type( this, rel ); // Also pushes the new Relation into _relations
}
else {
@@ -1016,17 +1086,18 @@
this.release();
this.processQueue();
},
-
+
/**
* When new values are set, notify this model's relations (also if options.silent is set).
* (Relation.setRelated locks this model before calling 'set' on it to prevent loops)
*/
updateRelations: function( options ) {
- if( this._isInitialized && !this.isLocked() ) {
+ if ( this._isInitialized && !this.isLocked() ) {
_.each( this._relations, function( rel ) {
- var val = this.attributes[ rel.key ];
+ // Update from data in `rel.keySource` if set, or `rel.key` otherwise
+ var val = this.attributes[ rel.keySource ] || this.attributes[ rel.key ];
if ( rel.related !== val ) {
- this.trigger('relational:change:' + rel.key, this, val, options || {} );
+ this.trigger( 'relational:change:' + rel.key, this, val, options || {} );
}
}, this );
}
@@ -1072,10 +1143,11 @@
/**
* Retrieve related objects.
* @param key {string} The relation key to fetch models for.
- * @param options {object} Options for 'Backbone.Model.fetch' and 'Backbone.sync'.
+ * @param options {Object} Options for 'Backbone.Model.fetch' and 'Backbone.sync'.
+ * @param update {boolean} Whether to force a fetch from the server (updating existing models).
* @return {jQuery.when[]} An array of request objects
*/
- fetchRelated: function( key, options ) {
+ fetchRelated: function( key, options, update ) {
options || ( options = {} );
var setUrl,
requests = [],
@@ -1083,7 +1155,7 @@
keyContents = rel && rel.keyContents,
toFetch = keyContents && _.select( _.isArray( keyContents ) ? keyContents : [ keyContents ], function( item ) {
var id = Backbone.Relational.store.resolveIdForItem( rel.relatedModel, item );
- return id && !Backbone.Relational.store.find( rel.relatedModel, id );
+ return id && ( update || !Backbone.Relational.store.find( rel.relatedModel, id ) );
}, this );
if ( toFetch && toFetch.length ) {
@@ -1091,13 +1163,13 @@
var models = _.map( toFetch, function( item ) {
var model;
- if ( typeof( item ) === 'object' ) {
- model = new rel.relatedModel( item );
+ if ( _.isObject( item ) ) {
+ model = rel.relatedModel.build( item );
}
else {
var attrs = {};
attrs[ rel.relatedModel.prototype.idAttribute ] = item;
- model = new rel.relatedModel( attrs );
+ model = rel.relatedModel.build( attrs );
}
return model;
@@ -1117,9 +1189,9 @@
error: function() {
var args = arguments;
_.each( models, function( model ) {
- model.trigger( 'destroy', model, model.collection, options );
- options.error && options.error.apply( model, args );
- });
+ model.trigger( 'destroy', model, model.collection, options );
+ options.error && options.error.apply( model, args );
+ });
},
url: setUrl
},
@@ -1153,7 +1225,7 @@
// Duplicate backbone's behavior to allow separate key/value parameters, instead of a single 'attributes' object
var attributes;
- if (_.isObject( key ) || key == null) {
+ if ( _.isObject( key ) || key == null ) {
attributes = key;
options = value;
}
@@ -1164,10 +1236,12 @@
var result = Backbone.Model.prototype.set.apply( this, arguments );
- // 'set' is called quite late in 'Backbone.Model.prototype.constructor', but before 'initialize'.
// Ideal place to set up relations :)
if ( !this._isInitialized && !this.isLocked() ) {
+ this.constructor.initializeModelHierarchy();
+
Backbone.Relational.store.register( this );
+
this.initializeRelations();
}
// Update the 'idAttribute' in Backbone.store if; we don't want it to miss an 'id' update due to {silent:true}
@@ -1227,8 +1301,8 @@
}
_.each( this.getRelations(), function( rel ) {
- delete attributes[ rel.key ];
- });
+ delete attributes[ rel.key ];
+ });
return new this.constructor( attributes );
},
@@ -1245,36 +1319,233 @@
this.acquire();
var json = Backbone.Model.prototype.toJSON.call( this );
+ if ( this.constructor._superModel && !( this.constructor._subModelTypeAttribute in json ) ) {
+ json[ this.constructor._subModelTypeAttribute ] = this.constructor._subModelTypeValue;
+ }
+
_.each( this._relations, function( rel ) {
- var value = json[ rel.key ];
+ var value = json[ rel.key ];
- if ( rel.options.includeInJSON === true && value && _.isFunction( value.toJSON ) ) {
- json[ rel.keyDestination ] = value.toJSON();
- }
- else if ( _.isString( rel.options.includeInJSON ) ) {
- if ( value instanceof Backbone.Collection ) {
- json[ rel.keyDestination ] = value.pluck( rel.options.includeInJSON );
+ if ( rel.options.includeInJSON === true) {
+ if ( value && _.isFunction( value.toJSON ) ) {
+ json[ rel.keyDestination ] = value.toJSON();
+ }
+ else {
+ json[ rel.keyDestination ] = null;
+ }
}
- else if ( value instanceof Backbone.Model ) {
- json[ rel.keyDestination ] = value.get( rel.options.includeInJSON );
+ else if ( _.isString( rel.options.includeInJSON ) ) {
+ if ( value instanceof Backbone.Collection ) {
+ json[ rel.keyDestination ] = value.pluck( rel.options.includeInJSON );
+ }
+ else if ( value instanceof Backbone.Model ) {
+ json[ rel.keyDestination ] = value.get( rel.options.includeInJSON );
+ }
+ else {
+ json[ rel.keyDestination ] = null;
+ }
}
- }
- else {
- delete json[ rel.key ];
- }
+ else if ( _.isArray( rel.options.includeInJSON ) ) {
+ if ( value instanceof Backbone.Collection ) {
+ var valueSub = [];
+ value.each( function( model ) {
+ var curJson = {};
+ _.each( rel.options.includeInJSON, function( key ) {
+ curJson[ key ] = model.get( key );
+ });
+ valueSub.push( curJson );
+ });
+ json[ rel.keyDestination ] = valueSub;
+ }
+ else if ( value instanceof Backbone.Model ) {
+ var valueSub = {};
+ _.each( rel.options.includeInJSON, function( key ) {
+ valueSub[ key ] = value.get( key );
+ });
+ json[ rel.keyDestination ] = valueSub;
+ }
+ else {
+ json[ rel.keyDestination ] = null;
+ }
+ }
+ else {
+ delete json[ rel.key ];
+ }
- if ( rel.keyDestination !== rel.key ) {
- delete json[ rel.key ];
- }
- }, this );
+ if ( rel.keyDestination !== rel.key ) {
+ delete json[ rel.key ];
+ }
+ });
this.release();
return json;
}
+ },
+ {
+ setup: function( superModel ) {
+ // We don't want to share a relations array with a parent, as this will cause problems with
+ // reverse relations.
+ this.prototype.relations = ( this.prototype.relations || [] ).slice( 0 );
+
+ this._subModels = {};
+ this._superModel = null;
+
+ // If this model has 'subModelTypes' itself, remember them in the store
+ if ( this.prototype.hasOwnProperty( 'subModelTypes' ) ) {
+ Backbone.Relational.store.addSubModels( this.prototype.subModelTypes, this );
+ }
+ // The 'subModelTypes' property should not be inherited, so reset it.
+ else {
+ this.prototype.subModelTypes = null;
+ }
+
+ // Initialize all reverseRelations that belong to this new model.
+ _.each( this.prototype.relations, function( rel ) {
+ if ( !rel.model ) {
+ rel.model = this;
+ }
+
+ if ( rel.reverseRelation && rel.model === this ) {
+ var preInitialize = true;
+ if ( _.isString( rel.relatedModel ) ) {
+ /**
+ * The related model might not be defined for two reasons
+ * 1. it never gets defined, e.g. a typo
+ * 2. it is related to itself
+ * In neither of these cases do we need to pre-initialize reverse relations.
+ */
+ var relatedModel = Backbone.Relational.store.getObjectByName( rel.relatedModel );
+ preInitialize = relatedModel && ( relatedModel.prototype instanceof Backbone.RelationalModel );
+ }
+
+ var type = !_.isString( rel.type ) ? rel.type : Backbone[ rel.type ] || Backbone.Relational.store.getObjectByName( rel.type );
+ if ( preInitialize && type && type.prototype instanceof Backbone.Relation ) {
+ new type( null, rel );
+ }
+ }
+ }, this );
+ },
+
+ /**
+ * Create a 'Backbone.Model' instance based on 'attributes'.
+ * @param {Object} attributes
+ * @param {Object} [options]
+ * @return {Backbone.Model}
+ */
+ build: function( attributes, options ) {
+ var model = this;
+
+ // 'build' is a possible entrypoint; it's possible no model hierarchy has been determined yet.
+ this.initializeModelHierarchy();
+
+ // Determine what type of (sub)model should be built if applicable.
+ // Lookup the proper subModelType in 'this._subModels'.
+ if ( this._subModels && this.prototype.subModelTypeAttribute in attributes ) {
+ var subModelTypeAttribute = attributes[ this.prototype.subModelTypeAttribute ];
+ var subModelType = this._subModels[ subModelTypeAttribute ];
+ if ( subModelType ) {
+ model = subModelType;
+ }
+ }
+
+ return new model( attributes, options );
+ },
+
+ initializeModelHierarchy: function() {
+ // If we're here for the first time, try to determine if this modelType has a 'superModel'.
+ if ( _.isUndefined( this._superModel ) || _.isNull( this._superModel ) ) {
+ Backbone.Relational.store.setupSuperModel( this );
+
+ // If a superModel has been found, copy relations from the _superModel if they haven't been
+ // inherited automatically (due to a redefinition of 'relations').
+ // Otherwise, make sure we don't get here again for this type by making '_superModel' false so we fail
+ // the isUndefined/isNull check next time.
+ if ( this._superModel ) {
+ //
+ if ( this._superModel.prototype.relations ) {
+ var supermodelRelationsExist = _.any( this.prototype.relations, function( rel ) {
+ return rel.model && rel.model !== this;
+ }, this );
+
+ if ( !supermodelRelationsExist ) {
+ this.prototype.relations = this._superModel.prototype.relations.concat( this.prototype.relations );
+ }
+ }
+ }
+ else {
+ this._superModel = false;
+ }
+ }
+
+ // If we came here through 'build' for a model that has 'subModelTypes', and not all of them have been resolved yet, try to resolve each.
+ if ( this.prototype.subModelTypes && _.keys( this.prototype.subModelTypes ).length !== _.keys( this._subModels ).length ) {
+ _.each( this.prototype.subModelTypes, function( subModelTypeName ) {
+ var subModelType = Backbone.Relational.store.getObjectByName( subModelTypeName );
+ subModelType && subModelType.initializeModelHierarchy();
+ });
+ }
+ },
+
+ /**
+ * Find an instance of `this` type in 'Backbone.Relational.store'.
+ * - If `attributes` is a string or a number, `findOrCreate` will just query the `store` and return a model if found.
+ * - If `attributes` is an object, the model will be updated with `attributes` if found.
+ * Otherwise, a new model is created with `attributes` (unless `options.create` is explicitly set to `false`).
+ * @param {Object|String|Number} attributes Either a model's id, or the attributes used to create or update a model.
+ * @param {Object} [options]
+ * @param {Boolean} [options.create=true]
+ * @return {Backbone.RelationalModel}
+ */
+ findOrCreate: function( attributes, options ) {
+ // Try to find an instance of 'this' model type in the store
+ var model = Backbone.Relational.store.find( this, attributes );
+
+ // If we found an instance, update it with the data in 'item'; if not, create an instance
+ // (unless 'options.create' is false).
+ if ( _.isObject( attributes ) ) {
+ if ( model ) {
+ model.set( attributes, options );
+ }
+ else if ( !options || ( options && options.create !== false ) ) {
+ model = this.build( attributes, options );
+ }
+ }
+
+ return model;
+ }
});
_.extend( Backbone.RelationalModel.prototype, Backbone.Semaphore );
/**
+ * Override Backbone.Collection._prepareModel, so objects will be built using the correct type
+ * if the collection.model has subModels.
+ */
+ Backbone.Collection.prototype.__prepareModel = Backbone.Collection.prototype._prepareModel;
+ Backbone.Collection.prototype._prepareModel = function ( model, options ) {
+ options || (options = {});
+ if ( !( model instanceof Backbone.Model ) ) {
+ var attrs = model;
+ options.collection = this;
+
+ if ( typeof this.model.build !== 'undefined' ) {
+ model = this.model.build( attrs, options );
+ }
+ else {
+ model = new this.model( attrs, options );
+ }
+
+ if ( !model._validate( model.attributes, options ) ) {
+ model = false;
+ }
+ }
+ else if ( !model.collection ) {
+ model.collection = this;
+ }
+
+ return model;
+ }
+
+ /**
* Override Backbone.Collection.add, so objects fetched from the server multiple times will
* update the existing Model. Also, trigger 'relational:add'.
*/
@@ -1289,22 +1560,22 @@
//console.debug( 'calling add on coll=%o; model=%o, options=%o', this, models, options );
_.each( models, function( model ) {
- if ( !( model instanceof Backbone.Model ) ) {
- // Try to find 'model' in Backbone.store. If it already exists, set the new properties on it.
- var existingModel = Backbone.Relational.store.find( this.model, model[ this.model.prototype.idAttribute ] );
- if ( existingModel ) {
- existingModel.set( existingModel.parse ? existingModel.parse( model ) : model, options );
- model = existingModel;
+ if ( !( model instanceof Backbone.Model ) ) {
+ // Try to find 'model' in Backbone.store. If it already exists, set the new properties on it.
+ var existingModel = Backbone.Relational.store.find( this.model, model[ this.model.prototype.idAttribute ] );
+ if ( existingModel ) {
+ existingModel.set( existingModel.parse ? existingModel.parse( model ) : model, options );
+ model = existingModel;
+ }
+ else {
+ model = Backbone.Collection.prototype._prepareModel.call( this, model, options );
+ }
}
- else {
- model = Backbone.Collection.prototype._prepareModel.call( this, model, options );
+
+ if ( model instanceof Backbone.Model && !this.get( model ) && !this.getByCid( model ) ) {
+ modelsToAdd.push( model );
}
- }
-
- if ( model instanceof Backbone.Model && !this.get( model ) && !this.getByCid( model ) ) {
- modelsToAdd.push( model );
- }
- }, this );
+ }, this );
// Add 'models' in a single batch, so the original add will only be called once (and thus 'sort', etc).
@@ -1312,8 +1583,8 @@
add.call( this, modelsToAdd, options );
_.each( modelsToAdd, function( model ) {
- this.trigger('relational:add', model, this, options);
- }, this );
+ this.trigger( 'relational:add', model, this, options );
+ }, this );
}
return this;
@@ -1325,19 +1596,22 @@
var remove = Backbone.Collection.prototype.__remove = Backbone.Collection.prototype.remove;
Backbone.Collection.prototype.remove = function( models, options ) {
options || (options = {});
- if (!_.isArray( models ) ) {
+ if ( !_.isArray( models ) ) {
models = [ models ];
}
+ else {
+ models = models.slice( 0 );
+ }
//console.debug('calling remove on coll=%o; models=%o, options=%o', this, models, options );
_.each( models, function( model ) {
- model = this.getByCid( model ) || this.get( model );
+ model = this.getByCid( model ) || this.get( model );
- if ( model instanceof Backbone.Model ) {
- remove.call( this, model, options );
- this.trigger('relational:remove', model, this, options);
- }
- }, this );
+ if ( model instanceof Backbone.Model ) {
+ remove.call( this, model, options );
+ this.trigger('relational:remove', model, this, options);
+ }
+ }, this );
return this;
};
@@ -1348,7 +1622,18 @@
var reset = Backbone.Collection.prototype.__reset = Backbone.Collection.prototype.reset;
Backbone.Collection.prototype.reset = function( models, options ) {
reset.call( this, models, options );
- this.trigger( 'relational:reset', models, options );
+ this.trigger( 'relational:reset', this, options );
+
+ return this;
+ };
+
+ /**
+ * Override 'Backbone.Collection.sort' to trigger 'relational:reset'.
+ */
+ var sort = Backbone.Collection.prototype.__sort = Backbone.Collection.prototype.sort;
+ Backbone.Collection.prototype.sort = function( options ) {
+ sort.call( this, options );
+ this.trigger( 'relational:reset', this, options );
return this;
};
@@ -1372,35 +1657,12 @@
return this;
};
- // Override .extend() to check for reverseRelations to initialize.
+ // Override .extend() to automatically call .setup()
Backbone.RelationalModel.extend = function( protoProps, classProps ) {
var child = Backbone.Model.extend.apply( this, arguments );
-
- var relations = ( protoProps && protoProps.relations ) || [];
- _.each( relations, function( rel ) {
- if( rel.reverseRelation ) {
- rel.model = child;
-
- var preInitialize = true;
- if ( _.isString( rel.relatedModel ) ) {
- /**
- * The related model might not be defined for two reasons
- * 1. it never gets defined, e.g. a typo
- * 2. it is related to itself
- * In neither of these cases do we need to pre-initialize reverse relations.
- */
- var relatedModel = Backbone.Relational.store.getObjectByName( rel.relatedModel );
- preInitialize = relatedModel && ( relatedModel.prototype instanceof Backbone.RelationalModel.prototype.constructor );
- }
-
- var type = !_.isString( rel.type ) ? rel.type : Backbone[ rel.type ] || Backbone.Relational.store.getObjectByName( rel.type );
- if ( preInitialize && type && type.prototype instanceof Backbone.Relation.prototype.constructor ) {
- new type( null, rel );
- }
- }
- });
+
+ child.setup( this );
return child;
};
-
})();
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
27 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/adc8114131fa/
changeset: adc8114131fa
user: jgoecks
date: 2012-06-27 20:55:54
summary: Use url_for to generate logo URL.
affected #: 3 files
diff -r 8cd9f0ce913260795ee749536face3bd54f1bc62 -r adc8114131fa700da3b5800d7ba4568bd665c9b5 templates/webapps/community/base_panels.mako
--- a/templates/webapps/community/base_panels.mako
+++ b/templates/webapps/community/base_panels.mako
@@ -118,7 +118,7 @@
## Logo, layered over tabs to be clickable
<div class="title">
- <a href="${app.config.get( 'logo_url', '/' )}">
+ <a href="${h.url_for( app.config.get( 'logo_url', '/' ) )}"><img border="0" src="${h.url_for('/static/images/galaxyIcon_noText.png')}">
Galaxy Tool Shed
%if app.config.brand:
diff -r 8cd9f0ce913260795ee749536face3bd54f1bc62 -r adc8114131fa700da3b5800d7ba4568bd665c9b5 templates/webapps/galaxy/base_panels.mako
--- a/templates/webapps/galaxy/base_panels.mako
+++ b/templates/webapps/galaxy/base_panels.mako
@@ -184,7 +184,7 @@
## Logo, layered over tabs to be clickable
<div class="title">
- <a href="${app.config.get( 'logo_url', '/' )}">
+ <a href="${h.url_for( app.config.get( 'logo_url', '/' ) )}"><img border="0" src="${h.url_for('/static/images/galaxyIcon_noText.png')}">
Galaxy
%if app.config.brand:
diff -r 8cd9f0ce913260795ee749536face3bd54f1bc62 -r adc8114131fa700da3b5800d7ba4568bd665c9b5 templates/webapps/reports/base_panels.mako
--- a/templates/webapps/reports/base_panels.mako
+++ b/templates/webapps/reports/base_panels.mako
@@ -27,7 +27,7 @@
</div>
## Logo, layered over tabs to be clickable
<div class="title" style="position: absolute; top: 0; left: 0;">
- <a href="${app.config.get( 'logo_url', '/' )}">
+ <a href="${h.url_for( app.config.get( 'logo_url', '/' ) )}"><img border="0" src="${h.url_for('/static/images/galaxyIcon_noText.png')}" style="width: 26px; vertical-align: top;">
Galaxy Reports
%if app.config.brand:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: Add tipsy config to icon buttons and add tipsy to paramamonster.
by Bitbucket 27 Jun '12
by Bitbucket 27 Jun '12
27 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/8cd9f0ce9132/
changeset: 8cd9f0ce9132
user: jgoecks
date: 2012-06-27 18:12:43
summary: Add tipsy config to icon buttons and add tipsy to paramamonster.
affected #: 3 files
diff -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 -r 8cd9f0ce913260795ee749536face3bd54f1bc62 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -8,10 +8,14 @@
* defines an icon button. Each dictionary must have the following
* elements: icon_class, title, and on_click.
*/
-var create_icon_buttons_menu = function(config) {
+var create_icon_buttons_menu = function(config, global_config) {
+ if (!global_config) { global_config = {}; }
+
// Create and initialize menu.
var buttons = new IconButtonCollection(
- _.map(config, function(button_config) { return new IconButton(button_config); })
+ _.map(config, function(button_config) {
+ return new IconButton(_.extend(button_config, global_config));
+ })
);
return new IconButtonMenuView( {collection: buttons} );
@@ -38,7 +42,8 @@
defaults: {
title: "",
icon_class: "",
- on_click: null
+ on_click: null,
+ tipsy_config: {}
}
});
@@ -60,12 +65,17 @@
var self = this;
this.collection.each(function(button) {
// Create and add icon button to menu.
- $("<a/>").attr('href', 'javascript:void(0)')
+ var elt =
+ $('<a/>').attr('href', 'javascript:void(0)')
.attr('title', button.attributes.title)
.addClass('icon-button menu-button')
.addClass(button.attributes.icon_class)
.appendTo(self.$el)
.click(button.attributes.on_click);
+
+ if (button.attributes.tipsy_config) {
+ elt.tipsy(button.attributes.tipsy_config);
+ }
});
return this;
}
diff -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 -r 8cd9f0ce913260795ee749536face3bd54f1bc62 static/scripts/viz/paramamonster.js
--- a/static/scripts/viz/paramamonster.js
+++ b/static/scripts/viz/paramamonster.js
@@ -294,7 +294,8 @@
icon_class: 'gear track-settings',
on_click: function () {
settings_div.toggle();
- }
+ },
+ tipsy_config: { gravity: 's' }
}
]);
settings_td.prepend(icon_menu.$el);
@@ -390,7 +391,7 @@
var self = this,
menu = create_icon_buttons_menu([
{
- title: 'Add',
+ title: 'Add parameter to tree',
icon_class: 'plus-button',
on_click: function () {
input.set('in_ptree', true);
@@ -400,7 +401,7 @@
},
{
- title: 'Remove',
+ title: 'Remove parameter from tree',
icon_class: 'toggle',
on_click: function() {
// Remove parameter from tree params where name matches clicked paramter.
@@ -409,7 +410,10 @@
single_input_row.show();
}
}
- ]);
+ ],
+ {
+ tipsy_config: {gravity: 's'}
+ });
this.$el.prepend(menu.$el);
// Update input's min, max, number of samples as values change.
diff -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 -r 8cd9f0ce913260795ee749536face3bd54f1bc62 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -177,14 +177,14 @@
{ icon_class: 'cross-circle', title: 'Close', on_click: function() {
window.location = "${h.url_for( controller='visualization', action='list' )}";
} }
- ]);
+ ],
+ {
+ tipsy_config: {gravity: 'n'}
+ });
menu.$el.attr("style", "float: right");
$("#center .unified-panel-header-inner").append(menu.$el);
- // Manual tipsy config because default gravity is S and cannot be changed.
- $(".menu-button").tipsy( {gravity: 'n'} );
-
// Hide bookmarks by default right now.
parent.force_right_panel("hide");
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: jgoecks: (a) Paramamonster implemention; (b) bug fixes and small additions to style sheets; and (c) bug fixes for rerunning tools on complete datasets.
by Bitbucket 27 Jun '12
by Bitbucket 27 Jun '12
27 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/27f54f28e9f1/
changeset: 27f54f28e9f1
user: jgoecks
date: 2012-06-27 16:51:20
summary: (a) Paramamonster implemention; (b) bug fixes and small additions to style sheets; and (c) bug fixes for rerunning tools on complete datasets.
affected #: 10 files
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 lib/galaxy/web/api/tools.py
--- a/lib/galaxy/web/api/tools.py
+++ b/lib/galaxy/web/api/tools.py
@@ -133,8 +133,9 @@
# Run tool on region if region is specificied.
run_on_regions = False
- regions = from_json_string( payload.get( 'regions', None ) )
+ regions = payload.get( 'regions', None )
if regions:
+ regions = from_json_string( regions )
if isinstance( regions, dict ):
# Regions is a single region.
regions = [ GenomeRegion.from_dict( regions ) ]
@@ -256,7 +257,8 @@
# Set input datasets for tool. If running on regions, extract and use subset
# when possible.
#
- regions_str = ",".join( [ str( r ) for r in regions ] )
+ if run_on_regions:
+ regions_str = ",".join( [ str( r ) for r in regions ] )
for jida in original_job.input_datasets:
# If param set previously by config actions, do nothing.
if jida.name in params_set:
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/june_2007_style/base.less
--- a/static/june_2007_style/base.less
+++ b/static/june_2007_style/base.less
@@ -650,7 +650,7 @@
}
div.form-row-input {
- width: 300px;
+ width: 90%;
float: left;
}
@@ -696,7 +696,7 @@
select, textarea, input[type="text"], input[type="file"], input[type="password"] {
// -webkit-box-sizing: border-box;
- max-width: 300px;
+ max-width: 90%;
}
textarea, input[type="text"], input[type="password"] {
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/june_2007_style/base_sprites.less.tmpl
--- a/static/june_2007_style/base_sprites.less.tmpl
+++ b/static/june_2007_style/base_sprites.less.tmpl
@@ -52,6 +52,10 @@
}
.icon-button.toggle {
-sprite-group: fugue;
+ -sprite-image: fugue/toggle-bw.png;
+}
+.icon-button.toggle:hover {
+ -sprite-group: fugue;
-sprite-image: fugue/toggle.png;
}
.icon-button.arrow-circle {
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/june_2007_style/blue/base.css
--- a/static/june_2007_style/blue/base.css
+++ b/static/june_2007_style/blue/base.css
@@ -742,23 +742,24 @@
.icon-button.tag--plus{background:url(fugue.png) no-repeat 0px -52px;}
.icon-button.toggle-expand{background:url(fugue.png) no-repeat 0px -78px;}
.icon-button.toggle{background:url(fugue.png) no-repeat 0px -104px;}
-.icon-button.arrow-circle{background:url(fugue.png) no-repeat 0px -130px;}
-.icon-button.chevron{background:url(fugue.png) no-repeat 0px -156px;}
-.icon-button.bug{background:url(fugue.png) no-repeat 0px -182px;}
-.icon-button.disk{background:url(fugue.png) no-repeat 0px -208px;}
-.icon-button.information{background:url(fugue.png) no-repeat 0px -234px;}
-.icon-button.annotate{background:url(fugue.png) no-repeat 0px -260px;}
-.icon-button.go-to-full-screen{background:url(fugue.png) no-repeat 0px -286px;}
-.icon-button.import{background:url(fugue.png) no-repeat 0px -312px;}
-.icon-button.plus-button{background:url(fugue.png) no-repeat 0px -338px;}
-.icon-button.plus-button:hover{background:url(fugue.png) no-repeat 0px -364px;}
-.icon-button.gear{background:url(fugue.png) no-repeat 0px -390px;}
-.icon-button.chart_curve{background:url(fugue.png) no-repeat 0px -416px;}
-.icon-button.disk--arrow{background:url(fugue.png) no-repeat 0px -442px;}
-.icon-button.disk--arrow:hover{background:url(fugue.png) no-repeat 0px -468px;}
-.icon-button.cross-circle{background:url(fugue.png) no-repeat 0px -494px;}
-.icon-button.cross-circle:hover{background:url(fugue.png) no-repeat 0px -520px;}
-.text-and-autocomplete-select{background:url(fugue.png) no-repeat right -546px;}
+.icon-button.toggle:hover{background:url(fugue.png) no-repeat 0px -130px;}
+.icon-button.arrow-circle{background:url(fugue.png) no-repeat 0px -156px;}
+.icon-button.chevron{background:url(fugue.png) no-repeat 0px -182px;}
+.icon-button.bug{background:url(fugue.png) no-repeat 0px -208px;}
+.icon-button.disk{background:url(fugue.png) no-repeat 0px -234px;}
+.icon-button.information{background:url(fugue.png) no-repeat 0px -260px;}
+.icon-button.annotate{background:url(fugue.png) no-repeat 0px -286px;}
+.icon-button.go-to-full-screen{background:url(fugue.png) no-repeat 0px -312px;}
+.icon-button.import{background:url(fugue.png) no-repeat 0px -338px;}
+.icon-button.plus-button{background:url(fugue.png) no-repeat 0px -364px;}
+.icon-button.plus-button:hover{background:url(fugue.png) no-repeat 0px -390px;}
+.icon-button.gear{background:url(fugue.png) no-repeat 0px -416px;}
+.icon-button.chart_curve{background:url(fugue.png) no-repeat 0px -442px;}
+.icon-button.disk--arrow{background:url(fugue.png) no-repeat 0px -468px;}
+.icon-button.disk--arrow:hover{background:url(fugue.png) no-repeat 0px -494px;}
+.icon-button.cross-circle{background:url(fugue.png) no-repeat 0px -520px;}
+.icon-button.cross-circle:hover{background:url(fugue.png) no-repeat 0px -546px;}
+.text-and-autocomplete-select{background:url(fugue.png) no-repeat right -572px;}
div.historyItem-error .state-icon{background:url(history-states.png) no-repeat 0px 0px;}
div.historyItem-empty .state-icon{background:url(history-states.png) no-repeat 0px -25px;}
div.historyItem-queued .state-icon{background:url(history-states.png) no-repeat 0px -50px;}
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/june_2007_style/blue/fugue.png
Binary file static/june_2007_style/blue/fugue.png has changed
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/scripts/mvc/tools.js
--- a/static/scripts/mvc/tools.js
+++ b/static/scripts/mvc/tools.js
@@ -52,6 +52,26 @@
],
urlRoot: galaxy_paths.get('tool_url'),
+
+ /**
+ * Returns object copy, optionally including only inputs that can be sampled.
+ */
+ copy: function(only_samplable_inputs) {
+ var copy = new Tool(this.toJSON());
+
+ // Return only samplable inputs if flag is set.
+ if (only_samplable_inputs) {
+ var valid_inputs = new Backbone.Collection();
+ copy.get('inputs').each(function(input) {
+ if (input.get_samples()) {
+ valid_inputs.push(input);
+ }
+ });
+ copy.set('inputs', valid_inputs);
+ }
+
+ return copy;
+ },
apply_search_results: function(results) {
( _.indexOf(results, this.attributes.id) !== -1 ? this.show() : this.hide() );
@@ -81,7 +101,7 @@
* Run tool; returns a Deferred that resolves to the tool's output(s).
*/
run: function() {
- return this._run()
+ return this._run();
},
/**
@@ -94,6 +114,17 @@
regions: JSON.stringify(regions)
});
},
+
+ /**
+ * Returns input dict for tool's inputs.
+ */
+ get_inputs_dict: function() {
+ var input_dict = {};
+ this.get('inputs').each(function(input) {
+ input_dict[input.get('name')] = input.get('value');
+ });
+ return input_dict;
+ },
/**
* Run tool; returns a Deferred that resolves to the tool's output(s).
@@ -102,13 +133,9 @@
_run: function(additional_params) {
// Create payload.
var payload = _.extend({
- tool_id: this.id
- }, additional_params),
- input_dict = {};
- this.get('inputs').each(function(input) {
- input_dict[input.get('name')] = input.get('value');
- });
- payload.inputs = input_dict;
+ tool_id: this.id,
+ inputs: this.get_inputs_dict()
+ }, additional_params);
// Because job may require indexing datasets, use server-side
// deferred to ensure that job is run. Also use deferred that
@@ -145,21 +172,27 @@
label: null,
type: null,
value: null,
+ num_samples: 5
},
initialize: function() {
this.attributes.html = unescape(this.attributes.html);
},
+
+ copy: function() {
+ return new ToolInput(this.toJSON());
+ },
/**
* Returns samples from a tool input.
*/
- get_samples: function(num_samples) {
- var
- type = this.get('type'),
- samples = []
+ get_samples: function() {
+ var type = this.get('type'),
+ samples = null;
if (type === 'number') {
- samples = d3.scale.linear().domain([this.get('min'), this.get('max')]).ticks(num_samples);
+ samples = d3.scale.linear()
+ .domain([this.get('min'), this.get('max')])
+ .ticks(this.get('num_samples'));
}
else if (type === 'select') {
samples = _.map(this.get('options'), function(option) {
@@ -167,24 +200,11 @@
});
}
- return new ParamSamples({
- param: this,
- samples: samples
- });
+ return samples;
}
});
/**
- * A tool and parameter samples.
- */
-var ParamSamples = Backbone.Model.extend({
- defaults: {
- param: null,
- samples: null
- }
-})
-
-/**
* Wrap collection of tools for fast access/manipulation.
*/
var ToolCollection = Backbone.Collection.extend({
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/scripts/mvc/ui.js
--- a/static/scripts/mvc/ui.js
+++ b/static/scripts/mvc/ui.js
@@ -51,6 +51,10 @@
*/
var IconButtonMenuView = Backbone.View.extend({
tagName: 'div',
+
+ initialize: function() {
+ this.render();
+ },
render: function() {
var self = this;
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 static/scripts/viz/paramamonster.js
--- a/static/scripts/viz/paramamonster.js
+++ b/static/scripts/viz/paramamonster.js
@@ -4,95 +4,230 @@
*/
/**
- * --- Models ---
+ * Tree for a tool's parameters.
*/
-
var ToolParameterTree = Backbone.Model.extend({
defaults: {
tool: null,
- params: null,
- num_samples: 4
- },
-
-
- initialize: function(options) {
- //
- // -- Create tree data from tool. --
- //
-
- // Valid inputs for tree are number, select parameters.
- var tool = this.get('tool'),
- num_samples = this.get('num_samples'),
- params_samples = tool.get('inputs').map(function(input) {
- return input.get_samples(num_samples);
- }),
- filtered_params_samples = _.filter(params_samples, function(param_sample) {
- return param_sample.get('samples').length !== 0;
- });
-
- /**
- * Returns tree data. Params_sampling is an array of
- *
- */
- var create_tree_data = function(params_samples, index) {
- var
- param_samples = params_samples[index],
- param = param_samples.get('param'),
- param_label = param.get('label'),
- settings = param_samples.get('samples');
-
- // Create leaves when last parameter setting is reached.
- if (params_samples.length - 1 === index) {
- return _.map(settings, function(setting) {
- return {
- name: param_label + '=' + setting,
- param: param,
- value: setting
- }
- });
- }
-
- // Recurse to handle other parameters.
- return _.map(settings, function(setting) {
- return {
- name: param_label + '=' + setting,
- param: param,
- value: setting,
- children: create_tree_data(filtered_params_samples, index + 1)
- }
- });
- };
-
- var tree_data = {
- name: 'Parameter Tree for ' + tool.get('name'),
- children: create_tree_data(filtered_params_samples, 0)
- };
-
- // Set valid inputs, tree data for later use.
- this.set('params', _.map(params_samples, function(s) { return s.get('param') }));
- this.set('tree_data', tree_data);
- }
-
-});
-
-/**
- * Tile of rendered genomic data.
- */
-var Tile = Backbone.Model.extend({
- defaults: {
- track: null,
- index: null,
- region: null,
- resolution: null,
- data: null,
- stale: null,
- html_elt: null
+ tree_data: null
},
initialize: function(options) {
+ // Set up tool parameters to work with tree.
+ var self = this;
+ this.get('tool').get('inputs').each(function(input) {
+ if (!input.get_samples()) { return; }
+
+ // All inputs are in tree to start.
+ self.add_param(input);
+
+ // Listen for changes to input's attributes.
+ input.on('change:min change:max change:num_samples', function(input) {
+ if (input.get('in_ptree')) {
+ self.set_tree_data();
+ }
+ }, self);
+ input.on('change:in_ptree', function(input) {
+ if (input.get('in_ptree')) {
+ self.add_param(input);
+ }
+ else {
+ self.remove_param(input);
+ }
+ self.set_tree_data();
+ }, self);
+ });
+
+ self.set_tree_data();
+ },
+
+ add_param: function(param) {
+ // If parameter already present, do not add it.
+ if (param.get('ptree_index')) { return; }
+
+ param.set('in_ptree', true);
+ param.set('ptree_index', this.get_tree_params().length);
+ },
+
+ remove_param: function(param) {
+ // Remove param from tree.
+ param.set('in_ptree', false);
+ param.set('ptree_index', null);
+
+ // Update ptree indices for remaining params.
+ _(this.get_tree_params()).each(function(input, index) {
+ // +1 to use 1-based indexing.
+ input.set('ptree_index', index + 1);
+ });
+ },
+
+ /**
+ * Sets tree data using tool's inputs.
+ */
+ set_tree_data: function() {
+ // Get samples for each parameter.
+ var params_samples = _.map(this.get_tree_params(), function(param) {
+ return {
+ param: param,
+ samples: param.get_samples()
+ };
+ });
+ var node_id = 0,
+ // Creates tree data recursively.
+ create_tree_data = function(params_samples, index) {
+ var param_samples = params_samples[index],
+ param = param_samples.param,
+ param_label = param.get('label'),
+ settings = param_samples.samples;
+
+ // Create leaves when last parameter setting is reached.
+ if (params_samples.length - 1 === index) {
+ return _.map(settings, function(setting) {
+ return {
+ id: node_id++,
+ name: setting,
+ param: param,
+ value: setting
+ };
+ });
+ }
+
+ // Recurse to handle other parameters.
+ return _.map(settings, function(setting) {
+ return {
+ id: node_id++,
+ name: setting,
+ param: param,
+ value: setting,
+ children: create_tree_data(params_samples, index + 1)
+ };
+ });
+ };
+
+ this.set('tree_data', {
+ name: 'Root',
+ children: (params_samples.length !== 0 ? create_tree_data(params_samples, 0) : null)
+ });
+ },
+
+ get_tree_params: function() {
+ // Filter and sort parameters to get list in tree.
+ return _(this.get('tool').get('inputs').where( {in_ptree: true} ))
+ .sortBy( function(input) { return input.get('ptree_index'); } );
+ },
+
+ /**
+ * Returns number of leaves in tree.
+ */
+ get_num_leaves: function() {
+ return this.get_tree_params().reduce(function(memo, param) { return memo * param.get_samples().length; }, 1);
+ },
+
+ /**
+ * Returns array of settings based on a node and its subtree.
+ */
+ get_node_settings: function(target_node) {
+ // -- Get fixed settings from tool and parent nodes.
+
+ // Start with tool's settings.
+ var fixed_settings = this.get('tool').get_inputs_dict();
+
+ // Get fixed settings using node's parents.
+ var cur_node = target_node.parent;
+ if (cur_node) {
+ while(cur_node.depth !== 0) {
+ fixed_settings[cur_node.param.get('name')] = cur_node.value;
+ cur_node = cur_node.parent;
+ }
+ }
+ // Walk subtree starting at clicked node to get full list of settings.
+ var get_settings = function(node, settings) {
+ // Add setting for this node.
+ settings[node.param.get('name')] = node.value;
+
+ if (!node.children) {
+ // At leaf node: add param setting and return.
+ return settings;
+ }
+ else {
+ // At interior node: return list of subtree settings.
+ return _.flatten( _.map(node.children, function(c) { return get_settings(c, _.clone(settings)); }) );
+ }
+ },
+ all_settings = get_settings(target_node, fixed_settings);
+
+ // If user clicked on leaf, settings is a single dict. Convert to array for simplicity.
+ if (!_.isArray(all_settings)) { all_settings = [ all_settings ]; }
+
+ return all_settings;
+ },
+
+ /**
+ * Returns all nodes connected a particular node; this includes parents and children of the node.
+ */
+ get_connected_nodes: function(node) {
+ var get_subtree_nodes = function(a_node) {
+ if (!a_node.children) {
+ return a_node;
+ }
+ else {
+ // At interior node: return subtree nodes.
+ return _.flatten( [a_node, _.map(a_node.children, function(c) { return get_subtree_nodes(c); })] );
+ }
+ };
+
+ // Get node's parents.
+ var parents = [],
+ cur_parent = node.parent;
+ while(cur_parent) {
+ parents.push(cur_parent);
+ cur_parent = cur_parent.parent;
+ }
+
+ return _.flatten([parents, get_subtree_nodes(node)]);
+ },
+
+ /**
+ * Returns the leaf that corresponds to a settings collection.
+ */
+ get_leaf: function(settings) {
+ var cur_node = this.get('tree_data'),
+ find_child = function(children) {
+ return _.find(children, function(child) {
+ return settings[child.param.get('name')] === child.value;
+ });
+ };
+
+ while (cur_node.children) {
+ cur_node = find_child(cur_node.children);
+ }
+ return cur_node;
}
-
+});
+
+var ParamaMonsterTrack = Backbone.Model.extend({
+ defaults: {
+ track: null,
+ settings: null,
+ regions: null
+ },
+
+ same_settings: function(a_track) {
+ var this_settings = this.get('settings'),
+ other_settings = a_track.get('settings');
+ for (var prop in this_settings) {
+ if (!other_settings[prop] ||
+ this_settings[prop] !== other_settings[prop]) {
+ return false;
+ }
+ }
+ return true;
+ }
+});
+
+var TrackCollection = Backbone.Collection.extend({
+ model: ParamaMonsterTrack
});
/**
@@ -102,11 +237,24 @@
defaults: _.extend({}, Visualization.prototype.defaults, {
tool: null,
parameter_tree: null,
- regions: null
+ regions: null,
+ tracks: null
}),
initialize: function(options) {
- this.set('parameter_tree', new ToolParameterTree({ tool: this.get('tool') }));
+ var tool_with_samplable_inputs = this.get('tool').copy(true);
+ this.set('tool_with_samplable_inputs', tool_with_samplable_inputs);
+
+ this.set('parameter_tree', new ToolParameterTree({ tool: tool_with_samplable_inputs }));
+ this.set('tracks', new TrackCollection());
+ },
+
+ add_placeholder: function(settings) {
+ this.get('tracks').add(new PlaceholderTrack(settings));
+ },
+
+ add_track: function(track) {
+ this.get('tracks').add(track);
}
});
@@ -114,87 +262,388 @@
* --- Views ---
*/
-var TileView = Backbone.View.extend({
-
+/**
+ * ParamaMonster track view.
+ */
+var ParamaMonsterTrackView = Backbone.View.extend({
+ tagName: 'tr',
+
+ initialize: function(options) {
+ this.canvas_manager = options.canvas_manager;
+ this.render();
+ this.model.on('change:track', this.draw_tiles, this);
+ },
+
+ render: function() {
+ // Render settings icon and popup.
+ // TODO: use template.
+ var settings = this.model.get('settings'),
+ settings_td = $('<td/>').addClass('settings').appendTo(this.$el),
+ settings_div = $('<div/>').addClass('track-info').hide().appendTo(settings_td);
+ settings_div.append( $('<div/>').css('font-weight', 'bold').text('Track Settings') );
+ _.each(_.keys(settings), function(name) {
+ settings_div.append( name + ': ' + settings[name] + '<br/>');
+ });
+ var self = this,
+ run_on_dataset_button = $('<button/>').appendTo(settings_div).text('Run on complete dataset').click(function() {
+ self.trigger('run_on_dataset', settings);
+ });
+ var icon_menu = create_icon_buttons_menu([
+ {
+ title: 'Settings',
+ icon_class: 'gear track-settings',
+ on_click: function () {
+ settings_div.toggle();
+ }
+ }
+ ]);
+ settings_td.prepend(icon_menu.$el);
+
+ // Render tile placeholders.
+ _.each(this.model.get('regions'), function() {
+ self.$el.append($('<td/>').addClass('tile').html(
+ $('<img/>').attr('src', galaxy_paths.get('image_path') + '/loading_large_white_bg.gif')
+ ));
+ });
+
+ if (this.model.get('track')) {
+ this.draw_tiles();
+ }
+ },
+
+ draw_tiles: function() {
+ // Display tiles for regions of interest.
+ var self = this,
+ track = this.model.get('track'),
+ regions = this.model.get('regions'),
+ tile_containers = this.$el.find('td.tile');
+
+ // When data is ready, draw tiles.
+ $.when(track.data_manager.data_is_ready()).then(function(data_ok) {
+ // Draw tile for each region.
+ _.each(regions, function(region, index) {
+ var resolution = region.length() / 300,
+ w_scale = 1/resolution,
+ mode = 'Pack';
+ $.when(track.data_manager.get_data(region, mode, resolution, {})).then(function(tile_data) {
+ var canvas = self.canvas_manager.new_canvas();
+ canvas.width = 300;
+ canvas.height = track.get_canvas_height(tile_data, mode, w_scale, canvas.width);
+ track.draw_tile(tile_data, canvas.getContext('2d'), mode, resolution, region, w_scale);
+ $(tile_containers[index]).empty().append(canvas);
+ });
+ });
+ });
+ }
});
+/**
+ * Tool input (parameter) that enables both value and sweeping inputs. View is unusual as
+ * it augments an existing input form row rather than creates a completely new HTML element.
+ */
+var ToolInputValOrSweepView = Backbone.View.extend({
+
+ // Template for rendering sweep inputs:
+ number_input_template: '<div class="form-row-input sweep">' +
+ '<input class="min" type="text" size="6" value="<%= min %>"> - ' +
+ '<input class="max" type="text" size="6" value="<%= max %>">' +
+ ' samples: <input class="num_samples" type="text" size="1" value="<%= num_samples %>">' +
+ '</div>',
+
+ select_input_template: '<div class="form-row-input sweep"><%= options %></div>',
+
+ initialize: function(options) {
+ this.$el = options.tool_row;
+ this.render();
+ },
+
+ render: function() {
+ var input = this.model,
+ type = input.get('type'),
+ single_input_row = this.$el.find('.form-row-input'),
+ sweep_inputs_row = null;
+
+ // Update tool inputs as single input changes.
+ single_input_row.find('input').change(function() {
+ input.set('value', $(this).val());
+ });
+
+ // Add row for parameter sweep inputs.
+ if (type === 'number') {
+ sweep_inputs_row = $(_.template(this.number_input_template, this.model.toJSON()));
+ }
+ else if (type === 'select') {
+ var options = _.map(this.$el.find('select option'), function(option) {
+ return $(option).val();
+ }),
+ options_text = options.join(', ');
+ sweep_inputs_row = $(_.template(this.select_input_template, {
+ options: options_text
+ }));
+ }
+
+ // Fow now, assume parameter is included in tree to start.
+ sweep_inputs_row.insertAfter(single_input_row);
+ single_input_row.hide();
+
+ // Add buttons for adding/removing parameter.
+ var self = this,
+ menu = create_icon_buttons_menu([
+ {
+ title: 'Add',
+ icon_class: 'plus-button',
+ on_click: function () {
+ input.set('in_ptree', true);
+ single_input_row.hide();
+ sweep_inputs_row.show();
+ }
+
+ },
+ {
+ title: 'Remove',
+ icon_class: 'toggle',
+ on_click: function() {
+ // Remove parameter from tree params where name matches clicked paramter.
+ input.set('in_ptree', false);
+ sweep_inputs_row.hide();
+ single_input_row.show();
+ }
+ }
+ ]);
+ this.$el.prepend(menu.$el);
+
+ // Update input's min, max, number of samples as values change.
+ _.each(['min', 'max', 'num_samples'], function(attr) {
+ sweep_inputs_row.find('.' + attr).change(function() {
+ input.set(attr, parseFloat( $(this).val() ));
+ });
+ });
+ }
+});
+
+var ToolParameterTreeDesignView = Backbone.View.extend({
+ className: 'tree-design',
+
+ initialize: function(options) {
+ this.render();
+ },
+
+ render: function() {
+ // Start with tool form view.
+ var tool_form_view = new ToolFormView({
+ model: this.model.get('tool')
+ });
+ tool_form_view.render();
+ this.$el.append(tool_form_view.$el);
+
+ // Set up views for each tool input.
+ var self = this,
+ inputs = self.model.get('tool').get('inputs');
+ this.$el.find('.form-row').not('.form-actions').each(function(i) {
+ var input_view = new ToolInputValOrSweepView({
+ model: inputs.at(i),
+ tool_row: $(this)
+ });
+ });
+ }
+});
+
+/**
+ * Displays and updates parameter tree.
+ */
var ToolParameterTreeView = Backbone.View.extend({
className: 'tool-parameter-tree',
initialize: function(options) {
+ // When tree data changes, re-render.
+ this.model.on('change:tree_data', this.render, this);
},
render: function() {
- var width = 960,
- height = 2000;
+ var tree_params = this.model.get_tree_params();
+ // Start fresh.
+ this.$el.children().remove();
+
+ // Set width, height based on params and samples.
+ this.width = 100 * (2 + tree_params.length);
+ this.height = 15 * this.model.get_num_leaves();
+
+ var self = this;
// Layout tree.
var cluster = d3.layout.cluster()
- .size([height, width - 160]);
+ .size([this.height - 10, this.width - 160]);
var diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
+ // Layout nodes.
+ var nodes = cluster.nodes(this.model.get('tree_data'));
+
+ // Setup and add labels for tree levels.
+ var param_depths = _.uniq(_.pluck(nodes, "y"));
+ _.each(tree_params, function(param, index) {
+ var x = param_depths[index+1];
+ self.$el.append( $('<div>').addClass('label')
+ .text(param.get('label'))
+ // HACK: add 250 b/c in center panel.
+ .css('left', x + 250) );
+ });
+
// Set up vis element.
var vis = d3.select(this.$el[0])
.append("svg")
- .attr("width", width)
- .attr("height", height)
+ .attr("width", this.width)
+ .attr("height", this.height)
.append("g")
- .attr("transform", "translate(80, 0)");
+ .attr("transform", "translate(40, 10)");
- // Set up nodes, links.
- var nodes = cluster.nodes(this.model.get('tree_data'));
-
+ // Draw links.
var link = vis.selectAll("path.link")
.data(cluster.links(nodes))
.enter().append("path")
.attr("class", "link")
.attr("d", diagonal);
+ // Draw nodes.
var node = vis.selectAll("g.node")
.data(nodes)
.enter().append("g")
.attr("class", "node")
- .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
+ .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
+ .on('mouseover', function(a_node) {
+ var connected_node_ids = _.pluck(self.model.get_connected_nodes(a_node), 'id');
+ // TODO: probably can use enter() to do this more easily.
+ node.filter(function(d) {
+ return _.find(connected_node_ids, function(id) { return id === d.id; }) !== undefined;
+ }).style('fill', '#f00');
+ })
+ .on('mouseout', function() {
+ node.style('fill', '#000');
+ });
node.append("circle")
- .attr("r", 4.5);
+ .attr("r", 9);
node.append("text")
- .attr("dx", function(d) { return d.children ? -8 : 8; })
+ .attr("dx", function(d) { return d.children ? -12 : 12; })
.attr("dy", 3)
.attr("text-anchor", function(d) { return d.children ? "end" : "start"; })
.text(function(d) { return d.name; });
}
});
+/**
+ * ParamaMonster visualization view. View requires rendering in 3-panel setup for now.
+ */
var ParamaMonsterVisualizationView = Backbone.View.extend({
className: 'paramamonster',
initialize: function(options) {
-
+ this.canvas_manager = new CanvasManager(this.$el.parents('body'));
+ this.tool_param_tree_view = new ToolParameterTreeView({ model: this.model.get('parameter_tree') });
+ this.track_collection_container = $('<table/>').addClass('tracks');
+
+ // Handle node clicks for tree data.
+ this.model.get('parameter_tree').on('change:tree_data', this.handle_node_clicks, this);
},
render: function() {
- // Set up tool parameter tree.
- var tool_param_tree_view = new ToolParameterTreeView({ model: this.model.get('parameter_tree') });
- tool_param_tree_view.render();
- this.$el.append(tool_param_tree_view.$el);
-
- // When node clicked in tree, run tool and show tiles.
- var node = d3.select(tool_param_tree_view.$el[0]).selectAll("g.node")
+ // Render tree design view in left panel.
+ var tree_design_view = new ToolParameterTreeDesignView({
+ model: this.model.get('parameter_tree')
+ });
+
+ $('#left').append(tree_design_view.$el);
+
+ // Render track collection container/view in right panel.
+ var self = this,
+ regions = self.model.get('regions'),
+ tr = $('<tr/>').appendTo(this.track_collection_container);
+
+ _.each(regions, function(region) {
+ tr.append( $('<th>').text(region.toString()) );
+ });
+ tr.children().first().attr('colspan', 2);
+
+ $('#right').append(this.track_collection_container);
+
+ // Render tool parameter tree in center panel.
+ this.tool_param_tree_view.render();
+ $('#center').append(this.tool_param_tree_view.$el);
+
+ this.handle_node_clicks();
+ },
+
+ run_tool_on_dataset: function(settings) {
+ var tool = this.model.get('tool'),
+ dataset = this.model.get('dataset');
+ tool.set_input_values(settings);
+ $.when(tool.rerun(dataset)).then(function(outputs) {
+ // TODO: show modal with information about how to get to datasets.
+ });
+ },
+
+ handle_node_clicks: function() {
+ // When node clicked in tree, run tool and add tracks to model.
+ var self = this,
+ param_tree = this.model.get('parameter_tree'),
+ regions = this.model.get('regions'),
+ node = d3.select(this.tool_param_tree_view.$el[0]).selectAll("g.node");
node.on("click", function(d, i) {
- console.log(d, i);
+ // TODO: Show popup menu.
- // Gather: (a) dataset of interest; (b) region(s) of interest and (c) sets of parameters based on node clicked.
-
- // Run job by submitting parameters + dataset as job inputs; get dataset ids as result.
-
- // Create tracks for all resulting dataset ids.
-
- // Display tiles for region(s) of interest.
+ // Get all settings corresponding to node.
+ var tool = self.model.get('tool'),
+ dataset = self.model.get('dataset'),
+ all_settings = param_tree.get_node_settings(d);
+
+ // Create and add tracks for each settings group.
+ var tracks = _.map(all_settings, function(settings) {
+ var pm_track = new ParamaMonsterTrack({
+ settings: settings,
+ regions: regions
+ });
+ self.model.add_track(pm_track);
+ var track_view = new ParamaMonsterTrackView({
+ model: pm_track,
+ canvas_manager: self.canvas_manager
+ });
+ track_view.on('run_on_dataset', self.run_tool_on_dataset, self);
+ self.track_collection_container.append(track_view.$el);
+ track_view.$el.hover(function() {
+ var settings_leaf = param_tree.get_leaf(settings);
+ var connected_node_ids = _.pluck(param_tree.get_connected_nodes(settings_leaf), 'id');
+
+ // TODO: can do faster with enter?
+ d3.select(self.tool_param_tree_view.$el[0]).selectAll("g.node")
+ .filter(function(d) {
+ return _.find(connected_node_ids, function(id) { return id === d.id; }) !== undefined;
+ }).style('fill', '#f00');
+ },
+ function() {
+ d3.select(self.tool_param_tree_view.$el[0]).selectAll("g.node").style('fill', '#000');
+ });
+ return pm_track;
+ });
+
+ // For each track, run tool using track's settings and update track.
+ _.each(tracks, function(pm_track, index) {
+ setTimeout(function() {
+ // Set inputs and run tool.
+ //console.log('running with settings', pm_track.get('settings'));
+ tool.set_input_values(pm_track.get('settings'));
+ $.when(tool.rerun(dataset, regions)).then(function(output) {
+ // Create and add track for output dataset.
+ var track_config = _.extend({
+ data_url: galaxy_paths.get('raw_data_url'),
+ converted_datasets_state_url: galaxy_paths.get('dataset_state_url')
+ }, output.first().get('track_config')),
+ track_obj = object_from_template(track_config, self, null);
+ pm_track.set('track', track_obj);
+ });
+ }, index * 10000);
+ });
});
-
- },
+ }
});
\ No newline at end of file
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 templates/tracks/browser.mako
--- a/templates/tracks/browser.mako
+++ b/templates/tracks/browser.mako
@@ -179,7 +179,6 @@
} }
]);
- menu.render();
menu.$el.attr("style", "float: right");
$("#center .unified-panel-header-inner").append(menu.$el);
diff -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 -r 27f54f28e9f1542e9681b8a4c238d856be7b9a34 templates/visualization/paramamonster.mako
--- a/templates/visualization/paramamonster.mako
+++ b/templates/visualization/paramamonster.mako
@@ -2,8 +2,8 @@
<%def name="init()"><%
- self.has_left_panel=False
- self.has_right_panel=False
+ self.has_left_panel=True
+ self.has_right_panel=True
self.active_view="visualization"
self.message_box_visible=False
%>
@@ -12,7 +12,7 @@
<%def name="stylesheets()">
${parent.stylesheets()}
<style>
- .unified-panel-body {
+ div#center {
overflow: auto;
}
.link {
@@ -27,6 +27,56 @@
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
+ cursor: pointer;
+ }
+ .node:hover {
+ fill: #f00;
+ }
+ .node:hover circle {
+ fill: #ccc;
+ stroke: #f00;
+ }
+ table.tracks {
+ border-collapse: separate;
+ border-spacing: 5px;
+ }
+ .tile {
+ border: solid 1px #DDD;
+ margin: 2px;
+ border-radius: 10px;
+ margin: 3px;
+ }
+ .label {
+ position: fixed;
+ font: 10px sans-serif;
+ font-weight: bold;
+ background-color: #DDD;
+ border-radius: 5px;
+ padding: 1px;
+ }
+ th,td {
+ text-align: center;
+ }
+ td.settings {
+ vertical-align: top;
+ }
+ .icon-button.track-settings {
+ float: none;
+ }
+ .track-info {
+ text-align: left;
+ font: 10px sans-serif;
+ position: fixed;
+ background-color: #CCC;
+ border: solid 1px #AAA;
+ border-radius: 2px;
+ padding: 2px;
+ }
+ .btn-primary, .btn-primary:hover {
+ color: #EEE;
+ background-color: #DDD;
+ background-image: none;
+ border-radius: 12px;
}
</style></%def>
@@ -34,28 +84,16 @@
<%def name="javascripts()">
${parent.javascripts()}
- ${h.templates( "tool_link", "panel_section", "tool_search" )}
- ${h.js( "libs/d3", "mvc/data", "mvc/tools", "viz/visualization", "viz/paramamonster" )}
+ ${h.templates( "tool_link", "panel_section", "tool_search", "tool_form" )}
+ ${h.js( "libs/d3", "mvc/data", "mvc/tools", "viz/visualization", "viz/paramamonster", "viz/trackster", "viz/trackster_ui", "jquery.ui.sortable.slider" )}
<script type="text/javascript">
- var tool;
+ var viz;
$(function() {
// -- Viz set up. --
- tool = new Tool(JSON.parse('${ h.to_json_string( tool ) }'));
- // HACK: need to replace \ with \\ due to simplejson bug.
- var dataset = new Dataset(JSON.parse('${ h.to_json_string( dataset.get_api_value() ).replace('\\', '\\\\' ) }')),
- paramamonster_viz = new ParamaMonsterVisualization({
- tool: tool,
- dataset: dataset
- });
- viz_view = new ParamaMonsterVisualizationView({ model: paramamonster_viz });
-
- viz_view.render();
- $('.unified-panel-body').append(viz_view.$el);
-
- // Tool testing.
- var regions = [
+ var tool = new Tool(JSON.parse('${ h.to_json_string( tool ) }')),
+ regions = [
new GenomeRegion({
chrom: 'chr19',
start: '10000',
@@ -63,25 +101,32 @@
}),
new GenomeRegion({
chrom: 'chr19',
- start: '30000',
- end: '36000'
+ start: '150000',
+ end: '175000'
})
- ];
+ ],
+ // HACK: need to replace \ with \\ due to simplejson bug.
+ dataset = new Dataset(JSON.parse('${ h.to_json_string( dataset.get_api_value() ).replace('\\', '\\\\' ) }'));
- $.when(tool.rerun(dataset, regions)).then(function(outputs) {
- console.log(outputs);
+
+ viz = new ParamaMonsterVisualization({
+ tool: tool,
+ dataset: dataset,
+ regions: regions
});
+ var viz_view = new ParamaMonsterVisualizationView({ model: viz });
+
+ viz_view.render();
+ $('.unified-panel-body').append(viz_view.$el);
});
</script></%def><%def name="center_panel()">
- <div class="unified-panel-header" unselectable="on">
- <div class="unified-panel-header-inner">
- <div style="float:left;" id="title"></div>
- </div>
- <div style="clear: both"></div>
- </div>
- <div class="unified-panel-body">
- </div></%def>
+
+<%def name="left_panel()">
+</%def>
+
+<%def name="right_panel()">
+</%def>
\ No newline at end of file
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: Added remote authentication to the toolshed.
by Bitbucket 27 Jun '12
by Bitbucket 27 Jun '12
27 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/21ec1290ad02/
changeset: 21ec1290ad02
user: inithello
date: 2012-06-27 15:47:32
summary: Added remote authentication to the toolshed.
affected #: 3 files
diff -r 9576fb8cd71e8ad16e9a6426c0c42dc6aba63716 -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 lib/galaxy/web/framework/__init__.py
--- a/lib/galaxy/web/framework/__init__.py
+++ b/lib/galaxy/web/framework/__init__.py
@@ -498,8 +498,10 @@
# remote user authenticates, we'll look for this information, and if missing, create it.
if not self.app.security_agent.get_private_user_role( user ):
self.app.security_agent.create_private_user_role( user )
- if not user.default_permissions:
- self.app.security_agent.user_set_default_permissions( user, history=True, dataset=True )
+ if 'webapp' not in self.environ or self.environ['webapp'] != 'community':
+ if not user.default_permissions:
+ self.app.security_agent.user_set_default_permissions( user )
+ self.app.security_agent.user_set_default_permissions( user, history=True, dataset=True )
elif user is None:
username = remote_user_email.split( '@', 1 )[0].lower()
random.seed()
@@ -520,7 +522,8 @@
self.sa_session.flush()
self.app.security_agent.create_private_user_role( user )
# We set default user permissions, before we log in and set the default history permissions
- self.app.security_agent.user_set_default_permissions( user )
+ if 'webapp' not in self.environ or self.environ['webapp'] != 'community':
+ self.app.security_agent.user_set_default_permissions( user )
#self.log_event( "Automatically created account '%s'", user.email )
return user
def __update_session_cookie( self, name='galaxysession' ):
diff -r 9576fb8cd71e8ad16e9a6426c0c42dc6aba63716 -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 lib/galaxy/webapps/community/buildapp.py
--- a/lib/galaxy/webapps/community/buildapp.py
+++ b/lib/galaxy/webapps/community/buildapp.py
@@ -17,6 +17,7 @@
import galaxy.webapps.community.model.mapping
import galaxy.web.framework
from galaxy.webapps.community.framework.middleware import hg
+from galaxy import util
log = logging.getLogger( __name__ )
@@ -102,6 +103,15 @@
# other middleware):
app = httpexceptions.make_middleware( app, conf )
log.debug( "Enabling 'httpexceptions' middleware" )
+ # If we're using remote_user authentication, add middleware that
+ # protects Galaxy from improperly configured authentication in the
+ # upstream server
+ if asbool(conf.get( 'use_remote_user', False )):
+ from galaxy.webapps.community.framework.middleware.remoteuser import RemoteUser
+ app = RemoteUser( app, maildomain = conf.get( 'remote_user_maildomain', None ),
+ display_servers = util.listify( conf.get( 'display_servers', '' ) ),
+ admin_users = conf.get( 'admin_users', '' ).split( ',' ) )
+ log.debug( "Enabling 'remote user' middleware" )
# The recursive middleware allows for including requests in other
# requests or forwarding of requests, all on the server side.
if asbool(conf.get('use_recursive', True)):
diff -r 9576fb8cd71e8ad16e9a6426c0c42dc6aba63716 -r 21ec1290ad02beb9c33516dcc4d5d4a732559414 lib/galaxy/webapps/community/framework/middleware/remoteuser.py
--- /dev/null
+++ b/lib/galaxy/webapps/community/framework/middleware/remoteuser.py
@@ -0,0 +1,93 @@
+"""
+Middleware for handling $REMOTE_USER if use_remote_user is enabled.
+"""
+
+import socket
+
+errorpage = """
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html lang="en">
+ <head>
+ <title>Galaxy</title>
+ <style type="text/css">
+ body {
+ min-width: 500px;
+ text-align: center;
+ }
+ .errormessage {
+ font: 75%% verdana, "Bitstream Vera Sans", geneva, arial, helvetica, helve, sans-serif;
+ padding: 10px;
+ margin: 100px auto;
+ min-height: 32px;
+ max-width: 500px;
+ border: 1px solid #AA6666;
+ background-color: #FFCCCC;
+ text-align: left;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="errormessage">
+ <h4>%s</h4>
+ <p>%s</p>
+ </div>
+ </body>
+</html>
+"""
+
+class RemoteUser( object ):
+ def __init__( self, app, maildomain=None, display_servers=None, admin_users=None ):
+ self.app = app
+ self.maildomain = maildomain
+ self.display_servers = display_servers or []
+ self.admin_users = admin_users or []
+ def __call__( self, environ, start_response ):
+ environ[ 'webapp' ] = 'community'
+ # Allow display servers
+ if self.display_servers and environ.has_key( 'REMOTE_ADDR' ):
+ try:
+ host = socket.gethostbyaddr( environ[ 'REMOTE_ADDR' ] )[0]
+ except( socket.error, socket.herror, socket.gaierror, socket.timeout ):
+ # in the event of a lookup failure, deny access
+ host = None
+ if host in self.display_servers:
+ environ[ 'HTTP_REMOTE_USER' ] = 'remote_display_server@%s' % ( self.maildomain or 'example.org' )
+ return self.app( environ, start_response )
+ # Apache sets REMOTE_USER to the string '(null)' when using the
+ # Rewrite* method for passing REMOTE_USER and a user is
+ # un-authenticated. Any other possible values need to go here as well.
+ path_info = environ.get('PATH_INFO', '')
+ if environ.has_key( 'HTTP_REMOTE_USER' ) and environ[ 'HTTP_REMOTE_USER' ] != '(null)':
+ if not environ[ 'HTTP_REMOTE_USER' ].count( '@' ):
+ if self.maildomain is not None:
+ environ[ 'HTTP_REMOTE_USER' ] += '@' + self.maildomain
+ else:
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but only a
+ username (not an email address) was provided by the
+ upstream (proxy) server. Since Galaxy usernames are email
+ addresses, a default mail domain must be set.</p>
+ <p>Please contact your local Galaxy administrator. The
+ variable <code>remote_user_maildomain</code> must be set
+ before you may access Galaxy.
+ """
+ return self.error( start_response, title, message )
+ return self.app( environ, start_response )
+ elif path_info.startswith( '/api/' ):
+ # The API handles its own authentication via keys
+ return self.app( environ, start_response )
+ else:
+ title = "Access to Galaxy is denied"
+ message = """
+ Galaxy is configured to authenticate users via an external
+ method (such as HTTP authentication in Apache), but a username
+ was not provided by the upstream (proxy) server. This is
+ generally due to a misconfiguration in the upstream server.</p>
+ <p>Please contact your local Galaxy administrator.
+ """
+ return self.error( start_response, title, message )
+ def error( self, start_response, title="Access denied", message="Please contact your local Galaxy administrator." ):
+ start_response( '403 Forbidden', [('Content-type', 'text/html')] )
+ return [errorpage % (title, message)]
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: scot...@gatech.edu: Generalized exit code and regex handling. TaskWrapper now uses the newly-generalized handling, too.
by Bitbucket 26 Jun '12
by Bitbucket 26 Jun '12
26 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/9576fb8cd71e/
changeset: 9576fb8cd71e
user: scot...(a)gatech.edu
date: 2012-06-26 23:31:30
summary: Generalized exit code and regex handling. TaskWrapper now uses the newly-generalized handling, too.
affected #: 2 files
diff -r fb67f73df9a24cb9eba278e7c62ba996fa11a6be -r 9576fb8cd71e8ad16e9a6426c0c42dc6aba63716 lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -306,78 +306,12 @@
#ERROR at this point means the job was deleted by an administrator.
return self.fail( job.info )
- err_msg = ""
- # Check exit codes and match regular expressions against stdout and
- # stderr if this tool was configured to do so.
- if ( len( self.tool.stdio_regexes ) > 0 or
- len( self.tool.stdio_exit_codes ) > 0 ):
- # We will check the exit code ranges in the order in which
- # they were specified. Each exit_code is a ToolStdioExitCode
- # that includes an applicable range. If the exit code was in
- # that range, then apply the error level and add in a message.
- # If we've reached a fatal error rule, then stop.
- max_error_level = galaxy.tools.StdioErrorLevel.NO_ERROR
- for stdio_exit_code in self.tool.stdio_exit_codes:
- if ( tool_exit_code >= stdio_exit_code.range_start and
- tool_exit_code <= stdio_exit_code.range_end ):
- if None != stdio_exit_code.desc:
- err_msg += stdio_exit_code.desc
- # TODO: Find somewhere to stick the err_msg - possibly to
- # the source (stderr/stdout), possibly in a new db column.
- max_error_level = max( max_error_level,
- stdio_exit_code.error_level )
- if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
- break
- # If there is a regular expression for scanning stdout/stderr,
- # then we assume that the tool writer overwrote the default
- # behavior of just setting an error if there is *anything* on
- # stderr.
- if max_error_level < galaxy.tools.StdioErrorLevel.FATAL:
- # We'll examine every regex. Each regex specifies whether
- # it is to be run on stdout, stderr, or both. (It is
- # possible for neither stdout nor stderr to be scanned,
- # but those won't be scanned.) We record the highest
- # error level, which are currently "warning" and "fatal".
- # If fatal, then we set the job's state to ERROR.
- # If warning, then we still set the job's state to OK
- # but include a message. We'll do this if we haven't seen
- # a fatal error yet
- for regex in self.tool.stdio_regexes:
- # If ( this regex should be matched against stdout )
- # - Run the regex's match pattern against stdout
- # - If it matched, then determine the error level.
- # o If it was fatal, then we're done - break.
- # Repeat the stdout stuff for stderr.
- # TODO: Collapse this into a single function.
- if ( regex.stdout_match ):
- regex_match = re.search( regex.match, stdout )
- if ( regex_match ):
- err_msg += self.regex_err_msg( regex_match, regex )
- max_error_level = max( max_error_level, regex.error_level )
- if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
- break
- if ( regex.stderr_match ):
- regex_match = re.search( regex.match, stderr )
- if ( regex_match ):
- err_msg += self.regex_err_msg( regex_match, regex )
- max_error_level = max( max_error_level,
- regex.error_level )
- if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
- break
- # If we encountered a fatal error, then we'll need to set the
- # job state accordingly. Otherwise the job is ok:
- if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
- job.state = job.states.ERROR
- else:
- job.state = job.states.OK
- # When there are no regular expressions and no exit codes to check,
- # default to the previous behavior: when there's anything on stderr
- # the job has an error, and the job is ok otherwise.
+ # Check the
+ if ( self.check_tool_output( stdout, stderr, tool_exit_code ) ):
+ job.state = job.states.OK
else:
- if stderr:
- job.state = job.states.ERROR
- else:
- job.state = job.states.OK
+ job.state = job.states.ERROR
+
if self.version_string_cmd:
version_filename = self.get_version_string_path()
if os.path.exists(version_filename):
@@ -566,6 +500,107 @@
if self.app.config.cleanup_job == 'always' or ( not stderr and self.app.config.cleanup_job == 'onsuccess' ):
self.cleanup()
+ def check_tool_output( self, stdout, stderr, tool_exit_code ):
+ """
+ Check the output of a tool - given the stdout, stderr, and the tool's
+ exit code, return True if the tool exited succesfully and False
+ otherwise. No exceptions should be thrown. If this code encounters
+ an exception, it returns True so that the workflow can continue;
+ otherwise, a bug in this code could halt workflow progress.
+ Note that, if the tool did not define any exit code handling or
+ any stdio/stderr handling, then it reverts back to previous behavior:
+ if stderr contains anything, then False is returned.
+ """
+ job = self.get_job()
+ err_msg = ""
+ # By default, the tool succeeded. This covers the case where the code
+ # has a bug but the tool was ok, and it lets a workflow continue.
+ success = True
+
+ try:
+ # Check exit codes and match regular expressions against stdout and
+ # stderr if this tool was configured to do so.
+ if ( len( self.tool.stdio_regexes ) > 0 or
+ len( self.tool.stdio_exit_codes ) > 0 ):
+ # We will check the exit code ranges in the order in which
+ # they were specified. Each exit_code is a ToolStdioExitCode
+ # that includes an applicable range. If the exit code was in
+ # that range, then apply the error level and add in a message.
+ # If we've reached a fatal error rule, then stop.
+ max_error_level = galaxy.tools.StdioErrorLevel.NO_ERROR
+ for stdio_exit_code in self.tool.stdio_exit_codes:
+ if ( tool_exit_code >= stdio_exit_code.range_start and
+ tool_exit_code <= stdio_exit_code.range_end ):
+ if None != stdio_exit_code.desc:
+ err_msg += stdio_exit_code.desc
+ # TODO: Find somewhere to stick the err_msg - possibly to
+ # the source (stderr/stdout), possibly in a new db column.
+ max_error_level = max( max_error_level,
+ stdio_exit_code.error_level )
+ if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
+ break
+
+ # If there is a regular expression for scanning stdout/stderr,
+ # then we assume that the tool writer overwrote the default
+ # behavior of just setting an error if there is *anything* on
+ # stderr.
+ if max_error_level < galaxy.tools.StdioErrorLevel.FATAL:
+ # We'll examine every regex. Each regex specifies whether
+ # it is to be run on stdout, stderr, or both. (It is
+ # possible for neither stdout nor stderr to be scanned,
+ # but those won't be scanned.) We record the highest
+ # error level, which are currently "warning" and "fatal".
+ # If fatal, then we set the job's state to ERROR.
+ # If warning, then we still set the job's state to OK
+ # but include a message. We'll do this if we haven't seen
+ # a fatal error yet
+ for regex in self.tool.stdio_regexes:
+ # If ( this regex should be matched against stdout )
+ # - Run the regex's match pattern against stdout
+ # - If it matched, then determine the error level.
+ # o If it was fatal, then we're done - break.
+ # Repeat the stdout stuff for stderr.
+ # TODO: Collapse this into a single function.
+ if ( regex.stdout_match ):
+ regex_match = re.search( regex.match, stdout )
+ if ( regex_match ):
+ err_msg += self.regex_err_msg( regex_match, regex )
+ max_error_level = max( max_error_level, regex.error_level )
+ if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
+ break
+ if ( regex.stderr_match ):
+ regex_match = re.search( regex.match, stderr )
+ if ( regex_match ):
+ err_msg += self.regex_err_msg( regex_match, regex )
+ max_error_level = max( max_error_level,
+ regex.error_level )
+ if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
+ break
+
+ # If we encountered a fatal error, then we'll need to set the
+ # job state accordingly. Otherwise the job is ok:
+ if max_error_level >= galaxy.tools.StdioErrorLevel.FATAL:
+ success = False
+ else:
+ success = True
+
+ # When there are no regular expressions and no exit codes to check,
+ # default to the previous behavior: when there's anything on stderr
+ # the job has an error, and the job is ok otherwise.
+ else:
+ log.debug( "The tool did not define exit code or stdio handling; "
+ + "checking stderr for success" )
+ if stderr:
+ success = False
+ else:
+ success = True
+ # On any exception, return True.
+ except:
+ log.warning( "Tool check encountered unexpected exception; "
+ + "assuming tool was successful" )
+ success = True
+ return success
+
def regex_err_msg( self, match, regex ):
"""
Return a message about the match on tool output using the given
@@ -970,7 +1005,7 @@
self.sa_session.add( task )
self.sa_session.flush()
- def finish( self, stdout, stderr ):
+ def finish( self, stdout, stderr, tool_exit_code=0 ):
# DBTODO integrate previous finish logic.
# Simple finish for tasks. Just set the flag OK.
log.debug( 'task %s for job %d ended' % (self.task_id, self.job_id) )
@@ -991,10 +1026,10 @@
# Job was deleted by an administrator
self.fail( task.info )
return
- if stderr:
+ if ( self.check_tool_output( stdout, stderr, tool_exit_code ) ):
+ task.state = task.states.OK
+ else:
task.state = task.states.ERROR
- else:
- task.state = task.states.OK
# Save stdout and stderr
if len( stdout ) > 32768:
log.error( "stdout for task %d is greater than 32K, only first part will be logged to database" % task.id )
diff -r fb67f73df9a24cb9eba278e7c62ba996fa11a6be -r 9576fb8cd71e8ad16e9a6426c0c42dc6aba63716 lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -560,7 +560,7 @@
def fail_job( self, pbs_job_state ):
"""
- Seperated out so we can use the worker threads for it.
+ Separated out so we can use the worker threads for it.
"""
if pbs_job_state.stop_job:
self.stop_job( self.sa_session.query( self.app.model.Job ).get( pbs_job_state.job_wrapper.job_id ) )
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
26 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/fb67f73df9a2/
changeset: fb67f73df9a2
user: inithello
date: 2012-06-26 21:18:19
summary: Also added missing publicbuilds.txt
affected #: 2 files
diff -r e112508794a8585e96bc1ba15c2be1cce421393d -r fb67f73df9a24cb9eba278e7c62ba996fa11a6be .hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -51,6 +51,7 @@
tool-data/shared/rviewer/rviewer_build_sites.txt
tool-data/shared/ucsc/builds.txt
tool-data/shared/ensembl/builds.txt
+tool-data/shared/ucsc/publicbuilds.txt
tool-data/*.loc
tool-data/genome/*
diff -r e112508794a8585e96bc1ba15c2be1cce421393d -r fb67f73df9a24cb9eba278e7c62ba996fa11a6be tool-data/shared/ucsc/publicbuilds.txt
--- /dev/null
+++ b/tool-data/shared/ucsc/publicbuilds.txt
@@ -0,0 +1,96 @@
+#Harvested from http://genome.cse.ucsc.edu/cgi-bin/das/dsn
+? unspecified (?)
+hg19 Human Feb. 2009 (GRCh37/hg19) (hg19)
+hg18 Human Mar. 2006 (NCBI36/hg18) (hg18)
+hg17 Human May 2004 (NCBI35/hg17) (hg17)
+panTro3 Chimp Oct. 2010 (CGSC 2.1.3/panTro3) (panTro3)
+panTro2 Chimp Mar. 2006 (CGSC 2.1/panTro2) (panTro2)
+gorGor3 Gorilla May 2011 (gorGor3.1/gorGor3) (gorGor3)
+ponAbe2 Orangutan July 2007 (WUGSC 2.0.2/ponAbe2) (ponAbe2)
+nomLeu1 Gibbon Jan. 2010 (GGSC Nleu1.0/nomLeu1) (nomLeu1)
+rheMac2 Rhesus Jan. 2006 (MGSC Merged 1.0/rheMac2) (rheMac2)
+calJac3 Marmoset March 2009 (WUGSC 3.2/calJac3) (calJac3)
+calJac1 Marmoset June 2007 (WUGSC 2.0.2/calJac1) (calJac1)
+mm10 Mouse Dec. 2011 (GRCm38/mm10) (mm10)
+mm9 Mouse July 2007 (NCBI37/mm9) (mm9)
+mm8 Mouse Feb. 2006 (NCBI36/mm8) (mm8)
+rn5 Rat Mar. 2012 (RGSC 5.0/rn5) (rn5)
+rn4 Rat Nov. 2004 (Baylor 3.4/rn4) (rn4)
+hetGla1 Naked mole-rat Jul. 2011 (BGI HetGla_1.0/hetGla1) (hetGla1)
+cavPor3 Guinea pig Feb. 2008 (Broad/cavPor3) (cavPor3)
+oryCun2 Rabbit Apr. 2009 (Broad/oryCun2) (oryCun2)
+susScr2 Pig Nov. 2009 (SGSC Sscrofa9.2/susScr2) (susScr2)
+oviAri1 Sheep Feb. 2010 (ISGC Ovis_aries_1.0/oviAri1) (oviAri1)
+bosTau7 Cow Oct. 2011 (Baylor Btau_4.6.1/bosTau7) (bosTau7)
+bosTau6 Cow Nov. 2009 (Bos_taurus_UMD_3.1/bosTau6) (bosTau6)
+bosTau4 Cow Oct. 2007 (Baylor 4.0/bosTau4) (bosTau4)
+equCab2 Horse Sep. 2007 (Broad/equCab2) (equCab2)
+equCab1 Horse Jan. 2007 (Broad/equCab1) (equCab1)
+felCat4 Cat Dec. 2008 (NHGRI/GTB V17e/felCat4) (felCat4)
+felCat3 Cat Mar. 2006 (Broad/felCat3) (felCat3)
+canFam3 Dog Sep. 2011 (Broad CanFam3.1/canFam3) (canFam3)
+canFam2 Dog May 2005 (Broad/canFam2) (canFam2)
+ailMel1 Panda Dec. 2009 (BGI-Shenzhen 1.0/ailMel1) (ailMel1)
+myoLuc2 Microbat Jul. 2010 (Broad Institute Myoluc2.0/myoLuc2) (myoLuc2)
+loxAfr3 Elephant Jul. 2009 (Broad/loxAfr3) (loxAfr3)
+monDom5 Opossum Oct. 2006 (Broad/monDom5) (monDom5)
+monDom4 Opossum Jan. 2006 (Broad/monDom4) (monDom4)
+macEug2 Wallaby Sep. 2009 (TWGS Meug_1.1/macEug2) (macEug2)
+ornAna1 Platypus Mar. 2007 (WUGSC 5.0.1/ornAna1) (ornAna1)
+galGal4 Chicken Nov. 2011 (ICGSC Gallus_gallus-4.0/galGal4) (galGal4)
+galGal3 Chicken May 2006 (WUGSC 2.1/galGal3) (galGal3)
+melGal1 Turkey Dec. 2009 (TGC Turkey_2.01/melGal1) (melGal1)
+taeGut1 Zebra finch Jul. 2008 (WUGSC 3.2.4/taeGut1) (taeGut1)
+anoCar2 Lizard May 2010 (Broad AnoCar2.0/anoCar2) (anoCar2)
+anoCar1 Lizard Feb. 2007 (Broad/anoCar1) (anoCar1)
+chrPic1 Painted turtle Dec. 2011 (v3.0.1/chrPic1) (chrPic1)
+xenTro3 X. tropicalis Nov. 2009 (JGI 4.2/xenTro3) (xenTro3)
+xenTro2 X. tropicalis Aug. 2005 (JGI 4.1/xenTro2) (xenTro2)
+danRer7 Zebrafish Jul. 2010 (Zv9/danRer7) (danRer7)
+danRer6 Zebrafish Dec. 2008 (Zv8/danRer6) (danRer6)
+tetNig2 Tetraodon Mar. 2007 (Genoscope 8.0/tetNig2) (tetNig2)
+tetNig1 Tetraodon Feb. 2004 (Genoscope 7/tetNig1) (tetNig1)
+fr3 Fugu Oct. 2011 (FUGU5/fr3) (fr3)
+fr2 Fugu Oct. 2004 (JGI 4.0/fr2) (fr2)
+gasAcu1 Stickleback Feb. 2006 (Broad/gasAcu1) (gasAcu1)
+oryLat2 Medaka Oct. 2005 (NIG/UT MEDAKA1/oryLat2) (oryLat2)
+petMar1 Lamprey Mar. 2007 (WUGSC 3.0/petMar1) (petMar1)
+aplCal1 Sea hare Sept. 2008 (Broad 2.0/aplCal1) (aplCal1)
+braFlo1 Lancelet Mar. 2006 (JGI 1.0/braFlo1) (braFlo1)
+ci2 C. intestinalis Mar. 2005 (JGI 2.1/ci2) (ci2)
+ci1 C. intestinalis Dec. 2002 (JGI 1.0/ci1) (ci1)
+strPur2 S. purpuratus Sep. 2006 (Baylor 2.1/strPur2) (strPur2)
+strPur1 S. purpuratus Apr. 2005 (Baylor 1.1/strPur1) (strPur1)
+ce10 C. elegans Oct. 2010 (WS220/ce10) (ce10)
+ce6 C. elegans May 2008 (WS190/ce6) (ce6)
+ce4 C. elegans Jan. 2007 (WS170/ce4) (ce4)
+caePb2 C. brenneri Feb. 2008 (WUGSC 6.0.1/caePb2) (caePb2)
+caePb1 C. brenneri Jan. 2007 (WUGSC 4.0/caePb1) (caePb1)
+cb3 C. briggsae Jan. 2007 (WUGSC 1.0/cb3) (cb3)
+cb1 C. briggsae July 2002 (WormBase cb25.agp8/cb1) (cb1)
+caeRem3 C. remanei May 2007 (WUGSC 15.0.1/caeRem3) (caeRem3)
+caeRem2 C. remanei Mar. 2006 (WUGSC 1.0/caeRem2) (caeRem2)
+caeJap1 C. japonica Mar. 2008 (WUGSC 3.0.2/caeJap1) (caeJap1)
+priPac1 P. pacificus Feb. 2007 (WUGSC 5.0/priPac1) (priPac1)
+dm3 D. melanogaster Apr. 2006 (BDGP R5/dm3) (dm3)
+dm2 D. melanogaster Apr. 2004 (BDGP R4/dm2) (dm2)
+droSim1 D. simulans Apr. 2005 (WUGSC mosaic 1.0/droSim1) (droSim1)
+droSec1 D. sechellia Oct. 2005 (Broad/droSec1) (droSec1)
+droYak2 D. yakuba Nov. 2005 (WUGSC 7.1/droYak2) (droYak2)
+droYak1 D. yakuba Apr. 2004 (WUGSC 1.0/droYak1) (droYak1)
+droEre1 D. erecta Aug. 2005 (Agencourt prelim/droEre1) (droEre1)
+droAna2 D. ananassae Aug. 2005 (Agencourt prelim/droAna2) (droAna2)
+droAna1 D. ananassae July 2004 (TIGR/droAna1) (droAna1)
+dp3 D. pseudoobscura Nov. 2004 (FlyBase 1.03/dp3) (dp3)
+dp2 D. pseudoobscura Aug. 2003 (Baylor freeze1/dp2) (dp2)
+droPer1 D. persimilis Oct. 2005 (Broad/droPer1) (droPer1)
+droVir2 D. virilis Aug. 2005 (Agencourt prelim/droVir2) (droVir2)
+droVir1 D. virilis July 2004 (Agencourt prelim/droVir1) (droVir1)
+droMoj2 D. mojavensis Aug. 2005 (Agencourt prelim/droMoj2) (droMoj2)
+droMoj1 D. mojavensis Aug. 2004 (Agencourt prelim/droMoj1) (droMoj1)
+droGri1 D. grimshawi Aug. 2005 (Agencourt prelim/droGri1) (droGri1)
+anoGam1 A. gambiae Feb. 2003 (IAGEC MOZ2/anoGam1) (anoGam1)
+apiMel2 A. mellifera Jan. 2005 (Baylor 2.0/apiMel2) (apiMel2)
+apiMel1 A. mellifera July 2004 (Baylor 1.2/apiMel1) (apiMel1)
+sacCer3 S. cerevisiae Apr. 2011 (SacCer_Apr2011/sacCer3) (sacCer3)
+sacCer2 S. cerevisiae June 2008 (SGD/sacCer2) (sacCer2)
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
commit/galaxy-central: inithello: Added missing builds.txt for Ensembl, fixed erroneous first line in output.
by Bitbucket 26 Jun '12
by Bitbucket 26 Jun '12
26 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/e112508794a8/
changeset: e112508794a8
user: inithello
date: 2012-06-26 21:10:25
summary: Added missing builds.txt for Ensembl, fixed erroneous first line in output.
affected #: 2 files
diff -r 40ff9b0e1549c1b083a3822b25b8337808ad8995 -r e112508794a8585e96bc1ba15c2be1cce421393d cron/get_ensembl.py
--- a/cron/get_ensembl.py
+++ b/cron/get_ensembl.py
@@ -17,6 +17,7 @@
for genome in genomes:
builds[genome[0]] = dict( release=genome[3], species='%s (%s/%s)' % ( genome[1], genome[2], genome[0] ) )
for build in builds.items():
- lines.append( '\t'.join( [ build[0], '%d' % build[1]['release'], build[1]['species'] ] ) )
+ if build[0]:
+ lines.append( '\t'.join( [ build[0], '%d' % build[1]['release'], build[1]['species'] ] ) )
-print '\n'.join( lines )
\ No newline at end of file
+print '\n'.join( lines )
diff -r 40ff9b0e1549c1b083a3822b25b8337808ad8995 -r e112508794a8585e96bc1ba15c2be1cce421393d tool-data/shared/ensembl/builds.txt
--- /dev/null
+++ b/tool-data/shared/ensembl/builds.txt
@@ -0,0 +1,165 @@
+ 67 Microcebus_murinus (Mouse lemur/)
+MEDAKA1 67 Oryzias_latipes (Medaka/MEDAKA1)
+Myoluc2.0 67 Myotis_lucifugus (Microbat/Myoluc2.0)
+anoCar1 67 Anolis_carolinensis (Anole lizard/anoCar1)
+WS220 67 Caenorhabditis_elegans (C.elegans/WS220)
+WS180 67 Caenorhabditis_elegans (C.elegans/WS180)
+MICROBAT1 67 Myotis_lucifugus (Microbat/MICROBAT1)
+loxAfr3 67 Loxodonta_africana (Elephant/loxAfr3)
+AgamP3 67 Anopheles_gambiae (Mosquito/AgamP3)
+DROM3 67 Drosophila_melanogaster (Fly/DROM3)
+LatCha1 67 Latimeria_chalumnae (Coelacanth/LatCha1)
+vicPac1 67 Vicugna_pacos (Alpaca/vicPac1)
+COMMON_SHREW1 67 Sorex_araneus (Shrew/COMMON_SHREW1)
+MGSC3 67 Mus_musculus (Mouse/MGSC3)
+MGSC1 67 Mus_musculus (Mouse/MGSC1)
+JGI4.1 67 Xenopus_tropicalis (Xenopus/JGI4.1)
+RGSC1 67 Rattus_norvegicus (Rat/RGSC1)
+RGSC2 67 Rattus_norvegicus (Rat/RGSC2)
+gadMor1 67 Gadus_morhua (Atlantic cod/gadMor1)
+CSAV2.0 67 Ciona_savignyi (C.savignyi/CSAV2.0)
+oryCun2 67 Oryctolagus_cuniculus (Rabbit/oryCun2)
+ZFISH6 67 Danio_rerio (Zebrafish/ZFISH6)
+ZFISH7 67 Danio_rerio (Zebrafish/ZFISH7)
+ZFISH4 67 Danio_rerio (Zebrafish/ZFISH4)
+ZFISH5 67 Danio_rerio (Zebrafish/ZFISH5)
+ZFISH2 67 Danio_rerio (Zebrafish/ZFISH2)
+ZFISH3 67 Danio_rerio (Zebrafish/ZFISH3)
+MOZ2a 67 Anopheles_gambiae (Mosquito/MOZ2a)
+EquCab2 67 Equus_caballus (Horse/EquCab2)
+AMEL1.1 67 Apis_mellifera (Honeybee/AMEL1.1)
+MMUL_1 67 Macaca_mulatta (Macaque/MMUL_1)
+dasNov2 67 Dasypus_novemcinctus (Armadillo/dasNov2)
+choHof1 67 Choloepus_hoffmanni (Sloth/choHof1)
+lamPac1 50 Lama_pacos (Alpaca/lamPac1)
+OANA5 67 Ornithorhynchus_anatinus (Platypus/OANA5)
+CEL160 67 Caenorhabditis_elegans (C.elegans/CEL160)
+WBcel215 67 Caenorhabditis_elegans (C.elegans/WBcel215)
+gorGor3 67 Gorilla_gorilla (Gorilla/gorGor3)
+SQUIRREL 67 Spermophilus_tridecemlineatus (Ground Squirrel/SQUIRREL)
+gorGor1 67 Gorilla_gorilla (Gorilla/gorGor1)
+pteVam1 67 Pteropus_vampyrus (Flying fox/pteVam1)
+SGD1 67 Saccharomyces_cerevisiae (S.cerevisiae/SGD1)
+micMur1 67 Microcebus_murinus (Mouse lemur/micMur1)
+proCap1 67 Procavia_capensis (Rock hyrax/proCap1)
+NCBIM30 67 Mus_musculus (Mouse/NCBIM30)
+NCBIM33 67 Mus_musculus (Mouse/NCBIM33)
+NCBIM32 67 Mus_musculus (Mouse/NCBIM32)
+NCBIM35 67 Mus_musculus (Mouse/NCBIM35)
+AaegL1 67 Aedes_aegypti (A.aegypti/AaegL1)
+NCBIM37 67 Mus_musculus (Mouse/NCBIM37)
+NCBIM36 67 Mus_musculus (Mouse/NCBIM36)
+EF2 67 Saccharomyces_cerevisiae (S.cerevisiae/EF2)
+EF3 67 Saccharomyces_cerevisiae (S.cerevisiae/EF3)
+EF4 67 Saccharomyces_cerevisiae (S.cerevisiae/EF4)
+BDGP5.4 67 Drosophila_melanogaster (Fly/BDGP5.4)
+PPYG2 67 Pongo_abelii (Orangutan/PPYG2)
+CEL150 67 Caenorhabditis_elegans (C.elegans/CEL150)
+AMEL2.0 67 Apis_mellifera (Honeybee/AMEL2.0)
+WASHUC1 67 Gallus_gallus (Chicken/WASHUC1)
+WASHUC2 67 Gallus_gallus (Chicken/WASHUC2)
+Btau_3.1 67 Bos_taurus (Cow/Btau_3.1)
+gorGor3.1 67 Gorilla_gorilla (Gorilla/gorGor3.1)
+CEL130 67 Caenorhabditis_elegans (C.elegans/CEL130)
+Zv9 67 Danio_rerio (Zebrafish/Zv9)
+BROADS1 67 Gasterosteus_aculeatus (Stickleback/BROADS1)
+BROADD2 67 Canis_familiaris (Dog/BROADD2)
+BROADD1 67 Canis_familiaris (Dog/BROADD1)
+pika 67 Ochotona_princeps (Pika/pika)
+ZFISH08 67 Danio_rerio (Zebrafish/ZFISH08)
+ZFISH06 67 Danio_rerio (Zebrafish/ZFISH06)
+calJac3 67 Callithrix_jacchus (Marmoset/calJac3)
+CHIMP2.1.4 67 Pan_troglodytes (Chimp/CHIMP2.1.4)
+JGI2 67 Ciona_intestinalis (C.intestinalis/JGI2)
+JGI3 67 Xenopus_tropicalis (Xenopus/JGI3)
+UCSC 67 Homo_sapiens (Human/UCSC)
+Zv8 67 Danio_rerio (Zebrafish/Zv8)
+JGI4 67 Xenopus_tropicalis (Xenopus/JGI4)
+CEL140 67 Caenorhabditis_elegans (C.elegans/CEL140)
+HEDGEHOG 67 Erinaceus_europaeus (Hedgehog/HEDGEHOG)
+callJacc3 67 Callithrix_jacchus (Marmoset/callJacc3)
+WS210 67 Caenorhabditis_elegans (C.elegans/WS210)
+BDGP4 67 Drosophila_melanogaster (Fly/BDGP4)
+BDGP5 67 Drosophila_melanogaster (Fly/BDGP5)
+CHIMP1 67 Pan_troglodytes (Chimp/CHIMP1)
+OtoGar3 67 Otolemur_garnettii (Bushbaby/OtoGar3)
+MOZ2 67 Anopheles_gambiae (Mosquito/MOZ2)
+FUGU4 67 Takifugu_rubripes (Fugu/FUGU4)
+MOZ1 67 Anopheles_gambiae (Mosquito/MOZ1)
+GUINEAPIG 67 Cavia_porcellus (Guinea Pig/GUINEAPIG)
+BROADE1 67 Loxodonta_africana (Elephant/BROADE1)
+RABBIT 67 Oryctolagus_cuniculus (Rabbit/RABBIT)
+TETRAODON7 67 Tetraodon_nigroviridis (Tetraodon/TETRAODON7)
+TETRAODON8 67 Tetraodon_nigroviridis (Tetraodon/TETRAODON8)
+gorGor2 67 Gorilla_gorilla (Gorilla/gorGor2)
+SGD1.01 67 Saccharomyces_cerevisiae (S.cerevisiae/SGD1.01)
+ailMel1 67 Ailuropoda_melanoleuca (Panda/ailMel1)
+Sscrofa9 67 Sus_scrofa (Pig/Sscrofa9)
+cavPor3 67 Cavia_porcellus (Guinea Pig/cavPor3)
+Orenil1.0 67 Oreochromis_niloticus (Nile tilapia/Orenil1.0)
+BDGP4.2 67 Drosophila_melanogaster (Fly/BDGP4.2)
+BDGP4.3 67 Drosophila_melanogaster (Fly/BDGP4.3)
+Petromyzon_marin 64 Petromyzon_marinus (Lamprey/Petromyzon_marin)
+RGSC3.4 67 Rattus_norvegicus (Rat/RGSC3.4)
+Pmarinus_7.0 67 Petromyzon_marinus (Lamprey/Pmarinus_7.0)
+RGSC3.1 67 Rattus_norvegicus (Rat/RGSC3.1)
+BDGP5.25 67 Drosophila_melanogaster (Fly/BDGP5.25)
+ARMA 67 Dasypus_novemcinctus (Armadillo/ARMA)
+CINT1.95 67 Ciona_intestinalis (C.intestinalis/CINT1.95)
+Btau_1.0 67 Bos_taurus (Cow/Btau_1.0)
+JGI_4.2 67 Xenopus_tropicalis (Xenopus/JGI_4.2)
+CEL116 67 Caenorhabditis_elegans (C.elegans/CEL116)
+BUSHBABY1 67 Otolemur_garnettii (Bushbaby/BUSHBABY1)
+Sscrofa10.2 67 Sus_scrofa (Pig/Sscrofa10.2)
+BDGP3.2.1 67 Drosophila_melanogaster (Fly/BDGP3.2.1)
+taeGut3.2.4 67 Taeniopygia_guttata (Zebra finch/taeGut3.2.4)
+KH 67 Ciona_intestinalis (C.intestinalis/KH)
+JGI4_1 67 Xenopus_tropicalis (Xenopus/JGI4_1)
+spetri2 67 Spermophilus_tridecemlineatus (Ground Squirrel/spetri2)
+Btau_4.0 67 Bos_taurus (Cow/Btau_4.0)
+UMD2 67 Meleagris_gallopavo (Turkey/UMD2)
+NCBI28 67 Homo_sapiens (Human/NCBI28)
+NCBI29 67 Homo_sapiens (Human/NCBI29)
+Btau_2.0 67 Bos_taurus (Cow/Btau_2.0)
+NCBI26 67 Homo_sapiens (Human/NCBI26)
+CAT 67 Felis_catus (Cat/CAT)
+TENREC 67 Echinops_telfairi (Tenrec/TENREC)
+WS200 67 Caenorhabditis_elegans (C.elegans/WS200)
+AnoCar1.0 67 Anolis_carolinensis (Anole lizard/AnoCar1.0)
+Nleu1.0 67 Nomascus_leucogenys (Gibbon/Nleu1.0)
+Meug_1.0 67 Macropus_eugenii (Wallaby/Meug_1.0)
+C_jacchus3.2.1 67 Callithrix_jacchus (Marmoset/C_jacchus3.2.1)
+CHIMP2.1 67 Pan_troglodytes (Chimp/CHIMP2.1)
+WS190 67 Caenorhabditis_elegans (C.elegans/WS190)
+dipOrd1 67 Dipodomys_ordii (Kangaroo rat/dipOrd1)
+AnoCar2.0 67 Anolis_carolinensis (Anole lizard/AnoCar2.0)
+ACME0.1 67 None (None/ACME0.1)
+CEL95 67 Caenorhabditis_elegans (C.elegans/CEL95)
+CEL93 67 Caenorhabditis_elegans (C.elegans/CEL93)
+DEVIL7.0 67 Sarcophilus_harrisii (Tasmanian Devil/DEVIL7.0)
+CEL98 67 Caenorhabditis_elegans (C.elegans/CEL98)
+CEL102 67 Caenorhabditis_elegans (C.elegans/CEL102)
+TREESHREW 67 Tupaia_belangeri (Tree Shrew/TREESHREW)
+NCBI31 67 Homo_sapiens (Human/NCBI31)
+NCBI30 67 Homo_sapiens (Human/NCBI30)
+NCBI33 67 Homo_sapiens (Human/NCBI33)
+NCBI35 67 Homo_sapiens (Human/NCBI35)
+NCBI34 67 Homo_sapiens (Human/NCBI34)
+turTru1 67 Tursiops_truncatus (Bottlenose dolphin/turTru1)
+NCBI36 67 Homo_sapiens (Human/NCBI36)
+UMD3.1 67 Bos_taurus (Cow/UMD3.1)
+speTri1 67 Spermophilus_tridecemlineatus (Ground Squirrel/speTri1)
+GRCh37 67 Homo_sapiens (Human/GRCh37)
+CHIMP1A 67 Pan_troglodytes (Chimp/CHIMP1A)
+WB170 67 Caenorhabditis_elegans (C.elegans/WB170)
+FUGU1 67 Takifugu_rubripes (Fugu/FUGU1)
+FUGU2 67 Takifugu_rubripes (Fugu/FUGU2)
+NCBIM34 67 Mus_musculus (Mouse/NCBIM34)
+DROM3A 67 Drosophila_melanogaster (Fly/DROM3A)
+tarSyr1 67 Tarsius_syrichta (Tarsier/tarSyr1)
+CBR25 67 Caenorhabditis_briggsae (C.briggsae/CBR25)
+BROADO5 67 Monodelphis_domestica (Opossum/BROADO5)
+BROADO2 67 Monodelphis_domestica (Opossum/BROADO2)
+BROADO3 67 Monodelphis_domestica (Opossum/BROADO3)
+BDGP5.13 67 Drosophila_melanogaster (Fly/BDGP5.13)
+MMUL_0_1 67 Macaca_mulatta (Macaque/MMUL_0_1)
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
26 Jun '12
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/40ff9b0e1549/
changeset: 40ff9b0e1549
user: dannon
date: 2012-06-26 17:07:09
summary: Add share_string option to cloud_launch.
affected #: 2 files
diff -r 2e0254547b09bfccbd0834524a0fb4919b6a6efd -r 40ff9b0e1549c1b083a3822b25b8337808ad8995 lib/galaxy/web/controllers/cloudlaunch.py
--- a/lib/galaxy/web/controllers/cloudlaunch.py
+++ b/lib/galaxy/web/controllers/cloudlaunch.py
@@ -25,11 +25,11 @@
BaseUIController.__init__(self, app)
@web.expose
- def index(self, trans):
- return trans.fill_template("cloud/index.mako")
+ def index(self, trans, share_string=None):
+ return trans.fill_template("cloud/index.mako", share_string=share_string)
@web.expose
- def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type):
+ def launch_instance(self, trans, cluster_name, password, key_id, secret, instance_type, share_string):
ec2_error = None
try:
# Create security group & key pair used when starting an instance
@@ -47,6 +47,8 @@
'instance_type':instance_type}
if password:
user_provided_data['password'] = password
+ if share_string:
+ user_provided_data['share_string'] = share_string
rs = run_instance(ec2_conn=ec2_conn,
user_provided_data=user_provided_data,
key_name=kp_name,
diff -r 2e0254547b09bfccbd0834524a0fb4919b6a6efd -r 40ff9b0e1549c1b083a3822b25b8337808ad8995 templates/cloud/index.mako
--- a/templates/cloud/index.mako
+++ b/templates/cloud/index.mako
@@ -59,7 +59,7 @@
<form action="${h.url_for( controller='cloudlaunch', action='launch_instance' )}" method="post"><div class="form-row"><label for="id_cluster_name">Cluster Name</label>
- <input type="text" size="80" name="cluster_name" id="id_cluster_name"/><br/>
+ <input type="text" size="40" name="cluster_name" id="id_cluster_name"/><br/></div><div class="form-row"><label for="id_password">Password</label>
@@ -73,6 +73,14 @@
<label for="id_secret">Secret Key</label><input type="password" size="120" name="secret" id="id_secret"/><br/></div>
+ %if share_string:
+ <input type='hidden' name='share_string' value='${share_string}'/>
+ %else:
+ <div class="form-row">
+ <label for="id_share_string">Instance Share String (optional)</label>
+ <input type="text" size="120" name="share_string" id="id_share_string"/><br/>
+ </div>
+ %endif
<div class="form-row"><label for="id_instance_type">Instance Type</label><select name="instance_type" id="id_instance_type">
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0
1 new commit in galaxy-central:
https://bitbucket.org/galaxy/galaxy-central/changeset/2e0254547b09/
changeset: 2e0254547b09
user: smcmanus
date: 2012-06-25 23:16:49
summary: Recommit of PBS and DRMAA fixes
affected #: 3 files
diff -r 319b2b0e832c8ea5ef520c76722f7ad6270507c3 -r 2e0254547b09bfccbd0834524a0fb4919b6a6efd lib/galaxy/jobs/__init__.py
--- a/lib/galaxy/jobs/__init__.py
+++ b/lib/galaxy/jobs/__init__.py
@@ -291,8 +291,6 @@
the output datasets based on stderr and stdout from the command, and
the contents of the output files.
"""
- # TODO: Eliminate debugging code after testing all runners
- log.debug( "JobWrapper.finish: exit code:" + str(tool_exit_code) )
# default post job setup
self.sa_session.expunge_all()
job = self.get_job()
diff -r 319b2b0e832c8ea5ef520c76722f7ad6270507c3 -r 2e0254547b09bfccbd0834524a0fb4919b6a6efd lib/galaxy/jobs/runners/drmaa.py
--- a/lib/galaxy/jobs/runners/drmaa.py
+++ b/lib/galaxy/jobs/runners/drmaa.py
@@ -39,6 +39,11 @@
drmaa.JobState.FAILED: 'job finished, but failed',
}
+# The last four lines (following the last fi) will:
+# - setup the env
+# - move to the job wrapper's working directory
+# - execute the command
+# - take the command's exit code ($?) and write it to a file.
drm_template = """#!/bin/sh
GALAXY_LIB="%s"
if [ "$GALAXY_LIB" != "None" ]; then
@@ -52,6 +57,7 @@
%s
cd %s
%s
+echo $? > %s
"""
def __lineno__():
"""Returns the current line number in our program."""
@@ -77,7 +83,7 @@
self.job_file = None
self.ofile = None
self.efile = None
- self.rcfile = None
+ self.ecfile = None
self.runner_url = None
class DRMAAJobRunner( BaseJobRunner ):
@@ -169,7 +175,7 @@
# define job attributes
ofile = "%s.drmout" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
efile = "%s.drmerr" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
- rcfile = "%s.drmrc" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
+ ecfile = "%s.drmec" % os.path.join(job_wrapper.working_directory, job_wrapper.get_id_tag())
job_name = "g%s_%s_%s" % ( job_wrapper.job_id, job_wrapper.tool.id, job_wrapper.user )
job_name = ''.join( map( lambda x: x if x in ( string.letters + string.digits + '_' ) else '_', job_name ) )
@@ -178,7 +184,7 @@
jt.jobName = job_name
jt.outputPath = ":%s" % ofile
jt.errorPath = ":%s" % efile
- jt.returnCodePath = ":%s" % rcfile
+ # Avoid a jt.exitCodePath for now - it's only used when finishing.
native_spec = self.get_native_spec( runner_url )
if native_spec is not None:
jt.nativeSpecification = native_spec
@@ -187,7 +193,8 @@
script = drm_template % ( job_wrapper.galaxy_lib_dir,
job_wrapper.get_env_setup_clause(),
os.path.abspath( job_wrapper.working_directory ),
- command_line )
+ command_line,
+ ecfile )
try:
fh = file( jt.remoteCommand, "w" )
@@ -231,7 +238,7 @@
drm_job_state.job_id = job_id
drm_job_state.ofile = ofile
drm_job_state.efile = efile
- drm_job_state.rcfile = rcfile
+ drm_job_state.ecfile = ecfile
drm_job_state.job_file = jt.remoteCommand
drm_job_state.old_state = 'new'
drm_job_state.running = False
@@ -316,17 +323,22 @@
"""
ofile = drm_job_state.ofile
efile = drm_job_state.efile
- rcfile = drm_job_state.rcfile
+ ecfile = drm_job_state.ecfile
job_file = drm_job_state.job_file
# collect the output
# wait for the files to appear
which_try = 0
+ # By default, the exit code is 0, which typically indicates success.
+ exit_code = 0
while which_try < (self.app.config.retry_job_output_collection + 1):
try:
ofh = file(ofile, "r")
efh = file(efile, "r")
+ ecfh = file(ecfile, "r")
stdout = ofh.read( 32768 )
stderr = efh.read( 32768 )
+ # The exit code should only be 8 bits, but read more anyway
+ exit_code_str = ecfh.read(32)
which_try = (self.app.config.retry_job_output_collection + 1)
except:
if which_try == self.app.config.retry_job_output_collection:
@@ -337,8 +349,15 @@
time.sleep(1)
which_try += 1
+ # Decode the exit code. If it's bogus, then just use 0.
try:
- drm_job_state.job_wrapper.finish( stdout, stderr )
+ exit_code = int(exit_code_str)
+ except:
+ log.warning( "Exit code " + exit_code_str + " invalid. Using 0." )
+ exit_code = 0
+
+ try:
+ drm_job_state.job_wrapper.finish( stdout, stderr, exit_code )
except:
log.exception("Job wrapper finish method failed")
@@ -382,7 +401,7 @@
drm_job_state = DRMAAJobState()
drm_job_state.ofile = "%s.drmout" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
drm_job_state.efile = "%s.drmerr" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
- drm_job_state.rcfile = "%s.drmrc" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
+ drm_job_state.ecfile = "%s.drmec" % os.path.join(os.getcwd(), job_wrapper.working_directory, job_wrapper.get_id_tag())
drm_job_state.job_file = "%s/galaxy_%s.sh" % (self.app.config.cluster_files_directory, job.id)
drm_job_state.job_id = str( job.job_runner_external_id )
drm_job_state.runner_url = job_wrapper.get_job_runner()
diff -r 319b2b0e832c8ea5ef520c76722f7ad6270507c3 -r 2e0254547b09bfccbd0834524a0fb4919b6a6efd lib/galaxy/jobs/runners/pbs.py
--- a/lib/galaxy/jobs/runners/pbs.py
+++ b/lib/galaxy/jobs/runners/pbs.py
@@ -532,16 +532,22 @@
stdout = ofh.read( 32768 )
stderr = efh.read( 32768 )
# This should be an 8-bit exit code, but read ahead anyway:
- exit_code = ecfh.read(32)
+ exit_code_str = ecfh.read(32)
except:
stdout = ''
stderr = 'Job output not returned by PBS: the output datasets were deleted while the job was running, the job was manually dequeued or there was a cluster error.'
# By default, the exit code is 0, which usually indicates success
# (although clearly some error happened).
+ exit_code_str = ""
+
+ # Translate the exit code string to an integer; use 0 on failure.
+ try:
+ exit_code = int( exit_code_str )
+ except:
+ log.warning( "Exit code " + exit_code_str + " was invalid. Using 0." )
exit_code = 0
- log.debug(stderr)
- log.debug( "Job exit code: " + exit_code )
+ # Call on the job wrapper to complete the call:
try:
pbs_job_state.job_wrapper.finish( stdout, stderr, exit_code )
except:
Repository URL: https://bitbucket.org/galaxy/galaxy-central/
--
This is a commit notification from bitbucket.org. You are receiving
this because you have the service enabled, addressing the recipient of
this email.
1
0