• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

antonvw / wex / 22262718470

21 Feb 2026 07:15PM UTC coverage: 64.252% (-0.009%) from 64.261%
22262718470

Pull #1176

github

antonvw
old fix is no longer necessary
Pull Request #1176: 1173 improve parse unified diff

18541 of 31648 branches covered (58.59%)

Branch coverage included in aggregate %.

14764 of 20187 relevant lines covered (73.14%)

1516.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.73
/src/factory/process-imp.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
// Name:      process-imp.cpp
3
// Purpose:   Implementation of class wex::factory::process_imp
4
// Author:    Anton van Wezenbeek
5
// Copyright: (c) 2021-2026 Anton van Wezenbeek
6
////////////////////////////////////////////////////////////////////////////////
7

8
#include <thread>
9
#include <wex/core/log.h>
10
#include <wex/factory/defs.h>
11
#include <wex/factory/process.h>
12
#include <wx/event.h>
13

14
#include <boost/process/v1/async_system.hpp>
15

16
#include "process-imp.h"
17

18
#define WEX_POST(ID, TEXT, DEST)                                               \
19
  if (DEST != nullptr)                                                         \
20
  {                                                                            \
21
    wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, ID);                     \
22
    event.SetString(TEXT);                                                     \
23
    wxPostEvent(DEST, event);                                                  \
24
  }
25

26
constexpr auto max_size = std::numeric_limits<std::streamsize>::max();
27

28
wex::factory::process_imp::process_imp()
9✔
29
  : m_io(std::make_shared<boost::asio::io_context>())
9✔
30
  , m_queue(std::make_shared<std::queue<std::string>>())
9✔
31
{
32
}
9✔
33

34
void wex::factory::process_imp::async_sleep_for(
2✔
35
  const std::chrono::milliseconds& ms)
36
{
37
  std::this_thread::sleep_for(ms);
2✔
38
}
2✔
39

40
void wex::factory::process_imp::async_system(process* p)
9✔
41
{
42
  m_debug.store(p->m_eh_debug != nullptr);
9✔
43

44
  try
45
  {
46
    boost_async_system(p);
9✔
47

48
    m_is_running.store(true);
8✔
49

50
    thread_input(p);
8✔
51
    thread_output(p);
8✔
52
    thread_error(p);
8✔
53
  }
54
  catch (std::exception& e)
1!
55
  {
56
    log("async_system") << e.what();
1✔
57
  }
1✔
58
}
9✔
59

60
void wex::factory::process_imp::boost_async_system(process* p)
9✔
61
{
62
  bp1::async_system(
8✔
63
    *m_io.get(),
8✔
64
    [this, p](boost::system::error_code error, int i)
8✔
65
    {
66
      m_is_running.store(false);
4✔
67

68
      if (error.value() != 0 && p->m_eh_out != nullptr)
4!
69
      {
70
        WEX_POST(ID_SHELL_APPEND_ERROR, error.message(), p->m_eh_out)
×
71
      }
72

73
      log::debug("async_system") << "exit" << p->data().exe();
4✔
74

75
      if (m_debug.load())
4!
76
      {
77
        WEX_POST(ID_DEBUG_EXIT, "", p->m_eh_debug)
×
78
      }
79
    },
4✔
80

81
    // clang-format off
82
    p->data().exe_path(),
17✔
83
    bp1::args = p->data().args(),
20✔
84
    bp1::start_dir = p->data().start_dir(),
19✔
85
    bp1::std_err > m_es,
10✔
86
    bp1::std_in < m_os,
10✔
87
    bp1::std_out > m_is,
9✔
88
    m_group);
9✔
89
  // clang-format on
90

91
  log::debug("async_system")
16✔
92
    << p->data().exe() << "wd:" << p->data().start_dir();
8✔
93

94
  WEX_POST(ID_SHELL_APPEND_START, "", p->m_eh_out)
8!
95
  WEX_POST(ID_SHELL_APPEND, p->data().exe() + "\n", p->m_eh_out)
8!
96
}
8✔
97

