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_mdim_info.h"
31 : #include "gdalalg_mdim_read.h"
32 : #include "gdalalg_mdim_write.h"
33 :
34 : #include "gdalalg_raster_as_features.h"
35 : #include "gdalalg_raster_compare.h"
36 : #include "gdalalg_raster_contour.h"
37 : #include "gdalalg_raster_footprint.h"
38 : #include "gdalalg_raster_polygonize.h"
39 : #include "gdalalg_raster_info.h"
40 : #include "gdalalg_raster_pixel_info.h"
41 : #include "gdalalg_raster_tile.h"
42 : #include "gdalalg_vector_grid.h"
43 : #include "gdalalg_vector_info.h"
44 : #include "gdalalg_vector_rasterize.h"
45 :
46 : #include <algorithm>
47 : #include <cassert>
48 :
49 : #ifndef _
50 : #define _(x) (x)
51 : #endif
52 :
53 : /************************************************************************/
54 : /* GDALPipelineStepAlgorithm() */
55 : /************************************************************************/
56 :
57 15115 : GDALPipelineStepAlgorithm::GDALPipelineStepAlgorithm(
58 : const std::string &name, const std::string &description,
59 15115 : const std::string &helpURL, const ConstructorOptions &options)
60 : : GDALAlgorithm(name, description, helpURL),
61 15115 : m_standaloneStep(options.standaloneStep), m_constructorOptions(options)
62 : {
63 15115 : }
64 :
65 : /************************************************************************/
66 : /* GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg() */
67 : /************************************************************************/
68 :
69 2242 : void GDALPipelineStepAlgorithm::AddRasterHiddenInputDatasetArg()
70 : {
71 2242 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER, false)
72 2242 : .SetMinCount(0)
73 2242 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
74 2242 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
75 2242 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
76 2242 : .SetHidden();
77 2242 : }
78 :
79 : /************************************************************************/
80 : /* GDALPipelineStepAlgorithm::AddRasterInputArgs() */
81 : /************************************************************************/
82 :
83 4982 : void GDALPipelineStepAlgorithm::AddRasterInputArgs(
84 : bool openForMixedRasterVector, bool hiddenForCLI)
85 : {
86 4982 : AddInputFormatsArg(&m_inputFormats)
87 : .AddMetadataItem(
88 : GAAMDI_REQUIRED_CAPABILITIES,
89 : openForMixedRasterVector
90 15294 : ? std::vector<std::string>{GDAL_DCAP_RASTER, GDAL_DCAP_VECTOR}
91 14598 : : std::vector<std::string>{GDAL_DCAP_RASTER})
92 4982 : .SetHiddenForCLI(hiddenForCLI)
93 4982 : .SetAvailableInPipelineStep(false);
94 4982 : AddOpenOptionsArg(&m_openOptions)
95 4982 : .SetHiddenForCLI(hiddenForCLI)
96 4982 : .SetAvailableInPipelineStep(false);
97 :
98 4982 : const int nDatasetType = openForMixedRasterVector
99 4982 : ? (GDAL_OF_RASTER | GDAL_OF_VECTOR)
100 : : GDAL_OF_RASTER;
101 : auto &arg =
102 : AddInputDatasetArg(
103 : &m_inputDataset, nDatasetType, false,
104 9487 : m_constructorOptions.inputDatasetHelpMsg.empty() &&
105 4505 : m_constructorOptions.inputDatasetMaxCount == 1
106 4129 : ? CPLSPrintf(
107 : "Input %s dataset",
108 9111 : GDALAlgorithmArgDatasetTypeName(nDatasetType).c_str())
109 13616 : : m_constructorOptions.inputDatasetHelpMsg.c_str())
110 4982 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
111 4982 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
112 4982 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
113 4982 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
114 4982 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
115 4982 : .SetHiddenForCLI(hiddenForCLI)
116 4982 : .SetAvailableInPipelineStep(false);
117 4982 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
118 4592 : arg.SetPositional();
119 4982 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
120 4592 : arg.SetRequired();
121 4982 : if (!m_constructorOptions.inputDatasetAlias.empty())
122 897 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
123 4982 : }
124 :
125 : /************************************************************************/
126 : /* GDALPipelineStepAlgorithm::AddRasterOutputArgs() */
127 : /************************************************************************/
128 :
129 3223 : void GDALPipelineStepAlgorithm::AddRasterOutputArgs(bool hiddenForCLI)
130 : {
131 3223 : m_outputFormatArg =
132 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
133 3223 : /* bGDALGAllowed = */ true)
134 : .AddMetadataItem(
135 : GAAMDI_REQUIRED_CAPABILITIES,
136 : {GDAL_DCAP_RASTER,
137 12892 : m_constructorOptions.outputFormatCreateCapability.c_str()})
138 3223 : .SetHiddenForCLI(hiddenForCLI))
139 3223 : .SetAvailableInPipelineStep(false);
140 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER,
141 3223 : /* positionalAndRequired = */ !hiddenForCLI,
142 3223 : m_constructorOptions.outputDatasetHelpMsg.c_str())
143 3223 : .SetHiddenForCLI(hiddenForCLI)
144 3223 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
145 3223 : .SetAvailableInPipelineStep(false);
146 3223 : AddCreationOptionsArg(&m_creationOptions)
147 3223 : .SetHiddenForCLI(hiddenForCLI)
148 3223 : .SetAvailableInPipelineStep(false);
149 3223 : constexpr const char *MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND =
150 : "overwrite-append";
151 3223 : AddOverwriteArg(&m_overwrite)
152 3223 : .SetHiddenForCLI(hiddenForCLI)
153 6446 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND)
154 3223 : .SetAvailableInPipelineStep(false);
155 : AddArg(GDAL_ARG_NAME_APPEND, 0,
156 6446 : _("Append as a subdataset to existing output"), &m_appendRaster)
157 3223 : .SetDefault(false)
158 3223 : .SetHiddenForCLI(hiddenForCLI)
159 6446 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_OVERWRITE_APPEND)
160 3223 : .SetAvailableInPipelineStep(false);
161 3223 : }
162 :
163 : /************************************************************************/
164 : /* GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg() */
165 : /************************************************************************/
166 :
167 2199 : void GDALPipelineStepAlgorithm::AddVectorHiddenInputDatasetArg()
168 : {
169 2199 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_VECTOR, false)
170 2199 : .SetMinCount(0)
171 2199 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
172 2199 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
173 2199 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
174 2199 : .SetHidden();
175 2199 : }
176 :
177 : /************************************************************************/
178 : /* GDALPipelineStepAlgorithm::AddVectorInputArgs() */
179 : /************************************************************************/
180 :
181 3051 : void GDALPipelineStepAlgorithm::AddVectorInputArgs(bool hiddenForCLI)
182 : {
183 3051 : AddInputFormatsArg(&m_inputFormats)
184 9153 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES, {GDAL_DCAP_VECTOR})
185 3051 : .SetHiddenForCLI(hiddenForCLI)
186 3051 : .SetAvailableInPipelineStep(false);
187 3051 : AddOpenOptionsArg(&m_openOptions)
188 3051 : .SetHiddenForCLI(hiddenForCLI)
189 3051 : .SetAvailableInPipelineStep(false);
190 : auto &datasetArg =
191 : AddInputDatasetArg(
192 : &m_inputDataset, GDAL_OF_VECTOR, false,
193 9021 : m_constructorOptions.inputDatasetHelpMsg.empty() &&
194 2919 : m_constructorOptions.inputDatasetMaxCount == 1
195 : ? "Input vector dataset"
196 5970 : : m_constructorOptions.inputDatasetHelpMsg.c_str())
197 3051 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
198 3051 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
199 3051 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
200 3051 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
201 3051 : .SetHiddenForCLI(hiddenForCLI)
202 3051 : .SetAvailableInPipelineStep(false);
203 3051 : if (!m_constructorOptions.inputDatasetAlias.empty())
204 192 : datasetArg.AddAlias(m_constructorOptions.inputDatasetAlias);
205 3051 : if (!m_constructorOptions.inputDatasetMetaVar.empty())
206 3051 : datasetArg.SetMetaVar(m_constructorOptions.inputDatasetMetaVar);
207 3051 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
208 2734 : datasetArg.SetPositional();
209 3051 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
210 2734 : datasetArg.SetRequired();
211 3051 : if (m_constructorOptions.addInputLayerNameArgument)
212 : {
213 : auto &layerArg = AddArg(GDAL_ARG_NAME_INPUT_LAYER, 'l',
214 5388 : _("Input layer name(s)"), &m_inputLayerNames)
215 5388 : .AddAlias("layer")
216 2694 : .SetHiddenForCLI(hiddenForCLI)
217 2694 : .SetAvailableInPipelineStep(false);
218 2694 : SetAutoCompleteFunctionForLayerName(layerArg, datasetArg);
219 : }
220 3051 : }
221 :
222 : /************************************************************************/
223 : /* GDALPipelineStepAlgorithm::AddVectorOutputArgs() */
224 : /************************************************************************/
225 :
226 3487 : void GDALPipelineStepAlgorithm::AddVectorOutputArgs(
227 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
228 : {
229 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
230 3487 : /* bGDALGAllowed = */ true)
231 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
232 13948 : {GDAL_DCAP_VECTOR, GDAL_DCAP_CREATE})
233 3487 : .SetHiddenForCLI(hiddenForCLI)
234 3487 : .SetAvailableInPipelineStep(false);
235 3487 : AddOutputOpenOptionsArg(&m_outputOpenOptions)
236 3487 : .SetHiddenForCLI(hiddenForCLI)
237 3487 : .SetAvailableInPipelineStep(false);
238 : auto &outputDatasetArg =
239 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_VECTOR,
240 3487 : /* positionalAndRequired = */ false)
241 3487 : .SetHiddenForCLI(hiddenForCLI)
242 3487 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
243 3487 : .SetAvailableInPipelineStep(false);
244 3487 : if (!hiddenForCLI)
245 3302 : outputDatasetArg.SetPositional();
246 3487 : if (!hiddenForCLI && m_constructorOptions.outputDatasetRequired)
247 3242 : outputDatasetArg.SetRequired();
248 :
249 3487 : AddCreationOptionsArg(&m_creationOptions)
250 3487 : .SetHiddenForCLI(hiddenForCLI)
251 3487 : .SetAvailableInPipelineStep(false);
252 3487 : AddLayerCreationOptionsArg(&m_layerCreationOptions)
253 3487 : .SetHiddenForCLI(hiddenForCLI)
254 3487 : .SetAvailableInPipelineStep(false);
255 3487 : AddOverwriteArg(&m_overwrite)
256 3487 : .SetHiddenForCLI(hiddenForCLI)
257 3487 : .SetAvailableInPipelineStep(false);
258 3487 : GDALInConstructionAlgorithmArg *updateArg = nullptr;
259 3487 : if (m_constructorOptions.addUpdateArgument)
260 : {
261 3424 : updateArg = &AddUpdateArg(&m_update)
262 3424 : .SetHiddenForCLI(hiddenForCLI)
263 3424 : .SetAvailableInPipelineStep(false);
264 : }
265 3487 : if (m_constructorOptions.addOverwriteLayerArgument)
266 : {
267 3424 : AddOverwriteLayerArg(&m_overwriteLayer)
268 3424 : .SetHiddenForCLI(hiddenForCLI)
269 3424 : .SetAvailableInPipelineStep(false);
270 : }
271 3487 : constexpr const char *MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT =
272 : "append-upsert";
273 3487 : if (m_constructorOptions.addAppendLayerArgument)
274 : {
275 3292 : AddAppendLayerArg(&m_appendLayer)
276 3292 : .SetHiddenForCLI(hiddenForCLI)
277 6584 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
278 3292 : .SetAvailableInPipelineStep(false);
279 : }
280 3487 : if (m_constructorOptions.addUpsertArgument)
281 : {
282 6154 : AddArg("upsert", 0, _("Upsert features (implies 'append')"), &m_upsert)
283 3077 : .SetHiddenForCLI(hiddenForCLI)
284 6154 : .SetMutualExclusionGroup(MUTUAL_EXCLUSION_GROUP_APPEND_UPSERT)
285 :
286 3077 : .SetAvailableInPipelineStep(false)
287 : .AddAction(
288 12 : [updateArg, this]()
289 : {
290 4 : if (m_upsert && updateArg)
291 4 : updateArg->Set(true);
292 6154 : })
293 3077 : .SetCategory(GAAC_ADVANCED);
294 : }
295 3487 : if (m_constructorOptions.addOutputLayerNameArgument)
296 : {
297 3355 : AddOutputLayerNameArg(hiddenForCLI, shortNameOutputLayerAllowed);
298 : }
299 3487 : if (m_constructorOptions.addSkipErrorsArgument)
300 : {
301 : AddArg("skip-errors", 0, _("Skip errors when writing features"),
302 6154 : &m_skipErrors)
303 6154 : .AddHiddenAlias("skip-failures") // For ogr2ogr nostalgic people
304 3077 : .SetAvailableInPipelineStep(false);
305 : }
306 3487 : if (m_constructorOptions.addNoCreateEmptyLayersArgument)
307 : {
308 : AddArg("no-create-empty-layers", 0,
309 : _("Avoid creating layers to which no features will be written"),
310 2346 : &m_noCreateEmptyLayers)
311 1173 : .SetAvailableInPipelineStep(false);
312 : }
313 3487 : }
314 :
315 : /************************************************************************/
316 : /* GDALPipelineStepAlgorithm::AddOutputLayerNameArg() */
317 : /************************************************************************/
318 :
319 3598 : void GDALPipelineStepAlgorithm::AddOutputLayerNameArg(
320 : bool hiddenForCLI, bool shortNameOutputLayerAllowed)
321 : {
322 : AddArg(GDAL_ARG_NAME_OUTPUT_LAYER, shortNameOutputLayerAllowed ? 'l' : 0,
323 : _("Output layer name"),
324 7196 : &m_outputLayerName)
325 7196 : .AddHiddenAlias("nln") // For ogr2ogr nostalgic people
326 3598 : .SetHiddenForCLI(hiddenForCLI)
327 : .SetAvailableInPipelineStep(
328 3598 : m_constructorOptions.outputLayerNameAvailableInPipelineStep);
329 3598 : }
330 :
331 : /************************************************************************/
332 : /* GDALPipelineStepAlgorithm::AddMdimHiddenInputDatasetArg() */
333 : /************************************************************************/
334 :
335 25 : void GDALPipelineStepAlgorithm::AddMdimHiddenInputDatasetArg()
336 : {
337 25 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_MULTIDIM_RASTER, false)
338 25 : .SetMinCount(0)
339 25 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
340 25 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
341 25 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
342 25 : .SetHidden();
343 25 : }
344 :
345 : /************************************************************************/
346 : /* GDALPipelineStepAlgorithm::AddMdimInputArgs() */
347 : /************************************************************************/
348 :
349 377 : void GDALPipelineStepAlgorithm::AddMdimInputArgs(bool openForMixedMdimVector,
350 : bool hiddenForCLI,
351 : bool acceptRaster)
352 : {
353 377 : AddInputFormatsArg(&m_inputFormats)
354 : .AddMetadataItem(
355 : GAAMDI_REQUIRED_CAPABILITIES,
356 : openForMixedMdimVector
357 1131 : ? std::vector<
358 : std::string>{acceptRaster
359 : ? GDAL_ALG_DCAP_RASTER_OR_MULTIDIM_RASTER
360 : : GDAL_DCAP_MULTIDIM_RASTER,
361 0 : GDAL_DCAP_VECTOR}
362 : : std::vector<
363 : std::string>{acceptRaster
364 : ? GDAL_ALG_DCAP_RASTER_OR_MULTIDIM_RASTER
365 1131 : : GDAL_DCAP_MULTIDIM_RASTER})
366 377 : .SetHiddenForCLI(hiddenForCLI)
367 377 : .SetAvailableInPipelineStep(false);
368 377 : AddOpenOptionsArg(&m_openOptions)
369 377 : .SetHiddenForCLI(hiddenForCLI)
370 377 : .SetAvailableInPipelineStep(false);
371 : auto &arg =
372 : AddInputDatasetArg(&m_inputDataset,
373 377 : (acceptRaster ? GDAL_OF_RASTER : 0) |
374 : (openForMixedMdimVector
375 377 : ? (GDAL_OF_MULTIDIM_RASTER | GDAL_OF_VECTOR)
376 : : GDAL_OF_MULTIDIM_RASTER),
377 : false,
378 754 : m_constructorOptions.inputDatasetHelpMsg.c_str())
379 377 : .SetDatasetInputFlags(m_constructorOptions.inputDatasetInputFlags)
380 377 : .SetMinCount(m_constructorOptions.inputDatasetRequired ? 1 : 0)
381 377 : .SetMaxCount(m_constructorOptions.inputDatasetMaxCount)
382 377 : .SetAutoOpenDataset(m_constructorOptions.autoOpenInputDatasets)
383 377 : .SetMetaVar(m_constructorOptions.inputDatasetMetaVar)
384 377 : .SetHiddenForCLI(hiddenForCLI)
385 377 : .SetAvailableInPipelineStep(false);
386 377 : if (m_constructorOptions.inputDatasetPositional && !hiddenForCLI)
387 323 : arg.SetPositional();
388 377 : if (m_constructorOptions.inputDatasetRequired && !hiddenForCLI)
389 323 : arg.SetRequired();
390 377 : if (!m_constructorOptions.inputDatasetAlias.empty())
391 57 : arg.AddAlias(m_constructorOptions.inputDatasetAlias);
392 377 : }
393 :
394 : /************************************************************************/
395 : /* GDALPipelineStepAlgorithm::AddMdimOutputArgs() */
396 : /************************************************************************/
397 :
398 245 : void GDALPipelineStepAlgorithm::AddMdimOutputArgs(bool hiddenForCLI)
399 : {
400 245 : m_outputFormatArg =
401 : &(AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
402 245 : /* bGDALGAllowed = */ true)
403 : .AddMetadataItem(GAAMDI_REQUIRED_CAPABILITIES,
404 735 : {GDAL_DCAP_CREATE_MULTIDIMENSIONAL})
405 245 : .SetHiddenForCLI(hiddenForCLI))
406 245 : .SetAvailableInPipelineStep(false);
407 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_MULTIDIM_RASTER,
408 245 : /* positionalAndRequired = */ !hiddenForCLI,
409 245 : m_constructorOptions.outputDatasetHelpMsg.c_str())
410 245 : .SetHiddenForCLI(hiddenForCLI)
411 245 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT)
412 245 : .SetAvailableInPipelineStep(false);
413 245 : AddCreationOptionsArg(&m_creationOptions)
414 245 : .SetHiddenForCLI(hiddenForCLI)
415 245 : .SetAvailableInPipelineStep(false);
416 245 : AddOverwriteArg(&m_overwrite)
417 245 : .SetHiddenForCLI(hiddenForCLI)
418 245 : .SetAvailableInPipelineStep(false);
419 245 : }
420 :
421 : /************************************************************************/
422 : /* GDALPipelineStepAlgorithm::RunImpl() */
423 : /************************************************************************/
424 :
425 3059 : bool GDALPipelineStepAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
426 : void *pProgressData)
427 : {
428 3059 : if (m_standaloneStep)
429 : {
430 1270 : std::unique_ptr<GDALPipelineStepAlgorithm> readAlg;
431 1270 : if (GetInputType() == GDAL_OF_RASTER)
432 774 : readAlg = std::make_unique<GDALRasterReadAlgorithm>();
433 496 : else if (GetInputType() == GDAL_OF_MULTIDIM_RASTER)
434 22 : readAlg = std::make_unique<GDALMdimReadAlgorithm>();
435 : else
436 474 : readAlg = std::make_unique<GDALVectorReadAlgorithm>();
437 10634 : for (auto &arg : readAlg->GetArgs())
438 : {
439 9364 : auto stepArg = GetArg(arg->GetName());
440 10651 : if (stepArg && stepArg->IsExplicitlySet() &&
441 1287 : stepArg->GetType() == arg->GetType())
442 : {
443 1284 : arg->SetSkipIfAlreadySet(true);
444 1284 : arg->SetFrom(*stepArg);
445 : }
446 : }
447 :
448 0 : std::unique_ptr<GDALPipelineStepAlgorithm> writeAlg;
449 1270 : if (GetOutputType() == GDAL_OF_RASTER)
450 : {
451 551 : if (GetName() == GDALRasterInfoAlgorithm::NAME)
452 26 : writeAlg = std::make_unique<GDALRasterInfoAlgorithm>();
453 525 : else if (GetName() == GDALRasterCompareAlgorithm::NAME)
454 0 : writeAlg = std::make_unique<GDALRasterCompareAlgorithm>();
455 : else
456 525 : writeAlg = std::make_unique<GDALRasterWriteAlgorithm>();
457 : }
458 719 : else if (GetOutputType() == GDAL_OF_MULTIDIM_RASTER)
459 : {
460 13 : if (GetName() == GDALMdimInfoAlgorithm::NAME)
461 10 : writeAlg = std::make_unique<GDALMdimInfoAlgorithm>();
462 : else
463 3 : writeAlg = std::make_unique<GDALMdimWriteAlgorithm>();
464 : }
465 : else
466 : {
467 706 : if (GetName() == GDALVectorInfoAlgorithm::NAME)
468 27 : writeAlg = std::make_unique<GDALVectorInfoAlgorithm>();
469 : else
470 679 : writeAlg = std::make_unique<GDALVectorWriteAlgorithm>();
471 : }
472 20699 : for (auto &arg : writeAlg->GetArgs())
473 : {
474 19429 : auto stepArg = GetArg(arg->GetName());
475 22649 : if (stepArg && stepArg->IsExplicitlySet() &&
476 3220 : stepArg->GetType() == arg->GetType())
477 : {
478 3214 : arg->SetSkipIfAlreadySet(true);
479 3214 : arg->SetFrom(*stepArg);
480 : }
481 : }
482 :
483 1270 : const bool bIsStreaming = m_format == "stream";
484 :
485 : // Already checked by GDALAlgorithm::Run()
486 1270 : CPLAssert(!m_executionForStreamOutput || bIsStreaming);
487 :
488 1270 : bool ret = false;
489 1326 : if (!m_outputVRTCompatible &&
490 112 : (EQUAL(m_format.c_str(), "VRT") ||
491 56 : (m_format.empty() &&
492 1271 : EQUAL(CPLGetExtensionSafe(m_outputDataset.GetName().c_str())
493 : .c_str(),
494 : "VRT"))))
495 : {
496 0 : ReportError(CE_Failure, CPLE_NotSupported,
497 : "VRT output is not supported. Consider using the "
498 : "GDALG driver instead (files with .gdalg.json "
499 : "extension)");
500 : }
501 1270 : else if (readAlg->Run())
502 : {
503 1266 : auto outputArg = GetArg(GDAL_ARG_NAME_OUTPUT);
504 : const bool bOutputSpecified =
505 2251 : outputArg && outputArg->IsExplicitlySet() &&
506 985 : (outputArg->GetType() == GAAT_DATASET ||
507 3 : outputArg->GetType() == GAAT_DATASET_LIST);
508 :
509 1266 : m_inputDataset.clear();
510 1266 : m_inputDataset.resize(1);
511 1266 : m_inputDataset[0].Set(readAlg->m_outputDataset.GetDatasetRef());
512 1266 : if (bOutputSpecified)
513 979 : m_outputDataset.Set(nullptr);
514 :
515 : std::unique_ptr<void, decltype(&GDALDestroyScaledProgress)>
516 2532 : pScaledData(nullptr, GDALDestroyScaledProgress);
517 :
518 : const bool bCanHandleNextStep =
519 1266 : !bIsStreaming && CanHandleNextStep(writeAlg.get());
520 :
521 1266 : GDALPipelineStepRunContext stepCtxt;
522 1266 : if (pfnProgress && GetName() == GDALRasterCompareAlgorithm::NAME)
523 : {
524 11 : stepCtxt.m_pfnProgress = pfnProgress;
525 11 : stepCtxt.m_pProgressData = pProgressData;
526 : }
527 1309 : else if (pfnProgress &&
528 54 : (bCanHandleNextStep || !IsNativelyStreamingCompatible()))
529 : {
530 52 : pScaledData.reset(GDALCreateScaledProgress(
531 22 : 0.0, bIsStreaming || bCanHandleNextStep ? 1.0 : 0.5,
532 : pfnProgress, pProgressData));
533 30 : stepCtxt.m_pfnProgress =
534 30 : pScaledData ? GDALScaledProgress : nullptr;
535 30 : stepCtxt.m_pProgressData = pScaledData.get();
536 : }
537 :
538 1266 : if (bCanHandleNextStep)
539 52 : stepCtxt.m_poNextUsableStep = writeAlg.get();
540 1266 : if (RunPreStepPipelineValidations() && RunStep(stepCtxt))
541 : {
542 1161 : if (bCanHandleNextStep || !bOutputSpecified)
543 : {
544 325 : ret = true;
545 : }
546 : else
547 : {
548 836 : writeAlg->m_outputVRTCompatible = m_outputVRTCompatible;
549 836 : writeAlg->m_quiet = m_quiet;
550 :
551 1672 : std::vector<GDALArgDatasetValue> inputDataset(1);
552 836 : inputDataset[0].Set(m_outputDataset.GetDatasetRef());
553 836 : auto inputArg = writeAlg->GetArg(GDAL_ARG_NAME_INPUT);
554 836 : CPLAssert(inputArg);
555 836 : inputArg->Set(std::move(inputDataset));
556 :
557 836 : if (pfnProgress)
558 : {
559 41 : pScaledData.reset(GDALCreateScaledProgress(
560 41 : IsNativelyStreamingCompatible() ? 0.0 : 0.5, 1.0,
561 : pfnProgress, pProgressData));
562 : }
563 836 : stepCtxt.m_pfnProgress =
564 836 : pScaledData ? GDALScaledProgress : nullptr;
565 836 : stepCtxt.m_pProgressData = pScaledData.get();
566 1672 : if (writeAlg->ValidateArguments() &&
567 836 : writeAlg->RunStep(stepCtxt))
568 : {
569 810 : if (pfnProgress)
570 40 : pfnProgress(1.0, "", pProgressData);
571 :
572 810 : m_outputDataset.Set(
573 810 : writeAlg->m_outputDataset.GetDatasetRef());
574 810 : ret = true;
575 : }
576 : }
577 : }
578 : }
579 :
580 1270 : return ret;
581 : }
582 : else
583 : {
584 1789 : GDALPipelineStepRunContext stepCtxt;
585 1789 : stepCtxt.m_pfnProgress = pfnProgress;
586 1789 : stepCtxt.m_pProgressData = pProgressData;
587 1789 : return RunPreStepPipelineValidations() && RunStep(stepCtxt);
588 : }
589 : }
590 :
591 : /************************************************************************/
592 : /* SetInputDataset() */
593 : /************************************************************************/
594 :
595 27 : void GDALPipelineStepAlgorithm::SetInputDataset(GDALDataset *poDS)
596 : {
597 27 : auto arg = GetArg(GDAL_ARG_NAME_INPUT);
598 27 : if (arg)
599 : {
600 27 : auto &val = arg->Get<std::vector<GDALArgDatasetValue>>();
601 27 : val.resize(1);
602 27 : val[0].Set(poDS);
603 27 : arg->NotifyValueSet();
604 27 : arg->SetSkipIfAlreadySet();
605 : }
606 27 : }
607 :
608 : /************************************************************************/
609 : /* ProcessGDALGOutput() */
610 : /************************************************************************/
611 :
612 : GDALAlgorithm::ProcessGDALGOutputRet
613 4242 : GDALPipelineStepAlgorithm::ProcessGDALGOutput()
614 : {
615 4242 : if (m_standaloneStep)
616 : {
617 2369 : return GDALAlgorithm::ProcessGDALGOutput();
618 : }
619 : else
620 : {
621 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep() might
622 : // actually detect a GDALG output request and process it.
623 1873 : return GDALAlgorithm::ProcessGDALGOutputRet::NOT_GDALG;
624 : }
625 : }
626 :
627 : /************************************************************************/
628 : /* GDALPipelineStepAlgorithm::CheckSafeForStreamOutput() */
629 : /************************************************************************/
630 :
631 98 : bool GDALPipelineStepAlgorithm::CheckSafeForStreamOutput()
632 : {
633 98 : if (m_standaloneStep)
634 : {
635 50 : return GDALAlgorithm::CheckSafeForStreamOutput();
636 : }
637 : else
638 : {
639 : // The check is actually done in
640 : // GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep()
641 : // so return true for now.
642 48 : return true;
643 : }
644 : }
645 :
646 : /************************************************************************/
647 : /* GDALPipelineStepAlgorithm::Finalize() */
648 : /************************************************************************/
649 :
650 1606 : bool GDALPipelineStepAlgorithm::Finalize()
651 : {
652 1606 : bool ret = GDALAlgorithm::Finalize();
653 2992 : for (auto &argValue : m_inputDataset)
654 1386 : ret = argValue.Close() && ret;
655 1606 : ret = m_outputDataset.Close() && ret;
656 1606 : return ret;
657 : }
658 :
659 : /************************************************************************/
660 : /* CreateDatasetSingleOutputLayerIfNeeded() */
661 : /************************************************************************/
662 :
663 68 : bool GDALPipelineStepAlgorithm::CreateDatasetSingleOutputLayerIfNeeded(
664 : GDALPipelineStepRunContext &ctxt, const std::string &defaultLayerName,
665 : GDALDataset *&poDstDS, bool &bTemporaryFile,
666 : std::unique_ptr<GDALDataset> &poNewRetDS, std::string &outputLayerName,
667 : OGRLayer *&poDstLayer)
668 : {
669 68 : auto poWriteStep = ctxt.m_poNextUsableStep ? ctxt.m_poNextUsableStep : this;
670 136 : std::string outputFilename = poWriteStep->GetOutputDataset().GetName();
671 :
672 68 : poDstDS = poWriteStep->GetOutputDataset().GetDatasetRef();
673 68 : poNewRetDS.reset();
674 68 : bTemporaryFile = false;
675 68 : poDstLayer = nullptr;
676 68 : GDALDriver *poDstDriver = nullptr;
677 68 : if (!poDstDS)
678 : {
679 48 : auto poDriverManager = GetGDALDriverManager();
680 48 : std::string format = poWriteStep->GetOutputFormat();
681 48 : if (m_standaloneStep || (ctxt.m_poNextUsableStep && format.empty()))
682 : {
683 41 : if (format.empty())
684 : {
685 : const auto aosFormats =
686 : CPLStringList(GDALGetOutputDriversForDatasetName(
687 : outputFilename.c_str(), GDAL_OF_VECTOR,
688 : /* bSingleMatch = */ true,
689 25 : /* bWarn = */ true));
690 25 : if (aosFormats.size() != 1)
691 : {
692 2 : ReportError(CE_Failure, CPLE_AppDefined,
693 : "Cannot guess driver for %s",
694 : outputFilename.c_str());
695 2 : return false;
696 : }
697 23 : format = aosFormats[0];
698 : }
699 : }
700 7 : else if (!ctxt.m_poNextUsableStep)
701 : {
702 5 : poDstDriver = poDriverManager->GetDriverByName("GPKG");
703 5 : if (poDstDriver)
704 : {
705 5 : bTemporaryFile = true;
706 : outputFilename =
707 5 : CPLGenerateTempFilenameSafe(
708 15 : std::string("_").append(defaultLayerName).c_str()) +
709 5 : ".gpkg";
710 5 : format = "GPKG";
711 : }
712 : else
713 0 : format = "MEM";
714 : }
715 :
716 46 : if (!poDstDriver)
717 41 : poDstDriver = poDriverManager->GetDriverByName(format.c_str());
718 46 : if (!poDstDriver)
719 : {
720 0 : ReportError(CE_Failure, CPLE_AppDefined, "Cannot find driver %s",
721 : format.c_str());
722 0 : return false;
723 : }
724 :
725 46 : poNewRetDS.reset(poDstDriver->Create(
726 : outputFilename.c_str(), 0, 0, 0, GDT_Unknown,
727 92 : CPLStringList(poWriteStep->GetCreationOptions()).List()));
728 46 : if (!poNewRetDS)
729 2 : return false;
730 :
731 44 : if (bTemporaryFile)
732 5 : poNewRetDS->MarkSuppressOnClose();
733 :
734 44 : poDstDS = poNewRetDS.get();
735 : }
736 : else
737 : {
738 20 : poDstDriver = poDstDS->GetDriver();
739 : }
740 :
741 64 : outputLayerName = poWriteStep->GetOutputLayerName();
742 64 : if (outputLayerName.empty() && poDstDS->GetLayerCount() > 1)
743 : {
744 3 : ReportError(CE_Failure, CPLE_AppDefined, "--%s must be specified",
745 : GDAL_ARG_NAME_OUTPUT_LAYER);
746 3 : return false;
747 : }
748 :
749 61 : if (poDstDriver && EQUAL(poDstDriver->GetDescription(), "ESRI Shapefile") &&
750 81 : (EQUAL(CPLGetExtensionSafe(poDstDS->GetDescription()).c_str(), "shp") ||
751 64 : EQUAL(CPLGetExtensionSafe(poDstDS->GetDescription()).c_str(),
752 122 : "shz")) &&
753 20 : poDstDS->GetLayerCount() <= 1)
754 : {
755 20 : outputLayerName = CPLGetBasenameSafe(poDstDS->GetDescription());
756 : }
757 61 : if (outputLayerName.empty())
758 33 : outputLayerName = defaultLayerName;
759 :
760 61 : poDstLayer = poDstDS->GetLayerByName(outputLayerName.c_str());
761 61 : if (poDstLayer)
762 : {
763 13 : if (poWriteStep->GetOverwriteLayer())
764 : {
765 5 : int iLayer = -1;
766 5 : const int nLayerCount = poDstDS->GetLayerCount();
767 6 : for (iLayer = 0; iLayer < nLayerCount; iLayer++)
768 : {
769 6 : if (poDstDS->GetLayer(iLayer) == poDstLayer)
770 5 : break;
771 : }
772 :
773 5 : if (iLayer < nLayerCount)
774 : {
775 5 : if (poDstDS->DeleteLayer(iLayer) != OGRERR_NONE)
776 : {
777 2 : ReportError(CE_Failure, CPLE_AppDefined,
778 : "Cannot delete layer '%s'",
779 : outputLayerName.c_str());
780 2 : return false;
781 : }
782 : }
783 3 : poDstLayer = nullptr;
784 : }
785 8 : else if (!poWriteStep->GetAppendLayer())
786 : {
787 3 : ReportError(CE_Failure, CPLE_AppDefined,
788 : "Layer '%s' already exists. Specify the "
789 : "--%s option to overwrite it, or --%s "
790 : "to append to it.",
791 : outputLayerName.c_str(), GDAL_ARG_NAME_OVERWRITE_LAYER,
792 : GDAL_ARG_NAME_APPEND);
793 3 : return false;
794 : }
795 : }
796 48 : else if (poWriteStep->GetAppendLayer() || poWriteStep->GetOverwriteLayer())
797 : {
798 3 : ReportError(CE_Failure, CPLE_AppDefined, "Cannot find layer '%s'",
799 : outputLayerName.c_str());
800 3 : return false;
801 : }
802 :
803 53 : return true;
804 : }
805 :
806 : GDALAlgorithmStepRegistry::~GDALAlgorithmStepRegistry() = default;
807 :
808 : /************************************************************************/
809 : /* GDALPipelineAlgorithm */
810 : /************************************************************************/
811 :
812 338 : GDALPipelineAlgorithm::GDALPipelineAlgorithm()
813 : : GDALAbstractPipelineAlgorithm(
814 : NAME, DESCRIPTION, HELP_URL,
815 338 : ConstructorOptions().SetStandaloneStep(false))
816 : {
817 338 : m_supportsStreamedOutput = true;
818 :
819 338 : AddProgressArg();
820 : AddInputDatasetArg(&m_inputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
821 338 : /* positionalAndRequired = */ false)
822 338 : .SetMinCount(1)
823 338 : .SetMaxCount(INT_MAX)
824 338 : .SetHiddenForCLI();
825 : AddOutputDatasetArg(&m_outputDataset, GDAL_OF_RASTER | GDAL_OF_VECTOR,
826 338 : /* positionalAndRequired = */ false)
827 338 : .SetHiddenForCLI()
828 338 : .SetDatasetInputFlags(GADV_NAME | GADV_OBJECT);
829 : AddOutputFormatArg(&m_format, /* bStreamAllowed = */ true,
830 338 : /* bGDALGAllowed = */ true)
831 338 : .SetHiddenForCLI();
832 676 : AddArg("pipeline", 0, _("Pipeline string or filename"), &m_pipeline)
833 338 : .SetHiddenForCLI()
834 338 : .SetPositional();
835 :
836 338 : AddOutputStringArg(&m_output).SetHiddenForCLI();
837 338 : AddStdoutArg(&m_stdout);
838 :
839 338 : AllowArbitraryLongNameArgs();
840 :
841 338 : GDALRasterPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
842 338 : GDALVectorPipelineAlgorithm::RegisterAlgorithms(m_stepRegistry, true);
843 338 : m_stepRegistry.Register<GDALExternalRasterOrVectorAlgorithm>();
844 338 : m_stepRegistry.Register<GDALRasterAsFeaturesAlgorithm>();
845 338 : m_stepRegistry.Register<GDALRasterContourAlgorithm>();
846 338 : m_stepRegistry.Register<GDALRasterFootprintAlgorithm>();
847 338 : m_stepRegistry.Register<GDALRasterPixelInfoAlgorithm>();
848 338 : m_stepRegistry.Register<GDALRasterPolygonizeAlgorithm>();
849 338 : m_stepRegistry.Register<GDALRasterZonalStatsAlgorithm>();
850 338 : m_stepRegistry.Register<GDALVectorGridAlgorithm>();
851 338 : m_stepRegistry.Register<GDALVectorRasterizeAlgorithm>();
852 338 : }
853 :
854 : /************************************************************************/
855 : /* GDALPipelineAlgorithm::GetUsageForCLI() */
856 : /************************************************************************/
857 :
858 : std::string
859 19 : GDALPipelineAlgorithm::GetUsageForCLI(bool shortUsage,
860 : const UsageOptions &usageOptions) const
861 : {
862 19 : UsageOptions stepUsageOptions;
863 19 : stepUsageOptions.isPipelineStep = true;
864 :
865 19 : if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
866 : {
867 4 : auto alg = GetStepAlg(m_helpDocCategory);
868 2 : if (alg)
869 : {
870 3 : alg->SetCallPath({CPLString(m_helpDocCategory)
871 2 : .replaceAll(RASTER_SUFFIX, "")
872 3 : .replaceAll(VECTOR_SUFFIX, "")});
873 1 : alg->GetArg("help-doc")->Set(true);
874 1 : return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
875 : }
876 : else
877 : {
878 1 : fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
879 : m_helpDocCategory.c_str());
880 : return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
881 1 : m_helpDocCategory.c_str());
882 : }
883 : }
884 :
885 17 : UsageOptions usageOptionsMain(usageOptions);
886 17 : usageOptionsMain.isPipelineMain = true;
887 : std::string ret =
888 34 : GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
889 17 : if (shortUsage)
890 15 : return ret;
891 :
892 : ret +=
893 : "\n<PIPELINE> is of the form: read|calc|concat|create|mosaic|stack "
894 : "[READ-OPTIONS] "
895 2 : "( ! <STEP-NAME> [STEP-OPTIONS] )* ! write!info!tile [WRITE-OPTIONS]\n";
896 :
897 2 : if (m_helpDocCategory == "main")
898 : {
899 1 : return ret;
900 : }
901 :
902 1 : ret += '\n';
903 1 : ret += "Example: 'gdal pipeline --progress ! read in.tif ! \\\n";
904 1 : ret += " rasterize --size 256 256 ! buffer 20 ! ";
905 1 : ret += "write out.gpkg --overwrite'\n";
906 1 : ret += '\n';
907 1 : ret += "Potential steps are:\n";
908 :
909 87 : for (const std::string &name : m_stepRegistry.GetNames())
910 : {
911 172 : auto alg = GetStepAlg(name);
912 86 : assert(alg);
913 86 : auto [options, maxOptLen] = alg->GetArgNamesForCLI();
914 86 : stepUsageOptions.maxOptLen =
915 86 : std::max(stepUsageOptions.maxOptLen, maxOptLen);
916 : }
917 :
918 : {
919 1 : ret += '\n';
920 1 : auto alg = std::make_unique<GDALRasterReadAlgorithm>();
921 2 : alg->SetCallPath({alg->GetName()});
922 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
923 : }
924 : {
925 1 : ret += '\n';
926 1 : auto alg = std::make_unique<GDALVectorReadAlgorithm>();
927 2 : alg->SetCallPath({alg->GetName()});
928 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
929 : }
930 87 : for (const std::string &name : m_stepRegistry.GetNames())
931 : {
932 172 : auto alg = GetStepAlg(name);
933 86 : assert(alg);
934 95 : if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
935 100 : !alg->IsHidden() &&
936 5 : !STARTS_WITH(name.c_str(), GDALRasterReadAlgorithm::NAME))
937 : {
938 3 : ret += '\n';
939 6 : alg->SetCallPath({name});
940 3 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
941 : }
942 : }
943 87 : for (const std::string &name : m_stepRegistry.GetNames())
944 : {
945 172 : auto alg = GetStepAlg(name);
946 86 : assert(alg);
947 86 : if (alg->CanBeMiddleStep() && !alg->IsHidden())
948 : {
949 73 : ret += '\n';
950 219 : alg->SetCallPath({CPLString(alg->GetName())
951 146 : .replaceAll(RASTER_SUFFIX, "")
952 219 : .replaceAll(VECTOR_SUFFIX, "")});
953 73 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
954 : }
955 : }
956 87 : for (const std::string &name : m_stepRegistry.GetNames())
957 : {
958 172 : auto alg = GetStepAlg(name);
959 86 : assert(alg);
960 99 : if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
961 107 : !alg->IsHidden() &&
962 8 : !STARTS_WITH(name.c_str(), GDALRasterWriteAlgorithm::NAME))
963 : {
964 6 : ret += '\n';
965 12 : alg->SetCallPath({name});
966 6 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
967 : }
968 : }
969 : {
970 1 : ret += '\n';
971 1 : auto alg = std::make_unique<GDALRasterWriteAlgorithm>();
972 2 : alg->SetCallPath({alg->GetName()});
973 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
974 : }
975 : {
976 1 : ret += '\n';
977 1 : auto alg = std::make_unique<GDALVectorWriteAlgorithm>();
978 2 : alg->SetCallPath({alg->GetName()});
979 1 : ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
980 : }
981 :
982 1 : ret += GetUsageForCLIEnd();
983 :
984 1 : return ret;
985 : }
986 :
987 : //! @endcond
|