1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-28 01:11:15 +02:00

Merge remote-tracking branch 'origin/master' into flakes

This commit is contained in:
Eelco Dolstra 2020-06-17 10:26:52 +02:00
commit 1524752c17
139 changed files with 2586 additions and 1707 deletions

View file

@ -1,107 +1,92 @@
#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>
#include "fmt.hh"
/* 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.
*/
typedef enum {
elWarning,
elError
} ErrLevel;
lvlError = 0,
lvlWarn,
lvlInfo,
lvlTalkative,
lvlChatty,
lvlDebug,
lvlVomit
} Verbosity;
struct ErrPos
{
int lineNumber;
int column;
string nixFile;
// 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.
template <class T>
struct yellowify
{
yellowify(T &s) : value(s) {}
T &value;
};
template <class T>
std::ostream& operator<<(std::ostream &out, const yellowify<T> &y)
{
return out << ANSI_YELLOW << y.value << ANSI_NORMAL;
}
class hintformat
{
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;
}
std::string str() const
{
return fmt.str();
}
template <typename U>
friend class AddHint;
private:
format fmt;
};
std::ostream& operator<<(std::ostream &os, const hintformat &hf);
template<typename... Args>
inline hintformat hintfmt(const std::string & fs, const Args & ... args)
{
hintformat f(fs);
formatHelper(f, args...);
return f;
}
// -------------------------------------------------
// ErrorInfo.
struct ErrorInfo
{
ErrLevel level;
struct ErrorInfo {
Verbosity level;
string name;
string description;
std::optional<hintformat> hint;
@ -110,12 +95,93 @@ struct ErrorInfo
static std::optional<string> programName;
};
// --------------------------------------------------------
// error printing
std::ostream& operator<<(std::ostream &out, const ErrorInfo &einfo);
// just to cout for now.
void printErrorInfo(const ErrorInfo &einfo);
/* 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:
unsigned int status = 1; // exit status
template<typename... Args>
BaseError(unsigned int status, const Args & ... args)
: err { .level = lvlError,
.hint = hintfmt(args...)
}
, status(status)
{ }
template<typename... Args>
BaseError(const std::string & fs, const Args & ... args)
: err { .level = lvlError,
.hint = hintfmt(fs, args...)
}
{ }
BaseError(hintformat hint)
: err { .level = lvlError,
.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
const string & msg() const { return calcWhat(); }
const string & prefix() const { return prefix_; }
BaseError & addPrefix(const FormatOrString & fs);
const ErrorInfo & info() { calcWhat(); return err; }
};
#define MakeError(newClass, superClass) \
class newClass : public superClass \
{ \
public: \
using superClass::superClass; \
virtual const char* sname() const override { return #newClass; } \
}
MakeError(Error, BaseError);
MakeError(UsageError, Error);
class SysError : public Error
{
public:
int errNo;
template<typename... Args>
SysError(const Args & ... args)
:Error("")
{
errNo = errno;
auto hf = hintfmt(args...);
err.hint = hintfmt("%1%: %2%", normaltxt(hf.str()), strerror(errNo));
}
virtual const char* sname() const override { return "SysError"; }
};
}
#endif