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 13187 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
54 : const std::string &name, const std::string &description,
55 13187 : const std::string &helpURL, const ConstructorOptions &options)
56 : : GDALAlgorithm(name, description, helpURL),
57 13187 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
58 : {
59 13187 : }
60 :
61 : /************************************************************************/
62 : /* GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg() */
63 : /************************************************************************/
64 :
65 2023 : void GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg()
66 : {
67 2023 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER, false)
68 2023 : .SetMinCount(0)
69 2023 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
70 2023 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
71 2023 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
72 2023 : .SetHidden();
73 2023 : }
74 :
75 : /************************************************************************/
76 : /* GDALPipelineStepAlgorithm::AddRasterInputArgs() */
77 : /************************************************************************/
78 :
79 4548 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
80 : bool openForMixedRasterVector, bool hiddenForCLI)
81 : {
82 4548 : AddInputFormatsArg(&m_inputFormats)
83 : .AddMetadataItem(
84 : GAAMDI_REQUIRED_CAPABILITIES,
85 : openForMixedRasterVector
86 13907 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
87 13381 : : std::vector<std::string>{GDAL_DCAP_RASTER})
88 4548 : .SetHiddenForCLI(hiddenForCLI)
89 4548 : .SetAvailableInPipelineStep(false);
90 4548 : AddOpenOptionsArg(&m_openOptions)
91 4548 : .SetHiddenForCLI(hiddenForCLI)
92 4548 : .SetAvailableInPipelineStep(false);
93 : auto &arg =
94 : AddInputDatasetArg(
95 : &m_inputDataset,
96 : openForMixedRasterVector ? (GDAL_OF_RASTER | GDAL_OF_VECTOR)
97 : : GDAL_OF_RASTER,
98 4548 : false, m_constructorOptions.inputDatasetHelpMsg.c_str())
99 4548 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
100 4548 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
101 4548 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
102 4548 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
103 4548 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
104 4548 : .SetHiddenForCLI(hiddenForCLI)
105 4548 : .SetAvailableInPipelineStep(false);
106 4548 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
107 4222 : arg.SetPositional();
108 4548 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
109 4222 : arg.SetRequired();
110 4548 : if (!m_constructorOptions.inputDatasetAlias.empty())
111 836 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
112 4548 : }
113 :
114 : /************************************************************************/
115 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
116 : /************************************************************************/
117 :
118 2968 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
119 : {
120 2968 : m_outputFormatArg =
121 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
122 2968 : /* bGDALGAllowed = */ true)
123 : .AddMetadataItem(
124 : GAAMDI_REQUIRED_CAPABILITIES,
125 : {GDAL_DCAP_RASTER,
126 11872 : m_constructorOptions.outputFormatCreateCapability.c_str()})
127 2968 : .SetHiddenForCLI(hiddenForCLI))
128 2968 : .SetAvailableInPipelineStep(false);
129 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
130 2968 : /* positionalAndRequired = */ !hiddenForCLI,
131 2968 : m_constructorOptions.outputDatasetHelpMsg.c_str())
132 2968 : .SetHiddenForCLI(hiddenForCLI)
133 2968 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
134 2968 : .SetAvailableInPipelineStep(false);
135 2968 : AddCreationOptionsArg(&m_creationOptions)
136 2968 : .SetHiddenForCLI(hiddenForCLI)
137 2968 : .SetAvailableInPipelineStep(false);
138 2968 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
139 : "overwrite-append";
140 2968 : AddOverwriteArg(&m_overwrite)
141 2968 : .SetHiddenForCLI(hiddenForCLI)
142 5936 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND)
143 2968 : .SetAvailableInPipelineStep(false);
144 : AddArg(GDAL_ARG_NAME_APPEND, 0,
145 5936 : _("Append as a subdataset to existing output"), &m_appendRaster)
146 2968 : .SetDefault(false)
147 2968 : .SetHiddenForCLI(hiddenForCLI)
148 5936 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND)
149 2968 : .SetAvailableInPipelineStep(false);
150 2968 : }
151 :
152 : /************************************************************************/
153 : /* GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg() */
154 : /************************************************************************/
155 :
156 1904 : void GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg()
157 : {
158 1904 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
159 1904 : .SetMinCount(0)
160 1904 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
161 1904 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
162 1904 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
163 1904 : .SetHidden();
164 1904 : }
165 :
166 : /************************************************************************/
167 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
168 : /************************************************************************/
169 :
170 2645 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
171 : {
172 2645 : AddInputFormatsArg(&m_inputFormats)
173 7935 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
174 2645 : .SetHiddenForCLI(hiddenForCLI)
175 2645 : .SetAvailableInPipelineStep(false);
176 2645 : AddOpenOptionsArg(&m_openOptions)
177 2645 : .SetHiddenForCLI(hiddenForCLI)
178 2645 : .SetAvailableInPipelineStep(false);
179 : auto &datasetArg =
180 2645 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
181 2645 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
182 2645 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
183 2645 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
184 2645 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
185 2645 : .SetHiddenForCLI(hiddenForCLI)
186 2645 : .SetAvailableInPipelineStep(false);
187 2645 : if (!m_constructorOptions.inputDatasetAlias.empty())
188 180 : datasetArg.AddAlias(m_constructorOptions.inputDatasetAlias);
189 2645 : if (!m_constructorOptions.inputDatasetMetaVar.empty())
190 2645 : datasetArg.SetMetaVar(m_constructorOptions.inputDatasetMetaVar);
191 2645 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
192 2367 : datasetArg.SetPositional();
193 2645 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
194 2367 : datasetArg.SetRequired();
195 2645 : if (m_constructorOptions.addInputLayerNameArgument)
196 : {
197 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
198 4752 : _("Input layer name(s)"), &m_inputLayerNames)
199 4752 : .AddAlias("layer")
200 2376 : .SetHiddenForCLI(hiddenForCLI)
201 2376 : .SetAvailableInPipelineStep(false);
202 2376 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
203 : }
204 2645 : }
205 :
206 : /************************************************************************/
207 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
208 : /************************************************************************/
209 :
210 3067 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
211 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
212 : {
213 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
214 3067 : /* bGDALGAllowed = */ true)
215 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
216 12268 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
217 3067 : .SetHiddenForCLI(hiddenForCLI)
218 3067 : .SetAvailableInPipelineStep(false);
219 3067 : AddOutputOpenOptionsArg(&m_outputOpenOptions)
220 3067 : .SetHiddenForCLI(hiddenForCLI)
221 3067 : .SetAvailableInPipelineStep(false);
222 : auto &outputDatasetArg =
223 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
224 3067 : /* positionalAndRequired = */ false)
225 3067 : .SetHiddenForCLI(hiddenForCLI)
226 3067 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
227 3067 : .SetAvailableInPipelineStep(false);
228 3067 : if (!hiddenForCLI)
229 2910 : outputDatasetArg.SetPositional();
230 3067 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
231 2851 : outputDatasetArg.SetRequired();
232 :
233 3067 : AddCreationOptionsArg(&m_creationOptions)
234 3067 : .SetHiddenForCLI(hiddenForCLI)
235 3067 : .SetAvailableInPipelineStep(false);
236 3067 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
237 3067 : .SetHiddenForCLI(hiddenForCLI)
238 3067 : .SetAvailableInPipelineStep(false);
239 3067 : AddOverwriteArg(&m_overwrite)
240 3067 : .SetHiddenForCLI(hiddenForCLI)
241 3067 : .SetAvailableInPipelineStep(false);
242 3067 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
243 3067 : if (m_constructorOptions.addUpdateArgument)
244 : {
245 3005 : updateArg = &AddUpdateArg(&m_update)
246 3005 : .SetHiddenForCLI(hiddenForCLI)
247 3005 : .SetAvailableInPipelineStep(false);
248 : }
249 3067 : if (m_constructorOptions.addOverwriteLayerArgument)
250 : {
251 3005 : AddOverwriteLayerArg(&m_overwriteLayer)
252 3005 : .SetHiddenForCLI(hiddenForCLI)
253 3005 : .SetAvailableInPipelineStep(false);
254 : }
255 3067 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
256 : "append-upsert";
257 3067 : if (m_constructorOptions.addAppendLayerArgument)
258 : {
259 2884 : AddAppendLayerArg(&m_appendLayer)
260 2884 : .SetHiddenForCLI(hiddenForCLI)
261 5768 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
262 2884 : .SetAvailableInPipelineStep(false);
263 : }
264 3067 : if (m_constructorOptions.addUpsertArgument)
265 : {
266 5518 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
267 2759 : .SetHiddenForCLI(hiddenForCLI)
268 5518 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
269 :
270 2759 : .SetAvailableInPipelineStep(false)
271 : .AddAction(
272 12 : [updateArg, this]()
273 : {
274 4 : if (m_upsert && updateArg)
275 4 : updateArg->Set(true);
276 5518 : })
277 2759 : .SetCategory(GAAC_ADVANCED);
278 : }
279 3067 : if (m_constructorOptions.addOutputLayerNameArgument)
280 : {
281 2939 : AddOutputLayerNameArg(hiddenForCLI, shortNameOutputLayerAllowed);
282 : }
283 3067 : if (m_constructorOptions.addSkipErrorsArgument)
284 : {
285 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
286 5518 : &m_skipErrors)
287 5518 : .AddHiddenAlias("skip-failures") // For ogr2ogr nostalgic people
288 2759 : .SetAvailableInPipelineStep(false);
289 : }
290 3067 : if (m_constructorOptions.addNoCreateEmptyLayersArgument)
291 : {
292 : AddArg("no-create-empty-layers", 0,
293 : _("Avoid creating layers to which no features will be written"),
294 2078 : &m_noCreateEmptyLayers)
295 1039 : .SetAvailableInPipelineStep(false);
296 : }
297 3067 : }
298 :
299 : /************************************************************************/
300 : /* GDALPipelineStepAlgorithm::AddOutputLayerNameArg() */
301 : /************************************************************************/
302 :
303 3124 : void GDALPipelineStepAlgorithm::AddOutputLayerNameArg(
304 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
305 : {
306 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER, shortNameOutputLayerAllowed ? 'l' : 0,
307 : _("Output layer name"),
308 6248 : &m_outputLayerName)
309 6248 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
310 3124 : .SetHiddenForCLI(hiddenForCLI)
311 : .SetAvailableInPipelineStep(
312 3124 : m_constructorOptions.outputLayerNameAvailableInPipelineStep);
313 3124 : }
314 :
315 : /************************************************************************/
316 : /* GDALPipelineStepAlgorithm::RunImpl() */
317 : /************************************************************************/
318 :
319 2600 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
320 : void *pProgressData)
321 : {
322 2600 : if (m_standaloneStep)
323 : {
324 1105 : std::unique_ptr<GDALPipelineStepAlgorithm> readAlg;
325 1105 : if (GetInputType() == GDAL_OF_RASTER)
326 701 : readAlg = std::make_unique<GDALRasterReadAlgorithm>();
327 : else
328 404 : readAlg = std::make_unique<GDALVectorReadAlgorithm>();
329 9244 : for (auto &arg : readAlg->GetArgs())
330 : {
331 8139 : auto stepArg = GetArg(arg->GetName());
332 9259 : if (stepArg && stepArg->IsExplicitlySet() &&
333 1120 : stepArg->GetType() == arg->GetType())
334 : {
335 1117 : arg->SetSkipIfAlreadySet(true);
336 1117 : arg->SetFrom(*stepArg);
337 : }
338 : }
339 :
340 0 : std::unique_ptr<GDALPipelineStepAlgorithm> writeAlg;
341 1105 : if (GetOutputType() == GDAL_OF_RASTER)
342 : {
343 485 : if (GetName() == GDALRasterInfoAlgorithm::NAME)
344 25 : writeAlg = std::make_unique<GDALRasterInfoAlgorithm>();
345 460 : else if (GetName() == GDALRasterCompareAlgorithm::NAME)
346 0 : writeAlg = std::make_unique<GDALRasterCompareAlgorithm>();
347 : else
348 460 : writeAlg = std::make_unique<GDALRasterWriteAlgorithm>();
349 : }
350 : else
351 : {
352 620 : if (GetName() == GDALVectorInfoAlgorithm::NAME)
353 27 : writeAlg = std::make_unique<GDALVectorInfoAlgorithm>();
354 : else
355 593 : writeAlg = std::make_unique<GDALVectorWriteAlgorithm>();
356 : }
357 18060 : for (auto &arg : writeAlg->GetArgs())
358 : {
359 16955 : auto stepArg = GetArg(arg->GetName());
360 19746 : if (stepArg && stepArg->IsExplicitlySet() &&
361 2791 : stepArg->GetType() == arg->GetType())
362 : {
363 2788 : arg->SetSkipIfAlreadySet(true);
364 2788 : arg->SetFrom(*stepArg);
365 : }
366 : }
367 :
368 1105 : const bool bIsStreaming = m_format == "stream";
369 :
370 : // Already checked by GDALAlgorithm::Run()
371 1105 : CPLAssert(!m_executionForStreamOutput || bIsStreaming);
372 :
373 1105 : bool ret = false;
374 1161 : if (!m_outputVRTCompatible &&
375 112 : (EQUAL(m_format.c_str(), "VRT") ||
376 56 : (m_format.empty() &&
377 1106 : 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 1105 : else if (readAlg->Run())
387 : {
388 1101 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
389 : const bool bOutputSpecified =
390 1101 : outputArg && outputArg->IsExplicitlySet();
391 :
392 1101 : m_inputDataset.clear();
393 1101 : m_inputDataset.resize(1);
394 1101 : m_inputDataset[0].Set(readAlg->m_outputDataset.GetDatasetRef());
395 1101 : if (bOutputSpecified)
396 843 : m_outputDataset.Set(nullptr);
397 :
398 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
399 2202 : pScaledData(nullptr, GDALDestroyScaledProgress);
400 :
401 : const bool bCanHandleNextStep =
402 1101 : !bIsStreaming && CanHandleNextStep(writeAlg.get());
403 :
404 1101 : GDALPipelineStepRunContext stepCtxt;
405 1101 : if (pfnProgress && GetName() == GDALRasterCompareAlgorithm::NAME)
406 : {
407 5 : stepCtxt.m_pfnProgress = pfnProgress;
408 5 : stepCtxt.m_pProgressData = pProgressData;
409 : }
410 1138 : 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 1101 : if (bCanHandleNextStep)
422 47 : stepCtxt.m_poNextUsableStep = writeAlg.get();
423 1101 : if (RunPreStepPipelineValidations() && RunStep(stepCtxt))
424 : {
425 1016 : if (bCanHandleNextStep || !bOutputSpecified)
426 : {
427 294 : ret = true;
428 : }
429 : else
430 : {
431 722 : writeAlg->m_outputVRTCompatible = m_outputVRTCompatible;
432 722 : writeAlg->m_quiet = m_quiet;
433 :
434 1444 : std::vector<GDALArgDatasetValue> inputDataset(1);
435 722 : inputDataset[0].Set(m_outputDataset.GetDatasetRef());
436 722 : auto inputArg = writeAlg->GetArg(GDAL_ARG_NAME_INPUT);
437 722 : CPLAssert(inputArg);
438 722 : inputArg->Set(std::move(inputDataset));
439 :
440 722 : if (pfnProgress)
441 : {
442 33 : pScaledData.reset(GDALCreateScaledProgress(
443 33 : IsNativelyStreamingCompatible() ? 0.0 : 0.5, 1.0,
444 : pfnProgress, pProgressData));
445 : }
446 722 : stepCtxt.m_pfnProgress =
447 722 : pScaledData ? GDALScaledProgress : nullptr;
448 722 : stepCtxt.m_pProgressData = pScaledData.get();
449 1444 : if (writeAlg->ValidateArguments() &&
450 722 : writeAlg->RunStep(stepCtxt))
451 : {
452 704 : if (pfnProgress)
453 32 : pfnProgress(1.0, "", pProgressData);
454 :
455 704 : m_outputDataset.Set(
456 704 : writeAlg->m_outputDataset.GetDatasetRef());
457 704 : ret = true;
458 : }
459 : }
460 : }
461 : }
462 :
463 1105 : return ret;
464 : }
465 : else
466 : {
467 1495 : GDALPipelineStepRunContext stepCtxt;
468 1495 : stepCtxt.m_pfnProgress = pfnProgress;
469 1495 : stepCtxt.m_pProgressData = pProgressData;
470 1495 : 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 3598 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
497 : {
498 3598 : if (m_standaloneStep)
499 : {
500 2045 : return GDALAlgorithm::ProcessGDALGOutput();
501 : }
502 : else
503 : {
504 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep() might
505 : // actually detect a GDALG output request and process it.
506 1553 : 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 1288 : bool GDALPipelineStepAlgorithm::Finalize()
534 : {
535 1288 : bool ret = GDALAlgorithm::Finalize();
536 2410 : for (auto &argValue : m_inputDataset)
537 1122 : ret = argValue.Close() && ret;
538 1288 : ret = m_outputDataset.Close() && ret;
539 1288 : 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
|