Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "pipeline" subcommand
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : //! @cond Doxygen_Suppress
14 :
15 : #include "gdalalg_pipeline.h"
16 : #include "cpl_error.h"
17 : #include "gdal_priv.h"
18 :
19 : #include "gdalalg_raster_read.h"
20 : #include "gdalalg_raster_mosaic.h"
21 : #include "gdalalg_raster_stack.h"
22 : #include "gdalalg_raster_write.h"
23 : #include "gdalalg_raster_zonal_stats.h"
24 :
25 : #include "gdalalg_vector_read.h"
26 : #include "gdalalg_vector_write.h"
27 :
28 : #include "gdalalg_raster_as_features.h"
29 : #include "gdalalg_raster_compare.h"
30 : #include "gdalalg_raster_contour.h"
31 : #include "gdalalg_raster_footprint.h"
32 : #include "gdalalg_raster_polygonize.h"
33 : #include "gdalalg_raster_info.h"
34 : #include "gdalalg_raster_tile.h"
35 : #include "gdalalg_vector_grid.h"
36 : #include "gdalalg_vector_info.h"
37 : #include "gdalalg_vector_rasterize.h"
38 :
39 : #include <algorithm>
40 : #include <cassert>
41 :
42 : #ifndef _
43 : #define _(x) (x)
44 : #endif
45 :
46 : /************************************************************************/
47 : /* GDALPipelineStepAlgorithm() */
48 : /************************************************************************/
49 :
50 8211 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
51 : const std::string &name, const std::string &description,
52 8211 : const std::string &helpURL, const ConstructorOptions &options)
53 : : GDALAlgorithm(name, description, helpURL),
54 8211 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
55 : {
56 8211 : }
57 :
58 : /************************************************************************/
59 : /* GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg() */
60 : /************************************************************************/
61 :
62 1858 : void GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg()
63 : {
64 : // Added so that "band" argument validation works, because
65 : // GDALAlgorithm must be able to retrieve the input dataset
66 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER,
67 1858 : /* positionalAndRequired = */ false)
68 1858 : .SetMinCount(1)
69 1858 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
70 1858 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
71 1858 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
72 1858 : .SetHidden();
73 1858 : }
74 :
75 : /************************************************************************/
76 : /* GDALPipelineStepAlgorithm::AddRasterInputArgs() */
77 : /************************************************************************/
78 :
79 2655 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
80 : bool openForMixedRasterVector, bool hiddenForCLI)
81 : {
82 2655 : AddInputFormatsArg(&m_inputFormats)
83 : .AddMetadataItem(
84 : GAAMDI_REQUIRED_CAPABILITIES,
85 : openForMixedRasterVector
86 8138 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
87 7792 : : std::vector<std::string>{GDAL_DCAP_RASTER})
88 2655 : .SetHiddenForCLI(hiddenForCLI);
89 2655 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
90 : auto &arg =
91 : AddInputDatasetArg(
92 : &m_inputDataset,
93 : openForMixedRasterVector ? (GDAL_OF_RASTER | GDAL_OF_VECTOR)
94 : : GDAL_OF_RASTER,
95 2655 : m_constructorOptions.inputDatasetRequired && !hiddenForCLI,
96 5310 : m_constructorOptions.inputDatasetHelpMsg.c_str())
97 2655 : .SetMinCount(1)
98 2655 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
99 2655 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
100 2655 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
101 2655 : .SetHiddenForCLI(hiddenForCLI);
102 2655 : if (!m_constructorOptions.inputDatasetAlias.empty())
103 448 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
104 2655 : }
105 :
106 : /************************************************************************/
107 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
108 : /************************************************************************/
109 :
110 1544 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
111 : {
112 1544 : m_outputFormatArg =
113 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
114 1544 : /* bGDALGAllowed = */ true)
115 : .AddMetadataItem(
116 : GAAMDI_REQUIRED_CAPABILITIES,
117 : {GDAL_DCAP_RASTER,
118 6176 : m_constructorOptions.outputFormatCreateCapability.c_str()})
119 1544 : .SetHiddenForCLI(hiddenForCLI));
120 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
121 1544 : /* positionalAndRequired = */ !hiddenForCLI,
122 1544 : m_constructorOptions.outputDatasetHelpMsg.c_str())
123 1544 : .SetHiddenForCLI(hiddenForCLI)
124 1544 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
125 1544 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
126 1544 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
127 : "overwrite-append";
128 1544 : AddOverwriteArg(&m_overwrite)
129 1544 : .SetHiddenForCLI(hiddenForCLI)
130 1544 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
131 : AddArg(GDAL_ARG_NAME_APPEND, 0,
132 3088 : _("Append as a subdataset to existing output"), &m_appendRaster)
133 1544 : .SetDefault(false)
134 1544 : .SetHiddenForCLI(hiddenForCLI)
135 1544 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
136 1544 : }
137 :
138 : /************************************************************************/
139 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
140 : /************************************************************************/
141 :
142 1103 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
143 : {
144 1103 : AddInputFormatsArg(&m_inputFormats)
145 3309 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
146 1103 : .SetHiddenForCLI(hiddenForCLI);
147 1103 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
148 : auto &datasetArg =
149 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR,
150 1103 : /* positionalAndRequired = */ !hiddenForCLI)
151 1103 : .SetMinCount(1)
152 1103 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
153 1103 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
154 1103 : .SetHiddenForCLI(hiddenForCLI);
155 1103 : if (m_constructorOptions.addInputLayerNameArgument)
156 : {
157 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
158 2014 : _("Input layer name(s)"), &m_inputLayerNames)
159 2014 : .AddAlias("layer")
160 1007 : .SetHiddenForCLI(hiddenForCLI);
161 1007 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
162 : }
163 1103 : }
164 :
165 : /************************************************************************/
166 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
167 : /************************************************************************/
168 :
169 1235 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
170 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
171 : {
172 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
173 1235 : /* bGDALGAllowed = */ true)
174 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
175 4940 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
176 1235 : .SetHiddenForCLI(hiddenForCLI);
177 1235 : AddOutputOpenOptionsArg(&m_outputOpenOptions).SetHiddenForCLI(hiddenForCLI);
178 : auto &outputDatasetArg =
179 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
180 1235 : /* positionalAndRequired = */ false)
181 1235 : .SetHiddenForCLI(hiddenForCLI)
182 1235 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
183 1235 : if (!hiddenForCLI)
184 1134 : outputDatasetArg.SetPositional();
185 1235 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
186 1113 : outputDatasetArg.SetRequired();
187 :
188 1235 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
189 1235 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
190 1235 : .SetHiddenForCLI(hiddenForCLI);
191 1235 : AddOverwriteArg(&m_overwrite).SetHiddenForCLI(hiddenForCLI);
192 1235 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
193 1235 : if (m_constructorOptions.addUpdateArgument)
194 : {
195 1210 : updateArg = &AddUpdateArg(&m_update).SetHiddenForCLI(hiddenForCLI);
196 : }
197 1235 : if (m_constructorOptions.addOverwriteLayerArgument)
198 : {
199 1210 : AddOverwriteLayerArg(&m_overwriteLayer).SetHiddenForCLI(hiddenForCLI);
200 : }
201 1235 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
202 : "append-upsert";
203 1235 : if (m_constructorOptions.addAppendLayerArgument)
204 : {
205 1210 : AddAppendLayerArg(&m_appendLayer)
206 1210 : .SetHiddenForCLI(hiddenForCLI)
207 1210 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT);
208 : }
209 1235 : if (m_constructorOptions.addUpsertArgument)
210 : {
211 2318 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
212 1159 : .SetHiddenForCLI(hiddenForCLI)
213 2318 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
214 : .AddAction(
215 12 : [updateArg, this]()
216 : {
217 4 : if (m_upsert && updateArg)
218 4 : updateArg->Set(true);
219 2318 : })
220 1159 : .SetCategory(GAAC_ADVANCED);
221 : }
222 1235 : if (m_constructorOptions.addOutputLayerNameArgument)
223 : {
224 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER,
225 : shortNameOutputLayerAllowed ? 'l' : 0, _("Output layer name"),
226 2362 : &m_outputLayerName)
227 2362 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
228 1181 : .SetHiddenForCLI(hiddenForCLI);
229 : }
230 1235 : if (m_constructorOptions.addSkipErrorsArgument)
231 : {
232 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
233 2318 : &m_skipErrors)
234 1159 : .AddHiddenAlias("skip-failures"); // For ogr2ogr nostalgic people
235 : }
236 1235 : }
237 :
238 : /************************************************************************/
239 : /* GDALPipelineStepAlgorithm::RunImpl() */
240 : /************************************************************************/
241 :
242 1976 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
243 : void *pProgressData)
244 : {
245 1976 : if (m_standaloneStep)
246 : {
247 831 : std::unique_ptr<GDALPipelineStepAlgorithm> readAlg;
248 831 : if (GetInputType() == GDAL_OF_RASTER)
249 542 : readAlg = std::make_unique<GDALRasterReadAlgorithm>();
250 : else
251 289 : readAlg = std::make_unique<GDALVectorReadAlgorithm>();
252 6937 : for (auto &arg : readAlg->GetArgs())
253 : {
254 6106 : auto stepArg = GetArg(arg->GetName());
255 6949 : if (stepArg && stepArg->IsExplicitlySet() &&
256 843 : stepArg->GetType() == arg->GetType())
257 : {
258 843 : arg->SetSkipIfAlreadySet(true);
259 843 : arg->SetFrom(*stepArg);
260 : }
261 : }
262 :
263 0 : std::unique_ptr<GDALPipelineStepAlgorithm> writeAlg;
264 831 : if (GetOutputType() == GDAL_OF_RASTER)
265 : {
266 528 : if (GetName() == GDALRasterInfoAlgorithm::NAME)
267 25 : writeAlg = std::make_unique<GDALRasterInfoAlgorithm>();
268 503 : else if (GetName() == GDALRasterCompareAlgorithm::NAME)
269 180 : writeAlg = std::make_unique<GDALRasterCompareAlgorithm>();
270 : else
271 323 : writeAlg = std::make_unique<GDALRasterWriteAlgorithm>();
272 : }
273 : else
274 : {
275 303 : if (GetName() == GDALVectorInfoAlgorithm::NAME)
276 26 : writeAlg = std::make_unique<GDALVectorInfoAlgorithm>();
277 : else
278 277 : writeAlg = std::make_unique<GDALVectorWriteAlgorithm>();
279 : }
280 12879 : for (auto &arg : writeAlg->GetArgs())
281 : {
282 12048 : auto stepArg = GetArg(arg->GetName());
283 14113 : if (stepArg && stepArg->IsExplicitlySet() &&
284 2065 : stepArg->GetType() == arg->GetType())
285 : {
286 2062 : arg->SetSkipIfAlreadySet(true);
287 2062 : arg->SetFrom(*stepArg);
288 : }
289 : }
290 :
291 831 : const bool bIsStreaming = m_format == "stream";
292 :
293 : // Already checked by GDALAlgorithm::Run()
294 831 : CPLAssert(!m_executionForStreamOutput || bIsStreaming);
295 :
296 831 : bool ret = false;
297 887 : if (!m_outputVRTCompatible &&
298 112 : (EQUAL(m_format.c_str(), "VRT") ||
299 56 : (m_format.empty() &&
300 832 : EQUAL(CPLGetExtensionSafe(m_outputDataset.GetName().c_str())
301 : .c_str(),
302 : "VRT"))))
303 : {
304 0 : ReportError(CE_Failure, CPLE_NotSupported,
305 : "VRT output is not supported. Consider using the "
306 : "GDALG driver instead (files with .gdalg.json "
307 : "extension)");
308 : }
309 831 : else if (readAlg->Run())
310 : {
311 827 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
312 : const bool bOutputSpecified =
313 827 : outputArg && outputArg->IsExplicitlySet();
314 :
315 827 : m_inputDataset.clear();
316 827 : m_inputDataset.resize(1);
317 827 : m_inputDataset[0].Set(readAlg->m_outputDataset.GetDatasetRef());
318 827 : if (bOutputSpecified)
319 594 : m_outputDataset.Set(nullptr);
320 :
321 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
322 1654 : pScaledData(nullptr, GDALDestroyScaledProgress);
323 :
324 : const bool bCanHandleNextStep =
325 827 : !bIsStreaming && CanHandleNextStep(writeAlg.get());
326 :
327 827 : GDALPipelineStepRunContext stepCtxt;
328 827 : if (pfnProgress && GetName() == GDALRasterCompareAlgorithm::NAME)
329 : {
330 5 : stepCtxt.m_pfnProgress = pfnProgress;
331 5 : stepCtxt.m_pProgressData = pProgressData;
332 : }
333 860 : else if (pfnProgress &&
334 38 : (bCanHandleNextStep || !IsNativelyStreamingCompatible()))
335 : {
336 40 : pScaledData.reset(GDALCreateScaledProgress(
337 18 : 0.0, bIsStreaming || bCanHandleNextStep ? 1.0 : 0.5,
338 : pfnProgress, pProgressData));
339 22 : stepCtxt.m_pfnProgress =
340 22 : pScaledData ? GDALScaledProgress : nullptr;
341 22 : stepCtxt.m_pProgressData = pScaledData.get();
342 : }
343 :
344 827 : if (bCanHandleNextStep)
345 45 : stepCtxt.m_poNextUsableStep = writeAlg.get();
346 827 : if (RunPreStepPipelineValidations() && RunStep(stepCtxt))
347 : {
348 747 : if (bIsStreaming || bCanHandleNextStep || !bOutputSpecified)
349 : {
350 423 : ret = true;
351 : }
352 : else
353 : {
354 324 : writeAlg->m_outputVRTCompatible = m_outputVRTCompatible;
355 324 : writeAlg->m_inputDataset.clear();
356 324 : writeAlg->m_inputDataset.resize(1);
357 324 : writeAlg->m_inputDataset[0].Set(
358 : m_outputDataset.GetDatasetRef());
359 324 : if (pfnProgress)
360 : {
361 25 : pScaledData.reset(GDALCreateScaledProgress(
362 25 : IsNativelyStreamingCompatible() ? 0.0 : 0.5, 1.0,
363 : pfnProgress, pProgressData));
364 : }
365 324 : stepCtxt.m_pfnProgress =
366 324 : pScaledData ? GDALScaledProgress : nullptr;
367 324 : stepCtxt.m_pProgressData = pScaledData.get();
368 648 : if (writeAlg->ValidateArguments() &&
369 324 : writeAlg->RunStep(stepCtxt))
370 : {
371 310 : if (pfnProgress)
372 24 : pfnProgress(1.0, "", pProgressData);
373 :
374 310 : m_outputDataset.Set(
375 310 : writeAlg->m_outputDataset.GetDatasetRef());
376 310 : ret = true;
377 : }
378 : }
379 : }
380 : }
381 :
382 831 : return ret;
383 : }
384 : else
385 : {
386 1145 : GDALPipelineStepRunContext stepCtxt;
387 1145 : stepCtxt.m_pfnProgress = pfnProgress;
388 1145 : stepCtxt.m_pProgressData = pProgressData;
389 1145 : return RunPreStepPipelineValidations() && RunStep(stepCtxt);
390 : }
391 : }
392 :
393 : /************************************************************************/
394 : /* SetInputDataset() */
395 : /************************************************************************/
396 :
397 11 : void GDALPipelineStepAlgorithm::SetInputDataset(GDALDataset *poDS)
398 : {
399 11 : auto arg = GetArg(GDAL_ARG_NAME_INPUT);
400 11 : if (arg)
401 : {
402 10 : auto &val = arg->Get<std::vector<GDALArgDatasetValue>>();
403 10 : val.resize(1);
404 10 : val[0].Set(poDS);
405 10 : arg->NotifyValueSet();
406 10 : arg->SetSkipIfAlreadySet();
407 : }
408 11 : }
409 :
410 : /************************************************************************/
411 : /* ProcessGDALGOutput() */
412 : /************************************************************************/
413 :
414 : GDALAlgorithm::ProcessGDALGOutputRet
415 2813 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
416 : {
417 2813 : if (m_standaloneStep)
418 : {
419 1610 : return GDALAlgorithm::ProcessGDALGOutput();
420 : }
421 : else
422 : {
423 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep() might
424 : // actually detect a GDALG output request and process it.
425 1203 : return GDALAlgorithm::ProcessGDALGOutputRet::NOT_GDALG;
426 : }
427 : }
428 :
429 : /************************************************************************/
430 : /* GDALPipelineStepAlgorithm::CheckSafeForStreamOutput() */
431 : /************************************************************************/
432 :
433 74 : bool GDALPipelineStepAlgorithm::CheckSafeForStreamOutput()
434 : {
435 74 : if (m_standaloneStep)
436 : {
437 29 : return GDALAlgorithm::CheckSafeForStreamOutput();
438 : }
439 : else
440 : {
441 : // The check is actually done in
442 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep()
443 : // so return true for now.
444 45 : return true;
445 : }
446 : }
447 :
448 : /************************************************************************/
449 : /* GDALPipelineStepAlgorithm::Finalize() */
450 : /************************************************************************/
451 :
452 1034 : bool GDALPipelineStepAlgorithm::Finalize()
453 : {
454 1034 : bool ret = GDALAlgorithm::Finalize();
455 1926 : for (auto &argValue : m_inputDataset)
456 892 : ret = argValue.Close() && ret;
457 1034 : ret = m_outputDataset.Close() && ret;
458 1034 : return ret;
459 : }
460 :
461 : GDALAlgorithmStepRegistry::~GDALAlgorithmStepRegistry() = default;
462 :
463 : /************************************************************************/
464 : /* GDALPipelineAlgorithm */
465 : /************************************************************************/
466 :
467 209 : GDALPipelineAlgorithm::GDALPipelineAlgorithm()
468 : : GDALAbstractPipelineAlgorithm(
469 : NAME, DESCRIPTION, HELP_URL,
470 209 : ConstructorOptions().SetStandaloneStep(false))
471 : {
472 209 : m_supportsStreamedOutput = true;
473 :
474 209 : AddProgressArg();
475 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
476 209 : /* positionalAndRequired = */ false)
477 209 : .SetMinCount(1)
478 209 : .SetMaxCount(INT_MAX)
479 209 : .SetHiddenForCLI();
480 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
481 209 : /* positionalAndRequired = */ false)
482 209 : .SetHiddenForCLI()
483 209 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
484 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
485 209 : /* bGDALGAllowed = */ true)
486 209 : .SetHiddenForCLI();
487 418 : AddArg("pipeline", 0, _("Pipeline string or filename"), &m_pipeline)
488 209 : .SetHiddenForCLI()
489 209 : .SetPositional();
490 :
491 209 : AddOutputStringArg(&m_output).SetHiddenForCLI();
492 209 : AddStdoutArg(&m_stdout);
493 :
494 209 : AllowArbitraryLongNameArgs();
495 :
496 209 : GDALRasterPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
497 209 : GDALVectorPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
498 209 : m_stepRegistry.Register<GDALRasterAsFeaturesAlgorithm>();
499 209 : m_stepRegistry.Register<GDALRasterContourAlgorithm>();
500 209 : m_stepRegistry.Register<GDALRasterFootprintAlgorithm>();
501 209 : m_stepRegistry.Register<GDALRasterPolygonizeAlgorithm>();
502 209 : m_stepRegistry.Register<GDALRasterZonalStatsAlgorithm>();
503 209 : m_stepRegistry.Register<GDALVectorGridAlgorithm>();
504 209 : m_stepRegistry.Register<GDALVectorRasterizeAlgorithm>();
505 209 : }
506 :
507 : /************************************************************************/
508 : /* GDALPipelineAlgorithm::GetUsageForCLI() */
509 : /************************************************************************/
510 :
511 : std::string
512 18 : GDALPipelineAlgorithm::GetUsageForCLI(bool shortUsage,
513 : const UsageOptions &usageOptions) const
514 : {
515 18 : UsageOptions stepUsageOptions;
516 18 : stepUsageOptions.isPipelineStep = true;
517 :
518 18 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
519 : {
520 4 : auto alg = GetStepAlg(m_helpDocCategory);
521 2 : if (alg)
522 : {
523 3 : alg->SetCallPath({CPLString(m_helpDocCategory)
524 2 : .replaceAll(RASTER_SUFFIX, "")
525 3 : .replaceAll(VECTOR_SUFFIX, "")});
526 1 : alg->GetArg("help-doc")->Set(true);
527 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
528 : }
529 : else
530 : {
531 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
532 : m_helpDocCategory.c_str());
533 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
534 1 : m_helpDocCategory.c_str());
535 : }
536 : }
537 :
538 16 : UsageOptions usageOptionsMain(usageOptions);
539 16 : usageOptionsMain.isPipelineMain = true;
540 : std::string ret =
541 32 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
542 16 : if (shortUsage)
543 14 : return ret;
544 :
545 : ret +=
546 : "\n<PIPELINE> is of the form: read|calc|concat|create|mosaic|stack "
547 : "[READ-OPTIONS] "
548 2 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write!info!tile [WRITE-OPTIONS]\n";
549 :
550 2 : if (m_helpDocCategory == "main")
551 : {
552 1 : return ret;
553 : }
554 :
555 1 : ret += '\n';
556 1 : ret += "Example: 'gdal pipeline --progress ! read in.tif ! \\\n";
557 1 : ret += " rasterize --size 256 256 ! buffer 20 ! ";
558 1 : ret += "write out.gpkg --overwrite'\n";
559 1 : ret += '\n';
560 1 : ret += "Potential steps are:\n";
561 :
562 75 : for (const std::string &name : m_stepRegistry.GetNames())
563 : {
564 148 : auto alg = GetStepAlg(name);
565 74 : assert(alg);
566 74 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
567 74 : stepUsageOptions.maxOptLen =
568 74 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
569 : }
570 :
571 : {
572 1 : ret += '\n';
573 1 : auto alg = std::make_unique<GDALRasterReadAlgorithm>();
574 2 : alg->SetCallPath({alg->GetName()});
575 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
576 : }
577 : {
578 1 : ret += '\n';
579 1 : auto alg = std::make_unique<GDALVectorReadAlgorithm>();
580 2 : alg->SetCallPath({alg->GetName()});
581 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
582 : }
583 75 : for (const std::string &name : m_stepRegistry.GetNames())
584 : {
585 148 : auto alg = GetStepAlg(name);
586 74 : assert(alg);
587 81 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
588 87 : !alg->IsHidden() &&
589 6 : !STARTS_WITH(name.c_str(), GDALRasterReadAlgorithm::NAME))
590 : {
591 4 : ret += '\n';
592 8 : alg->SetCallPath({name});
593 4 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
594 : }
595 : }
596 75 : for (const std::string &name : m_stepRegistry.GetNames())
597 : {
598 148 : auto alg = GetStepAlg(name);
599 74 : assert(alg);
600 74 : if (alg->CanBeMiddleStep() && !alg->IsHidden())
601 : {
602 61 : ret += '\n';
603 183 : alg->SetCallPath({CPLString(alg->GetName())
604 122 : .replaceAll(RASTER_SUFFIX, "")
605 183 : .replaceAll(VECTOR_SUFFIX, "")});
606 61 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
607 : }
608 : }
609 75 : for (const std::string &name : m_stepRegistry.GetNames())
610 : {
611 148 : auto alg = GetStepAlg(name);
612 74 : assert(alg);
613 84 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
614 91 : !alg->IsHidden() &&
615 7 : !STARTS_WITH(name.c_str(), GDALRasterWriteAlgorithm::NAME))
616 : {
617 5 : ret += '\n';
618 10 : alg->SetCallPath({name});
619 5 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
620 : }
621 : }
622 : {
623 1 : ret += '\n';
624 1 : auto alg = std::make_unique<GDALRasterWriteAlgorithm>();
625 2 : alg->SetCallPath({alg->GetName()});
626 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
627 : }
628 : {
629 1 : ret += '\n';
630 1 : auto alg = std::make_unique<GDALVectorWriteAlgorithm>();
631 2 : alg->SetCallPath({alg->GetName()});
632 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
633 : }
634 :
635 1 : ret += GetUsageForCLIEnd();
636 :
637 1 : return ret;
638 : }
639 :
640 : //! @endcond
|