split process

This commit is contained in:
isanae
2020-05-02 02:46:51 -04:00
parent 0f5759c4ba
commit 6a1fe22b65
11 changed files with 364 additions and 354 deletions
-1
View File
@@ -38,7 +38,6 @@ int run(int argc, char** argv)
::SetConsoleCtrlHandler(signal_handler, TRUE);
curl_init curl;
vcvars();
current_env::set(
"PATH",
-227
View File
@@ -6,233 +6,6 @@
namespace builder
{
process::impl::impl(const impl& i)
: interrupt(i.interrupt.load())
{
}
process::impl& process::impl::operator=(const impl& i)
{
interrupt = i.interrupt.load();
return *this;
}
process::process()
: flags_(process::noflags), code_(0)
{
}
process::~process()
{
try
{
join();
}
catch(...)
{
}
}
process process::raw(const std::string& cmd)
{
process p;
p.raw_ = cmd;
return p;
}
process& process::name(const std::string& name)
{
name_ = name;
return *this;
}
const std::string& process::name() const
{
return name_;
}
process& process::binary(const fs::path& p)
{
bin_ = p;
return *this;
}
const fs::path& process::binary() const
{
return bin_;
}
process& process::cwd(const fs::path& p)
{
cwd_ = p;
return *this;
}
const fs::path& process::cwd() const
{
return cwd_;
}
process& process::flags(flags_t f)
{
flags_ = f;
return *this;
}
process::flags_t process::flags() const
{
return flags_;
}
process& process::env(const builder::env& e)
{
env_ = e;
return *this;
}
std::string process::make_name() const
{
if (!name_.empty())
return name_;
return make_cmd();
}
std::string process::make_cmd() const
{
if (!raw_.empty())
return raw_;
std::string s = "\"" + bin_.string() + "\" " + cmd_.string();
if ((flags_ & stdout_is_verbose) == 0)
s += redir_nul();
return s;
}
void process::pipe_into(const process& p)
{
raw_ = make_cmd() + " | " + p.make_cmd();
}
void process::run()
{
if (!cwd_.empty())
debug("> cd " + cwd_.string());
const auto what = make_cmd();
debug("> " + what);
if (conf::dry())
return;
do_run(what);
}
void process::do_run(const std::string& what)
{
STARTUPINFOA si = { .cb=sizeof(si) };
PROCESS_INFORMATION pi = {};
const std::string cmd = current_env::get("COMSPEC");
const std::string args = "/C \"" + what + "\"";
const char* cwd_p = nullptr;
std::string cwd_s;
if (!cwd_.empty())
{
create_directories(cwd_);
cwd_s = cwd_.string();
cwd_p = (cwd_s.empty() ? nullptr : cwd_s.c_str());
}
const auto r = ::CreateProcessA(
cmd.c_str(), const_cast<char*>(args.c_str()),
nullptr, nullptr, FALSE, CREATE_NEW_PROCESS_GROUP,
env_.get_pointers(), cwd_p, &si, &pi);
if (!r)
{
const auto e = GetLastError();
bail_out("failed to start '" + cmd + "'", e);
}
::CloseHandle(pi.hThread);
impl_.handle.reset(pi.hProcess);
}
void process::interrupt()
{
impl_.interrupt = true;
}
void process::join()
{
if (!impl_.handle)
return;
bool interrupted = false;
for (;;)
{
const auto r = WaitForSingleObject(impl_.handle.get(), 100);
if (r == WAIT_OBJECT_0)
{
// done
GetExitCodeProcess(impl_.handle.get(), &code_);
if ((flags_ & allow_failure) || impl_.interrupt)
break;
if (code_ != 0)
{
impl_.handle = {};
bail_out(make_name() + " returned " + std::to_string(code_));
}
break;
}
if (r == WAIT_TIMEOUT)
{
if (impl_.interrupt && !interrupted)
{
const auto pid = GetProcessId(impl_.handle.get());
if (pid == 0)
{
error("process id is 0, terminating instead");
::TerminateProcess(impl_.handle.get(), 0xffff);
break;
}
else
{
debug("sending sigint to " + std::to_string(pid));
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid);
}
interrupted = true;
}
continue;
}
const auto e = GetLastError();
impl_.handle = {};
bail_out("failed to wait on process", e);
}
impl_.handle = {};
}
int process::exit_code() const
{
return static_cast<int>(code_);
}
void op::touch(const fs::path& p)
-110
View File
@@ -5,116 +5,6 @@
namespace builder
{
void vcvars();
class op;
class process
{
friend class op;
public:
enum flags_t
{
noflags = 0x00,
stdout_is_verbose = 0x01,
allow_failure = 0x02
};
process();
~process();
static process raw(const std::string& cmd);
static process pipe(const process& p)
{
return p;
}
template <class... Processes>
static process pipe(const process& p1, const process& p2, Processes&&... ps)
{
auto r = p1;
r.pipe_into(p2);
pipe(r, std::forward<Processes>(ps)...);
return r;
}
process& name(const std::string& name);
const std::string& name() const;
process& binary(const fs::path& p);
const fs::path& binary() const;
process& cwd(const fs::path& p);
const fs::path& cwd() const;
process& flags(flags_t f);
flags_t flags() const;
template <class... Args>
process& arg(Args&&... args)
{
cmd_.arg(std::forward<Args>(args)...);
return *this;
}
template <template<class, class> class Container, class K, class V, class Alloc>
process& args(const Container<std::pair<K, V>, Alloc>& v, cmd::flags f=cmd::noflags)
{
for (auto&& [name, value] : v)
arg(name, value, f);
return *this;
}
template <class Container>
process& args(const Container& v, cmd::flags f=cmd::noflags)
{
for (auto&& e : v)
cmd_.arg(e, f);
return *this;
}
process& env(const builder::env& e);
void run();
void interrupt();
void join();
int exit_code() const;
private:
struct impl
{
handle_ptr handle;
std::atomic<bool> interrupt{false};
impl() = default;
impl(const impl&);
impl& operator=(const impl&);
};
std::string name_;
fs::path bin_;
fs::path cwd_;
flags_t flags_;
cmd cmd_;
builder::env env_;
std::string raw_;
impl impl_;
DWORD code_;
std::string make_name() const;
std::string make_cmd() const;
void pipe_into(const process& p);
void do_run(const std::string& what);
};
class op
{
public:
+236
View File
@@ -0,0 +1,236 @@
#include "pch.h"
#include "process.h"
#include "conf.h"
namespace builder
{
process::impl::impl(const impl& i)
: interrupt(i.interrupt.load())
{
}
process::impl& process::impl::operator=(const impl& i)
{
interrupt = i.interrupt.load();
return *this;
}
process::process()
: flags_(process::noflags), code_(0)
{
}
process::~process()
{
try
{
join();
}
catch(...)
{
}
}
process process::raw(const std::string& cmd)
{
process p;
p.raw_ = cmd;
return p;
}
process& process::name(const std::string& name)
{
name_ = name;
return *this;
}
const std::string& process::name() const
{
return name_;
}
process& process::binary(const fs::path& p)
{
bin_ = p;
return *this;
}
const fs::path& process::binary() const
{
return bin_;
}
process& process::cwd(const fs::path& p)
{
cwd_ = p;
return *this;
}
const fs::path& process::cwd() const
{
return cwd_;
}
process& process::flags(flags_t f)
{
flags_ = f;
return *this;
}
process::flags_t process::flags() const
{
return flags_;
}
process& process::env(const builder::env& e)
{
env_ = e;
return *this;
}
std::string process::make_name() const
{
if (!name_.empty())
return name_;
return make_cmd();
}
std::string process::make_cmd() const
{
if (!raw_.empty())
return raw_;
std::string s = "\"" + bin_.string() + "\" " + cmd_.string();
if ((flags_ & stdout_is_verbose) == 0)
s += redir_nul();
return s;
}
void process::pipe_into(const process& p)
{
raw_ = make_cmd() + " | " + p.make_cmd();
}
void process::run()
{
if (!cwd_.empty())
debug("> cd " + cwd_.string());
const auto what = make_cmd();
debug("> " + what);
if (conf::dry())
return;
do_run(what);
}
void process::do_run(const std::string& what)
{
STARTUPINFOA si = { .cb=sizeof(si) };
PROCESS_INFORMATION pi = {};
const std::string cmd = current_env::get("COMSPEC");
const std::string args = "/C \"" + what + "\"";
const char* cwd_p = nullptr;
std::string cwd_s;
if (!cwd_.empty())
{
create_directories(cwd_);
cwd_s = cwd_.string();
cwd_p = (cwd_s.empty() ? nullptr : cwd_s.c_str());
}
const auto r = ::CreateProcessA(
cmd.c_str(), const_cast<char*>(args.c_str()),
nullptr, nullptr, FALSE, CREATE_NEW_PROCESS_GROUP,
env_.get_pointers(), cwd_p, &si, &pi);
if (!r)
{
const auto e = GetLastError();
bail_out("failed to start '" + cmd + "'", e);
}
::CloseHandle(pi.hThread);
impl_.handle.reset(pi.hProcess);
}
void process::interrupt()
{
impl_.interrupt = true;
}
void process::join()
{
if (!impl_.handle)
return;
bool interrupted = false;
for (;;)
{
const auto r = WaitForSingleObject(impl_.handle.get(), 100);
if (r == WAIT_OBJECT_0)
{
// done
GetExitCodeProcess(impl_.handle.get(), &code_);
if ((flags_ & allow_failure) || impl_.interrupt)
break;
if (code_ != 0)
{
impl_.handle = {};
bail_out(make_name() + " returned " + std::to_string(code_));
}
break;
}
if (r == WAIT_TIMEOUT)
{
if (impl_.interrupt && !interrupted)
{
const auto pid = GetProcessId(impl_.handle.get());
if (pid == 0)
{
error("process id is 0, terminating instead");
::TerminateProcess(impl_.handle.get(), 0xffff);
break;
}
else
{
debug("sending sigint to " + std::to_string(pid));
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, pid);
}
interrupted = true;
}
continue;
}
const auto e = GetLastError();
impl_.handle = {};
bail_out("failed to wait on process", e);
}
impl_.handle = {};
}
int process::exit_code() const
{
return static_cast<int>(code_);
}
} // namespace
+108
View File
@@ -0,0 +1,108 @@
#include "utility.h"
namespace builder
{
class process
{
public:
enum flags_t
{
noflags = 0x00,
stdout_is_verbose = 0x01,
allow_failure = 0x02
};
process();
~process();
static process raw(const std::string& cmd);
static process pipe(const process& p)
{
return p;
}
template <class... Processes>
static process pipe(const process& p1, const process& p2, Processes&&... ps)
{
auto r = p1;
r.pipe_into(p2);
pipe(r, std::forward<Processes>(ps)...);
return r;
}
process& name(const std::string& name);
const std::string& name() const;
process& binary(const fs::path& p);
const fs::path& binary() const;
process& cwd(const fs::path& p);
const fs::path& cwd() const;
process& flags(flags_t f);
flags_t flags() const;
template <class... Args>
process& arg(Args&&... args)
{
cmd_.arg(std::forward<Args>(args)...);
return *this;
}
template <template<class, class> class Container, class K, class V, class Alloc>
process& args(const Container<std::pair<K, V>, Alloc>& v, cmd::flags f=cmd::noflags)
{
for (auto&& [name, value] : v)
arg(name, value, f);
return *this;
}
template <class Container>
process& args(const Container& v, cmd::flags f=cmd::noflags)
{
for (auto&& e : v)
cmd_.arg(e, f);
return *this;
}
process& env(const builder::env& e);
void run();
void interrupt();
void join();
int exit_code() const;
private:
struct impl
{
handle_ptr handle;
std::atomic<bool> interrupt{false};
impl() = default;
impl(const impl&);
impl& operator=(const impl&);
};
std::string name_;
fs::path bin_;
fs::path cwd_;
flags_t flags_;
cmd cmd_;
builder::env env_;
std::string raw_;
impl impl_;
DWORD code_;
std::string make_name() const;
std::string make_cmd() const;
void pipe_into(const process& p);
void do_run(const std::string& what);
};
} // namespace
+1
View File
@@ -5,6 +5,7 @@
#include "../conf.h"
#include "../tools.h"
#include "../utility.h"
#include "../op.h"
namespace builder
{
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
#include "net.h"
#include "op.h"
#include "process.h"
namespace builder
{
+9 -14
View File
@@ -3,6 +3,7 @@
#include "conf.h"
#include "op.h"
#include "net.h"
#include "process.h"
namespace builder
{
@@ -262,9 +263,6 @@ void directory_deleter::cancel()
}
static env g_env_x86, g_env_x64;
fs::path find_vcvars()
{
const std::vector<std::string> editions =
@@ -347,20 +345,17 @@ env get_vcvars_env(arch a)
return e;
}
void vcvars()
env env::vs_x86()
{
g_env_x86 = get_vcvars_env(arch::x86);
g_env_x64 = get_vcvars_env(arch::x64);
static env e = get_vcvars_env(arch::x86);
return e;
}
env env::vs_x64()
{
return g_env_x64;
}
env env::vs_x86()
{
return g_env_x86;
static env e = get_vcvars_env(arch::x64);
return e;
}
env env::vs(arch a)
@@ -368,10 +363,10 @@ env env::vs(arch a)
switch (a)
{
case arch::x86:
return g_env_x86;
return vs_x86();
case arch::x64:
return g_env_x64;
return vs_x64();
case arch::dont_care:
return {};
+1 -1
View File
@@ -157,8 +157,8 @@ public:
prepend
};
static env vs_x64();
static env vs_x86();
static env vs_x64();
static env vs(arch a);
env& append_path(const fs::path& p);
+2
View File
@@ -85,6 +85,7 @@
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="..\src\process.cpp" />
<ClCompile Include="..\src\tasks\boost.cpp" />
<ClCompile Include="..\src\tasks\bzip2.cpp" />
<ClCompile Include="..\src\tasks\fmt.cpp" />
@@ -112,6 +113,7 @@
<ClInclude Include="..\src\op.h" />
<ClInclude Include="..\src\net.h" />
<ClInclude Include="..\src\pch.h" />
<ClInclude Include="..\src\process.h" />
<ClInclude Include="..\src\tasks\task.h" />
<ClInclude Include="..\src\tasks\tasks.h" />
<ClInclude Include="..\src\tools.h" />
+6
View File
@@ -87,6 +87,9 @@
<ClCompile Include="..\src\tasks\pyqt.cpp">
<Filter>src\tasks</Filter>
</ClCompile>
<ClCompile Include="..\src\process.cpp">
<Filter>src</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\src\pch.h">
@@ -113,5 +116,8 @@
<ClInclude Include="..\src\tasks\tasks.h">
<Filter>src\tasks</Filter>
</ClInclude>
<ClInclude Include="..\src\process.h">
<Filter>src</Filter>
</ClInclude>
</ItemGroup>
</Project>