Skip to content

Commit

Permalink
SDF.cc update calls to use sdf::Errors output (#1295)
Browse files Browse the repository at this point in the history
Adds missing sdf::Errors structure as an option to report errors on SDF. Makes sure that no errors are printed and all are reported through the structure when using the functions that include it as parameter.
---------

Signed-off-by: Marco A. Gutierrez <marco@openrobotics.org>
Signed-off-by: Steve Peters <scpeters@openrobotics.org>
Co-authored-by: Marco A. Gutierrez <marco@openrobotics.org>
Co-authored-by: Steve Peters <scpeters@openrobotics.org>
Co-authored-by: Addisu Z. Taddese <addisu@openrobotics.org>
  • Loading branch information
4 people authored Jun 26, 2024
1 parent 023cf4e commit 4053695
Show file tree
Hide file tree
Showing 3 changed files with 244 additions and 14 deletions.
94 changes: 94 additions & 0 deletions include/sdf/SDFImpl.hh
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,34 @@ namespace sdf
bool _searchLocalPath = true,
bool _useCallback = false);

/// \brief Find the absolute path of a file.
///
/// The search order in the function is as follows:
/// 1. Using the global URI path map, search in paths associated with the URI
/// scheme of the input.
/// 2. Seach in the path defined by the macro `SDF_SHARE_PATH`.
/// 3. Search in the the libsdformat install path. The path is formed by
/// has the pattern `SDF_SHARE_PATH/sdformat<major version>/<version>/`
/// 4. Directly check if the input path exists in the filesystem.
/// 5. Seach in the path defined by the environment variable `SDF_PATH`.
/// 6. If enabled via _searchLocalPath, prepend the input with the current
/// working directory and check if the result path exists.
/// 7. If enabled via _useCallback and the global callback function is set,
/// invoke the function and return its result.
///
/// \param[out] _errors Vector of errors.
/// \param[in] _filename Name of the file to find.
/// \param[in] _searchLocalPath True to search for the file in the current
/// working directory.
/// \param[in] _useCallback True to find a file based on a registered
/// callback if the file is not found via the normal mechanism.
/// \return File's full path.
SDFORMAT_VISIBLE
std::string findFile(sdf::Errors &_errors,
const std::string &_filename,
bool _searchLocalPath = true,
bool _useCallback = false);

/// \brief Find the absolute path of a file.
///
/// This overload uses the URI path map and and the callback function
Expand All @@ -99,6 +127,26 @@ namespace sdf
bool _useCallback,
const ParserConfig &_config);

/// \brief Find the absolute path of a file.
///
/// This overload uses the URI path map and and the callback function
/// configured in the input ParserConfig object instead of their global
/// counterparts.
///
/// \param[out] _errors Vector of errors.
/// \param[in] _filename Name of the file to find.
/// \param[in] _searchLocalPath True to search for the file in the current
/// working directory.
/// \param[in] _useCallback True to find a file based on a registered
/// callback if the file is not found via the normal mechanism.
/// \param[in] _config Custom parser configuration.
/// \return File's full path.
SDFORMAT_VISIBLE
std::string findFile(sdf::Errors &_errors,
const std::string &_filename,
bool _searchLocalPath,
bool _useCallback,
const ParserConfig &_config);

/// \brief Associate paths to a URI.
/// Example paramters: "model://", "/usr/share/models:~/.gazebo/models"
Expand All @@ -121,22 +169,45 @@ namespace sdf
/// \brief Destructor
public: ~SDF();
public: void PrintDescription();
public: void PrintDescription(sdf::Errors &_errors);
public: void PrintDoc();
public: void Write(const std::string &_filename);
public: void Write(sdf::Errors &_errors, const std::string &_filename);

/// \brief Output SDF's values to stdout.
/// \param[in] _config Configuration for printing the values.
public: void PrintValues(const PrintConfig &_config = PrintConfig());

/// \brief Output SDF's values to stdout.
/// \param[out] _errors Vector of errrors.
/// \param[in] _config Configuration for printing the values.
public: void PrintValues(sdf::Errors &_errors,
const PrintConfig &_config = PrintConfig());

/// \brief Convert the SDF values to a string representation.
/// \param[in] _config Configuration for printing the values.
/// \return The string representation.
public: std::string ToString(
const PrintConfig &_config = PrintConfig()) const;

/// \brief Convert the SDF values to a string representation.
/// \param[out] _errors Vector of errors.
/// \param[in] _config Configuration for printing the values.
/// \return The string representation.
public: std::string ToString(
sdf::Errors &_errors,
const PrintConfig &_config = PrintConfig()) const;

/// \brief Set SDF values from a string
/// \param[in] sdfData String with the values to load.
public: void SetFromString(const std::string &_sdfData);

/// \brief Set SDF values from a string
/// \param[out] _errors Vector of errors.
/// \param[in] sdfData String with the values to load.
public: void SetFromString(sdf::Errors &_Errors,
const std::string &_sdfData);

