LCOV - code coverage report
Current view: top level - apps - gdalalg_abstract_pipeline.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 67 67 100.0 %
Date: 2025-09-10 17:48:50 Functions: 26 26 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL
       4             :  * Purpose:  gdal "raster/vector 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             : #ifndef GDALALG_ABSTRACT_PIPELINE_INCLUDED
      14             : #define GDALALG_ABSTRACT_PIPELINE_INCLUDED
      15             : 
      16             : //! @cond Doxygen_Suppress
      17             : 
      18             : #include "gdalalgorithm.h"
      19             : #include "gdal_priv.h"
      20             : 
      21             : #include <algorithm>
      22             : 
      23             : // This is an easter egg to pay tribute to PROJ pipeline syntax
      24             : // We accept "gdal vector +gdal=pipeline +step +gdal=read +input=in.tif +step +gdal=reproject +dst-crs=EPSG:32632 +step +gdal=write +output=out.tif +overwrite"
      25             : // as an alternative to (recommended):
      26             : // "gdal vector pipeline ! read in.tif ! reproject--dst-crs=EPSG:32632 ! write out.tif --overwrite"
      27             : #ifndef GDAL_PIPELINE_PROJ_NOSTALGIA
      28             : #define GDAL_PIPELINE_PROJ_NOSTALGIA
      29             : #endif
      30             : 
      31             : /************************************************************************/
      32             : /*                      GDALPipelineStepRunContext                      */
      33             : /************************************************************************/
      34             : 
      35             : class GDALPipelineStepAlgorithm;
      36             : 
      37             : class GDALPipelineStepRunContext
      38             : {
      39             :   public:
      40             :     GDALPipelineStepRunContext() = default;
      41             : 
      42             :     // Progress callback to use during execution of the step
      43             :     GDALProgressFunc m_pfnProgress = nullptr;
      44             :     void *m_pProgressData = nullptr;
      45             : 
      46             :     // If there is a step in the pipeline immediately following step to which
      47             :     // this instance of GDALRasterPipelineStepRunContext is passed, and that
      48             :     // this next step is usable by the current step (as determined by
      49             :     // CanHandleNextStep()), then this member will point to this next step.
      50             :     GDALPipelineStepAlgorithm *m_poNextUsableStep = nullptr;
      51             : 
      52             :   private:
      53             :     CPL_DISALLOW_COPY_ASSIGN(GDALPipelineStepRunContext)
      54             : };
      55             : 
      56             : /************************************************************************/
      57             : /*                     GDALPipelineStepAlgorithm                        */
      58             : /************************************************************************/
      59             : 
      60             : class GDALPipelineStepAlgorithm /* non final */ : public GDALAlgorithm
      61             : {
      62             :   public:
      63          78 :     std::vector<GDALArgDatasetValue> &GetInputDatasets()
      64             :     {
      65          78 :         return m_inputDataset;
      66             :     }
      67             : 
      68             :     const std::vector<GDALArgDatasetValue> &GetInputDatasets() const
      69             :     {
      70             :         return m_inputDataset;
      71             :     }
      72             : 
      73          51 :     GDALArgDatasetValue &GetOutputDataset()
      74             :     {
      75          51 :         return m_outputDataset;
      76             :     }
      77             : 
      78             :     const GDALArgDatasetValue &GetOutputDataset() const
      79             :     {
      80             :         return m_outputDataset;
      81             :     }
      82             : 
      83         144 :     const std::string &GetOutputFormat() const
      84             :     {
      85         144 :         return m_format;
      86             :     }
      87             : 
      88          48 :     const std::vector<std::string> &GetCreationOptions() const
      89             :     {
      90          48 :         return m_creationOptions;
      91             :     }
      92             : 
      93             :     virtual int GetInputType() const = 0;
      94             : 
      95             :     virtual int GetOutputType() const = 0;
      96             : 
      97             :     bool Finalize() override;
      98             : 
      99             :     // Used by GDALDispatcherAlgorithm for vector info/convert
     100          26 :     GDALDataset *GetInputDatasetRef()
     101             :     {
     102          26 :         return m_inputDataset.empty() ? nullptr
     103          26 :                                       : m_inputDataset[0].GetDatasetRef();
     104             :     }
     105             : 
     106             :     // Used by GDALDispatcherAlgorithm for vector info/convert
     107             :     void SetInputDataset(GDALDataset *poDS);
     108             : 
     109             :   protected:
     110             :     struct ConstructorOptions
     111             :     {
     112             :         bool standaloneStep = false;
     113             :         bool addDefaultArguments = true;
     114             :         bool autoOpenInputDatasets = true;
     115             :         bool outputDatasetRequired = true;
     116             :         bool addInputLayerNameArgument = true;  // only for vector input
     117             :         int inputDatasetMaxCount = 1;
     118             :         std::string inputDatasetHelpMsg{};
     119             :         std::string inputDatasetAlias{};
     120             :         std::string inputDatasetMetaVar = "INPUT";
     121             :         std::string outputDatasetHelpMsg{};
     122             :         std::string updateMutualExclusionGroup{};
     123             :         std::string outputDatasetMutualExclusionGroup{};
     124             :         std::string outputFormatCreateCapability = GDAL_DCAP_CREATECOPY;
     125             : 
     126        6017 :         inline ConstructorOptions &SetStandaloneStep(bool b)
     127             :         {
     128        6017 :             standaloneStep = b;
     129        6017 :             return *this;
     130             :         }
     131             : 
     132        2817 :         inline ConstructorOptions &SetAddDefaultArguments(bool b)
     133             :         {
     134        2817 :             addDefaultArguments = b;
     135        2817 :             return *this;
     136             :         }
     137             : 
     138         150 :         inline ConstructorOptions &SetAddInputLayerNameArgument(bool b)
     139             :         {
     140         150 :             addInputLayerNameArgument = b;
     141         150 :             return *this;
     142             :         }
     143             : 
     144        1532 :         inline ConstructorOptions &SetInputDatasetMaxCount(int maxCount)
     145             :         {
     146        1532 :             inputDatasetMaxCount = maxCount;
     147        1532 :             return *this;
     148             :         }
     149             : 
     150         843 :         inline ConstructorOptions &SetInputDatasetHelpMsg(const std::string &s)
     151             :         {
     152         843 :             inputDatasetHelpMsg = s;
     153         843 :             return *this;
     154             :         }
     155             : 
     156         488 :         inline ConstructorOptions &SetInputDatasetAlias(const std::string &s)
     157             :         {
     158         488 :             inputDatasetAlias = s;
     159         488 :             return *this;
     160             :         }
     161             : 
     162         203 :         inline ConstructorOptions &SetInputDatasetMetaVar(const std::string &s)
     163             :         {
     164         203 :             inputDatasetMetaVar = s;
     165         203 :             return *this;
     166             :         }
     167             : 
     168          71 :         inline ConstructorOptions &SetOutputDatasetHelpMsg(const std::string &s)
     169             :         {
     170          71 :             outputDatasetHelpMsg = s;
     171          71 :             return *this;
     172             :         }
     173             : 
     174         362 :         inline ConstructorOptions &SetAutoOpenInputDatasets(bool b)
     175             :         {
     176         362 :             autoOpenInputDatasets = b;
     177         362 :             return *this;
     178             :         }
     179             : 
     180          58 :         inline ConstructorOptions &SetOutputDatasetRequired(bool b)
     181             :         {
     182          58 :             outputDatasetRequired = b;
     183          58 :             return *this;
     184             :         }
     185             : 
     186             :         inline ConstructorOptions &
     187          58 :         SetUpdateMutualExclusionGroup(const std::string &s)
     188             :         {
     189          58 :             updateMutualExclusionGroup = s;
     190          58 :             return *this;
     191             :         }
     192             : 
     193             :         inline ConstructorOptions &
     194          58 :         SetOutputDatasetMutualExclusionGroup(const std::string &s)
     195             :         {
     196          58 :             outputDatasetMutualExclusionGroup = s;
     197          58 :             return *this;
     198             :         }
     199             : 
     200             :         inline ConstructorOptions &
     201         459 :         SetOutputFormatCreateCapability(const std::string &capability)
     202             :         {
     203         459 :             outputFormatCreateCapability = capability;
     204         459 :             return *this;
     205             :         }
     206             :     };
     207             : 
     208             :     GDALPipelineStepAlgorithm(const std::string &name,
     209             :                               const std::string &description,
     210             :                               const std::string &helpURL,
     211             :                               const ConstructorOptions &);
     212             : 
     213             :     friend class GDALPipelineAlgorithm;
     214             :     friend class GDALRasterPipelineAlgorithm;
     215             :     friend class GDALVectorPipelineAlgorithm;
     216             :     friend class GDALAbstractPipelineAlgorithm;
     217             : 
     218        1477 :     virtual bool CanBeFirstStep() const
     219             :     {
     220        1477 :         return false;
     221             :     }
     222             : 
     223         422 :     virtual bool CanBeMiddleStep() const
     224             :     {
     225         422 :         return !CanBeFirstStep() && !CanBeLastStep();
     226             :     }
     227             : 
     228        1213 :     virtual bool CanBeLastStep() const
     229             :     {
     230        1213 :         return false;
     231             :     }
     232             : 
     233             :     //! Whether a user parameter can cause a file to be written at a specified location
     234          43 :     virtual bool GeneratesFilesFromUserInput() const
     235             :     {
     236          43 :         return false;
     237             :     }
     238             : 
     239         338 :     virtual bool IsNativelyStreamingCompatible() const
     240             :     {
     241         338 :         return true;
     242             :     }
     243             : 
     244         158 :     virtual bool SupportsInputMultiThreading() const
     245             :     {
     246         158 :         return false;
     247             :     }
     248             : 
     249         890 :     virtual bool CanHandleNextStep(GDALPipelineStepAlgorithm *) const
     250             :     {
     251         890 :         return false;
     252             :     }
     253             : 
     254             :     virtual bool RunStep(GDALPipelineStepRunContext &ctxt) = 0;
     255             : 
     256             :     bool m_standaloneStep = false;
     257             :     const ConstructorOptions m_constructorOptions;
     258             :     bool m_outputVRTCompatible = true;
     259             :     std::string m_helpDocCategory{};
     260             : 
     261             :     // Input arguments
     262             :     std::vector<GDALArgDatasetValue> m_inputDataset{};
     263             :     std::vector<std::string> m_openOptions{};
     264             :     std::vector<std::string> m_inputFormats{};
     265             :     std::vector<std::string> m_inputLayerNames{};
     266             : 
     267             :     // Output arguments
     268             :     bool m_stdout = false;
     269             :     std::string m_output{};
     270             :     GDALArgDatasetValue m_outputDataset{};
     271             :     std::string m_format{};
     272             :     std::vector<std::string> m_outputOpenOptions{};
     273             :     std::vector<std::string> m_creationOptions{};
     274             :     bool m_overwrite = false;
     275             :     std::string m_outputLayerName{};
     276             :     GDALInConstructionAlgorithmArg *m_outputFormatArg = nullptr;
     277             :     bool m_appendRaster = false;
     278             : 
     279             :     // Output arguments (vector specific)
     280             :     std::vector<std::string> m_layerCreationOptions{};
     281             :     bool m_update = false;
     282             :     bool m_overwriteLayer = false;
     283             :     bool m_appendLayer = false;
     284             :     bool m_upsert = false;
     285             :     bool m_skipErrors = false;
     286             : 
     287             :     void AddRasterInputArgs(bool openForMixedRasterVector, bool hiddenForCLI);
     288             :     void AddRasterOutputArgs(bool hiddenForCLI);
     289             :     void AddRasterHiddenInputDatasetArg();
     290             : 
     291             :     void AddVectorInputArgs(bool hiddenForCLI);
     292             :     void AddVectorOutputArgs(bool hiddenForCLI,
     293             :                              bool shortNameOutputLayerAllowed);
     294             : 
     295             :   private:
     296             :     bool RunImpl(GDALProgressFunc pfnProgress, void *pProgressData) override;
     297             :     GDALAlgorithm::ProcessGDALGOutputRet ProcessGDALGOutput() override;
     298             :     bool CheckSafeForStreamOutput() override;
     299             : 
     300             :     CPL_DISALLOW_COPY_ASSIGN(GDALPipelineStepAlgorithm)
     301             : };
     302             : 
     303             : /************************************************************************/
     304             : /*                    GDALAbstractPipelineAlgorithm                     */
     305             : /************************************************************************/
     306             : 
     307             : class GDALAbstractPipelineAlgorithm CPL_NON_FINAL
     308             :     : public GDALPipelineStepAlgorithm
     309             : {
     310             :   public:
     311             :     std::vector<std::string> GetAutoComplete(std::vector<std::string> &args,
     312             :                                              bool lastWordIsComplete,
     313             :                                              bool /* showAllOptions*/) override;
     314             : 
     315             :     bool Finalize() override;
     316             : 
     317             :     std::string GetUsageAsJSON() const override;
     318             : 
     319             :     static constexpr const char *OPEN_NESTED_PIPELINE = "[";
     320             :     static constexpr const char *CLOSE_NESTED_PIPELINE = "]";
     321             : 
     322             :   protected:
     323         402 :     GDALAbstractPipelineAlgorithm(
     324             :         const std::string &name, const std::string &description,
     325             :         const std::string &helpURL,
     326             :         const typename GDALPipelineStepAlgorithm::ConstructorOptions &options)
     327         402 :         : GDALPipelineStepAlgorithm(name, description, helpURL, options)
     328             :     {
     329         402 :     }
     330             : 
     331             :     std::string m_pipeline{};
     332             : 
     333             :     virtual GDALAlgorithmRegistry &GetStepRegistry() = 0;
     334             : 
     335             :     virtual const GDALAlgorithmRegistry &GetStepRegistry() const = 0;
     336             : 
     337             :     std::unique_ptr<GDALPipelineStepAlgorithm>
     338             :     GetStepAlg(const std::string &name) const;
     339             : 
     340             :     bool
     341             :     ParseCommandLineArguments(const std::vector<std::string> &args) override;
     342             : 
     343             :     static bool IsReadSpecificArgument(const char *pszArgName);
     344             :     static bool IsWriteSpecificArgument(const char *pszArgName);
     345             : 
     346             :     static constexpr const char *RASTER_SUFFIX = "-raster";
     347             :     static constexpr const char *VECTOR_SUFFIX = "-vector";
     348             : 
     349             :   private:
     350             :     std::vector<std::unique_ptr<GDALPipelineStepAlgorithm>> m_steps{};
     351             : 
     352             :     std::unique_ptr<GDALPipelineStepAlgorithm> m_stepOnWhichHelpIsRequested{};
     353             : 
     354             :     bool m_bExpectReadStep = true;
     355             :     bool m_bExpectWriteStep = true;
     356             : 
     357             :     std::vector<std::unique_ptr<GDALAbstractPipelineAlgorithm>>
     358             :         m_apoNestedPipelines{};
     359             : 
     360             :     // More would lead to unreadable pipelines
     361             :     static constexpr int MAX_NESTING_LEVEL = 3;
     362             : 
     363             :     bool CheckFirstAndLastStep(
     364             :         const std::vector<GDALPipelineStepAlgorithm *> &steps) const;
     365             : 
     366             :     bool ParseCommandLineArguments(const std::vector<std::string> &args,
     367             :                                    bool forAutoComplete);
     368             : 
     369             :     bool RunStep(GDALPipelineStepRunContext &ctxt) override;
     370             : 
     371             :     std::string
     372             :     BuildNestedPipeline(GDALPipelineStepAlgorithm *curAlg,
     373             :                         std::vector<std::string> &nestedPipelineArgs,
     374             :                         bool forAutoComplete);
     375             : 
     376             :     bool SaveGDALGFile(const std::string &outFilename,
     377             :                        std::string &outString) const;
     378             : 
     379             :     virtual std::unique_ptr<GDALAbstractPipelineAlgorithm>
     380             :     CreateNestedPipeline() const = 0;
     381             : };
     382             : 
     383             : //! @endcond
     384             : 
     385             : #endif

Generated by: LCOV version 1.14