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 13131 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
54 : const std::string &name, const std::string &description,
55 13131 : const std::string &helpURL, const ConstructorOptions &options)
56 : : GDALAlgorithm(name, description, helpURL),
57 13131 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
58 : {
59 13131 : }
60 :
61 : /************************************************************************/
62 : /* GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg() */
63 : /************************************************************************/
64 :
65 2027 : void GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg()
66 : {
67 2027 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER, false)
68 2027 : .SetMinCount(0)
69 2027 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
70 2027 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
71 2027 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
72 2027 : .SetHidden();
73 2027 : }
74 :
75 : /************************************************************************/
76 : /* GDALPipelineStepAlgorithm::AddRasterInputArgs() */
77 : /************************************************************************/
78 :
79 4528 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
80 : bool openForMixedRasterVector, bool hiddenForCLI)
81 : {
82 4528 : AddInputFormatsArg(&m_inputFormats)
83 : .AddMetadataItem(
84 : GAAMDI_REQUIRED_CAPABILITIES,
85 : openForMixedRasterVector
86 13847 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
87 13321 : : std::vector<std::string>{GDAL_DCAP_RASTER})
88 4528 : .SetHiddenForCLI(hiddenForCLI);
89 4528 : 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 4528 : false, m_constructorOptions.inputDatasetHelpMsg.c_str())
96 4528 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
97 4528 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
98 4528 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
99 4528 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
100 4528 : .SetHiddenForCLI(hiddenForCLI);
101 4528 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
102 4211 : arg.SetPositional();
103 4528 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
104 4211 : arg.SetRequired();
105 4528 : if (!m_constructorOptions.inputDatasetAlias.empty())
106 826 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
107 4528 : }
108 :
109 : /************************************************************************/
110 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
111 : /************************************************************************/
112 :
113 2961 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
114 : {
115 2961 : m_outputFormatArg =
116 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
117 2961 : /* bGDALGAllowed = */ true)
118 : .AddMetadataItem(
119 : GAAMDI_REQUIRED_CAPABILITIES,
120 : {GDAL_DCAP_RASTER,
121 11844 : m_constructorOptions.outputFormatCreateCapability.c_str()})
122 2961 : .SetHiddenForCLI(hiddenForCLI));
123 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
124 2961 : /* positionalAndRequired = */ !hiddenForCLI,
125 2961 : m_constructorOptions.outputDatasetHelpMsg.c_str())
126 2961 : .SetHiddenForCLI(hiddenForCLI)
127 2961 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
128 2961 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
129 2961 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
130 : "overwrite-append";
131 2961 : AddOverwriteArg(&m_overwrite)
132 2961 : .SetHiddenForCLI(hiddenForCLI)
133 2961 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
134 : AddArg(GDAL_ARG_NAME_APPEND, 0,
135 5922 : _("Append as a subdataset to existing output"), &m_appendRaster)
136 2961 : .SetDefault(false)
137 2961 : .SetHiddenForCLI(hiddenForCLI)
138 2961 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND);
139 2961 : }
140 :
141 : /************************************************************************/
142 : /* GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg() */
143 : /************************************************************************/
144 :
145 1890 : void GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg()
146 : {
147 1890 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
148 1890 : .SetMinCount(0)
149 1890 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
150 1890 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
151 1890 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
152 1890 : .SetHidden();
153 1890 : }
154 :
155 : /************************************************************************/
156 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
157 : /************************************************************************/
158 :
159 2619 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
160 : {
161 2619 : AddInputFormatsArg(&m_inputFormats)
162 7857 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
163 2619 : .SetHiddenForCLI(hiddenForCLI);
164 2619 : AddOpenOptionsArg(&m_openOptions).SetHiddenForCLI(hiddenForCLI);
165 : auto &datasetArg =
166 2619 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
167 2619 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
168 2619 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
169 2619 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
170 2619 : .SetHiddenForCLI(hiddenForCLI);
171 2619 : if (!m_constructorOptions.inputDatasetAlias.empty())
172 180 : datasetArg.AddAlias(m_constructorOptions.inputDatasetAlias);
173 2619 : if (!m_constructorOptions.inputDatasetMetaVar.empty())
174 2619 : datasetArg.SetMetaVar(m_constructorOptions.inputDatasetMetaVar);
175 2619 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
176 2353 : datasetArg.SetPositional();
177 2619 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
178 2353 : datasetArg.SetRequired();
179 2619 : if (m_constructorOptions.addInputLayerNameArgument)
180 : {
181 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
182 4700 : _("Input layer name(s)"), &m_inputLayerNames)
183 4700 : .AddAlias("layer")
184 2350 : .SetHiddenForCLI(hiddenForCLI);
185 2350 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
186 : }
187 2619 : }
188 :
189 : /************************************************************************/
190 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
191 : /************************************************************************/
192 :
193 3038 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
194 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
195 : {
196 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
197 3038 : /* bGDALGAllowed = */ true)
198 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
199 12152 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
200 3038 : .SetHiddenForCLI(hiddenForCLI);
201 3038 : AddOutputOpenOptionsArg(&m_outputOpenOptions).SetHiddenForCLI(hiddenForCLI);
202 : auto &outputDatasetArg =
203 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
204 3038 : /* positionalAndRequired = */ false)
205 3038 : .SetHiddenForCLI(hiddenForCLI)
206 3038 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
207 3038 : if (!hiddenForCLI)
208 2893 : outputDatasetArg.SetPositional();
209 3038 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
210 2834 : outputDatasetArg.SetRequired();
211 :
212 3038 : AddCreationOptionsArg(&m_creationOptions).SetHiddenForCLI(hiddenForCLI);
213 3038 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
214 3038 : .SetHiddenForCLI(hiddenForCLI);
215 3038 : AddOverwriteArg(&m_overwrite).SetHiddenForCLI(hiddenForCLI);
216 3038 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
217 3038 : if (m_constructorOptions.addUpdateArgument)
218 : {
219 2976 : updateArg = &AddUpdateArg(&m_update).SetHiddenForCLI(hiddenForCLI);
220 : }
221 3038 : if (m_constructorOptions.addOverwriteLayerArgument)
222 : {
223 2976 : AddOverwriteLayerArg(&m_overwriteLayer).SetHiddenForCLI(hiddenForCLI);
224 : }
225 3038 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
226 : "append-upsert";
227 3038 : if (m_constructorOptions.addAppendLayerArgument)
228 : {
229 2855 : AddAppendLayerArg(&m_appendLayer)
230 2855 : .SetHiddenForCLI(hiddenForCLI)
231 2855 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT);
232 : }
233 3038 : if (m_constructorOptions.addUpsertArgument)
234 : {
235 5460 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
236 2730 : .SetHiddenForCLI(hiddenForCLI)
237 5460 : .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 5460 : })
244 2730 : .SetCategory(GAAC_ADVANCED);
245 : }
246 3038 : if (m_constructorOptions.addOutputLayerNameArgument)
247 : {
248 2910 : AddOutputLayerNameArg(hiddenForCLI, shortNameOutputLayerAllowed);
249 : }
250 3038 : if (m_constructorOptions.addSkipErrorsArgument)
251 : {
252 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
253 5460 : &m_skipErrors)
254 2730 : .AddHiddenAlias("skip-failures"); // For ogr2ogr nostalgic people
255 : }
256 3038 : if (m_constructorOptions.addNoCreateEmptyLayersArgument)
257 : {
258 : AddArg("no-create-empty-layers", 0,
259 : _("Avoid creating layers to which no features will be written"),
260 1034 : &m_noCreateEmptyLayers);
261 : }
262 3038 : }
263 :
264 : /************************************************************************/
265 : /* GDALPipelineStepAlgorithm::AddOutputLayerNameArg() */
266 : /************************************************************************/
267 :
268 3035 : void GDALPipelineStepAlgorithm::AddOutputLayerNameArg(
269 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
270 : {
271 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER, shortNameOutputLayerAllowed ? 'l' : 0,
272 : _("Output layer name"),
273 6070 : &m_outputLayerName)
274 6070 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
275 3035 : .SetHiddenForCLI(hiddenForCLI);
276 3035 : }
277 :
278 : /************************************************************************/
279 : /* GDALPipelineStepAlgorithm::RunImpl() */
280 : /************************************************************************/
281 :
282 2594 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
283 : void *pProgressData)
284 : {
285 2594 : if (m_standaloneStep)
286 : {
287 1108 : std::unique_ptr<GDALPipelineStepAlgorithm> readAlg;
288 1108 : if (GetInputType() == GDAL_OF_RASTER)
289 705 : readAlg = std::make_unique<GDALRasterReadAlgorithm>();
290 : else
291 403 : readAlg = std::make_unique<GDALVectorReadAlgorithm>();
292 9267 : for (auto &arg : readAlg->GetArgs())
293 : {
294 8159 : auto stepArg = GetArg(arg->GetName());
295 9282 : if (stepArg && stepArg->IsExplicitlySet() &&
296 1123 : stepArg->GetType() == arg->GetType())
297 : {
298 1120 : arg->SetSkipIfAlreadySet(true);
299 1120 : arg->SetFrom(*stepArg);
300 : }
301 : }
302 :
303 0 : std::unique_ptr<GDALPipelineStepAlgorithm> writeAlg;
304 1108 : if (GetOutputType() == GDAL_OF_RASTER)
305 : {
306 489 : if (GetName() == GDALRasterInfoAlgorithm::NAME)
307 25 : writeAlg = std::make_unique<GDALRasterInfoAlgorithm>();
308 464 : else if (GetName() == GDALRasterCompareAlgorithm::NAME)
309 0 : writeAlg = std::make_unique<GDALRasterCompareAlgorithm>();
310 : else
311 464 : writeAlg = std::make_unique<GDALRasterWriteAlgorithm>();
312 : }
313 : else
314 : {
315 619 : if (GetName() == GDALVectorInfoAlgorithm::NAME)
316 27 : writeAlg = std::make_unique<GDALVectorInfoAlgorithm>();
317 : else
318 592 : writeAlg = std::make_unique<GDALVectorWriteAlgorithm>();
319 : }
320 18084 : for (auto &arg : writeAlg->GetArgs())
321 : {
322 16976 : auto stepArg = GetArg(arg->GetName());
323 19777 : if (stepArg && stepArg->IsExplicitlySet() &&
324 2801 : stepArg->GetType() == arg->GetType())
325 : {
326 2798 : arg->SetSkipIfAlreadySet(true);
327 2798 : arg->SetFrom(*stepArg);
328 : }
329 : }
330 :
331 1108 : const bool bIsStreaming = m_format == "stream";
332 :
333 : // Already checked by GDALAlgorithm::Run()
334 1108 : CPLAssert(!m_executionForStreamOutput || bIsStreaming);
335 :
336 1108 : bool ret = false;
337 1164 : if (!m_outputVRTCompatible &&
338 112 : (EQUAL(m_format.c_str(), "VRT") ||
339 56 : (m_format.empty() &&
340 1109 : 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 1108 : else if (readAlg->Run())
350 : {
351 1104 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
352 : const bool bOutputSpecified =
353 1104 : outputArg && outputArg->IsExplicitlySet();
354 :
355 1104 : m_inputDataset.clear();
356 1104 : m_inputDataset.resize(1);
357 1104 : m_inputDataset[0].Set(readAlg->m_outputDataset.GetDatasetRef());
358 1104 : if (bOutputSpecified)
359 846 : m_outputDataset.Set(nullptr);
360 :
361 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
362 2208 : pScaledData(nullptr, GDALDestroyScaledProgress);
363 :
364 : const bool bCanHandleNextStep =
365 1104 : !bIsStreaming && CanHandleNextStep(writeAlg.get());
366 :
367 1104 : GDALPipelineStepRunContext stepCtxt;
368 1104 : if (pfnProgress && GetName() == GDALRasterCompareAlgorithm::NAME)
369 : {
370 5 : stepCtxt.m_pfnProgress = pfnProgress;
371 5 : stepCtxt.m_pProgressData = pProgressData;
372 : }
373 1141 : 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 1104 : if (bCanHandleNextStep)
385 47 : stepCtxt.m_poNextUsableStep = writeAlg.get();
386 1104 : if (RunPreStepPipelineValidations() && RunStep(stepCtxt))
387 : {
388 1015 : if (bCanHandleNextStep || !bOutputSpecified)
389 : {
390 294 : ret = true;
391 : }
392 : else
393 : {
394 721 : writeAlg->m_outputVRTCompatible = m_outputVRTCompatible;
395 721 : writeAlg->m_quiet = m_quiet;
396 :
397 1442 : std::vector<GDALArgDatasetValue> inputDataset(1);
398 721 : inputDataset[0].Set(m_outputDataset.GetDatasetRef());
399 721 : auto inputArg = writeAlg->GetArg(GDAL_ARG_NAME_INPUT);
400 721 : CPLAssert(inputArg);
401 721 : inputArg->Set(std::move(inputDataset));
402 :
403 721 : if (pfnProgress)
404 : {
405 33 : pScaledData.reset(GDALCreateScaledProgress(
406 33 : IsNativelyStreamingCompatible() ? 0.0 : 0.5, 1.0,
407 : pfnProgress, pProgressData));
408 : }
409 721 : stepCtxt.m_pfnProgress =
410 721 : pScaledData ? GDALScaledProgress : nullptr;
411 721 : stepCtxt.m_pProgressData = pScaledData.get();
412 1442 : if (writeAlg->ValidateArguments() &&
413 721 : writeAlg->RunStep(stepCtxt))
414 : {
415 703 : if (pfnProgress)
416 32 : pfnProgress(1.0, "", pProgressData);
417 :
418 703 : m_outputDataset.Set(
419 703 : writeAlg->m_outputDataset.GetDatasetRef());
420 703 : ret = true;
421 : }
422 : }
423 : }
424 : }
425 :
426 1108 : return ret;
427 : }
428 : else
429 : {
430 1486 : GDALPipelineStepRunContext stepCtxt;
431 1486 : stepCtxt.m_pfnProgress = pfnProgress;
432 1486 : stepCtxt.m_pProgressData = pProgressData;
433 1486 : 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 3571 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
460 : {
461 3571 : if (m_standaloneStep)
462 : {
463 2027 : return GDALAlgorithm::ProcessGDALGOutput();
464 : }
465 : else
466 : {
467 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep() might
468 : // actually detect a GDALG output request and process it.
469 1544 : return GDALAlgorithm::ProcessGDALGOutputRet::NOT_GDALG;
470 : }
471 : }
472 :
473 : /************************************************************************/
474 : /* GDALPipelineStepAlgorithm::CheckSafeForStreamOutput() */
475 : /************************************************************************/
476 :
477 93 : bool GDALPipelineStepAlgorithm::CheckSafeForStreamOutput()
478 : {
479 93 : if (m_standaloneStep)
480 : {
481 48 : 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 1274 : bool GDALPipelineStepAlgorithm::Finalize()
497 : {
498 1274 : bool ret = GDALAlgorithm::Finalize();
499 2384 : for (auto &argValue : m_inputDataset)
500 1110 : ret = argValue.Close() && ret;
501 1274 : ret = m_outputDataset.Close() && ret;
502 1274 : 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
|