Skip to content

Commit eeb8c77

Browse files
authored
Merge pull request OSGeo#12809 from rouault/fix_12806
gdal raster index: emit error if using --dst-crs and non existing input dataset
2 parents ce10b20 + ada4a65 commit eeb8c77

File tree

6 files changed

+149
-27
lines changed

6 files changed

+149
-27
lines changed

apps/gdalalg_raster_index.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ void GDALRasterIndexAlgorithm::AddCommonOptions()
105105
{ return ParseAndValidateKeyValue(arg); });
106106
arg.AddHiddenAlias("mo");
107107
}
108+
109+
AddArg("skip-errors", 0, _("Skip errors related to input datasets"),
110+
&m_skipErrors);
108111
}
109112

110113
/************************************************************************/
@@ -135,6 +138,12 @@ bool GDALRasterIndexAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
135138
return false;
136139

137140
CPLStringList aosOptions;
141+
aosOptions.push_back("--invoked-from-gdal-raster-index");
142+
143+
if (m_skipErrors)
144+
{
145+
aosOptions.push_back("-skip_errors");
146+
}
138147
if (m_recursive)
139148
{
140149
aosOptions.push_back("-recursive");

apps/gdalalg_raster_index.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ class CPL_DLL GDALRasterIndexAlgorithm /* non final */
6161
std::string m_sourceCrsName{};
6262
std::string m_sourceCrsFormat = "auto";
6363
std::vector<std::string> m_metadata{};
64+
bool m_skipErrors = false;
6465
};
6566

6667
//! @endcond

apps/gdaltindex_lib.cpp

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ struct GDALTileIndexRasterMetadata
5656

5757
struct GDALTileIndexOptions
5858
{
59+
bool bInvokedFromGdalRasterIndex = false;
5960
bool bOverwrite = false;
61+
bool bSkipErrors = false;
6062
std::string osFormat{};
6163
std::string osIndexLayerName{};
6264
std::string osLocationField = "location";
@@ -106,6 +108,16 @@ static std::unique_ptr<GDALArgumentParser> GDALTileIndexAppOptionsGetParser(
106108
_("For more details, see the full documentation for gdaltindex at\n"
107109
"https://gdal.org/programs/gdaltindex.html"));
108110

111+
// Hidden as used by gdal raster index
112+
argParser->add_argument("--invoked-from-gdal-raster-index")
113+
.store_into(psOptions->bInvokedFromGdalRasterIndex)
114+
.hidden();
115+
116+
// Hidden as used by gdal raster index
117+
argParser->add_argument("-skip_errors")
118+
.store_into(psOptions->bSkipErrors)
119+
.hidden();
120+
109121
argParser->add_argument("-overwrite")
110122
.flag()
111123
.store_into(psOptions->bOverwrite)
@@ -605,6 +617,10 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest,
605617
: nullptr;
606618
const int nMaxFieldSize = pszVal ? atoi(pszVal) : 0;
607619

620+
const bool bFailOnErrors =
621+
psOptions->bInvokedFromGdalRasterIndex && !psOptions->bSkipErrors;
622+
bool bSkipFirstTile = false;
623+
608624
if (poLayer)
609625
{
610626
bExistingLayer = true;
@@ -665,15 +681,30 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest,
665681
return nullptr;
666682
}
667683
oGDALTileIndexTileIterator.reset();
684+
std::unique_ptr<CPLTurnFailureIntoWarningBackuper>
685+
poFailureIntoWarning;
686+
if (!bFailOnErrors)
687+
poFailureIntoWarning =
688+
std::make_unique<CPLTurnFailureIntoWarningBackuper>();
689+
CPL_IGNORE_RET_VAL(poFailureIntoWarning);
668690
auto poSrcDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
669691
osFilename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
670692
nullptr, nullptr, nullptr));
671693
if (!poSrcDS)
672-
return nullptr;
673-
674-
auto poSrcSRS = poSrcDS->GetSpatialRef();
675-
if (poSrcSRS)
676-
oSRS = *poSrcSRS;
694+
{
695+
CPLError(bFailOnErrors ? CE_Failure : CE_Warning,
696+
CPLE_AppDefined, "Unable to open %s%s.",
697+
osFilename.c_str(), bFailOnErrors ? "" : ", skipping");
698+
if (bFailOnErrors)
699+
return nullptr;
700+
bSkipFirstTile = true;
701+
}
702+
else
703+
{
704+
auto poSrcSRS = poSrcDS->GetSpatialRef();
705+
if (poSrcSRS)
706+
oSRS = *poSrcSRS;
707+
}
677708
}
678709

