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