mirror of https://github.com/mamba-org/mamba.git
391 lines
9.2 KiB
C++
391 lines
9.2 KiB
C++
// Copyright (c) 2019, QuantStack and Mamba Contributors
|
|
//
|
|
// Distributed under the terms of the BSD 3-Clause License.
|
|
//
|
|
// The full license is in the file LICENSE, distributed with this software.
|
|
|
|
#ifndef MAMBA_OUTPUT_HPP
|
|
#define MAMBA_OUTPUT_HPP
|
|
|
|
#include <string_view>
|
|
#include <iostream>
|
|
#include <iomanip>
|
|
#include <chrono>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <mutex>
|
|
|
|
#include "context.hpp"
|
|
#include "nlohmann/json.hpp"
|
|
|
|
#define ENUM_FLAG_OPERATOR(T,X) inline T operator X (T lhs, T rhs) { return (T) (static_cast<std::underlying_type_t <T>>(lhs) X static_cast<std::underlying_type_t <T>>(rhs)); }
|
|
#define ENUM_FLAGS(T) \
|
|
enum class T; \
|
|
inline T operator ~ (T t) { return (T) (~static_cast<std::underlying_type_t <T>>(t)); } \
|
|
ENUM_FLAG_OPERATOR(T,|) \
|
|
ENUM_FLAG_OPERATOR(T,^) \
|
|
ENUM_FLAG_OPERATOR(T,&) \
|
|
enum class T
|
|
|
|
#define PREFIX_LENGTH 25
|
|
|
|
namespace cursor
|
|
{
|
|
class CursorMovementTriple {
|
|
public:
|
|
CursorMovementTriple(const char* esc, int n, const char* mod)
|
|
: m_esc(esc), m_mod(mod), m_n(n)
|
|
{}
|
|
|
|
const char* m_esc;
|
|
const char* m_mod;
|
|
int m_n;
|
|
};
|
|
|
|
inline std::ostream& operator<<(std::ostream& o, const CursorMovementTriple& m)
|
|
{
|
|
o << m.m_esc << m.m_n << m.m_mod;
|
|
return o;
|
|
}
|
|
|
|
class CursorMod {
|
|
public:
|
|
CursorMod(const char* mod)
|
|
: m_mod(mod)
|
|
{}
|
|
|
|
std::ostream& operator<<(std::ostream& o)
|
|
{
|
|
o << m_mod;
|
|
return o;
|
|
}
|
|
|
|
const char* m_mod;
|
|
};
|
|
|
|
inline auto up(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "A");
|
|
}
|
|
|
|
inline auto down(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "B");
|
|
}
|
|
|
|
inline auto forward(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "C");
|
|
}
|
|
|
|
inline auto back(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "D");
|
|
}
|
|
|
|
inline auto next_line(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "E");
|
|
}
|
|
|
|
inline auto prev_line(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "F");
|
|
}
|
|
|
|
inline auto horizontal_abs(int n)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "G");
|
|
}
|
|
|
|
inline auto erase_line(int n = 0)
|
|
{
|
|
return CursorMovementTriple("\x1b[", n, "K");
|
|
}
|
|
|
|
inline auto show(int n)
|
|
{
|
|
return CursorMod("\x1b[?25h");
|
|
}
|
|
|
|
inline auto hide(int n)
|
|
{
|
|
return CursorMod("\x1b[?25l");
|
|
}
|
|
}
|
|
|
|
namespace mamba
|
|
{
|
|
|
|
std::string cut_repo_name(const std::string& reponame);
|
|
|
|
namespace printers
|
|
{
|
|
|
|
enum class format : std::size_t {
|
|
none = 0,
|
|
red = 1 << 1,
|
|
green = 1 << 2,
|
|
yellow = 1 << 3
|
|
};
|
|
|
|
struct FormattedString
|
|
{
|
|
std::string s;
|
|
format flag = format::none;
|
|
|
|
FormattedString() = default;
|
|
|
|
inline FormattedString(const std::string& i)
|
|
: s(i)
|
|
{
|
|
};
|
|
|
|
inline FormattedString(const char* i)
|
|
: s(i)
|
|
{
|
|
};
|
|
|
|
inline std::size_t size() const
|
|
{
|
|
return s.size();
|
|
}
|
|
};
|
|
|
|
enum class alignment : std::size_t
|
|
{
|
|
left = 1 << 1,
|
|
right = 1 << 2,
|
|
fill = 1 << 3
|
|
};
|
|
|
|
class Table
|
|
{
|
|
public:
|
|
|
|
Table(const std::vector<FormattedString>& header);
|
|
|
|
void set_alignment(const std::vector<alignment>& a);
|
|
void set_padding(const std::vector<int>& p);
|
|
void add_row(const std::vector<FormattedString>& r);
|
|
void add_rows(const std::string& header, const std::vector<std::vector<FormattedString>>& rs);
|
|
|
|
std::ostream& print(std::ostream& out);
|
|
|
|
private:
|
|
std::vector<FormattedString> m_header;
|
|
std::vector<alignment> m_align;
|
|
std::vector<int> m_padding;
|
|
std::vector<std::vector<FormattedString>> m_table;
|
|
};
|
|
}
|
|
|
|
// The next two functions / classes were ported from the awesome indicators library
|
|
// by p-ranav (MIT License)
|
|
// https://github.com/p-ranav/indicators
|
|
std::ostream& write_duration(std::ostream &os, std::chrono::nanoseconds ns);
|
|
int get_console_width();
|
|
|
|
class ProgressScaleWriter
|
|
{
|
|
public:
|
|
|
|
inline ProgressScaleWriter(int bar_width,
|
|
const std::string& fill,
|
|
const std::string& lead,
|
|
const std::string& remainder);
|
|
|
|
std::ostream& write(std::ostream& os, std::size_t progress) const;
|
|
|
|
private:
|
|
|
|
int m_bar_width;
|
|
std::string m_fill;
|
|
std::string m_lead;
|
|
std::string m_remainder;
|
|
};
|
|
|
|
class ProgressBar
|
|
{
|
|
public:
|
|
|
|
ProgressBar(const std::string& prefix);
|
|
|
|
void set_start();
|
|
void set_progress(char p);
|
|
void set_postfix(const std::string& postfix_text);
|
|
void print();
|
|
void mark_as_completed();
|
|
void elapsed_time_to_stream(std::stringstream& s);
|
|
const std::string& prefix() const;
|
|
|
|
private:
|
|
|
|
std::chrono::nanoseconds m_elapsed_ns;
|
|
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
|
|
|
|
std::string m_prefix, m_postfix;
|
|
bool m_start_time_saved, m_activate_bob;
|
|
char m_progress = 0;
|
|
};
|
|
|
|
class ProgressProxy
|
|
{
|
|
public:
|
|
|
|
ProgressProxy() = default;
|
|
~ProgressProxy() = default;
|
|
|
|
ProgressProxy(const ProgressProxy&) = default;
|
|
ProgressProxy& operator=(const ProgressProxy&) = default;
|
|
ProgressProxy(ProgressProxy&&) = default;
|
|
ProgressProxy& operator=(ProgressProxy&&) = default;
|
|
|
|
void set_progress(char p);
|
|
void elapsed_time_to_stream(std::stringstream& s);
|
|
void set_postfix(const std::string& s);
|
|
void mark_as_completed(const std::string_view& final_message = "");
|
|
|
|
private:
|
|
|
|
ProgressProxy(ProgressBar* ptr, std::size_t idx);
|
|
|
|
ProgressBar* p_bar;
|
|
std::size_t m_idx;
|
|
|
|
friend class Console;
|
|
};
|
|
|
|
// Todo: replace public inheritance with
|
|
// private one + using directives
|
|
class ConsoleStream : public std::stringstream
|
|
{
|
|
public:
|
|
|
|
ConsoleStream() = default;
|
|
~ConsoleStream();
|
|
};
|
|
|
|
class Console
|
|
{
|
|
public:
|
|
|
|
Console(const Console&) = delete;
|
|
Console& operator=(const Console&) = delete;
|
|
|
|
Console(Console&&) = delete;
|
|
Console& operator=(Console&&) = delete;
|
|
|
|
static Console& instance();
|
|
|
|
static ConsoleStream stream();
|
|
static void print(const std::string_view& str, bool force_print=false);
|
|
static bool prompt(const std::string_view& message, char fallback='_');
|
|
|
|
ProgressProxy add_progress_bar(const std::string& name);
|
|
void init_multi_progress();
|
|
|
|
private:
|
|
|
|
using progress_bar_ptr = std::unique_ptr<ProgressBar>;
|
|
|
|
Console();
|
|
~Console() = default;
|
|
|
|
void deactivate_progress_bar(std::size_t idx, const std::string_view& msg = "");
|
|
void print_progress(std::size_t idx);
|
|
void print_progress();
|
|
void print_progress_unlocked();
|
|
bool skip_progress_bars() const;
|
|
|
|
std::mutex m_mutex;
|
|
std::vector<progress_bar_ptr> m_progress_bars;
|
|
std::vector<ProgressBar*> m_active_progress_bars;
|
|
bool m_progress_started = false;
|
|
|
|
friend class ProgressProxy;
|
|
};
|
|
|
|
inline void ProgressProxy::set_postfix(const std::string& s)
|
|
{
|
|
p_bar->set_postfix(s);
|
|
Console::instance().print_progress(m_idx);
|
|
}
|
|
|
|
#undef DEBUG
|
|
#undef INFO
|
|
#undef WARNING
|
|
#undef ERROR
|
|
#undef FATAL
|
|
|
|
enum class LogSeverity
|
|
{
|
|
debug,
|
|
info,
|
|
warning,
|
|
error,
|
|
fatal
|
|
};
|
|
|
|
class MessageLogger
|
|
{
|
|
public:
|
|
|
|
MessageLogger(const char* file, int line, LogSeverity severity);
|
|
~MessageLogger();
|
|
|
|
std::stringstream& stream();
|
|
|
|
static LogSeverity& global_log_severity();
|
|
|
|
private:
|
|
|
|
std::string m_file;
|
|
int m_line;
|
|
LogSeverity m_severity;
|
|
std::stringstream m_stream;
|
|
|
|
};
|
|
|
|
class JsonLogger
|
|
{
|
|
public:
|
|
|
|
JsonLogger(const JsonLogger&) = delete;
|
|
JsonLogger& operator=(const JsonLogger&) = delete;
|
|
|
|
JsonLogger(JsonLogger&&) = delete;
|
|
JsonLogger& operator=(JsonLogger&&) = delete;
|
|
|
|
static JsonLogger& instance();
|
|
|
|
nlohmann::json json_log;
|
|
void json_write(const nlohmann::json& j);
|
|
void json_append(const std::string& value);
|
|
void json_append(const nlohmann::json& j);
|
|
void json_down(const std::string& key);
|
|
void json_up();
|
|
|
|
private:
|
|
|
|
JsonLogger();
|
|
~JsonLogger() = default;
|
|
|
|
std::string json_hier;
|
|
unsigned int json_index;
|
|
};
|
|
}
|
|
|
|
#undef ERROR
|
|
#undef WARNING
|
|
#undef FATAL
|
|
|
|
#define LOG(severity) mamba::MessageLogger(__FILE__, __LINE__, severity).stream()
|
|
#define LOG_DEBUG LOG(mamba::LogSeverity::debug)
|
|
#define LOG_INFO LOG(mamba::LogSeverity::info)
|
|
#define LOG_WARNING LOG(mamba::LogSeverity::warning)
|
|
#define LOG_ERROR LOG(mamba::LogSeverity::error)
|
|
#define LOG_FATAL LOG(mamba::LogSeverity::fatal)
|
|
|
|
#endif // MAMBA_OUTPUT_HPP
|