Coverage Report

Created: 2026-07-25 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(NAME, DESCRIPTION, HELP_URL,
75
0
                                    ConstructorOptions()
76
0
                                        .SetAddDefaultArguments(false)
77
0
                                        .SetInputDatasetRequired(false)
78
0
                                        .SetInputDatasetPositional(false)
79
0
                                        .SetInputDatasetMaxCount(INT_MAX))
80
0
{
81
0
    m_supportsStreamedOutput = true;
82
83
0
    AddMdimInputArgs(openForMixedMdimVector, /* hiddenForCLI = */ true,
84
0
                     /* acceptRaster = */ false);
85
0
    AddProgressArg();
86
0
    AddArg("pipeline", 0, _("Pipeline string"), &m_pipeline)
87
0
        .SetHiddenForCLI()
88
0
        .SetPositional();
89
0
    AddMdimOutputArgs(/* hiddenForCLI = */ true);
90
91
0
    AddOutputStringArg(&m_output).SetHiddenForCLI();
92
0
    AddStdoutArg(&m_stdout);
93
94
0
    RegisterAlgorithms(m_stepRegistry, false);
95
0
}
96
97
/************************************************************************/
98
/*           GDALMdimPipelineAlgorithm::RegisterAlgorithms()            */
99
/************************************************************************/
100
101
/* static */
102
void GDALMdimPipelineAlgorithm::RegisterAlgorithms(
103
    GDALMdimAlgorithmStepRegistry &registry, bool forMixedPipeline)
104
0
{
105
0
    GDALAlgorithmRegistry::AlgInfo algInfo;
106
107
0
    const auto addSuffixIfNeeded =
108
0
        [forMixedPipeline](const char *name) -> std::string
109
0
    {
110
0
        return forMixedPipeline ? std::string(name).append(MULTIDIM_SUFFIX)
111
0
                                : std::string(name);
112
0
    };
113
114
0
    registry.Register<GDALMdimReadAlgorithm>(
115
0
        addSuffixIfNeeded(GDALMdimReadAlgorithm::NAME));
116
117
0
    registry.Register<GDALMdimMosaicAlgorithm>(
118
0
        addSuffixIfNeeded(GDALMdimMosaicAlgorithm::NAME));
119
120
0
    registry.Register<GDALMdimCompareAlgorithm>(
121
0
        addSuffixIfNeeded(GDALMdimCompareAlgorithm::NAME));
122
123
0
    registry.Register<GDALMdimWriteAlgorithm>(
124
0
        addSuffixIfNeeded(GDALMdimWriteAlgorithm::NAME));
125
126
0
    registry.Register<GDALMdimInfoAlgorithm>(
127
0
        addSuffixIfNeeded(GDALMdimInfoAlgorithm::NAME));
128
129
0
    registry.Register<GDALMdimReprojectAlgorithm>(
130
0
        addSuffixIfNeeded(GDALMdimReprojectAlgorithm::NAME));
131
0
}
132
133
/************************************************************************/
134
/*             GDALMdimPipelineAlgorithm::GetUsageForCLI()              */
135
/************************************************************************/
136
137
std::string GDALMdimPipelineAlgorithm::GetUsageForCLI(
138
    bool shortUsage, const UsageOptions &usageOptions) const
