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 8120 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
51 : const std::string &name, const std::string &description,
52 8120 : const std::string &helpURL, const ConstructorOptions &options)
53 : : GDALAlgorithm(name, description, helpURL),
54 8120 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
55 : {
56 8120 : }
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 2614 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
80 : bool openForMixedRasterVector, bool hiddenForCLI)
81 : {
82 2614 : AddInputFormatsArg(&m_inputFormats)
83 : .AddMetadataItem(
84 : GAAMDI_REQUIRED_CAPABILITIES,
85 : openForMixedRasterVector
86 8013 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
87 7671 : : std::vector<std::string>{GDAL_DCAP_RASTER})
88 2614 : .SetHiddenForCLI(hiddenForCLI);
89 2614 : 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 2614 : m_constructorOptions.inputDatasetRequired && !hiddenForCLI,
96 5228 : m_constructorOptions.inputDatasetHelpMsg.c_str())
97 2614 : .SetMinCount(1)
98 2614 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
99 2614 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
100 2614 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
101 2614 : .SetHiddenForCLI(hiddenForCLI);
102 2614 : if (!m_constructorOptions.inputDatasetAlias.empty())
103 441 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
104 2614 : }
105 :
106 : /************************************************************************/
107 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
108 : /************************************************************************/
109 :
110 1512 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
111 : {
112 1512 : m_outputFormatArg =
113 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
114 1512 : /* bGDALGAllowed = */ true)
115 : .AddMetadataItem(
116 : GAAMDI_REQUIRED_CAPABILITIES,
117 : {GDAL_DCAP_RASTER,
118 6048 : m_constructorOptions.outputFormatCreateCapability.c_str()})
119 1512 : .SetHiddenForCLI(hiddenForCLI));
120 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
121 1512 : /* positionalAndRequired = */ !hiddenForCLI,
122 1512 : m_constructorOptions.outputDatasetHelpMsg.c_str())
123 1512 : .SetHiddenForCLI(hiddenForCLI)
124 1512 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
125 1512 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
126 1512 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
127 : "overwrite-append";
128 1512 : AddOverwriteArg(&m_overwrite)
129 1512 : .SetHiddenForCLI(hiddenForCLI)
130 1512 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
131 : AddArg(GDAL_ARG_NAME_APPEND, 0,
132 3024 : _("Append as a subdataset to existing output"), &m_appendRaster)
133 1512 : .SetDefault(false)
134 1512 : .SetHiddenForCLI(hiddenForCLI)
135 1512 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
136 1512 : }
137 :
138 : /************************************************************************/
139 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
140 : /************************************************************************/
141 :
142 1075 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
143 : {
144 1075 : AddInputFormatsArg(&m_inputFormats)
145 3225 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
146 1075 : .SetHiddenForCLI(hiddenForCLI);
147 1075 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
148 : auto &datasetArg =
149 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR,
150 1075 : /* positionalAndRequired = */ !hiddenForCLI)
151 1075 : .SetMinCount(1)
152 1075 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
153 1075 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
154 1075 : .SetHiddenForCLI(hiddenForCLI);
155 1075 : if (m_constructorOptions.addInputLayerNameArgument)
156 : {
157 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
158 1964 : _("Input layer name(s)"), &m_inputLayerNames)
159 1964 : .AddAlias("layer")
160 982 : .SetHiddenForCLI(hiddenForCLI);
161 982 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
162 : }
163 1075 : }
164 :
165 : /************************************************************************/
166 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
167 : /************************************************************************/
168 :
169 1205 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
170 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
171 : {
172 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
173 1205 : /* bGDALGAllowed = */ true)
174 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
175 4820 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
176 1205 : .SetHiddenForCLI(hiddenForCLI);
177 1205 : AddOutputOpenOptionsArg(&m_outputOpenOptions).SetHiddenForCLI(hiddenForCLI);
178 : auto &outputDatasetArg =
179 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
180 1205 : /* positionalAndRequired = */ false)
181 1205 : .SetHiddenForCLI(hiddenForCLI)
182 1205 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
183 1205 : if (!hiddenForCLI)
184 1106 : outputDatasetArg.SetPositional();
185 1205 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
186 1086 : outputDatasetArg.SetRequired();
187 :
188 1205 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
189 1205 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
190 1205 : .SetHiddenForCLI(hiddenForCLI);
191 1205 : AddOverwriteArg(&m_overwrite).SetHiddenForCLI(hiddenForCLI);
192 1205 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
193 1205 : if (m_constructorOptions.addUpdateArgument)
194 : {
195 1181 : updateArg = &AddUpdateArg(&m_update).SetHiddenForCLI(hiddenForCLI);
196 : }
197 1205 : if (m_constructorOptions.addOverwriteLayerArgument)
198 : {
199 1181 : AddOverwriteLayerArg(&m_overwriteLayer).SetHiddenForCLI(hiddenForCLI);
200 : }
201 1205 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
202 : "append-upsert";
203 1205 : if (m_constructorOptions.addAppendLayerArgument)
204 : {
205 1181 : AddAppendLayerArg(&m_appendLayer)
206 1181 : .SetHiddenForCLI(hiddenForCLI)
207 1181 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT);
208 : }
209 1205 : if (m_constructorOptions.addUpsertArgument)
210 : {
211 2264 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
212 1132 : .SetHiddenForCLI(hiddenForCLI)
213 2264 : .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 2264 : })
220 1132 : .SetCategory(GAAC_ADVANCED);
221 : }
222 1205 : if (m_constructorOptions.addOutputLayerNameArgument)
223 : {
224 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER,
225 : shortNameOutputLayerAllowed ? 'l' : 0, _("Output layer name"),
226 2306 : &m_outputLayerName)
227 2306 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
228 1153 : .SetHiddenForCLI(hiddenForCLI);
229 : }
230 1205 : if (m_constructorOptions.addSkipErrorsArgument)
231 : {
232 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
233 2264 : &m_skipErrors)
234 1132 : .AddHiddenAlias("skip-failures"); // For ogr2ogr nostalgic people
235 : }
236 1205 : }
237 :
238 : /************************************************************************/
239 : /* GDALPipelineStepAlgorithm::RunImpl() */
240 : /************************************************************************/
241 :
242 1975 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
243 : void *pProgressData)
244 : {
245 1975 : 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 1144 : GDALPipelineStepRunContext stepCtxt;
387 1144 : stepCtxt.m_pfnProgress = pfnProgress;
388 1144 : stepCtxt.m_pProgressData = pProgressData;
389 1144 : 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 2812 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
416 : {
417 2812 : 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 1202 : 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 1030 : bool GDALPipelineStepAlgorithm::Finalize()
453 : {
454 1030 : bool ret = GDALAlgorithm::Finalize();
455 1919 : for (auto &argValue : m_inputDataset)
456 889 : ret = argValue.Close() && ret;
457 1030 : ret = m_outputDataset.Close() && ret;
458 1030 : return ret;
459 : }
460 :
461 : /************************************************************************/
462 : /* GDALAlgorithmStepRegistry */
463 : /************************************************************************/
464 :
465 208 : class GDALAlgorithmStepRegistry final : public GDALRasterAlgorithmStepRegistry,
466 : public GDALVectorAlgorithmStepRegistry
467 : {
468 : public:
469 208 : GDALAlgorithmStepRegistry() = default;
470 : ~GDALAlgorithmStepRegistry() override;
471 :
472 : /** Register the algorithm of type MyAlgorithm.
473 : */
474 : template <class MyAlgorithm>
475 1456 : bool Register(const std::string &name = std::string())
476 : {
477 : static_assert(std::is_base_of_v<GDALPipelineStepAlgorithm, MyAlgorithm>,
478 : "Algorithm is not a GDALPipelineStepAlgorithm");
479 :
480 2912 : AlgInfo info;
481 1456 : info.m_name = name.empty() ? MyAlgorithm::NAME : name;
482 1456 : info.m_aliases = MyAlgorithm::GetAliasesStatic();
483 1563 : info.m_creationFunc = []() -> std::unique_ptr<GDALAlgorithm>
484 107 : { return std::make_unique<MyAlgorithm>(); };
485 2912 : return GDALAlgorithmRegistry::Register(info);
486 : }
487 : };
488 :
489 : GDALAlgorithmStepRegistry::~GDALAlgorithmStepRegistry() = default;
490 :
491 : /************************************************************************/
492 : /* GDALPipelineAlgorithm */
493 : /************************************************************************/
494 :
495 : class GDALPipelineAlgorithm final : public GDALAbstractPipelineAlgorithm
496 :
497 : {
498 : public:
499 : static constexpr const char *NAME = "pipeline";
500 : static constexpr const char *DESCRIPTION =
501 : "Process a dataset applying several steps.";
502 : static constexpr const char *HELP_URL = "/programs/gdal_pipeline.html";
503 :
504 1611 : static std::vector<std::string> GetAliasesStatic()
505 : {
506 : return {
507 : #ifdef GDAL_PIPELINE_PROJ_NOSTALGIA
508 : GDALAlgorithmRegistry::HIDDEN_ALIAS_SEPARATOR,
509 : "+pipeline",
510 : "+gdal=pipeline",
511 : #endif
512 6444 : };
513 : }
514 :
515 : GDALPipelineAlgorithm();
516 :
517 160 : int GetInputType() const override
518 : {
519 160 : return GDAL_OF_RASTER | GDAL_OF_VECTOR;
520 : }
521 :
522 0 : int GetOutputType() const override
523 : {
524 0 : return GDAL_OF_RASTER | GDAL_OF_VECTOR;
525 : }
526 :
527 : protected:
528 : GDALAlgorithmStepRegistry m_stepRegistry{};
529 :
530 491 : GDALAlgorithmRegistry &GetStepRegistry() override
531 : {
532 491 : return m_stepRegistry;
533 : }
534 :
535 1059 : const GDALAlgorithmRegistry &GetStepRegistry() const override
536 : {
537 1059 : return m_stepRegistry;
538 : }
539 :
540 : std::string GetUsageForCLI(bool shortUsage,
541 : const UsageOptions &usageOptions) const override;
542 :
543 : private:
544 : std::unique_ptr<GDALAbstractPipelineAlgorithm>
545 33 : CreateNestedPipeline() const override
546 : {
547 66 : auto pipeline = std::make_unique<GDALPipelineAlgorithm>();
548 33 : pipeline->m_bInnerPipeline = true;
549 66 : return pipeline;
550 : }
551 : };
552 :
553 : /************************************************************************/
554 : /* GDALPipelineAlgorithm */
555 : /************************************************************************/
556 :
557 208 : GDALPipelineAlgorithm::GDALPipelineAlgorithm()
558 : : GDALAbstractPipelineAlgorithm(
559 : NAME, DESCRIPTION, HELP_URL,
560 208 : ConstructorOptions().SetStandaloneStep(false))
561 : {
562 208 : m_supportsStreamedOutput = true;
563 :
564 208 : AddProgressArg();
565 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
566 208 : /* positionalAndRequired = */ false)
567 208 : .SetMinCount(1)
568 208 : .SetMaxCount(INT_MAX)
569 208 : .SetHiddenForCLI();
570 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
571 208 : /* positionalAndRequired = */ false)
572 208 : .SetHiddenForCLI()
573 208 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
574 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
575 208 : /* bGDALGAllowed = */ true)
576 208 : .SetHiddenForCLI();
577 416 : AddArg("pipeline", 0, _("Pipeline string or filename"), &m_pipeline)
578 208 : .SetHiddenForCLI()
579 208 : .SetPositional();
580 :
581 208 : AddOutputStringArg(&m_output).SetHiddenForCLI();
582 208 : AddStdoutArg(&m_stdout);
583 :
584 208 : AllowArbitraryLongNameArgs();
585 :
586 208 : GDALRasterPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
587 208 : GDALVectorPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
588 208 : m_stepRegistry.Register<GDALRasterAsFeaturesAlgorithm>();
589 208 : m_stepRegistry.Register<GDALRasterContourAlgorithm>();
590 208 : m_stepRegistry.Register<GDALRasterFootprintAlgorithm>();
591 208 : m_stepRegistry.Register<GDALRasterPolygonizeAlgorithm>();
592 208 : m_stepRegistry.Register<GDALRasterZonalStatsAlgorithm>();
593 208 : m_stepRegistry.Register<GDALVectorGridAlgorithm>();
594 208 : m_stepRegistry.Register<GDALVectorRasterizeAlgorithm>();
595 208 : }
596 :
597 : /************************************************************************/
598 : /* GDALPipelineAlgorithm::GetUsageForCLI() */
599 : /************************************************************************/
600 :
601 : std::string
602 18 : GDALPipelineAlgorithm::GetUsageForCLI(bool shortUsage,
603 : const UsageOptions &usageOptions) const
604 : {
605 18 : UsageOptions stepUsageOptions;
606 18 : stepUsageOptions.isPipelineStep = true;
607 :
608 18 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
609 : {
610 4 : auto alg = GetStepAlg(m_helpDocCategory);
611 2 : if (alg)
612 : {
613 3 : alg->SetCallPath({CPLString(m_helpDocCategory)
614 2 : .replaceAll(RASTER_SUFFIX, "")
615 3 : .replaceAll(VECTOR_SUFFIX, "")});
616 1 : alg->GetArg("help-doc")->Set(true);
617 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
618 : }
619 : else
620 : {
621 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
622 : m_helpDocCategory.c_str());
623 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
624 1 : m_helpDocCategory.c_str());
625 : }
626 : }
627 :
628 16 : UsageOptions usageOptionsMain(usageOptions);
629 16 : usageOptionsMain.isPipelineMain = true;
630 : std::string ret =
631 32 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
632 16 : if (shortUsage)
633 14 : return ret;
634 :
635 : ret +=
636 : "\n<PIPELINE> is of the form: read|calc|concat|create|mosaic|stack "
637 : "[READ-OPTIONS] "
638 2 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write!info!tile [WRITE-OPTIONS]\n";
639 :
640 2 : if (m_helpDocCategory == "main")
641 : {
642 1 : return ret;
643 : }
644 :
645 1 : ret += '\n';
646 1 : ret += "Example: 'gdal pipeline --progress ! read in.tif ! \\\n";
647 1 : ret += " rasterize --size 256 256 ! buffer 20 ! ";
648 1 : ret += "write out.gpkg --overwrite'\n";
649 1 : ret += '\n';
650 1 : ret += "Potential steps are:\n";
651 :
652 75 : for (const std::string &name : m_stepRegistry.GetNames())
653 : {
654 148 : auto alg = GetStepAlg(name);
655 74 : assert(alg);
656 74 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
657 74 : stepUsageOptions.maxOptLen =
658 74 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
659 : }
660 :
661 : {
662 1 : ret += '\n';
663 1 : auto alg = std::make_unique<GDALRasterReadAlgorithm>();
664 2 : alg->SetCallPath({alg->GetName()});
665 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
666 : }
667 : {
668 1 : ret += '\n';
669 1 : auto alg = std::make_unique<GDALVectorReadAlgorithm>();
670 2 : alg->SetCallPath({alg->GetName()});
671 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
672 : }
673 75 : for (const std::string &name : m_stepRegistry.GetNames())
674 : {
675 148 : auto alg = GetStepAlg(name);
676 74 : assert(alg);
677 81 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
678 87 : !alg->IsHidden() &&
679 6 : !STARTS_WITH(name.c_str(), GDALRasterReadAlgorithm::NAME))
680 : {
681 4 : ret += '\n';
682 8 : alg->SetCallPath({name});
683 4 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
684 : }
685 : }
686 75 : for (const std::string &name : m_stepRegistry.GetNames())
687 : {
688 148 : auto alg = GetStepAlg(name);
689 74 : assert(alg);
690 74 : if (alg->CanBeMiddleStep() && !alg->IsHidden())
691 : {
692 61 : ret += '\n';
693 183 : alg->SetCallPath({CPLString(alg->GetName())
694 122 : .replaceAll(RASTER_SUFFIX, "")
695 183 : .replaceAll(VECTOR_SUFFIX, "")});
696 61 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
697 : }
698 : }
699 75 : for (const std::string &name : m_stepRegistry.GetNames())
700 : {
701 148 : auto alg = GetStepAlg(name);
702 74 : assert(alg);
703 84 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
704 91 : !alg->IsHidden() &&
705 7 : !STARTS_WITH(name.c_str(), GDALRasterWriteAlgorithm::NAME))
706 : {
707 5 : ret += '\n';
708 10 : alg->SetCallPath({name});
709 5 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
710 : }
711 : }
712 : {
713 1 : ret += '\n';
714 1 : auto alg = std::make_unique<GDALRasterWriteAlgorithm>();
715 2 : alg->SetCallPath({alg->GetName()});
716 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
717 : }
718 : {
719 1 : ret += '\n';
720 1 : auto alg = std::make_unique<GDALVectorWriteAlgorithm>();
721 2 : alg->SetCallPath({alg->GetName()});
722 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
723 : }
724 :
725 1 : ret += GetUsageForCLIEnd();
726 :
727 1 : return ret;
728 : }
729 :
730 : GDAL_STATIC_REGISTER_ALG(GDALPipelineAlgorithm);
731 :
732 : //! @endcond
|