2020-04-26 23:47:41 +03:00
|
|
|
#pragma once
|
2020-03-22 20:25:47 +02:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
#include "ref.hh"
|
2020-04-03 17:48:20 +03:00
|
|
|
#include "types.hh"
|
2020-07-07 15:37:47 +03:00
|
|
|
#include "fmt.hh"
|
2020-03-27 18:55:09 +02:00
|
|
|
|
2020-06-16 02:35:07 +03:00
|
|
|
#include <cstring>
|
2020-04-26 23:47:41 +03:00
|
|
|
#include <list>
|
|
|
|
#include <memory>
|
|
|
|
#include <map>
|
|
|
|
#include <optional>
|
2020-03-22 20:25:47 +02:00
|
|
|
|
2020-07-07 15:37:47 +03:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2020-03-22 20:25:47 +02:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
/* Before 4.7, gcc's std::exception uses empty throw() specifiers for
|
|
|
|
* its (virtual) destructor and what() in c++11 mode, in violation of spec
|
|
|
|
*/
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
|
|
|
|
#define EXCEPTION_NEEDS_THROW_SPEC
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace nix {
|
|
|
|
|
2020-06-15 15:06:58 +03:00
|
|
|
/*
|
2020-06-04 20:53:19 +03:00
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
This file defines two main structs/classes used in nix error handling.
|
2020-06-04 20:53:19 +03:00
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
ErrorInfo provides a standard payload of error information, with conversion to string
|
|
|
|
happening in the logger rather than at the call site.
|
2020-06-04 20:53:19 +03:00
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains
|
|
|
|
an ErrorInfo.
|
2020-06-04 20:53:19 +03:00
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
ErrorInfo structs are sent to the logger as part of an exception, or directly with the
|
|
|
|
logError or logWarning macros.
|
2020-03-24 19:21:35 +02:00
|
|
|
|
2020-11-11 18:21:26 +02:00
|
|
|
See libutil/tests/logging.cc for usage examples.
|
2020-06-04 20:53:19 +03:00
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
*/
|
2020-06-04 20:53:19 +03:00
|
|
|
|
2020-04-29 06:06:08 +03:00
|
|
|
typedef enum {
|
2020-04-26 23:47:41 +03:00
|
|
|
lvlError = 0,
|
|
|
|
lvlWarn,
|
2020-11-27 12:19:36 +02:00
|
|
|
lvlNotice,
|
2020-04-26 23:47:41 +03:00
|
|
|
lvlInfo,
|
|
|
|
lvlTalkative,
|
|
|
|
lvlChatty,
|
|
|
|
lvlDebug,
|
|
|
|
lvlVomit
|
|
|
|
} Verbosity;
|
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
typedef enum {
|
2020-05-21 07:18:26 +03:00
|
|
|
foFile,
|
|
|
|
foStdin,
|
|
|
|
foString
|
|
|
|
} FileOrigin;
|
|
|
|
|
2020-06-24 17:33:53 +03:00
|
|
|
// the lines of code surrounding an error.
|
|
|
|
struct LinesOfCode {
|
|
|
|
std::optional<string> prevLineOfCode;
|
|
|
|
std::optional<string> errLineOfCode;
|
|
|
|
std::optional<string> nextLineOfCode;
|
|
|
|
};
|
|
|
|
|
2020-06-04 20:53:19 +03:00
|
|
|
// ErrPos indicates the location of an error in a nix file.
|
2020-04-29 06:06:08 +03:00
|
|
|
struct ErrPos {
|
2020-05-09 03:18:28 +03:00
|
|
|
int line = 0;
|
|
|
|
int column = 0;
|
2020-04-26 23:47:41 +03:00
|
|
|
string file;
|
2020-05-21 07:18:26 +03:00
|
|
|
FileOrigin origin;
|
2020-04-26 23:47:41 +03:00
|
|
|
|
2020-05-09 03:18:28 +03:00
|
|
|
operator bool() const
|
|
|
|
{
|
|
|
|
return line != 0;
|
|
|
|
}
|
|
|
|
|
2020-06-04 20:53:19 +03:00
|
|
|
// convert from the Pos struct, found in libexpr.
|
2020-04-08 18:07:58 +03:00
|
|
|
template <class P>
|
|
|
|
ErrPos& operator=(const P &pos)
|
|
|
|
{
|
2020-05-21 07:18:26 +03:00
|
|
|
origin = pos.origin;
|
2020-04-26 23:47:41 +03:00
|
|
|
line = pos.line;
|
2020-04-08 18:07:58 +03:00
|
|
|
column = pos.column;
|
2020-06-30 20:00:51 +03:00
|
|
|
// is file symbol null?
|
|
|
|
if (pos.file.set())
|
|
|
|
file = pos.file;
|
|
|
|
else
|
|
|
|
file = "";
|
2020-04-08 18:07:58 +03:00
|
|
|
return *this;
|
|
|
|
}
|
2020-04-08 18:48:21 +03:00
|
|
|
|
|
|
|
template <class P>
|
|
|
|
ErrPos(const P &p)
|
|
|
|
{
|
2020-04-28 00:15:08 +03:00
|
|
|
*this = p;
|
2020-04-08 18:48:21 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-06-19 00:25:26 +03:00
|
|
|
struct Trace {
|
2020-06-19 22:44:08 +03:00
|
|
|
std::optional<ErrPos> pos;
|
2020-06-19 00:25:26 +03:00
|
|
|
hintformat hint;
|
2020-03-24 19:21:35 +02:00
|
|
|
};
|
|
|
|
|
2020-04-29 06:06:08 +03:00
|
|
|
struct ErrorInfo {
|
2020-04-26 23:47:41 +03:00
|
|
|
Verbosity level;
|
2021-01-21 01:27:36 +02:00
|
|
|
string name; // FIXME: rename
|
|
|
|
hintformat msg;
|
2020-06-24 00:30:13 +03:00
|
|
|
std::optional<ErrPos> errPos;
|
2020-06-19 00:25:26 +03:00
|
|
|
std::list<Trace> traces;
|
2020-03-24 19:21:35 +02:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
static std::optional<string> programName;
|
2020-04-07 04:43:22 +03:00
|
|
|
};
|
2020-03-24 19:21:35 +02:00
|
|
|
|
2020-06-27 21:19:31 +03:00
|
|
|
std::ostream& showErrorInfo(std::ostream &out, const ErrorInfo &einfo, bool showTrace);
|
2020-03-24 19:21:35 +02:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
/* BaseError should generally not be caught, as it has Interrupted as
|
|
|
|
a subclass. Catch Error instead. */
|
|
|
|
class BaseError : public std::exception
|
2020-04-07 04:43:22 +03:00
|
|
|
{
|
2020-04-26 23:47:41 +03:00
|
|
|
protected:
|
2020-05-08 01:43:36 +03:00
|
|
|
mutable ErrorInfo err;
|
2020-04-30 03:57:05 +03:00
|
|
|
|
2020-05-08 01:43:36 +03:00
|
|
|
mutable std::optional<string> what_;
|
2020-05-14 21:28:18 +03:00
|
|
|
const string& calcWhat() const;
|
2020-06-15 15:06:58 +03:00
|
|
|
|
2020-04-07 04:43:22 +03:00
|
|
|
public:
|
2020-04-26 23:47:41 +03:00
|
|
|
unsigned int status = 1; // exit status
|
|
|
|
|
|
|
|
template<typename... Args>
|
|
|
|
BaseError(unsigned int status, const Args & ... args)
|
2021-01-21 01:27:36 +02:00
|
|
|
: err { .level = lvlError, .msg = hintfmt(args...) }
|
2020-04-26 23:47:41 +03:00
|
|
|
, status(status)
|
2020-04-30 03:57:05 +03:00
|
|
|
{ }
|
2020-04-26 23:47:41 +03:00
|
|
|
|
|
|
|
template<typename... Args>
|
2020-06-15 15:06:58 +03:00
|
|
|
BaseError(const std::string & fs, const Args & ... args)
|
2021-01-21 01:27:36 +02:00
|
|
|
: err { .level = lvlError, .msg = hintfmt(fs, args...) }
|
2020-04-30 03:57:05 +03:00
|
|
|
{ }
|
2020-04-26 23:47:41 +03:00
|
|
|
|
2020-05-03 17:01:25 +03:00
|
|
|
BaseError(hintformat hint)
|
2021-01-21 01:27:36 +02:00
|
|
|
: err { .level = lvlError, .msg = hint }
|
2020-05-03 17:01:25 +03:00
|
|
|
{ }
|
|
|
|
|
2020-06-15 15:06:58 +03:00
|
|
|
BaseError(ErrorInfo && e)
|
|
|
|
: err(std::move(e))
|
|
|
|
{ }
|
|
|
|
|
|
|
|
BaseError(const ErrorInfo & e)
|
2020-04-26 23:47:41 +03:00
|
|
|
: err(e)
|
2020-04-30 03:57:05 +03:00
|
|
|
{ }
|
2020-04-29 06:06:08 +03:00
|
|
|
|
|
|
|
virtual const char* sname() const { return "BaseError"; }
|
2020-04-26 23:47:41 +03:00
|
|
|
|
|
|
|
#ifdef EXCEPTION_NEEDS_THROW_SPEC
|
|
|
|
~BaseError() throw () { };
|
2020-05-08 01:43:36 +03:00
|
|
|
const char * what() const throw () { return calcWhat().c_str(); }
|
2020-04-26 23:47:41 +03:00
|
|
|
#else
|
2020-05-08 01:43:36 +03:00
|
|
|
const char * what() const noexcept override { return calcWhat().c_str(); }
|
2020-04-26 23:47:41 +03:00
|
|
|
#endif
|
2020-03-24 22:24:57 +02:00
|
|
|
|
2020-05-08 01:43:36 +03:00
|
|
|
const string & msg() const { return calcWhat(); }
|
2020-10-07 17:33:19 +03:00
|
|
|
const ErrorInfo & info() const { calcWhat(); return err; }
|
2020-06-24 22:10:41 +03:00
|
|
|
|
2020-06-24 22:46:25 +03:00
|
|
|
template<typename... Args>
|
|
|
|
BaseError & addTrace(std::optional<ErrPos> e, const string &fs, const Args & ... args)
|
|
|
|
{
|
|
|
|
return addTrace(e, hintfmt(fs, args...));
|
|
|
|
}
|
|
|
|
|
2020-06-24 22:10:41 +03:00
|
|
|
BaseError & addTrace(std::optional<ErrPos> e, hintformat hint);
|
2020-06-25 03:31:28 +03:00
|
|
|
|
|
|
|
bool hasTrace() const { return !err.traces.empty(); }
|
2020-04-07 04:43:22 +03:00
|
|
|
};
|
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
#define MakeError(newClass, superClass) \
|
|
|
|
class newClass : public superClass \
|
|
|
|
{ \
|
|
|
|
public: \
|
|
|
|
using superClass::superClass; \
|
2020-04-29 06:06:08 +03:00
|
|
|
virtual const char* sname() const override { return #newClass; } \
|
2020-04-26 23:47:41 +03:00
|
|
|
}
|
2020-04-08 18:07:58 +03:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
MakeError(Error, BaseError);
|
2020-06-17 11:26:52 +03:00
|
|
|
MakeError(UsageError, Error);
|
2020-07-20 21:13:37 +03:00
|
|
|
MakeError(UnimplementedError, Error);
|
2020-03-24 22:24:57 +02:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
class SysError : public Error
|
2020-04-03 01:02:40 +03:00
|
|
|
{
|
2020-04-26 23:47:41 +03:00
|
|
|
public:
|
|
|
|
int errNo;
|
2020-03-24 17:18:23 +02:00
|
|
|
|
2020-04-26 23:47:41 +03:00
|
|
|
template<typename... Args>
|
|
|
|
SysError(const Args & ... args)
|
2020-06-19 00:25:26 +03:00
|
|
|
: Error("")
|
2020-05-06 23:07:20 +03:00
|
|
|
{
|
|
|
|
errNo = errno;
|
|
|
|
auto hf = hintfmt(args...);
|
2021-01-21 01:27:36 +02:00
|
|
|
err.msg = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo));
|
2020-05-06 23:07:20 +03:00
|
|
|
}
|
2020-03-27 18:03:02 +02:00
|
|
|
|
2020-05-06 23:07:20 +03:00
|
|
|
virtual const char* sname() const override { return "SysError"; }
|
2020-04-26 23:47:41 +03:00
|
|
|
};
|
2020-03-27 18:03:02 +02:00
|
|
|
|
2020-03-22 20:25:47 +02:00
|
|
|
}
|