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