139
0
{
140
0
    UsageOptions stepUsageOptions;
141
0
    stepUsageOptions.isPipelineStep = true;
142
143
0
    if (!m_helpDocCategory.empty() && m_helpDocCategory != "main")
144
0
    {
145
0
        auto alg = GetStepAlg(m_helpDocCategory);
146
0
        if (alg)
147
0
        {
148
0
            alg->SetCallPath({m_helpDocCategory});
149
0
            alg->GetArg("help-doc")->Set(true);
150
0
            return alg->GetUsageForCLI(shortUsage, stepUsageOptions);
151
0
        }
152
0
        else
153
0
        {
154
0
            fprintf(stderr, "ERROR: unknown pipeline step '%s'\n",
155
0
                    m_helpDocCategory.c_str());
156
0
            return CPLSPrintf("ERROR: unknown pipeline step '%s'\n",
157
0
                              m_helpDocCategory.c_str());
158
0
        }
159
0
    }
160
161
0
    UsageOptions usageOptionsMain(usageOptions);
162
0
    usageOptionsMain.isPipelineMain = true;
163
0
    std::string ret =
164
0
        GDALAlgorithm::GetUsageForCLI(shortUsage, usageOptionsMain);
165
0
    if (shortUsage)
166
0
        return ret;
167
168
0
    ret += "\n<PIPELINE> is of the form: read|mosaic [READ-OPTIONS] "
169
0
           "( ! <STEP-NAME> [STEP-OPTIONS] )* ! info|write "
170
0
           "[WRITE-OPTIONS]\n";
171
172
0
    if (m_helpDocCategory == "main")
173
0
    {
174
0
        return ret;
175
0
    }
176
177
0
    ret += '\n';
178
0
    ret += "Example: 'gdal mdim pipeline --progress ! read in.nc ! \\\n";
179
0
    ret += "               reproject --output-crs=EPSG:32632 ! ";
180
0
    ret += "write out.nc --overwrite'\n";
181
0
    ret += '\n';
182
0
    ret += "Potential steps are:\n";
183
184
0
    for (const std::string &name : m_stepRegistry.GetNames())
185
0
    {
186
0
        auto alg = GetStepAlg(name);
187
0
        auto [options, maxOptLen] = alg->GetArgNamesForCLI();
188
0
        stepUsageOptions.maxOptLen =
189
0
            std::max(stepUsageOptions.maxOptLen, maxOptLen);
190
0
    }
191
192
0
    {
193
0
        const auto name = GDALMdimReadAlgorithm::NAME;
194
0
        ret += '\n';
195
0
        auto alg = GetStepAlg(name);
196
0
        alg->SetCallPath({name});
197
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
198
0
    }
199
0
    {
200
0
        const auto name = GDALMdimMosaicAlgorithm::NAME;
201
0
        ret += '\n';
202
0
        auto alg = GetStepAlg(name);
203
0
        alg->SetCallPath({name});
204
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
205
0
    }
206
0
    for (const std::string &name : m_stepRegistry.GetNames())
207
0
    {
208
0
        auto alg = GetStepAlg(name);
209
0
        assert(alg);
210
0
        if (alg->CanBeFirstStep() && !alg->CanBeMiddleStep() &&
211
0
            !alg->IsHidden() && name != GDALMdimReadAlgorithm::NAME &&
212
0
            name != GDALMdimMosaicAlgorithm::NAME)
213
0
        {
214
0
            ret += '\n';
215
0
            alg->SetCallPath({name});
216
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
217
0
        }
218
0
    }
219
0
    for (const std::string &name : m_stepRegistry.GetNames())
220
0
    {
221
0
        auto alg = GetStepAlg(name);
222
0
        assert(alg);
223
0
        if (alg->CanBeMiddleStep() && !alg->IsHidden())
224
0
        {
225
0
            ret += '\n';
226
0
            alg->SetCallPath({name});
227
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
228
0
        }
229
0
    }
230
0
    for (const std::string &name : m_stepRegistry.GetNames())
231
0
    {
232
0
        auto alg = GetStepAlg(name);
233
0
        assert(alg);
234
0
        if (alg->CanBeLastStep() && !alg->CanBeMiddleStep() &&
235
0
            !alg->IsHidden() && name != GDALMdimWriteAlgorithm::NAME)
236
0
        {
237
0
            ret += '\n';
238
0
            alg->SetCallPath({name});
239
0
            ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
240
0
        }
241
0
    }
242
0
    {
243
0
        const auto name = GDALMdimWriteAlgorithm::NAME;
244
0
        ret += '\n';
245
0
        auto alg = GetStepAlg(name);
246
0
        alg->SetCallPath({name});
247
0
        ret += alg->GetUsageForCLI(shortUsage, stepUsageOptions);
248
0
    }
249
0
    ret += GetUsageForCLIEnd();
250
251
0
    return ret;
252
0
}
253
254
//! @endcond