LCOV - code coverage report
Current view: top level - apps - gdalalg_pipeline.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 339 343 98.8 %
Date: 2025-12-20 00:03:37 Functions: 35 38 92.1 %

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

Generated by: LCOV version 1.14