3 Copyright [1999-2015] Wellcome Trust Sanger Institute and the EMBL-European Bioinformatics Institute
4 Copyright [2016-2022] EMBL-European Bioinformatics Institute
6 Licensed under the Apache License, Version 2.0 (the
"License");
7 you may not use
this file except in compliance with the License.
8 You may obtain a copy of the License at
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an
"AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License
for the specific language governing permissions and
16 limitations under the License.
20 package Bio::EnsEMBL::Hive::HivePipeline;
32 # needed for offline graph generation: 41 $self->{
'_hive_dba'} = shift @_;
42 $self->{
'_hive_dba'}->hive_pipeline($self)
if $self->{
'_hive_dba'};
44 return $self->{
'_hive_dba'};
51 if(my $dbc = $self->hive_dba && $self->hive_dba->dbc) {
52 return $dbc->dbname .
'@' .($dbc->host||
'');
59 sub unambig_key { # based on DBC
's URL if present, otherwise on pipeline_name 62 if(my $dbc = $self->hive_dba && $self->hive_dba->dbc) { 63 return Bio::EnsEMBL::Hive::Utils::URL::hash_to_unambig_url( $dbc->to_url_hash ); 65 return 'unstored:
'.$self->hive_pipeline_name; 75 $self->{'_cache_by_class
'}->{$type} = shift @_; 76 } elsif (not $self->{'_cache_by_class
'}->{$type}) { 79 my $adaptor = $hive_dba->get_adaptor( $type ); 80 my $all_objects = $adaptor->fetch_all(); 81 if(@$all_objects and UNIVERSAL::can($all_objects->[0], 'hive_pipeline
') ) { 82 $_->hive_pipeline($self) for @$all_objects; 84 $self->{'_cache_by_class
'}->{$type} = Bio::EnsEMBL::Hive::Utils::Collection->new( $all_objects ); 85 # warn "initialized collection_of($type) by loading all ".scalar(@$all_objects)."\n"; 87 $self->{'_cache_by_class
'}->{$type} = Bio::EnsEMBL::Hive::Utils::Collection->new(); 88 # warn "initialized collection_of($type) as an empty one\n"; 92 return $self->{'_cache_by_class
'}->{$type}; 98 my $query_params = shift @_; 99 my $no_die = shift @_; 101 if(my $object_type = delete $query_params->{'object_type
'}) { 106 unless($object = $self->collection_of($object_type)->find_one_by( %$query_params )) { 108 my @specific_adaptor_params = ($object_type eq 'NakedTable') 109 ? ('table_name
' => $query_params->{'table_name
'}, 110 $query_params->{'insertion_method
'} 111 ? ('insertion_method
' => $query_params->{'insertion_method
'}) 115 ($object) = $self->add_new_or_update( $object_type, # NB: add_new_or_update returns a list 117 $self->hive_dba ? ('adaptor
' => $self->hive_dba->get_adaptor($object_type, @specific_adaptor_params)) : (), 122 my $dbID = $query_params->{$id_name}; 123 my $coll = $self->collection_of($object_type); 124 unless($object = $coll->find_one_by( 'dbID
' => $dbID )) { 126 my $adaptor = $self->hive_dba->get_adaptor( $object_type ); 127 if( $object = $adaptor->fetch_by_dbID( $dbID ) ) { 128 $coll->add( $object ); 132 $object = $self->collection_of($object_type)->find_one_by( %$query_params ); 135 return $object if $object || $no_die; 136 throw("Could not find an '$object_type
' object from query ".stringify($query_params)." in ".$self->display_name); 139 throw("Could not find or guess the object_type from the query ".stringify($query_params)." , so could not find the object"); 143 sub test_connections { 149 my $analysis_url = $dft->to_analysis_url; 150 if ($analysis_url =~ m{^\w+$}) { 151 my $heir_analysis = $self->collection_of('Analysis')->find_one_by('logic_name
', $analysis_url) 152 or push @warnings, "Could not find a local analysis named '$analysis_url
' (dataflow from analysis '".($dft->source_dataflow_rule->from_analysis->logic_name)."')"; 157 my $analysis_url = $cf->condition_analysis_url; 158 if ($analysis_url =~ m{^\w+$}) { 159 my $heir_analysis = $self->collection_of('Analysis')->find_one_by('logic_name
', $analysis_url) 160 or push @warnings, "Could not find a local analysis named '$analysis_url
' (control-flow for analysis '".($cf->ctrled_analysis->logic_name)."')"; 166 push @warnings, '', 'Please fix these before running the pipeline
'; 167 warn join("\n", '', '#
' . '-
' x 26 . '[WARNINGS]
' . '-
' x 26, '', @warnings), "\n"; 172 sub new { # construct an attached or a detached Pipeline object 173 my $class = shift @_; 175 my $self = bless {}, $class; 178 my $existing_dba = delete $dba_flags{'-dba
'}; 181 my $hive_dba = Bio::EnsEMBL::Hive::DBSQL::DBAdaptor->new( %dba_flags ); 182 $self->hive_dba( $hive_dba ); 183 } elsif ($existing_dba) { 184 $self->hive_dba( $existing_dba ); 186 # warn "Created a standalone pipeline"; 189 Bio::EnsEMBL::Hive::TheApiary->pipelines_collection->add( $self ); 195 # If there is a DBAdaptor, collection_of() will fetch a collection on demand: 196 sub invalidate_collections { 199 delete $self->{'_cache_by_class
'}; 204 sub save_collections { 207 my $hive_dba = $self->hive_dba(); 211 foreach my $AdaptorType (reverse @adaptor_types) { 212 my $adaptor = $hive_dba->get_adaptor( $AdaptorType ); 213 my $coll = $self->collection_of( $AdaptorType ); 214 if( my $dark_collection = $coll->dark_collection) { 215 foreach my $obj_to_be_deleted ( $coll->dark_collection->list ) { 216 $adaptor->remove( $obj_to_be_deleted ); 217 # warn "Deleted ".(UNIVERSAL::can($obj_to_be_deleted, 'toString
') ? $obj_to_be_deleted->toString : stringify($obj_to_be_deleted))."\n"; 219 $coll->dark_collection( undef ); 223 foreach my $AdaptorType (@adaptor_types) { 224 my $adaptor = $hive_dba->get_adaptor( $AdaptorType ); 226 my $coll = $self->collection_of( $AdaptorType ); 227 foreach my $storable_object ( $coll->list ) { 228 $adaptor->store_or_update_one( $storable_object, $class->unikey() ); 229 # warn "Stored/updated ".$storable_object->toString()."\n"; 233 my $job_adaptor = $hive_dba->get_AnalysisJobAdaptor; 234 foreach my $analysis ( $self->collection_of( 'Analysis' )->list ) { 235 if(my $our_jobs = $analysis->jobs_collection ) { 236 $job_adaptor->store( $our_jobs ); 237 # foreach my $job (@$our_jobs) { 238 # warn "Stored ".$job->toString()."\n"; 245 sub add_new_or_update { 249 # $verbose is an extra optional argument that sits between the type and the object hash 250 my $verbose = scalar(@_) % 2 ? shift : 0; 253 my $coll = $self->collection_of( $type ); 258 if( my $unikey_keys = $class->unikey() ) { 259 my %other_pairs = @_; 261 @unikey_pairs{ @$unikey_keys} = delete @other_pairs{ @$unikey_keys }; 263 if( $object = $coll->find_one_by( %unikey_pairs ) ) { 264 my $found_display = $verbose && (UNIVERSAL::can($object, 'toString
') ? $object->toString : stringify($object)); 265 if(keys %other_pairs) { 266 print "Updating $found_display with (".stringify(\%other_pairs).")\n" if $verbose; 267 if( ref($object) eq 'HASH
' ) { 268 @$object{ keys %other_pairs } = values %other_pairs; 270 while( my ($key, $value) = each %other_pairs ) { 271 $object->$key($value); 275 print "Found a matching $found_display\n" if $verbose; 277 } elsif( my $dark_coll = $coll->dark_collection) { 278 if( my $shadow_object = $dark_coll->find_one_by( %unikey_pairs ) ) { 279 $dark_coll->forget( $shadow_object ); 280 my $found_display = $verbose && (UNIVERSAL::can($shadow_object, 'toString
') ? $shadow_object->toString : stringify($shadow_object)); 281 print "Undeleting $found_display\n" if $verbose; 285 warn "$class doesn't redefine unikey(), so unique objects cannot be identified
"; 289 $object = $class->can('new') ? $class->new( @_ ) : { @_ }; 292 $coll->add( $object ); 294 $object->hive_pipeline($self) if UNIVERSAL::can($object, 'hive_pipeline'); 296 my $found_display = $verbose && (UNIVERSAL::can($object, 'toString') ? $object->toString : 'naked entry '.stringify($object)); 297 print "Created a
new $found_display\n
" if $verbose; 300 return ($object, $newly_made); 304 =head2 get_source_analyses 306 Description: returns a listref of analyses that do not have local inflow ("source analyses
") 310 sub get_source_analyses { 313 my %analyses_to_discard = map {scalar($_->to_analysis) => 1} $self->collection_of( 'DataflowTarget' )->list; 315 return [grep {!$analyses_to_discard{"$_
"}} $self->collection_of( 'Analysis' )->list]; 319 =head2 _meta_value_by_key 321 Description: getter/setter for a particular meta_value from 'MetaParameters' collection given meta_key 325 sub _meta_value_by_key { 327 my $meta_key= shift @_; 329 my $hash = $self->collection_of( 'MetaParameters' )->find_one_by( 'meta_key', $meta_key ); 332 my $new_value = shift @_; 335 $hash->{'meta_value'} = $new_value; 337 ($hash) = $self->add_new_or_update( 'MetaParameters', 338 'meta_key' => $meta_key, 339 'meta_value' => $new_value, 344 return $hash && $hash->{'meta_value'}; 348 =head2 hive_use_param_stack 350 Description: getter/setter via MetaParameters. Defines which one of two modes of parameter propagation is used in this pipeline 354 sub hive_use_param_stack { 357 return $self->_meta_value_by_key('hive_use_param_stack', @_) // 0; 361 =head2 hive_pipeline_name 363 Description: getter/setter via MetaParameters. Defines the symbolic name of the pipeline. 367 sub hive_pipeline_name { 370 return $self->_meta_value_by_key('hive_pipeline_name', @_) // ''; 374 =head2 hive_auto_rebalance_semaphores 376 Description: getter/setter via MetaParameters. Defines whether beekeeper should attempt to rebalance semaphores on each iteration. 380 sub hive_auto_rebalance_semaphores { 383 return $self->_meta_value_by_key('hive_auto_rebalance_semaphores', @_) // '0'; 387 =head2 hive_use_triggers 389 Description: getter via MetaParameters. Defines whether SQL triggers are used to automatically update AnalysisStats counters 393 sub hive_use_triggers { 397 throw('HivePipeline::hive_use_triggers is not settable, it is only a getter'); 400 return $self->_meta_value_by_key('hive_use_triggers') // '0'; 403 =head2 hive_default_max_retry_count 405 Description: getter/setter via MetaParameters. Defines the default value for analysis_base.max_retry_count 409 sub hive_default_max_retry_count { 412 return $self->_meta_value_by_key('hive_default_max_retry_count', @_) // 0; 416 =head2 list_all_hive_tables 418 Description: getter via MetaParameters. Lists the (MySQL) table names used by the HivePipeline 422 sub list_all_hive_tables { 426 throw('HivePipeline::list_all_hive_tables is not settable, it is only a getter'); 429 return [ split /,/, ($self->_meta_value_by_key('hive_all_base_tables') // '') ]; 433 =head2 list_all_hive_views 435 Description: getter via MetaParameters. Lists the (MySQL) view names used by the HivePipeline 439 sub list_all_hive_views { 443 throw('HivePipeline::list_all_hive_views is not settable, it is only a getter'); 446 return [ split /,/, ($self->_meta_value_by_key('hive_all_views') // '') ]; 450 =head2 hive_sql_schema_version 452 Description: getter via MetaParameters. Defines the Hive SQL schema version of the database if it has been stored 456 sub hive_sql_schema_version { 460 throw('HivePipeline::hive_sql_schema_version is not settable, it is only a getter'); 463 return $self->_meta_value_by_key('hive_sql_schema_version') // 'N/A'; 467 =head2 params_as_hash 469 Description: returns the destringified contents of the 'PipelineWideParameters' collection as a hash 476 my $collection = $self->collection_of( 'PipelineWideParameters' ); 477 return { map { $_->{'param_name'} => destringify($_->{'param_value'}) } $collection->list() }; 481 =head2 get_cached_hive_current_load 483 Description: Proxy for RoleAdaptor::get_hive_current_load() that caches the last value. 487 sub get_cached_hive_current_load { 490 if (not exists $self->{'_cached_hive_load'}) { 491 if ($self->hive_dba) { 492 $self->{'_cached_hive_load'} = $self->hive_dba->get_RoleAdaptor->get_hive_current_load(); 494 $self->{'_cached_hive_load'} = 0; 497 return $self->{'_cached_hive_load'}; 501 =head2 invalidate_hive_current_load 503 Description: Method that forces the next get_cached_hive_current_load() call to fetch a fresh value from the database 507 sub invalidate_hive_current_load { 510 delete $self->{'_cached_hive_load'}; 516 Description: prints a "Unicode art
" textual representation of the pipeline's flow diagram 523 print ''.('─'x20).'[ '.$self->display_name.' ]'.('─'x20)."\n
"; 526 foreach my $source_analysis ( @{ $self->get_source_analyses } ) { 528 $source_analysis->print_diagram_node($self, '', \%seen); 530 foreach my $cyclic_analysis ( $self->collection_of( 'Analysis' )->list ) { 531 next if $seen{$cyclic_analysis}; 533 $cyclic_analysis->print_diagram_node($self, '', \%seen); 540 Description: changes attributes of Analyses|ResourceClasses|ResourceDescriptions or values of pipeline/analysis parameters 546 my $tweaks = shift @_; 550 foreach my $tweak (@$tweaks) { 551 print "\nTweak.Request\t$tweak\n
"; 553 if($tweak=~/^pipeline\.param\[(\w+)\](\?|#|=(.+))$/) { 554 my ($param_name, $operator, $new_value_str) = ($1, $2, $3); 556 my $pwp_collection = $self->collection_of( 'PipelineWideParameters' ); 557 my $hash_pair = $pwp_collection->find_one_by('param_name', $param_name); 559 if($operator eq '?') { 560 print "Tweak.Show \tpipeline.param[$param_name] ::\t
" 561 . ($hash_pair ? $hash_pair->{'param_value'} : '(missing_value)') . "\n
"; 562 } elsif($operator eq '#') { 565 $pwp_collection->forget_and_mark_for_deletion( $hash_pair ); 566 print "Tweak.Deleting\tpipeline.param[$param_name] ::\t
".stringify($hash_pair->{'param_value'})." --> (missing value)\n
"; 568 print "Tweak.Deleting\tpipeline.param[$param_name] skipped (does not exist)\n
"; 572 my $new_value = destringify( $new_value_str ); 573 $new_value_str = stringify($new_value); 576 print "Tweak.Changing\tpipeline.param[$param_name] ::\t$hash_pair->{
'param_value'} --> $new_value_str\n
"; 578 $hash_pair->{'param_value'} = $new_value_str; 580 print "Tweak.Adding \tpipeline.param[$param_name] ::\t(missing value) --> $new_value_str\n
"; 582 $self->add_new_or_update( 'PipelineWideParameters', 583 'param_name' => $param_name, 584 'param_value' => $new_value_str, 589 } elsif($tweak=~/^pipeline\.(\w+)(\?|=(.+))$/) { 590 my ($attrib_name, $operator, $new_value_str) = ($1, $2, $3); 592 if($self->can($attrib_name)) { 593 my $old_value = stringify( $self->$attrib_name() ); 595 if($operator eq '?') { 596 print "Tweak.Show \tpipeline.$attrib_name ::\t$old_value\n
"; 598 print "Tweak.Changing\tpipeline.$attrib_name ::\t$old_value --> $new_value_str\n
"; 600 $self->$attrib_name( $new_value_str ); 605 print "Tweak.Error \tCould not find the pipeline-wide
'$attrib_name' method\n
"; 608 } elsif($tweak=~/^analysis\[([^\]]+)\]\.param\[(\w+)\](\?|#|=(.+))$/) { 609 my ($analyses_pattern, $param_name, $operator, $new_value_str) = ($1, $2, $3, $4); 611 my $analyses = $self->collection_of( 'Analysis' )->find_all_by_pattern( $analyses_pattern ); 612 print "Tweak.Found \t
".scalar(@$analyses)." analyses matching the pattern
'$analyses_pattern'\n
"; 614 my $new_value = destringify( $new_value_str ); 615 $new_value_str = stringify( $new_value ); 617 foreach my $analysis (@$analyses) { 618 my $analysis_name = $analysis->logic_name; 620 my $old_value = $analysis->parameters; 622 my $param_hash = destringify( $old_value ); 624 if($operator eq '?') { 625 print "Tweak.Show \tanalysis[$analysis_name].param[$param_name] ::\t
" 626 . (exists($param_hash->{ $param_name }) ? stringify($param_hash->{ $param_name }) : '(missing value)') 628 } elsif($operator eq '#') { 629 print "Tweak.Deleting\tanalysis[$analysis_name].param[$param_name] ::\t
".stringify($param_hash->{ $param_name })." --> (missing value)\n
"; 631 delete $param_hash->{ $param_name }; 632 $analysis->parameters( stringify($param_hash) ); 635 if(exists($param_hash->{ $param_name })) { 636 print "Tweak.Changing\tanalysis[$analysis_name].param[$param_name] ::\t
".stringify($param_hash->{ $param_name })." --> $new_value_str\n
"; 638 print "Tweak.Adding \tanalysis[$analysis_name].param[$param_name] ::\t(missing value) --> $new_value_str\n
"; 641 $param_hash->{ $param_name } = $new_value; 642 $analysis->parameters( stringify($param_hash) ); 647 } elsif($tweak=~/^analysis\[([^\]]+)\]\.(wait_for|flow_into)(\?|#|\+?=(.+))$/) { 648 my ($analyses_pattern, $attrib_name, $operation, $new_value_str) = ($1, $2, $3, $4); 649 $operation=~/^(\?|#|\+?=)/; 652 my $analyses = $self->collection_of( 'Analysis' )->find_all_by_pattern( $analyses_pattern ); 653 print "Tweak.Found \t
".scalar(@$analyses)." analyses matching the pattern
'$analyses_pattern'\n
"; 655 my $new_value = destringify( $new_value_str ); 657 foreach my $analysis (@$analyses) { 659 my $analysis_name = $analysis->logic_name; 661 if( $attrib_name eq 'wait_for' ) { 663 my $cr_collection = $self->collection_of( 'AnalysisCtrlRule' ); 664 my $acr_collection = $analysis->control_rules_collection; 666 if($operator eq '?') { 667 print "Tweak.Show \tanalysis[$analysis_name].wait_for ::\t[
".join(', ', map { $_->condition_analysis_url } @$acr_collection )."]\n
"; 670 if($operator eq '#' or $operator eq '=') { # delete the existing rules 671 foreach my $c_rule ( @$acr_collection ) { 672 $cr_collection->forget_and_mark_for_deletion( $c_rule ); 675 print "Tweak.Deleting\t
".$c_rule->toString." --> (missing value)\n
"; 679 if($operator eq '=' or $operator eq '+=') { # create new rules 680 Bio::EnsEMBL::Hive::Utils::PCL::parse_wait_for($self, $analysis, $new_value); 681 foreach my $c_rule ( @{$analysis->control_rules_collection} ) { 682 print "Tweak.Adding\t
".$c_rule->toString."\n
"; 687 } elsif( $attrib_name eq 'flow_into' ) { 689 if($operator eq '?') { 690 # FIXME: should not recurse 691 $analysis->print_diagram_node($self, '', {}); 694 if($operator eq '#' or $operator eq '=') { # delete the existing rules 695 my $dfr_collection = $self->collection_of( 'DataflowRule' ); 696 my $dft_collection = $self->collection_of( 'DataflowTarget' ); 698 foreach my $group ( @{$analysis->get_grouped_dataflow_rules} ) { 699 my ($funnel_dfr, $fan_dfrs, $funnel_df_targets) = @$group; 701 foreach my $df_rule (@$fan_dfrs, $funnel_dfr) { 703 foreach my $df_target ( @{$df_rule->get_my_targets} ) { 704 $dft_collection->forget_and_mark_for_deletion( $df_target ); 706 print "Tweak.Deleting\t
".$df_target->toString." --> (missing value)\n
"; 708 $dfr_collection->forget_and_mark_for_deletion( $df_rule ); 711 print "Tweak.Deleting\t
".$df_rule->toString." --> (missing value)\n
"; 716 if($operator eq '=' or $operator eq '+=') { # create new rules 718 Bio::EnsEMBL::Hive::Utils::PCL::parse_flow_into($self, $analysis, $new_value ); 723 } elsif($tweak=~/^analysis\[([^\]]+)\]\.(\w+)(\?|#|=(.+))$/) { 724 my ($analyses_pattern, $attrib_name, $operator, $new_value_str) = ($1, $2, $3, $4); 726 my $analyses = $self->collection_of( 'Analysis' )->find_all_by_pattern( $analyses_pattern ); 727 print "Tweak.Found \t
".scalar(@$analyses)." analyses matching the pattern
'$analyses_pattern'\n
"; 729 my $new_value = destringify( $new_value_str ); 731 foreach my $analysis (@$analyses) { 733 my $analysis_name = $analysis->logic_name; 735 if( $attrib_name eq 'resource_class' ) { 737 if($operator eq '?') { 738 my $old_value = $analysis->resource_class; 739 print "Tweak.Show \tanalysis[$analysis_name].resource_class ::\t
".$old_value->name."\n
"; 740 } elsif($operator eq '#') { 741 print "Tweak.Error \tDeleting of an
Analysis' resource-class is not supported\n"; 744 my $old_value = $analysis->resource_class; 745 print "Tweak.Changing\tanalysis[$analysis_name].resource_class ::\t".$old_value->name." --> $new_value_str\n"; 748 if($resource_class = $self->collection_of( 'ResourceClass' )->find_one_by( 'name
', $new_value )) { 749 print "Tweak.Found \tresource_class[$new_value_str]\n"; 750 $analysis->resource_class( $resource_class ); 753 print "Tweak.Error \t'$new_value_str
' is not a known resource-class\n"; 758 } elsif( $attrib_name eq 'is_excluded
' ) { 759 my $analysis_stats = $analysis->stats(); 760 if($operator eq '?
') { 761 print "Tweak.Show \tanalysis[$analysis_name].is_excluded ::\t".$analysis_stats->is_excluded()."\n"; 762 } elsif($operator eq '#
') { 763 print "Tweak.Error \tDeleting of excluded status is not supported\n"; 765 if(!($new_value =~ /^[01]$/)) { 766 print "Tweak.Error \tis_excluded can only be 0 (no) or 1 (yes)\n"; 767 } elsif ($new_value == $analysis_stats->is_excluded()) { 768 print "Tweak.Info \tanalysis[$analysis_name].is_excluded is already $new_value, leaving as is\n"; 770 print "Tweak.Changing\tanalysis[$analysis_name].is_excluded ::\t" . 771 $analysis_stats->is_excluded() . " --> $new_value_str\n"; 772 $analysis_stats->is_excluded($new_value); 776 } elsif( $attrib_name eq 'dbID
' ) { 777 print "Tweak.Error \tChanging the dbID of an Analysis is not supported\n"; 779 } elsif($analysis->can($attrib_name)) { 780 my $old_value = stringify($analysis->$attrib_name()); 782 if($operator eq '?
') { 783 print "Tweak.Show \tanalysis[$analysis_name].$attrib_name ::\t$old_value\n"; 784 } elsif($operator eq '#
') { 785 print "Tweak.Error \tDeleting of Analysis attributes is not supported\n"; 787 print "Tweak.Changing\tanalysis[$analysis_name].$attrib_name ::\t$old_value --> ".stringify($new_value)."\n"; 789 $analysis->$attrib_name( $new_value ); 793 print "Tweak.Error \tAnalysis does not support '$attrib_name
' attribute\n"; 797 } elsif($tweak=~/^resource_class\[([^\]]+)\]\.(\w+)(\?|=(.+))$/) { 798 my ($rc_pattern, $meadow_type, $operator, $new_value_str) = ($1, $2, $3, $4); 800 my $resource_classes = $self->collection_of( 'ResourceClass' )->find_all_by_pattern( $rc_pattern ); 801 print "Tweak.Found \t".scalar(@$resource_classes)." resource_classes matching the pattern '$rc_pattern
'\n"; 803 if($operator eq '?
') { 804 foreach my $rc (@$resource_classes) { 805 my $rc_name = $rc->name; 807 if(my $rd = $self->collection_of( 'ResourceDescription' )->find_one_by('resource_class
', $rc, 'meadow_type
', $meadow_type)) { 808 my ($submission_cmd_args, $worker_cmd_args) = ($rd->submission_cmd_args, $rd->worker_cmd_args); 809 print "Tweak.Show \tresource_class[$rc_name].$meadow_type ::\t".stringify([$submission_cmd_args, $worker_cmd_args])."\n"; 811 print "Tweak.Show \tresource_class[$rc_name].$meadow_type ::\t(missing values)\n"; 817 # Auto-vivification of the ResourceClass 818 unless (@$resource_classes) { 819 print "Tweak.Adding \tresource_class[$rc_pattern]\n"; 820 my ($resource_class) = $self->add_new_or_update( 'ResourceClass', # NB: add_new_or_update returns a list 821 'name
' => $rc_pattern, 823 push @$resource_classes, $resource_class; 827 my $new_value = destringify( $new_value_str ); 828 my ($new_submission_cmd_args, $new_worker_cmd_args) = (ref($new_value) eq 'ARRAY
') ? @$new_value : ($new_value, ''); 830 foreach my $rc (@$resource_classes) { 831 my $rc_name = $rc->name; 833 if(my $rd = $self->collection_of( 'ResourceDescription' )->find_one_by('resource_class
', $rc, 'meadow_type
', $meadow_type)) { 834 my ($submission_cmd_args, $worker_cmd_args) = ($rd->submission_cmd_args, $rd->worker_cmd_args); 835 print "Tweak.Changing\tresource_class[$rc_name].$meadow_type :: " 836 .stringify([$submission_cmd_args, $worker_cmd_args])." --> " 837 .stringify([$new_submission_cmd_args, $new_worker_cmd_args])."\n"; 839 $rd->submission_cmd_args( $new_submission_cmd_args ); 840 $rd->worker_cmd_args( $new_worker_cmd_args ); 842 print "Tweak.Adding \tresource_class[$rc_name].$meadow_type :: (missing values) --> " 843 .stringify([$new_submission_cmd_args, $new_worker_cmd_args])."\n"; 845 my ($rd) = $self->add_new_or_update( 'ResourceDescription', # NB: add_new_or_update returns a list 846 'resource_class
' => $rc, 847 'meadow_type
' => $meadow_type, 848 'submission_cmd_args
' => $new_submission_cmd_args, 849 'worker_cmd_args
' => $new_worker_cmd_args, 857 print "Tweak.Error \tFailed to parse the tweak\n";
public hive_pipeline_name()