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 13208 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
54 : const std::string &name, const std::string &description,
55 13208 : const std::string &helpURL, const ConstructorOptions &options)
56 : : GDALAlgorithm(name, description, helpURL),
57 13208 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
58 : {
59 13208 : }
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 4558 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
80 : bool openForMixedRasterVector, bool hiddenForCLI)
81 : {
82 4558 : AddInputFormatsArg(&m_inputFormats)
83 : .AddMetadataItem(
84 : GAAMDI_REQUIRED_CAPABILITIES,
85 : openForMixedRasterVector
86 13937 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
87 13411 : : std::vector<std::string>{GDAL_DCAP_RASTER})
88 4558 : .SetHiddenForCLI(hiddenForCLI)
89 4558 : .SetAvailableInPipelineStep(false);
90 4558 : AddOpenOptionsArg(&m_openOptions)
91 4558 : .SetHiddenForCLI(hiddenForCLI)
92 4558 : .SetAvailableInPipelineStep(false);
93 : auto &arg =
94 : AddInputDatasetArg(
95 : &m_inputDataset,
96 : openForMixedRasterVector ? (GDAL_OF_RASTER | GDAL_OF_VECTOR)
97 : : GDAL_OF_RASTER,
98 4558 : false, m_constructorOptions.inputDatasetHelpMsg.c_str())
99 4558 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
100 4558 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
101 4558 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
102 4558 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
103 4558 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
104 4558 : .SetHiddenForCLI(hiddenForCLI)
105 4558 : .SetAvailableInPipelineStep(false);
106 4558 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
107 4232 : arg.SetPositional();
108 4558 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
109 4232 : arg.SetRequired();
110 4558 : if (!m_constructorOptions.inputDatasetAlias.empty())
111 836 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
112 4558 : }
113 :
114 : /************************************************************************/
115 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
116 : /************************************************************************/
117 :
118 2976 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
119 : {
120 2976 : m_outputFormatArg =
121 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
122 2976 : /* bGDALGAllowed = */ true)
123 : .AddMetadataItem(
124 : GAAMDI_REQUIRED_CAPABILITIES,
125 : {GDAL_DCAP_RASTER,
126 11904 : m_constructorOptions.outputFormatCreateCapability.c_str()})
127 2976 : .SetHiddenForCLI(hiddenForCLI))
128 2976 : .SetAvailableInPipelineStep(false);
129 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
130 2976 : /* positionalAndRequired = */ !hiddenForCLI,
131 2976 : m_constructorOptions.outputDatasetHelpMsg.c_str())
132 2976 : .SetHiddenForCLI(hiddenForCLI)
133 2976 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
134 2976 : .SetAvailableInPipelineStep(false);
135 2976 : AddCreationOptionsArg(&m_creationOptions)
136 2976 : .SetHiddenForCLI(hiddenForCLI)
137 2976 : .SetAvailableInPipelineStep(false);
138 2976 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
139 : "overwrite-append";
140 2976 : AddOverwriteArg(&m_overwrite)
141 2976 : .SetHiddenForCLI(hiddenForCLI)
142 5952 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND)
143 2976 : .SetAvailableInPipelineStep(false);
144 : AddArg(GDAL_ARG_NAME_APPEND, 0,
145 5952 : _("Append as a subdataset to existing output"), &m_appendRaster)
146 2976 : .SetDefault(false)
147 2976 : .SetHiddenForCLI(hiddenForCLI)
148 5952 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND)
149 2976 : .SetAvailableInPipelineStep(false);
150 2976 : }
151 :
152 : /************************************************************************/
153 : /* GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg() */
154 : /************************************************************************/
155 :
156 1903 : void GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg()
157 : {
158 1903 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
159 1903 : .SetMinCount(0)
160 1903 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
161 1903 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
162 1903 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
163 1903 : .SetHidden();
164 1903 : }
165 :
166 : /************************************************************************/
167 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
168 : /************************************************************************/
169 :
170 2657 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
171 : {
172 2657 : AddInputFormatsArg(&m_inputFormats)
173 7971 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
174 2657 : .SetHiddenForCLI(hiddenForCLI)
175 2657 : .SetAvailableInPipelineStep(false);
176 2657 : AddOpenOptionsArg(&m_openOptions)
177 2657 : .SetHiddenForCLI(hiddenForCLI)
178 2657 : .SetAvailableInPipelineStep(false);
179 : auto &datasetArg =
180 2657 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
181 2657 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
182 2657 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
183 2657 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
184 2657 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
185 2657 : .SetHiddenForCLI(hiddenForCLI)
186 2657 : .SetAvailableInPipelineStep(false);
187 2657 : if (!m_constructorOptions.inputDatasetAlias.empty())
188 188 : datasetArg.AddAlias(m_constructorOptions.inputDatasetAlias);
189 2657 : if (!m_constructorOptions.inputDatasetMetaVar.empty())
190 2657 : datasetArg.SetMetaVar(m_constructorOptions.inputDatasetMetaVar);
191 2657 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
192 2371 : datasetArg.SetPositional();
193 2657 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
194 2371 : datasetArg.SetRequired();
195 2657 : if (m_constructorOptions.addInputLayerNameArgument)
196 : {
197 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
198 4776 : _("Input layer name(s)"), &m_inputLayerNames)
199 4776 : .AddAlias("layer")
200 2388 : .SetHiddenForCLI(hiddenForCLI)
201 2388 : .SetAvailableInPipelineStep(false);
202 2388 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
203 : }
204 2657 : }
205 :
206 : /************************************************************************/
207 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
208 : /************************************************************************/
209 :
210 3081 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
211 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
212 : {
213 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
214 3081 : /* bGDALGAllowed = */ true)
215 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
216 12324 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
217 3081 : .SetHiddenForCLI(hiddenForCLI)
218 3081 : .SetAvailableInPipelineStep(false);
219 3081 : AddOutputOpenOptionsArg(&m_outputOpenOptions)
220 3081 : .SetHiddenForCLI(hiddenForCLI)
221 3081 : .SetAvailableInPipelineStep(false);
222 : auto &outputDatasetArg =
223 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
224 3081 : /* positionalAndRequired = */ false)
225 3081 : .SetHiddenForCLI(hiddenForCLI)
226 3081 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
227 3081 : .SetAvailableInPipelineStep(false);
228 3081 : if (!hiddenForCLI)
229 2924 : outputDatasetArg.SetPositional();
230 3081 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
231 2865 : outputDatasetArg.SetRequired();
232 :
233 3081 : AddCreationOptionsArg(&m_creationOptions)
234 3081 : .SetHiddenForCLI(hiddenForCLI)
235 3081 : .SetAvailableInPipelineStep(false);
236 3081 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
237 3081 : .SetHiddenForCLI(hiddenForCLI)
238 3081 : .SetAvailableInPipelineStep(false);
239 3081 : AddOverwriteArg(&m_overwrite)
240 3081 : .SetHiddenForCLI(hiddenForCLI)
241 3081 : .SetAvailableInPipelineStep(false);
242 3081 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
243 3081 : if (m_constructorOptions.addUpdateArgument)
244 : {
245 3019 : updateArg = &AddUpdateArg(&m_update)
246 3019 : .SetHiddenForCLI(hiddenForCLI)
247 3019 : .SetAvailableInPipelineStep(false);
248 : }
249 3081 : if (m_constructorOptions.addOverwriteLayerArgument)
250 : {
251 3019 : AddOverwriteLayerArg(&m_overwriteLayer)
252 3019 : .SetHiddenForCLI(hiddenForCLI)
253 3019 : .SetAvailableInPipelineStep(false);
254 : }
255 3081 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
256 : "append-upsert";
257 3081 : if (m_constructorOptions.addAppendLayerArgument)
258 : {
259 2890 : AddAppendLayerArg(&m_appendLayer)
260 2890 : .SetHiddenForCLI(hiddenForCLI)
261 5780 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
262 2890 : .SetAvailableInPipelineStep(false);
263 : }
264 3081 : if (m_constructorOptions.addUpsertArgument)
265 : {
266 5530 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
267 2765 : .SetHiddenForCLI(hiddenForCLI)
268 5530 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
269 :
270 2765 : .SetAvailableInPipelineStep(false)
271 : .AddAction(
272 12 : [updateArg, this]()
273 : {
274 4 : if (m_upsert && updateArg)
275 4 : updateArg->Set(true);
276 5530 : })
277 2765 : .SetCategory(GAAC_ADVANCED);
278 : }
279 3081 : if (m_constructorOptions.addOutputLayerNameArgument)
280 : {
281 2953 : AddOutputLayerNameArg(hiddenForCLI, shortNameOutputLayerAllowed);
282 : }
283 3081 : if (m_constructorOptions.addSkipErrorsArgument)
284 : {
285 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
286 5530 : &m_skipErrors)
287 5530 : .AddHiddenAlias("skip-failures") // For ogr2ogr nostalgic people
288 2765 : .SetAvailableInPipelineStep(false);
289 : }
290 3081 : if (m_constructorOptions.addNoCreateEmptyLayersArgument)
291 : {
292 : AddArg("no-create-empty-layers", 0,
293 : _("Avoid creating layers to which no features will be written"),
294 2080 : &m_noCreateEmptyLayers)
295 1040 : .SetAvailableInPipelineStep(false);
296 : }
297 3081 : }
298 :
299 : /************************************************************************/
300 : /* GDALPipelineStepAlgorithm::AddOutputLayerNameArg() */
301 : /************************************************************************/
302 :
303 3138 : void GDALPipelineStepAlgorithm::AddOutputLayerNameArg(
304 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
305 : {
306 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER, shortNameOutputLayerAllowed ? 'l' : 0,
307 : _("Output layer name"),
308 6276 : &m_outputLayerName)
309 6276 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
310 3138 : .SetHiddenForCLI(hiddenForCLI)
311 : .SetAvailableInPipelineStep(
312 3138 : m_constructorOptions.outputLayerNameAvailableInPipelineStep);
313 3138 : }
314 :
315 : /************************************************************************/
316 : /* GDALPipelineStepAlgorithm::RunImpl() */
317 : /************************************************************************/
318 :
319 2596 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
320 : void *pProgressData)
321 : {
322 2596 : if (m_standaloneStep)
323 : {
324 1104 : std::unique_ptr<GDALPipelineStepAlgorithm> readAlg;
325 1104 : if (GetInputType() == GDAL_OF_RASTER)
326 701 : readAlg = std::make_unique<GDALRasterReadAlgorithm>();
327 : else
328 403 : readAlg = std::make_unique<GDALVectorReadAlgorithm>();
329 9235 : for (auto &arg : readAlg->GetArgs())
330 : {
331 8131 : auto stepArg = GetArg(arg->GetName());
332 9250 : if (stepArg && stepArg->IsExplicitlySet() &&
333 1119 : stepArg->GetType() == arg->GetType())
334 : {
335 1116 : arg->SetSkipIfAlreadySet(true);
336 1116 : arg->SetFrom(*stepArg);
337 : }
338 : }
339 :
340 0 : std::unique_ptr<GDALPipelineStepAlgorithm> writeAlg;
341 1104 : 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 619 : if (GetName() == GDALVectorInfoAlgorithm::NAME)
353 27 : writeAlg = std::make_unique<GDALVectorInfoAlgorithm>();
354 : else
355 592 : writeAlg = std::make_unique<GDALVectorWriteAlgorithm>();
356 : }
357 18040 : for (auto &arg : writeAlg->GetArgs())
358 : {
359 16936 : auto stepArg = GetArg(arg->GetName());
360 19724 : if (stepArg && stepArg->IsExplicitlySet() &&
361 2788 : stepArg->GetType() == arg->GetType())
362 : {
363 2785 : arg->SetSkipIfAlreadySet(true);
364 2785 : arg->SetFrom(*stepArg);
365 : }
366 : }
367 :
368 1104 : const bool bIsStreaming = m_format == "stream";
369 :
370 : // Already checked by GDALAlgorithm::Run()
371 1104 : CPLAssert(!m_executionForStreamOutput || bIsStreaming);
372 :
373 1104 : bool ret = false;
374 1160 : if (!m_outputVRTCompatible &&
375 112 : (EQUAL(m_format.c_str(), "VRT") ||
376 56 : (m_format.empty() &&
377 1105 : 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 1104 : else if (readAlg->Run())
387 : {
388 1100 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
389 : const bool bOutputSpecified =
390 1100 : outputArg && outputArg->IsExplicitlySet();
391 :
392 1100 : m_inputDataset.clear();
393 1100 : m_inputDataset.resize(1);
394 1100 : m_inputDataset[0].Set(readAlg->m_outputDataset.GetDatasetRef());
395 1100 : if (bOutputSpecified)
396 842 : m_outputDataset.Set(nullptr);
397 :
398 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
399 2200 : pScaledData(nullptr, GDALDestroyScaledProgress);
400 :
401 : const bool bCanHandleNextStep =
402 1100 : !bIsStreaming && CanHandleNextStep(writeAlg.get());
403 :
404 1100 : GDALPipelineStepRunContext stepCtxt;
405 1100 : if (pfnProgress && GetName() == GDALRasterCompareAlgorithm::NAME)
406 : {
407 5 : stepCtxt.m_pfnProgress = pfnProgress;
408 5 : stepCtxt.m_pProgressData = pProgressData;
409 : }
410 1137 : 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 1100 : if (bCanHandleNextStep)
422 47 : stepCtxt.m_poNextUsableStep = writeAlg.get();
423 1100 : 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 1104 : return ret;
464 : }
465 : else
466 : {
467 1492 : GDALPipelineStepRunContext stepCtxt;
468 1492 : stepCtxt.m_pfnProgress = pfnProgress;
469 1492 : stepCtxt.m_pProgressData = pProgressData;
470 1492 : 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 3590 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
497 : {
498 3590 : if (m_standaloneStep)
499 : {
500 2040 : return GDALAlgorithm::ProcessGDALGOutput();
501 : }
502 : else
503 : {
504 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep() might
505 : // actually detect a GDALG output request and process it.
506 1550 : 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
|