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