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