mirror of
https://github.com/CHN-beta/nixos.git
synced 2026-01-11 07:49:24 +08:00
packages.biu: migrate to process v2
This commit is contained in:
6
flake.lock
generated
6
flake.lock
generated
@@ -880,11 +880,11 @@
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1751630609,
|
||||
"narHash": "sha256-mJ1XnKiLnNapGSUwyGdFD8tmQTzuJm8z3qaFC27guqE=",
|
||||
"lastModified": 1753842094,
|
||||
"narHash": "sha256-1IAtQ0itZjT07XyUNfHJ4r8nO4+036T6scVUFs1NEko=",
|
||||
"owner": "CHN-beta",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b263408b62d74a1e7a298fc47135653a70c227aa",
|
||||
"rev": "2ebe9e65f6f1223450f58bf0197fcbce3fb9bf0f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
13
flake/lib/buildNixpkgsConfig/boost188.patch
Normal file
13
flake/lib/buildNixpkgsConfig/boost188.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/boost/process/v2/stdio.hpp b/boost/process/v2/stdio.hpp
|
||||
index 01d0216..4084e46 100644
|
||||
--- a/boost/process/v2/stdio.hpp
|
||||
+++ b/boost/process/v2/stdio.hpp
|
||||
@@ -184,7 +184,7 @@ struct process_io_binding
|
||||
process_io_binding & operator=(const process_io_binding &) = delete;
|
||||
|
||||
process_io_binding(process_io_binding && other) noexcept
|
||||
- : fd(other.fd), fd_needs_closing(other.fd), ec(other.ec)
|
||||
+ : fd(other.fd), fd_needs_closing(other.fd_needs_closing), ec(other.ec)
|
||||
{
|
||||
other.fd = target;
|
||||
other.fd_needs_closing = false;
|
||||
@@ -69,6 +69,7 @@ in platformConfig //
|
||||
patches = prev.patches or [] ++ [ ./root.patch ];
|
||||
cmakeFlags = prev.cmakeFlags ++ [ "-DCMAKE_CXX_STANDARD=23" ];
|
||||
});
|
||||
boost188 = prev.boost188.overrideAttrs (prev: { patches = prev.patches or [] ++ [ ./boost188.patch ]; });
|
||||
inherit (final.pkgs-2411) iio-sensor-proxy;
|
||||
inherit (final.pkgs-unstable) bees;
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ endif()
|
||||
|
||||
find_package(magic_enum REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS headers iostreams filesystem system process stacktrace_from_exception)
|
||||
# stacktrace_backtrace
|
||||
find_package(Boost REQUIRED COMPONENTS headers iostreams filesystem system process stacktrace_from_exception
|
||||
stacktrace_backtrace)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_path(NAMEOF_INCLUDE_DIR nameof.hpp REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
@@ -36,7 +36,7 @@ target_include_directories(biu PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_D
|
||||
${LIBBACKTRACE_INCLUDE_DIR} ${POCKETFFT_INCLUDE_DIR})
|
||||
target_link_libraries(biu PUBLIC magic_enum::magic_enum fmt::fmt Boost::headers Boost::iostreams Boost::filesystem
|
||||
range-v3::range-v3 Eigen3::Eigen HighFive TgBot::TgBot ${LIBBACKTRACE_LIBRARY} hdf5::hdf5 concurrencpp::concurrencpp
|
||||
yaml-cpp::yaml-cpp glaze::glaze Boost::process Boost::stacktrace_from_exception)
|
||||
yaml-cpp::yaml-cpp glaze::glaze Boost::process Boost::stacktrace_from_exception Boost::stacktrace_backtrace)
|
||||
target_compile_features(biu PUBLIC cxx_std_23)
|
||||
target_compile_options(biu PUBLIC -Wno-gnu-string-literal-operator-template)
|
||||
install(TARGETS biu EXPORT biuTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/biuTargets.cmake")
|
||||
find_package(magic_enum REQUIRED)
|
||||
find_package(fmt REQUIRED)
|
||||
find_package(Boost REQUIRED COMPONENTS headers iostreams filesystem system process stacktrace_from_exception)
|
||||
find_package(Boost REQUIRED COMPONENTS headers iostreams filesystem system process stacktrace_from_exception
|
||||
stacktrace_backtrace)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_path(NAMEOF_INCLUDE_DIR nameof.hpp REQUIRED)
|
||||
find_package(Eigen3 REQUIRED)
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
src = ./.;
|
||||
buildInputs =
|
||||
[
|
||||
magic-enum fmt boost range-v3 nameof zpp-bits eigen highfive tgbot-cpp libbacktrace hdf5
|
||||
concurrencpp pocketfft yaml-cpp glaze
|
||||
magic-enum fmt boost range-v3 nameof zpp-bits eigen libbacktrace hdf5
|
||||
concurrencpp pocketfft yaml-cpp glaze (highfive.override { inherit boost; }) (tgbot-cpp.override { inherit boost; })
|
||||
];
|
||||
propagatedBuildInputs = buildInputs;
|
||||
nativeBuildInputs = [ cmake ];
|
||||
|
||||
@@ -17,3 +17,4 @@
|
||||
# include <biu/serialize.tpp>
|
||||
# include <biu/glaze.tpp>
|
||||
# include <range/v3/all.hpp>
|
||||
# include <biu/process.tpp>
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace biu
|
||||
public: ValueType get(this auto&& self);
|
||||
public: operator ValueType(this auto&& self);
|
||||
|
||||
protected: template <bool Throw = false> auto lock_(this auto&& self, auto&& condition_function, auto timeout);
|
||||
protected: template <bool Throw> auto lock_(this auto&& self, auto&& condition_function, auto timeout);
|
||||
|
||||
// Apply a function to stored value.
|
||||
// Wait for some time (if provided) until condition funciton returns true (if provided)
|
||||
@@ -45,6 +45,7 @@ namespace biu
|
||||
// NoReturn: throw exception if timeout, ignore function result, and return *this, if true;
|
||||
// return bool or std::optional wrapped result of function, if false.
|
||||
// Useful when chaining multiple apply() calls.
|
||||
// timeout 只考虑 condition_function 的超时,不考虑锁本身的超时。
|
||||
public: template <bool NoReturn = false> decltype(auto) apply
|
||||
(this auto&& self, auto&& function, auto&& condition_function, auto&& timeout);
|
||||
public: template <bool NoReturn = false> decltype(auto) apply
|
||||
@@ -54,8 +55,7 @@ namespace biu
|
||||
// Wait until condition funciton returns true or *this, with an optional timeout
|
||||
public: template <bool NoReturn = false> decltype(auto) wait
|
||||
(this auto&& self, auto&& condition_function, auto timeout);
|
||||
public: template <bool NoReturn = false> decltype(auto) wait
|
||||
(this auto&& self, auto&& condition_function);
|
||||
public: decltype(auto) wait(this auto&& self, auto&& condition_function);
|
||||
|
||||
// Attain lock from outside when constructing, and release when destructing.
|
||||
// Throw: same effect as NoReturn.
|
||||
|
||||
@@ -41,8 +41,11 @@ namespace biu
|
||||
(this auto&& self, auto&& condition_function, auto timeout)
|
||||
{
|
||||
if constexpr (Nullptr<decltype(condition_function)>)
|
||||
{
|
||||
static_assert(Nullptr<decltype(timeout)>);
|
||||
return Guard<std::is_const_v<decltype(self)>>
|
||||
(std::unique_lock{self.Mutex_}, std::experimental::make_observer(&self), {});
|
||||
}
|
||||
else if constexpr (Nullptr<decltype(timeout)>)
|
||||
{
|
||||
std::unique_lock lock(self.Mutex_);
|
||||
@@ -70,28 +73,35 @@ namespace biu
|
||||
using function_return_type = std::invoke_result_t<decltype(function), MoveQualifiers<decltype(self), ValueType>>;
|
||||
auto&& lock = std::forward<decltype(self)>(self).template lock_<NoReturn>
|
||||
(std::forward<decltype(condition_function)>(condition_function), timeout);
|
||||
// 如果得到的是 optional
|
||||
// 如果 lock 是 optional
|
||||
if constexpr (SpecializationOf<std::remove_cvref_t<decltype(lock)>, std::optional>)
|
||||
// 如果超时了,返回 false 或者对应的 nullopt
|
||||
// 如果超时了,这时 NoReturn 一定是 false,返回 false 或者对应的 nullopt
|
||||
if (!lock)
|
||||
{
|
||||
static_assert(!NoReturn);
|
||||
if constexpr (std::is_void_v<function_return_type>) return false;
|
||||
else return std::optional<function_return_type>();
|
||||
}
|
||||
// 否则,执行函数
|
||||
else
|
||||
// 如果函数本身返回 void,则返回 true 或者 *this
|
||||
if constexpr (std::is_void_v<function_return_type>)
|
||||
{
|
||||
std::forward<decltype(function)>(function)
|
||||
(std::forward<MoveQualifiers<decltype(self), ValueType>>(self.Value_));
|
||||
// 如果函数本身返回 void 并且不可能超时,返回 *this,否则返回 true
|
||||
if constexpr (Nullptr<decltype(condition_function)> || Nullptr<decltype(timeout)>)
|
||||
return std::forward<decltype(self)>(self);
|
||||
// 如果要求不返回结果,则返回 *this
|
||||
if constexpr (NoReturn) return std::forward<decltype(self)>(self);
|
||||
// 否则,返回 true
|
||||
else return true;
|
||||
}
|
||||
// 否则,返回函数的返回值或者 std::optional 包装的结果
|
||||
else
|
||||
{
|
||||
auto&& result = std::forward<decltype(function)>(function)
|
||||
(std::forward<MoveQualifiers<decltype(self), ValueType>>(self.Value_));
|
||||
return std::make_optional(std::forward<decltype(result)>(result));
|
||||
if constexpr (NoReturn)
|
||||
return std::forward<decltype(self)>(self);
|
||||
else return std::make_optional(std::forward<decltype(result)>(result));
|
||||
}
|
||||
// 否则,说明不可能超时,返回函数的返回值或者 *this
|
||||
else
|
||||
@@ -125,15 +135,15 @@ namespace biu
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::wait
|
||||
(this auto&& self, auto&& condition_function, auto timeout)
|
||||
{
|
||||
auto result = std::forward<decltype(self)>(self).template lock_<NoReturn>
|
||||
auto&& result = std::forward<decltype(self)>(self).template lock_<NoReturn>
|
||||
(std::forward<decltype(condition_function)>(condition_function), timeout);
|
||||
if constexpr (SpecializationOf<decltype(result), std::optional>) return result.has_value();
|
||||
else return std::forward<decltype(result)>(result);
|
||||
else return std::forward<decltype(self)>(self);
|
||||
}
|
||||
template <DecayedType ValueType> template <bool NoReturn> decltype(auto) Atomic<ValueType>::wait
|
||||
template <DecayedType ValueType> decltype(auto) Atomic<ValueType>::wait
|
||||
(this auto&& self, auto&& condition_function)
|
||||
{
|
||||
return std::forward<decltype(self)>(self).template wait<NoReturn>
|
||||
return std::forward<decltype(self)>(self).template wait<false>
|
||||
(std::forward<decltype(condition_function)>(condition_function), nullptr);
|
||||
}
|
||||
|
||||
|
||||
@@ -74,27 +74,6 @@ namespace biu
|
||||
template <typename T, typename Fallback = void> using FallbackIfNoTypeDeclared
|
||||
= typename detail_::FallbackIfNoTypeDeclaredHelper<T, Fallback>::Type;
|
||||
|
||||
namespace detail_
|
||||
{
|
||||
struct ExecMode { bool DirectStdin = false, DirectStdout = false, DirectStderr = false, SearchPath = false; };
|
||||
template <ExecMode Mode> struct ExecResult
|
||||
{
|
||||
int ExitCode;
|
||||
std::conditional_t<Mode.DirectStdout, Empty, std::string> Stdout;
|
||||
std::conditional_t<Mode.DirectStderr, Empty, std::string> Stderr;
|
||||
operator bool() const;
|
||||
};
|
||||
template <ExecMode Mode> struct ExecInput
|
||||
{
|
||||
std::conditional_t<Mode.SearchPath, std::string, std::filesystem::path> Program;
|
||||
std::vector<std::string> Args;
|
||||
std::conditional_t<Mode.DirectStdin, Empty, std::string> Stdin = {};
|
||||
std::map<std::string, std::string> ExtraEnv = {};
|
||||
std::optional<std::chrono::milliseconds> Timeout;
|
||||
};
|
||||
}
|
||||
template <detail_::ExecMode Mode = {}> detail_::ExecResult<Mode> exec(detail_::ExecInput<Mode> input);
|
||||
|
||||
template <typename Array> concurrencpp::generator<std::pair<Array, std::size_t>> sequence(Array from, Array to);
|
||||
template <typename Array> concurrencpp::generator<std::pair<Array, std::size_t>> sequence(Array to);
|
||||
|
||||
@@ -120,9 +99,11 @@ namespace biu
|
||||
constexpr detail_::ToLvalueHelper toLvalue;
|
||||
|
||||
template <typename Function, typename T, typename... Ts> void for_each(Function&& function, T&& arg, Ts&&... args);
|
||||
|
||||
template <typename T> decltype(auto) perfect_return(T&& obj);
|
||||
}
|
||||
using common::hash, common::unused, common::block_forever, common::is_interactive, common::env, common::int128_t,
|
||||
common::uint128_t, common::Empty, common::CaseInsensitiveStringLessComparator, common::RemoveMemberPointer,
|
||||
common::MoveQualifiers, common::FallbackIfNoTypeDeclared, common::exec, common::sequence, common::read,
|
||||
common::toLvalue, common::for_each;
|
||||
common::MoveQualifiers, common::FallbackIfNoTypeDeclared, common::sequence, common::read,
|
||||
common::toLvalue, common::for_each, common::perfect_return;
|
||||
}
|
||||
|
||||
@@ -75,4 +75,18 @@ namespace biu::common
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> decltype(auto) perfect_return(T&& obj)
|
||||
{
|
||||
// 不允许返回右值引用
|
||||
static_assert(!std::is_rvalue_reference_v<T>);
|
||||
// 左值引用则返回左值引用
|
||||
if constexpr (std::is_lvalue_reference_v<T>) return (obj);
|
||||
// 否则,假定可以移动,并返回值
|
||||
else
|
||||
{
|
||||
static_assert(std::is_move_constructible_v<std::remove_reference_t<T>>);
|
||||
return std::move(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
36
packages/biu/include/biu/process.hpp
Normal file
36
packages/biu/include/biu/process.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
# pragma once
|
||||
# include <biu/common.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
namespace process
|
||||
{
|
||||
enum class IoType { Direct, Close, String };
|
||||
namespace detail_
|
||||
{
|
||||
struct ExecMode
|
||||
{
|
||||
bool SearchPath = false, ModifyEnv = false, Timeout = false;
|
||||
IoType Stdin = IoType::Direct, Stdout = IoType::Direct, Stderr = IoType::Direct;
|
||||
};
|
||||
template <ExecMode Mode> struct ExecResult
|
||||
{
|
||||
int ExitCode;
|
||||
std::conditional_t<Mode.Stdout == IoType::String, std::string, Empty> Stdout;
|
||||
std::conditional_t<Mode.Stderr == IoType::String, std::string, Empty> Stderr;
|
||||
operator bool() const;
|
||||
};
|
||||
template <ExecMode Mode> struct ExecInput
|
||||
{
|
||||
std::conditional_t<Mode.SearchPath, std::string, std::filesystem::path> Program;
|
||||
std::vector<std::string> Args;
|
||||
std::conditional_t<Mode.Stdin == IoType::String, std::string, Empty> Stdin = {};
|
||||
std::conditional_t<Mode.ModifyEnv, std::map<std::string, std::string>, Empty> ExtraEnv = {};
|
||||
std::conditional_t<Mode.Timeout, std::chrono::milliseconds, Empty> Timeout = {};
|
||||
};
|
||||
}
|
||||
template <detail_::ExecMode Mode = {}, typename... Ts>
|
||||
detail_::ExecResult<Mode> exec(detail_::ExecInput<Mode> input, Ts&&... args);
|
||||
}
|
||||
using process::exec, process::IoType;
|
||||
}
|
||||
178
packages/biu/include/biu/process.tpp
Normal file
178
packages/biu/include/biu/process.tpp
Normal file
@@ -0,0 +1,178 @@
|
||||
# pragma once
|
||||
# include <biu/process.hpp>
|
||||
# include <biu/logger.hpp>
|
||||
# include <biu/format.tpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <boost/asio.hpp>
|
||||
|
||||
namespace biu::process
|
||||
{
|
||||
template <detail_::ExecMode Mode> detail_::ExecResult<Mode>::operator bool() const { return ExitCode == 0; }
|
||||
|
||||
template <detail_::ExecMode Mode, typename... Ts> detail_::ExecResult<Mode> exec
|
||||
(detail_::ExecInput<Mode> input, Ts&&... args)
|
||||
{
|
||||
Logger::Guard log;
|
||||
namespace bp = boost::process;
|
||||
boost::asio::io_context context;
|
||||
detail_::ExecResult<Mode> result;
|
||||
using namespace biu::literals;
|
||||
|
||||
// 进程是在创建时就开始运行的,而不是在 io_context.run() 时才开始运行
|
||||
|
||||
// seach actual program
|
||||
boost::filesystem::path actual_program = [&]
|
||||
{
|
||||
if constexpr (Mode.SearchPath) return bp::environment::find_executable(input.Program);
|
||||
else return input.Program.string();
|
||||
}();
|
||||
log.debug("Searching for program: {} -> {}"_f(input.Program, actual_program.string()));
|
||||
|
||||
// env
|
||||
auto env = [&]
|
||||
{
|
||||
if constexpr (Mode.ModifyEnv)
|
||||
{
|
||||
auto current = bp::environment::current();
|
||||
std::unordered_map<bp::environment::key, bp::environment::value> env
|
||||
(current.begin(), current.end());
|
||||
for (const auto& [key, value] : input.ExtraEnv) env[key] = value;
|
||||
}
|
||||
else return bp::environment::current();
|
||||
}();
|
||||
log();
|
||||
|
||||
// prepare io pipes
|
||||
std::unique_ptr<boost::asio::writable_pipe> stdin_pipe;
|
||||
std::unique_ptr<boost::asio::readable_pipe> stdout_pipe, stderr_pipe;
|
||||
std::function<void(boost::asio::readable_pipe& p, std::string& result)> read_some =
|
||||
[&read_some](auto& p, auto& result)
|
||||
{
|
||||
auto buffer = std::make_shared<std::array<char, 1024>>();
|
||||
p.async_read_some
|
||||
(
|
||||
boost::asio::buffer(*buffer),
|
||||
[&, buffer](const boost::system::error_code& ec, std::size_t len)
|
||||
{
|
||||
Logger::Guard log;
|
||||
if (!ec) { result.append(buffer->data(), len); read_some(p, result); log.debug("read {}"_f(len)); }
|
||||
else log.debug("Error reading from pipe: {} {}"_f(ec.value(), ec.message()));
|
||||
}
|
||||
);
|
||||
};
|
||||
std::function<void(boost::asio::writable_pipe& p, std::string& result)> write_some =
|
||||
[&write_some](auto& p, auto& result)
|
||||
{
|
||||
if (result.empty()) { p.close(); return; }
|
||||
auto buffer = std::make_shared<std::array<char, 1024>>();
|
||||
std::copy(result.begin(), result.end(), buffer->begin());
|
||||
p.async_write_some
|
||||
(
|
||||
boost::asio::buffer(*buffer),
|
||||
[&, buffer](const auto& ec, std::size_t len)
|
||||
{
|
||||
Logger::Guard log;
|
||||
if (!ec) { result.erase(0, len); write_some(p, result); log.debug("write {}"_f(len)); }
|
||||
else log.debug("Error reading from pipe: {} {}"_f(ec.value(), ec.message()));
|
||||
}
|
||||
);
|
||||
};
|
||||
bp::process_stdio stdio
|
||||
{
|
||||
.in = [&] -> decltype(auto)
|
||||
{
|
||||
if constexpr (Mode.Stdin == IoType::Close) return nullptr;
|
||||
else if constexpr (Mode.Stdin == IoType::Direct)
|
||||
return decltype(bp::process_stdio::in)();
|
||||
else if constexpr (Mode.Stdin == IoType::String)
|
||||
{
|
||||
stdin_pipe = std::make_unique<boost::asio::writable_pipe>(context);
|
||||
write_some(*stdin_pipe, input.Stdin);
|
||||
return (*stdin_pipe);
|
||||
}
|
||||
else std::unreachable();
|
||||
}(),
|
||||
.out = [&] -> decltype(auto)
|
||||
{
|
||||
if constexpr (Mode.Stdout == IoType::Close) return nullptr;
|
||||
else if constexpr (Mode.Stdout == IoType::Direct)
|
||||
return decltype(bp::process_stdio::out)();
|
||||
else if constexpr (Mode.Stdout == IoType::String)
|
||||
{
|
||||
stdout_pipe = std::make_unique<boost::asio::readable_pipe>(context);
|
||||
read_some(*stdout_pipe, result.Stdout);
|
||||
return (*stdout_pipe);
|
||||
}
|
||||
else std::unreachable();
|
||||
}(),
|
||||
.err = [&] -> decltype(auto)
|
||||
{
|
||||
if constexpr (Mode.Stderr == IoType::Close) return nullptr;
|
||||
else if constexpr (Mode.Stderr == IoType::Direct)
|
||||
return decltype(bp::process_stdio::err)();
|
||||
else if constexpr (Mode.Stderr == IoType::String)
|
||||
{
|
||||
stderr_pipe = std::make_unique<boost::asio::readable_pipe>(context);
|
||||
read_some(*stderr_pipe, result.Stderr);
|
||||
return (*stderr_pipe);
|
||||
}
|
||||
else std::unreachable();
|
||||
}()
|
||||
};
|
||||
log();
|
||||
|
||||
// start process
|
||||
if constexpr (Mode.Timeout)
|
||||
{
|
||||
boost::asio::steady_timer timeout{context, input.Timeout};
|
||||
boost::asio::cancellation_signal sig;
|
||||
Atomic<bool> finished{false};
|
||||
Logger::try_exec([&]
|
||||
{
|
||||
auto proc = bp::process
|
||||
(context, actual_program, input.Args, std::move(stdio), std::move(env), std::forward<Ts>(args)...);
|
||||
bp::async_execute
|
||||
(
|
||||
std::move(proc),
|
||||
boost::asio::bind_cancellation_slot
|
||||
(
|
||||
sig.slot(),
|
||||
[&](bp::v2::error_code ec, int exit_code)
|
||||
{
|
||||
result.ExitCode = exit_code;
|
||||
timeout.cancel();
|
||||
finished = true;
|
||||
}
|
||||
)
|
||||
);
|
||||
timeout.expires_after(input.Timeout);
|
||||
timeout.async_wait([&](auto ec)
|
||||
{
|
||||
if (ec) return;
|
||||
sig.emit(boost::asio::cancellation_type::partial);
|
||||
timeout.expires_after(input.Timeout);
|
||||
timeout.async_wait
|
||||
([&](auto ec) { if (!ec) sig.emit(boost::asio::cancellation_type::terminal); });
|
||||
});
|
||||
context.run();
|
||||
finished.wait([](auto& v) { return v; });
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto thread = std::thread([&]
|
||||
{
|
||||
Logger::try_exec([&]
|
||||
{
|
||||
auto proc = bp::process
|
||||
(context, actual_program, input.Args, std::move(stdio), std::move(env), std::forward<Ts>(args)...);
|
||||
proc.wait();
|
||||
result.ExitCode = proc.exit_code();
|
||||
});
|
||||
});
|
||||
context.run();
|
||||
thread.join();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,6 @@
|
||||
# include <cstdio>
|
||||
# define BIU_INTERNAL
|
||||
# include <biu.hpp>
|
||||
# include <boost/process.hpp>
|
||||
# include <boost/preprocessor.hpp>
|
||||
|
||||
namespace biu
|
||||
{
|
||||
@@ -19,56 +17,6 @@ namespace biu
|
||||
else return value;
|
||||
}
|
||||
|
||||
template <detail_::ExecMode Mode> detail_::ExecResult<Mode>::operator bool() const { return ExitCode == 0; }
|
||||
|
||||
template <detail_::ExecMode Mode> detail_::ExecResult<Mode> exec(detail_::ExecInput<Mode> input)
|
||||
{
|
||||
// TODO: switch to v2
|
||||
namespace bp = boost::process;
|
||||
|
||||
// decide input/output format, prepare environment, seach actual program
|
||||
bp::ipstream stdout_stream, stderr_stream;
|
||||
bp::opstream input_stream;
|
||||
auto&& stdin_format = [&]
|
||||
{ if constexpr (Mode.DirectStdin) return bp::std_in < stdin; else return bp::std_in < input_stream; }();
|
||||
auto&& stdout_format = [&]
|
||||
{ if constexpr (Mode.DirectStdout) return bp::std_out > stdout; else return bp::std_out > stdout_stream; }();
|
||||
auto&& stderr_format = [&]
|
||||
{ if constexpr (Mode.DirectStderr) return bp::std_err > stderr; else return bp::std_err > stderr_stream; }();
|
||||
auto&& actual_program = [&]
|
||||
{
|
||||
if constexpr (Mode.SearchPath) return bp::search_path(input.Program);
|
||||
else return input.Program.string();
|
||||
}();
|
||||
bp::environment env = boost::this_process::environment();
|
||||
for (const auto& [key, value] : input.ExtraEnv) env[key] = value;
|
||||
|
||||
// start
|
||||
auto process = bp::child
|
||||
(actual_program, bp::args(input.Args), stdout_format, stderr_format, stdin_format, env);
|
||||
if constexpr (!Mode.DirectStdin) { input_stream << input.Stdin; input_stream.pipe().close(); }
|
||||
|
||||
// wait for exit
|
||||
if (input.Timeout) { if (!process.wait_for(*input.Timeout)) process.terminate(); }
|
||||
else process.wait();
|
||||
|
||||
// collect output
|
||||
detail_::ExecResult<Mode> result;
|
||||
result.ExitCode = process.exit_code();
|
||||
if constexpr (!Mode.DirectStdout) result.Stdout = {std::istreambuf_iterator<char>{stdout_stream.rdbuf()}, {}};
|
||||
if constexpr (!Mode.DirectStderr) result.Stderr = {std::istreambuf_iterator<char>{stderr_stream.rdbuf()}, {}};
|
||||
return result;
|
||||
}
|
||||
|
||||
# define BIU_EXEC_PRED(r, i) BOOST_PP_NOT_EQUAL(i, 16)
|
||||
# define BIU_EXEC_OP(r, i) BOOST_PP_INC(i)
|
||||
# define BIU_EXEC_MACRO(r, i) \
|
||||
namespace detail_ \
|
||||
{ constexpr ExecMode ExecMode##i {(i & 1) != 0, (i & 2) != 0, (i & 4) != 0, (i & 8) != 0}; } \
|
||||
template detail_::ExecResult<detail_::ExecMode##i>::operator bool() const; \
|
||||
template detail_::ExecResult<detail_::ExecMode##i> \
|
||||
exec<detail_::ExecMode##i>(detail_::ExecInput<detail_::ExecMode##i>);
|
||||
BOOST_PP_FOR(0, BIU_EXEC_PRED, BIU_EXEC_OP, BIU_EXEC_MACRO)
|
||||
template<> std::vector<std::byte> read<std::byte>(const std::filesystem::path& path)
|
||||
{
|
||||
auto length = std::filesystem::file_size(path);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
int main()
|
||||
{
|
||||
using namespace biu::literals;
|
||||
auto result = biu::exec<{.SearchPath = true}>({.Program = "sleep", .Args = {"10"}, .Timeout = 3s});
|
||||
biu::Logger::Guard log;
|
||||
auto result = biu::exec<{.SearchPath = true, .Timeout = true}>({.Program = "sleep", .Args = {"10"}, .Timeout = 3s});
|
||||
std::cout << "{}\n"_f(result.ExitCode);
|
||||
assert(!result);
|
||||
}
|
||||
|
||||
@@ -76,9 +76,8 @@ inputs: rec
|
||||
# TODO: report glaze bug to upstream
|
||||
inherit (inputs.pkgs.pkgs-2411) glaze;
|
||||
stdenv = inputs.pkgs.clang18Stdenv;
|
||||
boost = inputs.pkgs.boost187;
|
||||
# boost = (inputs.pkgs.boost188.override { extraB2Args = [ "boost.stacktrace.backtrace=on" ]; }).overrideAttrs
|
||||
# (prev: { buildInputs = prev.buildInputs ++ [(inputs.pkgs.libbacktrace.override { enableStatic = true; })]; });
|
||||
boost = (inputs.pkgs.boost188.override { extraB2Args = [ "boost.stacktrace.backtrace=on" ]; }).overrideAttrs
|
||||
(prev: { buildInputs = prev.buildInputs ++ [(inputs.pkgs.libbacktrace.override { enableStatic = true; })]; });
|
||||
fmt = inputs.pkgs.fmt_11.overrideAttrs (prev: { patches = prev.patches or [] ++ [ ./biu/fmt.patch ]; });
|
||||
};
|
||||
hpcstat = inputs.pkgs.callPackage ./hpcstat
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace hpcstat::disk
|
||||
{ std::cerr << "HPCSTAT_DATADIR not set\n"; return false; }
|
||||
else if
|
||||
(
|
||||
auto result = biu::exec<{.DirectStdout = true, .DirectStderr = true}>
|
||||
auto result = biu::exec
|
||||
({
|
||||
// duc index -d ./duc.db -p ~
|
||||
"{}/duc"_f(*ducbindir),
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace hpcstat::lfs
|
||||
{
|
||||
if
|
||||
(
|
||||
auto result = biu::exec<{.SearchPath = true}>
|
||||
auto result = biu::exec<{.SearchPath = true, .ModifyEnv = true}>
|
||||
({
|
||||
.Program="bjobs",
|
||||
.Args={ "-a", "-o", "jobid submit_time stat cpu_used job_name", "-json" },
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace hpcstat::ssh
|
||||
return std::nullopt;
|
||||
else if
|
||||
(
|
||||
auto output = biu::exec
|
||||
auto output = biu::exec<{.Timeout = true}>
|
||||
({.Program=std::filesystem::path(*sshbindir) / "ssh-add", .Args{ "-l" }, .Timeout=10s});
|
||||
!output
|
||||
)
|
||||
@@ -41,7 +41,7 @@ namespace hpcstat::ssh
|
||||
return std::nullopt;
|
||||
else if
|
||||
(
|
||||
auto output = biu::exec
|
||||
auto output = biu::exec<.Stdin = biu::IoType::String, .Timeout = true>
|
||||
({
|
||||
.Program=std::filesystem::path(*sshbindir) / "ssh-keygen",
|
||||
.Args={
|
||||
@@ -69,7 +69,7 @@ namespace hpcstat::ssh
|
||||
bf::create_directories(tempdir);
|
||||
auto signaturefile = tempdir / "signature";
|
||||
std::ofstream(signaturefile) << signature;
|
||||
auto result = biu::exec
|
||||
auto result = biu::exec<.Stdin = biu::IoType::String, .Timeout = true>
|
||||
({
|
||||
.Program=std::filesystem::path(*sshbindir) / "ssh-keygen",
|
||||
.Args={
|
||||
|
||||
@@ -149,7 +149,7 @@ int main()
|
||||
catch (...) {}
|
||||
// 提交任务
|
||||
boost::replace_all(State.SubmitCommand, "\n", " ");
|
||||
biu::exec<{.DirectStdout = true, .DirectStderr = true, .SearchPath = true}>
|
||||
biu::exec<{.SearchPath = true}>
|
||||
({"sh", { "-c", State.SubmitCommand }});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -55,8 +55,7 @@ vm force-reboot <vm>
|
||||
if (!config.vm.contains(uid)) throw std::runtime_error("No VM found for current user");
|
||||
if (!config.vm[uid].contains(args[1]))
|
||||
throw std::runtime_error("VM {} is not owned by current user"_f(args[1]));
|
||||
biu::exec<{.DirectStdout = true, .DirectStderr = true, .SearchPath = false}>
|
||||
({config.virsh, { vm_to_virsh[args[0]], args[1] }});
|
||||
biu::exec({config.virsh, { vm_to_virsh[args[0]], args[1] }});
|
||||
}
|
||||
else throw std::runtime_error("unknown command: {}"_f(args[0]));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user