679710
poLayer = poTileIndexDS->CreateLayer(
@@ -964,6 +995,11 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest,
964995
const std::string osSrcFilename = oGDALTileIndexTileIterator.next();
965996
if (osSrcFilename.empty())
966997
break;
998+
if (bSkipFirstTile)
999+
{
1000+
bSkipFirstTile = false;
1001+
continue;
1002+
}
9671003

9681004
std::string osFileNameToWrite;
9691005
VSIStatBuf sStatBuf;
@@ -991,23 +1027,39 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest,
9911027
continue;
9921028
}
9931029

994-
auto poSrcDS = std::unique_ptr<GDALDataset>(GDALDataset::Open(
995-
osSrcFilename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
996-
nullptr, nullptr, nullptr));
997-
if (poSrcDS == nullptr)
1030+
std::unique_ptr<GDALDataset> poSrcDS;
9981031
{
999-
CPLError(CE_Warning, CPLE_AppDefined,
1000-
"Unable to open %s, skipping.", osSrcFilename.c_str());
1001-
continue;
1032+
std::unique_ptr<CPLTurnFailureIntoWarningBackuper>
1033+
poFailureIntoWarning;
1034+
if (!bFailOnErrors)
1035+
poFailureIntoWarning =
1036+
std::make_unique<CPLTurnFailureIntoWarningBackuper>();
1037+
CPL_IGNORE_RET_VAL(poFailureIntoWarning);
1038+
1039+
poSrcDS.reset(GDALDataset::Open(
1040+
osSrcFilename.c_str(), GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
1041+
nullptr, nullptr, nullptr));
1042+
if (poSrcDS == nullptr)
1043+
{
1044+
CPLError(bFailOnErrors ? CE_Failure : CE_Warning,
1045+
CPLE_AppDefined, "Unable to open %s%s.",
1046+
osSrcFilename.c_str(),
1047+
bFailOnErrors ? "" : ", skipping");
1048+
if (bFailOnErrors)
1049+
return nullptr;
1050+
continue;
1051+
}
10021052
}
10031053

10041054
GDALGeoTransform gt;
10051055
if (poSrcDS->GetGeoTransform(gt) != CE_None)
10061056
{
1007-
CPLError(CE_Warning, CPLE_AppDefined,
1057+
CPLError(bFailOnErrors ? CE_Failure : CE_Warning, CPLE_AppDefined,
10081058
"It appears no georeferencing is available for\n"
1009-
"`%s', skipping.",
1010-
osSrcFilename.c_str());
1059+
"`%s'%s.",
1060+
osSrcFilename.c_str(), bFailOnErrors ? "" : ", skipping");
1061+
if (bFailOnErrors)
1062+
return nullptr;
10111063
continue;
10121064
}
10131065

@@ -1049,9 +1101,11 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest,
10491101
const int nYSize = poSrcDS->GetRasterYSize();
10501102
if (nXSize == 0 || nYSize == 0)
10511103
{
1052-
CPLError(CE_Warning, CPLE_AppDefined,
1053-
"%s has 0 width or height. Skipping",
1054-
osSrcFilename.c_str());
1104+
CPLError(bFailOnErrors ? CE_Failure : CE_Warning, CPLE_AppDefined,
1105+
"%s has 0 width or height%s", osSrcFilename.c_str(),
1106+
bFailOnErrors ? "" : ", skipping");
1107+
if (bFailOnErrors)
1108+
return nullptr;
10551109
continue;
10561110
}
10571111

@@ -1081,13 +1135,16 @@ GDALDatasetH GDALTileIndexInternal(const char *pszDest,
10811135
OGRCreateCoordinateTransformation(poSrcSRS, &oTargetSRS));
10821136
if (!poCT || !poCT->Transform(5, adfX, adfY, nullptr))
10831137
{
1084-
CPLError(CE_Warning, CPLE_AppDefined,
1138+
CPLError(bFailOnErrors ? CE_Failure : CE_Warning,
1139+
CPLE_AppDefined,
10851140
"unable to transform points from source "
1086-
"SRS `%s' to target SRS `%s' for file `%s' - file "
1087-
"skipped",
1141+
"SRS `%s' to target SRS `%s' for file `%s'%s",
10881142
poSrcDS->GetProjectionRef(),
10891143
psOptions->osTargetSRS.c_str(),
1090-
osFileNameToWrite.c_str());
1144+
osFileNameToWrite.c_str(),
1145+
bFailOnErrors ? "" : ", skipping");
1146+
if (bFailOnErrors)
1147+
return nullptr;
10911148
continue;
10921149
}
10931150
}