98
bool wex::factory::process_imp::stop(wxEvtHandler* e)
12✔
99
{
100
  if (m_is_running.load())
12✔
101
  {
102
    if (m_group.valid())
4!
103
    {
104
      m_group.terminate();
4✔
105
    }
106

107
    m_io->stop();
4✔
108
    m_is_running.store(false);
4✔
109

110
    if (m_debug.load() && e != nullptr)
4!
111
    {
112
      WEX_POST(ID_DEBUG_EXIT, "", e)
×
113
    }
114

115
    return true;
4✔
116
  }
117

118
  return false;
8✔
119
}
120

121
void wex::factory::process_imp::thread_error(const process* p)
8✔
122
{
123
  std::thread v(
124
    [debug = m_debug.load(),
8✔
125
     &dbg  = p->m_eh_debug,
8✔
126
     out   = p->m_eh_out,
8✔
127
     &es   = m_es]
8✔
128
    {
129
      std::string text;
8✔
130
      char c;
131

132
      while (es.get(c))
16!
133
      {
134
        text.push_back(c);
×
135

136
        if (c == '\n')
×
137
        {
138
          WEX_POST(ID_SHELL_APPEND_ERROR, text, out)
×
139

140
          if (debug)
×
141
          {
142
            WEX_POST(ID_DEBUG_STDOUT, text, dbg)
×
143
          }
144

145
          text.clear();
×
146
        }
147
      }
148
    });
16✔
149

150
  v.detach();
8✔
151
}
8✔
152

153
void wex::factory::process_imp::thread_input(const process* p)
8✔
154
{
155
  std::thread t(
156
    [debug = m_debug.load(),
8✔
157
     &dbg  = p->m_eh_debug,
8✔
158
     &out  = p->m_eh_out,
8✔
159
     &is   = m_is]
8✔
160
    {
161
      std::string text, line;
8✔
162
      line.reserve(600);
8✔
163
      text.reserve(600);
8✔
164
      char c;
165

166
      while (is.get(c))
441✔
167
      {
168
        text.push_back(c);
433✔
169

170
        if (debug)
433!
171
        {
172
          line.append(text);
×
173

174
          if (line.size() > 3)
×
175
          {
176
            WEX_POST(ID_DEBUG_STDOUT, line, dbg)
×
177
            line.clear();
×
178
          }
179
        }
180

181
        if (text.size() > 500)
433!
182
        {
183
          text += "...\n";
×
184
          WEX_POST(ID_SHELL_APPEND, text, out)
×
185
          is.ignore(max_size, '\n');
×
186
          text.clear();
×
187
        }
188
        else if (std::isspace(static_cast<unsigned char>(c)))
433✔
189
        {
190
          WEX_POST(ID_SHELL_APPEND, text, out)
29!
191
          text.clear();
29✔
192
        }
193
      }
194

195
      WEX_POST(ID_SHELL_APPEND_FINISH, "", out)
8!
196
    });
16✔
197

198
  t.detach();
8✔
199
}
8✔
200

201
void wex::factory::process_imp::thread_output(const process* p)
8✔
202
{
203
  std::thread u(
204
    [debug = m_debug.load(),
16!
205
     io    = m_io,
8✔
206
     &os   = m_os,
8✔
207
     dbg   = p->m_eh_debug,
8✔
208
     queue = m_queue]
8✔
209
    {
210
      while (os.good() && !io->stopped())
28!
211
      {
212
        io->run_one_for(std::chrono::milliseconds(10));
12✔
213

214
        if (!queue->empty())
12✔
215
        {
216
          if (const auto& text(queue->front()); os.good() && !io->stopped())
2!
217
          {
218
            log::debug("async_system") << "write:" << text;
×
219

220
            os << text << "\n";
×
221

222
            if (debug)
×
223
            {
224
              WEX_POST(ID_DEBUG_STDIN, text, dbg)
×
225
            }
226
          }
227
          else
228
          {
229
            log::debug("async_system") << "skip:" << text;
4✔
230
          }
231

232
          queue->pop();
2✔
233
        }
234
      }
235
    });
16✔
236

237
  u.detach();
8✔
238
}
8✔
239

240
bool wex::factory::process_imp::write(const std::string& text)
5✔
241
{
242
  if (text.empty() || !m_is_running.load())
5!
243
  {
244
    return false;
1✔
245
  }
246

247
  m_queue->push(text);
4✔
248

249
  return true;
4✔
250
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc