LCOV - code coverage report
Current view: top level - apps - gdalalg_pipeline.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 331 335 98.8 %
Date: 2025-09-10 17:48:50 Functions: 31 34 91.2 %

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

Generated by: LCOV version 1.14