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 : #include "cpl_error.h"
14 : #include "gdalalg_abstract_pipeline.h"
15 : #include "gdal_priv.h"
16 :
17 : #include "gdalalg_raster_read.h"
18 : #include "gdalalg_raster_mosaic.h"
19 : #include "gdalalg_raster_stack.h"
20 : #include "gdalalg_raster_write.h"
21 : #include "gdalalg_raster_zonal_stats.h"
22 :
23 : #include "gdalalg_vector_read.h"
24 : #include "gdalalg_vector_write.h"
25 :
26 : #include "gdalalg_raster_as_features.h"
27 : #include "gdalalg_raster_compare.h"
28 : #include "gdalalg_raster_contour.h"
29 : #include "gdalalg_raster_footprint.h"
30 : #include "gdalalg_raster_polygonize.h"
31 : #include "gdalalg_raster_info.h"
32 : #include "gdalalg_raster_tile.h"
33 : #include "gdalalg_vector_grid.h"
34 : #include "gdalalg_vector_info.h"
35 : #include "gdalalg_vector_rasterize.h"
36 :
37 : #include <algorithm>
38 : #include <cassert>
39 :
40 : //! @cond Doxygen_Suppress
41 :
42 : #ifndef _
43 : #define _(x) (x)
44 : #endif
45 :
46 : /************************************************************************/
47 : /* GDALPipelineStepAlgorithm() */
48 : /************************************************************************/
49 :
50 7372 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
51 : const std::string &name, const std::string &description,
52 7372 : const std::string &helpURL, const ConstructorOptions &options)
53 : : GDALAlgorithm(name, description, helpURL),
54 7372 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
55 : {
56 7372 : }
57 :
58 : /************************************************************************/
59 : /* GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg() */
60 : /************************************************************************/
61 :
62 1460 : 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 1460 : /* positionalAndRequired = */ false)
68 1460 : .SetHidden();
69 1460 : }
70 :
71 : /************************************************************************/
72 : /* GDALPipelineStepAlgorithm::AddRasterInputArgs() */
73 : /************************************************************************/
74 :
75 2605 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
76 : bool openForMixedRasterVector, bool hiddenForCLI)
77 : {
78 2605 : AddInputFormatsArg(&m_inputFormats)
79 : .AddMetadataItem(
80 : GAAMDI_REQUIRED_CAPABILITIES,
81 : openForMixedRasterVector
82 7974 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
83 7656 : : std::vector<std::string>{GDAL_DCAP_RASTER})
84 2605 : .SetHiddenForCLI(hiddenForCLI);
85 2605 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
86 : auto &arg =
87 : AddInputDatasetArg(&m_inputDataset,
88 : openForMixedRasterVector
89 : ? (GDAL_OF_RASTER | GDAL_OF_VECTOR)
90 : : GDAL_OF_RASTER,
91 2605 : /* positionalAndRequired = */ !hiddenForCLI,
92 2605 : m_constructorOptions.inputDatasetHelpMsg.c_str())
93 2605 : .SetMinCount(1)
94 2605 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
95 2605 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
96 2605 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
97 2605 : .SetHiddenForCLI(hiddenForCLI);
98 2605 : if (!m_constructorOptions.inputDatasetAlias.empty())
99 405 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
100 2605 : }
101 :
102 : /************************************************************************/
103 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
104 : /************************************************************************/
105 :
106 1296 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
107 : {
108 1296 : m_outputFormatArg =
109 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
110 1296 : /* bGDALGAllowed = */ true)
111 : .AddMetadataItem(
112 : GAAMDI_REQUIRED_CAPABILITIES,
113 : {GDAL_DCAP_RASTER,
114 5184 : m_constructorOptions.outputFormatCreateCapability.c_str()})
115 1296 : .SetHiddenForCLI(hiddenForCLI));
116 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
117 1296 : /* positionalAndRequired = */ !hiddenForCLI,
118 1296 : m_constructorOptions.outputDatasetHelpMsg.c_str())
119 1296 : .SetHiddenForCLI(hiddenForCLI)
120 1296 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
121 1296 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
122 1296 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
123 : "overwrite-append";
124 1296 : AddOverwriteArg(&m_overwrite)
125 1296 : .SetHiddenForCLI(hiddenForCLI)
126 1296 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
127 : AddArg(GDAL_ARG_NAME_APPEND, 0,
128 2592 : _("Append as a subdataset to existing output"), &m_appendRaster)
129 1296 : .SetDefault(false)
130 1296 : .SetHiddenForCLI(hiddenForCLI)
131 1296 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
132 1296 : }
133 :
134 : /************************************************************************/
135 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
136 : /************************************************************************/
137 :
138 906 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
139 : {
140 906 : AddInputFormatsArg(&m_inputFormats)
141 2718 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
142 906 : .SetHiddenForCLI(hiddenForCLI);
143 906 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
144 : auto &datasetArg =
145 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR,
146 906 : /* positionalAndRequired = */ !hiddenForCLI)
147 906 : .SetMinCount(1)
148 906 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
149 906 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
150 906 : .SetHiddenForCLI(hiddenForCLI);
151 906 : if (m_constructorOptions.addInputLayerNameArgument)
152 : {
153 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
154 1692 : _("Input layer name(s)"), &m_inputLayerNames)
155 1692 : .AddAlias("layer")
156 846 : .SetHiddenForCLI(hiddenForCLI);
157 846 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
158 : }
159 906 : }
160 :
161 : /************************************************************************/
162 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
163 : /************************************************************************/
164 :
165 1029 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
166 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
167 : {
168 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
169 1029 : /* bGDALGAllowed = */ true)
170 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
171 4116 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
172 1029 : .SetHiddenForCLI(hiddenForCLI);
173 1029 : AddOutputOpenOptionsArg(&m_outputOpenOptions).SetHiddenForCLI(hiddenForCLI);
174 : auto &outputDatasetArg =
175 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
176 1029 : /* positionalAndRequired = */ false)
177 1029 : .SetHiddenForCLI(hiddenForCLI)
178 1029 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
179 1029 : if (!hiddenForCLI)
180 935 : outputDatasetArg.SetPositional();
181 1029 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
182 921 : outputDatasetArg.SetRequired();
183 1029 : if (!m_constructorOptions.outputDatasetMutualExclusionGroup.empty())
184 : {
185 : outputDatasetArg.SetMutualExclusionGroup(
186 14 : m_constructorOptions.outputDatasetMutualExclusionGroup);
187 : }
188 1029 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
189 1029 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
190 1029 : .SetHiddenForCLI(hiddenForCLI);
191 1029 : AddOverwriteArg(&m_overwrite).SetHiddenForCLI(hiddenForCLI);
192 1029 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
193 1029 : if (m_constructorOptions.addUpdateArgument)
194 : {
195 1009 : updateArg = &AddUpdateArg(&m_update).SetHiddenForCLI(hiddenForCLI);
196 : }
197 1029 : if (updateArg && !m_constructorOptions.updateMutualExclusionGroup.empty())
198 : {
199 : updateArg->SetMutualExclusionGroup(
200 14 : m_constructorOptions.updateMutualExclusionGroup);
201 : }
202 1029 : if (m_constructorOptions.addOverwriteLayerArgument)
203 : {
204 1009 : AddOverwriteLayerArg(&m_overwriteLayer).SetHiddenForCLI(hiddenForCLI);
205 : }
206 1029 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
207 : "append-upsert";
208 1029 : if (m_constructorOptions.addAppendLayerArgument)
209 : {
210 1009 : AddAppendLayerArg(&m_appendLayer)
211 1009 : .SetHiddenForCLI(hiddenForCLI)
212 1009 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT);
213 : }
214 1029 : if (m_constructorOptions.addUpsertArgument)
215 : {
216 1936 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
217 968 : .SetHiddenForCLI(hiddenForCLI)
218 1936 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
219 : .AddAction(
220 12 : [updateArg, this]()
221 : {
222 4 : if (m_upsert && updateArg)
223 4 : updateArg->Set(true);
224 1936 : })
225 968 : .SetCategory(GAAC_ADVANCED);
226 : }
227 1029 : if (m_constructorOptions.addOutputLayerNameArgument)
228 : {
229 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER,
230 : shortNameOutputLayerAllowed ? 'l' : 0, _("Output layer name"),
231 1974 : &m_outputLayerName)
232 1974 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
233 987 : .SetHiddenForCLI(hiddenForCLI);
234 : }
235 1029 : if (m_constructorOptions.addSkipErrorsArgument)
236 : {
237 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
238 1936 : &m_skipErrors)
239 968 : .AddHiddenAlias("skip-failures"); // For ogr2ogr nostalgic people
240 : }
241 1029 : }
242 :
243 : /************************************************************************/
244 : /* GDALPipelineStepAlgorithm::RunImpl() */
245 : /************************************************************************/
246 :
247 1895 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
248 : void *pProgressData)
249 : {
250 1895 : if (m_standaloneStep)
251 : {
252 802 : std::unique_ptr<GDALPipelineStepAlgorithm> readAlg;
253 802 : if (GetInputType() == GDAL_OF_RASTER)
254 534 : readAlg = std::make_unique<GDALRasterReadAlgorithm>();
255 : else
256 268 : readAlg = std::make_unique<GDALVectorReadAlgorithm>();
257 6684 : for (auto &arg : readAlg->GetArgs())
258 : {
259 5882 : auto stepArg = GetArg(arg->GetName());
260 6695 : if (stepArg && stepArg->IsExplicitlySet() &&
261 813 : stepArg->GetType() == arg->GetType())
262 : {
263 813 : arg->SetSkipIfAlreadySet(true);
264 813 : arg->SetFrom(*stepArg);
265 : }
266 : }
267 :
268 0 : std::unique_ptr<GDALPipelineStepAlgorithm> writeAlg;
269 802 : if (GetOutputType() == GDAL_OF_RASTER)
270 : {
271 520 : if (GetName() == GDALRasterInfoAlgorithm::NAME)
272 25 : writeAlg = std::make_unique<GDALRasterInfoAlgorithm>();
273 495 : else if (GetName() == GDALRasterCompareAlgorithm::NAME)
274 180 : writeAlg = std::make_unique<GDALRasterCompareAlgorithm>();
275 : else
276 315 : writeAlg = std::make_unique<GDALRasterWriteAlgorithm>();
277 : }
278 : else
279 : {
280 282 : if (GetName() == GDALVectorInfoAlgorithm::NAME)
281 27 : writeAlg = std::make_unique<GDALVectorInfoAlgorithm>();
282 : else
283 255 : writeAlg = std::make_unique<GDALVectorWriteAlgorithm>();
284 : }
285 12898 : for (auto &arg : writeAlg->GetArgs())
286 : {
287 12096 : auto stepArg = GetArg(arg->GetName());
288 14125 : if (stepArg && stepArg->IsExplicitlySet() &&
289 2029 : stepArg->GetType() == arg->GetType())
290 : {
291 2026 : arg->SetSkipIfAlreadySet(true);
292 2026 : arg->SetFrom(*stepArg);
293 : }
294 : }
295 :
296 802 : const bool bIsStreaming = m_format == "stream";
297 :
298 : // Already checked by GDALAlgorithm::Run()
299 802 : CPLAssert(!m_executionForStreamOutput || bIsStreaming);
300 :
301 802 : bool ret = false;
302 858 : if (!m_outputVRTCompatible &&
303 112 : (EQUAL(m_format.c_str(), "VRT") ||
304 56 : (m_format.empty() &&
305 803 : EQUAL(CPLGetExtensionSafe(m_outputDataset.GetName().c_str())
306 : .c_str(),
307 : "VRT"))))
308 : {
309 0 : ReportError(CE_Failure, CPLE_NotSupported,
310 : "VRT output is not supported. Consider using the "
311 : "GDALG driver instead (files with .gdalg.json "
312 : "extension)");
313 : }
314 802 : else if (readAlg->Run())
315 : {
316 798 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
317 : const bool bOutputSpecified =
318 798 : outputArg && outputArg->IsExplicitlySet();
319 :
320 798 : m_inputDataset.clear();
321 798 : m_inputDataset.resize(1);
322 798 : m_inputDataset[0].Set(readAlg->m_outputDataset.GetDatasetRef());
323 798 : if (bOutputSpecified)
324 564 : m_outputDataset.Set(nullptr);
325 :
326 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
327 1596 : pScaledData(nullptr, GDALDestroyScaledProgress);
328 :
329 : const bool bCanHandleNextStep =
330 798 : !bIsStreaming && CanHandleNextStep(writeAlg.get());
331 :
332 798 : GDALPipelineStepRunContext stepCtxt;
333 798 : if (pfnProgress && GetName() == GDALRasterCompareAlgorithm::NAME)
334 : {
335 5 : stepCtxt.m_pfnProgress = pfnProgress;
336 5 : stepCtxt.m_pProgressData = pProgressData;
337 : }
338 827 : else if (pfnProgress &&
339 34 : (bCanHandleNextStep || !IsNativelyStreamingCompatible()))
340 : {
341 36 : pScaledData.reset(GDALCreateScaledProgress(
342 18 : 0.0, bIsStreaming || bCanHandleNextStep ? 1.0 : 0.5,
343 : pfnProgress, pProgressData));
344 18 : stepCtxt.m_pfnProgress =
345 18 : pScaledData ? GDALScaledProgress : nullptr;
346 18 : stepCtxt.m_pProgressData = pScaledData.get();
347 : }
348 :
349 798 : if (bCanHandleNextStep)
350 43 : stepCtxt.m_poNextUsableStep = writeAlg.get();
351 798 : if (RunPreStepPipelineValidations() && RunStep(stepCtxt))
352 : {
353 724 : if (bIsStreaming || bCanHandleNextStep || !bOutputSpecified)
354 : {
355 409 : ret = true;
356 : }
357 : else
358 : {
359 315 : writeAlg->m_outputVRTCompatible = m_outputVRTCompatible;
360 315 : writeAlg->m_inputDataset.clear();
361 315 : writeAlg->m_inputDataset.resize(1);
362 315 : writeAlg->m_inputDataset[0].Set(
363 : m_outputDataset.GetDatasetRef());
364 315 : if (pfnProgress)
365 : {
366 25 : pScaledData.reset(GDALCreateScaledProgress(
367 25 : IsNativelyStreamingCompatible() ? 0.0 : 0.5, 1.0,
368 : pfnProgress, pProgressData));
369 : }
370 315 : stepCtxt.m_pfnProgress =
371 315 : pScaledData ? GDALScaledProgress : nullptr;
372 315 : stepCtxt.m_pProgressData = pScaledData.get();
373 630 : if (writeAlg->ValidateArguments() &&
374 315 : writeAlg->RunStep(stepCtxt))
375 : {
376 301 : if (pfnProgress)
377 24 : pfnProgress(1.0, "", pProgressData);
378 :
379 301 : m_outputDataset.Set(
380 301 : writeAlg->m_outputDataset.GetDatasetRef());
381 301 : ret = true;
382 : }
383 : }
384 : }
385 : }
386 :
387 802 : return ret;
388 : }
389 : else
390 : {
391 1093 : GDALPipelineStepRunContext stepCtxt;
392 1093 : stepCtxt.m_pfnProgress = pfnProgress;
393 1093 : stepCtxt.m_pProgressData = pProgressData;
394 1093 : return RunPreStepPipelineValidations() && RunStep(stepCtxt);
395 : }
396 : }
397 :
398 : /************************************************************************/
399 : /* SetInputDataset() */
400 : /************************************************************************/
401 :
402 11 : void GDALPipelineStepAlgorithm::SetInputDataset(GDALDataset *poDS)
403 : {
404 11 : auto arg = GetArg(GDAL_ARG_NAME_INPUT);
405 11 : if (arg)
406 : {
407 11 : auto &val = arg->Get<std::vector<GDALArgDatasetValue>>();
408 11 : val.resize(1);
409 11 : val[0].Set(poDS);
410 11 : arg->NotifyValueSet();
411 11 : arg->SetSkipIfAlreadySet();
412 : }
413 11 : }
414 :
415 : /************************************************************************/
416 : /* ProcessGDALGOutput() */
417 : /************************************************************************/
418 :
419 : GDALAlgorithm::ProcessGDALGOutputRet
420 2622 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
421 : {
422 2622 : if (m_standaloneStep)
423 : {
424 1471 : return GDALAlgorithm::ProcessGDALGOutput();
425 : }
426 : else
427 : {
428 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep() might
429 : // actually detect a GDALG output request and process it.
430 1151 : return GDALAlgorithm::ProcessGDALGOutputRet::NOT_GDALG;
431 : }
432 : }
433 :
434 : /************************************************************************/
435 : /* GDALPipelineStepAlgorithm::CheckSafeForStreamOutput() */
436 : /************************************************************************/
437 :
438 71 : bool GDALPipelineStepAlgorithm::CheckSafeForStreamOutput()
439 : {
440 71 : if (m_standaloneStep)
441 : {
442 29 : return GDALAlgorithm::CheckSafeForStreamOutput();
443 : }
444 : else
445 : {
446 : // The check is actually done in
447 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep()
448 : // so return true for now.
449 42 : return true;
450 : }
451 : }
452 :
453 : /************************************************************************/
454 : /* GDALPipelineStepAlgorithm::Finalize() */
455 : /************************************************************************/
456 :
457 947 : bool GDALPipelineStepAlgorithm::Finalize()
458 : {
459 947 : bool ret = GDALAlgorithm::Finalize();
460 1766 : for (auto &argValue : m_inputDataset)
461 819 : ret = argValue.Close() && ret;
462 947 : ret = m_outputDataset.Close() && ret;
463 947 : return ret;
464 : }
465 :
466 : /************************************************************************/
467 : /* GDALAlgorithmStepRegistry */
468 : /************************************************************************/
469 :
470 191 : class GDALAlgorithmStepRegistry final : public GDALRasterAlgorithmStepRegistry,
471 : public GDALVectorAlgorithmStepRegistry
472 : {
473 : public:
474 191 : GDALAlgorithmStepRegistry() = default;
475 : ~GDALAlgorithmStepRegistry() override;
476 :
477 : /** Register the algorithm of type MyAlgorithm.
478 : */
479 : template <class MyAlgorithm>
480 1146 : bool Register(const std::string &name = std::string())
481 : {
482 : static_assert(std::is_base_of_v<GDALPipelineStepAlgorithm, MyAlgorithm>,
483 : "Algorithm is not a GDALPipelineStepAlgorithm");
484 :
485 2292 : AlgInfo info;
486 1146 : info.m_name = name.empty() ? MyAlgorithm::NAME : name;
487 1146 : info.m_aliases = MyAlgorithm::GetAliasesStatic();
488 1240 : info.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
489 94 : { return std::make_unique<MyAlgorithm>(); };
490 2292 : return GDALAlgorithmRegistry::Register(info);
491 : }
492 : };
493 :
494 : GDALAlgorithmStepRegistry::~GDALAlgorithmStepRegistry() = default;
495 :
496 : /************************************************************************/
497 : /* GDALPipelineAlgorithm */
498 : /************************************************************************/
499 :
500 : class GDALPipelineAlgorithm final : public GDALAbstractPipelineAlgorithm
501 :
502 : {
503 : public:
504 : static constexpr const char *NAME = "pipeline";
505 : static constexpr const char *DESCRIPTION =
506 : "Process a dataset applying several steps.";
507 : static constexpr const char *HELP_URL = "/programs/gdal_pipeline.html";
508 :
509 1591 : static std::vector<std::string> GetAliasesStatic()
510 : {
511 : return {
512 : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
513 : GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR,
514 : "+pipeline",
515 : "+gdal=pipeline",
516 : #endif
517 6364 : };
518 : }
519 :
520 : GDALPipelineAlgorithm();
521 :
522 149 : int GetInputType() const override
523 : {
524 149 : return GDAL_OF_RASTER | GDAL_OF_VECTOR;
525 : }
526 :
527 0 : int GetOutputType() const override
528 : {
529 0 : return GDAL_OF_RASTER | GDAL_OF_VECTOR;
530 : }
531 :
532 : protected:
533 : GDALAlgorithmStepRegistry m_stepRegistry{};
534 :
535 466 : GDALAlgorithmRegistry &GetStepRegistry() override
536 : {
537 466 : return m_stepRegistry;
538 : }
539 :
540 970 : const GDALAlgorithmRegistry &GetStepRegistry() const override
541 : {
542 970 : return m_stepRegistry;
543 : }
544 :
545 : std::string GetUsageForCLI(bool shortUsage,
546 : const UsageOptions &usageOptions) const override;
547 :
548 : private:
549 : std::unique_ptr<GDALAbstractPipelineAlgorithm>
550 26 : CreateNestedPipeline() const override
551 : {
552 52 : auto pipeline = std::make_unique<GDALPipelineAlgorithm>();
553 26 : pipeline->m_bInnerPipeline = true;
554 52 : return pipeline;
555 : }
556 : };
557 :
558 : /************************************************************************/
559 : /* GDALPipelineAlgorithm */
560 : /************************************************************************/
561 :
562 191 : GDALPipelineAlgorithm::GDALPipelineAlgorithm()
563 : : GDALAbstractPipelineAlgorithm(
564 : NAME, DESCRIPTION, HELP_URL,
565 191 : ConstructorOptions().SetStandaloneStep(false))
566 : {
567 191 : m_supportsStreamedOutput = true;
568 :
569 191 : AddProgressArg();
570 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
571 191 : /* positionalAndRequired = */ false)
572 191 : .SetMinCount(1)
573 191 : .SetMaxCount(INT_MAX)
574 191 : .SetHiddenForCLI();
575 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
576 191 : /* positionalAndRequired = */ false)
577 191 : .SetHiddenForCLI()
578 191 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
579 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
580 191 : /* bGDALGAllowed = */ true)
581 191 : .SetHiddenForCLI();
582 382 : AddArg("pipeline", 0, _("Pipeline string or filename"), &m_pipeline)
583 191 : .SetHiddenForCLI()
584 191 : .SetPositional();
585 :
586 191 : AddOutputStringArg(&m_output).SetHiddenForCLI();
587 191 : AddStdoutArg(&m_stdout);
588 :
589 191 : AllowArbitraryLongNameArgs();
590 :
591 191 : GDALRasterPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
592 191 : GDALVectorPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
593 191 : m_stepRegistry.Register<GDALRasterContourAlgorithm>();
594 191 : m_stepRegistry.Register<GDALRasterFootprintAlgorithm>();
595 191 : m_stepRegistry.Register<GDALRasterPolygonizeAlgorithm>();
596 191 : m_stepRegistry.Register<GDALRasterZonalStatsAlgorithm>();
597 191 : m_stepRegistry.Register<GDALVectorGridAlgorithm>();
598 191 : m_stepRegistry.Register<GDALVectorRasterizeAlgorithm>();
599 191 : }
600 :
601 : /************************************************************************/
602 : /* GDALPipelineAlgorithm::GetUsageForCLI() */
603 : /************************************************************************/
604 :
605 : std::string
606 18 : GDALPipelineAlgorithm::GetUsageForCLI(bool shortUsage,
607 : const UsageOptions &usageOptions) const
608 : {
609 18 : UsageOptions stepUsageOptions;
610 18 : stepUsageOptions.isPipelineStep = true;
611 :
612 18 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
613 : {
614 4 : auto alg = GetStepAlg(m_helpDocCategory);
615 4 : std::string ret;
616 2 : if (alg)
617 : {
618 3 : alg->SetCallPath({CPLString(m_helpDocCategory)
619 2 : .replaceAll(RASTER_SUFFIX, "")
620 3 : .replaceAll(VECTOR_SUFFIX, "")});
621 1 : alg->GetArg("help-doc")->Set(true);
622 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
623 : }
624 : else
625 : {
626 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
627 : m_helpDocCategory.c_str());
628 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
629 1 : m_helpDocCategory.c_str());
630 : }
631 : }
632 :
633 16 : UsageOptions usageOptionsMain(usageOptions);
634 16 : usageOptionsMain.isPipelineMain = true;
635 : std::string ret =
636 32 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
637 16 : if (shortUsage)
638 14 : return ret;
639 :
640 : ret +=
641 : "\n<PIPELINE> is of the form: read|calc|concat|mosaic|stack "
642 : "[READ-OPTIONS] "
643 2 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write!info!tile [WRITE-OPTIONS]\n";
644 :
645 2 : if (m_helpDocCategory == "main")
646 : {
647 1 : return ret;
648 : }
649 :
650 1 : ret += '\n';
651 1 : ret += "Example: 'gdal pipeline --progress ! read in.tif ! \\\n";
652 1 : ret += " rasterize --size 256 256 ! buffer 20 ! ";
653 1 : ret += "write out.gpkg --overwrite'\n";
654 1 : ret += '\n';
655 1 : ret += "Potential steps are:\n";
656 :
657 71 : for (const std::string &name : m_stepRegistry.GetNames())
658 : {
659 140 : auto alg = GetStepAlg(name);
660 70 : assert(alg);
661 70 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
662 70 : stepUsageOptions.maxOptLen =
663 70 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
664 : }
665 :
666 : {
667 1 : ret += '\n';
668 1 : auto alg = std::make_unique<GDALRasterReadAlgorithm>();
669 2 : alg->SetCallPath({alg->GetName()});
670 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
671 : }
672 : {
673 1 : ret += '\n';
674 1 : auto alg = std::make_unique<GDALVectorReadAlgorithm>();
675 2 : alg->SetCallPath({alg->GetName()});
676 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
677 : }
678 71 : for (const std::string &name : m_stepRegistry.GetNames())
679 : {
680 140 : auto alg = GetStepAlg(name);
681 70 : assert(alg);
682 76 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
683 82 : !alg->IsHidden() &&
684 6 : !STARTS_WITH(name.c_str(), GDALRasterReadAlgorithm::NAME))
685 : {
686 4 : ret += '\n';
687 8 : alg->SetCallPath({name});
688 4 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
689 : }
690 : }
691 71 : for (const std::string &name : m_stepRegistry.GetNames())
692 : {
693 140 : auto alg = GetStepAlg(name);
694 70 : assert(alg);
695 70 : if (alg->CanBeMiddleStep() && !alg->IsHidden())
696 : {
697 56 : ret += '\n';
698 168 : alg->SetCallPath({CPLString(alg->GetName())
699 112 : .replaceAll(RASTER_SUFFIX, "")
700 168 : .replaceAll(VECTOR_SUFFIX, "")});
701 56 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
702 : }
703 : }
704 71 : for (const std::string &name : m_stepRegistry.GetNames())
705 : {
706 140 : auto alg = GetStepAlg(name);
707 70 : assert(alg);
708 79 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
709 86 : !alg->IsHidden() &&
710 7 : !STARTS_WITH(name.c_str(), GDALRasterWriteAlgorithm::NAME))
711 : {
712 5 : ret += '\n';
713 10 : alg->SetCallPath({name});
714 5 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
715 : }
716 : }
717 : {
718 1 : ret += '\n';
719 1 : auto alg = std::make_unique<GDALRasterWriteAlgorithm>();
720 2 : alg->SetCallPath({alg->GetName()});
721 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
722 : }
723 : {
724 1 : ret += '\n';
725 1 : auto alg = std::make_unique<GDALVectorWriteAlgorithm>();
726 2 : alg->SetCallPath({alg->GetName()});
727 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
728 : }
729 :
730 1 : ret += GetUsageForCLIEnd();
731 :
732 1 : return ret;
733 : }
734 :
735 : GDAL_STATIC_REGISTER_ALG(GDALPipelineAlgorithm);
736 :
737 : //! @endcond
|