62 new commits in galaxy-central: https://bitbucket.org/galaxy/galaxy-central/commits/08823838e8ad/ Changeset: 08823838e8ad User: guerler Date: 2015-03-02 23:12:34+00:00 Summary: Parameters: Cover additional case for multiple hdas Affected #: 1 file diff -r 13cc751d07ed98a6c0ebbd781a8c6319a7f8e1f9 -r 08823838e8ad98857d58b28372af520e710afb1c lib/galaxy/tools/parameters/basic.py --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2005,6 +2005,8 @@ rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) else: raise ValueError("Unknown input source %s passed to job submission API." % single_value['src']) + elif isinstance( single_value, trans.app.model.HistoryDatasetAssociation ): + rval.append( single_value ) else: rval.append( trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( single_value ) ) elif isinstance( value, trans.app.model.HistoryDatasetAssociation ): https://bitbucket.org/galaxy/galaxy-central/commits/51bc7e8dff5f/ Changeset: 51bc7e8dff5f User: guerler Date: 2015-03-02 23:25:46+00:00 Summary: Parameters: Fix collection selection for multiple dataset input field Affected #: 5 files diff -r 08823838e8ad98857d58b28372af520e710afb1c -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 client/galaxy/scripts/mvc/tools/tools-select-content.js --- a/client/galaxy/scripts/mvc/tools/tools-select-content.js +++ b/client/galaxy/scripts/mvc/tools/tools-select-content.js @@ -217,7 +217,7 @@ } // identify suitable select field - if (new_value && new_value.values.length > 0 && new_value.values[0].src == 'hcda') { + if (new_value && new_value.values.length > 0 && new_value.values[0].src == 'hdca') { this.current = 'collection'; this.select_collection.value(list[0]); } else { diff -r 08823838e8ad98857d58b28372af520e710afb1c -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -2316,6 +2316,11 @@ 'id' : trans.security.encode_id(v.id), 'src' : 'hda' } + elif isinstance(v, trans.app.model.HistoryDatasetCollectionAssociation): + return { + 'id' : trans.security.encode_id(v.id), + 'src' : 'hdca' + } elif isinstance(v, bool): if v is True: return 'true' diff -r 08823838e8ad98857d58b28372af520e710afb1c -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 lib/galaxy/tools/parameters/basic.py --- a/lib/galaxy/tools/parameters/basic.py +++ b/lib/galaxy/tools/parameters/basic.py @@ -2023,6 +2023,8 @@ encoded_id = str( value )[ len( "__collection_reduce__|" ): ] decoded_id = trans.app.security.decode_id( encoded_id ) rval = trans.sa_session.query( trans.app.model.HistoryDatasetCollectionAssociation ).get( decoded_id ) + elif isinstance( value, trans.app.model.HistoryDatasetCollectionAssociation ): + rval = value else: rval = trans.sa_session.query( trans.app.model.HistoryDatasetAssociation ).get( value ) if isinstance( rval, list ): diff -r 08823838e8ad98857d58b28372af520e710afb1c -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 static/scripts/mvc/tools/tools-select-content.js --- a/static/scripts/mvc/tools/tools-select-content.js +++ b/static/scripts/mvc/tools/tools-select-content.js @@ -217,7 +217,7 @@ } // identify suitable select field - if (new_value && new_value.values.length > 0 && new_value.values[0].src == 'hcda') { + if (new_value && new_value.values.length > 0 && new_value.values[0].src == 'hdca') { this.current = 'collection'; this.select_collection.value(list[0]); } else { diff -r 08823838e8ad98857d58b28372af520e710afb1c -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 static/scripts/packed/mvc/tools/tools-select-content.js --- a/static/scripts/packed/mvc/tools/tools-select-content.js +++ b/static/scripts/packed/mvc/tools/tools-select-content.js @@ -1,1 +1,1 @@ -define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(g,p){this.app=g;this.options=p;var o=this;this.setElement('<div class="ui-select-content"/>');this.list={};var m=[];if(p.type=="data_collection"){this.mode="collection"}else{if(p.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var k=c.textify(p.extensions);var j="No dataset available.";if(k){j="No "+k+" dataset available."}var l="No dataset list available.";if(k){l="No "+k+" dataset collection available."}if(this.mode=="single"){m.push({icon:"fa-file-o",value:"single",tooltip:"Single dataset"});this.select_single=new e.Select.View({optional:p.optional,error_text:j,onchange:function(){o.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",value:"multiple",tooltip:"Multiple datasets"});this.select_multiple=new e.Select.View({multiple:true,searchable:false,error_text:j,onchange:function(){o.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"||this.mode=="collection"){m.push({icon:"fa-folder-o",value:"collection",tooltip:"Dataset collection"});this.select_collection=new e.Select.View({error_text:l,optional:p.optional,onchange:function(){o.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){o.current=i;o.refresh();o.trigger("change")}});this.$batch=$(a.batchMode());var f=_.size(this.list);var n=0;if(f>1){this.$el.append(this.button_type.$el);n=Math.max(0,_.size(this.list)*35)+"px"}for(var h in this.list){this.$el.append(this.list[h].field.$el.css({"margin-left":n}))}this.$el.append(this.$batch.css({"margin-left":n}));this.update(p.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(p.onchange){p.onchange(o.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(h){var f=this;function g(m,j){if(m){var n=[];for(var k in j){var l=j[k];n.push({label:l.hid+": "+l.name,value:l.id});f.app.history[l.id+"_"+l.src]=l}m.update(n)}}g(this.select_single,h.hda);g(this.select_multiple,h.hda);g(this.select_collection,h.hdca)},value:function(j){if(j!==undefined){if(j&&j.values){try{var m=[];for(var h in j.values){m.push(j.values[h].id)}if(j&&j.values.length>0&&j.values[0].src=="hcda"){this.current="collection";this.select_collection.value(m[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(m)}else{this.current="single";this.select_single.value(m[0])}}}catch(l){console.debug("tools-select-content::value() - Skipped.")}}else{for(var h in this.list){this.list[h].field.value(null)}}}this.refresh();var k=this._select().value();if(k===null){return null}if(!(k instanceof Array)){k=[k]}if(k.length===0){return null}var f={batch:this._batch(),values:[]};for(var h in k){var g=_.findWhere(this.app.history,{id:k[h],src:this.list[this.current].type});if(g){f.values.push(g)}else{return null}}f.values.sort(function(n,i){return n.hid-i.hid});return f},refresh:function(){this.button_type.value(this.current);for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this._batch()){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field},_batch:function(){if(this.current=="collection"){var f=_.findWhere(this.app.history,{id:this._select().value(),src:"hdca"});if(f&&f.map_over_type){return true}}if(this.current!="single"){if(this.mode=="single"){return true}}return false}});return{View:d}}); \ No newline at end of file +define(["utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs","mvc/tools/tools-template"],function(c,e,b,a){var d=Backbone.View.extend({initialize:function(g,p){this.app=g;this.options=p;var o=this;this.setElement('<div class="ui-select-content"/>');this.list={};var m=[];if(p.type=="data_collection"){this.mode="collection"}else{if(p.multiple){this.mode="multiple"}else{this.mode="single"}}this.current=this.mode;this.list={};var k=c.textify(p.extensions);var j="No dataset available.";if(k){j="No "+k+" dataset available."}var l="No dataset list available.";if(k){l="No "+k+" dataset collection available."}if(this.mode=="single"){m.push({icon:"fa-file-o",value:"single",tooltip:"Single dataset"});this.select_single=new e.Select.View({optional:p.optional,error_text:j,onchange:function(){o.trigger("change")}});this.list.single={field:this.select_single,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"){m.push({icon:"fa-files-o",value:"multiple",tooltip:"Multiple datasets"});this.select_multiple=new e.Select.View({multiple:true,searchable:false,error_text:j,onchange:function(){o.trigger("change")}});this.list.multiple={field:this.select_multiple,type:"hda"}}if(this.mode=="single"||this.mode=="multiple"||this.mode=="collection"){m.push({icon:"fa-folder-o",value:"collection",tooltip:"Dataset collection"});this.select_collection=new e.Select.View({error_text:l,optional:p.optional,onchange:function(){o.trigger("change")}});this.list.collection={field:this.select_collection,type:"hdca"}}this.button_type=new e.RadioButton.View({value:this.current,data:m,onchange:function(i){o.current=i;o.refresh();o.trigger("change")}});this.$batch=$(a.batchMode());var f=_.size(this.list);var n=0;if(f>1){this.$el.append(this.button_type.$el);n=Math.max(0,_.size(this.list)*35)+"px"}for(var h in this.list){this.$el.append(this.list[h].field.$el.css({"margin-left":n}))}this.$el.append(this.$batch.css({"margin-left":n}));this.update(p.data);if(this.options.value!==undefined){this.value(this.options.value)}this.refresh();this.on("change",function(){if(p.onchange){p.onchange(o.value())}})},wait:function(){for(var f in this.list){this.list[f].field.wait()}},unwait:function(){for(var f in this.list){this.list[f].field.unwait()}},update:function(g){function f(l,h){if(l){var m=[];for(var j in h){var k=h[j];m.push({label:k.hid+": "+k.name,value:k.id})}l.update(m)}}f(this.select_single,g.hda);f(this.select_multiple,g.hda);f(this.select_collection,g.hdca);this.app.content.add(g)},value:function(j){if(j!==undefined){if(j&&j.values){try{var m=[];for(var h in j.values){m.push(j.values[h].id)}if(j&&j.values.length>0&&j.values[0].src=="hdca"){this.current="collection";this.select_collection.value(m[0])}else{if(this.mode=="multiple"){this.current="multiple";this.select_multiple.value(m)}else{this.current="single";this.select_single.value(m[0])}}}catch(l){console.debug("tools-select-content::value() - Skipped.")}}else{for(var h in this.list){this.list[h].field.value(null)}}}this.refresh();var k=this._select().value();if(k===null){return null}if(!(k instanceof Array)){k=[k]}if(k.length===0){return null}var f={batch:this._batch(),values:[]};for(var h in k){var g=this.app.content.get({id:k[h],src:this.list[this.current].type});if(g){f.values.push(g)}else{return null}}f.values.sort(function(n,i){return n.hid-i.hid});return f},refresh:function(){this.button_type.value(this.current);for(var g in this.list){var f=this.list[g].field.$el;if(this.current==g){f.show()}else{f.hide()}}if(this._batch()){this.$batch.show()}else{this.$batch.hide()}},_select:function(){return this.list[this.current].field},_batch:function(){if(this.current=="collection"){var f=this.app.content.get({id:this._select().value(),src:"hdca"});if(f&&f.map_over_type){return true}}if(this.current!="single"){if(this.mode=="single"){return true}}return false}});return{View:d}}); https://bitbucket.org/galaxy/galaxy-central/commits/97e7643798d4/ Changeset: 97e7643798d4 User: jmchilton Date: 2015-03-03 02:32:30+00:00 Summary: Tool data API testing fixes. - Add files I didn't commit previously in test/functional/tool-data/. - Comment out test for tool data table deletion since Dan fixed the problem of regular users running data managers through the API (https://github.com/galaxyproject/galaxy/commit/48f77dc742acf01ddbafafcc4634e...) that I previously exploited to write the test. Affected #: 5 files diff -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 -r 97e7643798d489d4b6e171f359a22a9c650e9fd5 test/api/test_tool_data.py --- a/test/api/test_tool_data.py +++ b/test/api/test_tool_data.py @@ -1,11 +1,6 @@ """ Tests for the tool data API. """ -import json - from base import api -from .helpers import DatasetPopulator - -from requests import delete import operator @@ -40,7 +35,7 @@ field = show_field_response.json() self._assert_has_keys( field, "files", "name", "fields", "fingerprint", "base_dir" ) files = field[ "files" ] - assert len( files ) == 2 + assert len( files ) == 2, "Length of files [%s] was not 2." % files def test_download_field_file(self): show_field_response = self._get( "tool_data/testalpha/fields/data1/files/entry.txt", admin=True ) @@ -48,27 +43,32 @@ content = show_field_response.content assert content == "This is data 1.", content - def test_delete_entry(self): - show_response = self._get( "tool_data/testbeta", admin=True ) - original_count = len(show_response.json()["fields"]) + # Following test case rendered invalid by the fix in + # https://github.com/galaxyproject/galaxy/commit/48f77dc742acf01ddbafafcc4634e.... + # TODO: Restore the test case when test framework allows actions from + # admin users. - dataset_populator = DatasetPopulator( self.galaxy_interactor ) - history_id = dataset_populator.new_history() - payload = dataset_populator.run_tool_payload( - tool_id="data_manager", - inputs={"ignored_value": "moo"}, - history_id=history_id, - ) - create_response = self._post( "tools", data=payload ) - self._assert_status_code_is( create_response, 200 ) - dataset_populator.wait_for_history( history_id, assert_ok=True ) - show_response = self._get( "tool_data/testbeta", admin=True ) - updated_fields = show_response.json()["fields"] - assert len(updated_fields) == original_count + 1 - field0 = updated_fields[0] - url = self._api_url( "tool_data/testbeta?key=%s" % self.galaxy_interactor.master_api_key ) - delete( url, data=json.dumps({"values": "\t".join(field0)}) ) + # def test_delete_entry(self): + # show_response = self._get( "tool_data/testbeta", admin=True ) + # original_count = len(show_response.json()["fields"]) - show_response = self._get( "tool_data/testbeta", admin=True ) - updated_fields = show_response.json()["fields"] - assert len(updated_fields) == original_count + # dataset_populator = DatasetPopulator( self.galaxy_interactor ) + # history_id = dataset_populator.new_history() + # payload = dataset_populator.run_tool_payload( + # tool_id="data_manager", + # inputs={"ignored_value": "moo"}, + # history_id=history_id, + # ) + # create_response = self._post( "tools", data=payload ) + # self._assert_status_code_is( create_response, 200 ) + # dataset_populator.wait_for_history( history_id, assert_ok=True ) + # show_response = self._get( "tool_data/testbeta", admin=True ) + # updated_fields = show_response.json()["fields"] + # assert len(updated_fields) == original_count + 1 + # field0 = updated_fields[0] + # url = self._api_url( "tool_data/testbeta?key=%s" % self.galaxy_interactor.master_api_key ) + # delete( url, data=json.dumps({"values": "\t".join(field0)}) ) + + # show_response = self._get( "tool_data/testbeta", admin=True ) + # updated_fields = show_response.json()["fields"] + # assert len(updated_fields) == original_count diff -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 -r 97e7643798d489d4b6e171f359a22a9c650e9fd5 test/functional/tool-data/data1/entry.txt --- /dev/null +++ b/test/functional/tool-data/data1/entry.txt @@ -0,0 +1,1 @@ +This is data 1. \ No newline at end of file diff -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 -r 97e7643798d489d4b6e171f359a22a9c650e9fd5 test/functional/tool-data/data1/entry.txt.index --- /dev/null +++ b/test/functional/tool-data/data1/entry.txt.index @@ -0,0 +1,1 @@ +fancy compressed map built with cool algorithms... \ No newline at end of file diff -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 -r 97e7643798d489d4b6e171f359a22a9c650e9fd5 test/functional/tool-data/data2/entry.txt --- /dev/null +++ b/test/functional/tool-data/data2/entry.txt @@ -0,0 +1,1 @@ +This is data 2. \ No newline at end of file diff -r 51bc7e8dff5fd57837977620a26a671f5bdc3019 -r 97e7643798d489d4b6e171f359a22a9c650e9fd5 test/functional/tool-data/data2/entry.txt.index --- /dev/null +++ b/test/functional/tool-data/data2/entry.txt.index @@ -0,0 +1,1 @@ +fancy compressed map built with cool algorithms...2 \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/88e6c41723f0/ Changeset: 88e6c41723f0 User: jmchilton Date: 2015-03-03 03:31:32+00:00 Summary: Attempt to fix intermittently failing jobs API test. Retry check several times in case there is some sort of timing problem where a history turns okay - before a job. Improve assertion error message. Affected #: 1 file diff -r 97e7643798d489d4b6e171f359a22a9c650e9fd5 -r 88e6c41723f00f8f002055ff60f04d7866978cda test/api/test_jobs.py --- a/test/api/test_jobs.py +++ b/test/api/test_jobs.py @@ -29,14 +29,23 @@ def test_index_state_filter( self ): # Initial number of ok jobs original_count = len( self.__uploads_with_state( "ok" ) ) - # Run through dataset upload to ensure num uplaods at least greater # by 1. self.__history_with_ok_dataset() # Verify number of ok jobs is actually greater. - new_count = len( self.__uploads_with_state( "ok" ) ) - assert original_count < new_count + count_increased = False + for i in range(10): + new_count = len( self.__uploads_with_state( "ok" ) ) + if original_count < new_count: + count_increased = True + break + time.sleep(.1) + + if not count_increased: + template = "Jobs in ok state did not increase (was %d, now %d)" + message = template % (original_count, new_count) + raise AssertionError(message) def test_index_date_filter( self ): self.__history_with_new_dataset() https://bitbucket.org/galaxy/galaxy-central/commits/3228080bffa9/ Changeset: 3228080bffa9 User: jmchilton Date: 2015-03-03 03:33:07+00:00 Summary: Clarify failing test test_tools.py. Affected #: 1 file diff -r 88e6c41723f00f8f002055ff60f04d7866978cda -r 3228080bffa9575b15b546624507f79c2f917793 test/api/test_tools.py --- a/test/api/test_tools.py +++ b/test/api/test_tools.py @@ -219,8 +219,9 @@ 'col': "' ; echo 'moo", } response = self._run( "column_param", history_id, inputs ) - # TODO: make this test pass... - self._assert_status_code_is( response, 400 ) + if response.status_code == 200: + message = "Known, high priority issue. Column parameters are sanitized but invalid values should prevent execution and doesn't." + raise AssertionError(message) @skip_without_tool( "collection_paired_test" ) def test_collection_parameter( self ): https://bitbucket.org/galaxy/galaxy-central/commits/f0daa8303fcc/ Changeset: f0daa8303fcc User: jmchilton Date: 2015-03-03 03:34:40+00:00 Summary: Remove assert False from test/api/test_workflows_from_yaml.py. These aren't ideal tests - but it is some indication that things are working that the API will import the workflow and produce a representation. Should follow up at some point and verify the representation is in fact the correct one. Affected #: 1 file diff -r 3228080bffa9575b15b546624507f79c2f917793 -r f0daa8303fccf087a7ec68269c865fbd6ceb94ab test/api/test_workflows_from_yaml.py --- a/test/api/test_workflows_from_yaml.py +++ b/test/api/test_workflows_from_yaml.py @@ -100,8 +100,6 @@ $link: the_pause """) print self._get("workflows/%s/download" % workflow_id).json() - assert False - # TODO: fill out test... def test_implicit_connections( self ): workflow_id = self._upload_yaml_workflow(""" @@ -132,4 +130,3 @@ """) workflow = self._get("workflows/%s/download" % workflow_id).json() print workflow - assert False https://bitbucket.org/galaxy/galaxy-central/commits/6dfbd65fa1e8/ Changeset: 6dfbd65fa1e8 User: jmchilton Date: 2015-03-03 14:30:55+00:00 Summary: Fix intermittently failing test test_workflow_run_dynamic_output_collections. Love it when the bugs correspond to actual TODOs I left in the code. Affected #: 1 file diff -r f0daa8303fccf087a7ec68269c865fbd6ceb94ab -r 6dfbd65fa1e839b90380bd7ea4c67282400b4502 test/api/test_workflows.py --- a/test/api/test_workflows.py +++ b/test/api/test_workflows.py @@ -570,11 +570,13 @@ '0': self._ds_entry(hda1), '1': self._ds_entry(hda2), } - self.__invoke_workflow( history_id, workflow_id, inputs ) - # TODO: wait on workflow invocations - time.sleep(10) - self.dataset_populator.wait_for_history( history_id, assert_ok=True ) - self.assertEquals("10.0\n30.0\n20.0\n40.0\n", self.dataset_populator.get_history_dataset_content( history_id, hid=0 ) ) + invocation_id = self.__invoke_workflow( history_id, workflow_id, inputs ) + self.wait_for_invocation_and_jobs( history_id, workflow_id, invocation_id ) + details = self.dataset_populator.get_history_dataset_details( history_id, hid=0 ) + last_item_hid = details["hid"] + assert last_item_hid == 7, "Expected 7 history items, got %s" % last_item_hid + content = self.dataset_populator.get_history_dataset_content( history_id, hid=0 ) + self.assertEquals("10.0\n30.0\n20.0\n40.0\n", content ) def test_workflow_request( self ): workflow = self.workflow_populator.load_workflow( name="test_for_queue" ) @@ -740,11 +742,14 @@ assert len( self._history_jobs( history_id ) ) == 2 self.__review_paused_steps( workflow_id, invocation_id, order_index=2, action=True ) + self.wait_for_invocation_and_jobs( history_id, workflow_id, invocation_id ) + assert len( self._history_jobs( history_id ) ) == 4 + + def wait_for_invocation_and_jobs( self, history_id, workflow_id, invocation_id, assert_ok=True ): self.wait_for_invocation( workflow_id, invocation_id ) - time.sleep(1) + time.sleep(.5) self.dataset_populator.wait_for_history( history_id, assert_ok=True ) - time.sleep(1) - assert len( self._history_jobs( history_id ) ) == 4 + time.sleep(.5) def test_cannot_run_inaccessible_workflow( self ): workflow = self.workflow_populator.load_workflow( name="test_for_run_cannot_access" ) https://bitbucket.org/galaxy/galaxy-central/commits/a9b3fe441879/ Changeset: a9b3fe441879 User: jmchilton Date: 2015-03-03 14:37:30+00:00 Summary: Fix bug in workflows test for implicit connections between steps. It would fail when being run with the rest of the suite and not on its own - because it was using the same id for the workflow id and invocation id - which is obviously wrong unless it is a completely fresh database :). Affected #: 1 file diff -r 6dfbd65fa1e839b90380bd7ea4c67282400b4502 -r a9b3fe441879b645dc98e339cbe26ca92c538c80 test/api/test_workflows.py --- a/test/api/test_workflows.py +++ b/test/api/test_workflows.py @@ -168,6 +168,7 @@ return RunJobsSummary( history_id=history_id, workflow_id=workflow_id, + invocation_id=invocation_id, inputs=inputs, jobs=jobs, ) @@ -733,7 +734,7 @@ time.sleep( 2 ) history_id = run_summary.history_id workflow_id = run_summary.workflow_id - invocation_id = run_summary.workflow_id + invocation_id = run_summary.invocation_id self.dataset_populator.wait_for_history( history_id, assert_ok=True ) invocation = self._invocation_details( workflow_id, invocation_id ) assert invocation[ 'state' ] != 'scheduled' @@ -1174,4 +1175,4 @@ 'input_steps', ) -RunJobsSummary = namedtuple('RunJobsSummary', ['history_id', 'workflow_id', 'inputs', 'jobs']) +RunJobsSummary = namedtuple('RunJobsSummary', ['history_id', 'workflow_id', 'invocation_id', 'inputs', 'jobs']) https://bitbucket.org/galaxy/galaxy-central/commits/ca5ea26759bc/ Changeset: ca5ea26759bc User: dan Date: 2015-03-03 15:49:12+00:00 Summary: When loading Dynamic Display application links, allow the application to load even if one set of links does not. Affected #: 1 file diff -r a9b3fe441879b645dc98e339cbe26ca92c538c80 -r ca5ea26759bc51b9ecde869892942b4fb23b554b lib/galaxy/datatypes/display_applications/application.py --- a/lib/galaxy/datatypes/display_applications/application.py +++ b/lib/galaxy/datatypes/display_applications/application.py @@ -245,8 +245,11 @@ if link: self.links[ link.id ] = link for dynamic_links in elem.findall( 'dynamic_links' ): - for link in DynamicDisplayApplicationBuilder( dynamic_links, self, self.app.datatypes_registry.build_sites ): - self.links[ link.id ] = link + try: + for link in DynamicDisplayApplicationBuilder( dynamic_links, self, self.app.datatypes_registry.build_sites ): + self.links[ link.id ] = link + except Exception, e: + log.error( "Error loading a set of Dynamic Display Application links: %s", e ) def get_link( self, link_name, data, dataset_hash, user_hash, trans, app_kwds ): #returns a link object with data knowledge to generate links self._check_and_reload() https://bitbucket.org/galaxy/galaxy-central/commits/483bef6ebb7a/ Changeset: 483bef6ebb7a User: dan Date: 2015-03-03 15:57:54+00:00 Summary: When loading Dynamic Display application links, allow the application to load even if one set of links does not. Affected #: 1 file diff -r ca5ea26759bc51b9ecde869892942b4fb23b554b -r 483bef6ebb7a9491e9edee728458f8bd81cff44a lib/galaxy/datatypes/display_applications/application.py --- a/lib/galaxy/datatypes/display_applications/application.py +++ b/lib/galaxy/datatypes/display_applications/application.py @@ -244,12 +244,12 @@ link = DisplayApplicationLink.from_elem( link_elem, self ) if link: self.links[ link.id ] = link - for dynamic_links in elem.findall( 'dynamic_links' ): - try: + try: + for dynamic_links in elem.findall( 'dynamic_links' ): for link in DynamicDisplayApplicationBuilder( dynamic_links, self, self.app.datatypes_registry.build_sites ): self.links[ link.id ] = link - except Exception, e: - log.error( "Error loading a set of Dynamic Display Application links: %s", e ) + except Exception, e: + log.error( "Error loading a set of Dynamic Display Application links: %s", e ) def get_link( self, link_name, data, dataset_hash, user_hash, trans, app_kwds ): #returns a link object with data knowledge to generate links self._check_and_reload() https://bitbucket.org/galaxy/galaxy-central/commits/b9984583dbb7/ Changeset: b9984583dbb7 User: carlfeberhard Date: 2015-03-03 18:13:26+00:00 Summary: Fix to safari that still uses prefixed flexbox attributes Affected #: 2 files diff -r 483bef6ebb7a9491e9edee728458f8bd81cff44a -r b9984583dbb73206131157f4cf21ebdb5bc8b451 static/style/blue/base.css --- a/static/style/blue/base.css +++ b/static/style/blue/base.css @@ -2119,7 +2119,7 @@ .annotated-history-panel table.list-items>tbody>tr>td>.list-item{border:0px} .annotated-history-panel .empty-message{margin-top:8px} .current-history-panel .list-item.history-content.current-content{border-left:5px solid #4E5777} -.multi-panel-history{display:flex;flex-direction:column;}.multi-panel-history .flex-row-container,.multi-panel-history .flex-column-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:0px;min-height:0px;-webkit-align-items:stretch;-ms-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;-ms-align-content:stretch;align-content:stretch;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start} +.multi-panel-history{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}.multi-panel-history .flex-row-container,.multi-panel-history .flex-column-container{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;min-width:0px;min-height:0px;-webkit-align-items:stretch;-ms-align-items:stretch;align-items:stretch;-webkit-align-content:stretch;-ms-align-content:stretch;align-content:stretch;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start} .multi-panel-history .flex-row-container{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column} .multi-panel-history .flex-column-container{-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row} .multi-panel-history .flex-row,.multi-panel-history .flex-column{-webkit-flex:1 1 auto;-ms-flex:1 1 auto;flex:1 1 auto;-webkit-align-self:auto;-ms-flex-item-align:auto;align-self:auto} @@ -2142,7 +2142,7 @@ .multi-panel-history .history-column:nth-child(2){margin-left:320px} .multi-panel-history .history-column:last-child{margin-right:0px} .multi-panel-history .history-column .dropdown-menu{z-index:inherit} -.multi-panel-history .history-column .panel-controls{width:100%;height:24px;border-radius:3px;background-color:white;text-align:center;flex:0 0 auto;-webkit-align-self:auto;-ms-flex-item-align:auto;align-self:auto}.multi-panel-history .history-column .panel-controls .btn{height:20px;line-height:normal;font-size:90%;padding-top:0px;padding-bottom:0px} +.multi-panel-history .history-column .panel-controls{width:100%;height:24px;border-radius:3px;background-color:white;text-align:center;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;-webkit-align-self:auto;-ms-flex-item-align:auto;align-self:auto}.multi-panel-history .history-column .panel-controls .btn{height:20px;line-height:normal;font-size:90%;padding-top:0px;padding-bottom:0px} .multi-panel-history .history-column .panel-controls .pull-left .btn{margin-right:4px} .multi-panel-history .history-column .panel-controls .pull-right .btn{margin-left:4px} .multi-panel-history .history-column .panel-controls .panel-menu{z-index:1}.multi-panel-history .history-column .panel-controls .panel-menu .dropdown-menu a{text-align:left} diff -r 483bef6ebb7a9491e9edee728458f8bd81cff44a -r b9984583dbb73206131157f4cf21ebdb5bc8b451 static/style/src/less/history.less --- a/static/style/src/less/history.less +++ b/static/style/src/less/history.less @@ -584,7 +584,13 @@ // for some reason, .flex-row-container below won't be applied to multi-panel-history since it's the enclosing node // re-apply here + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; display: flex; + + -webkit-flex-direction: column; + -ms-flex-direction: column; flex-direction: column; .flex-row-container, @@ -770,6 +776,8 @@ background-color: white; text-align: center; + -webkit-flex: 0 0 auto; + -ms-flex: 0 0 auto; flex: 0 0 auto; -webkit-align-self: auto; https://bitbucket.org/galaxy/galaxy-central/commits/a48224abb013/ Changeset: a48224abb013 User: martenson Date: 2015-03-03 18:17:29+00:00 Summary: compile AND pack handlebar templates Affected #: 8 files diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 client/galaxy/scripts/templates/compiled/panel_section.js --- a/client/galaxy/scripts/templates/compiled/panel_section.js +++ b/client/galaxy/scripts/templates/compiled/panel_section.js @@ -1,13 +1,14 @@ (function() { var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; templates['panel_section'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; + var helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression; + return "<div class=\"toolSectionTitle\" id=\"title_" - + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"id","hash":{},"data":data}) : helper))) + "\">\n <a href=\"javascript:void(0)\"><span>" - + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper))) + "</span></a>\n</div>\n<div id=\"" - + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"id","hash":{},"data":data}) : helper))) + "\" class=\"toolSectionBody\" style=\"display: none; \">\n <div class=\"toolSectionBg\"></div>\n<div>"; },"useData":true}); })(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 client/galaxy/scripts/templates/compiled/tool_form.js --- a/client/galaxy/scripts/templates/compiled/tool_form.js +++ b/client/galaxy/scripts/templates/compiled/tool_form.js @@ -1,26 +1,28 @@ (function() { var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; templates['tool_form'] = template({"1":function(depth0,helpers,partials,data) { - var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = " <div class=\"form-row\">\n <label for=\"" - + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper))) + var stack1, helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression; + + return " <div class=\"form-row\">\n <label for=\"" + + alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper))) + "\">" - + escapeExpression(((helper = (helper = helpers.label || (depth0 != null ? depth0.label : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"label","hash":{},"data":data}) : helper))) - + ":</label>\n <div class=\"form-row-input\">\n "; - stack1 = ((helper = (helper = helpers.html || (depth0 != null ? depth0.html : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"html","hash":{},"data":data}) : helper)); - if (stack1 != null) { buffer += stack1; } - return buffer + "\n </div>\n <div class=\"toolParamHelp\" style=\"clear: both;\">\n " - + escapeExpression(((helper = (helper = helpers.help || (depth0 != null ? depth0.help : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"help","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.label || (depth0 != null ? depth0.label : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"label","hash":{},"data":data}) : helper))) + + ":</label>\n <div class=\"form-row-input\">\n " + + ((stack1 = ((helper = (helper = helpers.html || (depth0 != null ? depth0.html : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"html","hash":{},"data":data}) : helper))) != null ? stack1 : "") + + "\n </div>\n <div class=\"toolParamHelp\" style=\"clear: both;\">\n " + + alias3(((helper = (helper = helpers.help || (depth0 != null ? depth0.help : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"help","hash":{},"data":data}) : helper))) + "\n </div>\n <div style=\"clear: both;\"></div>\n </div>\n"; },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"toolFormTitle\">" - + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper))) + var stack1, helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression; + + return "<div class=\"toolFormTitle\">" + + alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper))) + " (version " - + escapeExpression(((helper = (helper = helpers.version || (depth0 != null ? depth0.version : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"version","hash":{},"data":data}) : helper))) - + ")</div>\n <div class=\"toolFormBody\">\n"; - stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.inputs : depth0), {"name":"each","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data}); - if (stack1 != null) { buffer += stack1; } - return buffer + " </div>\n <div class=\"form-row form-actions\">\n <input type=\"submit\" class=\"btn btn-primary\" name=\"runtool_btn\" value=\"Execute\">\n</div>\n<div class=\"toolHelp\">\n <div class=\"toolHelpBody\">" - + escapeExpression(((helper = (helper = helpers.help || (depth0 != null ? depth0.help : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"help","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.version || (depth0 != null ? depth0.version : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"version","hash":{},"data":data}) : helper))) + + ")</div>\n <div class=\"toolFormBody\">\n" + + ((stack1 = helpers.each.call(depth0,(depth0 != null ? depth0.inputs : depth0),{"name":"each","hash":{},"fn":this.program(1, data, 0),"inverse":this.noop,"data":data})) != null ? stack1 : "") + + " </div>\n <div class=\"form-row form-actions\">\n <input type=\"submit\" class=\"btn btn-primary\" name=\"runtool_btn\" value=\"Execute\">\n</div>\n<div class=\"toolHelp\">\n <div class=\"toolHelpBody\">" + + alias3(((helper = (helper = helpers.help || (depth0 != null ? depth0.help : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"help","hash":{},"data":data}) : helper))) + "</div>\n</div>"; },"useData":true}); })(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 client/galaxy/scripts/templates/compiled/tool_link.js --- a/client/galaxy/scripts/templates/compiled/tool_link.js +++ b/client/galaxy/scripts/templates/compiled/tool_link.js @@ -1,18 +1,19 @@ (function() { var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; templates['tool_link'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; + var helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression; + return "<a class=\"" - + escapeExpression(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"id","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.id || (depth0 != null ? depth0.id : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"id","hash":{},"data":data}) : helper))) + " tool-link\" href=\"" - + escapeExpression(((helper = (helper = helpers.link || (depth0 != null ? depth0.link : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"link","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.link || (depth0 != null ? depth0.link : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"link","hash":{},"data":data}) : helper))) + "\" target=\"" - + escapeExpression(((helper = (helper = helpers.target || (depth0 != null ? depth0.target : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"target","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.target || (depth0 != null ? depth0.target : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"target","hash":{},"data":data}) : helper))) + "\" minsizehint=\"" - + escapeExpression(((helper = (helper = helpers.min_width || (depth0 != null ? depth0.min_width : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"min_width","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.min_width || (depth0 != null ? depth0.min_width : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"min_width","hash":{},"data":data}) : helper))) + "\">" - + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper))) + + alias3(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"name","hash":{},"data":data}) : helper))) + "</a> " - + escapeExpression(((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"description","hash":{},"data":data}) : helper))); + + alias3(((helper = (helper = helpers.description || (depth0 != null ? depth0.description : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"description","hash":{},"data":data}) : helper))); },"useData":true}); })(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 client/galaxy/scripts/templates/compiled/tool_search.js --- a/client/galaxy/scripts/templates/compiled/tool_search.js +++ b/client/galaxy/scripts/templates/compiled/tool_search.js @@ -1,11 +1,12 @@ (function() { var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {}; templates['tool_search'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { - var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; - return "<input type=\"text\" name=\"query\" value=\"" - + escapeExpression(((helper = (helper = helpers.search_hint_string || (depth0 != null ? depth0.search_hint_string : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"search_hint_string","hash":{},"data":data}) : helper))) + var helper, alias1=helpers.helperMissing, alias2="function", alias3=this.escapeExpression; + + return "<input type=\"text\" name=\"query\" placeholder=\"" + + alias3(((helper = (helper = helpers.search_hint_string || (depth0 != null ? depth0.search_hint_string : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"search_hint_string","hash":{},"data":data}) : helper))) + "\" id=\"tool-search-query\" autocomplete=\"off\" class=\"search-query parent-width\" />\n<a id=\"search-clear-btn\" title=\"clear search (esc)\"></a>\n<img src=\"" - + escapeExpression(((helper = (helper = helpers.spinner_url || (depth0 != null ? depth0.spinner_url : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"spinner_url","hash":{},"data":data}) : helper))) - + "\" id=\"search-spinner\" class=\"search-spinner\"/>"; + + alias3(((helper = (helper = helpers.spinner_url || (depth0 != null ? depth0.spinner_url : depth0)) != null ? helper : alias1),(typeof helper === alias2 ? helper.call(depth0,{"name":"spinner_url","hash":{},"data":data}) : helper))) + + "\" id=\"search-spinner\" class=\"search-spinner\"/>\n"; },"useData":true}); })(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 static/scripts/packed/templates/compiled/panel_section.js --- a/static/scripts/packed/templates/compiled/panel_section.js +++ b/static/scripts/packed/templates/compiled/panel_section.js @@ -1,1 +1,1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_section=b({compiler:[6,">= 2.0.0-beta.1"],main:function(j,f,c,g){var e,i="function",d=f.helperMissing,h=this.escapeExpression;return'<div class="toolSectionTitle" id="title_'+h(((e=(e=f.id||(j!=null?j.id:j))!=null?e:d),(typeof e===i?e.call(j,{name:"id",hash:{},data:g}):e)))+'">\n <a href="javascript:void(0)"><span>'+h(((e=(e=f.name||(j!=null?j.name:j))!=null?e:d),(typeof e===i?e.call(j,{name:"name",hash:{},data:g}):e)))+'</span></a>\n</div>\n<div id="'+h(((e=(e=f.id||(j!=null?j.id:j))!=null?e:d),(typeof e===i?e.call(j,{name:"id",hash:{},data:g}):e)))+'" class="toolSectionBody" style="display: none; ">\n <div class="toolSectionBg"></div>\n<div>'},useData:true})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.panel_section=b({compiler:[6,">= 2.0.0-beta.1"],main:function(j,f,c,h){var e,i=f.helperMissing,g="function",d=this.escapeExpression;return'<div class="toolSectionTitle" id="title_'+d(((e=(e=f.id||(j!=null?j.id:j))!=null?e:i),(typeof e===g?e.call(j,{name:"id",hash:{},data:h}):e)))+'">\n <a href="javascript:void(0)"><span>'+d(((e=(e=f.name||(j!=null?j.name:j))!=null?e:i),(typeof e===g?e.call(j,{name:"name",hash:{},data:h}):e)))+'</span></a>\n</div>\n<div id="'+d(((e=(e=f.id||(j!=null?j.id:j))!=null?e:i),(typeof e===g?e.call(j,{name:"id",hash:{},data:h}):e)))+'" class="toolSectionBody" style="display: none; ">\n <div class="toolSectionBg"></div>\n<div>'},useData:true})})(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 static/scripts/packed/templates/compiled/tool_form.js --- a/static/scripts/packed/templates/compiled/tool_form.js +++ b/static/scripts/packed/templates/compiled/tool_form.js @@ -1,1 +1,1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b({"1":function(l,d,j,i){var c,e,f="function",k=d.helperMissing,h=this.escapeExpression,g=' <div class="form-row">\n <label for="'+h(((e=(e=d.name||(l!=null?l.name:l))!=null?e:k),(typeof e===f?e.call(l,{name:"name",hash:{},data:i}):e)))+'">'+h(((e=(e=d.label||(l!=null?l.label:l))!=null?e:k),(typeof e===f?e.call(l,{name:"label",hash:{},data:i}):e)))+':</label>\n <div class="form-row-input">\n ';c=((e=(e=d.html||(l!=null?l.html:l))!=null?e:k),(typeof e===f?e.call(l,{name:"html",hash:{},data:i}):e));if(c!=null){g+=c}return g+'\n </div>\n <div class="toolParamHelp" style="clear: both;">\n '+h(((e=(e=d.help||(l!=null?l.help:l))!=null?e:k),(typeof e===f?e.call(l,{name:"help",hash:{},data:i}):e)))+'\n </div>\n <div style="clear: both;"></div>\n </div>\n'},compiler:[6,">= 2.0.0-beta.1"],main:function(l,d,j,i){var c,e,f="function",k=d.helperMissing,h=this.escapeExpression,g='<div class="toolFormTitle">'+h(((e=(e=d.name||(l!=null?l.name:l))!=null?e:k),(typeof e===f?e.call(l,{name:"name",hash:{},data:i}):e)))+" (version "+h(((e=(e=d.version||(l!=null?l.version:l))!=null?e:k),(typeof e===f?e.call(l,{name:"version",hash:{},data:i}):e)))+')</div>\n <div class="toolFormBody">\n';c=d.each.call(l,(l!=null?l.inputs:l),{name:"each",hash:{},fn:this.program(1,i),inverse:this.noop,data:i});if(c!=null){g+=c}return g+' </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">'+h(((e=(e=d.help||(l!=null?l.help:l))!=null?e:k),(typeof e===f?e.call(l,{name:"help",hash:{},data:i}):e)))+"</div>\n</div>"},useData:true})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_form=b({"1":function(h,d,g,f){var c,e,k=d.helperMissing,j="function",i=this.escapeExpression;return' <div class="form-row">\n <label for="'+i(((e=(e=d.name||(h!=null?h.name:h))!=null?e:k),(typeof e===j?e.call(h,{name:"name",hash:{},data:f}):e)))+'">'+i(((e=(e=d.label||(h!=null?h.label:h))!=null?e:k),(typeof e===j?e.call(h,{name:"label",hash:{},data:f}):e)))+':</label>\n <div class="form-row-input">\n '+((c=((e=(e=d.html||(h!=null?h.html:h))!=null?e:k),(typeof e===j?e.call(h,{name:"html",hash:{},data:f}):e)))!=null?c:"")+'\n </div>\n <div class="toolParamHelp" style="clear: both;">\n '+i(((e=(e=d.help||(h!=null?h.help:h))!=null?e:k),(typeof e===j?e.call(h,{name:"help",hash:{},data:f}):e)))+'\n </div>\n <div style="clear: both;"></div>\n </div>\n'},compiler:[6,">= 2.0.0-beta.1"],main:function(h,d,g,f){var c,e,k=d.helperMissing,j="function",i=this.escapeExpression;return'<div class="toolFormTitle">'+i(((e=(e=d.name||(h!=null?h.name:h))!=null?e:k),(typeof e===j?e.call(h,{name:"name",hash:{},data:f}):e)))+" (version "+i(((e=(e=d.version||(h!=null?h.version:h))!=null?e:k),(typeof e===j?e.call(h,{name:"version",hash:{},data:f}):e)))+')</div>\n <div class="toolFormBody">\n'+((c=d.each.call(h,(h!=null?h.inputs:h),{name:"each",hash:{},fn:this.program(1,f,0),inverse:this.noop,data:f}))!=null?c:"")+' </div>\n <div class="form-row form-actions">\n <input type="submit" class="btn btn-primary" name="runtool_btn" value="Execute">\n</div>\n<div class="toolHelp">\n <div class="toolHelpBody">'+i(((e=(e=d.help||(h!=null?h.help:h))!=null?e:k),(typeof e===j?e.call(h,{name:"help",hash:{},data:f}):e)))+"</div>\n</div>"},useData:true})})(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 static/scripts/packed/templates/compiled/tool_link.js --- a/static/scripts/packed/templates/compiled/tool_link.js +++ b/static/scripts/packed/templates/compiled/tool_link.js @@ -1,1 +1,1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_link=b({compiler:[6,">= 2.0.0-beta.1"],main:function(j,f,c,g){var e,i="function",d=f.helperMissing,h=this.escapeExpression;return'<a class="'+h(((e=(e=f.id||(j!=null?j.id:j))!=null?e:d),(typeof e===i?e.call(j,{name:"id",hash:{},data:g}):e)))+' tool-link" href="'+h(((e=(e=f.link||(j!=null?j.link:j))!=null?e:d),(typeof e===i?e.call(j,{name:"link",hash:{},data:g}):e)))+'" target="'+h(((e=(e=f.target||(j!=null?j.target:j))!=null?e:d),(typeof e===i?e.call(j,{name:"target",hash:{},data:g}):e)))+'" minsizehint="'+h(((e=(e=f.min_width||(j!=null?j.min_width:j))!=null?e:d),(typeof e===i?e.call(j,{name:"min_width",hash:{},data:g}):e)))+'">'+h(((e=(e=f.name||(j!=null?j.name:j))!=null?e:d),(typeof e===i?e.call(j,{name:"name",hash:{},data:g}):e)))+"</a> "+h(((e=(e=f.description||(j!=null?j.description:j))!=null?e:d),(typeof e===i?e.call(j,{name:"description",hash:{},data:g}):e)))},useData:true})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_link=b({compiler:[6,">= 2.0.0-beta.1"],main:function(j,f,c,h){var e,i=f.helperMissing,g="function",d=this.escapeExpression;return'<a class="'+d(((e=(e=f.id||(j!=null?j.id:j))!=null?e:i),(typeof e===g?e.call(j,{name:"id",hash:{},data:h}):e)))+' tool-link" href="'+d(((e=(e=f.link||(j!=null?j.link:j))!=null?e:i),(typeof e===g?e.call(j,{name:"link",hash:{},data:h}):e)))+'" target="'+d(((e=(e=f.target||(j!=null?j.target:j))!=null?e:i),(typeof e===g?e.call(j,{name:"target",hash:{},data:h}):e)))+'" minsizehint="'+d(((e=(e=f.min_width||(j!=null?j.min_width:j))!=null?e:i),(typeof e===g?e.call(j,{name:"min_width",hash:{},data:h}):e)))+'">'+d(((e=(e=f.name||(j!=null?j.name:j))!=null?e:i),(typeof e===g?e.call(j,{name:"name",hash:{},data:h}):e)))+"</a> "+d(((e=(e=f.description||(j!=null?j.description:j))!=null?e:i),(typeof e===g?e.call(j,{name:"description",hash:{},data:h}):e)))},useData:true})})(); \ No newline at end of file diff -r b9984583dbb73206131157f4cf21ebdb5bc8b451 -r a48224abb0132be28df463254abc5fbbb8494195 static/scripts/packed/templates/compiled/tool_search.js --- a/static/scripts/packed/templates/compiled/tool_search.js +++ b/static/scripts/packed/templates/compiled/tool_search.js @@ -1,1 +1,1 @@ -(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_search=b({compiler:[6,">= 2.0.0-beta.1"],main:function(j,f,c,g){var e,i="function",d=f.helperMissing,h=this.escapeExpression;return'<input type="text" name="query" value="'+h(((e=(e=f.search_hint_string||(j!=null?j.search_hint_string:j))!=null?e:d),(typeof e===i?e.call(j,{name:"search_hint_string",hash:{},data:g}):e)))+'" id="tool-search-query" autocomplete="off" class="search-query parent-width" />\n<a id="search-clear-btn" title="clear search (esc)"></a>\n<img src="'+h(((e=(e=f.spinner_url||(j!=null?j.spinner_url:j))!=null?e:d),(typeof e===i?e.call(j,{name:"spinner_url",hash:{},data:g}):e)))+'" id="search-spinner" class="search-spinner"/>'},useData:true})})(); \ No newline at end of file +(function(){var b=Handlebars.template,a=Handlebars.templates=Handlebars.templates||{};a.tool_search=b({compiler:[6,">= 2.0.0-beta.1"],main:function(j,f,c,h){var e,i=f.helperMissing,g="function",d=this.escapeExpression;return'<input type="text" name="query" placeholder="'+d(((e=(e=f.search_hint_string||(j!=null?j.search_hint_string:j))!=null?e:i),(typeof e===g?e.call(j,{name:"search_hint_string",hash:{},data:h}):e)))+'" id="tool-search-query" autocomplete="off" class="search-query parent-width" />\n<a id="search-clear-btn" title="clear search (esc)"></a>\n<img src="'+d(((e=(e=f.spinner_url||(j!=null?j.spinner_url:j))!=null?e:i),(typeof e===g?e.call(j,{name:"spinner_url",hash:{},data:h}):e)))+'" id="search-spinner" class="search-spinner"/>\n'},useData:true})})(); \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/d9374567fdcf/ Changeset: d9374567fdcf User: carlfeberhard Date: 2015-03-03 21:11:44+00:00 Summary: Fix user registration to respect use_panels when in the Galaxy app Affected #: 1 file diff -r a48224abb0132be28df463254abc5fbbb8494195 -r d9374567fdcf62b9623431eb4dba03b890a919f9 templates/user/register.mako --- a/templates/user/register.mako +++ b/templates/user/register.mako @@ -1,32 +1,59 @@ -<%inherit file="/base.mako"/> +<%! +#This is a hack, we should restructure templates to avoid this. +def inherit(context): + print 'context:', context + if context.get('trans').webapp.name == 'galaxy' and context.get( 'use_panels', True ): + return '/webapps/galaxy/base_panels.mako' + else: + return '/base.mako' +%> +<%inherit file="${inherit(context)}"/> + +<%def name="init()"> +<% + self.has_left_panel=False + self.has_right_panel=False + self.active_view="user" + self.message_box_visible=False +%> +</%def> + <%namespace file="/message.mako" import="render_msg" /> -%if redirect_url: - <script type="text/javascript"> - top.location.href = '${redirect_url | h}'; - </script> -%endif +<%def name="center_panel()"> + ${body()} +</%def><%def name="javascripts()"> ${parent.javascripts()} </%def> -%if not redirect_url and message: - ${render_msg( message, status )} -%endif +<%def name="body()"> + <div style="${ 'margin: 1em;' if context.get( 'use_panels', True ) else '' }"> -## An admin user may be creating a new user account, in which case we want to display the registration form. -## But if the current user is not an admin user, then don't display the registration form. -%if ( cntrller=='admin' and trans.user_is_admin() ) or not trans.user: - ${render_registration_form()} + %if redirect_url: + <script type="text/javascript"> + top.location.href = '${redirect_url | h}'; + </script> + %elif message: + ${render_msg( message, status )} + %endif - %if trans.app.config.get( 'terms_url', None ) is not None: - <br/> - <p> - <a href="${trans.app.config.get('terms_url', None)}">Terms and Conditions for use of this service</a> - </p> - %endif -%endif + ## An admin user may be creating a new user account, in which case we want to display the registration form. + ## But if the current user is not an admin user, then don't display the registration form. + %if ( cntrller=='admin' and trans.user_is_admin() ) or not trans.user: + ${render_registration_form()} + + %if trans.app.config.get( 'terms_url', None ) is not None: + <br/> + <p> + <a href="${trans.app.config.get('terms_url', None)}">Terms and Conditions for use of this service</a> + </p> + %endif + %endif + + </div> +</%def><%def name="render_registration_form( form_action=None )"> @@ -37,64 +64,60 @@ subscribe_check_box = CheckboxField( 'subscribe' ) %> -<script type="text/javascript"> - $(document).ready(function() { + <script type="text/javascript"> + $(document).ready(function() { - function validateString(test_string, type) { - var mail_re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - //var mail_re_RFC822 = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/; - var username_re = /^[a-z0-9\-]{3,255}$/; - if (type === 'email') { - return mail_re.test(test_string); - } else if (type === 'username'){ - return username_re.test(test_string); - } - } + function validateString(test_string, type) { + var mail_re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + //var mail_re_RFC822 = /^([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x22([^\x0d\x22\x5c\x80-\xff]|\x5c[\x00-\x7f])*\x22))*\x40([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d)(\x2e([^\x00-\x20\x22\x28\x29\x2c\x2e\x3a-\x3c\x3e\x40\x5b-\x5d\x7f-\xff]+|\x5b([^\x0d\x5b-\x5d\x80-\xff]|\x5c[\x00-\x7f])*\x5d))*$/; + var username_re = /^[a-z0-9\-]{3,255}$/; + if (type === 'email') { + return mail_re.test(test_string); + } else if (type === 'username'){ + return username_re.test(test_string); + } + } - function renderError(message) { - if ($(".errormessage").length === 1) { - $(".errormessage").html(message) - } else { - var div = document.createElement("div"); - div.className = "errormessage"; - div.innerHTML = message; - document.body.insertBefore(div, document.body.firstChild); - } - } + function renderError(message) { + if (!$(".errormessage").size()) { + $('<div/>').addClass('errormessage').insertBefore('#registrationForm'); + } + $(".errormessage").html(message); + } - $('#registration').bind('submit', function(e) { - $('#send').attr('disabled', 'disabled'); - - // we need this value to detect submitting at backend - var hidden_input = '<input type="hidden" id="create_user_button" name="create_user_button" value="Submit"/>'; - $("#email_input").before(hidden_input); + $('#registration').bind('submit', function(e) { + $('#send').attr('disabled', 'disabled'); + + // we need this value to detect submitting at backend + var hidden_input = '<input type="hidden" id="create_user_button" name="create_user_button" value="Submit"/>'; + $("#email_input").before(hidden_input); - var error_text_email= 'Please enter your valid email address'; - var error_text_email_long= 'Email cannot be more than 255 characters in length'; - var error_text_username_characters = 'Public name must contain only lowercase letters, numbers and "-". It also has to be shorter than 255 characters but longer than 3.'; - var error_text_password_short = 'Please use a password of at least 6 characters'; - var error_text_password_match = "Passwords don't match"; + var error_text_email= 'Please enter your valid email address'; + var error_text_email_long= 'Email cannot be more than 255 characters in length'; + var error_text_username_characters = 'Public name must contain only lowercase letters, numbers and "-". It also has to be shorter than 255 characters but longer than 3.'; + var error_text_password_short = 'Please use a password of at least 6 characters'; + var error_text_password_match = "Passwords don't match"; - var validForm = true; - - var email = $('#email_input').val(); - var name = $('#name_input').val(); - if (email.length > 255){ renderError(error_text_email_long); validForm = false;} - else if (!validateString(email,"email")){ renderError(error_text_email); validForm = false;} - else if (!($('#password_input').val() === $('#password_check_input').val())){ renderError(error_text_password_match); validForm = false;} - else if ($('#password_input').val().length < 6 ){ renderError(error_text_password_short); validForm = false;} - else if (name && !(validateString(name,"username"))){ renderError(error_text_username_characters); validForm = false;} + var validForm = true; + + var email = $('#email_input').val(); + var name = $('#name_input').val(); + if (email.length > 255){ renderError(error_text_email_long); validForm = false;} + else if (!validateString(email,"email")){ renderError(error_text_email); validForm = false;} + else if (!($('#password_input').val() === $('#password_check_input').val())){ renderError(error_text_password_match); validForm = false;} + else if ($('#password_input').val().length < 6 ){ renderError(error_text_password_short); validForm = false;} + else if (name && !(validateString(name,"username"))){ renderError(error_text_username_characters); validForm = false;} - if (!validForm) { - e.preventDefault(); - // reactivate the button if the form wasn't submitted - $('#send').removeAttr('disabled'); - } - }); - }); + if (!validForm) { + e.preventDefault(); + // reactivate the button if the form wasn't submitted + $('#send').removeAttr('disabled'); + } + }); + }); + </script> -</script> - <div class="toolForm"> + <div id="registration-form" class="toolForm"><form name="registration" id="registration" action="${form_action}" method="post" ><div class="toolFormTitle">Create account</div><div class="form-row"> https://bitbucket.org/galaxy/galaxy-central/commits/22271daeb2c9/ Changeset: 22271daeb2c9 User: carlfeberhard Date: 2015-03-03 21:35:00+00:00 Summary: Fix to 7ac8631 to use proper registrationForm id Affected #: 1 file diff -r d9374567fdcf62b9623431eb4dba03b890a919f9 -r 22271daeb2c94282e3dce586b3679f43a059c097 templates/user/register.mako --- a/templates/user/register.mako +++ b/templates/user/register.mako @@ -82,6 +82,8 @@ if (!$(".errormessage").size()) { $('<div/>').addClass('errormessage').insertBefore('#registrationForm'); } + console.debug( $( '#registrationForm' ) ); + console.debug( '.errormessage:', $( '.errormessage' ) ); $(".errormessage").html(message); } @@ -117,7 +119,7 @@ }); </script> - <div id="registration-form" class="toolForm"> + <div id="registrationForm" class="toolForm"><form name="registration" id="registration" action="${form_action}" method="post" ><div class="toolFormTitle">Create account</div><div class="form-row"> https://bitbucket.org/galaxy/galaxy-central/commits/edd3dc73f442/ Changeset: edd3dc73f442 User: carlfeberhard Date: 2015-03-03 22:08:10+00:00 Summary: Browser tests: Fix user module registration to search for the proper message class Affected #: 1 file diff -r 22271daeb2c94282e3dce586b3679f43a059c097 -r edd3dc73f4421a04231b171b1b3f2f674153aab3 test/casperjs/modules/user.js --- a/test/casperjs/modules/user.js +++ b/test/casperjs/modules/user.js @@ -50,8 +50,8 @@ this.waitForNavigation( 'user/create', function beforeRegister(){ this.withMainPanel( function mainBeforeRegister(){ - spaceghost.debug( '(' + spaceghost.getCurrentUrl() + ') registering user:\n' - + spaceghost.jsonStr( userInfo ) ); + spaceghost.debug( '(' + spaceghost.getCurrentUrl() + ') registering user:\n' + + spaceghost.jsonStr( userInfo ) ); this.fill( spaceghost.data.selectors.registrationPage.form, userInfo, false ); // need manual submit (not a normal html form) this.click( xpath( spaceghost.data.selectors.registrationPage.submit_xpath ) ); @@ -88,8 +88,8 @@ this.waitForNavigation( 'user/login', function beforeLogin(){ this.withMainPanel( function mainBeforeLogin(){ - spaceghost.debug( '(' + spaceghost.getCurrentUrl() + ') logging in user:\n' - + spaceghost.jsonStr( loginInfo ) ); + spaceghost.debug( '(' + spaceghost.getCurrentUrl() + ') logging in user:\n' + + spaceghost.jsonStr( loginInfo ) ); spaceghost.fill( spaceghost.data.selectors.loginPage.form, loginInfo, false ); spaceghost.click( xpath( spaceghost.data.selectors.loginPage.submit_xpath ) ); }); @@ -117,14 +117,15 @@ var spaceghost = this.spaceghost; this._submitRegistration( email, password, username ); spaceghost.withMainPanel( function mainAfterRegister(){ - var messageInfo = this.getElementInfo( spaceghost.data.selectors.messages.all ); - this.debug( 'post registration message:\n' + this.jsonStr( this.quickInfo( messageInfo ) ) ); - - if( messageInfo.attributes[ 'class' ] === 'errormessage' ){ - this.warning( 'Registration failed: ' + messageInfo.text ); - throw new spaceghost.GalaxyError( 'RegistrationError: ' + messageInfo.text ); + var errorMessage = this.elementInfoOrNull( spaceghost.data.selectors.messages.error ); + if( errorMessage ){ + this.warning( 'Registration failed: ' + errorMessage.text ); + throw new spaceghost.GalaxyError( 'RegistrationError: ' + errorMessage.text ); } + var messageInfo = this.elementInfoOrNull( spaceghost.data.selectors.messages.done ); + this.debug( 'post registration message:\n' + messageInfo.text ); + this.clickLabel( 'Return to the home page.' ); this.waitForNavigation( '' ); }); https://bitbucket.org/galaxy/galaxy-central/commits/352a9081be23/ Changeset: 352a9081be23 User: dannon Date: 2015-03-04 00:24:45+00:00 Summary: Fix undefined vars in toolshed add_repository_entry API script Affected #: 1 file diff -r edd3dc73f4421a04231b171b1b3f2f674153aab3 -r 352a9081be230e9fe8707ef14f8fb33b7347aae2 lib/tool_shed/scripts/api/add_repository_registry_entry.py --- a/lib/tool_shed/scripts/api/add_repository_registry_entry.py +++ b/lib/tool_shed/scripts/api/add_repository_registry_entry.py @@ -9,10 +9,10 @@ import os import sys import argparse -import urllib2 sys.path.insert( 0, os.path.dirname( __file__ ) ) from common import submit + def main( options ): api_key = options.api_key if api_key: @@ -26,7 +26,7 @@ response_dict = submit( url, data, api_key=api_key, return_formatted=False ) print response_dict else: - print "Invalid tool_shed: ", base_tool_shed_url, " name: ", name, " or owner: ", owner, "." + print "Invalid tool_shed: ", base_tool_shed_url, " name: ", options.name, " or owner: ", options.owner, "." else: print "An API key for an admin user in the Tool Shed is required to add entries into the Tool Shed's repository registry." https://bitbucket.org/galaxy/galaxy-central/commits/88191c3a722d/ Changeset: 88191c3a722d User: dannon Date: 2015-03-04 00:30:50+00:00 Summary: Fix file closing in lped_to_pbed_converter Affected #: 1 file diff -r 352a9081be230e9fe8707ef14f8fb33b7347aae2 -r 88191c3a722d78a71a42284989aa9bfc2f28f0f6 lib/galaxy/datatypes/converters/lped_to_pbed_converter.py --- a/lib/galaxy/datatypes/converters/lped_to_pbed_converter.py +++ b/lib/galaxy/datatypes/converters/lped_to_pbed_converter.py @@ -52,7 +52,7 @@ return missval if not missval: missval = 'N' # punt - close(f) + f.close() return missval def rgConv(inpedfilepath,outhtmlname,outfilepath,plink): https://bitbucket.org/galaxy/galaxy-central/commits/9b95a7797474/ Changeset: 9b95a7797474 User: dannon Date: 2015-03-04 00:33:27+00:00 Summary: Add missing 'web' to configuration manager Affected #: 1 file diff -r 88191c3a722d78a71a42284989aa9bfc2f28f0f6 -r 9b95a7797474433f82baa5be83f9072fb05f4ec3 lib/galaxy/managers/configuration.py --- a/lib/galaxy/managers/configuration.py +++ b/lib/galaxy/managers/configuration.py @@ -8,6 +8,7 @@ # but doesn't have a model like them. It might be better in config.py or a # totally new area, but I'm leaving it in managers for now for class consistency. +from galaxy import web from galaxy.managers import base import logging https://bitbucket.org/galaxy/galaxy-central/commits/ffbb03689c0e/ Changeset: ffbb03689c0e User: dannon Date: 2015-03-04 00:37:43+00:00 Summary: Fix twobit dataset dataprovider to return the correct sequence values, and a fix to the (currently unused) bcftools dataprovider initialization. Affected #: 1 file diff -r 9b95a7797474433f82baa5be83f9072fb05f4ec3 -r ffbb03689c0e7213da86efee60e0f5d291c14a62 lib/galaxy/datatypes/dataproviders/dataset.py --- a/lib/galaxy/datatypes/dataproviders/dataset.py +++ b/lib/galaxy/datatypes/dataproviders/dataset.py @@ -465,8 +465,8 @@ def __iter__( self ): for id_ in self.ids: yield { - 'id' : id_, - 'seq' : self.source[ name ] + 'id': id_, + 'seq': self.source[ id_ ] } @@ -690,7 +690,7 @@ def __init__( self, dataset, **kwargs ): #TODO: as samtools raise NotImplementedError() - super( BCFDataProvider, self ).__init__( dataset, **kwargs ) + super( BcftoolsDataProvider, self ).__init__( dataset, **kwargs ) class BGzipTabixDataProvider( base.DataProvider ): https://bitbucket.org/galaxy/galaxy-central/commits/8929985f9436/ Changeset: 8929985f9436 User: dannon Date: 2015-03-04 00:44:51+00:00 Summary: Remove unused old_change_datatype method that was referenceing another method that also doesn't exist anymore Affected #: 1 file diff -r ffbb03689c0e7213da86efee60e0f5d291c14a62 -r 8929985f943688b12ae596ae6f8e73736ca9cef6 lib/galaxy/datatypes/registry.py --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -482,14 +482,6 @@ data.init_meta( copy_from=data ) return data - def old_change_datatype( self, data, ext ): - """Creates and returns a new datatype based on an existing data and an extension""" - newdata = factory( ext )( id=data.id ) - for key, value in data.__dict__.items(): - setattr( newdata, key, value ) - newdata.ext = ext - return newdata - def load_datatype_converters( self, toolbox, installed_repository_dict=None, deactivate=False ): """ If deactivate is False, add datatype converters from self.converters or self.proprietary_converters https://bitbucket.org/galaxy/galaxy-central/commits/d175bd32877a/ Changeset: d175bd32877a User: dannon Date: 2015-03-04 05:52:40+00:00 Summary: Fix an issue in SnpSiftDbNSFP where generate_primary_dataset would blow up. Affected #: 1 file diff -r 8929985f943688b12ae596ae6f8e73736ca9cef6 -r d175bd32877a688d6c3b54e0616d26feee0c9319 lib/galaxy/datatypes/text.py --- a/lib/galaxy/datatypes/text.py +++ b/lib/galaxy/datatypes/text.py @@ -339,7 +339,7 @@ This is called only at upload to write the html file cannot rename the datasets here - they come with the default unfortunately """ - regenerate_primary_file( self, dataset) + self.regenerate_primary_file( self, dataset) def regenerate_primary_file(self,dataset): """ cannot do this until we are setting metadata https://bitbucket.org/galaxy/galaxy-central/commits/7092e71c3cbd/ Changeset: 7092e71c3cbd User: dannon Date: 2015-03-04 06:06:20+00:00 Summary: Cleanup/pep8 in galaxy forms while fixing bugs. Affected #: 1 file diff -r d175bd32877a688d6c3b54e0616d26feee0c9319 -r 7092e71c3cbd0493aad966f91ceb6e573b4bae3e lib/galaxy/forms/forms.py --- a/lib/galaxy/forms/forms.py +++ b/lib/galaxy/forms/forms.py @@ -1,18 +1,19 @@ """ FormDefinition and field factories """ -#TODO: A FormDefinitionField is closely linked to a form_builder result. -#Can this functionality be further abstracted and merged with form_builder? -import logging +# TODO: A FormDefinitionField is closely linked to a form_builder result. +# Can this functionality be further abstracted and merged with form_builder? from galaxy.util import string_as_bool from galaxy.model import FormDefinitionCurrent, FormDefinition FORM_TYPES = dict( [ ( f_type.lower(), f_descript ) for f_type, f_descript in FormDefinition.types.items() ] ) + class FormDefinitionFactory( object ): def __init__( self, form_types, field_type_factories ): self.form_types = form_types self.field_type_factories = field_type_factories + def new( self, form_type, name, description=None, fields=None, layout=None, form_definition_current=None ): """ Return new FormDefinition. @@ -25,21 +26,26 @@ layout = [] if fields is None: fields = [] - #Create new FormDefinitionCurrent + # Create new FormDefinitionCurrent if form_definition_current is None: form_definition_current = FormDefinitionCurrent() - - rval = FormDefinition( name=name, desc=description, form_type=self.form_types[form_type], form_definition_current=form_definition_current, layout=layout, fields=fields ) + rval = FormDefinition( name=name, + desc=description, + form_type=self.form_types[form_type], + form_definition_current=form_definition_current, + layout=layout, + fields=fields ) form_definition_current.latest_form = rval return rval - def from_elem( self, elem, form_definition_current = None ): + + def from_elem( self, elem, form_definition_current=None ): """ Return FormDefinition created from an xml element. """ name = elem.get( 'name', None ) description = elem.get( 'description', None ) form_type = elem.get( 'type', None ) - #load layout + # load layout layout = [] layouts_elem = elem.find( 'layout' ) if layouts_elem: @@ -47,7 +53,7 @@ layout_name = layout_elem.get( 'name', None ) assert layout_name and layout_name not in layout, 'Layout grid element requires a unique name.' layout.append( layout_name ) - #load fields + # load fields fields = [] fields_elem = elem.find( 'fields' ) if fields_elem is not None: @@ -55,13 +61,16 @@ field_type = field_elem.get( 'type' ) assert field_type in self.field_type_factories, 'Invalid form field type ( %s ).' % field_type fields.append( self.field_type_factories[field_type].from_elem( field_elem, layout ) ) - #create and return new form + # create and return new form return self.new( form_type, name, description=description, fields=fields, layout=layout, form_definition_current=form_definition_current ) + class FormDefinitionFieldFactory( object ): type = None + def __get_stored_field_type( self, **kwds ): raise 'not implemented' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): """ Return new FormDefinition field. @@ -84,10 +93,11 @@ default = '' rval['default'] = default rval['visible'] = visible - #if layout is None: #is this needed? + # if layout is None: #is this needed? # layout = '' rval['layout'] = layout return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition created from an xml element. @@ -100,24 +110,31 @@ visible = string_as_bool( elem.get( 'visible', 'true' ) ) field_layout = elem.get( 'layout', None ) if field_layout: - assert layout and field_layout in layout, 'Invalid layout specified: %s not in %s' %( field_layout, layout ) - field_layout = str( layout.index( field_layout ) ) #existing behavior: integer indexes are stored as strings. why? + assert layout and field_layout in layout, 'Invalid layout specified: %s not in %s' % ( field_layout, layout ) + field_layout = str( layout.index( field_layout ) ) # existing behavior: integer indexes are stored as strings. why? return self.new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=field_layout ) + class FormDefinitionTextFieldFactory( FormDefinitionFieldFactory ): type = 'text' + def __get_stored_field_type( self, area ): if area: return 'TextArea' else: return 'TextField' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None, area=False ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionTextFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionTextFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type( area ) return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. @@ -126,17 +143,24 @@ rval['type'] = self.__get_stored_field_type( string_as_bool( elem.get( 'area', 'false' ) ) ) return rval + class FormDefinitionPasswordFieldFactory( FormDefinitionFieldFactory ): type = 'password' + def __get_stored_field_type( self ): return 'PasswordField' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None, area=False ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionPasswordFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionPasswordFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type() return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. @@ -145,17 +169,24 @@ rval['type'] = self.__get_stored_field_type() return rval + class FormDefinitionAddressFieldFactory( FormDefinitionFieldFactory ): type = 'address' + def __get_stored_field_type( self ): return 'AddressField' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionAddressFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionAddressFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type() return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. @@ -164,17 +195,24 @@ rval['type'] = self.__get_stored_field_type() return rval + class FormDefinitionWorkflowFieldFactory( FormDefinitionFieldFactory ): type = 'workflow' + def __get_stored_field_type( self ): return 'WorkflowField' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionWorkflowFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionWorkflowFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type() return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. @@ -183,17 +221,24 @@ rval['type'] = self.__get_stored_field_type( area ) return rval + class FormDefinitionWorkflowMappingFieldFactory( FormDefinitionFieldFactory ): type = 'workflowmapping' + def __get_stored_field_type( self ): return 'WorkflowMappingField' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionWorkflowMappingFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionWorkflowMappingFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type() return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. @@ -202,17 +247,24 @@ rval['type'] = self.__get_stored_field_type( area ) return rval + class FormDefinitionHistoryFieldFactory( FormDefinitionFieldFactory ): type = 'history' + def __get_stored_field_type( self ): return 'HistoryField' + def new( self, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionHistoryFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionHistoryFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type() return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. @@ -221,30 +273,37 @@ rval['type'] = self.__get_stored_field_type( area ) return rval + class FormDefinitionSelectFieldFactory( FormDefinitionFieldFactory ): type = 'select' + def __get_stored_field_type( self, checkboxes ): if checkboxes: return 'CheckboxField' else: return 'SelectField' + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None, options=[], checkboxes=False ): """ Return new FormDefinition field. """ - rval = super( FormDefinitionSelectFieldFactory, self ).new( name=name, label=label, required=required, helptext=helptext, default=default, visible=visible, layout=layout ) + rval = super( FormDefinitionSelectFieldFactory, self ).new( name=name, label=label, + required=required, helptext=helptext, + default=default, visible=visible, + layout=layout ) rval['type'] = self.__get_stored_field_type( checkboxes ) if options is None: options = [] rval['selectlist'] = options return rval + def from_elem( self, elem, layout=None ): """ Return FormDefinition field created from an xml element. """ rval = super( FormDefinitionSelectFieldFactory, self ).from_elem( elem, layout=layout ) rval['type'] = self.__get_stored_field_type( string_as_bool( elem.get( 'checkboxes', 'false' ) ) ) - #load select options + # load select options rval['selectlist'] = [] for select_option in elem.findall( 'option' ): value = select_option.get( 'value', None ) @@ -252,6 +311,12 @@ rval['selectlist'].append( value ) return rval -field_type_factories = dict( [ ( field.type, field() ) for field in ( FormDefinitionTextFieldFactory, FormDefinitionPasswordFieldFactory, FormDefinitionAddressFieldFactory, FormDefinitionSelectFieldFactory, FormDefinitionWorkflowFieldFactory, FormDefinitionWorkflowMappingFieldFactory, FormDefinitionHistoryFieldFactory ) ] ) +field_type_factories = dict( [ ( field.type, field() ) for field in ( FormDefinitionTextFieldFactory, + FormDefinitionPasswordFieldFactory, + FormDefinitionAddressFieldFactory, + FormDefinitionSelectFieldFactory, + FormDefinitionWorkflowFieldFactory, + FormDefinitionWorkflowMappingFieldFactory, + FormDefinitionHistoryFieldFactory ) ] ) form_factory = FormDefinitionFactory( FORM_TYPES, field_type_factories ) https://bitbucket.org/galaxy/galaxy-central/commits/4033ab23b837/ Changeset: 4033ab23b837 User: dannon Date: 2015-03-04 06:13:41+00:00 Summary: Fix errors in galaxy form; usage of 'area' for fields where it doesn't apply, and a missing 'name' parameter to HistoryField new method. Affected #: 1 file diff -r 7092e71c3cbd0493aad966f91ceb6e573b4bae3e -r 4033ab23b837e17e4a6c0d1ff80a044941f444a9 lib/galaxy/forms/forms.py --- a/lib/galaxy/forms/forms.py +++ b/lib/galaxy/forms/forms.py @@ -218,7 +218,7 @@ Return FormDefinition field created from an xml element. """ rval = super( FormDefinitionWorkflowFieldFactory, self ).from_elem( elem, layout=layout ) - rval['type'] = self.__get_stored_field_type( area ) + rval['type'] = self.__get_stored_field_type() return rval @@ -244,7 +244,7 @@ Return FormDefinition field created from an xml element. """ rval = super( FormDefinitionWorkflowMappingFieldFactory, self ).from_elem( elem, layout=layout ) - rval['type'] = self.__get_stored_field_type( area ) + rval['type'] = self.__get_stored_field_type() return rval @@ -254,7 +254,7 @@ def __get_stored_field_type( self ): return 'HistoryField' - def new( self, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): + def new( self, name=None, label=None, required=False, helptext=None, default=None, visible=True, layout=None ): """ Return new FormDefinition field. """ @@ -270,7 +270,7 @@ Return FormDefinition field created from an xml element. """ rval = super( FormDefinitionHistoryFieldFactory, self ).from_elem( elem, layout=layout ) - rval['type'] = self.__get_stored_field_type( area ) + rval['type'] = self.__get_stored_field_type() return rval https://bitbucket.org/galaxy/galaxy-central/commits/4c2a19f26bf8/ Changeset: 4c2a19f26bf8 User: dannon Date: 2015-03-04 06:44:13+00:00 Summary: Use correct __safe_string_wrapper in object_wrapper Affected #: 1 file diff -r 4033ab23b837e17e4a6c0d1ff80a044941f444a9 -r 4c2a19f26bf8d3d0f79df2c00353af75a65e65b7 lib/galaxy/util/object_wrapper.py --- a/lib/galaxy/util/object_wrapper.py +++ b/lib/galaxy/util/object_wrapper.py @@ -378,19 +378,19 @@ # Do not implement in-place operands def __neg__( self ): - return __safe_string_wrapper_function__( -self.unsanitized ) + return self.__safe_string_wrapper_function__( -self.unsanitized ) def __pos__( self ): - return __safe_string_wrapper_function__( +self.unsanitized ) + return self.__safe_string_wrapper_function__( +self.unsanitized ) def __abs__( self ): - return __safe_string_wrapper_function__( abs( self.unsanitized ) ) + return self.__safe_string_wrapper_function__( abs( self.unsanitized ) ) def __invert__( self ): - return __safe_string_wrapper_function__( ~self.unsanitized ) + return self.__safe_string_wrapper_function__( ~self.unsanitized ) def __complex__( self ): - return __safe_string_wrapper_function__( complex( self.unsanitized ) ) + return self.__safe_string_wrapper_function__( complex( self.unsanitized ) ) def __int__( self ): return int( self.unsanitized ) https://bitbucket.org/galaxy/galaxy-central/commits/e93d02493496/ Changeset: e93d02493496 User: dannon Date: 2015-03-04 07:02:04+00:00 Summary: Fix errors in the toolshed's hg middleware that would have (at worst) prevented repository tag validation from doing anything, allowing in invalid content, or (at best) blowing up completely when using hg from the command line instead of uploading directly Affected #: 1 file diff -r 4c2a19f26bf8d3d0f79df2c00353af75a65e65b7 -r e93d024934963c70c01133c346169801e6439d5f lib/galaxy/webapps/tool_shed/framework/middleware/hg.py --- a/lib/galaxy/webapps/tool_shed/framework/middleware/hg.py +++ b/lib/galaxy/webapps/tool_shed/framework/middleware/hg.py @@ -12,6 +12,7 @@ from galaxy.util import asbool from galaxy.util.hash_util import new_secure_hash from tool_shed.util import hg_util +from tool_shed.util import commit_util import tool_shed.repository_types.util as rt_util from galaxy import eggs @@ -291,7 +292,7 @@ error_msg += 'the Tool Shed upload utility. ' return False, error_msg return True, '' - + def repository_tags_are_valid( self, filename, change_list ): """ Make sure the any complex repository dependency definitions contain valid <repository> tags when pushing @@ -299,9 +300,9 @@ """ tag = '<repository' for change_dict in change_list: - lines = get_change_lines_in_file_for_tag( tag, change_dict ) + lines = commit_util.get_change_lines_in_file_for_tag( tag, change_dict ) for line in lines: - is_valid, error_msg = repository_tag_is_valid( filename, line ) + is_valid, error_msg = self.repository_tag_is_valid( filename, line ) if not is_valid: return False, error_msg return True, '' https://bitbucket.org/galaxy/galaxy-central/commits/3d28518001a1/ Changeset: 3d28518001a1 User: dannon Date: 2015-03-04 07:05:47+00:00 Summary: Add missing bz2 import in toolshed.commit_util Affected #: 1 file diff -r e93d024934963c70c01133c346169801e6439d5f -r 3d28518001a10432d27375f440ffca7085880e01 lib/tool_shed/util/commit_util.py --- a/lib/tool_shed/util/commit_util.py +++ b/lib/tool_shed/util/commit_util.py @@ -4,6 +4,7 @@ import os import shutil import tempfile +import bz2 from galaxy.datatypes import checkers https://bitbucket.org/galaxy/galaxy-central/commits/c38205dfd6cc/ Changeset: c38205dfd6cc User: dannon Date: 2015-03-04 07:08:10+00:00 Summary: Correct bug in incorrect usage of log.exception, pep8 commit_util Affected #: 1 file diff -r 3d28518001a10432d27375f440ffca7085880e01 -r c38205dfd6cc6047cb4087d7cbd376d279d7029e lib/tool_shed/util/commit_util.py --- a/lib/tool_shed/util/commit_util.py +++ b/lib/tool_shed/util/commit_util.py @@ -1,26 +1,25 @@ +import bz2 import gzip import json import logging import os import shutil import tempfile -import bz2 from galaxy.datatypes import checkers +import tool_shed.repository_types.util as rt_util from tool_shed.tools import data_table_manager - from tool_shed.util import basic_util from tool_shed.util import hg_util from tool_shed.util import shed_util_common as suc -import tool_shed.repository_types.util as rt_util - log = logging.getLogger( __name__ ) UNDESIRABLE_DIRS = [ '.hg', '.svn', '.git', '.cvs' ] UNDESIRABLE_FILES = [ '.hg_archival.txt', 'hgrc', '.DS_Store', 'tool_test_output.html', 'tool_test_output.json' ] + def check_archive( repository, archive ): for member in archive.getmembers(): # Allow regular files and directories only @@ -47,6 +46,7 @@ return False, message return True, '' + def check_file_contents_for_email_alerts( app ): """ See if any admin users have chosen to receive email alerts when a repository is updated. @@ -62,6 +62,7 @@ return True return False + def check_file_content_for_html_and_images( file_path ): message = '' if checkers.check_html( file_path ): @@ -70,6 +71,7 @@ message = 'The file "%s" contains image content.\n' % str( file_path ) return message + def get_change_lines_in_file_for_tag( tag, change_dict ): """ The received change_dict is the jsonified version of the changes to a file in a @@ -88,6 +90,7 @@ cleaned_lines.append( line ) return cleaned_lines + def get_upload_point( repository, **kwd ): upload_point = kwd.get( 'upload_point', None ) if upload_point is not None: @@ -109,6 +112,7 @@ upload_point = None return upload_point + def handle_bz2( repository, uploaded_file_name ): fd, uncompressed = tempfile.mkstemp( prefix='repo_%d_upload_bunzip2_' % repository.id, dir=os.path.dirname( uploaded_file_name ), @@ -120,7 +124,7 @@ except IOError: os.close( fd ) os.remove( uncompressed ) - log.exception( 'Problem uncompressing bz2 data "%s": %s' % ( uploaded_file_name, str( e ) ) ) + log.exception( 'Problem uncompressing bz2 data "%s"' % uploaded_file_name ) return if not chunk: break @@ -129,6 +133,7 @@ bzipped_file.close() shutil.move( uncompressed, uploaded_file_name ) + def handle_directory_changes( app, host, username, repository, full_path, filenames_in_archive, remove_repo_files_not_in_tar, new_repo_alert, commit_message, undesirable_dirs_removed, undesirable_files_removed ): repo = hg_util.get_repo_for_repository( app, repository=repository, repo_path=None, create=False ) @@ -207,6 +212,7 @@ admin_only=admin_only ) return True, '', files_to_remove, content_alert_str, undesirable_dirs_removed, undesirable_files_removed + def handle_gzip( repository, uploaded_file_name ): fd, uncompressed = tempfile.mkstemp( prefix='repo_%d_upload_gunzip_' % repository.id, dir=os.path.dirname( uploaded_file_name ), @@ -227,6 +233,7 @@ gzipped_file.close() shutil.move( uncompressed, uploaded_file_name ) + def uncompress( repository, uploaded_file_name, uploaded_file_filename, isgzip=False, isbz2=False ): if isgzip: handle_gzip( repository, uploaded_file_name ) https://bitbucket.org/galaxy/galaxy-central/commits/f9a115b0eb3c/ Changeset: f9a115b0eb3c User: dannon Date: 2015-03-04 07:17:57+00:00 Summary: Fix (unlikely to occur, unless things were already broken) error in step_handler chmod action. Affected #: 1 file diff -r c38205dfd6cc6047cb4087d7cbd376d279d7029e -r f9a115b0eb3c97e4c677235431b77328be987774 lib/tool_shed/galaxy_install/tool_dependencies/recipe/step_handler.py --- a/lib/tool_shed/galaxy_install/tool_dependencies/recipe/step_handler.py +++ b/lib/tool_shed/galaxy_install/tool_dependencies/recipe/step_handler.py @@ -498,7 +498,7 @@ if os.path.exists( target_file ): os.chmod( target_file, mode ) else: - log.debug( 'Invalid file %s specified, ignoring %s action.', target_file, action_type ) + log.debug( 'Invalid file %s specified, ignoring %s action.', target_file, self.type ) return tool_dependency, None, None def prepare_step( self, tool_dependency, action_elem, action_dict, install_environment, is_binary_download ): https://bitbucket.org/galaxy/galaxy-central/commits/b7342e8fca5e/ Changeset: b7342e8fca5e User: dannon Date: 2015-03-04 13:28:33+00:00 Summary: Follow up on the second half of a fix in SnpSiftDbNSFP thanks to @nsoranzo's sharp eyes. Affected #: 1 file diff -r f9a115b0eb3c97e4c677235431b77328be987774 -r b7342e8fca5e6676fce8933747ef1ea57e99b8e9 lib/galaxy/datatypes/text.py --- a/lib/galaxy/datatypes/text.py +++ b/lib/galaxy/datatypes/text.py @@ -339,7 +339,7 @@ This is called only at upload to write the html file cannot rename the datasets here - they come with the default unfortunately """ - self.regenerate_primary_file( self, dataset) + self.regenerate_primary_file( dataset ) def regenerate_primary_file(self,dataset): """ cannot do this until we are setting metadata https://bitbucket.org/galaxy/galaxy-central/commits/a6dad23f9401/ Changeset: a6dad23f9401 User: dannon Date: 2015-03-04 14:14:20+00:00 Summary: Fix API authentication error related to new AuthManager Affected #: 1 file diff -r b7342e8fca5e6676fce8933747ef1ea57e99b8e9 -r a6dad23f94019b481ccd45187b55bcfdc6f983c3 lib/galaxy/webapps/galaxy/api/authenticate.py --- a/lib/galaxy/webapps/galaxy/api/authenticate.py +++ b/lib/galaxy/webapps/galaxy/api/authenticate.py @@ -52,7 +52,7 @@ raise exceptions.InconsistentDatabase( 'An error occured, please contact your administrator.' ) else: user = user[0] - is_valid_user = self.auth_manager.check_password(user, password) + is_valid_user = self.app.auth_manager.check_password(user, password) if is_valid_user: key = self.api_keys_manager.get_or_create_api_key( user ) return dict( api_key=key ) https://bitbucket.org/galaxy/galaxy-central/commits/5ce0704872a3/ Changeset: 5ce0704872a3 User: carlfeberhard Date: 2015-03-04 14:23:19+00:00 Summary: UI, multi-history: swap 'done' and 'create' buttons for better rtl intuition Affected #: 3 files diff -r a6dad23f94019b481ccd45187b55bcfdc6f983c3 -r 5ce0704872a33d6187f451d5c0c369b3b498b6fd client/galaxy/scripts/mvc/history/multi-panel.js --- a/client/galaxy/scripts/mvc/history/multi-panel.js +++ b/client/galaxy/scripts/mvc/history/multi-panel.js @@ -1043,7 +1043,7 @@ mainTemplate : _.template([ '<div class="header flex-column-container">', '<div class="control-column control-column-left flex-column">', - '<button class="create-new btn btn-default" tabindex="4">', _l( 'Create new' ), '</button> ', + '<button class="done btn btn-default" tabindex="1">', _l( 'Done' ), '</button>', '<div id="search-histories" class="search-control"></div>', '<div id="search-datasets" class="search-control"></div>', '<a class="open-more-options btn btn-default" tabindex="3">', @@ -1055,7 +1055,7 @@ '<div class="header-info">', '</div>', '</div>', '<div class="control-column control-column-right flex-column">', - '<button class="done btn btn-default" tabindex="1">', _l( 'Done' ), '</button>', + '<button class="create-new btn btn-default" tabindex="4">', _l( 'Create new' ), '</button> ', '</div>', '</div>', // middle - where the columns go diff -r a6dad23f94019b481ccd45187b55bcfdc6f983c3 -r 5ce0704872a33d6187f451d5c0c369b3b498b6fd static/scripts/mvc/history/multi-panel.js --- a/static/scripts/mvc/history/multi-panel.js +++ b/static/scripts/mvc/history/multi-panel.js @@ -1043,7 +1043,7 @@ mainTemplate : _.template([ '<div class="header flex-column-container">', '<div class="control-column control-column-left flex-column">', - '<button class="create-new btn btn-default" tabindex="4">', _l( 'Create new' ), '</button> ', + '<button class="done btn btn-default" tabindex="1">', _l( 'Done' ), '</button>', '<div id="search-histories" class="search-control"></div>', '<div id="search-datasets" class="search-control"></div>', '<a class="open-more-options btn btn-default" tabindex="3">', @@ -1055,7 +1055,7 @@ '<div class="header-info">', '</div>', '</div>', '<div class="control-column control-column-right flex-column">', - '<button class="done btn btn-default" tabindex="1">', _l( 'Done' ), '</button>', + '<button class="create-new btn btn-default" tabindex="4">', _l( 'Create new' ), '</button> ', '</div>', '</div>', // middle - where the columns go diff -r a6dad23f94019b481ccd45187b55bcfdc6f983c3 -r 5ce0704872a33d6187f451d5c0c369b3b498b6fd static/scripts/packed/mvc/history/multi-panel.js --- a/static/scripts/packed/mvc/history/multi-panel.js +++ b/static/scripts/packed/mvc/history/multi-panel.js @@ -1,1 +1,1 @@ -define(["mvc/history/history-model","mvc/history/history-panel-edit","mvc/base-mvc","utils/ajax-queue","ui/mode-button","ui/search-input"],function(d,l,z,a){function g(I,E){E=E||{};if(!(Galaxy&&Galaxy.modal)){return I.copy()}var F=I.get("name"),C="Copy of '"+F+"'";function D(K){if(!K){if(!Galaxy.modal.$("#invalid-title").size()){var J=$("<p/>").attr("id","invalid-title").css({color:"red","margin-top":"8px"}).addClass("bg-danger").text(_l("Please enter a valid history title"));Galaxy.modal.$(".modal-body").append(J)}return false}return K}function G(J){var K=$('<p><span class="fa fa-spinner fa-spin"></span> Copying history...</p>').css("margin-top","8px");Galaxy.modal.$(".modal-body").append(K);I.copy(true,J).fail(function(){alert(_l("History could not be copied. Please contact a Galaxy administrator"))}).always(function(){Galaxy.modal.hide()})}function H(){var J=Galaxy.modal.$("#copy-modal-title").val();if(!D(J)){return}G(J)}Galaxy.modal.show(_.extend({title:_l("Copying history")+' "'+F+'"',body:$(['<label for="copy-modal-title">',_l("Enter a title for the copied history"),":","</label><br />",'<input id="copy-modal-title" class="form-control" style="width: 100%" value="',C,'" />'].join("")),buttons:{Cancel:function(){Galaxy.modal.hide()},Copy:H}},E));$("#copy-modal-title").focus().select();$("#copy-modal-title").on("keydown",function(J){if(J.keyCode===13){H()}})}var B=Backbone.View.extend(z.LoggableMixin).extend({tagName:"div",className:"history-column flex-column flex-row-container",id:function q(){if(!this.model){return""}return"history-column-"+this.model.get("id")},initialize:function c(C){C=C||{};this.purgeAllowed=!_.isUndefined(C.purgeAllowed)?C.purgeAllowed:false;this.panel=C.panel||this.createPanel(C);this.setUpListeners()},createPanel:function u(D){D=_.extend({model:this.model,purgeAllowed:this.purgeAllowed,dragItems:true},D);var C=new l.HistoryPanelEdit(D);C._renderEmptyMessage=this.__patch_renderEmptyMessage;return C},__patch_renderEmptyMessage:function(E){var D=this,F=_.chain(this.model.get("state_ids")).values().flatten().value().length,C=D.$emptyMessage(E);if(!_.isEmpty(D.hdaViews)){C.hide()}else{if(F&&!this.model.contents.length){C.empty().append($('<span class="fa fa-spinner fa-spin"></span><i>loading datasets...</i>')).show()}else{if(D.searchFor){C.text(D.noneFoundMsg).show()}else{C.text(D.emptyMsg).show()}}}return C},setUpListeners:function f(){var C=this;this.once("rendered",function(){C.trigger("rendered:initial",C)});this.setUpPanelListeners()},setUpPanelListeners:function k(){var C=this;this.listenTo(this.panel,{rendered:function(){C.trigger("rendered",C)}},this)},inView:function(C,D){var F=this.$el.offset().left,E=F+this.$el.width();if(E<C){return false}if(F>D){return false}return true},$panel:function e(){return this.$(".history-panel")},render:function A(D){D=(D!==undefined)?(D):("fast");var C=this.model?this.model.toJSON():{};this.$el.html(this.template(C));this.renderPanel(D);this.setUpBehaviors();return this},setUpBehaviors:function v(){},template:function w(C){C=_.extend(C||{},{isCurrentHistory:this.currentHistory});return $(['<div class="panel-controls clear flex-row">',this.controlsLeftTemplate({history:C,view:this}),this.controlsRightTemplate({history:C,view:this}),"</div>",'<div class="inner flex-row flex-column-container">','<div id="history-',C.id,'" class="history-column history-panel flex-column"></div>',"</div>"].join(""))},renderPanel:function h(C){C=(C!==undefined)?(C):("fast");this.panel.setElement(this.$panel()).render(C);if(this.currentHistory){this.panel.$list().before(this.panel._renderDropTargetHelp())}return this},events:{"click .switch-to.btn":function(){this.model.setAsCurrent()},"click .delete-history":function(){var C=this;this.model._delete().fail(function(F,D,E){alert(_l("Could not delete the history")+":\n"+E)}).done(function(D){C.render()})},"click .undelete-history":function(){var C=this;this.model.undelete().fail(function(F,D,E){alert(_l("Could not undelete the history")+":\n"+E)}).done(function(D){C.render()})},"click .purge-history":function(){if(confirm(_l("This will permanently remove the data. Are you sure?"))){var C=this;this.model.purge().fail(function(F,D,E){alert(_l("Could not purge the history")+":\n"+E)}).done(function(D){C.render()})}},"click .copy-history":"copy"},copy:function s(){g(this.model)},controlsLeftTemplate:_.template(['<div class="pull-left">',"<% if( data.history.isCurrentHistory ){ %>",'<strong class="current-label">',_l("Current History"),"</strong>","<% } else { %>",'<button class="switch-to btn btn-default">',_l("Switch to"),"</button>","<% } %>","</div>"].join(""),{variable:"data"}),controlsRightTemplate:_.template(['<div class="pull-right">',"<% if( !data.history.purged ){ %>",'<div class="panel-menu btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu pull-right" role="menu">',"<% if( !data.history.deleted ){ %>",'<li><a href="javascript:void(0);" class="copy-history">',_l("Copy"),"</a></li>",'<li><a href="javascript:void(0);" class="delete-history">',_l("Delete"),"</a></li>","<% } else /* if is deleted */ { %>",'<li><a href="javascript:void(0);" class="undelete-history">',_l("Undelete"),"</a></li>","<% } %>","<% if( data.view.purgeAllowed ){ %>",'<li><a href="javascript:void(0);" class="purge-history">',_l("Purge"),"</a></li>","<% } %>","</ul>","</div>","<% } %>","</div>"].join(""),{variable:"data"}),toString:function(){return"HistoryPanelColumn("+(this.panel?this.panel:"")+")"}});var m=Backbone.View.extend(z.LoggableMixin).extend({className:"multi-panel-history",initialize:function c(C){C=C||{};this.log(this+".init",C);this.$el.addClass(this.className);if(!C.currentHistoryId){throw new Error(this+" requires a currentHistoryId in the options")}this.currentHistoryId=C.currentHistoryId;this.options={columnWidth:312,borderWidth:1,columnGap:8,headerHeight:29,footerHeight:0,controlsHeight:20};this.order=C.order||"update";this._initSortOrders();this.hdaQueue=new a.NamedAjaxQueue([],false);this.collection=null;this.setCollection(C.histories||[]);this.columnMap={};this.createColumns(C.columnOptions);this.setUpListeners()},_initSortOrders:function(){function C(D,E){return function F(H,G,I){if(H.id===I){return -1}if(G.id===I){return 1}H=D(H);G=D(G);return E.asc?((H===G)?(0):(H>G?1:-1)):((H===G)?(0):(H>G?-1:1))}}this.sortOrders={update:{text:_l("most recent first"),fn:C(function(D){return Date(D.get("update_time"))},{asc:false})},name:{text:_l("name, a to z"),fn:C(function(D){return D.get("name")},{asc:true})},"name-dsc":{text:_l("name, z to a"),fn:C(function(D){return D.get("name")},{asc:false})},size:{text:_l("size, large to small"),fn:C(function(D){return D.get("size")},{asc:false})},"size-dsc":{text:_l("size, small to large"),fn:C(function(D){return D.get("size")},{asc:true})}};return this.sortOrders},setUpListeners:function f(){},setCollection:function y(D){var C=this;C.stopListening(C.collection);C.collection=D;C.sortCollection(C.order,{silent:true});C.setUpCollectionListeners();C.trigger("new-collection",C);return C},setUpCollectionListeners:function(){var C=this,D=C.collection;C.listenTo(D,{add:C.addAsCurrentColumn,"set-as-current":C.setCurrentHistory,"change:deleted change:purged":C.handleDeletedHistory,sort:function(){C.renderColumns(0)}})},setCurrentHistory:function p(D){var C=this.columnMap[this.currentHistoryId];if(C){C.currentHistory=false;C.$el.height("")}this.currentHistoryId=D.id;var E=this.columnMap[this.currentHistoryId];E.currentHistory=true;this.sortCollection();multipanel._recalcFirstColumnHeight();return E},handleDeletedHistory:function b(D){if(D.get("deleted")||D.get("purged")){this.log("handleDeletedHistory",this.collection.includeDeleted,D);var C=this;column=C.columnMap[D.id];if(!column){return}if(column.model.id===this.currentHistoryId){}else{if(!C.collection.includeDeleted){C.removeColumn(column)}}}},sortCollection:function(C,D){if(!(C in this.sortOrders)){C="update"}this.order=C;var G=this.currentHistoryId,F=this.sortOrders[C];this.collection.comparator=function E(I,H){return F.fn(I,H,G)};this.$(".current-order").text(F.text);if(this.$(".more-options").is(":visible")){this.$(".open-more-options.btn").popover("show")}this.collection.sort(D);return this.collection},create:function(C){return this.collection.create({current:true})},createColumns:function r(D){D=D||{};var C=this;this.columnMap={};C.collection.each(function(E,F){var G=C.createColumn(E,D);C.columnMap[E.id]=G})},createColumn:function t(E,C){C=_.extend({},C,{model:E,purgeAllowed:Galaxy.config.allow_user_dataset_purge});var D=new B(C);if(E.id===this.currentHistoryId){D.currentHistory=true}this.setUpColumnListeners(D);return D},sortedFilteredColumns:function(C){C=C||this.filters;if(!C||!C.length){return this.sortedColumns()}var D=this;return D.sortedColumns().filter(function(G,F){var E=G.currentHistory||_.every(C.map(function(H){return H.call(G)}));return E})},sortedColumns:function(){var D=this;var C=this.collection.map(function(F,E){return D.columnMap[F.id]});return C},addColumn:function o(E,C){C=C!==undefined?C:true;var D=this.createColumn(E);this.columnMap[E.id]=D;if(C){this.renderColumns()}return D},addAsCurrentColumn:function o(E){var D=this,C=this.addColumn(E,false);this.setCurrentHistory(E);C.once("rendered",function(){D.queueHdaFetch(C)});return C},removeColumn:function x(E,D){D=D!==undefined?D:true;this.log("removeColumn",E);if(!E){return}var F=this,C=this.options.columnWidth+this.options.columnGap;E.$el.fadeOut("fast",function(){if(D){$(this).remove();F.$(".middle").width(F.$(".middle").width()-C);F.checkColumnsInView();F._recalcFirstColumnHeight()}F.stopListening(E.panel);F.stopListening(E);delete F.columnMap[E.model.id];E.remove()})},setUpColumnListeners:function n(C){var D=this;D.listenTo(C,{"in-view":D.queueHdaFetch});D.listenTo(C.panel,{"view:draggable:dragstart":function(H,F,E,G){D._dropData=JSON.parse(H.dataTransfer.getData("text"));D.currentColumnDropTargetOn()},"view:draggable:dragend":function(H,F,E,G){D._dropData=null;D.currentColumnDropTargetOff()},"droptarget:drop":function(G,H,F){var I=D._dropData.filter(function(J){return F.model.contents.isCopyable(J)});D._dropData=null;var E=new a.NamedAjaxQueue();I.forEach(function(J){E.add({name:"copy-"+J.id,fn:function(){return F.model.contents.copy(J)}})});E.start();E.done(function(J){F.model.fetch()})}})},columnMapLength:function(){return Object.keys(this.columnMap).length},render:function A(D){D=D!==undefined?D:this.fxSpeed;var C=this;C.log(C+".render");C.$el.html(C.mainTemplate(C));C.renderColumns(D);C.setUpBehaviors();C.trigger("rendered",C);return C},renderColumns:function j(F){F=F!==undefined?F:this.fxSpeed;var E=this,C=E.sortedFilteredColumns();E.$(".middle").width(C.length*(this.options.columnWidth+this.options.columnGap)+this.options.columnGap+16);var D=E.$(".middle");D.empty();C.forEach(function(H,G){H.$el.appendTo(D);H.delegateEvents();E.renderColumn(H,F)});if(this.searchFor&&C.length<=1){}else{E.checkColumnsInView();this._recalcFirstColumnHeight()}return C},renderColumn:function(C,D){D=D!==undefined?D:this.fxSpeed;return C.render(D)},queueHdaFetch:function i(E){if(E.model.contents.length===0&&!E.model.get("empty")){var C={},D=_.values(E.panel.storage.get("expandedIds")).join();if(D){C.dataset_details=D}this.hdaQueue.add({name:E.model.id,fn:function(){var F=E.model.contents.fetch({data:C,silent:true});return F.done(function(G){E.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},queueHdaFetchDetails:function(C){if((C.model.contents.length===0&&!C.model.get("empty"))||(!C.model.contents.haveDetails())){this.hdaQueue.add({name:C.model.id,fn:function(){var D=C.model.contents.fetch({data:{details:"all"},silent:true});return D.done(function(E){C.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},renderInfo:function(C){return this.$(".header .header-info").text(C)},events:{"click .done.btn":"close","click .create-new.btn":"create","click #include-deleted":"_clickToggleDeletedHistories","click .order .set-order":"_chooseOrder","click #toggle-deleted":"_clickToggleDeletedDatasets","click #toggle-hidden":"_clickToggleHiddenDatasets"},close:function(D){var C="/";if(Galaxy&&Galaxy.options&&Galaxy.options.root){C=Galaxy.options.root}else{if(galaxy_config&&galaxy_config.root){C=galaxy_config.root}}window.location=C},_clickToggleDeletedHistories:function(C){return this.toggleDeletedHistories($(C.currentTarget).is(":checked"))},toggleDeletedHistories:function(C){if(C){window.location=Galaxy.options.root+"history/view_multiple?include_deleted_histories=True"}else{window.location=Galaxy.options.root+"history/view_multiple"}},_clickToggleDeletedDatasets:function(C){return this.toggleDeletedDatasets($(C.currentTarget).is(":checked"))},toggleDeletedDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowDeleted(C,false)},E*200)})},_clickToggleHiddenDatasets:function(C){return this.toggleHiddenDatasets($(C.currentTarget).is(":checked"))},toggleHiddenDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowHidden(C,false)},E*200)})},_chooseOrder:function(D){var C=$(D.currentTarget).data("order");this.sortCollection(C)},setUpBehaviors:function(){var D=this;D._moreOptionsPopover();D.$("#search-histories").searchInput({name:"search-histories",placeholder:_l("search histories"),onsearch:function(E){D.searchFor=E;D.filters=[function(){return this.model.matchesAll(D.searchFor)}];D.renderColumns(0)},onclear:function(E){D.searchFor=null;D.filters=[];D.renderColumns(0)}});D.$("#search-datasets").searchInput({name:"search-datasets",placeholder:_l("search all datasets"),onfirstsearch:function(E){D.hdaQueue.clear();D.$("#search-datasets").searchInput("toggle-loading");D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E);D.queueHdaFetchDetails(F)});D.hdaQueue.progress(function(F){D.renderInfo([_l("searching"),(F.curr+1),_l("of"),F.total].join(" "))});D.hdaQueue.deferred.done(function(){D.renderInfo("");D.$("#search-datasets").searchInput("toggle-loading")})},onsearch:function(E){D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E)})},onclear:function(E){D.searchFor=null;D.sortedFilteredColumns().forEach(function(F){F.panel.clearSearch()})}});$(window).resize(function(){D._recalcFirstColumnHeight()});var C=_.debounce(_.bind(this.checkColumnsInView,this),100);this.$(".middle").parent().scroll(C)},_moreOptionsPopover:function(){return this.$(".open-more-options.btn").popover({container:".header",placement:"bottom",html:true,content:$(this.optionsPopoverTemplate(this))})},_recalcFirstColumnHeight:function(){var C=this.$(".history-column").first(),E=this.$(".middle").height(),D=C.find(".panel-controls").height();C.height(E).find(".inner").height(E-D)},_viewport:function(){var C=this.$(".middle").parent().offset().left;return{left:C,right:C+this.$(".middle").parent().width()}},columnsInView:function(){var C=this._viewport();return this.sortedFilteredColumns().filter(function(D){return D.currentHistory||D.inView(C.left,C.right)})},checkColumnsInView:function(){this.columnsInView().forEach(function(C){C.trigger("in-view",C)})},currentColumnDropTargetOn:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=function(D){};C.panel.dropTargetOn()},currentColumnDropTargetOff:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=l.HistoryPanelEdit.prototype.dataDrop;C.panel.dropTarget=false;C.panel.$(".history-drop-target").remove()},toString:function(){return"MultiPanelColumns("+(this.columns?this.columns.length:0)+")"},mainTemplate:_.template(['<div class="header flex-column-container">','<div class="control-column control-column-left flex-column">','<button class="create-new btn btn-default" tabindex="4">',_l("Create new"),"</button> ",'<div id="search-histories" class="search-control"></div>','<div id="search-datasets" class="search-control"></div>','<a class="open-more-options btn btn-default" tabindex="3">','<span class="fa fa-ellipsis-h"></span>',"</a>","</div>",'<div class="control-column control-column-center flex-column">','<div class="header-info">',"</div>","</div>",'<div class="control-column control-column-right flex-column">','<button class="done btn btn-default" tabindex="1">',_l("Done"),"</button>","</div>","</div>",'<div class="outer-middle flex-row flex-row-container">','<div class="middle flex-column-container flex-row"></div>',"</div>",'<div class="footer flex-column-container">',"</div>"].join(""),{variable:"view"}),optionsPopoverTemplate:_.template(['<div class="more-options">','<div class="order btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">',_l("Order histories by")+" ",'<span class="current-order"><%= view.sortOrders[ view.order ].text %></span> ','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu" role="menu">',"<% _.each( view.sortOrders, function( order, key ){ %>",'<li><a href="javascript:void(0);" class="set-order" data-order="<%= key %>">',"<%= order.text %>","</a></li>","<% }); %>","</ul>","</div>",'<div class="checkbox"><label><input id="include-deleted" type="checkbox"','<%= view.collection.includeDeleted? " checked" : "" %>>',_l("Include deleted histories"),"</label></div>","<hr />",'<div class="checkbox"><label><input id="toggle-deleted" type="checkbox">',_l("Include deleted datasets"),"</label></div>",'<div class="checkbox"><label><input id="toggle-hidden" type="checkbox">',_l("Include hidden datasets"),"</label></div>","</div>"].join(""),{variable:"view"})});return{MultiPanelColumns:m}}); \ No newline at end of file +define(["mvc/history/history-model","mvc/history/history-panel-edit","mvc/base-mvc","utils/ajax-queue","ui/mode-button","ui/search-input"],function(d,l,z,a){function g(I,E){E=E||{};if(!(Galaxy&&Galaxy.modal)){return I.copy()}var F=I.get("name"),C="Copy of '"+F+"'";function D(K){if(!K){if(!Galaxy.modal.$("#invalid-title").size()){var J=$("<p/>").attr("id","invalid-title").css({color:"red","margin-top":"8px"}).addClass("bg-danger").text(_l("Please enter a valid history title"));Galaxy.modal.$(".modal-body").append(J)}return false}return K}function G(J){var K=$('<p><span class="fa fa-spinner fa-spin"></span> Copying history...</p>').css("margin-top","8px");Galaxy.modal.$(".modal-body").append(K);I.copy(true,J).fail(function(){alert(_l("History could not be copied. Please contact a Galaxy administrator"))}).always(function(){Galaxy.modal.hide()})}function H(){var J=Galaxy.modal.$("#copy-modal-title").val();if(!D(J)){return}G(J)}Galaxy.modal.show(_.extend({title:_l("Copying history")+' "'+F+'"',body:$(['<label for="copy-modal-title">',_l("Enter a title for the copied history"),":","</label><br />",'<input id="copy-modal-title" class="form-control" style="width: 100%" value="',C,'" />'].join("")),buttons:{Cancel:function(){Galaxy.modal.hide()},Copy:H}},E));$("#copy-modal-title").focus().select();$("#copy-modal-title").on("keydown",function(J){if(J.keyCode===13){H()}})}var B=Backbone.View.extend(z.LoggableMixin).extend({tagName:"div",className:"history-column flex-column flex-row-container",id:function q(){if(!this.model){return""}return"history-column-"+this.model.get("id")},initialize:function c(C){C=C||{};this.purgeAllowed=!_.isUndefined(C.purgeAllowed)?C.purgeAllowed:false;this.panel=C.panel||this.createPanel(C);this.setUpListeners()},createPanel:function u(D){D=_.extend({model:this.model,purgeAllowed:this.purgeAllowed,dragItems:true},D);var C=new l.HistoryPanelEdit(D);C._renderEmptyMessage=this.__patch_renderEmptyMessage;return C},__patch_renderEmptyMessage:function(E){var D=this,F=_.chain(this.model.get("state_ids")).values().flatten().value().length,C=D.$emptyMessage(E);if(!_.isEmpty(D.hdaViews)){C.hide()}else{if(F&&!this.model.contents.length){C.empty().append($('<span class="fa fa-spinner fa-spin"></span><i>loading datasets...</i>')).show()}else{if(D.searchFor){C.text(D.noneFoundMsg).show()}else{C.text(D.emptyMsg).show()}}}return C},setUpListeners:function f(){var C=this;this.once("rendered",function(){C.trigger("rendered:initial",C)});this.setUpPanelListeners()},setUpPanelListeners:function k(){var C=this;this.listenTo(this.panel,{rendered:function(){C.trigger("rendered",C)}},this)},inView:function(C,D){var F=this.$el.offset().left,E=F+this.$el.width();if(E<C){return false}if(F>D){return false}return true},$panel:function e(){return this.$(".history-panel")},render:function A(D){D=(D!==undefined)?(D):("fast");var C=this.model?this.model.toJSON():{};this.$el.html(this.template(C));this.renderPanel(D);this.setUpBehaviors();return this},setUpBehaviors:function v(){},template:function w(C){C=_.extend(C||{},{isCurrentHistory:this.currentHistory});return $(['<div class="panel-controls clear flex-row">',this.controlsLeftTemplate({history:C,view:this}),this.controlsRightTemplate({history:C,view:this}),"</div>",'<div class="inner flex-row flex-column-container">','<div id="history-',C.id,'" class="history-column history-panel flex-column"></div>',"</div>"].join(""))},renderPanel:function h(C){C=(C!==undefined)?(C):("fast");this.panel.setElement(this.$panel()).render(C);if(this.currentHistory){this.panel.$list().before(this.panel._renderDropTargetHelp())}return this},events:{"click .switch-to.btn":function(){this.model.setAsCurrent()},"click .delete-history":function(){var C=this;this.model._delete().fail(function(F,D,E){alert(_l("Could not delete the history")+":\n"+E)}).done(function(D){C.render()})},"click .undelete-history":function(){var C=this;this.model.undelete().fail(function(F,D,E){alert(_l("Could not undelete the history")+":\n"+E)}).done(function(D){C.render()})},"click .purge-history":function(){if(confirm(_l("This will permanently remove the data. Are you sure?"))){var C=this;this.model.purge().fail(function(F,D,E){alert(_l("Could not purge the history")+":\n"+E)}).done(function(D){C.render()})}},"click .copy-history":"copy"},copy:function s(){g(this.model)},controlsLeftTemplate:_.template(['<div class="pull-left">',"<% if( data.history.isCurrentHistory ){ %>",'<strong class="current-label">',_l("Current History"),"</strong>","<% } else { %>",'<button class="switch-to btn btn-default">',_l("Switch to"),"</button>","<% } %>","</div>"].join(""),{variable:"data"}),controlsRightTemplate:_.template(['<div class="pull-right">',"<% if( !data.history.purged ){ %>",'<div class="panel-menu btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu pull-right" role="menu">',"<% if( !data.history.deleted ){ %>",'<li><a href="javascript:void(0);" class="copy-history">',_l("Copy"),"</a></li>",'<li><a href="javascript:void(0);" class="delete-history">',_l("Delete"),"</a></li>","<% } else /* if is deleted */ { %>",'<li><a href="javascript:void(0);" class="undelete-history">',_l("Undelete"),"</a></li>","<% } %>","<% if( data.view.purgeAllowed ){ %>",'<li><a href="javascript:void(0);" class="purge-history">',_l("Purge"),"</a></li>","<% } %>","</ul>","</div>","<% } %>","</div>"].join(""),{variable:"data"}),toString:function(){return"HistoryPanelColumn("+(this.panel?this.panel:"")+")"}});var m=Backbone.View.extend(z.LoggableMixin).extend({className:"multi-panel-history",initialize:function c(C){C=C||{};this.log(this+".init",C);this.$el.addClass(this.className);if(!C.currentHistoryId){throw new Error(this+" requires a currentHistoryId in the options")}this.currentHistoryId=C.currentHistoryId;this.options={columnWidth:312,borderWidth:1,columnGap:8,headerHeight:29,footerHeight:0,controlsHeight:20};this.order=C.order||"update";this._initSortOrders();this.hdaQueue=new a.NamedAjaxQueue([],false);this.collection=null;this.setCollection(C.histories||[]);this.columnMap={};this.createColumns(C.columnOptions);this.setUpListeners()},_initSortOrders:function(){function C(D,E){return function F(H,G,I){if(H.id===I){return -1}if(G.id===I){return 1}H=D(H);G=D(G);return E.asc?((H===G)?(0):(H>G?1:-1)):((H===G)?(0):(H>G?-1:1))}}this.sortOrders={update:{text:_l("most recent first"),fn:C(function(D){return Date(D.get("update_time"))},{asc:false})},name:{text:_l("name, a to z"),fn:C(function(D){return D.get("name")},{asc:true})},"name-dsc":{text:_l("name, z to a"),fn:C(function(D){return D.get("name")},{asc:false})},size:{text:_l("size, large to small"),fn:C(function(D){return D.get("size")},{asc:false})},"size-dsc":{text:_l("size, small to large"),fn:C(function(D){return D.get("size")},{asc:true})}};return this.sortOrders},setUpListeners:function f(){},setCollection:function y(D){var C=this;C.stopListening(C.collection);C.collection=D;C.sortCollection(C.order,{silent:true});C.setUpCollectionListeners();C.trigger("new-collection",C);return C},setUpCollectionListeners:function(){var C=this,D=C.collection;C.listenTo(D,{add:C.addAsCurrentColumn,"set-as-current":C.setCurrentHistory,"change:deleted change:purged":C.handleDeletedHistory,sort:function(){C.renderColumns(0)}})},setCurrentHistory:function p(D){var C=this.columnMap[this.currentHistoryId];if(C){C.currentHistory=false;C.$el.height("")}this.currentHistoryId=D.id;var E=this.columnMap[this.currentHistoryId];E.currentHistory=true;this.sortCollection();multipanel._recalcFirstColumnHeight();return E},handleDeletedHistory:function b(D){if(D.get("deleted")||D.get("purged")){this.log("handleDeletedHistory",this.collection.includeDeleted,D);var C=this;column=C.columnMap[D.id];if(!column){return}if(column.model.id===this.currentHistoryId){}else{if(!C.collection.includeDeleted){C.removeColumn(column)}}}},sortCollection:function(C,D){if(!(C in this.sortOrders)){C="update"}this.order=C;var G=this.currentHistoryId,F=this.sortOrders[C];this.collection.comparator=function E(I,H){return F.fn(I,H,G)};this.$(".current-order").text(F.text);if(this.$(".more-options").is(":visible")){this.$(".open-more-options.btn").popover("show")}this.collection.sort(D);return this.collection},create:function(C){return this.collection.create({current:true})},createColumns:function r(D){D=D||{};var C=this;this.columnMap={};C.collection.each(function(E,F){var G=C.createColumn(E,D);C.columnMap[E.id]=G})},createColumn:function t(E,C){C=_.extend({},C,{model:E,purgeAllowed:Galaxy.config.allow_user_dataset_purge});var D=new B(C);if(E.id===this.currentHistoryId){D.currentHistory=true}this.setUpColumnListeners(D);return D},sortedFilteredColumns:function(C){C=C||this.filters;if(!C||!C.length){return this.sortedColumns()}var D=this;return D.sortedColumns().filter(function(G,F){var E=G.currentHistory||_.every(C.map(function(H){return H.call(G)}));return E})},sortedColumns:function(){var D=this;var C=this.collection.map(function(F,E){return D.columnMap[F.id]});return C},addColumn:function o(E,C){C=C!==undefined?C:true;var D=this.createColumn(E);this.columnMap[E.id]=D;if(C){this.renderColumns()}return D},addAsCurrentColumn:function o(E){var D=this,C=this.addColumn(E,false);this.setCurrentHistory(E);C.once("rendered",function(){D.queueHdaFetch(C)});return C},removeColumn:function x(E,D){D=D!==undefined?D:true;this.log("removeColumn",E);if(!E){return}var F=this,C=this.options.columnWidth+this.options.columnGap;E.$el.fadeOut("fast",function(){if(D){$(this).remove();F.$(".middle").width(F.$(".middle").width()-C);F.checkColumnsInView();F._recalcFirstColumnHeight()}F.stopListening(E.panel);F.stopListening(E);delete F.columnMap[E.model.id];E.remove()})},setUpColumnListeners:function n(C){var D=this;D.listenTo(C,{"in-view":D.queueHdaFetch});D.listenTo(C.panel,{"view:draggable:dragstart":function(H,F,E,G){D._dropData=JSON.parse(H.dataTransfer.getData("text"));D.currentColumnDropTargetOn()},"view:draggable:dragend":function(H,F,E,G){D._dropData=null;D.currentColumnDropTargetOff()},"droptarget:drop":function(G,H,F){var I=D._dropData.filter(function(J){return F.model.contents.isCopyable(J)});D._dropData=null;var E=new a.NamedAjaxQueue();I.forEach(function(J){E.add({name:"copy-"+J.id,fn:function(){return F.model.contents.copy(J)}})});E.start();E.done(function(J){F.model.fetch()})}})},columnMapLength:function(){return Object.keys(this.columnMap).length},render:function A(D){D=D!==undefined?D:this.fxSpeed;var C=this;C.log(C+".render");C.$el.html(C.mainTemplate(C));C.renderColumns(D);C.setUpBehaviors();C.trigger("rendered",C);return C},renderColumns:function j(F){F=F!==undefined?F:this.fxSpeed;var E=this,C=E.sortedFilteredColumns();E.$(".middle").width(C.length*(this.options.columnWidth+this.options.columnGap)+this.options.columnGap+16);var D=E.$(".middle");D.empty();C.forEach(function(H,G){H.$el.appendTo(D);H.delegateEvents();E.renderColumn(H,F)});if(this.searchFor&&C.length<=1){}else{E.checkColumnsInView();this._recalcFirstColumnHeight()}return C},renderColumn:function(C,D){D=D!==undefined?D:this.fxSpeed;return C.render(D)},queueHdaFetch:function i(E){if(E.model.contents.length===0&&!E.model.get("empty")){var C={},D=_.values(E.panel.storage.get("expandedIds")).join();if(D){C.dataset_details=D}this.hdaQueue.add({name:E.model.id,fn:function(){var F=E.model.contents.fetch({data:C,silent:true});return F.done(function(G){E.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},queueHdaFetchDetails:function(C){if((C.model.contents.length===0&&!C.model.get("empty"))||(!C.model.contents.haveDetails())){this.hdaQueue.add({name:C.model.id,fn:function(){var D=C.model.contents.fetch({data:{details:"all"},silent:true});return D.done(function(E){C.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},renderInfo:function(C){return this.$(".header .header-info").text(C)},events:{"click .done.btn":"close","click .create-new.btn":"create","click #include-deleted":"_clickToggleDeletedHistories","click .order .set-order":"_chooseOrder","click #toggle-deleted":"_clickToggleDeletedDatasets","click #toggle-hidden":"_clickToggleHiddenDatasets"},close:function(D){var C="/";if(Galaxy&&Galaxy.options&&Galaxy.options.root){C=Galaxy.options.root}else{if(galaxy_config&&galaxy_config.root){C=galaxy_config.root}}window.location=C},_clickToggleDeletedHistories:function(C){return this.toggleDeletedHistories($(C.currentTarget).is(":checked"))},toggleDeletedHistories:function(C){if(C){window.location=Galaxy.options.root+"history/view_multiple?include_deleted_histories=True"}else{window.location=Galaxy.options.root+"history/view_multiple"}},_clickToggleDeletedDatasets:function(C){return this.toggleDeletedDatasets($(C.currentTarget).is(":checked"))},toggleDeletedDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowDeleted(C,false)},E*200)})},_clickToggleHiddenDatasets:function(C){return this.toggleHiddenDatasets($(C.currentTarget).is(":checked"))},toggleHiddenDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowHidden(C,false)},E*200)})},_chooseOrder:function(D){var C=$(D.currentTarget).data("order");this.sortCollection(C)},setUpBehaviors:function(){var D=this;D._moreOptionsPopover();D.$("#search-histories").searchInput({name:"search-histories",placeholder:_l("search histories"),onsearch:function(E){D.searchFor=E;D.filters=[function(){return this.model.matchesAll(D.searchFor)}];D.renderColumns(0)},onclear:function(E){D.searchFor=null;D.filters=[];D.renderColumns(0)}});D.$("#search-datasets").searchInput({name:"search-datasets",placeholder:_l("search all datasets"),onfirstsearch:function(E){D.hdaQueue.clear();D.$("#search-datasets").searchInput("toggle-loading");D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E);D.queueHdaFetchDetails(F)});D.hdaQueue.progress(function(F){D.renderInfo([_l("searching"),(F.curr+1),_l("of"),F.total].join(" "))});D.hdaQueue.deferred.done(function(){D.renderInfo("");D.$("#search-datasets").searchInput("toggle-loading")})},onsearch:function(E){D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E)})},onclear:function(E){D.searchFor=null;D.sortedFilteredColumns().forEach(function(F){F.panel.clearSearch()})}});$(window).resize(function(){D._recalcFirstColumnHeight()});var C=_.debounce(_.bind(this.checkColumnsInView,this),100);this.$(".middle").parent().scroll(C)},_moreOptionsPopover:function(){return this.$(".open-more-options.btn").popover({container:".header",placement:"bottom",html:true,content:$(this.optionsPopoverTemplate(this))})},_recalcFirstColumnHeight:function(){var C=this.$(".history-column").first(),E=this.$(".middle").height(),D=C.find(".panel-controls").height();C.height(E).find(".inner").height(E-D)},_viewport:function(){var C=this.$(".middle").parent().offset().left;return{left:C,right:C+this.$(".middle").parent().width()}},columnsInView:function(){var C=this._viewport();return this.sortedFilteredColumns().filter(function(D){return D.currentHistory||D.inView(C.left,C.right)})},checkColumnsInView:function(){this.columnsInView().forEach(function(C){C.trigger("in-view",C)})},currentColumnDropTargetOn:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=function(D){};C.panel.dropTargetOn()},currentColumnDropTargetOff:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=l.HistoryPanelEdit.prototype.dataDrop;C.panel.dropTarget=false;C.panel.$(".history-drop-target").remove()},toString:function(){return"MultiPanelColumns("+(this.columns?this.columns.length:0)+")"},mainTemplate:_.template(['<div class="header flex-column-container">','<div class="control-column control-column-left flex-column">','<button class="done btn btn-default" tabindex="1">',_l("Done"),"</button>",'<div id="search-histories" class="search-control"></div>','<div id="search-datasets" class="search-control"></div>','<a class="open-more-options btn btn-default" tabindex="3">','<span class="fa fa-ellipsis-h"></span>',"</a>","</div>",'<div class="control-column control-column-center flex-column">','<div class="header-info">',"</div>","</div>",'<div class="control-column control-column-right flex-column">','<button class="create-new btn btn-default" tabindex="4">',_l("Create new"),"</button> ","</div>","</div>",'<div class="outer-middle flex-row flex-row-container">','<div class="middle flex-column-container flex-row"></div>',"</div>",'<div class="footer flex-column-container">',"</div>"].join(""),{variable:"view"}),optionsPopoverTemplate:_.template(['<div class="more-options">','<div class="order btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">',_l("Order histories by")+" ",'<span class="current-order"><%= view.sortOrders[ view.order ].text %></span> ','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu" role="menu">',"<% _.each( view.sortOrders, function( order, key ){ %>",'<li><a href="javascript:void(0);" class="set-order" data-order="<%= key %>">',"<%= order.text %>","</a></li>","<% }); %>","</ul>","</div>",'<div class="checkbox"><label><input id="include-deleted" type="checkbox"','<%= view.collection.includeDeleted? " checked" : "" %>>',_l("Include deleted histories"),"</label></div>","<hr />",'<div class="checkbox"><label><input id="toggle-deleted" type="checkbox">',_l("Include deleted datasets"),"</label></div>",'<div class="checkbox"><label><input id="toggle-hidden" type="checkbox">',_l("Include hidden datasets"),"</label></div>","</div>"].join(""),{variable:"view"})});return{MultiPanelColumns:m}}); \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/10a1dd621cf0/ Changeset: 10a1dd621cf0 User: dannon Date: 2015-03-04 14:23:38+00:00 Summary: Update .gitignore to include run_api_tests.html Affected #: 1 file diff -r 5ce0704872a33d6187f451d5c0c369b3b498b6fd -r 10a1dd621cf0ea869179ab40d40c04e60cf6ea39 .gitignore --- a/.gitignore +++ b/.gitignore @@ -85,6 +85,7 @@ # Test output test-data-cache run_functional_tests.html +run_api_tests.html test/tool_shed/tmp/* .coverage htmlcov https://bitbucket.org/galaxy/galaxy-central/commits/58b95b1728ae/ Changeset: 58b95b1728ae User: martenson Date: 2015-03-04 16:04:14+00:00 Summary: move the logging to the timer function Affected #: 3 files diff -r 10a1dd621cf0ea869179ab40d40c04e60cf6ea39 -r 58b95b1728ae987ceb7b6291a63acf968a44d074 client/galaxy/scripts/mvc/tools.js --- a/client/galaxy/scripts/mvc/tools.js +++ b/client/galaxy/scripts/mvc/tools.js @@ -385,9 +385,9 @@ $("#search-clear-btn").hide(); $("#search-spinner").show(); var self = this; - // log the search to analytics - ga( 'send', 'pageview', galaxy_config.root + '?q=' + q ); this.timer = setTimeout(function () { + // log the search to analytics + ga( 'send', 'pageview', galaxy_config.root + '?q=' + q ); $.get(self.attributes.search_url, { query: q }, function (data) { self.set("results", data); $("#search-spinner").hide(); diff -r 10a1dd621cf0ea869179ab40d40c04e60cf6ea39 -r 58b95b1728ae987ceb7b6291a63acf968a44d074 static/scripts/mvc/tools.js --- a/static/scripts/mvc/tools.js +++ b/static/scripts/mvc/tools.js @@ -385,9 +385,9 @@ $("#search-clear-btn").hide(); $("#search-spinner").show(); var self = this; - // log the search to analytics - ga( 'send', 'pageview', galaxy_config.root + '?q=' + q ); this.timer = setTimeout(function () { + // log the search to analytics + ga( 'send', 'pageview', galaxy_config.root + '?q=' + q ); $.get(self.attributes.search_url, { query: q }, function (data) { self.set("results", data); $("#search-spinner").hide(); diff -r 10a1dd621cf0ea869179ab40d40c04e60cf6ea39 -r 58b95b1728ae987ceb7b6291a63acf968a44d074 static/scripts/packed/mvc/tools.js --- a/static/scripts/packed/mvc/tools.js +++ b/static/scripts/packed/mvc/tools.js @@ -1,1 +1,1 @@ -define(["libs/underscore","viz/trackster/util","mvc/data","libs/lunr"],function(y,a,z,s){var g={hidden:false,show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},toggle:function(){this.set("hidden",!this.get("hidden"))},is_visible:function(){return !this.attributes.hidden}};var e=Backbone.Model.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},initialize:function(A){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new e(this.toJSON())},set_value:function(A){this.set("value",A||"")}});var i=Backbone.Collection.extend({model:e});var k=e.extend({});var d=e.extend({set_value:function(A){this.set("value",parseInt(A,10))},get_samples:function(){return d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}});var f=d.extend({set_value:function(A){this.set("value",parseFloat(A))}});var u=e.extend({get_samples:function(){return y.map(this.get("options"),function(A){return A[0]})}});e.subModelTypes={integer:d,"float":f,data:k,select:u};var j=Backbone.Model.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[],outputs:[]},urlRoot:galaxy_config.root+"api/tools",initialize:function(A){this.set("inputs",new i(y.map(A.inputs,function(B){var C=e.subModelTypes[B.type]||e;return new C(B)})))},toJSON:function(){var A=Backbone.Model.prototype.toJSON.call(this);A.inputs=this.get("inputs").map(function(B){return B.toJSON()});return A},remove_inputs:function(B){var A=this,C=A.get("inputs").filter(function(D){return(B.indexOf(D.get("type"))!==-1)});A.get("inputs").remove(C)},copy:function(B){var C=new j(this.toJSON());if(B){var A=new Backbone.Collection();C.get("inputs").each(function(D){if(D.get_samples()){A.push(D)}});C.set("inputs",A)}return C},apply_search_results:function(A){(y.indexOf(A,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(A,B){this.get("inputs").find(function(C){return C.get("name")===A}).set("value",B)},set_input_values:function(B){var A=this;y.each(y.keys(B),function(C){A.set_input_value(C,B[C])})},run:function(){return this._run()},rerun:function(B,A){return this._run({action:"rerun",target_dataset_id:B.id,regions:A})},get_inputs_dict:function(){var A={};this.get("inputs").each(function(B){A[B.get("name")]=B.get("value")});return A},_run:function(C){var D=y.extend({tool_id:this.id,inputs:this.get_inputs_dict()},C);var B=$.Deferred(),A=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(D),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(E){return E!=="pending"}});$.when(A.go()).then(function(E){B.resolve(new z.DatasetCollection().reset(E))});return B}});y.extend(j.prototype,g);var q=Backbone.View.extend({});var n=Backbone.Collection.extend({model:j});var w=Backbone.Model.extend(g);var l=Backbone.Model.extend({defaults:{elems:[],open:false},clear_search_results:function(){y.each(this.attributes.elems,function(A){A.show()});this.show();this.set("open",false)},apply_search_results:function(B){var C=true,A;y.each(this.attributes.elems,function(D){if(D instanceof w){A=D;A.hide()}else{if(D instanceof j){if(D.apply_search_results(B)){C=false;if(A){A.show()}}}}});if(C){this.hide()}else{this.show();this.set("open",true)}}});y.extend(l.prototype,g);var c=Backbone.Model.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var C=this.attributes.query;if(C.length<this.attributes.min_chars_for_search){this.set("results",null);return}var B=C;if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var A=this;ga("send","pageview",galaxy_config.root+"?q="+B);this.timer=setTimeout(function(){$.get(A.attributes.search_url,{query:B},function(D){A.set("results",D);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},400)},clear_search:function(){this.set("query","");this.set("results",null)}});y.extend(c.prototype,g);var o=Backbone.Model.extend({initialize:function(A){this.attributes.tool_search=A.tool_search;this.attributes.tool_search.on("change:results",this.apply_search_results,this);this.attributes.tools=A.tools;this.attributes.layout=new Backbone.Collection(this.parse(A.layout))},parse:function(B){var A=this,C=function(F){var E=F.model_class;if(E.indexOf("Tool")===E.length-4){return A.attributes.tools.get(F.id)}else{if(E==="ToolSection"){var D=y.map(F.elems,C);F.elems=D;return new l(F)}else{if(E==="ToolSectionLabel"){return new w(F)}}}};return y.map(B,C)},clear_search_results:function(){this.get("layout").each(function(A){if(A instanceof l){A.clear_search_results()}else{A.show()}})},apply_search_results:function(){var B=this.get("tool_search").get("results");if(B===null){this.clear_search_results();return}var A=null;this.get("layout").each(function(C){if(C instanceof w){A=C;A.hide()}else{if(C instanceof j){if(C.apply_search_results(B)){if(A){A.show()}}}else{A=null;C.apply_search_results(B)}}})}});var t=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var m=t.extend({tagName:"div",render:function(){var A=$("<div/>");A.append(Handlebars.templates.tool_link(this.model.toJSON()));if(this.model.id==="upload1"){A.find("a").on("click",function(B){B.preventDefault();Galaxy.upload.show()})}this.$el.append(A);return this}});var b=t.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.text));return this}});var r=t.extend({tagName:"div",className:"toolSectionWrapper",initialize:function(){t.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(Handlebars.templates.panel_section(this.model.toJSON()));var A=this.$el.find(".toolSectionBody");y.each(this.model.attributes.elems,function(B){if(B instanceof j){var C=new m({model:B,className:"toolTitle"});C.render();A.append(C.$el)}else{if(B instanceof w){var D=new b({model:B});D.render();A.append(D.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var p=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(Handlebars.templates.tool_search(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find("[title]").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(A){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===A.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var x=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.model.get("tool_search").on("change:results",this.handle_search_results,this)},render:function(){var A=this;var B=new p({model:this.model.get("tool_search")});B.render();A.$el.append(B.$el);this.model.get("layout").each(function(D){if(D instanceof l){var C=new r({model:D});C.render();A.$el.append(C.$el)}else{if(D instanceof j){var E=new m({model:D,className:"toolTitleNoSection"});E.render();A.$el.append(E.$el)}else{if(D instanceof w){var F=new b({model:D});F.render();A.$el.append(F.$el)}}}});A.$el.find("a.tool-link").click(function(E){var D=$(this).attr("class").split(/\s+/)[0],C=A.model.get("tools").get(D);A.trigger("tool_link_click",E,C)});return this},handle_search_results:function(){var A=this.model.get("tool_search").get("results");if(A&&A.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var v=Backbone.View.extend({className:"toolForm",render:function(){this.$el.children().remove();this.$el.append(Handlebars.templates.tool_form(this.model.toJSON()))}});var h=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new x({collection:this.collection});this.tool_form_view=new v()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var A=this;this.tool_panel_view.on("tool_link_click",function(C,B){C.preventDefault();A.show_tool(B)})},show_tool:function(B){var A=this;B.fetch().done(function(){A.tool_form_view.model=B;A.tool_form_view.render();A.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:e,IntegerToolParameter:d,SelectToolParameter:u,Tool:j,ToolCollection:n,ToolSearch:c,ToolPanel:o,ToolPanelView:x,ToolFormView:v}}); \ No newline at end of file +define(["libs/underscore","viz/trackster/util","mvc/data","libs/lunr"],function(y,a,z,s){var g={hidden:false,show:function(){this.set("hidden",false)},hide:function(){this.set("hidden",true)},toggle:function(){this.set("hidden",!this.get("hidden"))},is_visible:function(){return !this.attributes.hidden}};var e=Backbone.Model.extend({defaults:{name:null,label:null,type:null,value:null,html:null,num_samples:5},initialize:function(A){this.attributes.html=unescape(this.attributes.html)},copy:function(){return new e(this.toJSON())},set_value:function(A){this.set("value",A||"")}});var i=Backbone.Collection.extend({model:e});var k=e.extend({});var d=e.extend({set_value:function(A){this.set("value",parseInt(A,10))},get_samples:function(){return d3.scale.linear().domain([this.get("min"),this.get("max")]).ticks(this.get("num_samples"))}});var f=d.extend({set_value:function(A){this.set("value",parseFloat(A))}});var u=e.extend({get_samples:function(){return y.map(this.get("options"),function(A){return A[0]})}});e.subModelTypes={integer:d,"float":f,data:k,select:u};var j=Backbone.Model.extend({defaults:{id:null,name:null,description:null,target:null,inputs:[],outputs:[]},urlRoot:galaxy_config.root+"api/tools",initialize:function(A){this.set("inputs",new i(y.map(A.inputs,function(B){var C=e.subModelTypes[B.type]||e;return new C(B)})))},toJSON:function(){var A=Backbone.Model.prototype.toJSON.call(this);A.inputs=this.get("inputs").map(function(B){return B.toJSON()});return A},remove_inputs:function(B){var A=this,C=A.get("inputs").filter(function(D){return(B.indexOf(D.get("type"))!==-1)});A.get("inputs").remove(C)},copy:function(B){var C=new j(this.toJSON());if(B){var A=new Backbone.Collection();C.get("inputs").each(function(D){if(D.get_samples()){A.push(D)}});C.set("inputs",A)}return C},apply_search_results:function(A){(y.indexOf(A,this.attributes.id)!==-1?this.show():this.hide());return this.is_visible()},set_input_value:function(A,B){this.get("inputs").find(function(C){return C.get("name")===A}).set("value",B)},set_input_values:function(B){var A=this;y.each(y.keys(B),function(C){A.set_input_value(C,B[C])})},run:function(){return this._run()},rerun:function(B,A){return this._run({action:"rerun",target_dataset_id:B.id,regions:A})},get_inputs_dict:function(){var A={};this.get("inputs").each(function(B){A[B.get("name")]=B.get("value")});return A},_run:function(C){var D=y.extend({tool_id:this.id,inputs:this.get_inputs_dict()},C);var B=$.Deferred(),A=new a.ServerStateDeferred({ajax_settings:{url:this.urlRoot,data:JSON.stringify(D),dataType:"json",contentType:"application/json",type:"POST"},interval:2000,success_fn:function(E){return E!=="pending"}});$.when(A.go()).then(function(E){B.resolve(new z.DatasetCollection().reset(E))});return B}});y.extend(j.prototype,g);var q=Backbone.View.extend({});var n=Backbone.Collection.extend({model:j});var w=Backbone.Model.extend(g);var l=Backbone.Model.extend({defaults:{elems:[],open:false},clear_search_results:function(){y.each(this.attributes.elems,function(A){A.show()});this.show();this.set("open",false)},apply_search_results:function(B){var C=true,A;y.each(this.attributes.elems,function(D){if(D instanceof w){A=D;A.hide()}else{if(D instanceof j){if(D.apply_search_results(B)){C=false;if(A){A.show()}}}}});if(C){this.hide()}else{this.show();this.set("open",true)}}});y.extend(l.prototype,g);var c=Backbone.Model.extend({defaults:{search_hint_string:"search tools",min_chars_for_search:3,spinner_url:"",clear_btn_url:"",search_url:"",visible:true,query:"",results:null,clear_key:27},initialize:function(){this.on("change:query",this.do_search)},do_search:function(){var C=this.attributes.query;if(C.length<this.attributes.min_chars_for_search){this.set("results",null);return}var B=C;if(this.timer){clearTimeout(this.timer)}$("#search-clear-btn").hide();$("#search-spinner").show();var A=this;this.timer=setTimeout(function(){ga("send","pageview",galaxy_config.root+"?q="+B);$.get(A.attributes.search_url,{query:B},function(D){A.set("results",D);$("#search-spinner").hide();$("#search-clear-btn").show()},"json")},400)},clear_search:function(){this.set("query","");this.set("results",null)}});y.extend(c.prototype,g);var o=Backbone.Model.extend({initialize:function(A){this.attributes.tool_search=A.tool_search;this.attributes.tool_search.on("change:results",this.apply_search_results,this);this.attributes.tools=A.tools;this.attributes.layout=new Backbone.Collection(this.parse(A.layout))},parse:function(B){var A=this,C=function(F){var E=F.model_class;if(E.indexOf("Tool")===E.length-4){return A.attributes.tools.get(F.id)}else{if(E==="ToolSection"){var D=y.map(F.elems,C);F.elems=D;return new l(F)}else{if(E==="ToolSectionLabel"){return new w(F)}}}};return y.map(B,C)},clear_search_results:function(){this.get("layout").each(function(A){if(A instanceof l){A.clear_search_results()}else{A.show()}})},apply_search_results:function(){var B=this.get("tool_search").get("results");if(B===null){this.clear_search_results();return}var A=null;this.get("layout").each(function(C){if(C instanceof w){A=C;A.hide()}else{if(C instanceof j){if(C.apply_search_results(B)){if(A){A.show()}}}else{A=null;C.apply_search_results(B)}}})}});var t=Backbone.View.extend({initialize:function(){this.model.on("change:hidden",this.update_visible,this);this.update_visible()},update_visible:function(){(this.model.attributes.hidden?this.$el.hide():this.$el.show())}});var m=t.extend({tagName:"div",render:function(){var A=$("<div/>");A.append(Handlebars.templates.tool_link(this.model.toJSON()));if(this.model.id==="upload1"){A.find("a").on("click",function(B){B.preventDefault();Galaxy.upload.show()})}this.$el.append(A);return this}});var b=t.extend({tagName:"div",className:"toolPanelLabel",render:function(){this.$el.append($("<span/>").text(this.model.attributes.text));return this}});var r=t.extend({tagName:"div",className:"toolSectionWrapper",initialize:function(){t.prototype.initialize.call(this);this.model.on("change:open",this.update_open,this)},render:function(){this.$el.append(Handlebars.templates.panel_section(this.model.toJSON()));var A=this.$el.find(".toolSectionBody");y.each(this.model.attributes.elems,function(B){if(B instanceof j){var C=new m({model:B,className:"toolTitle"});C.render();A.append(C.$el)}else{if(B instanceof w){var D=new b({model:B});D.render();A.append(D.$el)}else{}}});return this},events:{"click .toolSectionTitle > a":"toggle"},toggle:function(){this.model.set("open",!this.model.attributes.open)},update_open:function(){(this.model.attributes.open?this.$el.children(".toolSectionBody").slideDown("fast"):this.$el.children(".toolSectionBody").slideUp("fast"))}});var p=Backbone.View.extend({tagName:"div",id:"tool-search",className:"bar",events:{click:"focus_and_select","keyup :input":"query_changed","click #search-clear-btn":"clear"},render:function(){this.$el.append(Handlebars.templates.tool_search(this.model.toJSON()));if(!this.model.is_visible()){this.$el.hide()}this.$el.find("[title]").tooltip();return this},focus_and_select:function(){this.$el.find(":input").focus().select()},clear:function(){this.model.clear_search();this.$el.find(":input").val(this.model.attributes.search_hint_string);this.focus_and_select();return false},query_changed:function(A){if((this.model.attributes.clear_key)&&(this.model.attributes.clear_key===A.which)){this.clear();return false}this.model.set("query",this.$el.find(":input").val())}});var x=Backbone.View.extend({tagName:"div",className:"toolMenu",initialize:function(){this.model.get("tool_search").on("change:results",this.handle_search_results,this)},render:function(){var A=this;var B=new p({model:this.model.get("tool_search")});B.render();A.$el.append(B.$el);this.model.get("layout").each(function(D){if(D instanceof l){var C=new r({model:D});C.render();A.$el.append(C.$el)}else{if(D instanceof j){var E=new m({model:D,className:"toolTitleNoSection"});E.render();A.$el.append(E.$el)}else{if(D instanceof w){var F=new b({model:D});F.render();A.$el.append(F.$el)}}}});A.$el.find("a.tool-link").click(function(E){var D=$(this).attr("class").split(/\s+/)[0],C=A.model.get("tools").get(D);A.trigger("tool_link_click",E,C)});return this},handle_search_results:function(){var A=this.model.get("tool_search").get("results");if(A&&A.length===0){$("#search-no-results").show()}else{$("#search-no-results").hide()}}});var v=Backbone.View.extend({className:"toolForm",render:function(){this.$el.children().remove();this.$el.append(Handlebars.templates.tool_form(this.model.toJSON()))}});var h=Backbone.View.extend({className:"toolMenuAndView",initialize:function(){this.tool_panel_view=new x({collection:this.collection});this.tool_form_view=new v()},render:function(){this.tool_panel_view.render();this.tool_panel_view.$el.css("float","left");this.$el.append(this.tool_panel_view.$el);this.tool_form_view.$el.hide();this.$el.append(this.tool_form_view.$el);var A=this;this.tool_panel_view.on("tool_link_click",function(C,B){C.preventDefault();A.show_tool(B)})},show_tool:function(B){var A=this;B.fetch().done(function(){A.tool_form_view.model=B;A.tool_form_view.render();A.tool_form_view.$el.show();$("#left").width("650px")})}});return{ToolParameter:e,IntegerToolParameter:d,SelectToolParameter:u,Tool:j,ToolCollection:n,ToolSearch:c,ToolPanel:o,ToolPanelView:x,ToolFormView:v}}); \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/8e5a68ec6570/ Changeset: 8e5a68ec6570 User: carlfeberhard Date: 2015-03-04 18:13:29+00:00 Summary: Fix: in multi-history order properly instantiate Dates for comparison and handle variadic better Affected #: 3 files diff -r 58b95b1728ae987ceb7b6291a63acf968a44d074 -r 8e5a68ec65708f727af1470cd014ab8daacf2aff client/galaxy/scripts/mvc/history/multi-panel.js --- a/client/galaxy/scripts/mvc/history/multi-panel.js +++ b/client/galaxy/scripts/mvc/history/multi-panel.js @@ -439,7 +439,7 @@ // default update : { text: _l( 'most recent first' ), - fn: _comparator( function( h ){ return Date( h.get( 'update_time' ) ); }, { asc : false }) + fn: _comparator( function( h ){ return new Date( h.get( 'update_time' ) ); }, { asc : false }) }, 'name' : { text: _l( 'name, a to z' ), @@ -542,6 +542,7 @@ * (sorting the collection will re-render the panel) */ sortCollection : function( order, options ){ + order = !_.isUndefined( order )? order : this.order; if( !( order in this.sortOrders ) ){ order = 'update'; } diff -r 58b95b1728ae987ceb7b6291a63acf968a44d074 -r 8e5a68ec65708f727af1470cd014ab8daacf2aff static/scripts/mvc/history/multi-panel.js --- a/static/scripts/mvc/history/multi-panel.js +++ b/static/scripts/mvc/history/multi-panel.js @@ -439,7 +439,7 @@ // default update : { text: _l( 'most recent first' ), - fn: _comparator( function( h ){ return Date( h.get( 'update_time' ) ); }, { asc : false }) + fn: _comparator( function( h ){ return new Date( h.get( 'update_time' ) ); }, { asc : false }) }, 'name' : { text: _l( 'name, a to z' ), @@ -542,6 +542,7 @@ * (sorting the collection will re-render the panel) */ sortCollection : function( order, options ){ + order = !_.isUndefined( order )? order : this.order; if( !( order in this.sortOrders ) ){ order = 'update'; } diff -r 58b95b1728ae987ceb7b6291a63acf968a44d074 -r 8e5a68ec65708f727af1470cd014ab8daacf2aff static/scripts/packed/mvc/history/multi-panel.js --- a/static/scripts/packed/mvc/history/multi-panel.js +++ b/static/scripts/packed/mvc/history/multi-panel.js @@ -1,1 +1,1 @@ -define(["mvc/history/history-model","mvc/history/history-panel-edit","mvc/base-mvc","utils/ajax-queue","ui/mode-button","ui/search-input"],function(d,l,z,a){function g(I,E){E=E||{};if(!(Galaxy&&Galaxy.modal)){return I.copy()}var F=I.get("name"),C="Copy of '"+F+"'";function D(K){if(!K){if(!Galaxy.modal.$("#invalid-title").size()){var J=$("<p/>").attr("id","invalid-title").css({color:"red","margin-top":"8px"}).addClass("bg-danger").text(_l("Please enter a valid history title"));Galaxy.modal.$(".modal-body").append(J)}return false}return K}function G(J){var K=$('<p><span class="fa fa-spinner fa-spin"></span> Copying history...</p>').css("margin-top","8px");Galaxy.modal.$(".modal-body").append(K);I.copy(true,J).fail(function(){alert(_l("History could not be copied. Please contact a Galaxy administrator"))}).always(function(){Galaxy.modal.hide()})}function H(){var J=Galaxy.modal.$("#copy-modal-title").val();if(!D(J)){return}G(J)}Galaxy.modal.show(_.extend({title:_l("Copying history")+' "'+F+'"',body:$(['<label for="copy-modal-title">',_l("Enter a title for the copied history"),":","</label><br />",'<input id="copy-modal-title" class="form-control" style="width: 100%" value="',C,'" />'].join("")),buttons:{Cancel:function(){Galaxy.modal.hide()},Copy:H}},E));$("#copy-modal-title").focus().select();$("#copy-modal-title").on("keydown",function(J){if(J.keyCode===13){H()}})}var B=Backbone.View.extend(z.LoggableMixin).extend({tagName:"div",className:"history-column flex-column flex-row-container",id:function q(){if(!this.model){return""}return"history-column-"+this.model.get("id")},initialize:function c(C){C=C||{};this.purgeAllowed=!_.isUndefined(C.purgeAllowed)?C.purgeAllowed:false;this.panel=C.panel||this.createPanel(C);this.setUpListeners()},createPanel:function u(D){D=_.extend({model:this.model,purgeAllowed:this.purgeAllowed,dragItems:true},D);var C=new l.HistoryPanelEdit(D);C._renderEmptyMessage=this.__patch_renderEmptyMessage;return C},__patch_renderEmptyMessage:function(E){var D=this,F=_.chain(this.model.get("state_ids")).values().flatten().value().length,C=D.$emptyMessage(E);if(!_.isEmpty(D.hdaViews)){C.hide()}else{if(F&&!this.model.contents.length){C.empty().append($('<span class="fa fa-spinner fa-spin"></span><i>loading datasets...</i>')).show()}else{if(D.searchFor){C.text(D.noneFoundMsg).show()}else{C.text(D.emptyMsg).show()}}}return C},setUpListeners:function f(){var C=this;this.once("rendered",function(){C.trigger("rendered:initial",C)});this.setUpPanelListeners()},setUpPanelListeners:function k(){var C=this;this.listenTo(this.panel,{rendered:function(){C.trigger("rendered",C)}},this)},inView:function(C,D){var F=this.$el.offset().left,E=F+this.$el.width();if(E<C){return false}if(F>D){return false}return true},$panel:function e(){return this.$(".history-panel")},render:function A(D){D=(D!==undefined)?(D):("fast");var C=this.model?this.model.toJSON():{};this.$el.html(this.template(C));this.renderPanel(D);this.setUpBehaviors();return this},setUpBehaviors:function v(){},template:function w(C){C=_.extend(C||{},{isCurrentHistory:this.currentHistory});return $(['<div class="panel-controls clear flex-row">',this.controlsLeftTemplate({history:C,view:this}),this.controlsRightTemplate({history:C,view:this}),"</div>",'<div class="inner flex-row flex-column-container">','<div id="history-',C.id,'" class="history-column history-panel flex-column"></div>',"</div>"].join(""))},renderPanel:function h(C){C=(C!==undefined)?(C):("fast");this.panel.setElement(this.$panel()).render(C);if(this.currentHistory){this.panel.$list().before(this.panel._renderDropTargetHelp())}return this},events:{"click .switch-to.btn":function(){this.model.setAsCurrent()},"click .delete-history":function(){var C=this;this.model._delete().fail(function(F,D,E){alert(_l("Could not delete the history")+":\n"+E)}).done(function(D){C.render()})},"click .undelete-history":function(){var C=this;this.model.undelete().fail(function(F,D,E){alert(_l("Could not undelete the history")+":\n"+E)}).done(function(D){C.render()})},"click .purge-history":function(){if(confirm(_l("This will permanently remove the data. Are you sure?"))){var C=this;this.model.purge().fail(function(F,D,E){alert(_l("Could not purge the history")+":\n"+E)}).done(function(D){C.render()})}},"click .copy-history":"copy"},copy:function s(){g(this.model)},controlsLeftTemplate:_.template(['<div class="pull-left">',"<% if( data.history.isCurrentHistory ){ %>",'<strong class="current-label">',_l("Current History"),"</strong>","<% } else { %>",'<button class="switch-to btn btn-default">',_l("Switch to"),"</button>","<% } %>","</div>"].join(""),{variable:"data"}),controlsRightTemplate:_.template(['<div class="pull-right">',"<% if( !data.history.purged ){ %>",'<div class="panel-menu btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu pull-right" role="menu">',"<% if( !data.history.deleted ){ %>",'<li><a href="javascript:void(0);" class="copy-history">',_l("Copy"),"</a></li>",'<li><a href="javascript:void(0);" class="delete-history">',_l("Delete"),"</a></li>","<% } else /* if is deleted */ { %>",'<li><a href="javascript:void(0);" class="undelete-history">',_l("Undelete"),"</a></li>","<% } %>","<% if( data.view.purgeAllowed ){ %>",'<li><a href="javascript:void(0);" class="purge-history">',_l("Purge"),"</a></li>","<% } %>","</ul>","</div>","<% } %>","</div>"].join(""),{variable:"data"}),toString:function(){return"HistoryPanelColumn("+(this.panel?this.panel:"")+")"}});var m=Backbone.View.extend(z.LoggableMixin).extend({className:"multi-panel-history",initialize:function c(C){C=C||{};this.log(this+".init",C);this.$el.addClass(this.className);if(!C.currentHistoryId){throw new Error(this+" requires a currentHistoryId in the options")}this.currentHistoryId=C.currentHistoryId;this.options={columnWidth:312,borderWidth:1,columnGap:8,headerHeight:29,footerHeight:0,controlsHeight:20};this.order=C.order||"update";this._initSortOrders();this.hdaQueue=new a.NamedAjaxQueue([],false);this.collection=null;this.setCollection(C.histories||[]);this.columnMap={};this.createColumns(C.columnOptions);this.setUpListeners()},_initSortOrders:function(){function C(D,E){return function F(H,G,I){if(H.id===I){return -1}if(G.id===I){return 1}H=D(H);G=D(G);return E.asc?((H===G)?(0):(H>G?1:-1)):((H===G)?(0):(H>G?-1:1))}}this.sortOrders={update:{text:_l("most recent first"),fn:C(function(D){return Date(D.get("update_time"))},{asc:false})},name:{text:_l("name, a to z"),fn:C(function(D){return D.get("name")},{asc:true})},"name-dsc":{text:_l("name, z to a"),fn:C(function(D){return D.get("name")},{asc:false})},size:{text:_l("size, large to small"),fn:C(function(D){return D.get("size")},{asc:false})},"size-dsc":{text:_l("size, small to large"),fn:C(function(D){return D.get("size")},{asc:true})}};return this.sortOrders},setUpListeners:function f(){},setCollection:function y(D){var C=this;C.stopListening(C.collection);C.collection=D;C.sortCollection(C.order,{silent:true});C.setUpCollectionListeners();C.trigger("new-collection",C);return C},setUpCollectionListeners:function(){var C=this,D=C.collection;C.listenTo(D,{add:C.addAsCurrentColumn,"set-as-current":C.setCurrentHistory,"change:deleted change:purged":C.handleDeletedHistory,sort:function(){C.renderColumns(0)}})},setCurrentHistory:function p(D){var C=this.columnMap[this.currentHistoryId];if(C){C.currentHistory=false;C.$el.height("")}this.currentHistoryId=D.id;var E=this.columnMap[this.currentHistoryId];E.currentHistory=true;this.sortCollection();multipanel._recalcFirstColumnHeight();return E},handleDeletedHistory:function b(D){if(D.get("deleted")||D.get("purged")){this.log("handleDeletedHistory",this.collection.includeDeleted,D);var C=this;column=C.columnMap[D.id];if(!column){return}if(column.model.id===this.currentHistoryId){}else{if(!C.collection.includeDeleted){C.removeColumn(column)}}}},sortCollection:function(C,D){if(!(C in this.sortOrders)){C="update"}this.order=C;var G=this.currentHistoryId,F=this.sortOrders[C];this.collection.comparator=function E(I,H){return F.fn(I,H,G)};this.$(".current-order").text(F.text);if(this.$(".more-options").is(":visible")){this.$(".open-more-options.btn").popover("show")}this.collection.sort(D);return this.collection},create:function(C){return this.collection.create({current:true})},createColumns:function r(D){D=D||{};var C=this;this.columnMap={};C.collection.each(function(E,F){var G=C.createColumn(E,D);C.columnMap[E.id]=G})},createColumn:function t(E,C){C=_.extend({},C,{model:E,purgeAllowed:Galaxy.config.allow_user_dataset_purge});var D=new B(C);if(E.id===this.currentHistoryId){D.currentHistory=true}this.setUpColumnListeners(D);return D},sortedFilteredColumns:function(C){C=C||this.filters;if(!C||!C.length){return this.sortedColumns()}var D=this;return D.sortedColumns().filter(function(G,F){var E=G.currentHistory||_.every(C.map(function(H){return H.call(G)}));return E})},sortedColumns:function(){var D=this;var C=this.collection.map(function(F,E){return D.columnMap[F.id]});return C},addColumn:function o(E,C){C=C!==undefined?C:true;var D=this.createColumn(E);this.columnMap[E.id]=D;if(C){this.renderColumns()}return D},addAsCurrentColumn:function o(E){var D=this,C=this.addColumn(E,false);this.setCurrentHistory(E);C.once("rendered",function(){D.queueHdaFetch(C)});return C},removeColumn:function x(E,D){D=D!==undefined?D:true;this.log("removeColumn",E);if(!E){return}var F=this,C=this.options.columnWidth+this.options.columnGap;E.$el.fadeOut("fast",function(){if(D){$(this).remove();F.$(".middle").width(F.$(".middle").width()-C);F.checkColumnsInView();F._recalcFirstColumnHeight()}F.stopListening(E.panel);F.stopListening(E);delete F.columnMap[E.model.id];E.remove()})},setUpColumnListeners:function n(C){var D=this;D.listenTo(C,{"in-view":D.queueHdaFetch});D.listenTo(C.panel,{"view:draggable:dragstart":function(H,F,E,G){D._dropData=JSON.parse(H.dataTransfer.getData("text"));D.currentColumnDropTargetOn()},"view:draggable:dragend":function(H,F,E,G){D._dropData=null;D.currentColumnDropTargetOff()},"droptarget:drop":function(G,H,F){var I=D._dropData.filter(function(J){return F.model.contents.isCopyable(J)});D._dropData=null;var E=new a.NamedAjaxQueue();I.forEach(function(J){E.add({name:"copy-"+J.id,fn:function(){return F.model.contents.copy(J)}})});E.start();E.done(function(J){F.model.fetch()})}})},columnMapLength:function(){return Object.keys(this.columnMap).length},render:function A(D){D=D!==undefined?D:this.fxSpeed;var C=this;C.log(C+".render");C.$el.html(C.mainTemplate(C));C.renderColumns(D);C.setUpBehaviors();C.trigger("rendered",C);return C},renderColumns:function j(F){F=F!==undefined?F:this.fxSpeed;var E=this,C=E.sortedFilteredColumns();E.$(".middle").width(C.length*(this.options.columnWidth+this.options.columnGap)+this.options.columnGap+16);var D=E.$(".middle");D.empty();C.forEach(function(H,G){H.$el.appendTo(D);H.delegateEvents();E.renderColumn(H,F)});if(this.searchFor&&C.length<=1){}else{E.checkColumnsInView();this._recalcFirstColumnHeight()}return C},renderColumn:function(C,D){D=D!==undefined?D:this.fxSpeed;return C.render(D)},queueHdaFetch:function i(E){if(E.model.contents.length===0&&!E.model.get("empty")){var C={},D=_.values(E.panel.storage.get("expandedIds")).join();if(D){C.dataset_details=D}this.hdaQueue.add({name:E.model.id,fn:function(){var F=E.model.contents.fetch({data:C,silent:true});return F.done(function(G){E.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},queueHdaFetchDetails:function(C){if((C.model.contents.length===0&&!C.model.get("empty"))||(!C.model.contents.haveDetails())){this.hdaQueue.add({name:C.model.id,fn:function(){var D=C.model.contents.fetch({data:{details:"all"},silent:true});return D.done(function(E){C.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},renderInfo:function(C){return this.$(".header .header-info").text(C)},events:{"click .done.btn":"close","click .create-new.btn":"create","click #include-deleted":"_clickToggleDeletedHistories","click .order .set-order":"_chooseOrder","click #toggle-deleted":"_clickToggleDeletedDatasets","click #toggle-hidden":"_clickToggleHiddenDatasets"},close:function(D){var C="/";if(Galaxy&&Galaxy.options&&Galaxy.options.root){C=Galaxy.options.root}else{if(galaxy_config&&galaxy_config.root){C=galaxy_config.root}}window.location=C},_clickToggleDeletedHistories:function(C){return this.toggleDeletedHistories($(C.currentTarget).is(":checked"))},toggleDeletedHistories:function(C){if(C){window.location=Galaxy.options.root+"history/view_multiple?include_deleted_histories=True"}else{window.location=Galaxy.options.root+"history/view_multiple"}},_clickToggleDeletedDatasets:function(C){return this.toggleDeletedDatasets($(C.currentTarget).is(":checked"))},toggleDeletedDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowDeleted(C,false)},E*200)})},_clickToggleHiddenDatasets:function(C){return this.toggleHiddenDatasets($(C.currentTarget).is(":checked"))},toggleHiddenDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowHidden(C,false)},E*200)})},_chooseOrder:function(D){var C=$(D.currentTarget).data("order");this.sortCollection(C)},setUpBehaviors:function(){var D=this;D._moreOptionsPopover();D.$("#search-histories").searchInput({name:"search-histories",placeholder:_l("search histories"),onsearch:function(E){D.searchFor=E;D.filters=[function(){return this.model.matchesAll(D.searchFor)}];D.renderColumns(0)},onclear:function(E){D.searchFor=null;D.filters=[];D.renderColumns(0)}});D.$("#search-datasets").searchInput({name:"search-datasets",placeholder:_l("search all datasets"),onfirstsearch:function(E){D.hdaQueue.clear();D.$("#search-datasets").searchInput("toggle-loading");D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E);D.queueHdaFetchDetails(F)});D.hdaQueue.progress(function(F){D.renderInfo([_l("searching"),(F.curr+1),_l("of"),F.total].join(" "))});D.hdaQueue.deferred.done(function(){D.renderInfo("");D.$("#search-datasets").searchInput("toggle-loading")})},onsearch:function(E){D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E)})},onclear:function(E){D.searchFor=null;D.sortedFilteredColumns().forEach(function(F){F.panel.clearSearch()})}});$(window).resize(function(){D._recalcFirstColumnHeight()});var C=_.debounce(_.bind(this.checkColumnsInView,this),100);this.$(".middle").parent().scroll(C)},_moreOptionsPopover:function(){return this.$(".open-more-options.btn").popover({container:".header",placement:"bottom",html:true,content:$(this.optionsPopoverTemplate(this))})},_recalcFirstColumnHeight:function(){var C=this.$(".history-column").first(),E=this.$(".middle").height(),D=C.find(".panel-controls").height();C.height(E).find(".inner").height(E-D)},_viewport:function(){var C=this.$(".middle").parent().offset().left;return{left:C,right:C+this.$(".middle").parent().width()}},columnsInView:function(){var C=this._viewport();return this.sortedFilteredColumns().filter(function(D){return D.currentHistory||D.inView(C.left,C.right)})},checkColumnsInView:function(){this.columnsInView().forEach(function(C){C.trigger("in-view",C)})},currentColumnDropTargetOn:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=function(D){};C.panel.dropTargetOn()},currentColumnDropTargetOff:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=l.HistoryPanelEdit.prototype.dataDrop;C.panel.dropTarget=false;C.panel.$(".history-drop-target").remove()},toString:function(){return"MultiPanelColumns("+(this.columns?this.columns.length:0)+")"},mainTemplate:_.template(['<div class="header flex-column-container">','<div class="control-column control-column-left flex-column">','<button class="done btn btn-default" tabindex="1">',_l("Done"),"</button>",'<div id="search-histories" class="search-control"></div>','<div id="search-datasets" class="search-control"></div>','<a class="open-more-options btn btn-default" tabindex="3">','<span class="fa fa-ellipsis-h"></span>',"</a>","</div>",'<div class="control-column control-column-center flex-column">','<div class="header-info">',"</div>","</div>",'<div class="control-column control-column-right flex-column">','<button class="create-new btn btn-default" tabindex="4">',_l("Create new"),"</button> ","</div>","</div>",'<div class="outer-middle flex-row flex-row-container">','<div class="middle flex-column-container flex-row"></div>',"</div>",'<div class="footer flex-column-container">',"</div>"].join(""),{variable:"view"}),optionsPopoverTemplate:_.template(['<div class="more-options">','<div class="order btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">',_l("Order histories by")+" ",'<span class="current-order"><%= view.sortOrders[ view.order ].text %></span> ','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu" role="menu">',"<% _.each( view.sortOrders, function( order, key ){ %>",'<li><a href="javascript:void(0);" class="set-order" data-order="<%= key %>">',"<%= order.text %>","</a></li>","<% }); %>","</ul>","</div>",'<div class="checkbox"><label><input id="include-deleted" type="checkbox"','<%= view.collection.includeDeleted? " checked" : "" %>>',_l("Include deleted histories"),"</label></div>","<hr />",'<div class="checkbox"><label><input id="toggle-deleted" type="checkbox">',_l("Include deleted datasets"),"</label></div>",'<div class="checkbox"><label><input id="toggle-hidden" type="checkbox">',_l("Include hidden datasets"),"</label></div>","</div>"].join(""),{variable:"view"})});return{MultiPanelColumns:m}}); \ No newline at end of file +define(["mvc/history/history-model","mvc/history/history-panel-edit","mvc/base-mvc","utils/ajax-queue","ui/mode-button","ui/search-input"],function(d,l,z,a){function g(I,E){E=E||{};if(!(Galaxy&&Galaxy.modal)){return I.copy()}var F=I.get("name"),C="Copy of '"+F+"'";function D(K){if(!K){if(!Galaxy.modal.$("#invalid-title").size()){var J=$("<p/>").attr("id","invalid-title").css({color:"red","margin-top":"8px"}).addClass("bg-danger").text(_l("Please enter a valid history title"));Galaxy.modal.$(".modal-body").append(J)}return false}return K}function G(J){var K=$('<p><span class="fa fa-spinner fa-spin"></span> Copying history...</p>').css("margin-top","8px");Galaxy.modal.$(".modal-body").append(K);I.copy(true,J).fail(function(){alert(_l("History could not be copied. Please contact a Galaxy administrator"))}).always(function(){Galaxy.modal.hide()})}function H(){var J=Galaxy.modal.$("#copy-modal-title").val();if(!D(J)){return}G(J)}Galaxy.modal.show(_.extend({title:_l("Copying history")+' "'+F+'"',body:$(['<label for="copy-modal-title">',_l("Enter a title for the copied history"),":","</label><br />",'<input id="copy-modal-title" class="form-control" style="width: 100%" value="',C,'" />'].join("")),buttons:{Cancel:function(){Galaxy.modal.hide()},Copy:H}},E));$("#copy-modal-title").focus().select();$("#copy-modal-title").on("keydown",function(J){if(J.keyCode===13){H()}})}var B=Backbone.View.extend(z.LoggableMixin).extend({tagName:"div",className:"history-column flex-column flex-row-container",id:function q(){if(!this.model){return""}return"history-column-"+this.model.get("id")},initialize:function c(C){C=C||{};this.purgeAllowed=!_.isUndefined(C.purgeAllowed)?C.purgeAllowed:false;this.panel=C.panel||this.createPanel(C);this.setUpListeners()},createPanel:function u(D){D=_.extend({model:this.model,purgeAllowed:this.purgeAllowed,dragItems:true},D);var C=new l.HistoryPanelEdit(D);C._renderEmptyMessage=this.__patch_renderEmptyMessage;return C},__patch_renderEmptyMessage:function(E){var D=this,F=_.chain(this.model.get("state_ids")).values().flatten().value().length,C=D.$emptyMessage(E);if(!_.isEmpty(D.hdaViews)){C.hide()}else{if(F&&!this.model.contents.length){C.empty().append($('<span class="fa fa-spinner fa-spin"></span><i>loading datasets...</i>')).show()}else{if(D.searchFor){C.text(D.noneFoundMsg).show()}else{C.text(D.emptyMsg).show()}}}return C},setUpListeners:function f(){var C=this;this.once("rendered",function(){C.trigger("rendered:initial",C)});this.setUpPanelListeners()},setUpPanelListeners:function k(){var C=this;this.listenTo(this.panel,{rendered:function(){C.trigger("rendered",C)}},this)},inView:function(C,D){var F=this.$el.offset().left,E=F+this.$el.width();if(E<C){return false}if(F>D){return false}return true},$panel:function e(){return this.$(".history-panel")},render:function A(D){D=(D!==undefined)?(D):("fast");var C=this.model?this.model.toJSON():{};this.$el.html(this.template(C));this.renderPanel(D);this.setUpBehaviors();return this},setUpBehaviors:function v(){},template:function w(C){C=_.extend(C||{},{isCurrentHistory:this.currentHistory});return $(['<div class="panel-controls clear flex-row">',this.controlsLeftTemplate({history:C,view:this}),this.controlsRightTemplate({history:C,view:this}),"</div>",'<div class="inner flex-row flex-column-container">','<div id="history-',C.id,'" class="history-column history-panel flex-column"></div>',"</div>"].join(""))},renderPanel:function h(C){C=(C!==undefined)?(C):("fast");this.panel.setElement(this.$panel()).render(C);if(this.currentHistory){this.panel.$list().before(this.panel._renderDropTargetHelp())}return this},events:{"click .switch-to.btn":function(){this.model.setAsCurrent()},"click .delete-history":function(){var C=this;this.model._delete().fail(function(F,D,E){alert(_l("Could not delete the history")+":\n"+E)}).done(function(D){C.render()})},"click .undelete-history":function(){var C=this;this.model.undelete().fail(function(F,D,E){alert(_l("Could not undelete the history")+":\n"+E)}).done(function(D){C.render()})},"click .purge-history":function(){if(confirm(_l("This will permanently remove the data. Are you sure?"))){var C=this;this.model.purge().fail(function(F,D,E){alert(_l("Could not purge the history")+":\n"+E)}).done(function(D){C.render()})}},"click .copy-history":"copy"},copy:function s(){g(this.model)},controlsLeftTemplate:_.template(['<div class="pull-left">',"<% if( data.history.isCurrentHistory ){ %>",'<strong class="current-label">',_l("Current History"),"</strong>","<% } else { %>",'<button class="switch-to btn btn-default">',_l("Switch to"),"</button>","<% } %>","</div>"].join(""),{variable:"data"}),controlsRightTemplate:_.template(['<div class="pull-right">',"<% if( !data.history.purged ){ %>",'<div class="panel-menu btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu pull-right" role="menu">',"<% if( !data.history.deleted ){ %>",'<li><a href="javascript:void(0);" class="copy-history">',_l("Copy"),"</a></li>",'<li><a href="javascript:void(0);" class="delete-history">',_l("Delete"),"</a></li>","<% } else /* if is deleted */ { %>",'<li><a href="javascript:void(0);" class="undelete-history">',_l("Undelete"),"</a></li>","<% } %>","<% if( data.view.purgeAllowed ){ %>",'<li><a href="javascript:void(0);" class="purge-history">',_l("Purge"),"</a></li>","<% } %>","</ul>","</div>","<% } %>","</div>"].join(""),{variable:"data"}),toString:function(){return"HistoryPanelColumn("+(this.panel?this.panel:"")+")"}});var m=Backbone.View.extend(z.LoggableMixin).extend({className:"multi-panel-history",initialize:function c(C){C=C||{};this.log(this+".init",C);this.$el.addClass(this.className);if(!C.currentHistoryId){throw new Error(this+" requires a currentHistoryId in the options")}this.currentHistoryId=C.currentHistoryId;this.options={columnWidth:312,borderWidth:1,columnGap:8,headerHeight:29,footerHeight:0,controlsHeight:20};this.order=C.order||"update";this._initSortOrders();this.hdaQueue=new a.NamedAjaxQueue([],false);this.collection=null;this.setCollection(C.histories||[]);this.columnMap={};this.createColumns(C.columnOptions);this.setUpListeners()},_initSortOrders:function(){function C(D,E){return function F(H,G,I){if(H.id===I){return -1}if(G.id===I){return 1}H=D(H);G=D(G);return E.asc?((H===G)?(0):(H>G?1:-1)):((H===G)?(0):(H>G?-1:1))}}this.sortOrders={update:{text:_l("most recent first"),fn:C(function(D){return new Date(D.get("update_time"))},{asc:false})},name:{text:_l("name, a to z"),fn:C(function(D){return D.get("name")},{asc:true})},"name-dsc":{text:_l("name, z to a"),fn:C(function(D){return D.get("name")},{asc:false})},size:{text:_l("size, large to small"),fn:C(function(D){return D.get("size")},{asc:false})},"size-dsc":{text:_l("size, small to large"),fn:C(function(D){return D.get("size")},{asc:true})}};return this.sortOrders},setUpListeners:function f(){},setCollection:function y(D){var C=this;C.stopListening(C.collection);C.collection=D;C.sortCollection(C.order,{silent:true});C.setUpCollectionListeners();C.trigger("new-collection",C);return C},setUpCollectionListeners:function(){var C=this,D=C.collection;C.listenTo(D,{add:C.addAsCurrentColumn,"set-as-current":C.setCurrentHistory,"change:deleted change:purged":C.handleDeletedHistory,sort:function(){C.renderColumns(0)}})},setCurrentHistory:function p(D){var C=this.columnMap[this.currentHistoryId];if(C){C.currentHistory=false;C.$el.height("")}this.currentHistoryId=D.id;var E=this.columnMap[this.currentHistoryId];E.currentHistory=true;this.sortCollection();multipanel._recalcFirstColumnHeight();return E},handleDeletedHistory:function b(D){if(D.get("deleted")||D.get("purged")){this.log("handleDeletedHistory",this.collection.includeDeleted,D);var C=this;column=C.columnMap[D.id];if(!column){return}if(column.model.id===this.currentHistoryId){}else{if(!C.collection.includeDeleted){C.removeColumn(column)}}}},sortCollection:function(C,D){C=!_.isUndefined(C)?C:this.order;if(!(C in this.sortOrders)){C="update"}this.order=C;var G=this.currentHistoryId,F=this.sortOrders[C];this.collection.comparator=function E(I,H){return F.fn(I,H,G)};this.$(".current-order").text(F.text);if(this.$(".more-options").is(":visible")){this.$(".open-more-options.btn").popover("show")}this.collection.sort(D);return this.collection},create:function(C){return this.collection.create({current:true})},createColumns:function r(D){D=D||{};var C=this;this.columnMap={};C.collection.each(function(E,F){var G=C.createColumn(E,D);C.columnMap[E.id]=G})},createColumn:function t(E,C){C=_.extend({},C,{model:E,purgeAllowed:Galaxy.config.allow_user_dataset_purge});var D=new B(C);if(E.id===this.currentHistoryId){D.currentHistory=true}this.setUpColumnListeners(D);return D},sortedFilteredColumns:function(C){C=C||this.filters;if(!C||!C.length){return this.sortedColumns()}var D=this;return D.sortedColumns().filter(function(G,F){var E=G.currentHistory||_.every(C.map(function(H){return H.call(G)}));return E})},sortedColumns:function(){var D=this;var C=this.collection.map(function(F,E){return D.columnMap[F.id]});return C},addColumn:function o(E,C){C=C!==undefined?C:true;var D=this.createColumn(E);this.columnMap[E.id]=D;if(C){this.renderColumns()}return D},addAsCurrentColumn:function o(E){var D=this,C=this.addColumn(E,false);this.setCurrentHistory(E);C.once("rendered",function(){D.queueHdaFetch(C)});return C},removeColumn:function x(E,D){D=D!==undefined?D:true;this.log("removeColumn",E);if(!E){return}var F=this,C=this.options.columnWidth+this.options.columnGap;E.$el.fadeOut("fast",function(){if(D){$(this).remove();F.$(".middle").width(F.$(".middle").width()-C);F.checkColumnsInView();F._recalcFirstColumnHeight()}F.stopListening(E.panel);F.stopListening(E);delete F.columnMap[E.model.id];E.remove()})},setUpColumnListeners:function n(C){var D=this;D.listenTo(C,{"in-view":D.queueHdaFetch});D.listenTo(C.panel,{"view:draggable:dragstart":function(H,F,E,G){D._dropData=JSON.parse(H.dataTransfer.getData("text"));D.currentColumnDropTargetOn()},"view:draggable:dragend":function(H,F,E,G){D._dropData=null;D.currentColumnDropTargetOff()},"droptarget:drop":function(G,H,F){var I=D._dropData.filter(function(J){return F.model.contents.isCopyable(J)});D._dropData=null;var E=new a.NamedAjaxQueue();I.forEach(function(J){E.add({name:"copy-"+J.id,fn:function(){return F.model.contents.copy(J)}})});E.start();E.done(function(J){F.model.fetch()})}})},columnMapLength:function(){return Object.keys(this.columnMap).length},render:function A(D){D=D!==undefined?D:this.fxSpeed;var C=this;C.log(C+".render");C.$el.html(C.mainTemplate(C));C.renderColumns(D);C.setUpBehaviors();C.trigger("rendered",C);return C},renderColumns:function j(F){F=F!==undefined?F:this.fxSpeed;var E=this,C=E.sortedFilteredColumns();E.$(".middle").width(C.length*(this.options.columnWidth+this.options.columnGap)+this.options.columnGap+16);var D=E.$(".middle");D.empty();C.forEach(function(H,G){H.$el.appendTo(D);H.delegateEvents();E.renderColumn(H,F)});if(this.searchFor&&C.length<=1){}else{E.checkColumnsInView();this._recalcFirstColumnHeight()}return C},renderColumn:function(C,D){D=D!==undefined?D:this.fxSpeed;return C.render(D)},queueHdaFetch:function i(E){if(E.model.contents.length===0&&!E.model.get("empty")){var C={},D=_.values(E.panel.storage.get("expandedIds")).join();if(D){C.dataset_details=D}this.hdaQueue.add({name:E.model.id,fn:function(){var F=E.model.contents.fetch({data:C,silent:true});return F.done(function(G){E.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},queueHdaFetchDetails:function(C){if((C.model.contents.length===0&&!C.model.get("empty"))||(!C.model.contents.haveDetails())){this.hdaQueue.add({name:C.model.id,fn:function(){var D=C.model.contents.fetch({data:{details:"all"},silent:true});return D.done(function(E){C.panel.renderItems()})}});if(!this.hdaQueue.running){this.hdaQueue.start()}}},renderInfo:function(C){return this.$(".header .header-info").text(C)},events:{"click .done.btn":"close","click .create-new.btn":"create","click #include-deleted":"_clickToggleDeletedHistories","click .order .set-order":"_chooseOrder","click #toggle-deleted":"_clickToggleDeletedDatasets","click #toggle-hidden":"_clickToggleHiddenDatasets"},close:function(D){var C="/";if(Galaxy&&Galaxy.options&&Galaxy.options.root){C=Galaxy.options.root}else{if(galaxy_config&&galaxy_config.root){C=galaxy_config.root}}window.location=C},_clickToggleDeletedHistories:function(C){return this.toggleDeletedHistories($(C.currentTarget).is(":checked"))},toggleDeletedHistories:function(C){if(C){window.location=Galaxy.options.root+"history/view_multiple?include_deleted_histories=True"}else{window.location=Galaxy.options.root+"history/view_multiple"}},_clickToggleDeletedDatasets:function(C){return this.toggleDeletedDatasets($(C.currentTarget).is(":checked"))},toggleDeletedDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowDeleted(C,false)},E*200)})},_clickToggleHiddenDatasets:function(C){return this.toggleHiddenDatasets($(C.currentTarget).is(":checked"))},toggleHiddenDatasets:function(C){C=C!==undefined?C:false;var D=this;D.sortedFilteredColumns().forEach(function(F,E){_.delay(function(){F.panel.toggleShowHidden(C,false)},E*200)})},_chooseOrder:function(D){var C=$(D.currentTarget).data("order");this.sortCollection(C)},setUpBehaviors:function(){var D=this;D._moreOptionsPopover();D.$("#search-histories").searchInput({name:"search-histories",placeholder:_l("search histories"),onsearch:function(E){D.searchFor=E;D.filters=[function(){return this.model.matchesAll(D.searchFor)}];D.renderColumns(0)},onclear:function(E){D.searchFor=null;D.filters=[];D.renderColumns(0)}});D.$("#search-datasets").searchInput({name:"search-datasets",placeholder:_l("search all datasets"),onfirstsearch:function(E){D.hdaQueue.clear();D.$("#search-datasets").searchInput("toggle-loading");D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E);D.queueHdaFetchDetails(F)});D.hdaQueue.progress(function(F){D.renderInfo([_l("searching"),(F.curr+1),_l("of"),F.total].join(" "))});D.hdaQueue.deferred.done(function(){D.renderInfo("");D.$("#search-datasets").searchInput("toggle-loading")})},onsearch:function(E){D.searchFor=E;D.sortedFilteredColumns().forEach(function(F){F.panel.searchItems(E)})},onclear:function(E){D.searchFor=null;D.sortedFilteredColumns().forEach(function(F){F.panel.clearSearch()})}});$(window).resize(function(){D._recalcFirstColumnHeight()});var C=_.debounce(_.bind(this.checkColumnsInView,this),100);this.$(".middle").parent().scroll(C)},_moreOptionsPopover:function(){return this.$(".open-more-options.btn").popover({container:".header",placement:"bottom",html:true,content:$(this.optionsPopoverTemplate(this))})},_recalcFirstColumnHeight:function(){var C=this.$(".history-column").first(),E=this.$(".middle").height(),D=C.find(".panel-controls").height();C.height(E).find(".inner").height(E-D)},_viewport:function(){var C=this.$(".middle").parent().offset().left;return{left:C,right:C+this.$(".middle").parent().width()}},columnsInView:function(){var C=this._viewport();return this.sortedFilteredColumns().filter(function(D){return D.currentHistory||D.inView(C.left,C.right)})},checkColumnsInView:function(){this.columnsInView().forEach(function(C){C.trigger("in-view",C)})},currentColumnDropTargetOn:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=function(D){};C.panel.dropTargetOn()},currentColumnDropTargetOff:function(){var C=this.columnMap[this.currentHistoryId];if(!C){return}C.panel.dataDropped=l.HistoryPanelEdit.prototype.dataDrop;C.panel.dropTarget=false;C.panel.$(".history-drop-target").remove()},toString:function(){return"MultiPanelColumns("+(this.columns?this.columns.length:0)+")"},mainTemplate:_.template(['<div class="header flex-column-container">','<div class="control-column control-column-left flex-column">','<button class="done btn btn-default" tabindex="1">',_l("Done"),"</button>",'<div id="search-histories" class="search-control"></div>','<div id="search-datasets" class="search-control"></div>','<a class="open-more-options btn btn-default" tabindex="3">','<span class="fa fa-ellipsis-h"></span>',"</a>","</div>",'<div class="control-column control-column-center flex-column">','<div class="header-info">',"</div>","</div>",'<div class="control-column control-column-right flex-column">','<button class="create-new btn btn-default" tabindex="4">',_l("Create new"),"</button> ","</div>","</div>",'<div class="outer-middle flex-row flex-row-container">','<div class="middle flex-column-container flex-row"></div>',"</div>",'<div class="footer flex-column-container">',"</div>"].join(""),{variable:"view"}),optionsPopoverTemplate:_.template(['<div class="more-options">','<div class="order btn-group">','<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">',_l("Order histories by")+" ",'<span class="current-order"><%= view.sortOrders[ view.order ].text %></span> ','<span class="caret"></span>',"</button>",'<ul class="dropdown-menu" role="menu">',"<% _.each( view.sortOrders, function( order, key ){ %>",'<li><a href="javascript:void(0);" class="set-order" data-order="<%= key %>">',"<%= order.text %>","</a></li>","<% }); %>","</ul>","</div>",'<div class="checkbox"><label><input id="include-deleted" type="checkbox"','<%= view.collection.includeDeleted? " checked" : "" %>>',_l("Include deleted histories"),"</label></div>","<hr />",'<div class="checkbox"><label><input id="toggle-deleted" type="checkbox">',_l("Include deleted datasets"),"</label></div>",'<div class="checkbox"><label><input id="toggle-hidden" type="checkbox">',_l("Include hidden datasets"),"</label></div>","</div>"].join(""),{variable:"view"})});return{MultiPanelColumns:m}}); \ No newline at end of file https://bitbucket.org/galaxy/galaxy-central/commits/571919393f2b/ Changeset: 571919393f2b User: natefoo Date: 2015-03-02 19:58:49+00:00 Summary: Relocate the external set_metadata script to the galaxy_utils package. A temporary script in the job working directory will be created to import and call it (trusting that `$PYTHONPATH` in a job script is always set to `galaxy/lib`). This is so the auto-detect button can defer command line generation until job preparation time for the case that handlers and web processes run from different paths. Related Trello card: https://trello.com/c/v2eCOYZi Affected #: 9 files diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy/datatypes/metadata.py --- a/lib/galaxy/datatypes/metadata.py +++ b/lib/galaxy/datatypes/metadata.py @@ -667,8 +667,12 @@ # need to make different keys for them, since ids can overlap return "%s_%d" % ( dataset.__class__.__name__, dataset.id ) - def setup_external_metadata( self, datasets, sa_session, exec_dir=None, tmp_dir=None, dataset_files_path=None, - output_fnames=None, config_root=None, config_file=None, datatypes_config=None, job_metadata=None, compute_tmp_dir=None, kwds=None ): + def setup_external_metadata( self, datasets, sa_session, exec_dir=None, + tmp_dir=None, dataset_files_path=None, + output_fnames=None, config_root=None, + config_file=None, datatypes_config=None, + job_metadata=None, compute_tmp_dir=None, + include_command=True, kwds=None ): kwds = kwds or {} if tmp_dir is None: tmp_dir = MetadataTempFile.tmp_dir @@ -761,8 +765,22 @@ sa_session.add( metadata_files ) sa_session.flush() metadata_files_list.append( metadata_files ) - #return command required to build - return "%s %s %s %s %s %s %s %s" % ( os.path.join( exec_dir, 'set_metadata.sh' ), dataset_files_path, compute_tmp_dir or tmp_dir, config_root, config_file, datatypes_config, job_metadata, " ".join( map( __metadata_files_list_to_cmd_line, metadata_files_list ) ) ) + args = "%s %s %s %s %s %s %s" % ( dataset_files_path, + compute_tmp_dir or tmp_dir, + config_root, + config_file, + datatypes_config, + job_metadata, + " ".join( map( __metadata_files_list_to_cmd_line, metadata_files_list ) ) ) + if include_command: + #return command required to build + fd, fp = tempfile.mkstemp( suffix='.py', dir = tmp_dir, prefix = "set_metadata_" ) + metadata_script_file = abspath( fp ) + os.fdopen( fd, 'w' ).write( 'from galaxy_utils.metadata.set_metadata import set_metadata; set_metadata()' ) + return "python %s %s" % ( metadata_script_file, args ) + else: + # return args to galaxy_utils.metadata.set_metadata required to build + return args def external_metadata_set_successfully( self, dataset, sa_session ): metadata_files = self.get_output_filenames_by_dataset( dataset, sa_session ) diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy/datatypes/registry.py --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -645,12 +645,15 @@ <requirement type="package">samtools</requirement></requirements><action module="galaxy.tools.actions.metadata" class="SetMetadataToolAction"/> - <command>$__SET_EXTERNAL_METADATA_COMMAND_LINE__</command> + <command>python $set_metadata $__SET_EXTERNAL_METADATA_COMMAND_LINE__</command><inputs><param format="data" name="input1" type="data" label="File to set metadata on."/><param name="__ORIGINAL_DATASET_STATE__" type="hidden" value=""/><param name="__SET_EXTERNAL_METADATA_COMMAND_LINE__" type="hidden" value=""/></inputs> + <configfiles> + <configfile name="set_metadata">from galaxy_utils.metadata.set_metadata import set_metadata; set_metadata()</configfile> + </configfiles></tool> """ tmp_name = tempfile.NamedTemporaryFile() diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy/jobs/__init__.py --- a/lib/galaxy/jobs/__init__.py +++ b/lib/galaxy/jobs/__init__.py @@ -839,8 +839,7 @@ self.command_line, self.extra_filenames = tool_evaluator.build() # FIXME: for now, tools get Galaxy's lib dir in their path - if self.command_line and self.command_line.startswith( 'python' ): - self.galaxy_lib_dir = os.path.abspath( "lib" ) # cwd = galaxy root + self.galaxy_lib_dir = os.path.abspath( "lib" ) # cwd = galaxy root # Shell fragment to inject dependencies self.dependency_shell_commands = self.tool.build_dependency_shell_commands() # We need command_line persisted to the db in order for Galaxy to re-queue the job diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy/jobs/command_factory.py --- a/lib/galaxy/jobs/command_factory.py +++ b/lib/galaxy/jobs/command_factory.py @@ -145,7 +145,7 @@ metadata_command = metadata_command.strip() if metadata_command: commands_builder.capture_return_code() - commands_builder.append_command("cd %s; %s" % (exec_dir, metadata_command)) + commands_builder.append_command(metadata_command) def __copy_if_exists_command(work_dir_output): diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy/tools/actions/metadata.py --- a/lib/galaxy/tools/actions/metadata.py +++ b/lib/galaxy/tools/actions/metadata.py @@ -76,6 +76,7 @@ config_file = app.config.config_file, datatypes_config = app.datatypes_registry.integrated_datatypes_configs, job_metadata = None, + include_command = False, kwds = { 'overwrite' : overwrite } ) incoming[ '__SET_EXTERNAL_METADATA_COMMAND_LINE__' ] = cmd_line for name, value in tool.params_to_strings( incoming, app ).iteritems(): diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy_utils/metadata/__init__.py --- /dev/null +++ b/lib/galaxy_utils/metadata/__init__.py @@ -0,0 +1,2 @@ +""" Work with Galaxy metadata +""" diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 lib/galaxy_utils/metadata/set_metadata.py --- /dev/null +++ b/lib/galaxy_utils/metadata/set_metadata.py @@ -0,0 +1,144 @@ +""" +Execute an external process to set_meta() on a provided list of pickled datasets. + +This was formerly scripts/set_metadata.py and expects the same arguments as +that script. +""" + +import logging +logging.basicConfig() +log = logging.getLogger( __name__ ) + +import cPickle +import json +import os +import sys + +# ensure supported version +assert sys.version_info[:2] >= ( 2, 6 ) and sys.version_info[:2] <= ( 2, 7 ), 'Python version must be 2.6 or 2.7, this is: %s' % sys.version + +new_path = [ os.path.join( os.getcwd(), "lib" ) ] +new_path.extend( sys.path[ 1: ] ) # remove scripts/ from the path +sys.path = new_path + +from galaxy import eggs +import pkg_resources +import galaxy.model.mapping # need to load this before we unpickle, in order to setup properties assigned by the mappers +galaxy.model.Job() # this looks REAL stupid, but it is REQUIRED in order for SA to insert parameters into the classes defined by the mappers --> it appears that instantiating ANY mapper'ed class would suffice here +from galaxy.util import stringify_dictionary_keys +from sqlalchemy.orm import clear_mappers +from galaxy.objectstore import build_object_store_from_config +from galaxy import config +import ConfigParser +from galaxy.util.properties import load_app_properties + + +def set_meta_with_tool_provided( dataset_instance, file_dict, set_meta_kwds ): + # This method is somewhat odd, in that we set the metadata attributes from tool, + # then call set_meta, then set metadata attributes from tool again. + # This is intentional due to interplay of overwrite kwd, the fact that some metadata + # parameters may rely on the values of others, and that we are accepting the + # values provided by the tool as Truth. + for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): + setattr( dataset_instance.metadata, metadata_name, metadata_value ) + dataset_instance.datatype.set_meta( dataset_instance, **set_meta_kwds ) + for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): + setattr( dataset_instance.metadata, metadata_name, metadata_value ) + +def set_metadata(): + # set cwd to galaxy root + os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))) + file_path = sys.argv.pop( 1 ) + tool_job_working_directory = tmp_dir = sys.argv.pop( 1 ) #this is also the job_working_directory now + galaxy.model.Dataset.file_path = file_path + galaxy.datatypes.metadata.MetadataTempFile.tmp_dir = tmp_dir + + config_root = sys.argv.pop( 1 ) + config_file_name = sys.argv.pop( 1 ) + if not os.path.isabs( config_file_name ): + config_file_name = os.path.join( config_root, config_file_name ) + + # Set up reference to object store + # First, read in the main config file for Galaxy; this is required because + # the object store configuration is stored there + conf_dict = load_app_properties( ini_file=config_file_name ) + # config object is required by ObjectStore class so create it now + universe_config = config.Configuration(**conf_dict) + universe_config.ensure_tempdir() + object_store = build_object_store_from_config(universe_config) + galaxy.model.Dataset.object_store = object_store + + # Set up datatypes registry + datatypes_config = sys.argv.pop( 1 ) + datatypes_registry = galaxy.datatypes.registry.Registry() + datatypes_registry.load_datatypes( root_dir=config_root, config=datatypes_config ) + galaxy.model.set_datatypes_registry( datatypes_registry ) + + job_metadata = sys.argv.pop( 1 ) + existing_job_metadata_dict = {} + new_job_metadata_dict = {} + if job_metadata != "None" and os.path.exists( job_metadata ): + for line in open( job_metadata, 'r' ): + try: + line = stringify_dictionary_keys( json.loads( line ) ) + if line['type'] == 'dataset': + existing_job_metadata_dict[ line['dataset_id'] ] = line + elif line['type'] == 'new_primary_dataset': + new_job_metadata_dict[ line[ 'filename' ] ] = line + except: + continue + + for filenames in sys.argv[1:]: + fields = filenames.split( ',' ) + filename_in = fields.pop( 0 ) + filename_kwds = fields.pop( 0 ) + filename_out = fields.pop( 0 ) + filename_results_code = fields.pop( 0 ) + dataset_filename_override = fields.pop( 0 ) + # Need to be careful with the way that these parameters are populated from the filename splitting, + # because if a job is running when the server is updated, any existing external metadata command-lines + #will not have info about the newly added override_metadata file + if fields: + override_metadata = fields.pop( 0 ) + else: + override_metadata = None + set_meta_kwds = stringify_dictionary_keys( json.load( open( filename_kwds ) ) ) # load kwds; need to ensure our keywords are not unicode + try: + dataset = cPickle.load( open( filename_in ) ) # load DatasetInstance + if dataset_filename_override: + dataset.dataset.external_filename = dataset_filename_override + files_path = os.path.abspath(os.path.join( tool_job_working_directory, "dataset_%s_files" % (dataset.dataset.id) )) + dataset.dataset.external_extra_files_path = files_path + if dataset.dataset.id in existing_job_metadata_dict: + dataset.extension = existing_job_metadata_dict[ dataset.dataset.id ].get( 'ext', dataset.extension ) + # Metadata FileParameter types may not be writable on a cluster node, and are therefore temporarily substituted with MetadataTempFiles + if override_metadata: + override_metadata = json.load( open( override_metadata ) ) + for metadata_name, metadata_file_override in override_metadata: + if galaxy.datatypes.metadata.MetadataTempFile.is_JSONified_value( metadata_file_override ): + metadata_file_override = galaxy.datatypes.metadata.MetadataTempFile.from_JSON( metadata_file_override ) + setattr( dataset.metadata, metadata_name, metadata_file_override ) + file_dict = existing_job_metadata_dict.get( dataset.dataset.id, {} ) + set_meta_with_tool_provided( dataset, file_dict, set_meta_kwds ) + dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta + json.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) # setting metadata has succeeded + except Exception, e: + json.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) # setting metadata has failed somehow + + for i, ( filename, file_dict ) in enumerate( new_job_metadata_dict.iteritems(), start=1 ): + new_dataset = galaxy.model.Dataset( id=-i, external_filename=os.path.join( tool_job_working_directory, file_dict[ 'filename' ] ) ) + extra_files = file_dict.get( 'extra_files', None ) + if extra_files is not None: + new_dataset._extra_files_path = os.path.join( tool_job_working_directory, extra_files ) + new_dataset.state = new_dataset.states.OK + new_dataset_instance = galaxy.model.HistoryDatasetAssociation( id=-i, dataset=new_dataset, extension=file_dict.get( 'ext', 'data' ) ) + set_meta_with_tool_provided( new_dataset_instance, file_dict, set_meta_kwds ) + file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) #storing metadata in external form, need to turn back into dict, then later jsonify + if existing_job_metadata_dict or new_job_metadata_dict: + with open( job_metadata, 'wb' ) as job_metadata_fh: + for value in existing_job_metadata_dict.values() + new_job_metadata_dict.values(): + job_metadata_fh.write( "%s\n" % ( json.dumps( value ) ) ) + + clear_mappers() + # Shut down any additional threads that might have been created via the ObjectStore + object_store.shutdown() diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 scripts/set_metadata.py --- a/scripts/set_metadata.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -Execute an external process to set_meta() on a provided list of pickled datasets. - -This should not be called directly! Use the set_metadata.sh script in Galaxy's -top level directly. - -""" - -import logging -logging.basicConfig() -log = logging.getLogger( __name__ ) - -import cPickle -import json -import os -import sys - -# ensure supported version -from check_python import check_python -try: - check_python() -except: - sys.exit(1) - -new_path = [ os.path.join( os.getcwd(), "lib" ) ] -new_path.extend( sys.path[ 1: ] ) # remove scripts/ from the path -sys.path = new_path - -from galaxy import eggs -import pkg_resources -import galaxy.model.mapping # need to load this before we unpickle, in order to setup properties assigned by the mappers -galaxy.model.Job() # this looks REAL stupid, but it is REQUIRED in order for SA to insert parameters into the classes defined by the mappers --> it appears that instantiating ANY mapper'ed class would suffice here -from galaxy.util import stringify_dictionary_keys -from sqlalchemy.orm import clear_mappers -from galaxy.objectstore import build_object_store_from_config -from galaxy import config -import ConfigParser -from galaxy.util.properties import load_app_properties - - -def set_meta_with_tool_provided( dataset_instance, file_dict, set_meta_kwds ): - # This method is somewhat odd, in that we set the metadata attributes from tool, - # then call set_meta, then set metadata attributes from tool again. - # This is intentional due to interplay of overwrite kwd, the fact that some metadata - # parameters may rely on the values of others, and that we are accepting the - # values provided by the tool as Truth. - for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): - setattr( dataset_instance.metadata, metadata_name, metadata_value ) - dataset_instance.datatype.set_meta( dataset_instance, **set_meta_kwds ) - for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): - setattr( dataset_instance.metadata, metadata_name, metadata_value ) - -def __main__(): - file_path = sys.argv.pop( 1 ) - tool_job_working_directory = tmp_dir = sys.argv.pop( 1 ) #this is also the job_working_directory now - galaxy.model.Dataset.file_path = file_path - galaxy.datatypes.metadata.MetadataTempFile.tmp_dir = tmp_dir - - config_root = sys.argv.pop( 1 ) - config_file_name = sys.argv.pop( 1 ) - if not os.path.isabs( config_file_name ): - config_file_name = os.path.join( config_root, config_file_name ) - - # Set up reference to object store - # First, read in the main config file for Galaxy; this is required because - # the object store configuration is stored there - conf_dict = load_app_properties( ini_file=config_file_name ) - # config object is required by ObjectStore class so create it now - universe_config = config.Configuration(**conf_dict) - universe_config.ensure_tempdir() - object_store = build_object_store_from_config(universe_config) - galaxy.model.Dataset.object_store = object_store - - # Set up datatypes registry - datatypes_config = sys.argv.pop( 1 ) - datatypes_registry = galaxy.datatypes.registry.Registry() - datatypes_registry.load_datatypes( root_dir=config_root, config=datatypes_config ) - galaxy.model.set_datatypes_registry( datatypes_registry ) - - job_metadata = sys.argv.pop( 1 ) - existing_job_metadata_dict = {} - new_job_metadata_dict = {} - if job_metadata != "None" and os.path.exists( job_metadata ): - for line in open( job_metadata, 'r' ): - try: - line = stringify_dictionary_keys( json.loads( line ) ) - if line['type'] == 'dataset': - existing_job_metadata_dict[ line['dataset_id'] ] = line - elif line['type'] == 'new_primary_dataset': - new_job_metadata_dict[ line[ 'filename' ] ] = line - except: - continue - - for filenames in sys.argv[1:]: - fields = filenames.split( ',' ) - filename_in = fields.pop( 0 ) - filename_kwds = fields.pop( 0 ) - filename_out = fields.pop( 0 ) - filename_results_code = fields.pop( 0 ) - dataset_filename_override = fields.pop( 0 ) - # Need to be careful with the way that these parameters are populated from the filename splitting, - # because if a job is running when the server is updated, any existing external metadata command-lines - #will not have info about the newly added override_metadata file - if fields: - override_metadata = fields.pop( 0 ) - else: - override_metadata = None - set_meta_kwds = stringify_dictionary_keys( json.load( open( filename_kwds ) ) ) # load kwds; need to ensure our keywords are not unicode - try: - dataset = cPickle.load( open( filename_in ) ) # load DatasetInstance - if dataset_filename_override: - dataset.dataset.external_filename = dataset_filename_override - files_path = os.path.abspath(os.path.join( tool_job_working_directory, "dataset_%s_files" % (dataset.dataset.id) )) - dataset.dataset.external_extra_files_path = files_path - if dataset.dataset.id in existing_job_metadata_dict: - dataset.extension = existing_job_metadata_dict[ dataset.dataset.id ].get( 'ext', dataset.extension ) - # Metadata FileParameter types may not be writable on a cluster node, and are therefore temporarily substituted with MetadataTempFiles - if override_metadata: - override_metadata = json.load( open( override_metadata ) ) - for metadata_name, metadata_file_override in override_metadata: - if galaxy.datatypes.metadata.MetadataTempFile.is_JSONified_value( metadata_file_override ): - metadata_file_override = galaxy.datatypes.metadata.MetadataTempFile.from_JSON( metadata_file_override ) - setattr( dataset.metadata, metadata_name, metadata_file_override ) - file_dict = existing_job_metadata_dict.get( dataset.dataset.id, {} ) - set_meta_with_tool_provided( dataset, file_dict, set_meta_kwds ) - dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta - json.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) # setting metadata has succeeded - except Exception, e: - json.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) # setting metadata has failed somehow - - for i, ( filename, file_dict ) in enumerate( new_job_metadata_dict.iteritems(), start=1 ): - new_dataset = galaxy.model.Dataset( id=-i, external_filename=os.path.join( tool_job_working_directory, file_dict[ 'filename' ] ) ) - extra_files = file_dict.get( 'extra_files', None ) - if extra_files is not None: - new_dataset._extra_files_path = os.path.join( tool_job_working_directory, extra_files ) - new_dataset.state = new_dataset.states.OK - new_dataset_instance = galaxy.model.HistoryDatasetAssociation( id=-i, dataset=new_dataset, extension=file_dict.get( 'ext', 'data' ) ) - set_meta_with_tool_provided( new_dataset_instance, file_dict, set_meta_kwds ) - file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) #storing metadata in external form, need to turn back into dict, then later jsonify - if existing_job_metadata_dict or new_job_metadata_dict: - with open( job_metadata, 'wb' ) as job_metadata_fh: - for value in existing_job_metadata_dict.values() + new_job_metadata_dict.values(): - job_metadata_fh.write( "%s\n" % ( json.dumps( value ) ) ) - - clear_mappers() - # Shut down any additional threads that might have been created via the ObjectStore - object_store.shutdown() - -__main__() diff -r 8e5a68ec65708f727af1470cd014ab8daacf2aff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 set_metadata.sh --- a/set_metadata.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd `dirname $0` -python ./scripts/set_metadata.py $@ https://bitbucket.org/galaxy/galaxy-central/commits/8fe9a4c12495/ Changeset: 8fe9a4c12495 User: natefoo Date: 2015-03-04 18:23:40+00:00 Summary: Simply external set_metadata's requirements. Do not pass the config, files/temp, or galaxy root paths to the script. Instead, directly pass the path(s) to the files on which we are setting metadata, and determine the galaxy_root directory automatically based on the location of the set_metadata script. This is a fix to the previous commit for allowing the web and handler processes to run from different directories. Affected #: 3 files diff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 -r 8fe9a4c12495aab16b64330031c929b47bb7050a lib/galaxy/datatypes/metadata.py --- a/lib/galaxy/datatypes/metadata.py +++ b/lib/galaxy/datatypes/metadata.py @@ -691,8 +691,8 @@ def __get_filename_override(): if output_fnames: for dataset_path in output_fnames: - if dataset_path.false_path and dataset_path.real_path == metadata_files.dataset.file_name: - return dataset_path.false_path + if dataset_path.real_path == metadata_files.dataset.file_name: + return dataset_path.false_path or dataset_path.real_path return "" line = "%s,%s,%s,%s,%s,%s" % ( metadata_path_on_compute(metadata_files.filename_in), @@ -765,13 +765,9 @@ sa_session.add( metadata_files ) sa_session.flush() metadata_files_list.append( metadata_files ) - args = "%s %s %s %s %s %s %s" % ( dataset_files_path, - compute_tmp_dir or tmp_dir, - config_root, - config_file, - datatypes_config, - job_metadata, - " ".join( map( __metadata_files_list_to_cmd_line, metadata_files_list ) ) ) + args = "%s %s %s" % ( datatypes_config, + job_metadata, + " ".join( map( __metadata_files_list_to_cmd_line, metadata_files_list ) ) ) if include_command: #return command required to build fd, fp = tempfile.mkstemp( suffix='.py', dir = tmp_dir, prefix = "set_metadata_" ) diff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 -r 8fe9a4c12495aab16b64330031c929b47bb7050a lib/galaxy/tools/actions/metadata.py --- a/lib/galaxy/tools/actions/metadata.py +++ b/lib/galaxy/tools/actions/metadata.py @@ -2,6 +2,7 @@ from galaxy.datatypes.metadata import JobExternalOutputMetadataWrapper from galaxy.util.odict import odict from galaxy.util.json import dumps +from galaxy.jobs.datasets import DatasetPath import logging log = logging.getLogger( __name__ ) @@ -65,13 +66,14 @@ #add parameters to job_parameter table # Store original dataset state, so we can restore it. A separate table might be better (no chance of 'losing' the original state)? incoming[ '__ORIGINAL_DATASET_STATE__' ] = dataset.state + input_paths = [DatasetPath( dataset.id, real_path=dataset.file_name, mutable=False )] external_metadata_wrapper = JobExternalOutputMetadataWrapper( job ) cmd_line = external_metadata_wrapper.setup_external_metadata( dataset, sa_session, exec_dir = None, tmp_dir = app.config.new_file_path, dataset_files_path = app.model.Dataset.file_path, - output_fnames = None, + output_fnames = input_paths, config_root = app.config.root, config_file = app.config.config_file, datatypes_config = app.datatypes_registry.integrated_datatypes_configs, diff -r 571919393f2b860486d7a8d5c08a4f4bd47327d9 -r 8fe9a4c12495aab16b64330031c929b47bb7050a lib/galaxy_utils/metadata/set_metadata.py --- a/lib/galaxy_utils/metadata/set_metadata.py +++ b/lib/galaxy_utils/metadata/set_metadata.py @@ -1,8 +1,14 @@ """ Execute an external process to set_meta() on a provided list of pickled datasets. -This was formerly scripts/set_metadata.py and expects the same arguments as -that script. +This was formerly scripts/set_metadata.py and expects these arguments: + + %prog datatypes_conf.xml job_metadata_file metadata_in,metadata_kwds,metadata_out,metadata_results_code,output_filename_override,metadata_override... + +Galaxy should be importable on sys.path and output_filename_override should be +set to the path of the dataset on which metadata is being set +(output_filename_override could previously be left empty and the path would be +constructed automatically). """ import logging @@ -46,32 +52,14 @@ setattr( dataset_instance.metadata, metadata_name, metadata_value ) def set_metadata(): - # set cwd to galaxy root - os.chdir(os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir))) - file_path = sys.argv.pop( 1 ) - tool_job_working_directory = tmp_dir = sys.argv.pop( 1 ) #this is also the job_working_directory now - galaxy.model.Dataset.file_path = file_path - galaxy.datatypes.metadata.MetadataTempFile.tmp_dir = tmp_dir - - config_root = sys.argv.pop( 1 ) - config_file_name = sys.argv.pop( 1 ) - if not os.path.isabs( config_file_name ): - config_file_name = os.path.join( config_root, config_file_name ) - - # Set up reference to object store - # First, read in the main config file for Galaxy; this is required because - # the object store configuration is stored there - conf_dict = load_app_properties( ini_file=config_file_name ) - # config object is required by ObjectStore class so create it now - universe_config = config.Configuration(**conf_dict) - universe_config.ensure_tempdir() - object_store = build_object_store_from_config(universe_config) - galaxy.model.Dataset.object_store = object_store + # locate galaxy_root for loading datatypes + galaxy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) + tool_job_working_directory = os.path.abspath(os.getcwd()) # Set up datatypes registry datatypes_config = sys.argv.pop( 1 ) datatypes_registry = galaxy.datatypes.registry.Registry() - datatypes_registry.load_datatypes( root_dir=config_root, config=datatypes_config ) + datatypes_registry.load_datatypes( root_dir=galaxy_root, config=datatypes_config ) galaxy.model.set_datatypes_registry( datatypes_registry ) job_metadata = sys.argv.pop( 1 ) @@ -105,8 +93,7 @@ set_meta_kwds = stringify_dictionary_keys( json.load( open( filename_kwds ) ) ) # load kwds; need to ensure our keywords are not unicode try: dataset = cPickle.load( open( filename_in ) ) # load DatasetInstance - if dataset_filename_override: - dataset.dataset.external_filename = dataset_filename_override + dataset.dataset.external_filename = dataset_filename_override files_path = os.path.abspath(os.path.join( tool_job_working_directory, "dataset_%s_files" % (dataset.dataset.id) )) dataset.dataset.external_extra_files_path = files_path if dataset.dataset.id in existing_job_metadata_dict: @@ -123,6 +110,7 @@ dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta json.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) # setting metadata has succeeded except Exception, e: + raise json.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) # setting metadata has failed somehow for i, ( filename, file_dict ) in enumerate( new_job_metadata_dict.iteritems(), start=1 ): @@ -140,5 +128,3 @@ job_metadata_fh.write( "%s\n" % ( json.dumps( value ) ) ) clear_mappers() - # Shut down any additional threads that might have been created via the ObjectStore - object_store.shutdown() https://bitbucket.org/galaxy/galaxy-central/commits/7c1101715457/ Changeset: 7c1101715457 User: natefoo Date: 2015-03-04 18:44:17+00:00 Summary: Run history export jobs in the same manner as metadata auto-detection (so the absolute path of the web galaxy dir is not part of the command line and can be computed at runtime). Affected #: 2 files diff -r 8fe9a4c12495aab16b64330031c929b47bb7050a -r 7c11017154576a0c9c83fa0526aa0d44d6b291a0 lib/galaxy/tools/imp_exp/__init__.py --- a/lib/galaxy/tools/imp_exp/__init__.py +++ b/lib/galaxy/tools/imp_exp/__init__.py @@ -17,12 +17,15 @@ <tool id="__EXPORT_HISTORY__" name="Export History" version="0.1" tool_type="export_history"><type class="ExportHistoryTool" module="galaxy.tools"/><action module="galaxy.tools.actions.history_imp_exp" class="ExportHistoryToolAction"/> - <command>$__EXPORT_HISTORY_COMMAND_INPUTS_OPTIONS__ $output_file</command> + <command>python $export_history $__EXPORT_HISTORY_COMMAND_INPUTS_OPTIONS__ $output_file</command><inputs><param name="__HISTORY_TO_EXPORT__" type="hidden"/><param name="compress" type="boolean"/><param name="__EXPORT_HISTORY_COMMAND_INPUTS_OPTIONS__" type="hidden"/></inputs> + <configfiles> + <configfile name="export_history">from galaxy.tools.imp_exp.export_history import main; main()</configfile> + </configfiles><outputs><data format="gzip" name="output_file"/></outputs> @@ -530,11 +533,9 @@ options = "" if jeha.compressed: options = "-G" - return "python %s %s %s %s %s" % ( os.path.join( os.path.abspath( os.getcwd() ), - "lib/galaxy/tools/imp_exp/export_history.py" ), - options, history_attrs_filename, - datasets_attrs_filename, - jobs_attrs_filename ) + return "%s %s %s %s" % ( options, history_attrs_filename, + datasets_attrs_filename, + jobs_attrs_filename ) def cleanup_after_job( self, db_session ): """ Remove temporary directory and attribute files generated during setup for this job. """ diff -r 8fe9a4c12495aab16b64330031c929b47bb7050a -r 7c11017154576a0c9c83fa0526aa0d44d6b291a0 lib/galaxy/tools/imp_exp/export_history.py --- a/lib/galaxy/tools/imp_exp/export_history.py +++ b/lib/galaxy/tools/imp_exp/export_history.py @@ -70,7 +70,7 @@ except Exception, e: return 'Error creating history archive: %s' % str( e ), sys.stderr -if __name__ == "__main__": +def main(): # Parse command line. parser = optparse.OptionParser() parser.add_option( '-G', '--gzip', dest='gzip', action="store_true", help='Compress archive using gzip.' ) @@ -81,3 +81,6 @@ # Create archive. status = create_archive( history_attrs, dataset_attrs, job_attrs, out_file, gzip ) print status + +if __name__ == "__main__": + main() https://bitbucket.org/galaxy/galaxy-central/commits/39418cb02f8d/ Changeset: 39418cb02f8d User: jmchilton Date: 2015-03-04 16:09:29+00:00 Summary: API fixes for tools and datatypes. By replacing _future_expose_api_anonymous with _future_expose_api_anonymous_and_sessionless. Affected #: 2 files diff -r 7c11017154576a0c9c83fa0526aa0d44d6b291a0 -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 lib/galaxy/webapps/galaxy/api/datatypes.py --- a/lib/galaxy/webapps/galaxy/api/datatypes.py +++ b/lib/galaxy/webapps/galaxy/api/datatypes.py @@ -2,7 +2,7 @@ API operations allowing clients to determine datatype supported by Galaxy. """ -from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous +from galaxy.web import _future_expose_api_anonymous_and_sessionless as expose_api_anonymous_and_sessionless from galaxy import exceptions from galaxy.web.base.controller import BaseAPIController from galaxy.util import asbool @@ -14,7 +14,7 @@ class DatatypesController( BaseAPIController ): - @expose_api_anonymous + @expose_api_anonymous_and_sessionless def index( self, trans, **kwd ): """ GET /api/datatypes @@ -47,7 +47,7 @@ else: raise - @expose_api_anonymous + @expose_api_anonymous_and_sessionless def mapping( self, trans, **kwd ): ''' GET /api/datatypes/mapping @@ -81,7 +81,7 @@ else: raise - @expose_api_anonymous + @expose_api_anonymous_and_sessionless def sniffers( self, trans, **kwd ): ''' GET /api/datatypes/sniffers @@ -101,7 +101,7 @@ else: raise - @expose_api_anonymous + @expose_api_anonymous_and_sessionless def converters( self, trans, **kwd ): converters = [] for (source_type, targets) in self._datatypes_registry.datatype_converters.iteritems(): diff -r 7c11017154576a0c9c83fa0526aa0d44d6b291a0 -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 lib/galaxy/webapps/galaxy/api/tools.py --- a/lib/galaxy/webapps/galaxy/api/tools.py +++ b/lib/galaxy/webapps/galaxy/api/tools.py @@ -4,6 +4,7 @@ from galaxy import web, util from galaxy import managers from galaxy.web import _future_expose_api_anonymous +from galaxy.web import _future_expose_api_anonymous_and_sessionless from galaxy.web import _future_expose_api from galaxy.web.base.controller import BaseAPIController from galaxy.web.base.controller import UsesVisualizationMixin @@ -59,7 +60,7 @@ trans.response.status = 500 return { 'error': str( exc ) } - @_future_expose_api_anonymous + @_future_expose_api_anonymous_and_sessionless def show( self, trans, id, **kwd ): """ GET /api/tools/{tool_id} @@ -129,7 +130,7 @@ "guid": tool.guid, } - @_future_expose_api_anonymous + @_future_expose_api_anonymous_and_sessionless def citations( self, trans, id, **kwds ): tool = self._get_tool( id, user=trans.user ) rval = [] https://bitbucket.org/galaxy/galaxy-central/commits/5c15a291d6d0/ Changeset: 5c15a291d6d0 User: natefoo Date: 2015-03-04 21:03:06+00:00 Summary: Move set_metadata script from galaxy_utils to galaxy, remove unused imports. Affected #: 6 files diff -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 lib/galaxy/datatypes/metadata.py --- a/lib/galaxy/datatypes/metadata.py +++ b/lib/galaxy/datatypes/metadata.py @@ -772,10 +772,10 @@ #return command required to build fd, fp = tempfile.mkstemp( suffix='.py', dir = tmp_dir, prefix = "set_metadata_" ) metadata_script_file = abspath( fp ) - os.fdopen( fd, 'w' ).write( 'from galaxy_utils.metadata.set_metadata import set_metadata; set_metadata()' ) + os.fdopen( fd, 'w' ).write( 'from galaxy.metadata.set_metadata import set_metadata; set_metadata()' ) return "python %s %s" % ( metadata_script_file, args ) else: - # return args to galaxy_utils.metadata.set_metadata required to build + # return args to galaxy.metadata.set_metadata required to build return args def external_metadata_set_successfully( self, dataset, sa_session ): diff -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 lib/galaxy/datatypes/registry.py --- a/lib/galaxy/datatypes/registry.py +++ b/lib/galaxy/datatypes/registry.py @@ -652,7 +652,7 @@ <param name="__SET_EXTERNAL_METADATA_COMMAND_LINE__" type="hidden" value=""/></inputs><configfiles> - <configfile name="set_metadata">from galaxy_utils.metadata.set_metadata import set_metadata; set_metadata()</configfile> + <configfile name="set_metadata">from galaxy.metadata.set_metadata import set_metadata; set_metadata()</configfile></configfiles></tool> """ diff -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 lib/galaxy/metadata/__init__.py --- /dev/null +++ b/lib/galaxy/metadata/__init__.py @@ -0,0 +1,2 @@ +""" Work with Galaxy metadata +""" diff -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 lib/galaxy/metadata/set_metadata.py --- /dev/null +++ b/lib/galaxy/metadata/set_metadata.py @@ -0,0 +1,126 @@ +""" +Execute an external process to set_meta() on a provided list of pickled datasets. + +This was formerly scripts/set_metadata.py and expects these arguments: + + %prog datatypes_conf.xml job_metadata_file metadata_in,metadata_kwds,metadata_out,metadata_results_code,output_filename_override,metadata_override... + +Galaxy should be importable on sys.path and output_filename_override should be +set to the path of the dataset on which metadata is being set +(output_filename_override could previously be left empty and the path would be +constructed automatically). +""" + +import logging +logging.basicConfig() +log = logging.getLogger( __name__ ) + +import cPickle +import json +import os +import sys + +# ensure supported version +assert sys.version_info[:2] >= ( 2, 6 ) and sys.version_info[:2] <= ( 2, 7 ), 'Python version must be 2.6 or 2.7, this is: %s' % sys.version + +new_path = [ os.path.join( os.getcwd(), "lib" ) ] +new_path.extend( sys.path[ 1: ] ) # remove scripts/ from the path +sys.path = new_path + +from galaxy import eggs +import pkg_resources +import galaxy.model.mapping # need to load this before we unpickle, in order to setup properties assigned by the mappers +galaxy.model.Job() # this looks REAL stupid, but it is REQUIRED in order for SA to insert parameters into the classes defined by the mappers --> it appears that instantiating ANY mapper'ed class would suffice here +from galaxy.util import stringify_dictionary_keys +from sqlalchemy.orm import clear_mappers + + +def set_meta_with_tool_provided( dataset_instance, file_dict, set_meta_kwds ): + # This method is somewhat odd, in that we set the metadata attributes from tool, + # then call set_meta, then set metadata attributes from tool again. + # This is intentional due to interplay of overwrite kwd, the fact that some metadata + # parameters may rely on the values of others, and that we are accepting the + # values provided by the tool as Truth. + for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): + setattr( dataset_instance.metadata, metadata_name, metadata_value ) + dataset_instance.datatype.set_meta( dataset_instance, **set_meta_kwds ) + for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): + setattr( dataset_instance.metadata, metadata_name, metadata_value ) + +def set_metadata(): + # locate galaxy_root for loading datatypes + galaxy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) + tool_job_working_directory = os.path.abspath(os.getcwd()) + + # Set up datatypes registry + datatypes_config = sys.argv.pop( 1 ) + datatypes_registry = galaxy.datatypes.registry.Registry() + datatypes_registry.load_datatypes( root_dir=galaxy_root, config=datatypes_config ) + galaxy.model.set_datatypes_registry( datatypes_registry ) + + job_metadata = sys.argv.pop( 1 ) + existing_job_metadata_dict = {} + new_job_metadata_dict = {} + if job_metadata != "None" and os.path.exists( job_metadata ): + for line in open( job_metadata, 'r' ): + try: + line = stringify_dictionary_keys( json.loads( line ) ) + if line['type'] == 'dataset': + existing_job_metadata_dict[ line['dataset_id'] ] = line + elif line['type'] == 'new_primary_dataset': + new_job_metadata_dict[ line[ 'filename' ] ] = line + except: + continue + + for filenames in sys.argv[1:]: + fields = filenames.split( ',' ) + filename_in = fields.pop( 0 ) + filename_kwds = fields.pop( 0 ) + filename_out = fields.pop( 0 ) + filename_results_code = fields.pop( 0 ) + dataset_filename_override = fields.pop( 0 ) + # Need to be careful with the way that these parameters are populated from the filename splitting, + # because if a job is running when the server is updated, any existing external metadata command-lines + #will not have info about the newly added override_metadata file + if fields: + override_metadata = fields.pop( 0 ) + else: + override_metadata = None + set_meta_kwds = stringify_dictionary_keys( json.load( open( filename_kwds ) ) ) # load kwds; need to ensure our keywords are not unicode + try: + dataset = cPickle.load( open( filename_in ) ) # load DatasetInstance + dataset.dataset.external_filename = dataset_filename_override + files_path = os.path.abspath(os.path.join( tool_job_working_directory, "dataset_%s_files" % (dataset.dataset.id) )) + dataset.dataset.external_extra_files_path = files_path + if dataset.dataset.id in existing_job_metadata_dict: + dataset.extension = existing_job_metadata_dict[ dataset.dataset.id ].get( 'ext', dataset.extension ) + # Metadata FileParameter types may not be writable on a cluster node, and are therefore temporarily substituted with MetadataTempFiles + if override_metadata: + override_metadata = json.load( open( override_metadata ) ) + for metadata_name, metadata_file_override in override_metadata: + if galaxy.datatypes.metadata.MetadataTempFile.is_JSONified_value( metadata_file_override ): + metadata_file_override = galaxy.datatypes.metadata.MetadataTempFile.from_JSON( metadata_file_override ) + setattr( dataset.metadata, metadata_name, metadata_file_override ) + file_dict = existing_job_metadata_dict.get( dataset.dataset.id, {} ) + set_meta_with_tool_provided( dataset, file_dict, set_meta_kwds ) + dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta + json.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) # setting metadata has succeeded + except Exception, e: + raise + json.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) # setting metadata has failed somehow + + for i, ( filename, file_dict ) in enumerate( new_job_metadata_dict.iteritems(), start=1 ): + new_dataset = galaxy.model.Dataset( id=-i, external_filename=os.path.join( tool_job_working_directory, file_dict[ 'filename' ] ) ) + extra_files = file_dict.get( 'extra_files', None ) + if extra_files is not None: + new_dataset._extra_files_path = os.path.join( tool_job_working_directory, extra_files ) + new_dataset.state = new_dataset.states.OK + new_dataset_instance = galaxy.model.HistoryDatasetAssociation( id=-i, dataset=new_dataset, extension=file_dict.get( 'ext', 'data' ) ) + set_meta_with_tool_provided( new_dataset_instance, file_dict, set_meta_kwds ) + file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) #storing metadata in external form, need to turn back into dict, then later jsonify + if existing_job_metadata_dict or new_job_metadata_dict: + with open( job_metadata, 'wb' ) as job_metadata_fh: + for value in existing_job_metadata_dict.values() + new_job_metadata_dict.values(): + job_metadata_fh.write( "%s\n" % ( json.dumps( value ) ) ) + + clear_mappers() diff -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 lib/galaxy_utils/metadata/__init__.py --- a/lib/galaxy_utils/metadata/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -""" Work with Galaxy metadata -""" diff -r 39418cb02f8dff8d6c62d00504cd254dc7c4c885 -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 lib/galaxy_utils/metadata/set_metadata.py --- a/lib/galaxy_utils/metadata/set_metadata.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -Execute an external process to set_meta() on a provided list of pickled datasets. - -This was formerly scripts/set_metadata.py and expects these arguments: - - %prog datatypes_conf.xml job_metadata_file metadata_in,metadata_kwds,metadata_out,metadata_results_code,output_filename_override,metadata_override... - -Galaxy should be importable on sys.path and output_filename_override should be -set to the path of the dataset on which metadata is being set -(output_filename_override could previously be left empty and the path would be -constructed automatically). -""" - -import logging -logging.basicConfig() -log = logging.getLogger( __name__ ) - -import cPickle -import json -import os -import sys - -# ensure supported version -assert sys.version_info[:2] >= ( 2, 6 ) and sys.version_info[:2] <= ( 2, 7 ), 'Python version must be 2.6 or 2.7, this is: %s' % sys.version - -new_path = [ os.path.join( os.getcwd(), "lib" ) ] -new_path.extend( sys.path[ 1: ] ) # remove scripts/ from the path -sys.path = new_path - -from galaxy import eggs -import pkg_resources -import galaxy.model.mapping # need to load this before we unpickle, in order to setup properties assigned by the mappers -galaxy.model.Job() # this looks REAL stupid, but it is REQUIRED in order for SA to insert parameters into the classes defined by the mappers --> it appears that instantiating ANY mapper'ed class would suffice here -from galaxy.util import stringify_dictionary_keys -from sqlalchemy.orm import clear_mappers -from galaxy.objectstore import build_object_store_from_config -from galaxy import config -import ConfigParser -from galaxy.util.properties import load_app_properties - - -def set_meta_with_tool_provided( dataset_instance, file_dict, set_meta_kwds ): - # This method is somewhat odd, in that we set the metadata attributes from tool, - # then call set_meta, then set metadata attributes from tool again. - # This is intentional due to interplay of overwrite kwd, the fact that some metadata - # parameters may rely on the values of others, and that we are accepting the - # values provided by the tool as Truth. - for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): - setattr( dataset_instance.metadata, metadata_name, metadata_value ) - dataset_instance.datatype.set_meta( dataset_instance, **set_meta_kwds ) - for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): - setattr( dataset_instance.metadata, metadata_name, metadata_value ) - -def set_metadata(): - # locate galaxy_root for loading datatypes - galaxy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) - tool_job_working_directory = os.path.abspath(os.getcwd()) - - # Set up datatypes registry - datatypes_config = sys.argv.pop( 1 ) - datatypes_registry = galaxy.datatypes.registry.Registry() - datatypes_registry.load_datatypes( root_dir=galaxy_root, config=datatypes_config ) - galaxy.model.set_datatypes_registry( datatypes_registry ) - - job_metadata = sys.argv.pop( 1 ) - existing_job_metadata_dict = {} - new_job_metadata_dict = {} - if job_metadata != "None" and os.path.exists( job_metadata ): - for line in open( job_metadata, 'r' ): - try: - line = stringify_dictionary_keys( json.loads( line ) ) - if line['type'] == 'dataset': - existing_job_metadata_dict[ line['dataset_id'] ] = line - elif line['type'] == 'new_primary_dataset': - new_job_metadata_dict[ line[ 'filename' ] ] = line - except: - continue - - for filenames in sys.argv[1:]: - fields = filenames.split( ',' ) - filename_in = fields.pop( 0 ) - filename_kwds = fields.pop( 0 ) - filename_out = fields.pop( 0 ) - filename_results_code = fields.pop( 0 ) - dataset_filename_override = fields.pop( 0 ) - # Need to be careful with the way that these parameters are populated from the filename splitting, - # because if a job is running when the server is updated, any existing external metadata command-lines - #will not have info about the newly added override_metadata file - if fields: - override_metadata = fields.pop( 0 ) - else: - override_metadata = None - set_meta_kwds = stringify_dictionary_keys( json.load( open( filename_kwds ) ) ) # load kwds; need to ensure our keywords are not unicode - try: - dataset = cPickle.load( open( filename_in ) ) # load DatasetInstance - dataset.dataset.external_filename = dataset_filename_override - files_path = os.path.abspath(os.path.join( tool_job_working_directory, "dataset_%s_files" % (dataset.dataset.id) )) - dataset.dataset.external_extra_files_path = files_path - if dataset.dataset.id in existing_job_metadata_dict: - dataset.extension = existing_job_metadata_dict[ dataset.dataset.id ].get( 'ext', dataset.extension ) - # Metadata FileParameter types may not be writable on a cluster node, and are therefore temporarily substituted with MetadataTempFiles - if override_metadata: - override_metadata = json.load( open( override_metadata ) ) - for metadata_name, metadata_file_override in override_metadata: - if galaxy.datatypes.metadata.MetadataTempFile.is_JSONified_value( metadata_file_override ): - metadata_file_override = galaxy.datatypes.metadata.MetadataTempFile.from_JSON( metadata_file_override ) - setattr( dataset.metadata, metadata_name, metadata_file_override ) - file_dict = existing_job_metadata_dict.get( dataset.dataset.id, {} ) - set_meta_with_tool_provided( dataset, file_dict, set_meta_kwds ) - dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta - json.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) # setting metadata has succeeded - except Exception, e: - raise - json.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) # setting metadata has failed somehow - - for i, ( filename, file_dict ) in enumerate( new_job_metadata_dict.iteritems(), start=1 ): - new_dataset = galaxy.model.Dataset( id=-i, external_filename=os.path.join( tool_job_working_directory, file_dict[ 'filename' ] ) ) - extra_files = file_dict.get( 'extra_files', None ) - if extra_files is not None: - new_dataset._extra_files_path = os.path.join( tool_job_working_directory, extra_files ) - new_dataset.state = new_dataset.states.OK - new_dataset_instance = galaxy.model.HistoryDatasetAssociation( id=-i, dataset=new_dataset, extension=file_dict.get( 'ext', 'data' ) ) - set_meta_with_tool_provided( new_dataset_instance, file_dict, set_meta_kwds ) - file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) #storing metadata in external form, need to turn back into dict, then later jsonify - if existing_job_metadata_dict or new_job_metadata_dict: - with open( job_metadata, 'wb' ) as job_metadata_fh: - for value in existing_job_metadata_dict.values() + new_job_metadata_dict.values(): - job_metadata_fh.write( "%s\n" % ( json.dumps( value ) ) ) - - clear_mappers() https://bitbucket.org/galaxy/galaxy-central/commits/1ba191e7158e/ Changeset: 1ba191e7158e User: natefoo Date: 2015-03-04 21:05:24+00:00 Summary: Restore old set_metadata files to prevent failure of jobs running at upgrade time. Affected #: 2 files diff -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 -r 1ba191e7158e7649e9e91f6422d10667c273feea scripts/set_metadata.py --- /dev/null +++ b/scripts/set_metadata.py @@ -0,0 +1,149 @@ +""" +Execute an external process to set_meta() on a provided list of pickled datasets. + +This should not be called directly! Use the set_metadata.sh script in Galaxy's +top level directly. + +""" + +import logging +logging.basicConfig() +log = logging.getLogger( __name__ ) + +import cPickle +import json +import os +import sys + +# ensure supported version +from check_python import check_python +try: + check_python() +except: + sys.exit(1) + +new_path = [ os.path.join( os.getcwd(), "lib" ) ] +new_path.extend( sys.path[ 1: ] ) # remove scripts/ from the path +sys.path = new_path + +from galaxy import eggs +import pkg_resources +import galaxy.model.mapping # need to load this before we unpickle, in order to setup properties assigned by the mappers +galaxy.model.Job() # this looks REAL stupid, but it is REQUIRED in order for SA to insert parameters into the classes defined by the mappers --> it appears that instantiating ANY mapper'ed class would suffice here +from galaxy.util import stringify_dictionary_keys +from sqlalchemy.orm import clear_mappers +from galaxy.objectstore import build_object_store_from_config +from galaxy import config +import ConfigParser +from galaxy.util.properties import load_app_properties + + +def set_meta_with_tool_provided( dataset_instance, file_dict, set_meta_kwds ): + # This method is somewhat odd, in that we set the metadata attributes from tool, + # then call set_meta, then set metadata attributes from tool again. + # This is intentional due to interplay of overwrite kwd, the fact that some metadata + # parameters may rely on the values of others, and that we are accepting the + # values provided by the tool as Truth. + for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): + setattr( dataset_instance.metadata, metadata_name, metadata_value ) + dataset_instance.datatype.set_meta( dataset_instance, **set_meta_kwds ) + for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): + setattr( dataset_instance.metadata, metadata_name, metadata_value ) + +def __main__(): + file_path = sys.argv.pop( 1 ) + tool_job_working_directory = tmp_dir = sys.argv.pop( 1 ) #this is also the job_working_directory now + galaxy.model.Dataset.file_path = file_path + galaxy.datatypes.metadata.MetadataTempFile.tmp_dir = tmp_dir + + config_root = sys.argv.pop( 1 ) + config_file_name = sys.argv.pop( 1 ) + if not os.path.isabs( config_file_name ): + config_file_name = os.path.join( config_root, config_file_name ) + + # Set up reference to object store + # First, read in the main config file for Galaxy; this is required because + # the object store configuration is stored there + conf_dict = load_app_properties( ini_file=config_file_name ) + # config object is required by ObjectStore class so create it now + universe_config = config.Configuration(**conf_dict) + universe_config.ensure_tempdir() + object_store = build_object_store_from_config(universe_config) + galaxy.model.Dataset.object_store = object_store + + # Set up datatypes registry + datatypes_config = sys.argv.pop( 1 ) + datatypes_registry = galaxy.datatypes.registry.Registry() + datatypes_registry.load_datatypes( root_dir=config_root, config=datatypes_config ) + galaxy.model.set_datatypes_registry( datatypes_registry ) + + job_metadata = sys.argv.pop( 1 ) + existing_job_metadata_dict = {} + new_job_metadata_dict = {} + if job_metadata != "None" and os.path.exists( job_metadata ): + for line in open( job_metadata, 'r' ): + try: + line = stringify_dictionary_keys( json.loads( line ) ) + if line['type'] == 'dataset': + existing_job_metadata_dict[ line['dataset_id'] ] = line + elif line['type'] == 'new_primary_dataset': + new_job_metadata_dict[ line[ 'filename' ] ] = line + except: + continue + + for filenames in sys.argv[1:]: + fields = filenames.split( ',' ) + filename_in = fields.pop( 0 ) + filename_kwds = fields.pop( 0 ) + filename_out = fields.pop( 0 ) + filename_results_code = fields.pop( 0 ) + dataset_filename_override = fields.pop( 0 ) + # Need to be careful with the way that these parameters are populated from the filename splitting, + # because if a job is running when the server is updated, any existing external metadata command-lines + #will not have info about the newly added override_metadata file + if fields: + override_metadata = fields.pop( 0 ) + else: + override_metadata = None + set_meta_kwds = stringify_dictionary_keys( json.load( open( filename_kwds ) ) ) # load kwds; need to ensure our keywords are not unicode + try: + dataset = cPickle.load( open( filename_in ) ) # load DatasetInstance + if dataset_filename_override: + dataset.dataset.external_filename = dataset_filename_override + files_path = os.path.abspath(os.path.join( tool_job_working_directory, "dataset_%s_files" % (dataset.dataset.id) )) + dataset.dataset.external_extra_files_path = files_path + if dataset.dataset.id in existing_job_metadata_dict: + dataset.extension = existing_job_metadata_dict[ dataset.dataset.id ].get( 'ext', dataset.extension ) + # Metadata FileParameter types may not be writable on a cluster node, and are therefore temporarily substituted with MetadataTempFiles + if override_metadata: + override_metadata = json.load( open( override_metadata ) ) + for metadata_name, metadata_file_override in override_metadata: + if galaxy.datatypes.metadata.MetadataTempFile.is_JSONified_value( metadata_file_override ): + metadata_file_override = galaxy.datatypes.metadata.MetadataTempFile.from_JSON( metadata_file_override ) + setattr( dataset.metadata, metadata_name, metadata_file_override ) + file_dict = existing_job_metadata_dict.get( dataset.dataset.id, {} ) + set_meta_with_tool_provided( dataset, file_dict, set_meta_kwds ) + dataset.metadata.to_JSON_dict( filename_out ) # write out results of set_meta + json.dump( ( True, 'Metadata has been set successfully' ), open( filename_results_code, 'wb+' ) ) # setting metadata has succeeded + except Exception, e: + json.dump( ( False, str( e ) ), open( filename_results_code, 'wb+' ) ) # setting metadata has failed somehow + + for i, ( filename, file_dict ) in enumerate( new_job_metadata_dict.iteritems(), start=1 ): + new_dataset = galaxy.model.Dataset( id=-i, external_filename=os.path.join( tool_job_working_directory, file_dict[ 'filename' ] ) ) + extra_files = file_dict.get( 'extra_files', None ) + if extra_files is not None: + new_dataset._extra_files_path = os.path.join( tool_job_working_directory, extra_files ) + new_dataset.state = new_dataset.states.OK + new_dataset_instance = galaxy.model.HistoryDatasetAssociation( id=-i, dataset=new_dataset, extension=file_dict.get( 'ext', 'data' ) ) + set_meta_with_tool_provided( new_dataset_instance, file_dict, set_meta_kwds ) + file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) #storing metadata in external form, need to turn back into dict, then later jsonify + if existing_job_metadata_dict or new_job_metadata_dict: + with open( job_metadata, 'wb' ) as job_metadata_fh: + for value in existing_job_metadata_dict.values() + new_job_metadata_dict.values(): + job_metadata_fh.write( "%s\n" % ( json.dumps( value ) ) ) + + clear_mappers() + # Shut down any additional threads that might have been created via the ObjectStore + object_store.shutdown() + +__main__() diff -r 5c15a291d6d0f28746658a34441fa7cea509ccb9 -r 1ba191e7158e7649e9e91f6422d10667c273feea set_metadata.sh --- /dev/null +++ b/set_metadata.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +cd `dirname $0` +python ./scripts/set_metadata.py $@ https://bitbucket.org/galaxy/galaxy-central/commits/b3a236230733/ Changeset: b3a236230733 User: dannon Date: 2015-03-04 23:04:00+00:00 Summary: Python 2.6 has a bug in deepcopy that causes an error when attempting to copy datasets between users (which uses deepcopy). Py2.7 worked fine. Now they both should. Affected #: 1 file diff -r 1ba191e7158e7649e9e91f6422d10667c273feea -r b3a236230733354107c1cdf848f74670f24c98d2 lib/galaxy/model/custom_types.py --- a/lib/galaxy/model/custom_types.py +++ b/lib/galaxy/model/custom_types.py @@ -182,6 +182,12 @@ list.__delslice__(self, start, stop) self.changed() + def __copy__(self): + return MutationList(MutationObj.coerce(self._key, self[:])) + + def __deepcopy__(self, memo): + return MutationList(MutationObj.coerce(self._key, copy.deepcopy(self[:]))) + def append(self, value): list.append(self, MutationObj.coerce(self._key, value)) self.changed() https://bitbucket.org/galaxy/galaxy-central/commits/521695e2903a/ Changeset: 521695e2903a User: dannon Date: 2015-03-05 14:47:14+00:00 Summary: Cleanup related to PR#7 and affected files. Affected #: 7 files diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd lib/galaxy/datatypes/metadata.py --- a/lib/galaxy/datatypes/metadata.py +++ b/lib/galaxy/datatypes/metadata.py @@ -30,7 +30,8 @@ import logging log = logging.getLogger(__name__) -STATEMENTS = "__galaxy_statements__" #this is the name of the property in a Datatype class where new metadata spec element Statements are stored +STATEMENTS = "__galaxy_statements__" # this is the name of the property in a Datatype class where new metadata spec element Statements are stored + class Statement( object ): """ @@ -43,14 +44,17 @@ self.target = target def __call__( self, *args, **kwargs ): - class_locals = sys._getframe( 1 ).f_locals #get the locals dictionary of the frame object one down in the call stack (i.e. the Datatype class calling MetadataElement) - statements = class_locals.setdefault( STATEMENTS, [] ) #get and set '__galaxy_statments__' to an empty list if not in locals dict - statements.append( ( self, args, kwargs ) ) #add Statement containing info to populate a MetadataElementSpec + # get the locals dictionary of the frame object one down in the call stack (i.e. the Datatype class calling MetadataElement) + class_locals = sys._getframe( 1 ).f_locals + # get and set '__galaxy_statments__' to an empty list if not in locals dict + statements = class_locals.setdefault( STATEMENTS, [] ) + # add Statement containing info to populate a MetadataElementSpec + statements.append( ( self, args, kwargs ) ) @classmethod def process( cls, element ): for statement, args, kwargs in getattr( element, STATEMENTS, [] ): - statement.target( element, *args, **kwargs ) #statement.target is MetadataElementSpec, element is a Datatype class + statement.target( element, *args, **kwargs ) # statement.target is MetadataElementSpec, element is a Datatype class class MetadataCollection( object ): @@ -62,7 +66,7 @@ """ def __init__(self, parent ): self.parent = parent - #initialize dict if needed + # initialize dict if needed if self.parent._metadata is None: self.parent._metadata = {} @@ -72,7 +76,10 @@ return None def set_parent( self, parent ): - self.__dict__["_parent"] = weakref.ref( parent ) # use weakref to prevent a circular reference interfering with garbage collection: hda/lda (parent) <--> MetadataCollection (self) ; needs to be hashable, so cannot use proxy. + # use weakref to prevent a circular reference interfering with garbage + # collection: hda/lda (parent) <--> MetadataCollection (self) ; needs to be + # hashable, so cannot use proxy. + self.__dict__["_parent"] = weakref.ref( parent ) parent = property( get_parent, set_parent ) @property @@ -144,7 +151,7 @@ elif isinstance( json_dict, dict ): JSONified_dict = json_dict else: - raise ValueError( "json_dict must be either a dictionary or a string, got %s." % ( type( json_dict ) ) ) + raise ValueError( "json_dict must be either a dictionary or a string, got %s." % ( type( json_dict ) ) ) else: raise ValueError( "You must provide either a filename or a json_dict" ) for name, spec in self.spec.items(): @@ -156,12 +163,12 @@ from_ext_kwds[ 'path_rewriter' ] = path_rewriter dataset._metadata[ name ] = param.from_external_value( external_value, dataset, **from_ext_kwds ) elif name in dataset._metadata: - #if the metadata value is not found in our externally set metadata but it has a value in the 'old' - #metadata associated with our dataset, we'll delete it from our dataset's metadata dict + # if the metadata value is not found in our externally set metadata but it has a value in the 'old' + # metadata associated with our dataset, we'll delete it from our dataset's metadata dict del dataset._metadata[ name ] def to_JSON_dict( self, filename=None ): - #galaxy.model.customtypes.json_encoder.encode() + # galaxy.model.customtypes.json_encoder.encode() meta_dict = {} dataset_meta_dict = self.parent._metadata for name, spec in self.spec.items(): @@ -172,7 +179,9 @@ json.dump( meta_dict, open( filename, 'wb+' ) ) def __getstate__( self ): - return None #cannot pickle a weakref item (self._parent), when data._metadata_collection is None, it will be recreated on demand + # cannot pickle a weakref item (self._parent), when + # data._metadata_collection is None, it will be recreated on demand + return None class MetadataSpecCollection( odict ): @@ -182,8 +191,8 @@ list. append() is also implemented for simplicity and does not "append". """ - def __init__( self, dict = None ): - odict.__init__( self, dict = None ) + def __init__( self, dict=None ): + odict.__init__( self, dict=None ) def append( self, item ): self[item.name] = item @@ -224,7 +233,8 @@ return value if self.spec.get("optional"): checked = False - if value: checked = "true" + if value: + checked = "true" checkbox = form_builder.CheckboxField( "is_" + self.spec.name, checked=checked ) return checkbox.get_html() + self.get_html_field( value=value, context=context, other_values=other_values, **kwd ).get_html() else: @@ -236,11 +246,11 @@ def to_safe_string( self, value ): return sanitize_lists_to_string( self.to_string( value ) ) - def make_copy( self, value, target_context = None, source_context = None ): + def make_copy( self, value, target_context=None, source_context=None ): return copy.deepcopy( value ) @classmethod - def marshal ( cls, value ): + def marshal( cls, value ): """ This method should/can be overridden to convert the incoming value to whatever type it is supposed to be. @@ -285,9 +295,9 @@ Defines a metadata element and adds it to the metadata_spec (which is a MetadataSpecCollection) of datatype. """ - def __init__( self, datatype, - name=None, desc=None, param=MetadataParameter, default=None, no_value = None, - visible=True, set_in_upload = False, **kwargs ): + def __init__( self, datatype, name=None, desc=None, + param=MetadataParameter, default=None, no_value=None, + visible=True, set_in_upload=False, **kwargs ): self.name = name self.desc = desc or name self.default = default @@ -317,7 +327,7 @@ return self.param.unwrap( value ) def __str__( self ): - #TODO??: assuming param is the class of this MetadataElementSpec - add the plain class name for that + # TODO??: assuming param is the class of this MetadataElementSpec - add the plain class name for that spec_dict = dict( param_class=self.param.__class__.__name__ ) spec_dict.update( self.__dict__ ) return ( "{name} ({param_class}): {desc}, defaults to '{default}'".format( **spec_dict ) ) @@ -331,6 +341,7 @@ MetadataParameter sub-classes. """ + class SelectParameter( MetadataParameter ): def __init__( self, spec ): MetadataParameter.__init__( self, spec ) @@ -378,18 +389,24 @@ return MetadataParameter.get_html( self, value, context=context, other_values=other_values, values=values, **kwd ) def wrap( self, value, session ): - value = self.marshal( value ) #do we really need this (wasteful)? - yes because we are not sure that all existing selects have been stored previously as lists. Also this will handle the case where defaults/no_values are specified and are single non-list values. + # do we really need this (wasteful)? - yes because we are not sure that + # all existing selects have been stored previously as lists. Also this + # will handle the case where defaults/no_values are specified and are + # single non-list values. + value = self.marshal( value ) if self.multiple: return value elif value: - return value[0] #single select, only return the first value + return value[0] # single select, only return the first value return None @classmethod def marshal( cls, value ): # Store select as list, even if single item - if value is None: return [] - if not isinstance( value, list ): return [value] + if value is None: + return [] + if not isinstance( value, list ): + return [value] return value @@ -482,7 +499,7 @@ class DictParameter( MetadataParameter ): def to_string( self, value ): - return json.dumps( value ) + return json.dumps( value ) def to_safe_string( self, value ): # We do not sanitize json dicts @@ -543,7 +560,7 @@ def make_copy( self, value, target_context, source_context ): value = self.wrap( value, object_session( target_context.parent ) ) if value: - new_value = galaxy.model.MetadataFile( dataset = target_context.parent, name = self.spec.name ) + new_value = galaxy.model.MetadataFile( dataset=target_context.parent, name=self.spec.name ) object_session( target_context.parent ).add( new_value ) object_session( target_context.parent ).flush() shutil.copy( value.file_name, new_value.file_name ) @@ -565,14 +582,18 @@ if isinstance( value, MetadataTempFile ): mf = parent.metadata.get( self.spec.name, None) if mf is None: - mf = self.new_file( dataset = parent, **value.kwds ) + mf = self.new_file( dataset=parent, **value.kwds ) # Ensure the metadata file gets updated with content file_name = value.file_name if path_rewriter: # Job may have run with a different (non-local) tmp/working # directory. Correct. file_name = path_rewriter( file_name ) - parent.dataset.object_store.update_from_file( mf, file_name=file_name, extra_dir='_metadata_files', extra_dir_at_root=True, alt_name=os.path.basename(mf.file_name) ) + parent.dataset.object_store.update_from_file( mf, + file_name=file_name, + extra_dir='_metadata_files', + extra_dir_at_root=True, + alt_name=os.path.basename(mf.file_name) ) os.unlink( file_name ) value = mf.id return value @@ -587,22 +608,22 @@ value = MetadataTempFile.to_JSON( value ) return value - def new_file( self, dataset = None, **kwds ): + def new_file( self, dataset=None, **kwds ): if object_session( dataset ): - mf = galaxy.model.MetadataFile( name = self.spec.name, dataset = dataset, **kwds ) + mf = galaxy.model.MetadataFile( name=self.spec.name, dataset=dataset, **kwds ) object_session( dataset ).add( mf ) - object_session( dataset ).flush() #flush to assign id + object_session( dataset ).flush() # flush to assign id return mf else: - #we need to make a tmp file that is accessable to the head node, - #we will be copying its contents into the MetadataFile objects filename after restoring from JSON - #we do not include 'dataset' in the kwds passed, as from_JSON_value() will handle this for us + # we need to make a tmp file that is accessable to the head node, + # we will be copying its contents into the MetadataFile objects filename after restoring from JSON + # we do not include 'dataset' in the kwds passed, as from_JSON_value() will handle this for us return MetadataTempFile( **kwds ) -#This class is used when a database file connection is not available +# This class is used when a database file connection is not available class MetadataTempFile( object ): - tmp_dir = 'database/tmp' #this should be overwritten as necessary in calling scripts + tmp_dir = 'database/tmp' # this should be overwritten as necessary in calling scripts def __init__( self, **kwds ): self.kwds = kwds @@ -611,17 +632,19 @@ @property def file_name( self ): if self._filename is None: - #we need to create a tmp file, accessable across all nodes/heads, save the name, and return it - self._filename = abspath( tempfile.NamedTemporaryFile( dir = self.tmp_dir, prefix = "metadata_temp_file_" ).name ) - open( self._filename, 'wb+' ) #create an empty file, so it can't be reused using tempfile + # we need to create a tmp file, accessable across all nodes/heads, save the name, and return it + self._filename = abspath( tempfile.NamedTemporaryFile( dir=self.tmp_dir, prefix="metadata_temp_file_" ).name ) + open( self._filename, 'wb+' ) # create an empty file, so it can't be reused using tempfile return self._filename def to_JSON( self ): - return { '__class__':self.__class__.__name__, 'filename':self.file_name, 'kwds':self.kwds } + return { '__class__': self.__class__.__name__, + 'filename': self.file_name, + 'kwds': self.kwds } @classmethod def from_JSON( cls, json_dict ): - #need to ensure our keywords are not unicode + # need to ensure our keywords are not unicode rval = cls( **stringify_dictionary_keys( json_dict['kwds'] ) ) rval._filename = json_dict['filename'] return rval @@ -643,10 +666,16 @@ log.debug( 'Failed to cleanup MetadataTempFile temp files from %s: %s' % ( filename, e ) ) -#Class with methods allowing set_meta() to be called externally to the Galaxy head class JobExternalOutputMetadataWrapper( object ): - #this class allows access to external metadata filenames for all outputs associated with a job - #We will use JSON as the medium of exchange of information, except for the DatasetInstance object which will use pickle (in the future this could be JSONified as well) + """ + Class with methods allowing set_meta() to be called externally to the + Galaxy head. + This class allows access to external metadata filenames for all outputs + associated with a job. + We will use JSON as the medium of exchange of information, except for the + DatasetInstance object which will use pickle (in the future this could be + JSONified as well) + """ def __init__( self, job ): self.job_id = job.id @@ -654,12 +683,12 @@ def get_output_filenames_by_dataset( self, dataset, sa_session ): if isinstance( dataset, galaxy.model.HistoryDatasetAssociation ): return sa_session.query( galaxy.model.JobExternalOutputMetadata ) \ - .filter_by( job_id = self.job_id, history_dataset_association_id = dataset.id ) \ - .first() #there should only be one or None + .filter_by( job_id=self.job_id, history_dataset_association_id=dataset.id ) \ + .first() # there should only be one or None elif isinstance( dataset, galaxy.model.LibraryDatasetDatasetAssociation ): return sa_session.query( galaxy.model.JobExternalOutputMetadata ) \ - .filter_by( job_id = self.job_id, library_dataset_dataset_association_id = dataset.id ) \ - .first() #there should only be one or None + .filter_by( job_id=self.job_id, library_dataset_dataset_association_id=dataset.id ) \ + .first() # there should only be one or None return None def get_dataset_metadata_key( self, dataset ): @@ -686,7 +715,7 @@ compute_path = os.path.join(compute_tmp_dir, path_relative) return compute_path - #fill in metadata_files_dict and return the command with args required to set metadata + # fill in metadata_files_dict and return the command with args required to set metadata def __metadata_files_list_to_cmd_line( metadata_files ): def __get_filename_override(): if output_fnames: @@ -717,43 +746,44 @@ metadata_files_list = [] for dataset in datasets: key = self.get_dataset_metadata_key( dataset ) - #future note: - #wonkiness in job execution causes build command line to be called more than once - #when setting metadata externally, via 'auto-detect' button in edit attributes, etc., - #we don't want to overwrite (losing the ability to cleanup) our existing dataset keys and files, - #so we will only populate the dictionary once + # future note: + # wonkiness in job execution causes build command line to be called more than once + # when setting metadata externally, via 'auto-detect' button in edit attributes, etc., + # we don't want to overwrite (losing the ability to cleanup) our existing dataset keys and files, + # so we will only populate the dictionary once metadata_files = self.get_output_filenames_by_dataset( dataset, sa_session ) if not metadata_files: - metadata_files = galaxy.model.JobExternalOutputMetadata( dataset = dataset) + metadata_files = galaxy.model.JobExternalOutputMetadata( dataset=dataset) metadata_files.job_id = self.job_id - #we are using tempfile to create unique filenames, tempfile always returns an absolute path - #we will use pathnames relative to the galaxy root, to accommodate instances where the galaxy root - #is located differently, i.e. on a cluster node with a different filesystem structure + # we are using tempfile to create unique filenames, tempfile always returns an absolute path + # we will use pathnames relative to the galaxy root, to accommodate instances where the galaxy root + # is located differently, i.e. on a cluster node with a different filesystem structure - #file to store existing dataset - metadata_files.filename_in = abspath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_in_%s_" % key ).name ) + # file to store existing dataset + metadata_files.filename_in = abspath( tempfile.NamedTemporaryFile( dir=tmp_dir, prefix="metadata_in_%s_" % key ).name ) - #FIXME: HACK - #sqlalchemy introduced 'expire_on_commit' flag for sessionmaker at version 0.5x - #This may be causing the dataset attribute of the dataset_association object to no-longer be loaded into memory when needed for pickling. - #For now, we'll simply 'touch' dataset_association.dataset to force it back into memory. - dataset.dataset #force dataset_association.dataset to be loaded before pickling - #A better fix could be setting 'expire_on_commit=False' on the session, or modifying where commits occur, or ? + # FIXME: HACK + # sqlalchemy introduced 'expire_on_commit' flag for sessionmaker at version 0.5x + # This may be causing the dataset attribute of the dataset_association object to no-longer be loaded into memory when needed for pickling. + # For now, we'll simply 'touch' dataset_association.dataset to force it back into memory. + dataset.dataset # force dataset_association.dataset to be loaded before pickling + # A better fix could be setting 'expire_on_commit=False' on the session, or modifying where commits occur, or ? cPickle.dump( dataset, open( metadata_files.filename_in, 'wb+' ) ) - #file to store metadata results of set_meta() - metadata_files.filename_out = abspath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_out_%s_" % key ).name ) - open( metadata_files.filename_out, 'wb+' ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible) - #file to store a 'return code' indicating the results of the set_meta() call - #results code is like (True/False - if setting metadata was successful/failed , exception or string of reason of success/failure ) - metadata_files.filename_results_code = abspath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_results_%s_" % key ).name ) - json.dump( ( False, 'External set_meta() not called' ), open( metadata_files.filename_results_code, 'wb+' ) ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible) - #file to store kwds passed to set_meta() - metadata_files.filename_kwds = abspath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_kwds_%s_" % key ).name ) + # file to store metadata results of set_meta() + metadata_files.filename_out = abspath( tempfile.NamedTemporaryFile( dir=tmp_dir, prefix="metadata_out_%s_" % key ).name ) + open( metadata_files.filename_out, 'wb+' ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible) + # file to store a 'return code' indicating the results of the set_meta() call + # results code is like (True/False - if setting metadata was successful/failed , exception or string of reason of success/failure ) + metadata_files.filename_results_code = abspath( tempfile.NamedTemporaryFile( dir=tmp_dir, prefix="metadata_results_%s_" % key ).name ) + # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible) + json.dump( ( False, 'External set_meta() not called' ), open( metadata_files.filename_results_code, 'wb+' ) ) + # file to store kwds passed to set_meta() + metadata_files.filename_kwds = abspath( tempfile.NamedTemporaryFile( dir=tmp_dir, prefix="metadata_kwds_%s_" % key ).name ) json.dump( kwds, open( metadata_files.filename_kwds, 'wb+' ), ensure_ascii=True ) - #existing metadata file parameters need to be overridden with cluster-writable file locations - metadata_files.filename_override_metadata = abspath( tempfile.NamedTemporaryFile( dir = tmp_dir, prefix = "metadata_override_%s_" % key ).name ) - open( metadata_files.filename_override_metadata, 'wb+' ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible) + # existing metadata file parameters need to be overridden with cluster-writable file locations + metadata_files.filename_override_metadata = abspath( tempfile.NamedTemporaryFile( dir=tmp_dir, prefix="metadata_override_%s_" % key ).name ) + open( metadata_files.filename_override_metadata, 'wb+' ) # create the file on disk, so it cannot be reused by tempfile (unlikely, but possible) override_metadata = [] for meta_key, spec_value in dataset.metadata.spec.iteritems(): if isinstance( spec_value.param, FileParameter ) and dataset.metadata.get( meta_key, None ) is not None: @@ -761,7 +791,7 @@ shutil.copy( dataset.metadata.get( meta_key, None ).file_name, metadata_temp.file_name ) override_metadata.append( ( meta_key, metadata_temp.to_JSON() ) ) json.dump( override_metadata, open( metadata_files.filename_override_metadata, 'wb+' ) ) - #add to session and flush + # add to session and flush sa_session.add( metadata_files ) sa_session.flush() metadata_files_list.append( metadata_files ) @@ -769,8 +799,8 @@ job_metadata, " ".join( map( __metadata_files_list_to_cmd_line, metadata_files_list ) ) ) if include_command: - #return command required to build - fd, fp = tempfile.mkstemp( suffix='.py', dir = tmp_dir, prefix = "set_metadata_" ) + # return command required to build + fd, fp = tempfile.mkstemp( suffix='.py', dir=tmp_dir, prefix="set_metadata_" ) metadata_script_file = abspath( fp ) os.fdopen( fd, 'w' ).write( 'from galaxy.metadata.set_metadata import set_metadata; set_metadata()' ) return "python %s %s" % ( metadata_script_file, args ) @@ -781,7 +811,7 @@ def external_metadata_set_successfully( self, dataset, sa_session ): metadata_files = self.get_output_filenames_by_dataset( dataset, sa_session ) if not metadata_files: - return False # this file doesn't exist + return False # this file doesn't exist rval, rstring = json.load( open( metadata_files.filename_results_code ) ) if not rval: log.debug( 'setting metadata externally failed for %s %s: %s' % ( dataset.__class__.__name__, dataset.id, rstring ) ) @@ -790,11 +820,15 @@ def cleanup_external_metadata( self, sa_session ): log.debug( 'Cleaning up external metadata files' ) for metadata_files in sa_session.query( galaxy.model.Job ).get( self.job_id ).external_output_metadata: - #we need to confirm that any MetadataTempFile files were removed, if not we need to remove them - #can occur if the job was stopped before completion, but a MetadataTempFile is used in the set_meta + # we need to confirm that any MetadataTempFile files were removed, if not we need to remove them + # can occur if the job was stopped before completion, but a MetadataTempFile is used in the set_meta MetadataTempFile.cleanup_from_JSON_dict_filename( metadata_files.filename_out ) dataset_key = self.get_dataset_metadata_key( metadata_files.dataset ) - for key, fname in [ ( 'filename_in', metadata_files.filename_in ), ( 'filename_out', metadata_files.filename_out ), ( 'filename_results_code', metadata_files.filename_results_code ), ( 'filename_kwds', metadata_files.filename_kwds ), ( 'filename_override_metadata', metadata_files.filename_override_metadata ) ]: + for key, fname in [ ( 'filename_in', metadata_files.filename_in ), + ( 'filename_out', metadata_files.filename_out ), + ( 'filename_results_code', metadata_files.filename_results_code ), + ( 'filename_kwds', metadata_files.filename_kwds ), + ( 'filename_override_metadata', metadata_files.filename_override_metadata ) ]: try: os.remove( fname ) except Exception, e: diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd lib/galaxy/jobs/__init__.py --- a/lib/galaxy/jobs/__init__.py +++ b/lib/galaxy/jobs/__init__.py @@ -12,7 +12,6 @@ import os import pwd import random -import re import shutil import subprocess import sys @@ -132,7 +131,9 @@ tree = util.parse_xml(job_config_file) self.__parse_job_conf_xml(tree) except IOError: - log.warning( 'Job configuration "%s" does not exist, using legacy job configuration from Galaxy config file "%s" instead' % ( self.app.config.job_config_file, self.app.config.config_file ) ) + log.warning( 'Job configuration "%s" does not exist, using legacy' + ' job configuration from Galaxy config file "%s" instead' + % ( self.app.config.job_config_file, self.app.config.config_file ) ) self.__parse_job_conf_legacy() except Exception as e: raise config_exception(e, job_config_file) @@ -262,7 +263,7 @@ if limits is not None: for limit in self.__findall_with_required(limits, 'limit', ('type',)): type = limit.get('type') - # concurrent_jobs renamed to destination_user_concurrent_jobs in job_conf.xml + # concurrent_jobs renamed to destination_user_concurrent_jobs in job_conf.xml if type in ( 'destination_user_concurrent_jobs', 'concurrent_jobs', 'destination_total_concurrent_jobs' ): id = limit.get('tag', None) or limit.get('id') if type == 'destination_total_concurrent_jobs': @@ -284,7 +285,8 @@ log.debug('Loading job configuration from %s' % self.app.config.config_file) # Always load local and lwr - self.runner_plugins = [dict(id='local', load='local', workers=self.app.config.local_job_queue_workers), dict(id='lwr', load='lwr', workers=self.app.config.cluster_job_queue_workers)] + self.runner_plugins = [dict(id='local', load='local', workers=self.app.config.local_job_queue_workers), + dict(id='lwr', load='lwr', workers=self.app.config.cluster_job_queue_workers)] # Load tasks if configured if self.app.config.use_tasked_jobs: self.runner_plugins.append(dict(id='tasks', load='tasks', workers=self.app.config.local_task_queue_workers)) @@ -326,7 +328,11 @@ runner_config['destination'] = runner_config.pop('url') self.tools[id].append(JobToolConfiguration(**runner_config)) - self.destinations[self.app.config.default_cluster_job_runner] = (JobDestination(id=self.app.config.default_cluster_job_runner, runner=self.app.config.default_cluster_job_runner.split(':', 1)[0], url=self.app.config.default_cluster_job_runner, legacy=True, converted=False),) + self.destinations[self.app.config.default_cluster_job_runner] = (JobDestination(id=self.app.config.default_cluster_job_runner, + runner=self.app.config.default_cluster_job_runner.split(':', 1)[0], + url=self.app.config.default_cluster_job_runner, + legacy=True, + converted=False),) self.default_destination_id = self.app.config.default_cluster_job_runner # Set the job limits @@ -384,12 +390,15 @@ # stripping it off when making it available to dynamic job # destination. Not needed because resource parameters are wrapped # in a conditional. - ## expanded_name = "__job_resource_param__%s" % name - ## parameter_elem.set( "name", expanded_name ) + # # expanded_name = "__job_resource_param__%s" % name + # # parameter_elem.set( "name", expanded_name ) self.resource_parameters[ name ] = parameter_elem def __get_default(self, parent, names): - """Returns the default attribute set in a parent tag like <handlers> or <destinations>, or return the ID of the child, if there is no explicit default and only one child. + """ + Returns the default attribute set in a parent tag like <handlers> or + <destinations>, or return the ID of the child, if there is no explicit + default and only one child. :param parent: Object representing a tag that may or may not have a 'default' attribute. :type parent: ``xml.etree.ElementTree.Element`` @@ -494,7 +503,10 @@ @property def default_job_tool_configuration(self): - """The default JobToolConfiguration, used if a tool does not have an explicit defintion in the configuration. It consists of a reference to the default handler and default destination. + """ + The default JobToolConfiguration, used if a tool does not have an + explicit defintion in the configuration. It consists of a reference to + the default handler and default destination. :returns: JobToolConfiguration -- a representation of a <tool> element that uses the default handler and destination """ @@ -502,7 +514,10 @@ # Called upon instantiation of a Tool object def get_job_tool_configurations(self, ids): - """Get all configured JobToolConfigurations for a tool ID, or, if given a list of IDs, the JobToolConfigurations for the first id in ``ids`` matching a tool definition. + """ + Get all configured JobToolConfigurations for a tool ID, or, if given + a list of IDs, the JobToolConfigurations for the first id in ``ids`` + matching a tool definition. .. note:: @@ -650,7 +665,8 @@ try: rval[id] = runner_class( self.app, runner[ 'workers' ], **runner.get( 'kwds', {} ) ) except TypeError: - log.exception( "Job runner '%s:%s' has not been converted to a new-style runner or encountered TypeError on load" % ( module_name, class_name ) ) + log.exception( "Job runner '%s:%s' has not been converted to a new-style runner or encountered TypeError on load" + % ( module_name, class_name ) ) rval[id] = runner_class( self.app ) log.debug( "Loaded job runner '%s:%s' as '%s'" % ( module_name, class_name, id ) ) return rval @@ -943,12 +959,12 @@ log.info( "stderr for job %d is greater than %s, only a portion will be logged to database" % ( job.id, DATABASE_MAX_STRING_SIZE_PRETTY ) ) job.stderr = stderr # Let the exit code be Null if one is not provided: - if ( exit_code != None ): + if ( exit_code is not None ): job.exit_code = exit_code self.sa_session.add( job ) self.sa_session.flush() - #Perform email action even on failure. + # Perform email action even on failure. for pja in [pjaa.post_job_action for pjaa in job.post_job_actions if pjaa.post_job_action.action_type == "EmailAction"]: ActionBox.execute(self.app, self.sa_session, pja, job) # If the job was deleted, call tool specific fail actions (used for e.g. external metadata) and clean up @@ -1079,7 +1095,8 @@ # finish method - the false_path file has already moved, # and when the job is recovered, it won't be found. if os.path.exists( dataset_path.real_path ) and os.stat( dataset_path.real_path ).st_size > 0: - log.warning( "finish(): %s not found, but %s is not empty, so it will be used instead" % ( dataset_path.false_path, dataset_path.real_path ) ) + log.warning( "finish(): %s not found, but %s is not empty, so it will be used instead" + % ( dataset_path.false_path, dataset_path.real_path ) ) else: # Prior to fail we need to set job.state job.set_state( final_job_state ) @@ -1088,8 +1105,10 @@ job_context = ExpressionContext( dict( stdout=job.stdout, stderr=job.stderr ) ) for dataset_assoc in job.output_datasets + job.output_library_datasets: context = self.get_dataset_finish_context( job_context, dataset_assoc.dataset.dataset ) - #should this also be checking library associations? - can a library item be added from a history before the job has ended? - lets not allow this to occur - for dataset in dataset_assoc.dataset.dataset.history_associations + dataset_assoc.dataset.dataset.library_associations: # need to update all associated output hdas, i.e. history was shared with job running + # should this also be checking library associations? - can a library item be added from a history before the job has ended? - + # lets not allow this to occur + # need to update all associated output hdas, i.e. history was shared with job running + for dataset in dataset_assoc.dataset.dataset.history_associations + dataset_assoc.dataset.dataset.library_associations: trynum = 0 while trynum < self.app.config.retry_job_output_collection: try: @@ -1107,10 +1126,10 @@ dataset.peek = 'no peek' dataset.info = (dataset.info or '') if context['stdout'].strip(): - #Ensure white space between entries + # Ensure white space between entries dataset.info = dataset.info.rstrip() + "\n" + context['stdout'].strip() if context['stderr'].strip(): - #Ensure white space between entries + # Ensure white space between entries dataset.info = dataset.info.rstrip() + "\n" + context['stderr'].strip() dataset.tool_version = self.version_string dataset.set_size() @@ -1127,20 +1146,23 @@ if dataset.ext == 'auto': dataset.extension = context.get( 'ext', 'data' ) dataset.init_meta( copy_from=dataset ) - #if a dataset was copied, it won't appear in our dictionary: - #either use the metadata from originating output dataset, or call set_meta on the copies - #it would be quicker to just copy the metadata from the originating output dataset, - #but somewhat trickier (need to recurse up the copied_from tree), for now we'll call set_meta() - if ( not self.external_output_metadata.external_metadata_set_successfully( dataset, self.sa_session ) and self.app.config.retry_metadata_internally ): - dataset.datatype.set_meta( dataset, overwrite=False ) # call datatype.set_meta directly for the initial set_meta call during dataset creation - elif not self.external_output_metadata.external_metadata_set_successfully( dataset, self.sa_session ) and job.states.ERROR != final_job_state: + # if a dataset was copied, it won't appear in our dictionary: + # either use the metadata from originating output dataset, or call set_meta on the copies + # it would be quicker to just copy the metadata from the originating output dataset, + # but somewhat trickier (need to recurse up the copied_from tree), for now we'll call set_meta() + if ( not self.external_output_metadata.external_metadata_set_successfully( dataset, self.sa_session ) + and self.app.config.retry_metadata_internally ): + # call datatype.set_meta directly for the initial set_meta call during dataset creation + dataset.datatype.set_meta( dataset, overwrite=False ) + elif ( not self.external_output_metadata.external_metadata_set_successfully( dataset, self.sa_session ) + and job.states.ERROR != final_job_state ): dataset._state = model.Dataset.states.FAILED_METADATA else: - #load metadata from file - #we need to no longer allow metadata to be edited while the job is still running, - #since if it is edited, the metadata changed on the running output will no longer match - #the metadata that was stored to disk for use via the external process, - #and the changes made by the user will be lost, without warning or notice + # load metadata from file + # we need to no longer allow metadata to be edited while the job is still running, + # since if it is edited, the metadata changed on the running output will no longer match + # the metadata that was stored to disk for use via the external process, + # and the changes made by the user will be lost, without warning or notice output_filename = self.external_output_metadata.get_output_filenames_by_dataset( dataset, self.sa_session ).filename_out def path_rewriter( path ): @@ -1224,8 +1246,10 @@ if not data: continue input_ext = data.ext - - param_dict = dict( [ ( p.name, p.value ) for p in job.parameters ] ) # why not re-use self.param_dict here? ##dunno...probably should, this causes tools.parameters.basic.UnvalidatedValue to be used in following methods instead of validated and transformed values during i.e. running workflows + # why not re-use self.param_dict here? ##dunno...probably should, this causes + # tools.parameters.basic.UnvalidatedValue to be used in following methods + # instead of validated and transformed values during i.e. running workflows + param_dict = dict( [ ( p.name, p.value ) for p in job.parameters ] ) param_dict = self.tool.params_from_strings( param_dict, self.app ) # Check for and move associated_files self.tool.collect_associated_files(out_data, self.working_directory) @@ -1318,11 +1342,15 @@ for outfile, size in self.get_output_sizes(): if size > self.app.job_config.limits.output_size: log.warning( '(%s) Job output size %s has exceeded the global output size limit', self.get_id_tag(), os.path.basename( outfile ) ) - return JobState.runner_states.OUTPUT_SIZE_LIMIT, 'Job output file grew too large (greater than %s), please try different inputs or parameters' % util.nice_size( self.app.job_config.limits.output_size ) + return ( JobState.runner_states.OUTPUT_SIZE_LIMIT, + 'Job output file grew too large (greater than %s), please try different inputs or parameters' + % util.nice_size( self.app.job_config.limits.output_size ) ) if self.app.job_config.limits.walltime_delta is not None and runtime is not None: if runtime > self.app.job_config.limits.walltime_delta: log.warning( '(%s) Job runtime %s has exceeded the global walltime, it will be terminated', self.get_id_tag(), runtime ) - return JobState.runner_states.GLOBAL_WALLTIME_REACHED, 'Job ran longer than the maximum allowed execution time (runtime: %s, limit: %s), please try different inputs or parameters' % ( str(runtime).split('.')[0], self.app.job_config.limits.walltime ) + return ( JobState.runner_states.GLOBAL_WALLTIME_REACHED, + 'Job ran longer than the maximum allowed execution time (runtime: %s, limit: %s), please try different inputs or parameters' + % ( str(runtime).split('.')[0], self.app.job_config.limits.walltime ) ) return None def has_limits( self ): @@ -1341,11 +1369,11 @@ return '' return '[ -f "%s" ] && . %s' % ( self.app.config.environment_setup_file, self.app.config.environment_setup_file ) - def get_input_dataset_fnames( self, ds ): + def get_input_dataset_fnames( self, ds ): filenames = [] filenames = [ ds.file_name ] - #we will need to stage in metadata file names also - #TODO: would be better to only stage in metadata files that are actually needed (found in command line, referenced in config files, etc.) + # we will need to stage in metadata file names also + # TODO: would be better to only stage in metadata files that are actually needed (found in command line, referenced in config files, etc.) for key, value in ds.metadata.items(): if isinstance( value, model.MetadataFile ): filenames.append( value.file_name ) @@ -1386,7 +1414,7 @@ self.compute_outputs() return self.output_hdas_and_paths - def compute_outputs( self ) : + def compute_outputs( self ): dataset_path_rewriter = self.dataset_path_rewriter job = self.get_job() @@ -1402,7 +1430,7 @@ results.append( ( da.name, da.dataset, dataset_path ) ) self.output_paths = [t[2] for t in results] - self.output_hdas_and_paths = dict([(t[0], t[1:]) for t in results]) + self.output_hdas_and_paths = dict([(t[0], t[1:]) for t in results]) if special: false_path = dataset_path_rewriter.rewrite_dataset_path( special.dataset, 'output' ) dsp = DatasetPath( special.dataset.id, special.dataset.file_name, false_path ) @@ -1454,7 +1482,10 @@ return ExpressionContext( meta, job_context ) return job_context - def setup_external_metadata( self, exec_dir=None, tmp_dir=None, dataset_files_path=None, config_root=None, config_file=None, datatypes_config=None, set_extension=True, **kwds ): + def setup_external_metadata( self, exec_dir=None, tmp_dir=None, + dataset_files_path=None, config_root=None, + config_file=None, datatypes_config=None, + set_extension=True, **kwds ): # extension could still be 'auto' if this is the upload tool. job = self.get_job() if set_extension: @@ -1464,7 +1495,7 @@ output_dataset_assoc.dataset.extension = context.get( 'ext', 'data' ) self.sa_session.flush() if tmp_dir is None: - #this dir should should relative to the exec_dir + # this dir should should relative to the exec_dir tmp_dir = self.app.config.new_file_path if dataset_files_path is None: dataset_files_path = self.app.model.Dataset.file_path @@ -1474,7 +1505,9 @@ config_file = self.app.config.config_file if datatypes_config is None: datatypes_config = self.app.datatypes_registry.integrated_datatypes_configs - return self.external_output_metadata.setup_external_metadata( [ output_dataset_assoc.dataset for output_dataset_assoc in job.output_datasets + job.output_library_datasets ], + return self.external_output_metadata.setup_external_metadata( [ output_dataset_assoc.dataset for + output_dataset_assoc in + job.output_datasets + job.output_library_datasets ], self.sa_session, exec_dir=exec_dir, tmp_dir=tmp_dir, @@ -1691,8 +1724,8 @@ # This may have ended too soon log.debug( 'task %s for job %d ended; exit code: %d' - % (self.task_id, self.job_id, - tool_exit_code if tool_exit_code != None else -256 ) ) + % (self.task_id, self.job_id, + tool_exit_code if tool_exit_code is not None else -256 ) ) # default post job setup_external_metadata self.sa_session.expunge_all() task = self.get_task() @@ -1748,7 +1781,9 @@ # Handled at the parent job level. Do nothing here. pass - def setup_external_metadata( self, exec_dir=None, tmp_dir=None, dataset_files_path=None, config_root=None, config_file=None, datatypes_config=None, set_extension=True, **kwds ): + def setup_external_metadata( self, exec_dir=None, tmp_dir=None, dataset_files_path=None, + config_root=None, config_file=None, datatypes_config=None, + set_extension=True, **kwds ): # There is no metadata setting for tasks. This is handled after the merge, at the job level. return "" diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd lib/galaxy/jobs/command_factory.py --- a/lib/galaxy/jobs/command_factory.py +++ b/lib/galaxy/jobs/command_factory.py @@ -140,7 +140,7 @@ config_file=config_file, datatypes_config=datatypes_config, compute_tmp_dir=compute_tmp_dir, - kwds={ 'overwrite' : False } + kwds={ 'overwrite': False } ) or '' metadata_command = metadata_command.strip() if metadata_command: diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd lib/galaxy/tools/imp_exp/__init__.py --- a/lib/galaxy/tools/imp_exp/__init__.py +++ b/lib/galaxy/tools/imp_exp/__init__.py @@ -11,6 +11,8 @@ from galaxy.util.json import dumps, loads from galaxy.web.framework.helpers import to_unicode +from sqlalchemy.sql import expression + log = logging.getLogger(__name__) EXPORT_HISTORY_TEXT = """ @@ -289,8 +291,8 @@ # Connect jobs to output datasets. for output_hid in job_attrs[ 'output_datasets' ]: # print "%s job has output dataset %i" % (imported_job.id, output_hid) - output_hda = self.sa_session.query( model.HistoryDatasetAssociation ) \ - .filter_by( history=new_history, hid=output_hid ).first() + output_hda = self.sa_session.query( model.HistoryDatasetAssociation + ).filter_by(history=new_history, hid=output_hid ).first() if output_hda: imported_job.add_output_dataset( output_hda.name, output_hda ) @@ -334,8 +336,8 @@ .join( "dataset" ) .options( eagerload_all( "dataset.actions" ) ) .order_by( trans.model.HistoryDatasetAssociation.hid ) - .filter( trans.model.HistoryDatasetAssociation.deleted == False ) #noqa - .filter( trans.model.Dataset.purged == False ) ) + .filter( trans.model.HistoryDatasetAssociation.deleted == expression.false() ) + .filter( trans.model.Dataset.purged == expression.false() ) ) return query.all() # TODO: should use db_session rather than trans in this method. @@ -389,7 +391,7 @@ "deleted": obj.deleted, "visible": obj.visible, "file_name": obj.file_name, - "uuid": ( lambda uuid: str( uuid ) if uuid else None )( obj.dataset.uuid ), + "uuid": ( lambda uuid: str( uuid ) if uuid else None )( obj.dataset.uuid ), "annotation": to_unicode( getattr( obj, 'annotation', '' ) ), "tags": get_item_tag_dict( obj ), } diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd lib/galaxy/tools/imp_exp/export_history.py --- a/lib/galaxy/tools/imp_exp/export_history.py +++ b/lib/galaxy/tools/imp_exp/export_history.py @@ -6,9 +6,14 @@ -G, --gzip: gzip archive file """ +import optparse +import os +import sys +import tarfile + from galaxy import eggs -from galaxy.util.json import * -import optparse, sys, os, tempfile, tarfile +from galaxy.util.json import dumps, loads + def get_dataset_filename( name, ext ): """ @@ -18,6 +23,7 @@ base = ''.join( c in valid_chars and c or '_' for c in name ) return base + ".%s" % ext + def create_archive( history_attrs_file, datasets_attrs_file, jobs_attrs_file, out_file, gzip=False ): """ Create archive from the given attribute/metadata files and save it to out_file. """ tarfile_mode = "w" @@ -45,7 +51,7 @@ # TODO: security check to ensure that files added are in Galaxy dataset directory? for dataset_attrs in datasets_attrs: if dataset_attrs['exported']: - dataset_file_name = dataset_attrs[ 'file_name' ] # Full file name. + dataset_file_name = dataset_attrs[ 'file_name' ] # Full file name. dataset_archive_name = os.path.join( 'datasets', get_dataset_filename( dataset_attrs[ 'name' ], dataset_attrs[ 'extension' ] ) ) history_archive.add( dataset_file_name, arcname=dataset_archive_name ) @@ -61,7 +67,7 @@ history_archive.add( history_attrs_file, arcname="history_attrs.txt" ) history_archive.add( datasets_attrs_file, arcname="datasets_attrs.txt" ) if os.path.exists( datasets_attrs_file + ".provenance" ): - history_archive.add( datasets_attrs_file + ".provenance", arcname="datasets_attrs.txt.provenance" ) + history_archive.add( datasets_attrs_file + ".provenance", arcname="datasets_attrs.txt.provenance" ) history_archive.add( jobs_attrs_file, arcname="jobs_attrs.txt" ) history_archive.close() @@ -70,6 +76,7 @@ except Exception, e: return 'Error creating history archive: %s' % str( e ), sys.stderr + def main(): # Parse command line. parser = optparse.OptionParser() diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py --- a/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py +++ b/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py @@ -112,11 +112,11 @@ else: kp_material_tag = None return dumps({'cluster_name': cluster_name, - 'instance_id': result['rs'].instances[0].id, - 'image_id': result['rs'].instances[0].image_id, - 'public_dns_name': result['rs'].instances[0].public_dns_name, - 'kp_name': result['kp_name'], - 'kp_material_tag': kp_material_tag}) + 'instance_id': result['rs'].instances[0].id, + 'image_id': result['rs'].instances[0].image_id, + 'public_dns_name': result['rs'].instances[0].public_dns_name, + 'kp_name': result['kp_name'], + 'kp_material_tag': kp_material_tag}) @web.expose def get_pkey(self, trans, kp_material_tag=None): diff -r b3a236230733354107c1cdf848f74670f24c98d2 -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd scripts/set_metadata.py --- a/scripts/set_metadata.py +++ b/scripts/set_metadata.py @@ -29,12 +29,16 @@ from galaxy import eggs import pkg_resources import galaxy.model.mapping # need to load this before we unpickle, in order to setup properties assigned by the mappers -galaxy.model.Job() # this looks REAL stupid, but it is REQUIRED in order for SA to insert parameters into the classes defined by the mappers --> it appears that instantiating ANY mapper'ed class would suffice here + +# This looks REAL stupid, but it is REQUIRED in order for SA to insert +# parameters into the classes defined by the mappers --> it appears that +# instantiating ANY mapper'ed class would suffice here +galaxy.model.Job() + from galaxy.util import stringify_dictionary_keys from sqlalchemy.orm import clear_mappers from galaxy.objectstore import build_object_store_from_config from galaxy import config -import ConfigParser from galaxy.util.properties import load_app_properties @@ -43,16 +47,17 @@ # then call set_meta, then set metadata attributes from tool again. # This is intentional due to interplay of overwrite kwd, the fact that some metadata # parameters may rely on the values of others, and that we are accepting the - # values provided by the tool as Truth. + # values provided by the tool as Truth. for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): setattr( dataset_instance.metadata, metadata_name, metadata_value ) dataset_instance.datatype.set_meta( dataset_instance, **set_meta_kwds ) for metadata_name, metadata_value in file_dict.get( 'metadata', {} ).iteritems(): setattr( dataset_instance.metadata, metadata_name, metadata_value ) + def __main__(): file_path = sys.argv.pop( 1 ) - tool_job_working_directory = tmp_dir = sys.argv.pop( 1 ) #this is also the job_working_directory now + tool_job_working_directory = tmp_dir = sys.argv.pop( 1 ) # this is also the job_working_directory now galaxy.model.Dataset.file_path = file_path galaxy.datatypes.metadata.MetadataTempFile.tmp_dir = tmp_dir @@ -100,7 +105,7 @@ dataset_filename_override = fields.pop( 0 ) # Need to be careful with the way that these parameters are populated from the filename splitting, # because if a job is running when the server is updated, any existing external metadata command-lines - #will not have info about the newly added override_metadata file + # will not have info about the newly added override_metadata file if fields: override_metadata = fields.pop( 0 ) else: @@ -136,7 +141,8 @@ new_dataset.state = new_dataset.states.OK new_dataset_instance = galaxy.model.HistoryDatasetAssociation( id=-i, dataset=new_dataset, extension=file_dict.get( 'ext', 'data' ) ) set_meta_with_tool_provided( new_dataset_instance, file_dict, set_meta_kwds ) - file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) #storing metadata in external form, need to turn back into dict, then later jsonify + # storing metadata in external form, need to turn back into dict, then later jsonify + file_dict[ 'metadata' ] = json.loads( new_dataset_instance.metadata.to_JSON_dict() ) if existing_job_metadata_dict or new_job_metadata_dict: with open( job_metadata, 'wb' ) as job_metadata_fh: for value in existing_job_metadata_dict.values() + new_job_metadata_dict.values(): https://bitbucket.org/galaxy/galaxy-central/commits/f905079143dc/ Changeset: f905079143dc User: natefoo Date: 2015-03-05 14:54:26+00:00 Summary: Fix unit test broken by set_metadata changes. Affected #: 1 file diff -r 521695e2903a9f6de4a73e8eba2c0966fbded6cd -r f905079143dc0ea379f5e15a008991578cbabed2 test/unit/jobs/test_command_factory.py --- a/test/unit/jobs/test_command_factory.py +++ b/test/unit/jobs/test_command_factory.py @@ -72,7 +72,7 @@ self.include_metadata = True self.include_work_dir_outputs = False self.job_wrapper.metadata_line = TEST_METADATA_LINE - expected_command = '%s; return_code=$?; cd %s; %s; sh -c "exit $return_code"' % (MOCK_COMMAND_LINE, getcwd(), TEST_METADATA_LINE) + expected_command = '%s; return_code=$?; %s; sh -c "exit $return_code"' % (MOCK_COMMAND_LINE, TEST_METADATA_LINE) self.__assert_command_is( expected_command ) def test_empty_metadata(self): https://bitbucket.org/galaxy/galaxy-central/commits/2e28b74cbb96/ Changeset: 2e28b74cbb96 User: dannon Date: 2015-03-05 18:27:22+00:00 Summary: Tweaks to the password reset email template to help email clients not mangle it, and when they do, to suggest copying and pasting. Affected #: 1 file diff -r f905079143dc0ea379f5e15a008991578cbabed2 -r 2e28b74cbb96d9606cc3ddc023b8bb2e37dbed72 lib/galaxy/webapps/galaxy/controllers/user.py --- a/lib/galaxy/webapps/galaxy/controllers/user.py +++ b/lib/galaxy/webapps/galaxy/controllers/user.py @@ -42,10 +42,14 @@ PASSWORD_RESET_TEMPLATE = """ To reset your Galaxy password for the instance at %s, use the following link: - <a href="%s">%s</a> +<a href="%s">%s</a> If you did not make this request, no action is necessary on your part, though -you may want to notify an administrator.""" +you may want to notify an administrator. + +If you're having trouble using the link when clicking it from email client, you +can also copy and paste it into your browser. +""" class UserOpenIDGrid( grids.Grid ): https://bitbucket.org/galaxy/galaxy-central/commits/e455b4d21974/ Changeset: e455b4d21974 User: dan Date: 2015-03-05 22:02:45+00:00 Summary: Fix for displaying Tools in ToolShed that use Dynamically Generated multiple selects as checkboxes and for displaying select lists using old-style dynamic options. Affected #: 1 file diff -r 2e28b74cbb96d9606cc3ddc023b8bb2e37dbed72 -r e455b4d21974490f6a2e42eb4f2dee91d6f01397 templates/webapps/tool_shed/repository/tool_form.mako --- a/templates/webapps/tool_shed/repository/tool_form.mako +++ b/templates/webapps/tool_shed/repository/tool_form.mako @@ -78,18 +78,21 @@ field.add_option( param.name, param.name ) field_html = field.get_html() elif isinstance( param, SelectToolParameter ) and hasattr( param, 'data_ref' ): - field = SelectField( param.name, display=param.display ) + field = SelectField( param.name, display=param.display, multiple=param.multiple ) field.add_option( param.data_ref, param.data_ref ) field_html = field.get_html( prefix ) elif isinstance( param, SelectToolParameter ) and param.is_dynamic: - field = SelectField( param.name, display=param.display ) + field = SelectField( param.name, display=param.display, multiple=param.multiple ) dynamic_options = param.options - if dynamic_options.index_file: - option_label = "Dynamically generated from entries in file %s" % str( dynamic_options.index_file ) - field.add_option( option_label, "none" ) - elif dynamic_options.missing_index_file: - option_label = "Dynamically generated from entries in missing file %s" % str( dynamic_options.missing_index_file ) - field.add_option( option_label, "none" ) + if dynamic_options is not None: + if dynamic_options.index_file: + option_label = "Dynamically generated from entries in file %s" % str( dynamic_options.index_file ) + field.add_option( option_label, "none" ) + elif dynamic_options.missing_index_file: + option_label = "Dynamically generated from entries in missing file %s" % str( dynamic_options.missing_index_file ) + field.add_option( option_label, "none" ) + else: + field.add_option( "Dynamically generated from old-style Dynamic Options.", "none" ) field_html = field.get_html( prefix ) else: field = param.get_html_field( trans, None, other_values ) https://bitbucket.org/galaxy/galaxy-central/commits/6f1859533d83/ Changeset: 6f1859533d83 User: guerler Date: 2015-03-06 03:15:21+00:00 Summary: Fix dataset and collection mapping for re-run in imported histories Affected #: 1 file diff -r e455b4d21974490f6a2e42eb4f2dee91d6f01397 -r 6f1859533d83be19e77b9ad6aca7122fe95b70de lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -34,10 +34,10 @@ from galaxy.tools.actions.data_source import DataSourceToolAction from galaxy.tools.actions.data_manager import DataManagerToolAction from galaxy.tools.deps import build_dependency_manager -from galaxy.tools.parameters import params_to_incoming, check_param, params_from_strings, params_to_strings +from galaxy.tools.parameters import params_to_incoming, check_param, params_from_strings, params_to_strings, visit_input_values from galaxy.tools.parameters import output_collect from galaxy.tools.parameters.basic import (BaseURLToolParameter, - DataToolParameter, HiddenToolParameter, LibraryDatasetToolParameter, + DataToolParameter, DataCollectionToolParameter, HiddenToolParameter, LibraryDatasetToolParameter, SelectToolParameter, ToolParameter, UnvalidatedValue, IntegerToolParameter, FloatToolParameter) from galaxy.tools.parameters.grouping import Conditional, ConditionalWhen, Repeat, UploadDataset @@ -52,7 +52,7 @@ from galaxy.tools.parameters.meta import expand_meta_parameters from galaxy.util.bunch import Bunch from galaxy.util.expressions import ExpressionContext -from galaxy.util.hash_util import hmac_new +from galaxy.util.hash_util import hmac_new, is_hashable from galaxy.util.odict import odict from galaxy.util.template import fill_template from galaxy.web import url_for @@ -2291,6 +2291,7 @@ try: job_params = job.get_param_values( trans.app, ignore_errors = True ) job_messages = self.check_and_update_param_values( job_params, trans, update_values=False ) + self._map_source_to_history( trans, self.inputs, job_params ) tool_message = self._compare_tool_version(trans, job) params_to_incoming( kwd, self.inputs, job_params, trans.app, to_html=False ) except Exception, exception: @@ -2564,6 +2565,59 @@ # return enriched tool model return tool_model + def _map_source_to_history(self, trans, tool_inputs, params): + # Need to remap dataset parameters. Job parameters point to original + # dataset used; parameter should be the analygous dataset in the + # current history. + history = trans.get_history() + hda_source_dict = {} # Mapping from HDA in history to source HDAs. + for hda in history.datasets: + source_hda = hda.copied_from_history_dataset_association + while source_hda:#should this check library datasets as well? + #FIXME: could be multiple copies of a hda in a single history, this does a better job of matching on cloned histories, + #but is still less than perfect when eg individual datasets are copied between histories + if source_hda not in hda_source_dict or source_hda.hid == hda.hid: + hda_source_dict[ source_hda ] = hda + source_hda = source_hda.copied_from_history_dataset_association + + # Ditto for dataset collections. + hdca_source_dict = {} + for hdca in history.dataset_collections: + source_hdca = hdca.copied_from_history_dataset_collection_association + while source_hdca: + if source_hdca not in hdca_source_dict or source_hdca.hid == hdca.hid: + hdca_source_dict[ source_hdca ] = hdca + source_hdca = source_hdca.copied_from_history_dataset_collection_association + + # Unpack unvalidated values to strings, they'll be validated when the + # form is submitted (this happens when re-running a job that was + # initially run by a workflow) + #This needs to be done recursively through grouping parameters + def rerun_callback( input, value, prefixed_name, prefixed_label ): + if isinstance( value, UnvalidatedValue ): + try: + return input.to_html_value( value.value, trans.app ) + except Exception, e: + # Need to determine when (if ever) the to_html_value call could fail. + log.debug( "Failed to use input.to_html_value to determine value of unvalidated parameter, defaulting to string: %s" % ( e ) ) + return str( value ) + if isinstance( input, DataToolParameter ): + if isinstance(value,list): + values = [] + for val in value: + if is_hashable( val ): + if val in history.datasets: + values.append( val ) + elif val in hda_source_dict: + values.append( hda_source_dict[ val ]) + return values + if is_hashable( value ) and value not in history.datasets and value in hda_source_dict: + return hda_source_dict[ value ] + elif isinstance( input, DataCollectionToolParameter ): + if is_hashable( value ) and value not in history.dataset_collections and value in hdca_source_dict: + return hdca_source_dict[ value ] + visit_input_values( tool_inputs, params, rerun_callback ) + def _compare_tool_version( self, trans, job ): """ Compares a tool version with the tool version from a job (from ToolRunner). https://bitbucket.org/galaxy/galaxy-central/commits/e8b0e25d5abb/ Changeset: e8b0e25d5abb User: jmchilton Date: 2015-03-06 18:16:31+00:00 Summary: Add verbose test error flag option in run_tests.sh. Affected #: 1 file diff -r 6f1859533d83be19e77b9ad6aca7122fe95b70de -r e8b0e25d5abb87ac3e5b47b9c53be904da25c4ec run_tests.sh --- a/run_tests.sh +++ b/run_tests.sh @@ -26,6 +26,7 @@ Extra options: + --verbose_errors Force some tests produce more verbose error reporting. --no_cleanup Do not delete temp files for Python functional tests (-toolshed, -framework, etc...) --report_file Path of HTML report to produce (for Python Galaxy functional tests). --xunit_report_file Path of XUnit report to produce (for Python Galaxy functional tests). @@ -193,6 +194,11 @@ exit 1 fi ;; + --verbose_errors) + GALAXY_TEST_VERBOSE_ERRORS=True + export GALAXY_TEST_VERBOSE_ERRORS + shift + ;; -c|--coverage) # Must have coverage installed (try `which coverage`) - only valid with --unit # for now. Would be great to get this to work with functional tests though. https://bitbucket.org/galaxy/galaxy-central/commits/5bb46d2a601f/ Changeset: 5bb46d2a601f User: jmchilton Date: 2015-03-06 18:16:55+00:00 Summary: Add broken bam test... Nate will fix metadata and I can continue working on it. Run with: ./run_tests.sh --verbose_errors --framework --id compare_bam_as_sam Affected #: 3 files diff -r e8b0e25d5abb87ac3e5b47b9c53be904da25c4ec -r 5bb46d2a601f2fbd62326d00843bec1ce6e1d822 test/functional/tools/compare_bam_as_sam.xml --- /dev/null +++ b/test/functional/tools/compare_bam_as_sam.xml @@ -0,0 +1,15 @@ +<tool id="compare_bam_as_sam" name="compare_bam_as_sam" version="1.0.0"> + <command>cp $input1 out</command> + <inputs> + <param name="input1" type="data" format="bam" label="Concatenate Dataset" /> + </inputs> + <outputs> + <data format="bam" name="output1" from_work_dir="out" /> + </outputs> + <tests> + <test> + <param name="input1" value="3unsorted.bam" /> + <output name="output1" file="3unsorted.bam" ftype="bam" /> + </test> + </tests> +</tool> diff -r e8b0e25d5abb87ac3e5b47b9c53be904da25c4ec -r 5bb46d2a601f2fbd62326d00843bec1ce6e1d822 test/functional/tools/sample_datatypes_conf.xml --- a/test/functional/tools/sample_datatypes_conf.xml +++ b/test/functional/tools/sample_datatypes_conf.xml @@ -10,5 +10,7 @@ <datatype extension="fastqsolexa" type="galaxy.datatypes.sequence:FastqSolexa" display_in_upload="true" /><datatype extension="fastqcssanger" type="galaxy.datatypes.sequence:FastqCSSanger" display_in_upload="true" /><datatype extension="fastqillumina" type="galaxy.datatypes.sequence:FastqIllumina" display_in_upload="true" /> + <datatype extension="sam" type="galaxy.datatypes.tabular:Sam" display_in_upload="true" /> + <datatype extension="bam" type="galaxy.datatypes.binary:Bam" mimetype="application/octet-stream" display_in_upload="true" description="A binary file compressed in the BGZF format with a '.bam' file extension." description_url="https://wiki.galaxyproject.org/Learn/Datatypes#BAM" /></registration></datatypes> \ No newline at end of file diff -r e8b0e25d5abb87ac3e5b47b9c53be904da25c4ec -r 5bb46d2a601f2fbd62326d00843bec1ce6e1d822 test/functional/tools/samples_tool_conf.xml --- a/test/functional/tools/samples_tool_conf.xml +++ b/test/functional/tools/samples_tool_conf.xml @@ -3,6 +3,7 @@ <tool file="upload.xml"/><tool file="simple_constructs.xml" /><tool file="composite.xml" /> + <tool file="compare_bam_as_sam.xml" /><tool file="code_file.xml" /><tool file="disambiguate_cond.xml" /><tool file="multi_repeats.xml"/> https://bitbucket.org/galaxy/galaxy-central/commits/bfdd8317b7e8/ Changeset: bfdd8317b7e8 User: natefoo Date: 2015-03-06 18:50:49+00:00 Summary: Use the job working directory for creating MetadataFiles in external set_metadata, rather than new_files_path. Affected #: 1 file diff -r 5bb46d2a601f2fbd62326d00843bec1ce6e1d822 -r bfdd8317b7e851b168751e657433d88bd85a131a lib/galaxy/metadata/set_metadata.py --- a/lib/galaxy/metadata/set_metadata.py +++ b/lib/galaxy/metadata/set_metadata.py @@ -50,7 +50,7 @@ def set_metadata(): # locate galaxy_root for loading datatypes galaxy_root = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)) - tool_job_working_directory = os.path.abspath(os.getcwd()) + galaxy.datatypes.metadata.MetadataTempFile.tmp_dir = tool_job_working_directory = os.path.abspath(os.getcwd()) # Set up datatypes registry datatypes_config = sys.argv.pop( 1 ) https://bitbucket.org/galaxy/galaxy-central/commits/9f799e8c874d/ Changeset: 9f799e8c874d User: dan Date: 2015-03-06 19:18:48+00:00 Summary: Make api/config /version usable as sessionless in addition to anonymous. Affected #: 1 file diff -r bfdd8317b7e851b168751e657433d88bd85a131a -r 9f799e8c874df4bc640ae1668b20e9cecf5b9f9c lib/galaxy/webapps/galaxy/api/configuration.py --- a/lib/galaxy/webapps/galaxy/api/configuration.py +++ b/lib/galaxy/webapps/galaxy/api/configuration.py @@ -3,7 +3,7 @@ and configuration settings. """ -from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous +from galaxy.web import _future_expose_api_anonymous_and_sessionless as expose_api_anonymous_and_sessionless from galaxy.web import _future_expose_api as expose_api from galaxy.web import require_admin from galaxy.web.base.controller import BaseAPIController @@ -21,7 +21,7 @@ self.config_serializer = ConfigSerializer( app ) self.admin_config_serializer = AdminConfigSerializer( app ) - @expose_api_anonymous + @expose_api_anonymous_and_sessionless def index( self, trans, **kwd ): """ GET /api/configuration @@ -33,7 +33,7 @@ serialization_params = self._parse_serialization_params( kwd, 'all' ) return self.get_config_dict( trans, is_admin, **serialization_params ) - @expose_api_anonymous + @expose_api_anonymous_and_sessionless def version( self, trans, **kwds ): """ GET /api/version https://bitbucket.org/galaxy/galaxy-central/commits/2e595cb3d430/ Changeset: 2e595cb3d430 User: dannon Date: 2015-03-06 19:54:02+00:00 Summary: Expose expose tool list sessionless/anon via API (access to specific members is already this way) Affected #: 1 file diff -r 9f799e8c874df4bc640ae1668b20e9cecf5b9f9c -r 2e595cb3d4302ac9ba1b4b0aece15a9909e1090f lib/galaxy/webapps/galaxy/api/tools.py --- a/lib/galaxy/webapps/galaxy/api/tools.py +++ b/lib/galaxy/webapps/galaxy/api/tools.py @@ -35,7 +35,7 @@ self.history_manager = managers.histories.HistoryManager( app ) self.hda_manager = managers.hdas.HDAManager( app ) - @web.expose_api + @_future_expose_api_anonymous_and_sessionless def index( self, trans, **kwds ): """ GET /api/tools: returns a list of tools defined by parameters:: https://bitbucket.org/galaxy/galaxy-central/commits/f9d065cf044f/ Changeset: f9d065cf044f User: BjoernGruening Date: 2015-03-07 02:05:14+00:00 Summary: Sync report options with galaxy.ini. This will only improve documentation and has no effect on the default settings. Affected #: 1 file diff -r 2e595cb3d4302ac9ba1b4b0aece15a9909e1090f -r f9d065cf044f32179bfa526ec159ac9b6ea80ce6 config/reports_wsgi.ini.sample --- a/config/reports_wsgi.ini.sample +++ b/config/reports_wsgi.ini.sample @@ -8,10 +8,37 @@ use_threadpool = true threadpool_workers = 10 +# ---- Filters -------------------------------------------------------------- + +# Filters sit between Galaxy and the HTTP server. + +# These filters are disabled by default. They can be enabled with +# 'filter-with' in the [app:main] section below. + +# Define the proxy-prefix filter. +[filter:proxy-prefix] +use = egg:PasteDeploy#prefix +prefix = /reports + # ---- Galaxy Webapps Report Interface ------------------------------------------------- [app:main] +# -- Application and filtering + +# If running behind a proxy server and Galaxy is served from a subdirectory, +# enable the proxy-prefix filter and set the prefix in the +# [filter:proxy-prefix] section above. +#filter-with = proxy-prefix + +# If proxy-prefix is enabled and you're running more than one Galaxy instance +# behind one hostname, you will want to set this to the same path as the prefix +# in the filter above. This value becomes the "path" attribute set in the +# cookie so the cookies from each instance will not clobber each other. +#cookie_path = None + +# -- Report + # Specifies the factory for the universe WSGI application paste.app_factory = galaxy.webapps.reports.buildapp:app_factory log_level = DEBUG https://bitbucket.org/galaxy/galaxy-central/commits/3f262ad7678a/ Changeset: 3f262ad7678a User: guerler Date: 2015-03-06 20:24:31+00:00 Summary: Add resume option for job dependencies Affected #: 3 files diff -r f9d065cf044f32179bfa526ec159ac9b6ea80ce6 -r 3f262ad7678ac003ef0d40f065a3f42ec001d164 client/galaxy/scripts/mvc/tools/tools-form-base.js --- a/client/galaxy/scripts/mvc/tools/tools-form-base.js +++ b/client/galaxy/scripts/mvc/tools/tools-form-base.js @@ -295,6 +295,20 @@ }); } + // add remap button + if (this.options.job_id && this.options.job_remap) { + options.inputs['rerun_remap_job_id'] = { + label : 'Resume dependencies from this job', + name : 'rerun_remap_job_id', + type : 'select', + display : 'radio', + ignore : '__ignore__', + value : '__ignore__', + options : [['Yes', this.options.job_id], ['No', '__ignore__']], + help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully, use this option to resume those tools using the outputs of this tool run.' + } + } + // create tool form section this.section = new ToolSection.View(self, { inputs : options.inputs diff -r f9d065cf044f32179bfa526ec159ac9b6ea80ce6 -r 3f262ad7678ac003ef0d40f065a3f42ec001d164 lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -1215,7 +1215,8 @@ if 'rerun_remap_job_id' in incoming: try: rerun_remap_job_id = trans.app.security.decode_id( incoming[ 'rerun_remap_job_id' ] ) - except Exception: + except Exception, exception: + log.error( str( exception ) ) message = 'Failure executing tool (attempting to rerun invalid job).' return 'message.mako', dict( status='error', message=message, refresh_frames=[] ) @@ -2296,6 +2297,7 @@ params_to_incoming( kwd, self.inputs, job_params, trans.app, to_html=False ) except Exception, exception: trans.response.status = 500 + log.error( str( exception ) ) return { 'error': str( exception ) } # create parameter object @@ -2555,7 +2557,8 @@ 'versions' : tool_versions, 'requirements' : tool_requirements, 'errors' : state_errors, - 'state_inputs' : state_inputs + 'state_inputs' : state_inputs, + 'job_remap' : self._get_job_remap(job) }) # check for errors @@ -2565,6 +2568,18 @@ # return enriched tool model return tool_model + def _get_job_remap ( self, job): + if job: + if job.state == job.states.ERROR: + return True + try: + if [ hda.dependent_jobs for hda in [ jtod.dataset for jtod in job.output_datasets ] if hda.dependent_jobs ]: + return True + except Exception, exception: + log.error( str( exception ) ) + pass + return False + def _map_source_to_history(self, trans, tool_inputs, params): # Need to remap dataset parameters. Job parameters point to original # dataset used; parameter should be the analygous dataset in the diff -r f9d065cf044f32179bfa526ec159ac9b6ea80ce6 -r 3f262ad7678ac003ef0d40f065a3f42ec001d164 static/scripts/mvc/tools/tools-form-base.js --- a/static/scripts/mvc/tools/tools-form-base.js +++ b/static/scripts/mvc/tools/tools-form-base.js @@ -295,6 +295,20 @@ }); } + // add remap button + if (this.options.job_id && this.options.job_remap) { + options.inputs['rerun_remap_job_id'] = { + label : 'Resume dependencies from this job', + name : 'rerun_remap_job_id', + type : 'select', + display : 'radio', + ignore : '__ignore__', + value : '__ignore__', + options : [['Yes', this.options.job_id], ['No', '__ignore__']], + help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully, use this option to resume those tools using the outputs of this tool run.' + } + } + // create tool form section this.section = new ToolSection.View(self, { inputs : options.inputs https://bitbucket.org/galaxy/galaxy-central/commits/057261b79174/ Changeset: 057261b79174 User: guerler Date: 2015-03-06 20:28:22+00:00 Summary: Enable remap condition Affected #: 1 file diff -r 3f262ad7678ac003ef0d40f065a3f42ec001d164 -r 057261b79174a4d49ec418e658f3a1aa3116a61a lib/galaxy/tools/__init__.py --- a/lib/galaxy/tools/__init__.py +++ b/lib/galaxy/tools/__init__.py @@ -2571,7 +2571,6 @@ def _get_job_remap ( self, job): if job: if job.state == job.states.ERROR: - return True try: if [ hda.dependent_jobs for hda in [ jtod.dataset for jtod in job.output_datasets ] if hda.dependent_jobs ]: return True https://bitbucket.org/galaxy/galaxy-central/commits/65aa7fb51c1a/ Changeset: 65aa7fb51c1a User: dannon Date: 2015-03-06 20:49:14+00:00 Summary: Minor wording tweaks. Affected #: 2 files diff -r 057261b79174a4d49ec418e658f3a1aa3116a61a -r 65aa7fb51c1a6ed20bcd73a3b2e9d1e72cd43332 client/galaxy/scripts/mvc/tools/tools-form-base.js --- a/client/galaxy/scripts/mvc/tools/tools-form-base.js +++ b/client/galaxy/scripts/mvc/tools/tools-form-base.js @@ -133,12 +133,12 @@ highlight: function (input_id, message, silent) { // get input field var input_element = this.element_list[input_id]; - + // check input element if (input_element) { // mark error input_element.error(message || 'Please verify this parameter.'); - + // scroll to first input element if (!silent) { $('html, body').animate({ @@ -153,7 +153,7 @@ _errors: function(options) { // hide previous error statements this.trigger('reset'); - + // highlight all errors if (options && options.errors) { var error_messages = this.tree.matchResponse(options.errors); @@ -193,7 +193,7 @@ // here we update the tool version (some tools encode the version also in the id) self.options.id = self.options.id.replace(self.options.version, this.version); self.options.version = this.version; - + // rebuild the model and form self.deferred.reset(); self.deferred.execute(function(){self._buildModel()}); @@ -223,7 +223,7 @@ window.open(options.biostar_url + '/p/new/post/'); } }); - + // create search button menu_button.addMenu({ icon : 'fa-search', @@ -305,7 +305,7 @@ ignore : '__ignore__', value : '__ignore__', options : [['Yes', this.options.job_id], ['No', '__ignore__']], - help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully, use this option to resume those tools using the outputs of this tool run.' + help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully. Use this option to resume those tools using the new output(s) of this tool run.' } } diff -r 057261b79174a4d49ec418e658f3a1aa3116a61a -r 65aa7fb51c1a6ed20bcd73a3b2e9d1e72cd43332 static/scripts/mvc/tools/tools-form-base.js --- a/static/scripts/mvc/tools/tools-form-base.js +++ b/static/scripts/mvc/tools/tools-form-base.js @@ -133,12 +133,12 @@ highlight: function (input_id, message, silent) { // get input field var input_element = this.element_list[input_id]; - + // check input element if (input_element) { // mark error input_element.error(message || 'Please verify this parameter.'); - + // scroll to first input element if (!silent) { $('html, body').animate({ @@ -153,7 +153,7 @@ _errors: function(options) { // hide previous error statements this.trigger('reset'); - + // highlight all errors if (options && options.errors) { var error_messages = this.tree.matchResponse(options.errors); @@ -193,7 +193,7 @@ // here we update the tool version (some tools encode the version also in the id) self.options.id = self.options.id.replace(self.options.version, this.version); self.options.version = this.version; - + // rebuild the model and form self.deferred.reset(); self.deferred.execute(function(){self._buildModel()}); @@ -223,7 +223,7 @@ window.open(options.biostar_url + '/p/new/post/'); } }); - + // create search button menu_button.addMenu({ icon : 'fa-search', @@ -305,7 +305,7 @@ ignore : '__ignore__', value : '__ignore__', options : [['Yes', this.options.job_id], ['No', '__ignore__']], - help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully, use this option to resume those tools using the outputs of this tool run.' + help : 'The previous run of this tool failed and other tools were waiting for it to finish successfully. Use this option to resume those tools using the new output(s) of this tool run.' } } https://bitbucket.org/galaxy/galaxy-central/commits/4b3647b73b0f/ Changeset: 4b3647b73b0f User: dannon Date: 2015-03-06 21:04:43+00:00 Summary: Ensure path was well constructed (has value) before trying to determine whether or not it exists. Affected #: 1 file diff -r 65aa7fb51c1a6ed20bcd73a3b2e9d1e72cd43332 -r 4b3647b73b0f8db76a5c0d2cb5efafb3dc872c9b lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py --- a/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py +++ b/lib/galaxy/webapps/galaxy/controllers/admin_toolshed.py @@ -341,8 +341,9 @@ repository = suc.get_tool_shed_repository_by_id( trans.app, repository_id ) if repository: repo_files_dir = repository.repo_files_directory( trans.app ) + # The following line sometimes returns None. TODO: Figure out why. path_to_file = suc.get_absolute_path_to_file_in_repository( repo_files_dir, relative_path_to_image_file ) - if os.path.exists( path_to_file ): + if path_to_file and os.path.exists( path_to_file ): file_name = os.path.basename( relative_path_to_image_file ) try: extension = file_name.split( '.' )[ -1 ] https://bitbucket.org/galaxy/galaxy-central/commits/7fff20f3be3a/ Changeset: 7fff20f3be3a User: dannon Date: 2015-03-08 03:51:35+00:00 Summary: Cleanup in pbed_to_lped converter Affected #: 2 files diff -r 4b3647b73b0f8db76a5c0d2cb5efafb3dc872c9b -r 7fff20f3be3a20c0adeebb622637d214acf25b50 lib/galaxy/datatypes/converters/pbed_to_lped_converter.py --- a/lib/galaxy/datatypes/converters/pbed_to_lped_converter.py +++ b/lib/galaxy/datatypes/converters/pbed_to_lped_converter.py @@ -4,7 +4,10 @@ # eg lped/eigen/fbat/snpmatrix all to pbed # and pbed to lped/eigen/fbat/snpmatrix ? # that's a lot of converters -import sys,os,time,subprocess +import os +import subprocess +import sys +import time prog = os.path.split(sys.argv[0])[-1] @@ -23,23 +26,21 @@ <div class="document"> """ + def timenow(): """return current time as a string """ return time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(time.time())) -def rgConv(inpedfilepath,outhtmlname,outfilepath,plink): +def rgConv(inpedfilepath, outhtmlname, outfilepath, plink): """ """ - - basename = os.path.split(inpedfilepath)[-1] # get basename - outroot = os.path.join(outfilepath,basename) - cl = '%s --noweb --bfile %s --recode --out %s ' % (plink,inpedfilepath,outroot) - p = subprocess.Popen(cl,shell=True,cwd=outfilepath) - retval = p.wait() # run plink - - + basename = os.path.split(inpedfilepath)[-1] # get basename + outroot = os.path.join(outfilepath, basename) + cl = '%s --noweb --bfile %s --recode --out %s ' % (plink, inpedfilepath, outroot) + p = subprocess.Popen(cl, shell=True, cwd=outfilepath) + p.wait() # run plink def main(): @@ -52,7 +53,7 @@ """ nparm = 4 if len(sys.argv) < nparm: - sys.stderr.write('## %s called with %s - needs %d parameters \n' % (myname,sys.argv,nparm)) + sys.stderr.write('## %s called with %s - needs %d parameters \n' % (myname, sys.argv, nparm)) sys.exit(1) inpedfilepath = sys.argv[1] outhtmlname = sys.argv[2] @@ -62,19 +63,18 @@ except: pass plink = sys.argv[4] - rgConv(inpedfilepath,outhtmlname,outfilepath,plink) - f = file(outhtmlname,'w') + rgConv(inpedfilepath, outhtmlname, outfilepath, plink) + f = file(outhtmlname, 'w') f.write(galhtmlprefix % prog) flist = os.listdir(outfilepath) - s = '## Rgenetics: http://bitbucket.org/rgalaxy Galaxy Tools %s %s' % (prog,timenow()) # becomes info + s = '## Rgenetics: http://bitbucket.org/rgalaxy Galaxy Tools %s %s' % (prog, timenow()) # becomes info print s f.write('<div>%s\n<ol>' % (s)) for i, data in enumerate( flist ): - f.write('<li><a href="%s">%s</a></li>\n' % (os.path.split(data)[-1],os.path.split(data)[-1])) + f.write('<li><a href="%s">%s</a></li>\n' % (os.path.split(data)[-1], os.path.split(data)[-1])) f.write("</div></body></html>") f.close() - if __name__ == "__main__": - main() + main() diff -r 4b3647b73b0f8db76a5c0d2cb5efafb3dc872c9b -r 7fff20f3be3a20c0adeebb622637d214acf25b50 lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py --- a/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py +++ b/lib/galaxy/webapps/galaxy/controllers/cloudlaunch.py @@ -21,8 +21,6 @@ eggs.require('bioblend') from boto.exception import EC2ResponseError - - from bioblend import cloudman log = logging.getLogger(__name__) https://bitbucket.org/galaxy/galaxy-central/commits/bc29d4475c21/ Changeset: bc29d4475c21 User: dannon Date: 2015-03-08 03:54:22+00:00 Summary: Fix error message in pbed_to_lped when args are incorrect Affected #: 1 file diff -r 7fff20f3be3a20c0adeebb622637d214acf25b50 -r bc29d4475c217cdae4bcbb4798d2d5ced80bbcaf lib/galaxy/datatypes/converters/pbed_to_lped_converter.py --- a/lib/galaxy/datatypes/converters/pbed_to_lped_converter.py +++ b/lib/galaxy/datatypes/converters/pbed_to_lped_converter.py @@ -53,7 +53,7 @@ """ nparm = 4 if len(sys.argv) < nparm: - sys.stderr.write('## %s called with %s - needs %d parameters \n' % (myname, sys.argv, nparm)) + sys.stderr.write('PBED to LPED converter called with %s - needs %d parameters \n' % (sys.argv, nparm)) sys.exit(1) inpedfilepath = sys.argv[1] outhtmlname = sys.argv[2] https://bitbucket.org/galaxy/galaxy-central/commits/742bec3a5007/ Changeset: 742bec3a5007 User: jmchilton Date: 2015-03-08 17:11:24+00:00 Summary: Sychornize tools module with latest planemo changes. Affected #: 4 files diff -r bc29d4475c217cdae4bcbb4798d2d5ced80bbcaf -r 742bec3a500739b31417b70c83ab625fddfa8347 lib/galaxy/tools/linters/command.py --- /dev/null +++ b/lib/galaxy/tools/linters/command.py @@ -0,0 +1,18 @@ + + +def lint_command(tool_xml, lint_ctx): + root = tool_xml.getroot() + commands = root.findall("command") + if len(commands) > 1: + lint_ctx.error("More than one command tag found, behavior undefined.") + return + + if len(commands) == 0: + lint_ctx.error("No command tag found, must specify a command template to execute.") + return + + command = commands[0] + if "TODO" in command: + lint_ctx.warn("Command template contains TODO text.") + + lint_ctx.info("Tool contains a command.") diff -r bc29d4475c217cdae4bcbb4798d2d5ced80bbcaf -r 742bec3a500739b31417b70c83ab625fddfa8347 lib/galaxy/tools/linters/help.py --- a/lib/galaxy/tools/linters/help.py +++ b/lib/galaxy/tools/linters/help.py @@ -1,3 +1,4 @@ +from galaxy.util import rst_to_html def lint_help(tool_xml, lint_ctx): @@ -11,5 +12,22 @@ lint_ctx.warn("No help section found, consider adding a help section to your tool.") return - # TODO: validate help section RST. + help = helps[0].text + if not help.strip(): + lint_ctx.warn("Help section appears to be empty.") + return + lint_ctx.valid("Tool contains help section.") + invalid_rst = False + try: + rst_to_html(help) + except Exception as e: + invalid_rst = str(e) + + if "TODO" in help: + lint_ctx.warn("Help contains TODO text.") + + if invalid_rst: + lint_ctx.warn("Invalid reStructuredText found in help - [%s]." % invalid_rst) + else: + lint_ctx.valid("Help contains valid reStructuredText.") diff -r bc29d4475c217cdae4bcbb4798d2d5ced80bbcaf -r 742bec3a500739b31417b70c83ab625fddfa8347 lib/galaxy/tools/linters/outputs.py --- a/lib/galaxy/tools/linters/outputs.py +++ b/lib/galaxy/tools/linters/outputs.py @@ -3,7 +3,7 @@ def lint_output(tool_xml, lint_ctx): outputs = tool_xml.findall("./outputs/data") if not outputs: - lint_ctx.warn("Tool contains no outputs, most tools should produce outputs..") + lint_ctx.warn("Tool contains no outputs, most tools should produce outputs.") return num_outputs = 0 @@ -15,7 +15,7 @@ format_set = True format = output_attrib["format"] if format == "input": - lint_ctx.warn("Using format='input' on output data, format_source attribute is less ambigious and should be used instead.") + lint_ctx.warn("Using format='input' on output data, format_source attribute is less ambiguous and should be used instead.") elif "format_source" in output_attrib: format_set = True diff -r bc29d4475c217cdae4bcbb4798d2d5ced80bbcaf -r 742bec3a500739b31417b70c83ab625fddfa8347 lib/galaxy/tools/linters/tests.py --- a/lib/galaxy/tools/linters/tests.py +++ b/lib/galaxy/tools/linters/tests.py @@ -1,7 +1,7 @@ # Misspelled so as not be picked up by nosetests. -def lint_tsts(tool_xml, lint_ctx): +def lint_tests(tool_xml, lint_ctx): tests = tool_xml.findall("./tests/test") if not tests: lint_ctx.warn("No tests found, most tools should define test cases.") https://bitbucket.org/galaxy/galaxy-central/commits/cb0e940ddb1b/ Changeset: cb0e940ddb1b User: jmchilton Date: 2015-03-08 17:24:47+00:00 Summary: Missed a file in previous planemo update commit. Affected #: 1 file diff -r 742bec3a500739b31417b70c83ab625fddfa8347 -r cb0e940ddb1b08679f3ad2d00804f496be90d1c4 lib/galaxy/tools/loader_directory.py --- a/lib/galaxy/tools/loader_directory.py +++ b/lib/galaxy/tools/loader_directory.py @@ -2,21 +2,44 @@ import os from ..tools import loader +import sys + +import logging +log = logging.getLogger(__name__) + PATH_DOES_NOT_EXIST_ERROR = "Could not load tools from path [%s] - this path does not exist." +LOAD_FAILURE_ERROR = "Failed to load tool with path %s." -def load_tool_elements_from_path(path): +def load_exception_handler(path, exc_info): + log.warn(LOAD_FAILURE_ERROR % path, exc_info=exc_info) + + +def load_tool_elements_from_path(path, load_exception_handler=load_exception_handler): tool_elements = [] for file in __find_tool_files(path): - if __looks_like_a_tool(file): - tool_elements.append((file, loader.load_tool(file))) + try: + looks_like_a_tool = __looks_like_a_tool(file) + except IOError: + # Some problem reading the tool file, skip. + continue + + if looks_like_a_tool: + try: + tool_elements.append((file, loader.load_tool(file))) + except Exception: + exc_info = sys.exc_info() + load_exception_handler(file, exc_info) return tool_elements def __looks_like_a_tool(path): with open(path) as f: for i in range(10): - line = f.next() + try: + line = f.next() + except StopIteration: + break if "<tool" in line: return True return False https://bitbucket.org/galaxy/galaxy-central/commits/cd2aed870c00/ Changeset: cd2aed870c00 User: jmchilton Date: 2015-03-08 20:24:50+00:00 Summary: Fix for unit tests failling in 963032ecdddf39e0127e91f85d0253e98af317a6. Affected #: 2 files diff -r cb0e940ddb1b08679f3ad2d00804f496be90d1c4 -r cd2aed870c002601dbc2913dc82146089e451748 lib/galaxy/tools/lint.py --- a/lib/galaxy/tools/lint.py +++ b/lib/galaxy/tools/lint.py @@ -31,6 +31,7 @@ self.found_warns = False def lint(self, module, name, lint_func, tool_xml): + name = name.replace("tsts", "tests") self.printed_linter_info = False self.valid_messages = [] self.info_messages = [] diff -r cb0e940ddb1b08679f3ad2d00804f496be90d1c4 -r cd2aed870c002601dbc2913dc82146089e451748 lib/galaxy/tools/linters/tests.py --- a/lib/galaxy/tools/linters/tests.py +++ b/lib/galaxy/tools/linters/tests.py @@ -1,7 +1,7 @@ # Misspelled so as not be picked up by nosetests. -def lint_tests(tool_xml, lint_ctx): +def lint_tsts(tool_xml, lint_ctx): tests = tool_xml.findall("./tests/test") if not tests: lint_ctx.warn("No tests found, most tools should define test cases.") https://bitbucket.org/galaxy/galaxy-central/commits/da996e89dbfb/ Changeset: da996e89dbfb User: dannon Date: 2015-03-09 03:51:39+00:00 Summary: Minor cleanup, removal of unnecessarily duplicated vars in workflow/render Affected #: 1 file diff -r cd2aed870c002601dbc2913dc82146089e451748 -r da996e89dbfb8249deeeafd30489a62970f8af7d lib/galaxy/workflow/render.py --- a/lib/galaxy/workflow/render.py +++ b/lib/galaxy/workflow/render.py @@ -14,21 +14,17 @@ self.text = svgfig.SVG( "g" ) self.connectors = svgfig.SVG( "g" ) self.boxes = svgfig.SVG( "g" ) - svgfig.Text.defaults[ "font-size" ] = "10px" - self.in_pos = {} self.out_pos = {} self.widths = {} self.max_x = 0 self.max_y = 0 self.max_width = 0 - self.data = [] def finish( self ): max_x, max_y, max_width = self.max_x, self.max_y, self.max_width - canvas = self.canvas canvas.append( self.connectors ) canvas.append( self.boxes ) @@ -39,19 +35,16 @@ canvas[ 'viewBox' ] = "0 0 %s %s" % ( width, height ) def add_boxes( self, step_dict, width, name_fill ): - margin = MARGIN - line_px = LINE_SPACING - x, y = step_dict[ 'position' ][ 'left' ], step_dict[ 'position' ][ 'top' ] - self.boxes.append( svgfig.Rect( x - margin, y, x + width - margin, y + 30, fill=name_fill ).SVG() ) - box_height = ( len( step_dict[ 'data_inputs' ] ) + len( step_dict[ 'data_outputs' ] ) ) * line_px + margin + self.boxes.append( svgfig.Rect( x - MARGIN, y, x + width - MARGIN, y + 30, fill=name_fill ).SVG() ) + box_height = ( len( step_dict[ 'data_inputs' ] ) + len( step_dict[ 'data_outputs' ] ) ) * LINE_SPACING + MARGIN # Draw separator line. if len( step_dict[ 'data_inputs' ] ) > 0: box_height += 15 - sep_y = y + len( step_dict[ 'data_inputs' ] ) * line_px + 40 - self.text.append( svgfig.Line( x - margin, sep_y, x + width - margin, sep_y ).SVG() ) + sep_y = y + len( step_dict[ 'data_inputs' ] ) * LINE_SPACING + 40 + self.text.append( svgfig.Line( x - MARGIN, sep_y, x + width - MARGIN, sep_y ).SVG() ) # Define an input/output box. - self.boxes.append( svgfig.Rect( x - margin, y + 30, x + width - margin, y + 30 + box_height, fill="#ffffff" ).SVG() ) + self.boxes.append( svgfig.Rect( x - MARGIN, y + 30, x + width - MARGIN, y + 30 + box_height, fill="#ffffff" ).SVG() ) def add_text( self, module_data_inputs, module_data_outputs, step, module_name ): left, top = step.position[ 'left' ], step.position[ 'top' ] @@ -59,16 +52,12 @@ order_index = step.order_index max_len = len( module_name ) * 1.5 self.text.append( svgfig.Text( x, y + 20, module_name, **{ "font-size": "14px" } ).SVG() ) - y += 45 - count = 0 - line_px = LINE_SPACING in_pos = self.in_pos out_pos = self.out_pos - for di in module_data_inputs: - cur_y = y + count * line_px + cur_y = y + count * LINE_SPACING if order_index not in in_pos: in_pos[ order_index ] = {} in_pos[ order_index ][ di[ 'name' ] ] = ( x, cur_y ) @@ -78,7 +67,7 @@ if len( module_data_inputs ) > 0: y += 15 for do in module_data_outputs: - cur_y = y + count * line_px + cur_y = y + count * LINE_SPACING if order_index not in out_pos: out_pos[ order_index ] = {} out_pos[ order_index ][ do[ 'name' ] ] = ( x, cur_y ) @@ -91,8 +80,6 @@ self.max_width = max( self.max_width, self.widths[ order_index ] ) def add_connection( self, step_dict, conn, output_dict): - margin = MARGIN - in_coords = self.in_pos[ step_dict[ 'id' ] ][ conn ] # out_pos_index will be a step number like 1, 2, 3... out_pos_index = output_dict[ 'id' ] @@ -112,12 +99,12 @@ out_conn_pos = self.out_pos[ out_pos_index ][ key ] adjusted = ( out_conn_pos[ 0 ] + self.widths[ output_dict[ 'id' ] ], out_conn_pos[ 1 ] ) self.text.append( svgfig.SVG( "circle", - cx=out_conn_pos[ 0 ] + self.widths[ output_dict[ 'id' ] ] - margin, - cy=out_conn_pos[ 1 ] - margin, + cx=out_conn_pos[ 0 ] + self.widths[ output_dict[ 'id' ] ] - MARGIN, + cy=out_conn_pos[ 1 ] - MARGIN, r=5, fill="#ffffff" ) ) self.connectors.append( svgfig.Line( adjusted[ 0 ], - adjusted[ 1 ] - margin, + adjusted[ 1 ] - MARGIN, in_coords[ 0 ] - 10, in_coords[ 1 ], arrow_end="true" ).SVG() ) 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.