2
0
mirror of https://github.com/boostorg/process.git synced 2026-01-26 06:42:26 +00:00

Compare commits

...

30 Commits

Author SHA1 Message Date
Klemens
9edacbdb98 ec fix for search_path with std::filesystem.
closes #287.
2023-01-04 08:11:22 +08:00
Klemens Morgenstern
a9f083f45c Update process.cpp 2022-12-13 13:50:03 +08:00
Klemens Morgenstern
b5ab94c932 Disabled some tests for freebsd & added interrupt handling to osx test. 2022-12-13 10:45:47 +08:00
sdarwin
9ceda79fa2 Update metadata 2022-12-13 09:22:13 +08:00
Klemens Morgenstern
68cbeae491 Typo fix. 2022-12-13 09:19:45 +08:00
Klemens Morgenstern
ae778f36a8 Include fixes. 2022-11-11 11:14:46 +08:00
Sam Darwin
0671e4a133 Drone: update freebsd jobs (#274) 2022-11-01 10:40:04 +08:00
Klemens Morgenstern
cbf944c57b using scope-exit limit group_wait. 2022-11-01 03:08:12 +08:00
Klemens Morgenstern
5f2b8c53f4 Disabled limit_fd for freebsd. 2022-11-01 02:58:31 +08:00
Klemens Morgenstern
dac3614a38 group wait test on_scope exit fix. 2022-10-31 12:25:30 +08:00
Klemens Morgenstern
2fc71ca0a3 Disabled pdfork by default, bc of asio errors. 2022-10-31 11:23:49 +08:00
Klemens Morgenstern
404682d75d Increased timeout for sporadically failing test. 2022-10-31 11:21:48 +08:00
Klemens Morgenstern
9fbbdc3421 Merge pull request #276 from Flamefire/patch-1
Update .drone.star
2022-10-23 11:21:09 +08:00
Alexander Grund
3df0009a2f Update .drone.star
Remove the `image` param which is superflous, misleading and may become an error. See https://github.com/boostorg/boost-ci/pull/189

[skip ci]
2022-10-22 11:26:04 +02:00
Klemens Morgenstern
ecb384b253 Improved error message for OSX. 2022-10-21 12:03:31 +08:00
Klemens Morgenstern
05bce942c1 passing a pipe into sh test. 2022-10-12 11:54:05 +08:00
Klemens Morgenstern
dcf5d8ce41 Added return_type to async_result<code_as_error_t> 2022-10-12 10:54:30 +08:00
Klemens Morgenstern
4209f8ee6e Minor bugfixes 2022-10-12 01:12:28 +08:00
Klemens Morgenstern
d9513269cc Enabled freebsd build 2022-10-11 21:03:33 +08:00
Klemens
293f28dab6 Fixed async_system. 2022-09-20 13:45:43 +08:00
Klemens
fe1b629b5d Added bind_launcher. 2022-09-18 22:13:57 +08:00
Klemens
278fa57214 Added code_as_error completion handler. 2022-09-18 17:56:47 +08:00
Klemens Morgenstern
1addfba12e Added WIN32_LEAN_AND_MEAN to cmake 2022-09-17 20:39:01 +08:00
Klemens Morgenstern
4cc469b2a4 Merge pull request #252 from grtowel1510f/patch-1
fix issue #251 - fix simple shell command in posix
2022-09-14 11:38:37 +08:00
Klemens Morgenstern
6e4d1e29d2 Merge pull request #271 from boostorg/shell_v2
Shell v2
2022-09-02 20:30:03 +08:00
Klemens Morgenstern
dada865fd0 Merge pull request #269 from boostorg/klemens-morgenstern-patch-2
Closes #266
2022-09-02 20:29:20 +08:00
Klemens Morgenstern
380dd1b00f Merge pull request #268 from boostorg/klemens-morgenstern-patch-1
Closes #267
2022-09-02 20:28:50 +08:00
Klemens Morgenstern
7cb7af6c8b Closes #267 2022-08-31 15:40:57 +08:00
Klemens Morgenstern
90cbe7cec0 Closes #266 2022-08-31 15:35:51 +08:00
grtowel1510f
8a61f8daa3 fix issue #251 - fix simple shell command in posix
see issue #251 for description.
2022-05-21 14:59:37 +00:00
23 changed files with 660 additions and 69 deletions

View File

@@ -14,7 +14,8 @@ windowsglobalimage="cppalliance/dronevs2019"
def main(ctx): def main(ctx):
return [ return [
#freebsd_cxx("FreeBSD", "g++10", packages="g++10", buildtype="boost", buildscript="drone", environment={ "VARIANT": "release", "TOOLSET": "gcc", "COMPILER": "g++", "CXXSTD": "11" }, globalenv=globalenv), freebsd_cxx("gcc 11 freebsd", "g++-11", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'gcc-11', 'B2_CXXSTD': '17,20', 'B2_LINKFLAGS': '-Wl,-rpath=/usr/local/lib/gcc11'}, globalenv=globalenv),
freebsd_cxx("clang 14 freebsd", "clang++-14", buildtype="boost", buildscript="drone", freebsd_version="13.1", environment={'B2_TOOLSET': 'clang-14', 'B2_CXXSTD': '17,20'}, globalenv=globalenv),
linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync mlocate", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv), linux_cxx("docs", "", packages="docbook docbook-xml docbook-xsl xsltproc libsaxonhe-java default-jre-headless flex libfl-dev bison unzip rsync mlocate", image="cppalliance/droneubuntu1804:1", buildtype="docs", buildscript="drone", environment={"COMMENT": "docs"}, globalenv=globalenv),
linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True), linux_cxx("asan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'asan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_ASAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'DRONE_EXTRA_PRIVILEGED': 'True', 'DRONE_JOB_UUID': '356a192b79'}, globalenv=globalenv, privileged=True),
linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv), linux_cxx("ubsan", "g++-8", packages="g++-8", buildtype="boost", buildscript="drone", image=linuxglobalimage, environment={'COMMENT': 'ubsan', 'B2_VARIANT': 'debug', 'B2_TOOLSET': 'gcc-8', 'B2_CXXSTD': '11', 'B2_UBSAN': '1', 'B2_DEFINES': 'BOOST_NO_STRESS_TEST=1', 'B2_LINKFLAGS': '-fuse-ld=gold', 'DRONE_JOB_UUID': '77de68daec'}, globalenv=globalenv),

View File

@@ -1,4 +1,4 @@
[section:quickstart Quickstrat] [section:quickstart Quickstart]
A process needs four things to be launched: A process needs four things to be launched:

View File

@@ -38,12 +38,11 @@ namespace process {
namespace detail namespace detail
{ {
template<typename ExitHandler> template<typename Handler>
struct async_system_handler : ::boost::process::detail::api::async_handler struct async_system_handler : ::boost::process::detail::api::async_handler
{ {
boost::asio::io_context & ios; boost::asio::io_context & ios;
boost::asio::async_completion< Handler handler;
ExitHandler, void(boost::system::error_code, int)> init;
#if defined(BOOST_POSIX_API) #if defined(BOOST_POSIX_API)
bool errored = false; bool errored = false;
@@ -52,9 +51,8 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
template<typename ExitHandler_> template<typename ExitHandler_>
async_system_handler( async_system_handler(
boost::asio::io_context & ios, boost::asio::io_context & ios,
ExitHandler_ && exit_handler) : ios(ios), init(exit_handler) ExitHandler_ && exit_handler) : ios(ios), handler(std::forward<ExitHandler_>(exit_handler))
{ {
} }
@@ -64,21 +62,15 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
#if defined(BOOST_POSIX_API) #if defined(BOOST_POSIX_API)
errored = true; errored = true;
#endif #endif
auto & h = init.completion_handler; auto h = std::make_shared<Handler>(std::move(handler));
boost::asio::post( boost::asio::post(
ios.get_executor(), ios.get_executor(),
[h, ec]() mutable [h, ec]() mutable
{ {
h(boost::system::error_code(ec.value(), boost::system::system_category()), -1); (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), -1);
}); });
} }
BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
get_result()
{
return init.result.get();
}
template<typename Executor> template<typename Executor>
std::function<void(int, const std::error_code&)> on_exit_handler(Executor&) std::function<void(int, const std::error_code&)> on_exit_handler(Executor&)
{ {
@@ -86,10 +78,10 @@ struct async_system_handler : ::boost::process::detail::api::async_handler
if (errored) if (errored)
return [](int , const std::error_code &){}; return [](int , const std::error_code &){};
#endif #endif
auto & h = init.completion_handler; auto h = std::make_shared<Handler>(std::move(handler));
return [h](int exit_code, const std::error_code & ec) mutable return [h](int exit_code, const std::error_code & ec) mutable
{ {
h(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code); (*h)(boost::system::error_code(ec.value(), boost::system::system_category()), exit_code);
}; };
} }
}; };
@@ -120,21 +112,36 @@ inline boost::process::detail::dummy
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args); async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args);
#endif #endif
namespace detail
{
struct async_system_init_op
{
template<typename Handler, typename ... Args>
void operator()(Handler && handler, asio::io_context & ios, Args && ... args)
{
detail::async_system_handler<typename std::decay<Handler>::type> async_h{ios, std::forward<Handler>(handler)};
child(ios, std::forward<Args>(args)..., async_h ).detach();
}
};
}
template<typename ExitHandler, typename ...Args> template<typename ExitHandler, typename ...Args>
inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int)) inline BOOST_ASIO_INITFN_RESULT_TYPE(ExitHandler, void (boost::system::error_code, int))
async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args) async_system(boost::asio::io_context & ios, ExitHandler && exit_handler, Args && ...args)
{ {
detail::async_system_handler<ExitHandler> async_h{ios, std::forward<ExitHandler>(exit_handler)};
typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type typedef typename ::boost::process::detail::has_error_handler<boost::fusion::tuple<Args...>>::type
has_err_handling; has_err_handling;
static_assert(!has_err_handling::value, "async_system cannot have custom error handling"); static_assert(!has_err_handling::value, "async_system cannot have custom error handling");
return boost::asio::async_initiate<ExitHandler, void (boost::system::error_code, int)>(
child(ios, std::forward<Args>(args)..., async_h ).detach(); detail::async_system_init_op{}, exit_handler, ios, std::forward<Args>(args)...
);
return async_h.get_result();
} }

