LCOV - code coverage report
Current view: top level - apps - gdalalg_pipeline.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 512 519 98.7 %
Date: 2026-06-13 02:54:04 Functions: 20 20 100.0 %

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

Generated by: LCOV version 1.14