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

Generated by: LCOV version 1.14