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