LCOV - code coverage report
Current view: top level - apps - gdalalg_abstract_pipeline.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 70 78 89.7 %
Date: 2025-01-18 12:42:00 Functions: 12 14 85.7 %

          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 "cpl_conv.h"
      19             : #include "cpl_json.h"
      20             : #include "gdalalgorithm.h"
      21             : 
      22             : template <class StepAlgorithm>
      23             : class GDALAbstractPipelineAlgorithm CPL_NON_FINAL : public StepAlgorithm
      24             : {
      25             :   public:
      26             :     std::vector<std::string> GetAutoComplete(std::vector<std::string> &args,
      27             :                                              bool /* showAllOptions*/) override;
      28             : 
      29             :     bool Finalize() override;
      30             : 
      31             :     std::string GetUsageAsJSON() const override;
      32             : 
      33             :     /* cppcheck-suppress functionStatic */
      34           0 :     void SetDataset(GDALDataset *)
      35             :     {
      36           0 :     }
      37             : 
      38             :   protected:
      39         117 :     GDALAbstractPipelineAlgorithm(const std::string &name,
      40             :                                   const std::string &description,
      41             :                                   const std::string &helpURL,
      42             :                                   bool standaloneStep)
      43         117 :         : StepAlgorithm(name, description, helpURL, standaloneStep)
      44             :     {
      45         117 :     }
      46             : 
      47             :     virtual GDALArgDatasetValue &GetOutputDataset() = 0;
      48             : 
      49             :     std::string m_pipeline{};
      50             : 
      51             :     std::unique_ptr<StepAlgorithm> GetStepAlg(const std::string &name) const;
      52             : 
      53             :     GDALAlgorithmRegistry m_stepRegistry{};
      54             :     std::vector<std::unique_ptr<StepAlgorithm>> m_steps{};
      55             : 
      56             :   private:
      57             :     bool RunStep(GDALProgressFunc pfnProgress, void *pProgressData) override;
      58             : };
      59             : 
      60             : /************************************************************************/
      61             : /*              GDALAbstractPipelineAlgorithm::GetStepAlg()             */
      62             : /************************************************************************/
      63             : 
      64             : template <class StepAlgorithm>
      65             : std::unique_ptr<StepAlgorithm>
      66         243 : GDALAbstractPipelineAlgorithm<StepAlgorithm>::GetStepAlg(
      67             :     const std::string &name) const
      68             : {
      69         486 :     auto alg = m_stepRegistry.Instantiate(name);
      70             :     return std::unique_ptr<StepAlgorithm>(
      71         486 :         cpl::down_cast<StepAlgorithm *>(alg.release()));
      72             : }
      73             : 
      74             : /************************************************************************/
      75             : /*         GDALAbstractPipelineAlgorithm::GetAutoComplete()             */
      76             : /************************************************************************/
      77             : 
      78             : template <class StepAlgorithm>
      79             : std::vector<std::string>
      80          16 : GDALAbstractPipelineAlgorithm<StepAlgorithm>::GetAutoComplete(
      81             :     std::vector<std::string> &args, bool /* showAllOptions*/)
      82             : {
      83          16 :     std::vector<std::string> ret;
      84          16 :     if (args.size() <= 1)
      85             :     {
      86           6 :         if (args.empty() || args.front() != "read")
      87           4 :             ret.push_back("read");
      88             :     }
      89          10 :     else if (args.back() == "!" || args[args.size() - 2] == "!")
      90             :     {
      91          22 :         for (const std::string &name : m_stepRegistry.GetNames())
      92             :         {
      93          18 :             if (name != "read")
      94             :             {
      95          14 :                 ret.push_back(name);
      96             :             }
      97             :         }
      98             :     }
      99             :     else
     100             :     {
     101          12 :         std::string lastStep = "read";
     102          12 :         std::vector<std::string> lastArgs;
     103          21 :         for (size_t i = 1; i < args.size(); ++i)
     104             :         {
     105          15 :             lastArgs.push_back(args[i]);
     106          15 :             if (i + 1 < args.size() && args[i] == "!")
     107             :             {
     108           5 :                 ++i;
     109           5 :                 lastArgs.clear();
     110           5 :                 lastStep = args[i];
     111             :             }
     112             :         }
     113             : 
     114          12 :         auto curAlg = GetStepAlg(lastStep);
     115           6 :         if (curAlg)
     116             :         {
     117           6 :             ret =
     118           6 :                 curAlg->GetAutoComplete(lastArgs, /* showAllOptions = */ false);
     119             :         }
     120             :     }
     121          16 :     return ret;
     122             : }
     123             : 
     124             : /************************************************************************/
     125             : /*              GDALAbstractPipelineAlgorithm::RunStep()                */
     126             : /************************************************************************/
     127             : 
     128             : template <class StepAlgorithm>
     129          58 : bool GDALAbstractPipelineAlgorithm<StepAlgorithm>::RunStep(
     130             :     GDALProgressFunc pfnProgress, void *pProgressData)
     131             : {
     132          58 :     if (m_steps.empty())
     133             :     {
     134             :         // If invoked programmatically, not from the command line.
     135             : 
     136          17 :         if (m_pipeline.empty())
     137             :         {
     138           2 :             StepAlgorithm::ReportError(CE_Failure, CPLE_AppDefined,
     139             :                                        "'pipeline' argument not set");
     140           4 :             return false;
     141             :         }
     142             : 
     143          15 :         const CPLStringList aosTokens(CSLTokenizeString(m_pipeline.c_str()));
     144          15 :         if (!this->ParseCommandLineArguments(aosTokens))
     145           2 :             return false;
     146             :     }
     147             : 
     148          54 :     GDALDataset *poCurDS = nullptr;
     149         166 :     for (size_t i = 0; i < m_steps.size(); ++i)
     150             :     {
     151         121 :         auto &step = m_steps[i];
     152         121 :         if (i > 0)
     153             :         {
     154          67 :             if (step->m_inputDataset.GetDatasetRef())
     155             :             {
     156             :                 // Shouldn't happen
     157           0 :                 StepAlgorithm::ReportError(
     158             :                     CE_Failure, CPLE_AppDefined,
     159             :                     "Step nr %d (%s) has already an input dataset",
     160           0 :                     static_cast<int>(i), step->GetName().c_str());
     161           0 :                 return false;
     162             :             }
     163          67 :             step->m_inputDataset.Set(poCurDS);
     164             :         }
     165         121 :         if (i + 1 < m_steps.size() && step->m_outputDataset.GetDatasetRef())
     166             :         {
     167             :             // Shouldn't happen
     168           2 :             StepAlgorithm::ReportError(
     169             :                 CE_Failure, CPLE_AppDefined,
     170             :                 "Step nr %d (%s) has already an output dataset",
     171           2 :                 static_cast<int>(i), step->GetName().c_str());
     172           2 :             return false;
     173             :         }
     174         238 :         if (!step->Run(i < m_steps.size() - 1 ? nullptr : pfnProgress,
     175         119 :                        i < m_steps.size() - 1 ? nullptr : pProgressData))
     176             :         {
     177           7 :             return false;
     178             :         }
     179         112 :         poCurDS = step->m_outputDataset.GetDatasetRef();
     180         112 :         if (!poCurDS)
     181             :         {
     182           0 :             StepAlgorithm::ReportError(
     183             :                 CE_Failure, CPLE_AppDefined,
     184             :                 "Step nr %d (%s) failed to produce an output dataset",
     185           0 :                 static_cast<int>(i), step->GetName().c_str());
     186           0 :             return false;
     187             :         }
     188             :     }
     189             : 
     190          45 :     if (!GetOutputDataset().GetDatasetRef())
     191             :     {
     192          45 :         GetOutputDataset().Set(poCurDS);
     193             :     }
     194             : 
     195          45 :     return true;
     196             : }
     197             : 
     198             : /************************************************************************/
     199             : /*               GDALAbstractPipelineAlgorithm::Finalize()              */
     200             : /************************************************************************/
     201             : 
     202             : template <class StepAlgorithm>
     203          45 : bool GDALAbstractPipelineAlgorithm<StepAlgorithm>::Finalize()
     204             : {
     205          45 :     bool ret = GDALAlgorithm::Finalize();
     206         147 :     for (auto &step : m_steps)
     207             :     {
     208         102 :         ret = step->Finalize() && ret;
     209             :     }
     210          45 :     return ret;
     211             : }
     212             : 
     213             : /************************************************************************/
     214             : /*             GDALAbstractPipelineAlgorithm::GetUsageAsJSON()          */
     215             : /************************************************************************/
     216             : 
     217             : template <class StepAlgorithm>
     218           7 : std::string GDALAbstractPipelineAlgorithm<StepAlgorithm>::GetUsageAsJSON() const
     219             : {
     220          14 :     CPLJSONDocument oDoc;
     221           7 :     CPL_IGNORE_RET_VAL(oDoc.LoadMemory(GDALAlgorithm::GetUsageAsJSON()));
     222             : 
     223          14 :     CPLJSONArray jPipelineSteps;
     224          39 :     for (const std::string &name : m_stepRegistry.GetNames())
     225             :     {
     226          64 :         auto alg = GetStepAlg(name);
     227          32 :         CPLJSONDocument oStepDoc;
     228          32 :         CPL_IGNORE_RET_VAL(oStepDoc.LoadMemory(alg->GetUsageAsJSON()));
     229          32 :         jPipelineSteps.Add(oStepDoc.GetRoot());
     230             :     }
     231           7 :     oDoc.GetRoot().Add("pipeline_algorithms", jPipelineSteps);
     232             : 
     233          14 :     return oDoc.SaveAsString();
     234             : }
     235             : 
     236             : //! @endcond
     237             : 
     238             : #endif

Generated by: LCOV version 1.14