diff options
-rw-r--r-- | meson.build | 7 | ||||
-rw-r--r-- | src/build-remote/build-remote.cc | 47 | ||||
-rw-r--r-- | src/libcmd/meson.build | 14 | ||||
-rw-r--r-- | src/libexpr/flake/meson.build | 8 | ||||
-rw-r--r-- | src/libexpr/meson.build | 37 | ||||
-rw-r--r-- | src/libexpr/print.cc | 2 | ||||
-rw-r--r-- | src/libexpr/print.hh | 2 | ||||
-rw-r--r-- | src/libmain/meson.build | 14 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 9 | ||||
-rw-r--r-- | src/libstore/meson.build | 30 | ||||
-rw-r--r-- | src/libutil/fmt.hh | 177 | ||||
-rw-r--r-- | src/libutil/logging.hh | 4 | ||||
-rw-r--r-- | src/libutil/meson.build | 1 | ||||
-rw-r--r-- | tests/functional/meson.build | 3 | ||||
-rw-r--r-- | tests/unit/libutil/fmt.cc | 23 |
15 files changed, 243 insertions, 135 deletions
diff --git a/meson.build b/meson.build index 556712c34..a4c2bbc14 100644 --- a/meson.build +++ b/meson.build @@ -244,13 +244,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', ) diff --git a/src/build-remote/build-remote.cc b/src/build-remote/build-remote.cc index e2ada70cd..f7a159829 100644 --- a/src/build-remote/build-remote.cc +++ b/src/build-remote/build-remote.cc @@ -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(); - - for (auto & m : machines) - error - % concatStringsSep<StringSet>(", ", m.systemTypes) - % m.maxJobs - % concatStringsSep<StringSet>(", ", m.supportedFeatures) - % concatStringsSep<StringSet>(", ", m.mandatoryFeatures); + std::string machinesFormatted; + + 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()); diff --git a/src/libcmd/meson.build b/src/libcmd/meson.build index e033bb1cd..c3782723b 100644 --- a/src/libcmd/meson.build +++ b/src/libcmd/meson.build @@ -56,3 +56,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(), + }, +) diff --git a/src/libexpr/flake/meson.build b/src/libexpr/flake/meson.build new file mode 100644 index 000000000..3ecc30f4e --- /dev/null +++ b/src/libexpr/flake/meson.build @@ -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', +) diff --git a/src/libexpr/meson.build b/src/libexpr/meson.build index 2e810f4c9..7c0555f8f 100644 --- a/src/libexpr/meson.build +++ b/src/libexpr/meson.build @@ -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, @@ -152,3 +159,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(), + }, +) diff --git a/src/libexpr/print.cc b/src/libexpr/print.cc index 19ef6f8aa..43e366d08 100644 --- a/src/libexpr/print.cc +++ b/src/libexpr/print.cc @@ -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; diff --git a/src/libexpr/print.hh b/src/libexpr/print.hh index 7ddda81b8..94cb11ca7 100644 --- a/src/libexpr/print.hh +++ b/src/libexpr/print.hh @@ -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); } diff --git a/src/libmain/meson.build b/src/libmain/meson.build index 54326c305..3f50b158d 100644 --- a/src/libmain/meson.build +++ b/src/libmain/meson.build @@ -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(), + }, +) diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 29081244f..db3934d5e 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -548,6 +548,15 @@ void LocalStore::openDB(State & state, bool create) sqlite3_exec(db, ("pragma main.journal_mode = " + mode + ";").c_str(), 0, 0, 0) != SQLITE_OK) SQLiteError::throw_(db, "setting journal mode"); + if (mode == "wal" ) { + /* persist the WAL files when the DB connection is closed. + * This allows for read-only connections without any write permissions + * on the state directory to succeed on a closed database. */ + int enable = 1; + if (sqlite3_file_control(db, NULL, SQLITE_FCNTL_PERSIST_WAL, &enable) != SQLITE_OK) + SQLiteError::throw_(db, "setting persistent WAL mode"); + } + /* Increase the auto-checkpoint interval to 40000 pages. This seems enough to ensure that instantiating the NixOS system derivation is done in a single fsync(). */ diff --git a/src/libstore/meson.build b/src/libstore/meson.build index 33e475f70..29dbc5e70 100644 --- a/src/libstore/meson.build +++ b/src/libstore/meson.build @@ -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', @@ -157,8 +166,7 @@ endforeach libstore = library( 'nixstore', - schema_sql_gen, - ca_specific_schema_gen, + libstore_generated_headers, libstore_sources, dependencies : [ libarchive, @@ -186,3 +194,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(), + }, +) diff --git a/src/libutil/fmt.hh b/src/libutil/fmt.hh index 84a3e3e11..c68591b72 100644 --- a/src/libutil/fmt.hh +++ b/src/libutil/fmt.hh @@ -5,43 +5,94 @@ #include <string> #include "ansicolor.hh" - namespace nix { -namespace { /** - * A helper for writing `boost::format` expressions. - * - * These are equivalent: + * Values wrapped in this struct are printed in magenta. * - * ``` - * formatHelper(formatter, a_0, ..., a_n) - * formatter % a_0 % ... % a_n - * ``` + * 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_MAGENTA << y.value << ANSI_NORMAL; +} + +/** + * Values wrapped in this class are printed without coloring. * - * With a single argument, `formatHelper(s)` is a no-op. + * By default, arguments to `HintFmt` are printed in magenta (see `Magenta`). */ -template<class F> -inline void formatHelper(F & f) -{ } +template<class T> +struct Uncolored +{ + Uncolored(const T & s) : value(s) {} + const T & value; +}; -template<class F, typename T, typename... Args> -inline void formatHelper(F & f, const T & x, const Args & ... args) +template<class T> +std::ostream & operator<<(std::ostream & out, const Uncolored<T> & y) { - // Interpolate one argument and then recurse. - formatHelper(f % x, args...); + 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,53 +128,15 @@ 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) - { } - - template<typename... Args> - HintFmt(boost::format && fmt, const Args & ... args) - : fmt(std::move(fmt)) { - setExceptions(fmt); - formatHelper(*this, args...); } - template<class T> - HintFmt & operator%(const T & value) - { - fmt % Magenta(value); - return *this; - } + HintFmt(const HintFmt & hf) : fmt(hf.fmt) {} - template<class T> - HintFmt & operator%(const Uncolored<T> & value) + template<typename... Args> + HintFmt(boost::format && fmt, const Args &... args) + : fmt(fmt_internal::HintFmt(std::move(fmt), args...).into_format()) { - fmt % value.value; - return *this; + if (this->fmt.remaining_args() != 0) { + throw boost::io::too_few_args( + this->fmt.bound_args() + this->fmt.fed_args(), this->fmt.expected_args() + ); + } } std::string str() const diff --git a/src/libutil/logging.hh b/src/libutil/logging.hh index dc6f53d77..7b7f69833 100644 --- a/src/libutil/logging.hh +++ b/src/libutil/logging.hh @@ -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...) \ diff --git a/src/libutil/meson.build b/src/libutil/meson.build index cdfda3cf5..c37e7ae68 100644 --- a/src/libutil/meson.build +++ b/src/libutil/meson.build @@ -36,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', diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 53dc21af5..0ea0e4df5 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -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 diff --git a/tests/unit/libutil/fmt.cc b/tests/unit/libutil/fmt.cc new file mode 100644 index 000000000..383a688d3 --- /dev/null +++ b/tests/unit/libutil/fmt.cc @@ -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); +} + +} |