Some notational convenience for formatting strings

We can now write

  throw Error("file '%s' not found", path);

instead of

  throw Error(format("file '%s' not found") % path);

and similarly

  printError("file '%s' not found", path);

instead of

  printMsg(lvlError, format("file '%s' not found") % path);
This commit is contained in:
Eelco Dolstra 2016-09-21 16:00:03 +02:00
parent 3f8e620b19
commit 4036185cb4
6 changed files with 81 additions and 22 deletions

View file

@ -3768,7 +3768,7 @@ void LocalStore::buildPaths(const PathSet & drvPaths, BuildMode buildMode)
}
if (!failed.empty())
throw Error(format("build of %1% failed") % showPaths(failed), worker.exitStatus());
throw Error(worker.exitStatus(), "build of %s failed",showPaths(failed));
}
@ -3804,7 +3804,7 @@ void LocalStore::ensurePath(const Path & path)
worker.run(goals);
if (goal->getExitCode() != Goal::ecSuccess)
throw Error(format("path %1% does not exist and cannot be created") % path, worker.exitStatus());
throw Error(worker.exitStatus(), "path %s does not exist and cannot be created", path);
}
@ -3825,7 +3825,7 @@ void LocalStore::repairPath(const Path & path)
goals.insert(worker.makeDerivationGoal(deriver, StringSet(), bmRepair));
worker.run(goals);
} else
throw Error(format("cannot repair path %1%") % path, worker.exitStatus());
throw Error(worker.exitStatus(), "cannot repair path %s", path);
}
}

View file

@ -564,7 +564,7 @@ void RemoteStore::Connection::processStderr(Sink * sink, Source * source)
if (msg == STDERR_ERROR) {
string error = readString(from);
unsigned int status = readInt(from);
throw Error(format("%1%") % error, status);
throw Error(status, error);
}
else if (msg != STDERR_LAST)
throw Error("protocol error processing standard error");

View file

@ -8,7 +8,7 @@
namespace nix {
MakeError(UsageError, nix::Error);
MakeError(UsageError, Error);
enum HashType : char;

View file

@ -66,14 +66,19 @@ Logger * makeDefaultLogger();
extern Verbosity verbosity; /* suppress msgs > this */
#define printMsg(level, f) \
/* Print a message if the current log level is at least the specified
level. Note that this has to be implemented as a macro to ensure
that the arguments are evaluated lazily. */
#define printMsg(level, args...) \
do { \
if (level <= nix::verbosity) { \
logger->log(level, (f)); \
logger->log(level, fmt(args)); \
} \
} while (0)
#define debug(f) printMsg(lvlDebug, f)
#define printError(args...) printMsg(lvlError, args)
#define printInfo(args...) printMsg(lvlInfo, args)
#define debug(args...) printMsg(lvlDebug, args)
void warnOnce(bool & haveWarned, const FormatOrString & fs);

View file

@ -41,6 +41,45 @@ struct FormatOrString
};
/* A helper for formatting strings. fmt(format, a_0, ..., a_n) is
equivalent to boost::format(format) % a_0 % ... %
... a_n. However, fmt(s) is equivalent to s (so no %-expansion
takes place). */
inline void formatHelper(boost::format & f)
{
}
template<typename T, typename... Args>
inline void formatHelper(boost::format & f, T x, Args... args)
{
formatHelper(f % x, args...);
}
inline std::string fmt(const std::string & s)
{
return s;
}
inline std::string fmt(const char * s)
{
return s;
}
inline std::string fmt(const FormatOrString & fs)
{
return fs.s;
}
template<typename... Args>
inline std::string fmt(const std::string & fs, Args... args)
{
boost::format f(fs);
formatHelper(f, args...);
return f.str();
}
/* BaseError should generally not be caught, as it has Interrupted as
a subclass. Catch Error instead. */
class BaseError : public std::exception
@ -49,14 +88,28 @@ protected:
string prefix_; // used for location traces etc.
string err;
public:
unsigned int status; // exit status
BaseError(const FormatOrString & fs, unsigned int status = 1);
unsigned int status = 1; // exit status
template<typename... Args>
BaseError(unsigned int status, Args... args)
: err(fmt(args...))
, status(status)
{
}
template<typename... Args>
BaseError(Args... args)
: err(fmt(args...))
{
}
#ifdef EXCEPTION_NEEDS_THROW_SPEC
~BaseError() throw () { };
const char * what() const throw () { return err.c_str(); }
#else
const char * what() const noexcept { return err.c_str(); }
#endif
const string & msg() const { return err; }
const string & prefix() const { return prefix_; }
BaseError & addPrefix(const FormatOrString & fs);
@ -66,7 +119,7 @@ public:
class newClass : public superClass \
{ \
public: \
newClass(const FormatOrString & fs, unsigned int status = 1) : superClass(fs, status) { }; \
using superClass::superClass; \
};
MakeError(Error, BaseError)
@ -75,7 +128,15 @@ class SysError : public Error
{
public:
int errNo;
SysError(const FormatOrString & fs);
template<typename... Args>
SysError(Args... args)
: Error(addErrno(fmt(args...)))
{ }
private:
std::string addErrno(const std::string & s);
};

View file

@ -31,13 +31,6 @@ extern char * * environ;
namespace nix {
BaseError::BaseError(const FormatOrString & fs, unsigned int status)
: status(status)
{
err = fs.s;
}
BaseError & BaseError::addPrefix(const FormatOrString & fs)
{
prefix_ = fs.s + prefix_;
@ -45,10 +38,10 @@ BaseError & BaseError::addPrefix(const FormatOrString & fs)
}
SysError::SysError(const FormatOrString & fs)
: Error(format("%1%: %2%") % fs.s % strerror(errno))
, errNo(errno)
std::string SysError::addErrno(const std::string & s)
{
errNo = errno;
return s + ": " + strerror(errNo);
}