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 356 : GDALMdimPipelineStepAlgorithm::GDALMdimPipelineStepAlgorithm( 45 : const std::string &name, const std::string &description, 46 356 : const std::string &helpURL, const ConstructorOptions &options) 47 356 : : GDALPipelineStepAlgorithm(name, description, helpURL, options) 48 : { 49 356 : if (m_standaloneStep) 50 : { 51 295 : m_supportsStreamedOutput = true; 52 : 53 295 : if (m_constructorOptions.addDefaultArguments) 54 : { 55 47 : AddMdimInputArgs(false, false, /* acceptRaster = */ false); 56 47 : AddProgressArg(); 57 47 : AddMdimOutputArgs(false); 58 : } 59 : } 60 61 : else if (m_constructorOptions.addDefaultArguments) 61 : { 62 13 : AddMdimHiddenInputDatasetArg(); 63 : } 64 356 : } 65 : 66 : GDALMdimPipelineStepAlgorithm::~GDALMdimPipelineStepAlgorithm() = default; 67 : 68 : /************************************************************************/ 69 : /* GDALMdimPipelineAlgorithm::GDALMdimPipelineAlgorithm() */ 70 : /************************************************************************/ 71 : 72 55 : GDALMdimPipelineAlgorithm::GDALMdimPipelineAlgorithm( 73 55 : bool openForMixedMdimVector) 74 : : GDALAbstractPipelineAlgorithm( 75 : NAME, DESCRIPTION, HELP_URL, 76 0 : ConstructorOptions() 77 55 : .SetAddDefaultArguments(false) 78 55 : .SetInputDatasetRequired(false) 79 55 : .SetInputDatasetPositional(false) 80 55 : .SetInputDatasetMaxCount(INT_MAX) 81 110 : .SetMdimOutputAcceptsClassicRaster(true)) 82 : { 83 55 : m_supportsStreamedOutput = true; 84 : 85 55 : AddMdimInputArgs(openForMixedMdimVector, /* hiddenForCLI = */ true, 86 : /* acceptRaster = */ false); 87 55 : AddProgressArg(); 88 110 : AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline) 89 55 : .SetHiddenForCLI() 90 55 : .SetPositional(); 91 55 : AddMdimOutputArgs(/* hiddenForCLI = */ true); 92 : 93 55 : AddOutputStringArg(&m_output).SetHiddenForCLI(); 94 55 : AddStdoutArg(&m_stdout); 95 : 96 55 : RegisterAlgorithms(m_stepRegistry, false); 97 55 : } 98 : 99 : /************************************************************************/ 100 : /* GDALMdimPipelineAlgorithm::RegisterAlgorithms() */ 101 : /************************************************************************/ 102 : 103 : /* static */ 104 55 : void GDALMdimPipelineAlgorithm::RegisterAlgorithms( 105 : GDALMdimAlgorithmStepRegistry ®istry, bool forMixedPipeline) 106 : { 107 55 : GDALAlgorithmRegistry::AlgInfo algInfo; 108 : 109 : const auto addSuffixIfNeeded = 110 330 : [forMixedPipeline](const char *name) -> std::string 111 : { 112 330 : return forMixedPipeline ? std::string(name).append(MULTIDIM_SUFFIX) 113 660 : : std::string(name); 114 55 : }; 115 : 116 55 : registry.Register<GDALMdimReadAlgorithm>( 117 110 : addSuffixIfNeeded(GDALMdimReadAlgorithm::NAME)); 118 : 119 55 : registry.Register<GDALMdimMosaicAlgorithm>( 120 110 : addSuffixIfNeeded(GDALMdimMosaicAlgorithm::NAME)); 121 : 122 55 : registry.Register<GDALMdimCompareAlgorithm>( 123 110 : addSuffixIfNeeded(GDALMdimCompareAlgorithm::NAME)); 124 : 125 55 : registry.Register<GDALMdimWriteAlgorithm>( 126 110 : addSuffixIfNeeded(GDALMdimWriteAlgorithm::NAME)); 127 : 128 55 : registry.Register<GDALMdimInfoAlgorithm>( 129 110 : addSuffixIfNeeded(GDALMdimInfoAlgorithm::NAME)); 130 : 131 55 : registry.Register<GDALMdimReprojectAlgorithm>( 132 110 : addSuffixIfNeeded(GDALMdimReprojectAlgorithm::NAME)); 133 55 : } 134 : 135 : /************************************************************************/ 136 : /* GDALMdimPipelineAlgorithm::GetUsageForCLI() */ 137 : /************************************************************************/ 138 : 139 3 : std::string GDALMdimPipelineAlgorithm::GetUsageForCLI( 140 : bool shortUsage, const UsageOptions &usageOptions) const 141 : { 142 3 : UsageOptions stepUsageOptions; 143 3 : stepUsageOptions.isPipelineStep = true; 144 : 145 3 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main") 146 : { 147 4 : auto alg = GetStepAlg(m_helpDocCategory); 148 2 : if (alg) 149 : { 150 2 : alg->SetCallPath({m_helpDocCategory}); 151 1 : alg->GetArg("help-doc")->Set(true); 152 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions); 153 : } 154 : else 155 : { 156 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n", 157 : m_helpDocCategory.c_str()); 158 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n", 159 1 : m_helpDocCategory.c_str()); 160 : } 161 : } 162 : 163 1 : UsageOptions usageOptionsMain(usageOptions); 164 1 : usageOptionsMain.isPipelineMain = true; 165 : std::string ret = 166 2 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain); 167 1 : if (shortUsage) 168 0 : return ret; 169 : 170 : ret += "\n<PIPELINE> is of the form: read|mosaic [READ-OPTIONS] " 171 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! info|write " 172 1 : "[WRITE-OPTIONS]\n"; 173 : 174 1 : if (m_helpDocCategory == "main") 175 : { 176 1 : return ret; 177 : } 178 : 179 0 : ret += '\n'; 180 0 : ret += "Example: 'gdal mdim pipeline --progress ! read in.nc ! \\\n"; 181 0 : ret += " reproject --output-crs=EPSG:32632 ! "; 182 0 : ret += "write out.nc --overwrite'\n"; 183 0 : ret += '\n'; 184 0 : ret += "Potential steps are:\n"; 185 : 186 0 : for (const std::string &name : m_stepRegistry.GetNames()) 187 : { 188 0 : auto alg = GetStepAlg(name); 189 0 : auto [options, maxOptLen] = alg->GetArgNamesForCLI(); 190 0 : stepUsageOptions.maxOptLen = 191 0 : std::max(stepUsageOptions.maxOptLen, maxOptLen); 192 : } 193 : 194 : { 195 0 : const auto name = GDALMdimReadAlgorithm::NAME; 196 0 : ret += '\n'; 197 0 : auto alg = GetStepAlg(name); 198 0 : alg->SetCallPath({name}); 199 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 200 : } 201 : { 202 0 : const auto name = GDALMdimMosaicAlgorithm::NAME; 203 0 : ret += '\n'; 204 0 : auto alg = GetStepAlg(name); 205 0 : alg->SetCallPath({name}); 206 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 207 : } 208 0 : for (const std::string &name : m_stepRegistry.GetNames()) 209 : { 210 0 : auto alg = GetStepAlg(name); 211 0 : assert(alg); 212 0 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() && 213 0 : !alg->IsHidden() && name != GDALMdimReadAlgorithm::NAME && 214 0 : name != GDALMdimMosaicAlgorithm::NAME) 215 : { 216 0 : ret += '\n'; 217 0 : alg->SetCallPath({name}); 218 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 219 : } 220 : } 221 0 : for (const std::string &name : m_stepRegistry.GetNames()) 222 : { 223 0 : auto alg = GetStepAlg(name); 224 0 : assert(alg); 225 0 : if (alg->CanBeMiddleStep() && !alg->IsHidden()) 226 : { 227 0 : ret += '\n'; 228 0 : alg->SetCallPath({name}); 229 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 230 : } 231 : } 232 0 : for (const std::string &name : m_stepRegistry.GetNames()) 233 : { 234 0 : auto alg = GetStepAlg(name); 235 0 : assert(alg); 236 0 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() && 237 0 : !alg->IsHidden() && name != GDALMdimWriteAlgorithm::NAME) 238 : { 239 0 : ret += '\n'; 240 0 : alg->SetCallPath({name}); 241 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 242 : } 243 : } 244 : { 245 0 : const auto name = GDALMdimWriteAlgorithm::NAME; 246 0 : ret += '\n'; 247 0 : auto alg = GetStepAlg(name); 248 0 : alg->SetCallPath({name}); 249 0 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions); 250 : } 251 0 : ret += GetUsageForCLIEnd(); 252 : 253 0 : return ret; 254 : } 255 : 256 : //! @endcond