Coverage Report

Created: 2026-09-14 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/apps/gdalalg_mdim_pipeline.cpp
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  GDAL
4
 * Purpose:  gdal "mdim pipeline" subcommand
5
 * Author:   Even Rouault <even dot rouault at spatialys.com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2026, Even Rouault <even dot rouault at spatialys.com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#include "gdalalg_mdim_pipeline.h"
14
#include "gdalalg_mdim_compare.h"
15
#include "gdalalg_mdim_read.h"
16
#include "gdalalg_mdim_write.h"
17
#include "gdalalg_mdim_info.h"
18
#include "gdalalg_mdim_mosaic.h"
19
#include "gdalalg_mdim_reproject.h"
20
21
#include "cpl_conv.h"
22
#include "cpl_progress.h"
23
#include "cpl_string.h"
24
#include "cpl_vsi.h"
25
#include "gdal_priv.h"
26
#include "gdal_utils.h"
27
28
#include <algorithm>
29
#include <array>
30
#include <cassert>
31
32
//! @cond Doxygen_Suppress
33
34
#ifndef _
35
0
#define _(x) (x)
36
#endif
37
38
0
GDALMdimAlgorithmStepRegistry::~GDALMdimAlgorithmStepRegistry() = default;
39
40
/************************************************************************/
41
/*    GDALMdimPipelineStepAlgorithm::GDALMdimPipelineStepAlgorithm()    */
42
/************************************************************************/
43
44
GDALMdimPipelineStepAlgorithm::GDALMdimPipelineStepAlgorithm(
45
    const std::string &name, const std::string &description,
46
    const std::string &helpURL, const ConstructorOptions &options)
47
0
    : GDALPipelineStepAlgorithm(name, description, helpURL, options)
48
0
{
49
0
    if (m_standaloneStep)
50
0
    {
51
0
        m_supportsStreamedOutput = true;
52
53
0
        if (m_constructorOptions.addDefaultArguments)
54
0
        {
55
0
            AddMdimInputArgs(false, false, /* acceptRaster = */ false);
56
0
            AddProgressArg();
57
0
            AddMdimOutputArgs(false);
58
0
        }
59
0
    }
60
0
    else if (m_constructorOptions.addDefaultArguments)
61
0
    {
62
0
        AddMdimHiddenInputDatasetArg();
63
0
    }
64
0
}
65
66
0
GDALMdimPipelineStepAlgorithm::~GDALMdimPipelineStepAlgorithm() = default;
67
68
/************************************************************************/
69
/*        GDALMdimPipelineAlgorithm::GDALMdimPipelineAlgorithm()        */
70
/************************************************************************/
71
72
GDALMdimPipelineAlgorithm::GDALMdimPipelineAlgorithm(
73
    bool openForMixedMdimVector)
74
0
    : GDALAbstractPipelineAlgorithm(
75
0
          NAME, DESCRIPTION, HELP_URL,
76
0
          ConstructorOptions()
77
0
              .SetAddDefaultArguments(false)
78
0
              .SetInputDatasetRequired(false)
79
0
              .SetInputDatasetPositional(false)
80
0
              .SetInputDatasetMaxCount(INT_MAX)
81
0
              .SetMdimOutputAcceptsClassicRaster(true))
82
0
{
83
0
    m_supportsStreamedOutput = true;
84
85
0
    AddMdimInputArgs(openForMixedMdimVector, /* hiddenForCLI = */ true,
86
0
                     /* acceptRaster = */ false);
87
0
    AddProgressArg();
88
0
    AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
89
0
        .SetHiddenForCLI()
90
0
        .SetPositional();
91
0
    AddMdimOutputArgs(/* hiddenForCLI = */ true);
92
93
0
    AddOutputStringArg(&m_output).SetHiddenForCLI();
94
0
    AddStdoutArg(&m_stdout);
95
96
0
    RegisterAlgorithms(m_stepRegistry, false);
97
0
}
98
99
/************************************************************************/
100
/*           GDALMdimPipelineAlgorithm::RegisterAlgorithms()            */
101
/************************************************************************/
102
103
/* static */
104
void GDALMdimPipelineAlgorithm::RegisterAlgorithms(
105
    GDALMdimAlgorithmStepRegistry &registry, bool forMixedPipeline)
106
0
{
107
0
    GDALAlgorithmRegistry::AlgInfo algInfo;
108
109
0
    const auto addSuffixIfNeeded =
110
0
        [forMixedPipeline](const char *name) -> std::string
111
0
    {
112
0
        return forMixedPipeline ? std::string(name).append(MULTIDIM_SUFFIX)
113
0
                                : std::string(name);
114
0
    };
115
116
0
    registry.Register<GDALMdimReadAlgorithm>(
117
0
        addSuffixIfNeeded(GDALMdimReadAlgorithm::NAME));
118
119
0
    registry.Register<GDALMdimMosaicAlgorithm>(
120
0
        addSuffixIfNeeded(GDALMdimMosaicAlgorithm::NAME));
121
122
0
    registry.Register<GDALMdimCompareAlgorithm>(
123
0
        addSuffixIfNeeded(GDALMdimCompareAlgorithm::NAME));
124
125
0
    registry.Register<GDALMdimWriteAlgorithm>(
126
0
        addSuffixIfNeeded(GDALMdimWriteAlgorithm::NAME));
127
128
0
    registry.Register<GDALMdimInfoAlgorithm>(
129
0
        addSuffixIfNeeded(GDALMdimInfoAlgorithm::NAME));
130
131
0
    registry.Register<GDALMdimReprojectAlgorithm>(
132
0
        addSuffixIfNeeded(GDALMdimReprojectAlgorithm::NAME));
133
0
}
134
135
/************************************************************************/
136
/*             GDALMdimPipelineAlgorithm::GetUsageForCLI()              */
137
/************************************************************************/
138
139
std::string GDALMdimPipelineAlgorithm::GetUsageForCLI(
140
    bool shortUsage, const UsageOptions &usageOptions) const
