Coverage Report

Created: 2026-02-14 06:52

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