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