View File

@@ -139,7 +139,7 @@ struct exe_cmd_init<char> : boost::process::detail::api::handler_base_ext
} }
static exe_cmd_init cmd_shell(std::string&& cmd) static exe_cmd_init cmd_shell(std::string&& cmd)
{ {
std::vector<std::string> args = {"-c", "\"" + cmd + "\""}; std::vector<std::string> args = {"-c", cmd};
std::string sh = shell().string(); std::string sh = shell().string();
return exe_cmd_init( return exe_cmd_init(

View File

@@ -155,8 +155,8 @@ class executor
void write_error(const std::error_code & ec, const char * msg) void write_error(const std::error_code & ec, const char * msg)
{ {
//I am the child //I am the child
const auto len = std::strlen(msg); const auto len = static_cast<int>(std::strlen(msg));
int data[2] = {ec.value(), static_cast<int>(len + 1)}; int data[2] = {ec.value(), len + 1};
boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2)); boost::ignore_unused(::write(_pipe_sink, &data[0], sizeof(int) * 2));
boost::ignore_unused(::write(_pipe_sink, msg, len)); boost::ignore_unused(::write(_pipe_sink, msg, len));

View File

@@ -27,7 +27,11 @@ inline boost::process::filesystem::path search_path(
for (const boost::process::filesystem::path & pp : path) for (const boost::process::filesystem::path & pp : path)
{ {
auto p = pp / filename; auto p = pp / filename;
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec; boost::system::error_code ec;
#endif
bool file = boost::process::filesystem::is_regular_file(p, ec); bool file = boost::process::filesystem::is_regular_file(p, ec);
if (!ec && file && ::access(p.c_str(), X_OK) == 0) if (!ec && file && ::access(p.c_str(), X_OK) == 0)
return p; return p;

View File

@@ -61,7 +61,11 @@ inline boost::process::filesystem::path search_path(
{ {
boost::process::filesystem::path pp_ext = p; boost::process::filesystem::path pp_ext = p;
pp_ext += ext; pp_ext += ext;
#if defined(BOOST_PROCESS_USE_STD_FS)
std::error_code ec;
#else
boost::system::error_code ec; boost::system::error_code ec;
#endif
bool file = boost::process::filesystem::is_regular_file(pp_ext, ec); bool file = boost::process::filesystem::is_regular_file(pp_ext, ec);
if (!ec && file && if (!ec && file &&
::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_)) ::boost::winapi::sh_get_file_info(pp_ext.native().c_str(), 0, 0, 0, ::boost::winapi::SHGFI_EXETYPE_))

View File

@@ -263,7 +263,7 @@ public:
auto st1 = key + ::boost::process::detail::equal_sign<Char>(); auto st1 = key + ::boost::process::detail::equal_sign<Char>();
while (*p != nullptr) while (*p != nullptr)
{ {
const int len = std::char_traits<Char>::length(*p); const auto len = std::char_traits<Char>::length(*p);
if ((std::distance(st1.begin(), st1.end()) < len) if ((std::distance(st1.begin(), st1.end()) < len)
&& std::equal(st1.begin(), st1.end(), *p)) && std::equal(st1.begin(), st1.end(), *p))
break; break;

View File

@@ -0,0 +1,240 @@
//
// boost/process/v2/bind_launcher.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2022 Klemens D. Morgenstern (klemens dot morgenstern at gmx dot net)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
#define BOOST_PROCESS_V2_BIND_LAUNCHER_HPP
#include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/default_launcher.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE
namespace detail
{
template<std::size_t ... Idx>
struct index_sequence { };
template<std::size_t Size, typename T>
struct make_index_sequence_impl;
template<std::size_t Size, std::size_t ... Idx>
struct make_index_sequence_impl<Size, index_sequence<Idx...>>
{
constexpr make_index_sequence_impl() {}
using type = typename make_index_sequence_impl<Size - 1u, index_sequence<Size - 1u, Idx...>>::type;
};
template<std::size_t ... Idx>
struct make_index_sequence_impl<0u, index_sequence<Idx...>>
{
constexpr make_index_sequence_impl() {}
using type = index_sequence<Idx...>;
};
template<std::size_t Cnt>
struct make_index_sequence
{
using type = typename make_index_sequence_impl<Cnt, index_sequence<>>::type;
};
template<std::size_t Cnt>
using make_index_sequence_t = typename make_index_sequence<Cnt>::type;
}
/** @brief Utility class to bind initializers to a launcher
* @tparam Launcher The inner launcher to be used
* @tparam ...Init The initializers to be prepended.
*
* This can be used when multiple processes shared some settings,
* e.g.
*
*/
template<typename Launcher, typename ... Init>
struct bound_launcher
{
template<typename Launcher_, typename ... Init_>
bound_launcher(Launcher_ && l, Init_ && ... init) :
launcher_(std::forward<Launcher_>(l)), init_(std::forward<Init_>(init)...)
{
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
context,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename ExecutionContext, typename Args, typename ... Inits>
auto operator()(ExecutionContext & context,
error_code & ec,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
context, ec,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
std::move(exec),
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
template<typename Executor, typename Args, typename ... Inits>
auto operator()(Executor exec,
error_code & ec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return invoke(detail::make_index_sequence_t<sizeof...(Init)>{},
std::move(exec), ec,
executable,
std::forward<Args>(args),
std::forward<Inits>(inits)...);
}
private:
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
ExecutionContext & context,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits) -> basic_process<typename ExecutionContext::executor_type>
{
return launcher_(context,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename ExecutionContext, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
ExecutionContext & context,
error_code & ec,
const typename std::enable_if<std::is_convertible<
ExecutionContext&, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<typename ExecutionContext::executor_type>
{
return launcher_(context, ec,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
Executor exec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return launcher_(std::move(exec),
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
template<std::size_t ... Idx, typename Executor, typename Args, typename ... Inits>
auto invoke(detail::index_sequence<Idx...>,
Executor exec,
error_code & ec,
const typename std::enable_if<
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution::is_executor<Executor>::value ||
BOOST_PROCESS_V2_ASIO_NAMESPACE::is_executor<Executor>::value,
filesystem::path >::type & executable,
Args && args,
Inits && ... inits ) -> basic_process<Executor>
{
return launcher_(std::move(exec), ec,
executable,
std::forward<Args>(args),
std::get<Idx>(init_)...,
std::forward<Inits>(inits)...);
}
Launcher launcher_;
std::tuple<Init...> init_;
};
template<typename Launcher, typename ... Init>
auto bind_launcher(Launcher && launcher, Init && ... init)
-> bound_launcher<typename std::decay<Launcher>::type,
typename std::decay<Init>::type...>
{
return bound_launcher<typename std::decay<Launcher>::type,
typename std::decay<Init>::type...>(
std::forward<Launcher>(launcher),
std::forward<Init>(init)...);
}
/// @brief @overload bind_launcher(Launcher && launcher, Init && init)
/// @tparam ...Init The initializer types to bind to the default_launcher.
/// @param ...init The initializers types to bind to the default_launcher.
/// @return The new default_launcher.
template<typename ... Init>
auto bind_default_launcher(Init && ... init)
-> bound_launcher<default_process_launcher,
typename std::decay<Init>::type...>
{
return bound_launcher<default_process_launcher,
typename std::decay<Init>::type...>(
default_process_launcher(),
std::forward<Init>(init)...);
}
BOOST_PROCESS_V2_END_NAMESPACE
#endif // BOOST_PROCESS_V2_BIND_LAUNCHER_HPP

View File

@@ -7,18 +7,19 @@
#if defined(BOOST_PROCESS_V2_STANDALONE) #if defined(BOOST_PROCESS_V2_STANDALONE)
#define BOOST_PROCESS_V2_ASIO_NAMESPACE ::asio #define BOOST_PROCESS_V2_ASIO_NAMESPACE asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig) #define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) #define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature) #define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor) #define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#include <asio/detail/config.hpp> #include <asio/detail/config.hpp>
#include <system_error> #include <system_error>
#include <filesystem> #include <filesystem>
#include <string_view> #include <string_view>
#include <iomanip> #include <iomanip>
#include <optional>
#if defined(ASIO_WINDOWS) #if defined(ASIO_WINDOWS)
#define BOOST_PROCESS_V2_WINDOWS 1 #define BOOST_PROCESS_V2_WINDOWS 1
@@ -39,18 +40,19 @@
#else #else
#define BOOST_PROCESS_V2_ASIO_NAMESPACE ::boost::asio #define BOOST_PROCESS_V2_ASIO_NAMESPACE boost::asio
#define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig) #define BOOST_PROCESS_V2_COMPLETION_TOKEN_FOR(Sig) BOOST_ASIO_COMPLETION_TOKEN_FOR(Sig)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) #define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN_TYPE(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)
#define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature) #define BOOST_PROCESS_V2_INITFN_AUTO_RESULT_TYPE(Token, Signature) BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(Token, Signature)
#define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor) #define BOOST_PROCESS_V2_DEFAULT_COMPLETION_TOKEN(Executor) BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(Executor)
#define BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(x,y,z) BOOST_ASIO_INITFN_DEDUCED_RESULT_TYPE(x,y,z)
#include <boost/config.hpp> #include <boost/config.hpp>
#include <boost/io/quoted.hpp> #include <boost/io/quoted.hpp>
#include <boost/system/error_code.hpp> #include <boost/system/error_code.hpp>
#include <boost/system/system_category.hpp> #include <boost/system/system_category.hpp>
#include <boost/system/system_error.hpp> #include <boost/system/system_error.hpp>
#include <boost/optional.hpp>
#if defined(BOOST_WINDOWS_API) #if defined(BOOST_WINDOWS_API)
#define BOOST_PROCESS_V2_WINDOWS 1 #define BOOST_PROCESS_V2_WINDOWS 1
@@ -72,11 +74,9 @@
#if defined(BOOST_PROCESS_USE_STD_FS) #if defined(BOOST_PROCESS_USE_STD_FS)
#include <filesystem> #include <filesystem>
#include <optional>
#else #else
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp> #include <boost/filesystem/operations.hpp>
#include <boost/optional.hpp>
#endif #endif
#define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 { #define BOOST_PROCESS_V2_BEGIN_NAMESPACE namespace boost { namespace process { namespace v2 {
@@ -142,7 +142,7 @@ BOOST_PROCESS_V2_END_NAMESPACE
#endif #endif
#endif #endif
#if defined(__FreeBSD__) && !defined(BOOST_PROCESS_V2_DISABLE_PDFORK) #if defined(__FreeBSD__) && defined(BOOST_PROCESS_V2_ENABLE_PDFORK)
#define BOOST_PROCESS_V2_PDFORK 1 #define BOOST_PROCESS_V2_PDFORK 1
#define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1 #define BOOST_PROCESS_V2_HAS_PROCESS_HANDLE 1
#endif #endif

View File

@@ -12,6 +12,15 @@
#define BOOST_PROCESS_V2_EXIT_CODE_HPP #define BOOST_PROCESS_V2_EXIT_CODE_HPP
#include <boost/process/v2/detail/config.hpp> #include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/error.hpp>
#if defined(BOOST_PROCESS_V2_STANDALONE)
#include <asio/associator.hpp>
#include <asio/async_result.hpp>
#else
#include <boost/asio/associator.hpp>
#include <boost/asio/async_result.hpp>
#endif
#if defined(BOOST_PROCESS_V2_POSIX) #if defined(BOOST_PROCESS_V2_POSIX)
#include <sys/wait.h> #include <sys/wait.h>
@@ -85,6 +94,157 @@ inline int evaluate_exit_code(int code)
#endif #endif
/** Convert the exit-code in a completion into an error if the actual error isn't set.
* @code {.cpp}
* process proc{ctx, "exit", {"1"}};
*
* proc.async_wait(code_as_error(
* [](error_code ec)
* {
* assert(ec.value() == 10);
* assert(ec.category() == error::get_exit_code_category());
* }));
*
* @endcode
*/
template<typename CompletionToken>
struct code_as_error_t
{
CompletionToken token_;
const error_category & category;
template<typename Token_>
code_as_error_t(Token_ && token, const error_category & category)
: token_(std::forward<Token_>(token)), category(category)
{
}
};
/// Deduction function for code_as_error_t.
template<typename CompletionToken>
code_as_error_t<CompletionToken> code_as_error(
CompletionToken && token,
const error_category & category = error::get_exit_code_category())
{
return code_as_error_t<typename std::decay<CompletionToken>::type>(
std::forward<CompletionToken>(token), category);
};
namespace detail
{
template<typename Handler>
struct code_as_error_handler
{
typedef void result_type;
template<typename H>
code_as_error_handler(H && h, const error_category & category)
: handler_(std::forward<H>(h)), category(category)
{
}
void operator()(error_code ec, native_exit_code_type code)
{
if (!ec)
ec.assign(code, category);
std::move(handler_)(ec);
}
Handler handler_;
const error_category & category;
};
}
BOOST_PROCESS_V2_END_NAMESPACE BOOST_PROCESS_V2_END_NAMESPACE
#if !defined(BOOST_PROCESS_V2_STANDALONE)
namespace boost
{
#endif
namespace asio
{
template <typename CompletionToken>
struct async_result<
BOOST_PROCESS_V2_NAMESPACE::code_as_error_t<CompletionToken>,
void(BOOST_PROCESS_V2_NAMESPACE::error_code,
BOOST_PROCESS_V2_NAMESPACE::native_exit_code_type)>
{
using signature = void(BOOST_PROCESS_V2_NAMESPACE::error_code);
using return_type = typename async_result<CompletionToken, void(BOOST_PROCESS_V2_NAMESPACE::error_code)>::return_type;
template <typename Initiation>
struct init_wrapper
{
init_wrapper(Initiation init)
: initiation_(std::move(init))
{
}
template <typename Handler, typename... Args>
void operator()(
Handler && handler,
const BOOST_PROCESS_V2_NAMESPACE::error_category & cat,
Args && ... args)
{
std::move(initiation_)(
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<typename decay<Handler>::type>(
std::forward<Handler>(handler), cat),
std::forward<Args>(args)...);
}
Initiation initiation_;
};
template <typename Initiation, typename RawCompletionToken, typename... Args>
static BOOST_PROCESS_V2_INITFN_DEDUCED_RESULT_TYPE(CompletionToken, signature,
(async_initiate<CompletionToken, signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<CompletionToken&>(),
declval<BOOST_ASIO_MOVE_ARG(Args)>()...)))
initiate(
Initiation && initiation,
RawCompletionToken && token,
Args &&... args)
{
return async_initiate<CompletionToken, signature>(
init_wrapper<typename decay<Initiation>::type>(
std::forward<Initiation>(initiation)),
token.token_,
token.category,
std::forward<Args>(args)...);
}
};
template<template <typename, typename> class Associator, typename Handler, typename DefaultCandidate>
struct associator<Associator,
BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler>, DefaultCandidate>
: Associator<Handler, DefaultCandidate>
{
static typename Associator<Handler, DefaultCandidate>::type get(
const BOOST_PROCESS_V2_NAMESPACE::detail::code_as_error_handler<Handler> & h,
const DefaultCandidate& c = DefaultCandidate()) noexcept
{
return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
}
};
}
#if !defined(BOOST_PROCESS_V2_STANDALONE)
} // boost
#endif
#endif //BOOST_PROCESS_V2_EXIT_CODE_HPP #endif //BOOST_PROCESS_V2_EXIT_CODE_HPP

View File

@@ -74,8 +74,6 @@ struct basic_popen : basic_process<Executor>
{ {
} }
/// Construct a child from a property list and launch it using the default process launcher. /// Construct a child from a property list and launch it using the default process launcher.
template<typename ... Inits> template<typename ... Inits>
explicit basic_popen( explicit basic_popen(
@@ -85,30 +83,66 @@ struct basic_popen : basic_process<Executor>
Inits&&... inits) Inits&&... inits)
: basic_process<Executor>(executor) : basic_process<Executor>(executor)
{ {
*static_cast<basic_process<Executor>*>(this) = this->basic_process<Executor>::operator=(
default_process_launcher()( default_process_launcher()(
this->get_executor(), exe, args, this->get_executor(), exe, args,
std::forward<Inits>(inits)..., std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_} process_stdio{stdin_, stdout_}
); ));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
} }
/// Construct a child from a property list and launch it using the default process launcher. /// Construct a child from a property list and launch it using the default process launcher.
template<typename ... Inits> template<typename ... Inits>
explicit basic_popen( explicit basic_popen(
executor_type executor, executor_type executor,
const filesystem::path& exe, const filesystem::path& exe,
std::initializer_list<wstring_view> args, std::initializer_list<wstring_view> args,
Inits&&... inits) Inits&&... inits)
: basic_process<Executor>(executor) : basic_process<Executor>(executor)
{ {
*static_cast<basic_process<Executor>*>(this) = this->basic_process<Executor>::operator=(
default_process_launcher()( default_process_launcher()(
this->get_executor(), exe, args, this->get_executor(), exe, args,
std::forward<Inits>(inits)..., std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_} process_stdio{stdin_, stdout_}
); ));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
std::initializer_list<wstring_view> args,
Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
} }
/// Construct a child from a property list and launch it using the default process launcher. /// Construct a child from a property list and launch it using the default process launcher.
@@ -119,53 +153,112 @@ struct basic_popen : basic_process<Executor>
Args&& args, Inits&&... inits) Args&& args, Inits&&... inits)
: basic_process<Executor>(executor) : basic_process<Executor>(executor)
{ {
*static_cast<basic_process<Executor>*>(this) = this->basic_process<Executor>::operator=(
default_process_launcher()( default_process_launcher()(
std::move(executor), exe, args, std::move(executor), exe, args,
std::forward<Inits>(inits)..., std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_} process_stdio{stdin_, stdout_}
); ));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename Args, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
executor_type executor,
const filesystem::path& exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(executor)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
std::move(executor), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
} }
/// Construct a child from a property list and launch it using the default process launcher. /// Construct a child from a property list and launch it using the default process launcher.
template<typename ExecutionContext, typename ... Inits> template<typename ExecutionContext, typename ... Inits>
explicit basic_popen( explicit basic_popen(
ExecutionContext & context, ExecutionContext & context,
typename std::enable_if< typename std::enable_if<
std::is_convertible<ExecutionContext&, std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe, const filesystem::path&>::type exe,
std::initializer_list<string_view> args, std::initializer_list<string_view> args,
Inits&&... inits) Inits&&... inits)
: basic_process<Executor>(context) : basic_process<Executor>(context)
{ {
*static_cast<basic_process<Executor>*>(this) = this->basic_process<Executor>::operator=(
default_process_launcher()( default_process_launcher()(
this->get_executor(), exe, args, this->get_executor(), exe, args,
std::forward<Inits>(inits)..., std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_} process_stdio{stdin_, stdout_}
); ));
}
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ExecutionContext, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
std::initializer_list<string_view> args,
Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
} }
/// Construct a child from a property list and launch it using the default process launcher. /// Construct a child from a property list and launch it using the default process launcher.
template<typename ExecutionContext, typename Args, typename ... Inits> template<typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_popen( explicit basic_popen(
ExecutionContext & context, ExecutionContext & context,
typename std::enable_if< typename std::enable_if<
std::is_convertible<ExecutionContext&, std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value, BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe, const filesystem::path&>::type exe,
Args&& args, Inits&&... inits) Args&& args, Inits&&... inits)
: basic_process<Executor>(context) : basic_process<Executor>(context)
{ {
*static_cast<basic_process<Executor>*>(this) = this->basic_process<Executor>::operator=(
default_process_launcher()( default_process_launcher()(
this->get_executor(), exe, args, this->get_executor(), exe, args,
std::forward<Inits>(inits)..., std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_} process_stdio{stdin_, stdout_}
); ));
} }
/// Construct a child from a property list and launch it using the default process launcher.
template<typename Launcher, typename ExecutionContext, typename Args, typename ... Inits>
explicit basic_popen(
Launcher && launcher,
ExecutionContext & context,
typename std::enable_if<
std::is_convertible<ExecutionContext&,
BOOST_PROCESS_V2_ASIO_NAMESPACE::execution_context&>::value,
const filesystem::path&>::type exe,
Args&& args, Inits&&... inits)
: basic_process<Executor>(context)
{
this->basic_process<Executor>::operator=(
std::forward<Launcher>(launcher)(
this->get_executor(), exe, args,
std::forward<Inits>(inits)...,
process_stdio{stdin_, stdout_}
));
}
/// The type used for stdin on the parent process side. /// The type used for stdin on the parent process side.
using stdin_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor>; using stdin_type = BOOST_PROCESS_V2_ASIO_NAMESPACE::basic_writable_pipe<Executor>;
/// The type used for stdout on the parent process side. /// The type used for stdout on the parent process side.

View File

@@ -94,6 +94,7 @@ struct bind_fd
error_code on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *) error_code on_setup(posix::default_launcher & launcher, const filesystem::path &, const char * const *)
{ {
launcher.fd_whitelist.push_back(target); launcher.fd_whitelist.push_back(target);
return {};
} }
/// Implementation of the initialization function. /// Implementation of the initialization function.

View File

@@ -11,6 +11,7 @@
#define BOOST_PROCESS_v2_START_DIR_HPP #define BOOST_PROCESS_v2_START_DIR_HPP
#include <boost/process/v2/detail/config.hpp> #include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/default_launcher.hpp> #include <boost/process/v2/default_launcher.hpp>
BOOST_PROCESS_V2_BEGIN_NAMESPACE BOOST_PROCESS_V2_BEGIN_NAMESPACE

View File

@@ -11,6 +11,7 @@
#define BOOST_PROCESS_V2_STDIO_HPP #define BOOST_PROCESS_V2_STDIO_HPP
#include <boost/process/v2/detail/config.hpp> #include <boost/process/v2/detail/config.hpp>
#include <boost/process/v2/detail/last_error.hpp>
#include <boost/process/v2/default_launcher.hpp> #include <boost/process/v2/default_launcher.hpp>
#include <cstddef> #include <cstddef>
#if defined(BOOST_PROCESS_V2_STANDALONE) #if defined(BOOST_PROCESS_V2_STANDALONE)

View File

@@ -1,6 +1,6 @@
{ {
"key": "process", "key": "process",
"name": "process", "name": "Process",
"authors": [ "authors": [
"Merino Vidal", "Ilya Sokolov", "Felipe Tanus", "Merino Vidal", "Ilya Sokolov", "Felipe Tanus",
"Jeff Flinn", "Thomas Jarosch", "Boris Schaeling", "Klemens D. Morgenstern" "Jeff Flinn", "Thomas Jarosch", "Boris Schaeling", "Klemens D. Morgenstern"

View File

@@ -100,8 +100,8 @@ test-suite with-valgrind :
[ run env.cpp program_options system filesystem : [ test-options env ] : sparring_partner ] [ run env.cpp program_options system filesystem : [ test-options env ] : sparring_partner ]
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch ] [ run group.cpp system thread filesystem : [ test-options group ] : sub_launch ]
[ run group.cpp system thread filesystem : [ test-options group ] : sub_launch : <build>no <target-os>windows:<build>yes <define>BOOST_USE_WINDOWS_H=1 : group-windows-h ] [ run group.cpp system thread filesystem : [ test-options group ] : sub_launch : <build>no <target-os>windows:<build>yes <define>BOOST_USE_WINDOWS_H=1 : group-windows-h ]
[ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no ] [ run group_wait.cpp system thread filesystem : [ test-options group_wait ] : sparring_partner : <target-os>darwin:<build>no <target-os>freebsd:<build>no ]
[ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner ] [ run limit_fd.cpp program_options system filesystem : [ test-options limit_fd ] : sparring_partner : <target-os>freebsd:<build>no ]
[ run run_exe.cpp filesystem : : sparring_partner ] [ run run_exe.cpp filesystem : : sparring_partner ]
[ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ] [ run run_exe_path.cpp filesystem : [ test-options run_exe_path ] : sparring_partner ]
[ run search_path.cpp filesystem system : [ test-options search_path ] : : <target-os>windows:<source>shell32 ] [ run search_path.cpp filesystem system : [ test-options search_path ] : : <target-os>windows:<source>shell32 ]

View File

@@ -16,7 +16,7 @@
#include <boost/asio.hpp> #include <boost/asio.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/scope_exit.hpp>
#include <boost/process/error.hpp> #include <boost/process/error.hpp>
#include <boost/process/io.hpp> #include <boost/process/io.hpp>
#include <boost/process/args.hpp> #include <boost/process/args.hpp>
@@ -45,6 +45,10 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
BOOST_REQUIRE(done.load()); BOOST_REQUIRE(done.load());
}}; }};
BOOST_SCOPE_EXIT_ALL(&) {
done.store(true);
thr.join();
};
using boost::unit_test::framework::master_test_suite; using boost::unit_test::framework::master_test_suite;
@@ -78,9 +82,6 @@ BOOST_AUTO_TEST_CASE(wait_group_test, *boost::unit_test::timeout(5))
BOOST_CHECK(!c1.running()); BOOST_CHECK(!c1.running());
BOOST_CHECK(!c2.running()); BOOST_CHECK(!c2.running());
done.store(true);
thr.join();
} }

View File

@@ -40,12 +40,19 @@ BOOST_AUTO_TEST_CASE(leak_test, *boost::unit_test::timeout(5))
{ {
using boost::unit_test::framework::master_test_suite; using boost::unit_test::framework::master_test_suite;
#if defined(BOOST_WINDOWS_API) #if defined(BOOST_WINDOWS_API)
const auto get_handle = [](FILE * f) {return reinterpret_cast<bt::native_handle_type>(_get_osfhandle(_fileno(f)));}; const auto get_handle = [](FILE * f) {return reinterpret_cast<bt::native_handle_type>(_get_osfhandle(_fileno(f)));};
const auto socket_to_handle = [](::boost::winapi::UINT_PTR_ sock){return reinterpret_cast<::boost::winapi::HANDLE_>(sock);}; const auto socket_to_handle = [](::boost::winapi::UINT_PTR_ sock){return reinterpret_cast<::boost::winapi::HANDLE_>(sock);};
#else #else
const auto get_handle = [](FILE * f) {return fileno(f);}; const auto get_handle = [](FILE * f) {return fileno(f);};
const auto socket_to_handle = [](int i){ return i;}; const auto socket_to_handle = [](int i){ return i;};
#if !defined(__linux__)
return ;
#endif
#endif #endif
std::error_code ec; std::error_code ec;

View File

@@ -4,6 +4,9 @@ add_library(boost_process_v2_test_impl test_impl.cpp)
target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process) target_link_libraries(boost_process_v2_test_impl Boost::process Boost::unit_test_framework Boost::process)
target_compile_definitions(boost_process_v2_test_impl PUBLIC -DBOOST_PROCESS_V2_SEPARATE_COMPILATION=1) target_compile_definitions(boost_process_v2_test_impl PUBLIC -DBOOST_PROCESS_V2_SEPARATE_COMPILATION=1)
if (WIN32)
target_compile_definitions(boost_process_v2_test_impl PUBLIC WIN32_LEAN_AND_MEAN=1)
endif()
function(boost_process_v2_standalone_test name) function(boost_process_v2_standalone_test name)
add_executable(boost_process_v2_${name} ${name}.cpp) add_executable(boost_process_v2_${name} ${name}.cpp)

View File

@@ -24,6 +24,7 @@
#include <boost/process/v2/start_dir.hpp> #include <boost/process/v2/start_dir.hpp>
#include <boost/process/v2/execute.hpp> #include <boost/process/v2/execute.hpp>
#include <boost/process/v2/stdio.hpp> #include <boost/process/v2/stdio.hpp>
#include <boost/process/v2/bind_launcher.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
#include <boost/asio/io_context.hpp> #include <boost/asio/io_context.hpp>
@@ -159,7 +160,12 @@ BOOST_AUTO_TEST_CASE(request_exit)
auto sh = closable(); auto sh = closable();
BOOST_CHECK_MESSAGE(!sh.empty(), sh); BOOST_CHECK_MESSAGE(!sh.empty(), sh);
bpv::process proc(ctx, sh, {}
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
bpv::process proc(ctx, sh, {}, bpv::process_stdio{wp}
#if defined(ASIO_WINDOWS) #if defined(ASIO_WINDOWS)
, asio::windows::show_window_minimized_not_active , asio::windows::show_window_minimized_not_active
#endif #endif
@@ -357,16 +363,16 @@ BOOST_AUTO_TEST_CASE(popen)
// default CWD // default CWD
bpv::popen proc(ctx, pth, {"echo"}); bpv::popen proc(/*bpv::default_process_launcher(), */ctx, pth, {"echo"});
auto written = asio::write(proc, asio::buffer("FOOBAR")); asio::write(proc, asio::buffer("FOOBAR"));
proc.get_stdin().close(); proc.get_stdin().close();
std::string res; std::string res;
boost::system::error_code ec; boost::system::error_code ec;
std::size_t n = asio::read(proc, asio::dynamic_buffer(res), ec); std::size_t n = asio::read(proc, asio::dynamic_buffer(res), ec);
BOOST_CHECK(ec == asio::error::eof || ec == asio::error::broken_pipe); BOOST_CHECK_MESSAGE(ec == asio::error::eof || ec == asio::error::broken_pipe, ec.message());
BOOST_REQUIRE_GE(n, 1); BOOST_REQUIRE_GE(n, 1u);
// remove EOF // remove EOF
res.pop_back(); res.pop_back();
BOOST_CHECK_EQUAL(res, "FOOBAR"); BOOST_CHECK_EQUAL(res, "FOOBAR");
@@ -428,7 +434,10 @@ std::string read_env(const char * name, Inits && ... inits)
std::string out; std::string out;
bpv::error_code ec; bpv::error_code ec;
const auto sz = asio::read(rp, asio::dynamic_buffer(out), ec); auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
while (ec == asio::error::interrupted)
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message()); BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
out.resize(sz); out.resize(sz);
trim_end(out); trim_end(out);
@@ -473,5 +482,64 @@ BOOST_AUTO_TEST_CASE(environment)
BOOST_CHECK_EQUAL(read_env("PATH", bpv::process_environment(bpv::environment::current())), ::getenv("PATH")); BOOST_CHECK_EQUAL(read_env("PATH", bpv::process_environment(bpv::environment::current())), ::getenv("PATH"));
} }
BOOST_AUTO_TEST_CASE(exit_code_as_error)
{
using boost::unit_test::framework::master_test_suite;
const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]);
asio::io_context ctx;
bpv::process proc1(ctx, pth, {"exit-code", "0"});
bpv::process proc2(ctx, pth, {"exit-code", "2"});
bpv::process proc3(ctx, pth, {"sleep", "2000"});
int called = 0;
proc3.terminate();
proc1.async_wait(bpv::code_as_error([&](bpv::error_code ec){called ++; BOOST_CHECK(!ec);}));
proc2.async_wait(bpv::code_as_error([&](bpv::error_code ec){called ++; BOOST_CHECK_MESSAGE(ec, ec.message());}));
proc3.async_wait(bpv::code_as_error([&](bpv::error_code ec){called ++; BOOST_CHECK_MESSAGE(ec, ec.message());}));
ctx.run();
BOOST_CHECK_EQUAL(called, 3);
}
BOOST_AUTO_TEST_CASE(bind_launcher)
{
using boost::unit_test::framework::master_test_suite;
const auto pth = bpv::filesystem::absolute(master_test_suite().argv[1]);
asio::io_context ctx;
asio::readable_pipe rp{ctx};
asio::writable_pipe wp{ctx};
asio::connect_pipe(rp, wp);
auto target = bpv::filesystem::canonical(bpv::filesystem::temp_directory_path());
auto l = bpv::bind_default_launcher(bpv::process_start_dir(target));
std::vector<std::string> args = {"print-cwd"};
// default CWD
bpv::process proc = l(ctx, pth, args, bpv::process_stdio{/*.in=*/{}, /*.out=*/wp});
wp.close();
std::string out;
bpv::error_code ec;
auto sz = asio::read(rp, asio::dynamic_buffer(out), ec);
while (ec == asio::error::interrupted)
sz += asio::read(rp, asio::dynamic_buffer(out), ec);
BOOST_CHECK(sz != 0);
BOOST_CHECK_MESSAGE((ec == asio::error::broken_pipe) || (ec == asio::error::eof), ec.message());
BOOST_CHECK_MESSAGE(bpv::filesystem::path(out) == target,
bpv::filesystem::path(out) << " != " << target);
proc.wait();
BOOST_CHECK_MESSAGE(proc.exit_code() == 0, proc.exit_code() << " from " << proc.native_exit_code());
}
BOOST_AUTO_TEST_SUITE_END(); BOOST_AUTO_TEST_SUITE_END();

View File

@@ -39,9 +39,9 @@ BOOST_AUTO_TEST_CASE(test_shell_parser)
BOOST_CHECK(sh.argv()[2] == STR_VIEW("foo bar")); BOOST_CHECK(sh.argv()[2] == STR_VIEW("foo bar"));
#if defined(BOOST_PROCESS_V2_POSIX) #if defined(BOOST_PROCESS_V2_POSIX)
auto raw_shell = "sh -c false"; auto raw_shell = "sh -c true";
#else #else
auto raw_shell = "cmd /c exit 1"; auto raw_shell = "cmd /c exit 0";
#endif #endif
sh = shell(raw_shell); sh = shell(raw_shell);
@@ -52,5 +52,5 @@ BOOST_AUTO_TEST_CASE(test_shell_parser)
bpv::process proc{ctx, exe, sh.args()}; bpv::process proc{ctx, exe, sh.args()};
proc.wait(); proc.wait();
BOOST_CHECK_EQUAL(proc.exit_code(), 1); BOOST_CHECK_EQUAL(proc.exit_code(), 0);
} }

View File

@@ -40,7 +40,7 @@ BOOST_AUTO_TEST_CASE(wait_for)
BOOST_CHECK(!c.wait_for(std::chrono::milliseconds(200))); BOOST_CHECK(!c.wait_for(std::chrono::milliseconds(200)));
BOOST_CHECK( c.wait_for(std::chrono::milliseconds(1000))); BOOST_CHECK( c.wait_for(std::chrono::milliseconds(2000)));
auto timeout_t = std::chrono::system_clock::now(); auto timeout_t = std::chrono::system_clock::now();