Skip to content

Commit

Permalink
Implement RFC 104: Adding a "gdal" front-end command line interface
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Nov 21, 2024
1 parent 4da351d commit 0d17ede
Show file tree
Hide file tree
Showing 44 changed files with 12,642 additions and 5 deletions.
17 changes: 17 additions & 0 deletions apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ add_library(
commonutils.h
gdal_utils.h
gdalargumentparser.cpp
gdalalg_convert.cpp
gdalalg_info.cpp
gdalalg_main.cpp
gdalalg_pipeline.cpp
gdalalg_raster.cpp
gdalalg_raster_info.cpp
gdalalg_raster_convert.cpp
gdalalg_vector.cpp
gdalalg_vector_info.cpp
gdalalg_vector_convert.cpp
gdalalg_vector_pipeline.cpp
gdalalg_vector_read.cpp
gdalalg_vector_filter.cpp
gdalalg_vector_reproject.cpp
gdalalg_vector_write.cpp
gdalinfo_lib.cpp
gdalbuildvrt_lib.cpp
gdal_grid_lib.cpp
Expand Down Expand Up @@ -49,6 +64,7 @@ target_public_header(TARGET ${GDAL_LIB_TARGET_NAME} HEADERS gdal_utils.h)

if (BUILD_APPS)
# Default Apps
add_executable(gdal gdal_utils_priv.h gdal.cpp)
add_executable(gdalinfo gdal_utils_priv.h gdalinfo_bin.cpp)
add_executable(gdalbuildvrt gdal_utils_priv.h gdalbuildvrt_bin.cpp)
add_executable(gdaladdo gdal_utils_priv.h gdaladdo.cpp)
Expand Down Expand Up @@ -89,6 +105,7 @@ if (BUILD_APPS)
add_dependencies(utils_common generate_gdal_version_h)

set(APPS_TARGETS
gdal
gdalinfo
gdalbuildvrt
gdaladdo
Expand Down
87 changes: 87 additions & 0 deletions apps/gdal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: CLI front-end
* Author: Even Rouault <even dot rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
*
* SPDX-License-Identifier: MIT
****************************************************************************/

#include "gdalalgorithm.h"
#include "commonutils.h"

#include "gdal.h"

#include <cassert>

/************************************************************************/
/* main() */
/************************************************************************/

MAIN_START(argc, argv)
{
EarlySetConfigOptions(argc, argv);

/* -------------------------------------------------------------------- */
/* Register standard GDAL drivers, and process generic GDAL */
/* command options. */
/* -------------------------------------------------------------------- */

GDALAllRegister();
argc = GDALGeneralCmdLineProcessor(argc, &argv, 0);
if (argc < 1)
return (-argc);

auto alg = GDALGlobalAlgorithmRegistry::GetSingleton().Instantiate(
GDALGlobalAlgorithmRegistry::ROOT_ALG_NAME);
assert(alg);
alg->SetCallPath(std::vector<std::string>{argv[0]});
std::vector<std::string> args;
for (int i = 1; i < argc; ++i)
args.push_back(argv[i]);

if (!alg->ParseCommandLineArguments(args))
{
fprintf(stderr, "%s", alg->GetUsageForCLI(true).c_str());
CSLDestroy(argv);
return 1;
}

{
const auto stdoutArg = alg->GetActualAlgorithm().GetArg("stdout");
if (stdoutArg && stdoutArg->GetType() == GAAT_BOOLEAN)
stdoutArg->Set(true);
}

GDALProgressFunc pfnProgress =
alg->IsProgressBarRequested() ? GDALTermProgress : nullptr;
void *pProgressData = nullptr;

int ret = 0;
if (alg->Run(pfnProgress, pProgressData))
{
const auto outputArg =
alg->GetActualAlgorithm().GetArg("output-string");
if (outputArg && outputArg->GetType() == GAAT_STRING &&
outputArg->IsOutput())
{
printf("%s", outputArg->Get<std::string>().c_str());
}

if (!alg->Finalize())
ret = 1;
}
else
{
ret = 1;
}

CSLDestroy(argv);

return ret;
}

MAIN_END
31 changes: 31 additions & 0 deletions apps/gdal_translate_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,9 @@ struct GDALTranslateOptions
/*! overview level of source file to be used */
int nOvLevel = OVR_LEVEL_AUTO;

/*! set to true to prevent overwriting existing dataset */
bool bNoOverwrite = false;

GDALTranslateOptions() = default;
~GDALTranslateOptions();
GDALTranslateOptions *Clone() const;
Expand Down Expand Up @@ -1106,6 +1109,29 @@ GDALDatasetH GDALTranslate(const char *pszDest, GDALDatasetH hSrcDataset,
"@QUIET_DELETE_ON_CREATE_COPY", "NO");
}

if (psOptions->bNoOverwrite && !EQUAL(pszDest, ""))
{
VSIStatBufL sStat;
if (VSIStatL(pszDest, &sStat) == 0)
{
CPLError(CE_Failure, CPLE_AppDefined,
"File '%s' already exists. Specify the --overwrite "
"option to overwrite it.",
pszDest);
GDALTranslateOptionsFree(psOptions);
return nullptr;
}
else if (std::unique_ptr<GDALDataset>(GDALDataset::Open(pszDest)))
{
CPLError(CE_Failure, CPLE_AppDefined,
"Dataset '%s' already exists. Specify the --overwrite "
"option to overwrite it.",
pszDest);
GDALTranslateOptionsFree(psOptions);
return nullptr;
}
}

GDALDriver::FromHandle(hDriver)->QuietDeleteForCreateCopy(pszDest,
poSrcDS);

Expand Down Expand Up @@ -3127,6 +3153,11 @@ GDALTranslateOptionsGetParser(GDALTranslateOptions *psOptions,
.hidden()
.store_into(psOptions->nLimitOutSize);

// Undocumented option used by gdal raster convert
argParser->add_argument("--no-overwrite")
.store_into(psOptions->bNoOverwrite)
.hidden();

if (psOptionsForBinary)
{
argParser->add_argument("input_file")
Expand Down
59 changes: 59 additions & 0 deletions apps/gdalalg_convert.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/******************************************************************************
*
* Project: GDAL
* Purpose: gdal "convert" subcommand
* Author: Even Rouault <even dot rouault at spatialys.com>
*
******************************************************************************
* Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com>
*
* SPDX-License-Identifier: MIT
****************************************************************************/

#include "cpl_error.h"
#include "gdalalgorithm.h"
#include "gdalalg_raster_convert.h"
#include "gdalalg_vector_convert.h"
#include "gdalalg_dispatcher.h"
#include "gdal_priv.h"

/************************************************************************/
/* GDALConvertAlgorithm */
/************************************************************************/

class GDALConvertAlgorithm
: public GDALDispatcherAlgorithm<GDALRasterConvertAlgorithm,
GDALVectorConvertAlgorithm>
{
public:
static constexpr const char *NAME = "convert";
static constexpr const char *DESCRIPTION =
"Convert a dataset (shortcut for 'gdal raster convert' or "
"'gdal vector convert').";
static constexpr const char *HELP_URL = ""; // TODO

static std::vector<std::string> GetAliases()
{
return {};
}

GDALConvertAlgorithm()
: GDALDispatcherAlgorithm(NAME, DESCRIPTION, HELP_URL)
{
// only for the help message
AddProgressArg();
AddOutputFormatArg(&m_format);
AddInputDatasetArg(&m_inputDataset);
AddOutputDatasetArg(&m_outputDataset);

m_longDescription = "For all options, run 'gdal raster convert --help' "
"or 'gdal vector convert --help'";
}

private:
std::string m_format{};
GDALArgDatasetValue m_inputDataset{};
GDALArgDatasetValue m_outputDataset{};
};

GDAL_STATIC_REGISTER_ALG(GDALConvertAlgorithm);
Loading

0 comments on commit 0d17ede

Please sign in to comment.