1111#include " WorkflowHelpers.h"
1212#include " Framework/AnalysisSupportHelpers.h"
1313#include " Framework/AlgorithmSpec.h"
14+ #include " Framework/CommonLabels.h"
1415#include " Framework/ConfigParamSpec.h"
1516#include " Framework/ConfigParamsHelper.h"
1617#include " Framework/CommonDataProcessors.h"
1718#include " Framework/ConfigContext.h"
19+ #include " Framework/DataProcessorSpecHelpers.h"
1820#include " Framework/DeviceSpec.h"
1921#include " Framework/DataSpecUtils.h"
2022#include " Framework/DataSpecViews.h"
3234#include " Headers/DataHeader.h"
3335#include < algorithm>
3436#include < list>
37+ #include < map>
3538#include < set>
3639#include < utility>
3740#include < vector>
@@ -959,7 +962,7 @@ WorkflowParsingState WorkflowHelpers::verifyWorkflow(const o2::framework::Workfl
959962 if (workflow.empty ()) {
960963 return WorkflowParsingState::Empty;
961964 }
962- std::set <std::string> validNames;
965+ std::map <std::string, size_t > validNames;
963966 // std::vector<OutputSpec> availableOutputs;
964967 // std::vector<InputSpec> requiredInputs;
965968
@@ -971,17 +974,25 @@ WorkflowParsingState WorkflowHelpers::verifyWorkflow(const o2::framework::Workfl
971974
972975 std::ostringstream ss;
973976
974- for (auto & spec : workflow) {
977+ for (size_t si = 0 ; si < workflow.size (); ++si) {
978+ auto & spec = workflow[si];
975979 if (spec.name .empty ()) {
976980 throw std::runtime_error (" Invalid DataProcessorSpec name" );
977981 }
978982 if (strpbrk (spec.name .data (), " ,;:\" '$" ) != nullptr ) {
979983 throw std::runtime_error (" Cannot use any of ,;:\" '$ as DataProcessor name" );
980984 }
981- if (validNames.find (spec.name ) != validNames.end ()) {
982- throw std::runtime_error (" Name " + spec.name + " is used twice." );
985+ auto it = validNames.find (spec.name );
986+ if (it != validNames.end ()) {
987+ auto & firstSpec = workflow[it->second ];
988+ if (!DataProcessorSpecHelpers::hasLabel (firstSpec, allowDuplicatesLabel.value .c_str ()) ||
989+ !DataProcessorSpecHelpers::hasLabel (spec, allowDuplicatesLabel.value .c_str ())) {
990+ throw std::runtime_error (" Name " + spec.name + " is used twice." );
991+ }
992+ LOG (warning) << " Duplicate DataProcessorSpec " << spec.name << " found with allow-duplicates label. Will be deduplicated." ;
993+ continue ;
983994 }
984- validNames.insert (spec.name );
995+ validNames.emplace (spec.name , si );
985996 for (auto & option : spec.options ) {
986997 if (option.defaultValue .type () != VariantType::Empty &&
987998 option.type != option.defaultValue .type ()) {
@@ -1005,6 +1016,22 @@ WorkflowParsingState WorkflowHelpers::verifyWorkflow(const o2::framework::Workfl
10051016 return WorkflowParsingState::Valid;
10061017}
10071018
1019+ void WorkflowHelpers::removeDuplicates (WorkflowSpec& workflow)
1020+ {
1021+ std::set<std::string> seen;
1022+ auto it = std::remove_if (workflow.begin (), workflow.end (), [&seen](DataProcessorSpec const & spec) {
1023+ if (seen.find (spec.name ) == seen.end ()) {
1024+ seen.insert (spec.name );
1025+ return false ;
1026+ }
1027+ if (!DataProcessorSpecHelpers::hasLabel (spec, allowDuplicatesLabel.value .c_str ())) {
1028+ return false ;
1029+ }
1030+ return true ;
1031+ });
1032+ workflow.erase (it, workflow.end ());
1033+ }
1034+
10081035using UnifiedDataSpecType = std::variant<InputSpec, OutputSpec>;
10091036struct DataMatcherId {
10101037 size_t workflowId;
0 commit comments