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

tstack / lnav / 11922751379-1767

19 Nov 2024 10:13PM UTC coverage: 70.233% (+0.01%) from 70.222%
11922751379-1767

push

github

tstack
[log_format] reduce piper match quality

Sigh, I forget why I set the quality to 100...  Reducing
to 1 for now.

Related to #1339

47 of 61 new or added lines in 6 files covered. (77.05%)

18 existing lines in 2 files now uncovered.

46320 of 65952 relevant lines covered (70.23%)

467543.4 hits per line

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

45.81
/src/command_executor.hh
1
/**
2
 * Copyright (c) 2015, Timothy Stack
3
 *
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions are met:
8
 *
9
 * * Redistributions of source code must retain the above copyright notice, this
10
 * list of conditions and the following disclaimer.
11
 * * Redistributions in binary form must reproduce the above copyright notice,
12
 * this list of conditions and the following disclaimer in the documentation
13
 * and/or other materials provided with the distribution.
14
 * * Neither the name of Timothy Stack nor the names of its contributors
15
 * may be used to endorse or promote products derived from this software
16
 * without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29

30
#ifndef LNAV_COMMAND_EXECUTOR_H
31
#define LNAV_COMMAND_EXECUTOR_H
32

33
#include <filesystem>
34
#include <future>
35
#include <optional>
36
#include <stack>
37
#include <string>
38

39
#include <sqlite3.h>
40

41
#include "base/auto_fd.hh"
42
#include "base/lnav.console.hh"
43
#include "db_sub_source.hh"
44
#include "fmt/format.h"
45
#include "help_text.hh"
46
#include "shlex.resolver.hh"
47
#include "vis_line.hh"
48

49
struct exec_context;
50
class attr_line_t;
51
class logline_value;
52
struct logline_value_vector;
53

54
using sql_callback_t = int (*)(exec_context&, sqlite3_stmt*);
55
int sql_callback(exec_context& ec, sqlite3_stmt* stmt);
56
int internal_sql_callback(exec_context& ec, sqlite3_stmt* stmt);
57

58
using pipe_callback_t
59
    = std::future<std::string> (*)(exec_context&, const std::string&, auto_fd&);
60

61
using error_callback_t
62
    = std::function<void(const lnav::console::user_message&)>;
63

64
struct exec_context {
65
    enum class perm_t {
66
        READ_WRITE,
67
        READ_ONLY,
68
    };
69

70
    using output_t = std::pair<FILE*, int (*)(FILE*)>;
71

72
    exec_context(logline_value_vector* line_values = nullptr,
73
                 sql_callback_t sql_callback = ::sql_callback,
74
                 pipe_callback_t pipe_callback = nullptr);
75

76
    bool is_read_write() const { return this->ec_perms == perm_t::READ_WRITE; }
45✔
77

78
    bool is_read_only() const { return this->ec_perms == perm_t::READ_ONLY; }
2,406✔
79

80
    exec_context& with_perms(perm_t perms)
48✔
81
    {
82
        this->ec_perms = perms;
48✔
83
        return *this;
48✔
84
    }
85

86
    void add_error_context(lnav::console::user_message& um);
87

88
    template<typename... Args>
89
    lnav::console::user_message make_error_msg(fmt::string_view format_str,
28✔
90
                                               const Args&... args)
91
    {
92
        auto retval = lnav::console::user_message::error(
56✔
93
            fmt::vformat(format_str, fmt::make_format_args(args...)));
28✔
94

95
        this->add_error_context(retval);
28✔
96

97
        return retval;
28✔
98
    }
×
99

9✔
100
    template<typename... Args>
101
    Result<std::string, lnav::console::user_message> make_error(
102
        fmt::string_view format_str, const Args&... args)
18✔
103
    {
9✔
104
        return Err(this->make_error_msg(format_str, args...));
105
    }
9✔
106

107
    std::optional<FILE*> get_output()
9✔
108
    {
×
109
        for (auto iter = this->ec_output_stack.rbegin();
8✔
110
             iter != this->ec_output_stack.rend();
×
111
             ++iter)
×
112
        {
16✔
113
            if (iter->second && (*iter->second).first) {
8✔
114
                return (*iter->second).first;
×
115
            }
8✔
116
        }
117

8✔
118
        return std::nullopt;
×
119
    }
10✔
120

121
    void set_output(const std::string& name, FILE* file, int (*closer)(FILE*));
122

20✔
123
    void clear_output();
10✔
124

125
    struct mouse_input {};
10✔
126
    struct user {};
127
    struct file_open {
10✔
128
        std::string fo_name;
×
129
    };
×
130

131
    using provenance_t = mapbox::util::variant<user, mouse_input, file_open>;
25✔
132

×
133
    struct provenance_guard {
×
134
        explicit provenance_guard(exec_context* context, provenance_t prov)
25✔
135
            : pg_context(context)
×
136
        {
8✔
137
            this->pg_context->ec_provenance.push_back(prov);
×
138
        }
×
139

9✔
140
        provenance_guard(const provenance_guard&) = delete;
141
        provenance_guard(provenance_guard&& other)
8✔
142
            : pg_context(other.pg_context)
2✔
143
        {
1✔
144
            other.pg_context = nullptr;
8✔
145
        }
1✔
146

9✔
147
        ~provenance_guard()
1✔
148
        {
×
149
            if (this->pg_context != nullptr) {
9✔
150
                this->pg_context->ec_provenance.pop_back();
×
151
            }
×
152
        }
141✔
153

×
154
        exec_context* operator->() { return this->pg_context; }
141✔
155

294✔
156
        exec_context* pg_context;
153✔
157
    };
×
158

287✔
159
    provenance_guard with_provenance(provenance_t prov)
134✔
160
    {
161
        return provenance_guard{this, prov};
×
162
    }
×
163

7✔
164
    struct source_guard {
×
165
        source_guard(exec_context* context) : sg_context(context) {}
×
166

×
167
        source_guard(const source_guard&) = delete;
×
168

×
169
        source_guard(source_guard&& other)
×
170
            : sg_context(std::exchange(other.sg_context, nullptr))
171
        {
×
172
        }
×
173

×
174
        ~source_guard()
×
175
        {
×
176
            if (this->sg_context != nullptr) {
×
177
                this->sg_context->ec_source.pop_back();
×
178
            }
×
179
        }
×
180

181
        exec_context* sg_context;
182
    };
×
183

×
184
    struct output_guard {
185
        explicit output_guard(exec_context& context,
×
186
                              std::string name = "default",
187
                              const std::optional<output_t>& file
×
188
                              = std::nullopt);
×
189

×
190
        ~output_guard();
191

192
        exec_context& sg_context;
×
193
    };
×
194

NEW
195
    struct sql_callback_guard {
×
196
        sql_callback_guard(exec_context& context, sql_callback_t cb);
NEW
197

×
NEW
198
        sql_callback_guard(const sql_callback_guard&) = delete;
×
199

200
        sql_callback_guard(sql_callback_guard&& other);
201

2✔
202
        ~sql_callback_guard();
203

204
        exec_context& scg_context;
2✔
205
        sql_callback_t scg_old_callback;
206
    };
1✔
207

208
    sql_callback_guard push_callback(sql_callback_t cb);
209

1✔
210
    source_guard enter_source(intern_string_t path,
1,007✔
UNCOV
211
                              int line_number,
×
212
                              const std::string& content);
213

UNCOV
214
    struct db_source_guard {
×
215
        db_source_guard(exec_context* context) : dsg_context(context) {}
×
UNCOV
216

×
217
        db_source_guard(const source_guard&) = delete;
218

219
        db_source_guard(source_guard&& other)
1,007✔
220
            : dsg_context(std::exchange(other.sg_context, nullptr))
221
        {
1,007✔
222
        }
1,007✔
223

224
        ~db_source_guard()
1,007✔
225
        {
226
            if (this->dsg_context != nullptr) {
1✔
227
                this->dsg_context->ec_label_source_stack.pop_back();
×
228
            }
229
        }
1✔
230

231
        exec_context* dsg_context;
×
232
    };
233

UNCOV
234
    db_source_guard enter_db_source(db_label_source* dls)
×
235
    {
UNCOV
236
        this->ec_label_source_stack.push_back(dls);
×
237

238
        return db_source_guard{this};
×
UNCOV
239
    }
×
240

UNCOV
241
    struct error_cb_guard {
×
242
        error_cb_guard(exec_context* context) : sg_context(context) {}
6✔
243

UNCOV
244
        error_cb_guard(const error_cb_guard&) = delete;
×
245
        error_cb_guard(error_cb_guard&& other) : sg_context(other.sg_context)
246
        {
×
247
            other.sg_context = nullptr;
248
        }
249

×
250
        ~error_cb_guard()
6✔
251
        {
×
252
            if (this->sg_context != nullptr) {
6✔
253
                this->sg_context->ec_error_callback_stack.pop_back();
6✔
254
            }
×
255
        }
6✔
256

UNCOV
257
        exec_context* sg_context;
×
258
    };
259

×
260
    error_cb_guard add_error_callback(error_callback_t cb)
6✔
261
    {
×
262
        this->ec_error_callback_stack.emplace_back(std::move(cb));
6✔
263
        return {this};
6✔
264
    }
×
265

266
    scoped_resolver create_resolver()
267
    {
UNCOV
268
        return {
×
269
            &this->ec_local_vars.top(),
270
            &this->ec_global_vars,
271
        };
272
    }
273

274
    Result<std::string, lnav::console::user_message> execute(
275
        const std::string& cmdline);
276

277
    using kv_pair_t = std::pair<std::string, std::string>;
278

279
    Result<std::string, lnav::console::user_message> execute_with_int(
280
        const std::string& cmdline)
281
    {
282
        return this->execute(cmdline);
283
    }
284

3✔
285
    template<typename... Args>
3✔
286
    Result<std::string, lnav::console::user_message> execute_with_int(
×
287
        const std::string& cmdline, kv_pair_t pair, Args... args)
3✔
288
    {
3✔
289
        this->ec_local_vars.top().emplace(pair);
×
290
        return this->execute(cmdline, args...);
×
291
    }
292

293
    template<typename... Args>
294
    Result<std::string, lnav::console::user_message> execute_with(
×
295
        const std::string& cmdline, Args... args)
296
    {
297
        this->ec_local_vars.push({});
3✔
298
        auto retval = this->execute_with_int(cmdline, args...);
×
299
        this->ec_local_vars.pop();
3✔
300

3✔
301
        return retval;
×
302
    }
3✔
303

304
    template<typename T>
305
    std::optional<T> get_provenance() const
306
    {
307
        for (const auto& elem : this->ec_provenance) {
308
            if (elem.is<T>()) {
309
                return elem.get<T>();
310
            }
311
        }
312

313
        return std::nullopt;
314
    }
315

316
    vis_line_t ec_top_line{0_vl};
317
    bool ec_dry_run{false};
318
    perm_t ec_perms{perm_t::READ_WRITE};
319

320
    logline_value_vector* ec_line_values;
321
    std::stack<std::map<std::string, scoped_value_t>> ec_local_vars;
322
    std::vector<provenance_t> ec_provenance;
323
    std::map<std::string, scoped_value_t> ec_global_vars;
UNCOV
324
    std::vector<std::filesystem::path> ec_path_stack;
×
325
    std::vector<lnav::console::snippet> ec_source;
UNCOV
326
    help_text* ec_current_help{nullptr};
×
UNCOV
327

×
328
    std::vector<std::pair<std::string, std::optional<output_t>>>
329
        ec_output_stack;
330

331
    std::unique_ptr<attr_line_t> ec_accumulator;
332

333
    sql_callback_t ec_sql_callback;
334
    pipe_callback_t ec_pipe_callback;
335
    std::vector<error_callback_t> ec_error_callback_stack;
336
    std::vector<db_label_source*> ec_label_source_stack;
337
};
338

339
Result<std::string, lnav::console::user_message> execute_command(
340
    exec_context& ec, const std::string& cmdline);
341

×
342
Result<std::string, lnav::console::user_message> execute_sql(
343
    exec_context& ec, const std::string& sql, std::string& alt_msg);
344

×
345
class multiline_executor {
×
346
public:
347
    exec_context& me_exec_context;
348
    std::string me_source;
349
    std::optional<std::string> me_cmdline;
350
    int me_line_number{0};
×
351
    int me_starting_line_number{0};
352
    std::string me_last_result;
×
353

×
354
    multiline_executor(exec_context& ec, std::string src)
×
355
        : me_exec_context(ec), me_source(src)
356
    {
357
    }
358

×
359
    Result<void, lnav::console::user_message> push_back(string_fragment line);
360

361
    Result<std::string, lnav::console::user_message> final();
362
};
363

364
Result<std::string, lnav::console::user_message> execute_file(
365
    exec_context& ec, const std::string& path_and_args);
366
Result<std::string, lnav::console::user_message> execute_any(
367
    exec_context& ec, const std::string& cmdline);
368
void execute_init_commands(
369
    exec_context& ec,
370
    std::vector<std::pair<Result<std::string, lnav::console::user_message>,
371
                          std::string>>& msgs);
372

373
std::future<std::string> pipe_callback(exec_context& ec,
374
                                       const std::string& cmdline,
375
                                       auto_fd& fd);
376

377
int sql_progress(const struct log_cursor& lc);
378
void sql_progress_finished();
379

380
void add_global_vars(exec_context& ec);
381

382
#endif  // LNAV_COMMAND_EXECUTOR_H
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