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