LCOV - code coverage report
Current view: top level - apps - gdalalg_pipeline.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 343 347 98.8 %
Date: 2025-11-18 00:07:43 Functions: 33 36 91.7 %

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

Generated by: LCOV version 1.14