/// \brief Clear the data in this object.
public: void Clear();

Expand Down Expand Up @@ -182,6 +253,13 @@ namespace sdf
/// \return a wrapped clone of the SDF element
public: static ElementPtr WrapInRoot(const ElementPtr &_sdf);

/// \brief wraps the SDF element into a root element with the version info.
/// \param[out] _errors Vector of errors.
/// \param[in] _sdf the sdf element. Will be cloned by this function.
/// \return a wrapped clone of the SDF element
public: static ElementPtr WrapInRoot(sdf::Errors &_errors,
const ElementPtr &_sdf);

/// \brief Get a string representation of an SDF specification file.
/// This function uses a built-in version of a .sdf file located in
/// the sdf directory. The parser.cc code uses this function, which avoids
Expand All @@ -198,6 +276,22 @@ namespace sdf
public: static const std::string &EmbeddedSpec(
const std::string &_filename, const bool _quiet);

/// \brief Get a string representation of an SDF specification file.
/// This function uses a built-in version of a .sdf file located in
/// the sdf directory. The parser.cc code uses this function, which avoids
/// touching the filesystem.
///
/// Most people should not use this function.
///
/// \param[out] _errors Vector of errors.
/// \param[in] _filename Base name of the SDF specification file to
/// load. For example "root.sdf" or "world.sdf".
/// \return A string that contains the contents of the specified
/// _filename. An empty string is returned if the _filename could not be
/// found.
public: static const std::string &EmbeddedSpec(
sdf::Errors &_errors, const std::string &_filename);

/// \internal
/// \brief Pointer to private data.
private: std::unique_ptr<SDFPrivate> dataPtr;
Expand Down
124 changes: 110 additions & 14 deletions src/SDF.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
#include "sdf/parser.hh"
#include "sdf/Assert.hh"
#include "sdf/Console.hh"
#include "sdf/Error.hh"
#include "sdf/Filesystem.hh"
#include "sdf/SDFImpl.hh"
#include "SDFImplPrivate.hh"
#include "sdf/sdf_config.h"
#include "EmbeddedSdf.hh"
#include "Utils.hh"

#include <gz/utils/Environment.hh>

Expand Down Expand Up @@ -61,14 +63,40 @@ void setFindCallback(std::function<std::string(const std::string &)> _cb)
/////////////////////////////////////////////////
std::string findFile(
const std::string &_filename, bool _searchLocalPath, bool _useCallback)
{
sdf::Errors errors;
std::string result = findFile(errors, _filename, _searchLocalPath,
_useCallback, ParserConfig::GlobalConfig());
sdf::throwOrPrintErrors(errors);
return result;
}

/////////////////////////////////////////////////
std::string findFile(
sdf::Errors &_errors, const std::string &_filename, bool _searchLocalPath,
bool _useCallback)
{
return findFile(
_filename, _searchLocalPath, _useCallback, ParserConfig::GlobalConfig());
_errors, _filename, _searchLocalPath,
_useCallback, ParserConfig::GlobalConfig());
}

/////////////////////////////////////////////////
std::string findFile(const std::string &_filename, bool _searchLocalPath,
bool _useCallback, const ParserConfig &_config)
{
sdf::Errors errors;
std::string result = findFile(errors, _filename, _searchLocalPath,
_useCallback, _config);
sdf::throwOrPrintErrors(errors);
return result;
}


