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