autotest/pymod/gdaltest.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,7 +2124,6 @@ def error_raised(type, match=""):
21242124
gdal.CE_Debug: "CE_Debug",
21252125
gdal.CE_Failure: "CE_Failure",
21262126
gdal.CE_Fatal: "CE_Fatal",
2127-
gdal.CE_None: "CE_None",
21282127
gdal.CE_Warning: "CE_Warning",
21292128
}
21302129

@@ -2136,9 +2135,12 @@ def handler(lvl, no, msg):
21362135
with error_handler(handler):
21372136
yield
21382137

2139-
assert any(
2140-
[err["level"] == type and match in err["message"] for err in errors]
2141-
), f'Did not receive an error of type {err_levels[type]} matching "{match}". Received: {[(err["level"], err["message"]) for err in errors]}'
2138+
if type == gdal.CE_None:
2139+
assert not any([err["level"] != gdal.CE_Debug for err in errors])
2140+
else:
2141+
assert any(
2142+
[err["level"] == type and match in err["message"] for err in errors]
2143+
), f'Did not receive an error of type {err_levels[type]} matching "{match}". Received: {[(err["level"], err["message"]) for err in errors]}'
21422144

21432145

21442146
###############################################################################

autotest/utilities/test_gdalalg_raster_index.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import os
1515

16+
import gdaltest
1617
import pytest
1718

1819
from osgeo import gdal, ogr
@@ -204,7 +205,10 @@ def test_gdalalg_raster_index_min_pixel_size(min_pixel_size, expected_count):
204205
alg["output-format"] = "MEM"
205206
alg["layer"] = "out"
206207
alg["min-pixel-size"] = min_pixel_size
207-
assert alg.Run()
208+
with gdaltest.error_raised(
209+
gdal.CE_Warning if min_pixel_size == 61 else gdal.CE_None
210+
):
211+
assert alg.Run()
208212
ds = alg["output"].GetDataset()
209213
lyr = ds.GetLayer(0)
210214
assert lyr.GetFeatureCount() == expected_count
@@ -229,3 +233,46 @@ def test_gdalalg_raster_index_crs():
229233
f.GetGeometryRef().ExportToWkt()
230234
== "POLYGON ((-117.641168620797 33.9023526904272,-117.628190189534 33.9024195619211,-117.628110837847 33.8915970129623,-117.641087629972 33.8915301685907,-117.641168620797 33.9023526904272))"
231235
)
236+
237+
238+
def test_gdalalg_raster_error():
239+
240+
alg = get_alg()
241+
alg["input"] = "/i/do/not/exist"
242+
alg["output"] = ""
243+
alg["output-format"] = "MEM"
244+
alg["layer"] = "out"
245+
alg["dst-crs"] = "EPSG:4267"
246+
with pytest.raises(Exception, match="Unable to open /i/do/not/exist"):
247+
alg.Run()
248+
249+
250+
def test_gdalalg_raster_skip_errors_with_crs():
251+
252+
alg = get_alg()
253+
alg["input"] = "/i/do/not/exist"
254+
alg["output"] = ""
255+
alg["output-format"] = "MEM"
256+
alg["layer"] = "out"
257+
alg["dst-crs"] = "EPSG:4267"
258+
alg["skip-errors"] = True
259+
with gdaltest.error_raised(gdal.CE_Warning):
260+
assert alg.Run()
261+
ds = alg["output"].GetDataset()
262+
lyr = ds.GetLayer(0)
263+
assert lyr.GetFeatureCount() == 0
264+
265+
266+
def test_gdalalg_raster_skip_errors_without_crs():
267+
268+
alg = get_alg()
269+
alg["input"] = "/i/do/not/exist"
270+
alg["output"] = ""
271+
alg["output-format"] = "MEM"
272+
alg["layer"] = "out"
273+
alg["skip-errors"] = True
274+
with gdaltest.error_raised(gdal.CE_Warning):
275+
assert alg.Run()
276+
ds = alg["output"].GetDataset()
277+
lyr = ds.GetLayer(0)
278+
assert lyr.GetFeatureCount() == 0

doc/source/programs/gdal_raster_index.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ Standard options
123123
metadata.
124124
This option may be repeated.
125125

126+
.. option:: --skip-errors
127+
128+
.. versionadded:: 3.12
129+
130+
Skip errors related to input datasets.
131+
126132
Examples
127133
--------
128134

0 commit comments

Comments
 (0)