packages.biu: migrate to process v2

This commit is contained in:
2025-08-01 10:32:14 +08:00
parent 2eb6f4ae67
commit 8f72efadd3
21 changed files with 291 additions and 109 deletions

6
flake.lock generated
View File

@@ -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": {

View 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;

View File

@@ -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;
}

View File

@@ -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}

View File

@@ -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)

View File

@@ -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 ];

View File

@@ -17,3 +17,4 @@
# include <biu/serialize.tpp>
# include <biu/glaze.tpp>
# include <range/v3/all.hpp>
# include <biu/process.tpp>

View File

@@ -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.

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View 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;
}

View 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;
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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),

View File

@@ -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" },

View File

@@ -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={

View File

@@ -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;
}

View File

@@ -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]));
});