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