mirror of
https://github.com/CHN-beta/nixos.git
synced 2026-01-12 04:19:22 +08:00
localPackages.biu: exec allow use parent process std{in,out,err}
This commit is contained in:
@@ -22,6 +22,8 @@ namespace biu
|
||||
using int128_t = __int128_t;
|
||||
using uint128_t = __uint128_t;
|
||||
|
||||
struct Empty {};
|
||||
|
||||
struct CaseInsensitiveStringLessComparator
|
||||
{
|
||||
template <typename String> constexpr bool operator()(const String& s1, const String& s2) const;
|
||||
@@ -64,11 +66,31 @@ namespace biu
|
||||
template <typename T, typename Fallback = void> using FallbackIfNoTypeDeclared
|
||||
= typename detail_::FallbackIfNoTypeDeclaredHelper<T, Fallback>::Type;
|
||||
|
||||
namespace detail_ { struct ExecResult { int exit_code; std::string stdout, stderr; }; }
|
||||
detail_::ExecResult exec
|
||||
namespace detail_
|
||||
{
|
||||
template <bool DirectStdout, bool DirectStderr> struct ExecResult
|
||||
{
|
||||
int exit_code;
|
||||
std::conditional_t<DirectStdout, Empty, std::string> stdout;
|
||||
std::conditional_t<DirectStderr, Empty, std::string> stderr;
|
||||
};
|
||||
template <bool DirectStdin, bool DirectStdout, bool DirectStderr>
|
||||
detail_::ExecResult<DirectStdout, DirectStderr> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
);
|
||||
}
|
||||
template <bool DirectStdin = false, bool DirectStdout = false, bool DirectStderr = false> requires (!DirectStdin)
|
||||
detail_::ExecResult<DirectStdout, DirectStderr> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin = {},
|
||||
std::map<std::string, std::string> extra_env = {}
|
||||
);
|
||||
template <bool DirectStdin = false, bool DirectStdout = false, bool DirectStderr = false> requires DirectStdin
|
||||
detail_::ExecResult<DirectStdout, DirectStderr> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::map<std::string, std::string> extra_env = {}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# pragma once
|
||||
# include <boost/functional/hash.hpp>
|
||||
# include <biu/common.hpp>
|
||||
# include <boost/process.hpp>
|
||||
|
||||
namespace biu::common
|
||||
{
|
||||
@@ -21,4 +22,56 @@ namespace biu::common
|
||||
[](char c1, char c2){return std::tolower(c1) < std::tolower(c2);}
|
||||
);
|
||||
}
|
||||
}
|
||||
template <bool directStdin, bool directStdout, bool directStderr> detail_::ExecResult<directStdout, directStderr> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{
|
||||
namespace bp = boost::process;
|
||||
bp::ipstream stdout_stream, stderr_stream;
|
||||
bp::opstream input_stream;
|
||||
auto&& stdout =
|
||||
[&]{ if constexpr (directStdout) return bp::std_out > ::stdout; else return bp::std_out > stdout_stream; }();
|
||||
auto&& stderr =
|
||||
[&]{ if constexpr (directStderr) return bp::std_err > ::stderr; else return bp::std_err > stderr_stream; }();
|
||||
auto&& input = [&]
|
||||
{
|
||||
if constexpr (directStdin) return bp::std_in < ::stdin;
|
||||
else if (stdin) return bp::std_in < input_stream; else return bp::std_in < bp::null;
|
||||
}();
|
||||
std::unique_ptr<bp::child> process;
|
||||
bp::environment env = boost::this_process::environment();
|
||||
for (const auto& [key, value] : extra_env) env[key] = value;
|
||||
process = std::make_unique<bp::child>(program.string(), bp::args(args), stdout, stderr, input, env);
|
||||
if (stdin) { input << *stdin; input.pipe().close(); }
|
||||
process->wait();
|
||||
return
|
||||
{
|
||||
process->exit_code(),
|
||||
[&]
|
||||
{
|
||||
if constexpr (directStdout) return std::string{std::istreambuf_iterator<char>{stdout.rdbuf()}, {}};
|
||||
else return Empty{};
|
||||
}(),
|
||||
[&]
|
||||
{
|
||||
if constexpr (directStderr) return std::string{std::istreambuf_iterator<char>{stderr.rdbuf()}, {}};
|
||||
else return Empty{};
|
||||
}()
|
||||
};
|
||||
}
|
||||
template <bool DirectStdin, bool DirectStdout, bool DirectStderr> requires (!DirectStdin)
|
||||
detail_::ExecResult<DirectStdout, DirectStderr> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{ return exec<DirectStdout, DirectStderr>(program, args, stdin, extra_env); }
|
||||
template <bool DirectStdin, bool DirectStdout, bool DirectStderr> requires DirectStdin
|
||||
detail_::ExecResult<DirectStdout, DirectStderr> exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{ return exec<DirectStdin, DirectStdout, DirectStderr>(program, args, {}, extra_env); }
|
||||
}
|
||||
|
||||
@@ -1,45 +1,9 @@
|
||||
# include <future>
|
||||
# include <utility>
|
||||
# include <biu.hpp>
|
||||
# include <boost/process.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
std::regex literals::operator""_re(const char* str, std::size_t len) { return std::regex{str, len}; }
|
||||
namespace common
|
||||
{
|
||||
void block_forever() { std::promise<void>().get_future().wait(); std::unreachable(); }
|
||||
detail_::ExecResult exec
|
||||
(
|
||||
std::filesystem::path program, std::vector<std::string> args, std::optional<std::string> stdin,
|
||||
std::map<std::string, std::string> extra_env
|
||||
)
|
||||
{
|
||||
namespace bp = boost::process;
|
||||
bp::ipstream stdout, stderr;
|
||||
bp::opstream input;
|
||||
std::unique_ptr<bp::child> process;
|
||||
bp::environment env = boost::this_process::environment();
|
||||
for (const auto& [key, value] : extra_env) env[key] = value;
|
||||
if (stdin)
|
||||
{
|
||||
process = std::make_unique<bp::child>
|
||||
(program.string(), bp::args(args), bp::std_out > stdout, bp::std_err > stderr,
|
||||
bp::std_in < input, env);
|
||||
input << *stdin;
|
||||
input.pipe().close();
|
||||
}
|
||||
else process = std::make_unique<bp::child>
|
||||
(program.string(), bp::args(args), bp::std_out > stdout, bp::std_err > stderr,
|
||||
bp::std_in < bp::null, env);
|
||||
process->wait();
|
||||
return
|
||||
{
|
||||
process->exit_code(),
|
||||
std::string{std::istreambuf_iterator<char>{stdout.rdbuf()}, {}},
|
||||
std::string{std::istreambuf_iterator<char>{stderr.rdbuf()}, {}}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace common { void block_forever() { std::promise<void>().get_future().wait(); std::unreachable(); } }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user