forked from lix-project/lix
Compare commits
12 commits
sb/rbt/mak
...
main
Author | SHA1 | Date | |
---|---|---|---|
eldritch horrors | 5a54b0a20c | ||
eldritch horrors | e28dc26084 | ||
eldritch horrors | 1da1f501fc | ||
Winter Cute | 6646b80396 | ||
Rebecca Turner | 9d97d1cb68 | ||
Rebecca Turner | 877750b7c5 | ||
eldritch horrors | 6e5db5e4a2 | ||
eldritch horrors | 69bfd21e20 | ||
eldritch horrors | 86b954a7af | ||
Rebecca Turner | 236bc046ba | ||
Rebecca Turner | 5ec2efb686 | ||
Rebecca Turner | 8e63eca912 |
17
meson.build
17
meson.build
|
@ -214,6 +214,9 @@ deps += gtest
|
|||
toml11 = dependency('toml11', version : '>=3.7.0', required : true)
|
||||
deps += toml11
|
||||
|
||||
nlohmann_json = dependency('nlohmann_json', required : true)
|
||||
deps += nlohmann_json
|
||||
|
||||
#
|
||||
# Build-time tools
|
||||
#
|
||||
|
@ -244,13 +247,12 @@ bison = find_program('bison')
|
|||
flex = find_program('flex')
|
||||
|
||||
# This is how Nix does generated headers...
|
||||
# other instances of header generation use a very similar command.
|
||||
# FIXME(Qyriad): do we really need to use the shell for this?
|
||||
gen_header_sh = 'echo \'R"__NIX_STR(\' | cat - @INPUT@ && echo \')__NIX_STR"\''
|
||||
gen_header = generator(
|
||||
bash,
|
||||
arguments : [
|
||||
'-c',
|
||||
'echo \'R"__NIX_STR(\' | cat - @INPUT@ && echo \')__NIX_STR"\'',
|
||||
],
|
||||
arguments : [ '-c', gen_header_sh ],
|
||||
capture : true,
|
||||
output : '@PLAINNAME@.gen.hh',
|
||||
)
|
||||
|
@ -352,13 +354,10 @@ if get_option('profile-build').require(meson.get_compiler('cpp').get_id() == 'cl
|
|||
endif
|
||||
|
||||
subdir('src')
|
||||
subdir('scripts')
|
||||
subdir('misc')
|
||||
|
||||
if enable_tests
|
||||
# Just configures `scripts/nix-profile.sh.in` (and copies the original to the build directory).
|
||||
# Done as a subdirectory to convince Meson to put the configured files
|
||||
# in `build/scripts` instead of just `build`.
|
||||
subdir('scripts')
|
||||
|
||||
subdir('tests/unit')
|
||||
subdir('tests/functional')
|
||||
endif
|
||||
|
|
|
@ -39,7 +39,7 @@ option('store-dir', type : 'string', value : '/nix/store',
|
|||
description : 'path of the Nix store',
|
||||
)
|
||||
|
||||
option('state-dir', type : 'string', value : '/nix/var/nix',
|
||||
option('state-dir', type : 'string', value : '/nix/var',
|
||||
description : 'path to store state in for Nix',
|
||||
)
|
||||
|
||||
|
|
8
misc/bash/meson.build
Normal file
8
misc/bash/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
configure_file(
|
||||
input : 'completion.sh',
|
||||
output : 'nix',
|
||||
install : true,
|
||||
install_dir : datadir / 'bash-completion/completions',
|
||||
install_mode : 'rw-r--r--',
|
||||
copy : true,
|
||||
)
|
8
misc/fish/meson.build
Normal file
8
misc/fish/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
configure_file(
|
||||
input : 'completion.fish',
|
||||
output : 'nix.fish',
|
||||
install : true,
|
||||
install_dir : datadir / 'fish/vendor_completions.d',
|
||||
install_mode : 'rw-r--r--',
|
||||
copy : true,
|
||||
)
|
5
misc/meson.build
Normal file
5
misc/meson.build
Normal file
|
@ -0,0 +1,5 @@
|
|||
subdir('bash')
|
||||
subdir('fish')
|
||||
subdir('zsh')
|
||||
|
||||
subdir('systemd')
|
25
misc/systemd/meson.build
Normal file
25
misc/systemd/meson.build
Normal file
|
@ -0,0 +1,25 @@
|
|||
foreach config : [ 'nix-daemon.socket', 'nix-daemon.service' ]
|
||||
configure_file(
|
||||
input : config + '.in',
|
||||
output : config,
|
||||
install : true,
|
||||
install_dir : prefix / 'lib/systemd/system',
|
||||
install_mode : 'rw-r--r--',
|
||||
configuration : {
|
||||
'storedir' : store_dir,
|
||||
'localstatedir' : state_dir,
|
||||
'bindir' : bindir,
|
||||
},
|
||||
)
|
||||
endforeach
|
||||
|
||||
configure_file(
|
||||
input : 'nix-daemon.conf.in',
|
||||
output : 'nix-daemon.conf',
|
||||
install : true,
|
||||
install_dir : prefix / 'lib/tmpfiles.d',
|
||||
install_mode : 'rw-r--r--',
|
||||
configuration : {
|
||||
'localstatedir' : state_dir,
|
||||
},
|
||||
)
|
10
misc/zsh/meson.build
Normal file
10
misc/zsh/meson.build
Normal file
|
@ -0,0 +1,10 @@
|
|||
foreach script : [ [ 'completion.zsh', '_nix' ], [ 'run-help-nix' ] ]
|
||||
configure_file(
|
||||
input : script[0],
|
||||
output : script.get(1, script[0]),
|
||||
install : true,
|
||||
install_dir : datadir / 'zsh/site-functions',
|
||||
install_mode : 'rw-r--r--',
|
||||
copy : true,
|
||||
)
|
||||
endforeach
|
|
@ -1,3 +1,5 @@
|
|||
# configures `scripts/nix-profile.sh.in` (and copies the original to the build directory).
|
||||
# this is only needed for tests, but running it unconditionally does not hurt enough to care.
|
||||
configure_file(
|
||||
input : 'nix-profile.sh.in',
|
||||
output : 'nix-profile.sh',
|
||||
|
@ -12,3 +14,16 @@ configure_file(
|
|||
output : 'nix-profile.sh.in',
|
||||
copy : true,
|
||||
)
|
||||
|
||||
foreach rc : [ '.sh', '.fish', '-daemon.sh', '-daemon.fish' ]
|
||||
configure_file(
|
||||
input : 'nix-profile' + rc + '.in',
|
||||
output : 'nix' + rc,
|
||||
install : true,
|
||||
install_dir : sysconfdir / 'profile.d',
|
||||
install_mode : 'rw-r--r--',
|
||||
configuration : {
|
||||
'localstatedir': state_dir,
|
||||
},
|
||||
)
|
||||
endforeach
|
||||
|
|
|
@ -185,16 +185,6 @@ static int main_build_remote(int argc, char * * argv)
|
|||
std::cerr << "# postpone\n";
|
||||
else
|
||||
{
|
||||
// build the hint template.
|
||||
std::string errorText =
|
||||
"Failed to find a machine for remote build!\n"
|
||||
"derivation: %s\nrequired (system, features): (%s, [%s])";
|
||||
errorText += "\n%s available machines:";
|
||||
errorText += "\n(systems, maxjobs, supportedFeatures, mandatoryFeatures)";
|
||||
|
||||
for (unsigned int i = 0; i < machines.size(); ++i)
|
||||
errorText += "\n([%s], %s, [%s], [%s])";
|
||||
|
||||
// add the template values.
|
||||
std::string drvstr;
|
||||
if (drvPath.has_value())
|
||||
|
@ -202,19 +192,30 @@ static int main_build_remote(int argc, char * * argv)
|
|||
else
|
||||
drvstr = "<unknown>";
|
||||
|
||||
auto error = HintFmt::fromFormatString(errorText);
|
||||
error
|
||||
% drvstr
|
||||
% neededSystem
|
||||
% concatStringsSep<StringSet>(", ", requiredFeatures)
|
||||
% machines.size();
|
||||
std::string machinesFormatted;
|
||||
|
||||
for (auto & m : machines)
|
||||
error
|
||||
% concatStringsSep<StringSet>(", ", m.systemTypes)
|
||||
% m.maxJobs
|
||||
% concatStringsSep<StringSet>(", ", m.supportedFeatures)
|
||||
% concatStringsSep<StringSet>(", ", m.mandatoryFeatures);
|
||||
for (auto & m : machines) {
|
||||
machinesFormatted += HintFmt(
|
||||
"\n([%s], %s, [%s], [%s])",
|
||||
concatStringsSep<StringSet>(", ", m.systemTypes),
|
||||
m.maxJobs,
|
||||
concatStringsSep<StringSet>(", ", m.supportedFeatures),
|
||||
concatStringsSep<StringSet>(", ", m.mandatoryFeatures)
|
||||
).str();
|
||||
}
|
||||
|
||||
auto error = HintFmt(
|
||||
"Failed to find a machine for remote build!\n"
|
||||
"derivation: %s\n"
|
||||
"required (system, features): (%s, [%s])\n"
|
||||
"%s available machines:\n"
|
||||
"(systems, maxjobs, supportedFeatures, mandatoryFeatures)%s",
|
||||
drvstr,
|
||||
neededSystem,
|
||||
concatStringsSep<StringSet>(", ", requiredFeatures),
|
||||
machines.size(),
|
||||
Uncolored(machinesFormatted)
|
||||
);
|
||||
|
||||
printMsg(couldBuildLocally ? lvlChatty : lvlWarn, error.str());
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ libcmd = library(
|
|||
boehm,
|
||||
editline,
|
||||
lowdown,
|
||||
nlohmann_json,
|
||||
],
|
||||
install : true,
|
||||
# FIXME(Qyriad): is this right?
|
||||
|
@ -56,3 +57,17 @@ liblixcmd = declare_dependency(
|
|||
include_directories : '.',
|
||||
link_with : libcmd,
|
||||
)
|
||||
|
||||
# FIXME: not using the pkg-config module because it creates way too many deps
|
||||
# while meson migration is in progress, and we want to not include boost here
|
||||
configure_file(
|
||||
input : 'nix-cmd.pc.in',
|
||||
output : 'nix-cmd.pc',
|
||||
install_dir : libdir / 'pkgconfig',
|
||||
configuration : {
|
||||
'prefix' : prefix,
|
||||
'libdir' : libdir,
|
||||
'includedir' : includedir,
|
||||
'PACKAGE_VERSION' : meson.project_version(),
|
||||
},
|
||||
)
|
||||
|
|
8
src/libexpr/flake/meson.build
Normal file
8
src/libexpr/flake/meson.build
Normal file
|
@ -0,0 +1,8 @@
|
|||
libexpr_generated_headers += custom_target(
|
||||
command : [ 'bash', '-c', 'echo \'R"__NIX_STR(\' | cat - @INPUT@ && echo \')__NIX_STR"\'' ],
|
||||
input : 'call-flake.nix',
|
||||
output : '@PLAINNAME@.gen.hh',
|
||||
capture : true,
|
||||
install : true,
|
||||
install_dir : includedir / 'nix/flake',
|
||||
)
|
|
@ -49,10 +49,20 @@ meson.add_install_script(
|
|||
'@0@'.format(includedir),
|
||||
)
|
||||
|
||||
imported_drv_to_derivation_gen = gen_header.process('imported-drv-to-derivation.nix')
|
||||
fetchurl_gen = gen_header.process('fetchurl.nix')
|
||||
derivation_gen = gen_header.process('primops/derivation.nix', preserve_path_from : meson.current_source_dir())
|
||||
call_flake_gen = gen_header.process('flake/call-flake.nix')
|
||||
libexpr_generated_headers = [
|
||||
gen_header.process('primops/derivation.nix', preserve_path_from : meson.current_source_dir()),
|
||||
]
|
||||
foreach header : [ 'imported-drv-to-derivation.nix', 'fetchurl.nix' ]
|
||||
libexpr_generated_headers += custom_target(
|
||||
command : [ 'bash', '-c', 'echo \'R"__NIX_STR(\' | cat - @INPUT@ && echo \')__NIX_STR"\'' ],
|
||||
input : header,
|
||||
output : '@PLAINNAME@.gen.hh',
|
||||
capture : true,
|
||||
install : true,
|
||||
install_dir : includedir / 'nix',
|
||||
)
|
||||
endforeach
|
||||
subdir('flake')
|
||||
|
||||
libexpr_sources = files(
|
||||
'attr-path.cc',
|
||||
|
@ -121,10 +131,7 @@ libexpr = library(
|
|||
libexpr_sources,
|
||||
parser_tab,
|
||||
lexer_tab,
|
||||
imported_drv_to_derivation_gen,
|
||||
fetchurl_gen,
|
||||
derivation_gen,
|
||||
call_flake_gen,
|
||||
libexpr_generated_headers,
|
||||
dependencies : [
|
||||
liblixutil,
|
||||
liblixstore,
|
||||
|
@ -132,6 +139,7 @@ libexpr = library(
|
|||
boehm,
|
||||
boost,
|
||||
toml11,
|
||||
nlohmann_json,
|
||||
],
|
||||
# for shared.hh
|
||||
include_directories : [
|
||||
|
@ -152,3 +160,17 @@ liblixexpr = declare_dependency(
|
|||
include_directories : include_directories('.'),
|
||||
link_with : libexpr,
|
||||
)
|
||||
|
||||
# FIXME: not using the pkg-config module because it creates way too many deps
|
||||
# while meson migration is in progress, and we want to not include boost here
|
||||
configure_file(
|
||||
input : 'nix-expr.pc.in',
|
||||
output : 'nix-expr.pc',
|
||||
install_dir : libdir / 'pkgconfig',
|
||||
configuration : {
|
||||
'prefix' : prefix,
|
||||
'libdir' : libdir,
|
||||
'includedir' : includedir,
|
||||
'PACKAGE_VERSION' : meson.project_version(),
|
||||
},
|
||||
)
|
||||
|
|
|
@ -608,7 +608,7 @@ std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer)
|
|||
}
|
||||
|
||||
template<>
|
||||
HintFmt & HintFmt::operator%(const ValuePrinter & value)
|
||||
fmt_internal::HintFmt & fmt_internal::HintFmt::operator%(const ValuePrinter & value)
|
||||
{
|
||||
fmt % value;
|
||||
return *this;
|
||||
|
|
|
@ -86,6 +86,6 @@ std::ostream & operator<<(std::ostream & output, const ValuePrinter & printer);
|
|||
* magenta.
|
||||
*/
|
||||
template<>
|
||||
HintFmt & HintFmt::operator%(const ValuePrinter & value);
|
||||
fmt_internal::HintFmt & fmt_internal::HintFmt::operator%(const ValuePrinter & value);
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ libfetchers = library(
|
|||
dependencies : [
|
||||
liblixstore,
|
||||
liblixutil,
|
||||
nlohmann_json,
|
||||
],
|
||||
install : true,
|
||||
# FIXME(Qyriad): is this right?
|
||||
|
|
|
@ -31,3 +31,17 @@ liblixmain = declare_dependency(
|
|||
include_directories : include_directories('.'),
|
||||
link_with : libmain,
|
||||
)
|
||||
|
||||
# FIXME: not using the pkg-config module because it creates way too many deps
|
||||
# while meson migration is in progress, and we want to not include boost here
|
||||
configure_file(
|
||||
input : 'nix-main.pc.in',
|
||||
output : 'nix-main.pc',
|
||||
install_dir : libdir / 'pkgconfig',
|
||||
configuration : {
|
||||
'prefix' : prefix,
|
||||
'libdir' : libdir,
|
||||
'includedir' : includedir,
|
||||
'PACKAGE_VERSION' : meson.project_version(),
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
schema_sql_gen = gen_header.process('schema.sql')
|
||||
ca_specific_schema_gen = gen_header.process('ca-specific-schema.sql')
|
||||
libstore_generated_headers = []
|
||||
foreach header : [ 'schema.sql', 'ca-specific-schema.sql' ]
|
||||
libstore_generated_headers += custom_target(
|
||||
command : [ 'bash', '-c', 'echo \'R"__NIX_STR(\' | cat - @INPUT@ && echo \')__NIX_STR"\'' ],
|
||||
input : header,
|
||||
output : '@PLAINNAME@.gen.hh',
|
||||
capture : true,
|
||||
install : true,
|
||||
install_dir : includedir / 'nix',
|
||||
)
|
||||
endforeach
|
||||
|
||||
libstore_sources = files(
|
||||
'binary-cache-store.cc',
|
||||
|
@ -140,7 +149,7 @@ cpp_str_defines = {
|
|||
'NIX_PREFIX': prefix,
|
||||
'NIX_STORE_DIR': store_dir,
|
||||
'NIX_DATA_DIR': datadir,
|
||||
'NIX_STATE_DIR': state_dir,
|
||||
'NIX_STATE_DIR': state_dir / 'nix',
|
||||
'NIX_LOG_DIR': log_dir,
|
||||
'NIX_CONF_DIR': sysconfdir,
|
||||
'NIX_BIN_DIR': bindir,
|
||||
|
@ -157,8 +166,7 @@ endforeach
|
|||
|
||||
libstore = library(
|
||||
'nixstore',
|
||||
schema_sql_gen,
|
||||
ca_specific_schema_gen,
|
||||
libstore_generated_headers,
|
||||
libstore_sources,
|
||||
dependencies : [
|
||||
libarchive,
|
||||
|
@ -172,6 +180,7 @@ libstore = library(
|
|||
aws_sdk,
|
||||
aws_s3,
|
||||
aws_sdk_transfer,
|
||||
nlohmann_json,
|
||||
],
|
||||
cpp_args : cpp_args,
|
||||
install : true,
|
||||
|
@ -186,3 +195,17 @@ liblixstore = declare_dependency(
|
|||
include_directories : include_directories('.'),
|
||||
link_with : libstore,
|
||||
)
|
||||
|
||||
# FIXME: not using the pkg-config module because it creates way too many deps
|
||||
# while meson migration is in progress, and we want to not include boost here
|
||||
configure_file(
|
||||
input : 'nix-store.pc.in',
|
||||
output : 'nix-store.pc',
|
||||
install_dir : libdir / 'pkgconfig',
|
||||
configuration : {
|
||||
'prefix' : prefix,
|
||||
'libdir' : libdir,
|
||||
'includedir' : includedir,
|
||||
'PACKAGE_VERSION' : meson.project_version(),
|
||||
},
|
||||
)
|
||||
|
|
22
src/libutil/escape-char.cc
Normal file
22
src/libutil/escape-char.cc
Normal file
|
@ -0,0 +1,22 @@
|
|||
#include <boost/io/ios_state.hpp>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
#include "escape-char.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
std::ostream & operator<<(std::ostream & s, MaybeHexEscapedChar c)
|
||||
{
|
||||
boost::io::ios_flags_saver _ifs(s);
|
||||
|
||||
if (isprint(c.c)) {
|
||||
s << static_cast<char>(c.c);
|
||||
} else {
|
||||
s << "\\x" << std::hex << std::setfill('0') << std::setw(2)
|
||||
<< (static_cast<unsigned int>(c.c) & 0xff);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace nix
|
22
src/libutil/escape-char.hh
Normal file
22
src/libutil/escape-char.hh
Normal file
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include <ostream>
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* A struct that prints a debug representation of a character, like `\x1f` for
|
||||
* non-printable characters, or the character itself for other characters.
|
||||
*
|
||||
* Note that these are suitable for human readable output, but further care is
|
||||
* necessary to include them in C++ strings to avoid running into adjacent
|
||||
* hex-like characters. (`"puppy\x1bdoggy"` parses as `"puppy" "\x1bd" "oggy"`
|
||||
* and errors because 0x1bd is too big for a `char`.)
|
||||
*/
|
||||
struct MaybeHexEscapedChar
|
||||
{
|
||||
char c;
|
||||
};
|
||||
|
||||
std::ostream & operator<<(std::ostream & s, MaybeHexEscapedChar c);
|
||||
|
||||
} // namespace nix
|
|
@ -5,43 +5,94 @@
|
|||
#include <string>
|
||||
#include "ansicolor.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* A helper for writing `boost::format` expressions.
|
||||
* Values wrapped in this struct are printed in magenta.
|
||||
*
|
||||
* These are equivalent:
|
||||
*
|
||||
* ```
|
||||
* formatHelper(formatter, a_0, ..., a_n)
|
||||
* formatter % a_0 % ... % a_n
|
||||
* ```
|
||||
*
|
||||
* With a single argument, `formatHelper(s)` is a no-op.
|
||||
* By default, arguments to `HintFmt` are printed in magenta. To avoid this,
|
||||
* either wrap the argument in `Uncolored` or add a specialization of
|
||||
* `HintFmt::operator%`.
|
||||
*/
|
||||
template<class F>
|
||||
inline void formatHelper(F & f)
|
||||
{ }
|
||||
|
||||
template<class F, typename T, typename... Args>
|
||||
inline void formatHelper(F & f, const T & x, const Args & ... args)
|
||||
template<class T>
|
||||
struct Magenta
|
||||
{
|
||||
// Interpolate one argument and then recurse.
|
||||
formatHelper(f % x, args...);
|
||||
Magenta(const T & s) : value(s) {}
|
||||
const T & value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
std::ostream & operator<<(std::ostream & out, const Magenta<T> & y)
|
||||
{
|
||||
return out << ANSI_MAGENTA << y.value << ANSI_NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Values wrapped in this class are printed without coloring.
|
||||
*
|
||||
* By default, arguments to `HintFmt` are printed in magenta (see `Magenta`).
|
||||
*/
|
||||
template<class T>
|
||||
struct Uncolored
|
||||
{
|
||||
Uncolored(const T & s) : value(s) {}
|
||||
const T & value;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
std::ostream & operator<<(std::ostream & out, const Uncolored<T> & y)
|
||||
{
|
||||
return out << ANSI_NORMAL << y.value;
|
||||
}
|
||||
|
||||
namespace fmt_internal {
|
||||
|
||||
/**
|
||||
* Set the correct exceptions for `fmt`.
|
||||
*/
|
||||
void setExceptions(boost::format & fmt)
|
||||
inline void setExceptions(boost::format & fmt)
|
||||
{
|
||||
fmt.exceptions(
|
||||
boost::io::all_error_bits ^
|
||||
boost::io::too_many_args_bit ^
|
||||
boost::io::too_few_args_bit);
|
||||
boost::io::all_error_bits ^ boost::io::too_many_args_bit ^ boost::io::too_few_args_bit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for `HintFmt` that supports the evil `operator%`.
|
||||
*
|
||||
* See: https://git.lix.systems/lix-project/lix/issues/178
|
||||
*/
|
||||
struct HintFmt
|
||||
{
|
||||
boost::format fmt;
|
||||
|
||||
template<typename... Args>
|
||||
HintFmt(boost::format && fmt, const Args &... args) : fmt(std::move(fmt))
|
||||
{
|
||||
setExceptions(fmt);
|
||||
(*this % ... % args);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
HintFmt & operator%(const T & value)
|
||||
{
|
||||
fmt % Magenta(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
HintFmt & operator%(const Uncolored<T> & value)
|
||||
{
|
||||
fmt % value.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
boost::format into_format()
|
||||
{
|
||||
return std::move(fmt);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,52 +128,14 @@ inline std::string fmt(const char * s)
|
|||
}
|
||||
|
||||
template<typename... Args>
|
||||
inline std::string fmt(const std::string & fs, const Args & ... args)
|
||||
inline std::string fmt(const std::string & fs, const Args &... args)
|
||||
{
|
||||
boost::format f(fs);
|
||||
setExceptions(f);
|
||||
formatHelper(f, args...);
|
||||
fmt_internal::setExceptions(f);
|
||||
(f % ... % args);
|
||||
return f.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Values wrapped in this struct are printed in magenta.
|
||||
*
|
||||
* By default, arguments to `HintFmt` are printed in magenta. To avoid this,
|
||||
* either wrap the argument in `Uncolored` or add a specialization of
|
||||
* `HintFmt::operator%`.
|
||||
*/
|
||||
template <class T>
|
||||
struct Magenta
|
||||
{
|
||||
Magenta(const T &s) : value(s) {}
|
||||
const T & value;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::ostream & operator<<(std::ostream & out, const Magenta<T> & y)
|
||||
{
|
||||
return out << ANSI_WARNING << y.value << ANSI_NORMAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Values wrapped in this class are printed without coloring.
|
||||
*
|
||||
* By default, arguments to `HintFmt` are printed in magenta (see `Magenta`).
|
||||
*/
|
||||
template <class T>
|
||||
struct Uncolored
|
||||
{
|
||||
Uncolored(const T & s) : value(s) {}
|
||||
const T & value;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
std::ostream & operator<<(std::ostream & out, const Uncolored<T> & y)
|
||||
{
|
||||
return out << ANSI_NORMAL << y.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around `boost::format` which colors interpolated arguments in
|
||||
* magenta by default.
|
||||
|
@ -137,46 +150,28 @@ public:
|
|||
* Format the given string literally, without interpolating format
|
||||
* placeholders.
|
||||
*/
|
||||
HintFmt(const std::string & literal)
|
||||
: HintFmt("%s", Uncolored(literal))
|
||||
{ }
|
||||
|
||||
static HintFmt fromFormatString(const std::string & format) {
|
||||
return HintFmt(boost::format(format));
|
||||
}
|
||||
HintFmt(const std::string & literal) : HintFmt("%s", Uncolored(literal)) {}
|
||||
|
||||
/**
|
||||
* Interpolate the given arguments into the format string.
|
||||
*/
|
||||
template<typename... Args>
|
||||
HintFmt(const std::string & format, const Args & ... args)
|
||||
HintFmt(const std::string & format, const Args &... args)
|
||||
: HintFmt(boost::format(format), args...)
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
HintFmt(const HintFmt & hf)
|
||||
: fmt(hf.fmt)
|
||||
{ }
|
||||
HintFmt(const HintFmt & hf) : fmt(hf.fmt) {}
|
||||
|
||||
template<typename... Args>
|
||||
HintFmt(boost::format && fmt, const Args & ... args)
|
||||
: fmt(std::move(fmt))
|
||||
HintFmt(boost::format && fmt, const Args &... args)
|
||||
: fmt(fmt_internal::HintFmt(std::move(fmt), args...).into_format())
|
||||
{
|
||||
setExceptions(fmt);
|
||||
formatHelper(*this, args...);
|
||||
if (this->fmt.remaining_args() != 0) {
|
||||
throw boost::io::too_few_args(
|
||||
this->fmt.bound_args() + this->fmt.fed_args(), this->fmt.expected_args()
|
||||
);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
HintFmt & operator%(const T & value)
|
||||
{
|
||||
fmt % Magenta(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
HintFmt & operator%(const Uncolored<T> & value)
|
||||
{
|
||||
fmt % value.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::string str() const
|
||||
|
|
|
@ -230,9 +230,7 @@ extern Verbosity verbosity;
|
|||
template<typename... Args>
|
||||
inline void warn(const std::string & fs, const Args & ... args)
|
||||
{
|
||||
boost::format f(fs);
|
||||
formatHelper(f, args...);
|
||||
logger->warn(f.str());
|
||||
logger->warn(HintFmt(fs, args...).str());
|
||||
}
|
||||
|
||||
#define warnOnce(haveWarned, args...) \
|
||||
|
|
|
@ -8,6 +8,7 @@ libutil_sources = files(
|
|||
'config.cc',
|
||||
'english.cc',
|
||||
'error.cc',
|
||||
'escape-char.cc',
|
||||
'exit.cc',
|
||||
'experimental-features.cc',
|
||||
'filesystem.cc',
|
||||
|
@ -35,6 +36,7 @@ libutil_headers = files(
|
|||
'abstract-setting-to-json.hh',
|
||||
'ansicolor.hh',
|
||||
'archive.hh',
|
||||
'args/root.hh',
|
||||
'args.hh',
|
||||
'box_ptr.hh',
|
||||
'callback.hh',
|
||||
|
@ -49,6 +51,7 @@ libutil_headers = files(
|
|||
'config.hh',
|
||||
'english.hh',
|
||||
'error.hh',
|
||||
'escape-char.hh',
|
||||
'exit.hh',
|
||||
'experimental-features.hh',
|
||||
'experimental-features-json.hh',
|
||||
|
@ -102,6 +105,7 @@ libutil = library(
|
|||
libarchive,
|
||||
brotli,
|
||||
openssl,
|
||||
nlohmann_json,
|
||||
],
|
||||
implicit_include_directories : true,
|
||||
install : true,
|
||||
|
|
|
@ -87,6 +87,7 @@ nix = executable(
|
|||
liblixfetchers,
|
||||
liblixmain,
|
||||
boehm,
|
||||
nlohmann_json,
|
||||
],
|
||||
install : true,
|
||||
# FIXME(Qyriad): is this right?
|
||||
|
|
|
@ -176,5 +176,8 @@ foreach script : functional_tests_scripts
|
|||
env : {
|
||||
'MESON_BUILD_ROOT': meson.project_build_root(),
|
||||
},
|
||||
# some tests take 15+ seconds even on an otherwise idle machine, on a loaded machine
|
||||
# this can easily drive them to failure. give them more time, 5min rather than 30sec
|
||||
timeout : 300,
|
||||
)
|
||||
endforeach
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "test-session.hh"
|
||||
#include "util.hh"
|
||||
#include "tests/debug-char.hh"
|
||||
#include "escape-char.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -60,7 +60,7 @@ std::ostream & operator<<(std::ostream & os, ReplOutputParser::State s)
|
|||
void ReplOutputParser::transition(State new_state, char responsible_char, bool wasPrompt)
|
||||
{
|
||||
if constexpr (DEBUG_REPL_PARSER) {
|
||||
std::cerr << "transition " << new_state << " for " << DebugChar{responsible_char}
|
||||
std::cerr << "transition " << new_state << " for " << MaybeHexEscapedChar{responsible_char}
|
||||
<< (wasPrompt ? " [prompt]" : "") << "\n";
|
||||
}
|
||||
state = new_state;
|
||||
|
@ -118,7 +118,7 @@ bool TestSession::waitForPrompt()
|
|||
});
|
||||
|
||||
if constexpr (DEBUG_REPL_PARSER) {
|
||||
std::cerr << "raw " << DebugChar{buf[i]} << (wasEaten ? " [eaten]" : "") << "\n";
|
||||
std::cerr << "raw " << MaybeHexEscapedChar{buf[i]} << (wasEaten ? " [eaten]" : "") << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "cli-literate-parser.hh"
|
||||
#include "libexpr/print.hh"
|
||||
#include "debug-char.hh"
|
||||
#include "escape-char.hh"
|
||||
#include "types.hh"
|
||||
#include "util.hh"
|
||||
#include <ranges>
|
||||
|
@ -77,7 +77,7 @@ CLILiterateParser::CLILiterateParser(std::string prompt, size_t indent)
|
|||
void CLILiterateParser::feed(char c)
|
||||
{
|
||||
if constexpr (DEBUG_PARSER) {
|
||||
std::cout << stateDebug(state_) << " " << DebugChar{c} << "\n";
|
||||
std::cout << stateDebug(state_) << " " << MaybeHexEscapedChar{c} << "\n";
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
///@file
|
||||
#include <ostream>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
||||
struct DebugChar
|
||||
{
|
||||
char c;
|
||||
};
|
||||
|
||||
inline std::ostream & operator<<(std::ostream & s, DebugChar c)
|
||||
{
|
||||
boost::io::ios_flags_saver _ifs(s);
|
||||
|
||||
if (isprint(c.c)) {
|
||||
s << static_cast<char>(c.c);
|
||||
} else {
|
||||
s << std::hex << "0x" << (static_cast<unsigned int>(c.c) & 0xff);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
#include "terminal-code-eater.hh"
|
||||
#include "debug-char.hh"
|
||||
#include "escape-char.hh"
|
||||
#include <assert.h>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
|
@ -14,7 +14,7 @@ void TerminalCodeEater::feed(char c, std::function<void(char)> on_char)
|
|||
auto isIntermediateChar = [](char v) -> bool { return v >= 0x20 && v <= 0x2f; };
|
||||
auto isFinalChar = [](char v) -> bool { return v >= 0x40 && v <= 0x7e; };
|
||||
if constexpr (DEBUG_EATER) {
|
||||
std::cerr << "eater" << DebugChar{c} << "\n";
|
||||
std::cerr << "eater" << MaybeHexEscapedChar{c} << "\n";
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
|
@ -28,7 +28,7 @@ void TerminalCodeEater::feed(char c, std::function<void(char)> on_char)
|
|||
return;
|
||||
}
|
||||
if constexpr (DEBUG_EATER) {
|
||||
std::cerr << "eater uneat" << DebugChar{c} << "\n";
|
||||
std::cerr << "eater uneat" << MaybeHexEscapedChar{c} << "\n";
|
||||
}
|
||||
on_char(c);
|
||||
break;
|
||||
|
|
23
tests/unit/libutil/fmt.cc
Normal file
23
tests/unit/libutil/fmt.cc
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "fmt.hh"
|
||||
#include "ansicolor.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(HintFmt, arg_count)
|
||||
{
|
||||
// Single arg is treated as a literal string.
|
||||
ASSERT_EQ(HintFmt("%s").str(), "%s");
|
||||
|
||||
// Other strings format as expected:
|
||||
ASSERT_EQ(HintFmt("%s", 1).str(), ANSI_MAGENTA "1" ANSI_NORMAL);
|
||||
ASSERT_EQ(HintFmt("%1%", "hello").str(), ANSI_MAGENTA "hello" ANSI_NORMAL);
|
||||
|
||||
// Argument counts are detected at construction.
|
||||
ASSERT_THROW(HintFmt("%s %s", 1), boost::io::too_few_args);
|
||||
|
||||
ASSERT_THROW(HintFmt("%s", 1, 2), boost::io::too_many_args);
|
||||
}
|
||||
|
||||
}
|
|
@ -63,6 +63,7 @@ libutil_tester = executable(
|
|||
liblixutil,
|
||||
liblixexpr,
|
||||
liblixutil_test_support,
|
||||
nlohmann_json,
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -127,6 +128,7 @@ libstore_tester = executable(
|
|||
liblixutil,
|
||||
rapidcheck,
|
||||
gtest,
|
||||
nlohmann_json,
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -191,6 +193,7 @@ libexpr_tester = executable(
|
|||
rapidcheck,
|
||||
boehm,
|
||||
gtest,
|
||||
nlohmann_json,
|
||||
],
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in a new issue