/////////////////////////////////////////////////
std::string findFile(sdf::Errors &_errors, const std::string &_filename,
bool _searchLocalPath, bool _useCallback,
const ParserConfig &_config)
{
// Check to see if _filename is URI. If so, resolve the URI path.
for (const auto &[uriScheme, paths] : _config.URIPathMap())
Expand Down Expand Up @@ -162,8 +190,9 @@ std::string findFile(const std::string &_filename, bool _searchLocalPath,
{
if (!_config.FindFileCallback())
{
sdferr << "Tried to use callback in sdf::findFile(), but the callback "
"is empty. Did you call sdf::setFindCallback()?\n";
_errors.push_back({sdf::ErrorCode::FILE_READ,
"Tried to use callback in sdf::findFile(), but the callback "
"is empty. Did you call sdf::setFindCallback()?"});
return std::string();
}
else
Expand Down Expand Up @@ -195,13 +224,29 @@ SDF::~SDF()
/////////////////////////////////////////////////
void SDF::PrintDescription()
{
this->Root()->PrintDescription("");
sdf::Errors errors;
this->PrintDescription(errors);
sdf::throwOrPrintErrors(errors);
}

/////////////////////////////////////////////////
void SDF::PrintDescription(sdf::Errors &_errors)
{
this->Root()->PrintDescription(_errors, "");
}

/////////////////////////////////////////////////
void SDF::PrintValues(const PrintConfig &_config)
{
this->Root()->PrintValues("", _config);
sdf::Errors errors;
this->PrintValues(errors, _config);
sdf::throwOrPrintErrors(errors);
}

/////////////////////////////////////////////////
void SDF::PrintValues(sdf::Errors &_errors, const PrintConfig &_config)
{
this->Root()->PrintValues(_errors, "", _config);
}

/////////////////////////////////////////////////
Expand Down Expand Up @@ -319,13 +364,22 @@ void SDF::PrintDoc()
/////////////////////////////////////////////////
void SDF::Write(const std::string &_filename)
{
std::string string = this->Root()->ToString("");
sdf::Errors errors;
this->Write(errors, _filename);
sdf::throwOrPrintErrors(errors);
}

/////////////////////////////////////////////////
void SDF::Write(sdf::Errors &_errors, const std::string &_filename)
{
std::string string = this->Root()->ToString(_errors, "");

std::ofstream out(_filename.c_str(), std::ios::out);

if (!out)
{
sdferr << "Unable to open file[" << _filename << "] for writing\n";
_errors.push_back({sdf::ErrorCode::FILE_READ,
"Unable to open file[" + _filename + "] for writing."});
return;
}
out << string;
Expand All @@ -334,6 +388,16 @@ void SDF::Write(const std::string &_filename)

/////////////////////////////////////////////////
std::string SDF::ToString(const PrintConfig &_config) const
{
sdf::Errors errors;
std::string result = this->ToString(errors, _config);
sdf::throwOrPrintErrors(errors);
return result;
}

/////////////////////////////////////////////////
std::string SDF::ToString(sdf::Errors &_errors,
const PrintConfig &_config) const
{
std::ostringstream stream;

Expand All @@ -343,7 +407,7 @@ std::string SDF::ToString(const PrintConfig &_config) const
stream << "<sdf version='" << SDF::Version() << "'>\n";
}

stream << this->Root()->ToString("", _config);
stream << this->Root()->ToString(_errors, "", _config);

if (this->Root()->GetName() != "sdf")
{
Expand All @@ -355,11 +419,21 @@ std::string SDF::ToString(const PrintConfig &_config) const

/////////////////////////////////////////////////
void SDF::SetFromString(const std::string &_sdfData)
{
sdf::Errors errors;
this->SetFromString(errors, _sdfData);
sdf::throwOrPrintErrors(errors);
}

/////////////////////////////////////////////////
void SDF::SetFromString(sdf::Errors &_errors,
const std::string &_sdfData)
{
sdf::initFile("root.sdf", this->Root());
if (!sdf::readString(_sdfData, this->Root()))
if (!sdf::readString(_sdfData, this->Root(), _errors))
{
sdferr << "Unable to parse sdf string[" << _sdfData << "]\n";
_errors.push_back({sdf::ErrorCode::PARSING_ERROR,
"Unable to parse sdf string[" + _sdfData + "]"});
}
}

Expand Down Expand Up @@ -429,19 +503,41 @@ void SDF::Version(const std::string &_version)

/////////////////////////////////////////////////
ElementPtr SDF::WrapInRoot(const ElementPtr &_sdf)
{
sdf::Errors errors;
ElementPtr result = SDF::WrapInRoot(errors, _sdf);
sdf::throwOrPrintErrors(errors);
return result;
}

/////////////////////////////////////////////////
ElementPtr SDF::WrapInRoot(sdf::Errors &_errors, const ElementPtr &_sdf)
{
ElementPtr root(new Element);
root->SetName("sdf");
std::stringstream v;
v << Version();
root->AddAttribute("version", "string", v.str(), true, "version");
root->AddAttribute("version", "string", v.str(), true, _errors, "version");
root->InsertElement(_sdf->Clone());
return root;
}

/////////////////////////////////////////////////
const std::string &SDF::EmbeddedSpec(
const std::string &_filename, const bool _quiet)
{
sdf::Errors errors;
const std::string &result = EmbeddedSpec(errors, _filename);
if (!_quiet)
{
sdf::throwOrPrintErrors(errors);
}
return result;
}

/////////////////////////////////////////////////
const std::string &SDF::EmbeddedSpec(
sdf::Errors &_errors, const std::string &_filename)
{
try
{
Expand All @@ -450,9 +546,9 @@ const std::string &SDF::EmbeddedSpec(
}
catch(const std::out_of_range &)
{
if (!_quiet)
sdferr << "Unable to find SDF filename[" << _filename << "] with "
<< "version " << SDF::Version() << "\n";
_errors.push_back({sdf::ErrorCode::FILE_READ,
"Unable to find SDF filename[" + _filename + "] with " +
"version " + SDF::Version()});
}

// An empty SDF string is returned if a query into the embeddedSdf map fails.
Expand Down
Loading

0 comments on commit 4053695

Please sign in to comment.