Line data Source code
1 : /****************************************************************************** 2 : * 3 : * Project: GDAL 4 : * Purpose: gdal "mdim pipeline" subcommand 5 : * Author: Even Rouault <even dot rouault at spatialys.com> 6 : * 7 : ****************************************************************************** 8 : * Copyright (c) 2026, Even Rouault <even dot rouault at spatialys.com> 9 : * 10 : * SPDX-License-Identifier: MIT 11 : ****************************************************************************/ 12 : 13 : #include "gdalalg_mdim_pipeline.h" 14 : #include "gdalalg_mdim_compare.h" 15 : #include "gdalalg_mdim_read.h" 16 : #include "gdalalg_mdim_write.h" 17 : #include "gdalalg_mdim_info.h" 18 : #include "gdalalg_mdim_mosaic.h" 19 : #include "gdalalg_mdim_reproject.h" 20 : 21 : #include "cpl_conv.h" 22 : #include "cpl_progress.h" 23 : #include "cpl_string.h" 24 : #include "cpl_vsi.h" 25 : #include "gdal_priv.h" 26 : #include "gdal_utils.h" 27 : 28 : #include <algorithm> 29 : #include <array> 30 : #include <cassert> 31 : 32 : //! @cond Doxygen_Suppress 33 : 34 : #ifndef _ 35 : #define _(x) (x) 36 : #endif 37 : 38 : GDALMdimAlgorithmStepRegistry::~GDALMdimAlgorithmStepRegistry() = default; 39 : 40 : /************************************************************************/ 41 : /* GDALMdimPipelineStepAlgorithm::GDALMdimPipelineStepAlgorithm() */ 42 : /************************************************************************/ 43 : 44 306 : GDALMdimPipelineStepAlgorithm::GDALMdimPipelineStepAlgorithm( 45 : const std::string &name, const std::string &description, 46 306 : const std::string &helpURL, const ConstructorOptions &options) 47 306 : : GDALPipelineStepAlgorithm(name, description, helpURL, options) 48 : { 49 306 : if (m_standaloneStep) 50 : { 51 284 : m_supportsStreamedOutput = true; 52 : 53 284 : if (m_constructorOptions.addDefaultArguments) 54 : { 55 44 : AddMdimInputArgs(false, false, /* acceptRaster = */ false); 56 44 : AddProgressArg(); 57 44 : AddMdimOutputArgs(false); 58 : } 59 : } 60 22 : else if (m_constructorOptions.addDefaultArguments) 61 : { 62 8 : AddMdimHiddenInputDatasetArg(); 63 : } 64 306 : } 65 : 66 : GDALMdimPipelineStepAlgorithm::~GDALMdimPipelineStepAlgorithm() = default; 67 : 68 : /************************************************************************/ 69 : /* GDALMdimPipelineAlgorithm::GDALMdimPipelineAlgorithm() */ 70 : /************************************************************************/ 71 : 72 53 : GDALMdimPipelineAlgorithm::GDALMdimPipelineAlgorithm( 73 53 : bool openForMixedMdimVector) 74 : : GDALAbstractPipelineAlgorithm(NAME, DESCRIPTION, HELP_URL, 75 0 : ConstructorOptions() 76 53 : .SetAddDefaultArguments(false) 77 53 : .SetInputDatasetRequired(false) 78 53 : .SetInputDatasetPositional(false) 79 106 : .SetInputDatasetMaxCount(INT_MAX)) 80 : { 81 53 : m_supportsStreamedOutput = true; 82 : 83 53 : AddMdimInputArgs(openForMixedMdimVector, /* hiddenForCLI = */ true, 84 : /* acceptRaster = */ false); 85 53 : AddProgressArg(); 86 106 : AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline) 87 53 : .SetHiddenForCLI() 88 53 : .SetPositional(); 89 53 : AddMdimOutputArgs(/* hiddenForCLI = */ true); 90 : 91 53 : AddOutputStringArg(&m_output).SetHiddenForCLI(); 92 53 : AddStdoutArg(&m_stdout); 93 : 94 53 : RegisterAlgorithms(m_stepRegistry, false); 95 53 : } 96 : 97 : /************************************************************************/ 98 : /* GDALMdimPipelineAlgorithm::RegisterAlgorithms() */ 99 : /************************************************************************/ 100 : 101 : /* static */ 102 53 : void GDALMdimPipelineAlgorithm::RegisterAlgorithms( 103 : GDALMdimAlgorithmStepRegistry ®istry, bool forMixedPipeline) 104 : { 105 53 : GDALAlgorithmRegistry::AlgInfo algInfo; 106 : 107 : const auto addSuffixIfNeeded = 108 318 : [forMixedPipeline](const char *name) -> std::string 109 : { 110 318 : return forMixedPipeline ? std::string(name).append(MULTIDIM_SUFFIX) 111 636 : : std::string(name); 112 53 : }; 113 : 114 53 : registry.Register<GDALMdimReadAlgorithm>( 115 106 : addSuffixIfNeeded(GDALMdimReadAlgorithm::NAME)); 116 : 117 53 : registry.Register<GDALMdimMosaicAlgorithm>( 118 106 : addSuffixIfNeeded(GDALMdimMosaicAlgorithm::NAME)); 119 : 120 53 : registry.Register<GDALMdimCompareAlgorithm>( 121 106 : addSuffixIfNeeded(GDALMdimCompareAlgorithm::NAME)); 122 : 123 53 : registry.Register<GDALMdimWriteAlgorithm>( 124 106 : addSuffixIfNeeded(GDALMdimWriteAlgorithm::NAME)); 125 : 126 53 : registry.Register<GDALMdimInfoAlgorithm>( 127 106 : addSuffixIfNeeded(GDALMdimInfoAlgorithm::NAME)); 128 : 129 53 : registry.Register<GDALMdimReprojectAlgorithm>( 130 106 : addSuffixIfNeeded(GDALMdimReprojectAlgorithm::NAME)); 131 53 : } 132 : 133 : /************************************************************************/ 134 : /* GDALMdimPipelineAlgorithm::GetUsageForCLI() */ 135 : /************************************************************************/ 136 : 137 3 : std::string GDALMdimPipelineAlgorithm::GetUsageForCLI( 138 : bool shortUsage, const UsageOptions &usageOptions) const 139 : { 140 3 : UsageOptions stepUsageOptions; 141 3 : stepUsageOptions.isPipelineStep = true; 142 : 143 3 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main") 144 : { 145 4 : auto alg = GetStepAlg(m_helpDocCategory); 146 2 : if (alg) 147 : { 148 2 : alg->SetCallPath({m_helpDocCategory}); 149 1 : alg->GetArg("help-doc")->Set(true); 150 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions); 151 : } 152 : else 153 : { 154 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n", 155 : m_helpDocCategory.c_str()); 156 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n", 157 1 : m_helpDocCategory.c_str()); 158 : } 159 : } 160 : 161 1 : UsageOptions usageOptionsMain(usageOptions); 162 1 : usageOptionsMain.isPipelineMain = true; 163 : std::string ret = 164 2 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain); 165 1 : if (shortUsage) 166 0 : return ret; 167 : 168 : ret += "\n<PIPELINE> is of the form: read|mosaic [READ-OPTIONS] " 169 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! info|write " 170 1 : "[WRITE-OPTIONS]\n"; 171 : 172 1 : if (m_helpDocCategory == "main") 173 : { 174 1 : return ret; 175 : } 176 : 177 0 : ret += '\n'; 178 0 : ret += "Example: 'gdal mdim pipeline --progress ! read in.nc ! \\\n"; 179 0 : ret += " reproject --output-crs=EPSG:32632 ! "; 180 0 : ret += "write out.nc --overwrite'\n"; 181 0 : ret += '\n'; 182 0 : ret += "Potential steps are:\n"; 183 : 184 0 : for (const std::string &name : m_stepRegistry.GetNames()) 185 : { 186 0 : auto alg = GetStepAlg(name); 187 0 : auto [options, maxOptLen] = alg->GetArgNamesForCLI(); 188 0 : stepUsageOptions.maxOptLen = 189 0 : std::max(stepUsageOptions.maxOptLen, maxOptLen); 190 : } 191 : 192 : { 193 0 : const auto name = GDALMdimReadAlgorithm::NAME; 194 0 : ret += '\n'; 195 0 : auto alg = GetStepAlg(name); 196 0 : alg->SetCallPath({name}); 197 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 198 : } 199 : { 200 0 : const auto name = GDALMdimMosaicAlgorithm::NAME; 201 0 : ret += '\n'; 202 0 : auto alg = GetStepAlg(name); 203 0 : alg->SetCallPath({name}); 204 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 205 : } 206 0 : for (const std::string &name : m_stepRegistry.GetNames()) 207 : { 208 0 : auto alg = GetStepAlg(name); 209 0 : assert(alg); 210 0 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() && 211 0 : !alg->IsHidden() && name != GDALMdimReadAlgorithm::NAME && 212 0 : name != GDALMdimMosaicAlgorithm::NAME) 213 : { 214 0 : ret += '\n'; 215 0 : alg->SetCallPath({name}); 216 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 217 : } 218 : } 219 0 : for (const std::string &name : m_stepRegistry.GetNames()) 220 : { 221 0 : auto alg = GetStepAlg(name); 222 0 : assert(alg); 223 0 : if (alg->CanBeMiddleStep() && !alg->IsHidden()) 224 : { 225 0 : ret += '\n'; 226 0 : alg->SetCallPath({name}); 227 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 228 : } 229 : } 230 0 : for (const std::string &name : m_stepRegistry.GetNames()) 231 : { 232 0 : auto alg = GetStepAlg(name); 233 0 : assert(alg); 234 0 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() && 235 0 : !alg->IsHidden() && name != GDALMdimWriteAlgorithm::NAME) 236 : { 237 0 : ret += '\n'; 238 0 : alg->SetCallPath({name}); 239 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 240 : } 241 : } 242 : { 243 0 : const auto name = GDALMdimWriteAlgorithm::NAME; 244 0 : ret += '\n'; 245 0 : auto alg = GetStepAlg(name); 246 0 : alg->SetCallPath({name}); 247 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 248 : } 249 0 : ret += GetUsageForCLIEnd(); 250 : 251 0 : return ret; 252 : } 253 : 254 : //! @endcond