aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/error.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/libutil/error.hh')
-rw-r--r--src/libutil/error.hh225
1 files changed, 145 insertions, 80 deletions
diff --git a/src/libutil/error.hh b/src/libutil/error.hh
index f402b692e..4f9df826f 100644
--- a/src/libutil/error.hh
+++ b/src/libutil/error.hh
@@ -1,121 +1,186 @@
-#ifndef error_hh
-#define error_hh
+#pragma once
-#include "ansicolor.hh"
-#include <string>
-#include <optional>
-#include <iostream>
+
+#include "ref.hh"
#include "types.hh"
-namespace nix
-{
+#include <cstring>
+#include <list>
+#include <memory>
+#include <map>
+#include <optional>
-typedef enum {
- elWarning,
- elError
-} ErrLevel;
+#include "fmt.hh"
-struct ErrPos
-{
- int lineNumber;
- int column;
- string nixFile;
+/* 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 {
+
+/*
+
+This file defines two main structs/classes used in nix error handling.
+
+ErrorInfo provides a standard payload of error information, with conversion to string
+happening in the logger rather than at the call site.
+
+BaseError is the ancestor of nix specific exceptions (and Interrupted), and contains
+an ErrorInfo.
+
+ErrorInfo structs are sent to the logger as part of an exception, or directly with the
+logError or logWarning macros.
+
+See the error-demo.cc program for usage examples.
+*/
+
+enum struct Verbosity {
+ Error = 0,
+ Warn,
+ Info,
+ Talkative,
+ Chatty,
+ Debug,
+ Vomit,
+};
+
+// ErrPos indicates the location of an error in a nix file.
+struct ErrPos {
+ int line = 0;
+ int column = 0;
+ string file;
+
+ operator bool() const
+ {
+ return line != 0;
+ }
+
+ // convert from the Pos struct, found in libexpr.
template <class P>
ErrPos& operator=(const P &pos)
{
- lineNumber = pos.line;
+ line = pos.line;
column = pos.column;
- nixFile = pos.file;
+ file = pos.file;
return *this;
}
template <class P>
ErrPos(const P &p)
{
- *this = p;
+ *this = p;
}
};
-struct NixCode
-{
+struct NixCode {
ErrPos errPos;
std::optional<string> prevLineOfCode;
- string errLineOfCode;
+ std::optional<string> errLineOfCode;
std::optional<string> nextLineOfCode;
};
-// ----------------------------------------------------------------
-// format function for hints. same as fmt, except templated values
-// are always in yellow.
+struct ErrorInfo {
+ Verbosity level;
+ string name;
+ string description;
+ std::optional<hintformat> hint;
+ std::optional<NixCode> nixCode;
-template <class T>
-struct yellowify
-{
- yellowify(T &s) : value(s) {}
- T &value;
+ static std::optional<string> programName;
};
-template <class T>
-std::ostream& operator<<(std::ostream &out, const yellowify<T> &y)
-{
- return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
-}
+std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo);
-class hintformat
+/* BaseError should generally not be caught, as it has Interrupted as
+ a subclass. Catch Error instead. */
+class BaseError : public std::exception
{
+protected:
+ string prefix_; // used for location traces etc.
+ mutable ErrorInfo err;
+
+ mutable std::optional<string> what_;
+ const string& calcWhat() const;
+
public:
- hintformat(string format) :fmt(format)
- {
- fmt.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
- }
- template<class T>
- hintformat& operator%(const T &value)
- {
- fmt % yellowify(value);
- return *this;
- }
+ unsigned int status = 1; // exit status
+
+ template<typename... Args>
+ BaseError(unsigned int status, const Args & ... args)
+ : err { .level = Verbosity::Error,
+ .hint = hintfmt(args...)
+ }
+ , status(status)
+ { }
+
+ template<typename... Args>
+ BaseError(const std::string & fs, const Args & ... args)
+ : err { .level = Verbosity::Error,
+ .hint = hintfmt(fs, args...)
+ }
+ { }
+
+ BaseError(hintformat hint)
+ : err { .level = Verbosity::Error,
+ .hint = hint
+ }
+ { }
+
+ BaseError(ErrorInfo && e)
+ : err(std::move(e))
+ { }
+
+ BaseError(const ErrorInfo & e)
+ : err(e)
+ { }
+
+ virtual const char* sname() const { return "BaseError"; }
+
+#ifdef EXCEPTION_NEEDS_THROW_SPEC
+ ~BaseError() throw () { };
+ const char * what() const throw () { return calcWhat().c_str(); }
+#else
+ const char * what() const noexcept override { return calcWhat().c_str(); }
+#endif
- std::string str() const
- {
- return fmt.str();
- }
+ const string & msg() const { return calcWhat(); }
+ const string & prefix() const { return prefix_; }
+ BaseError & addPrefix(const FormatOrString & fs);
- template <typename U>
- friend class AddHint;
-private:
- format fmt;
+ const ErrorInfo & info() { calcWhat(); return err; }
};
-std::ostream& operator<<(std::ostream &os, const hintformat &hf);
+#define MakeError(newClass, superClass) \
+ class newClass : public superClass \
+ { \
+ public: \
+ using superClass::superClass; \
+ virtual const char* sname() const override { return #newClass; } \
+ }
-template<typename... Args>
-inline hintformat hintfmt(const std::string & fs, const Args & ... args)
-{
- hintformat f(fs);
- formatHelper(f, args...);
- return f;
-}
+MakeError(Error, BaseError);
-// -------------------------------------------------
-// ErrorInfo.
-struct ErrorInfo
+class SysError : public Error
{
- ErrLevel level;
- string name;
- string description;
- std::optional<hintformat> hint;
- std::optional<NixCode> nixCode;
-
- static std::optional<string> programName;
-};
+public:
+ int errNo;
-// --------------------------------------------------------
-// error printing
+ template<typename... Args>
+ SysError(const Args & ... args)
+ :Error("")
+ {
+ errNo = errno;
+ auto hf = hintfmt(args...);
+ err.hint = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo));
+ }
-// just to cout for now.
-void printErrorInfo(const ErrorInfo &einfo);
+ virtual const char* sname() const override { return "SysError"; }
+};
}
-
-#endif