141
0
{
142
0
    UsageOptions stepUsageOptions;
143
0
    stepUsageOptions.isPipelineStep = true;
144
145
0
    if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
146
0
    {
147
0
        auto alg = GetStepAlg(m_helpDocCategory);
148
0
        if (alg)
149
0
        {
150
0
            alg->SetCallPath({m_helpDocCategory});
151
0
            alg->GetArg("help-doc")->Set(true);
152
0
            return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
153
0
        }
154
0
        else
155
0
        {
156
0
            fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
157
0
                    m_helpDocCategory.c_str());
158
0
            return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
159
0
                              m_helpDocCategory.c_str());
160
0
        }
161
0
    }
162
163
0
    UsageOptions usageOptionsMain(usageOptions);
164
0
    usageOptionsMain.isPipelineMain = true;
165
0
    std::string ret =
166
0
        GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
167
0
    if (shortUsage)
168
0
        return ret;
169
170
0
    ret += "\n<PIPELINE> is of the form: read|mosaic [READ-OPTIONS] "
171
0
           "( ! <STEP-NAME> [STEP-OPTIONS] )* ! info|write "
172
0
           "[WRITE-OPTIONS]\n";
173
174
0
    if (m_helpDocCategory == "main")
175
0
    {
176
0
        return ret;
177
0
    }
178
179
0
    ret += '\n';
180
0
    ret += "Example: 'gdal mdim pipeline --progress ! read in.nc ! \\\n";
181
0
    ret += "               reproject --output-crs=EPSG:32632 ! ";
182
0
    ret += "write out.nc --overwrite'\n";
183
0
    ret += '\n';
184
0
    ret += "Potential steps are:\n";
185
186
0
    for (const std::string &name : m_stepRegistry.GetNames())
187
0
    {
188
0
        auto alg = GetStepAlg(name);
189
0
        auto [options, maxOptLen] = alg->GetArgNamesForCLI();
190
0
        stepUsageOptions.maxOptLen =
191
0
            std::max(stepUsageOptions.maxOptLen, maxOptLen);
192
0
    }
193
194
0
    {
195
0
        const auto name = GDALMdimReadAlgorithm::NAME;
196
0
        ret += '\n';
197
0
        auto alg = GetStepAlg(name);
198
0
        alg->SetCallPath({name});
199
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
200
0
    }
201
0
    {
202
0
        const auto name = GDALMdimMosaicAlgorithm::NAME;
203
0
        ret += '\n';
204
0
        auto alg = GetStepAlg(name);
205
0
        alg->SetCallPath({name});
206
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
207
0
    }
208
0
    for (const std::string &name : m_stepRegistry.GetNames())
209
0
    {
210
0
        auto alg = GetStepAlg(name);
211
0
        assert(alg);
212
0
        if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
213
0
            !alg->IsHidden() && name != GDALMdimReadAlgorithm::NAME &&
214
0
            name != GDALMdimMosaicAlgorithm::NAME)
215
0
        {
216
0
            ret += '\n';
217
0
            alg->SetCallPath({name});
218
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
219
0
        }
220
0
    }
221
0
    for (const std::string &name : m_stepRegistry.GetNames())
222
0
    {
223
0
        auto alg = GetStepAlg(name);
224
0
        assert(alg);
225
0
        if (alg->CanBeMiddleStep() && !alg->IsHidden())
226
0
        {
227
0
            ret += '\n';
228
0
            alg->SetCallPath({name});
229
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
230
0
        }
231
0
    }
232
0
    for (const std::string &name : m_stepRegistry.GetNames())
233
0
    {
234
0
        auto alg = GetStepAlg(name);
235
0
        assert(alg);
236
0
        if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
237
0
            !alg->IsHidden() && name != GDALMdimWriteAlgorithm::NAME)
238
0
        {
239
0
            ret += '\n';
240
0
            alg->SetCallPath({name});
241
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
242
0
        }
243
0
    }
244
0
    {
245
0
        const auto name = GDALMdimWriteAlgorithm::NAME;
246
0
        ret += '\n';
247
0
        auto alg = GetStepAlg(name);
248
0
        alg->SetCallPath({name});
249
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
250
0
    }
251
0
    ret += GetUsageForCLIEnd();
252
253
0
    return ret;
254
0
}
255
256
//! @endcond