Skip to content

Commit 1600cf1

Browse files
committed
misc: ditch selfmade command execute functions in favour of tiny-proccess-library
follow up of parent commit this library is cross-platform and easier so
1 parent f617d11 commit 1600cf1

9 files changed

Lines changed: 218 additions & 329 deletions

File tree

cufetchpm/src/pluginManager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ void PluginManager::add_repo_plugins(const std::string& repo)
5959
std::filesystem::create_directories(working_dir);
6060

6161
status("Cloning repository '{}' at '{}'", repo, working_dir.string());
62-
if (!taur_exec({"git", "clone", "--recursive", repo, working_dir.string()}, false))
62+
if (Process({"git", "clone", "--recursive", repo, working_dir.string()}).get_exit_status() != 0)
6363
{
6464
std::filesystem::remove_all(working_dir);
6565
die("Failed to clone at directory '{}'", working_dir.string());
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#ifndef TINY_PROCESS_LIBRARY_HPP_
2+
#define TINY_PROCESS_LIBRARY_HPP_
3+
#include <functional>
4+
#include <memory>
5+
#include <mutex>
6+
#include <string>
7+
#include <thread>
8+
#include <unordered_map>
9+
#include <vector>
10+
#ifndef _WIN32
11+
#include <sys/wait.h>
12+
#endif
13+
14+
namespace TinyProcessLib {
15+
/// Additional parameters to Process constructors.
16+
struct Config {
17+
/// Buffer size for reading stdout and stderr. Default is 131072 (128 kB).
18+
std::size_t buffer_size = 131072;
19+
/// Set to true to inherit file descriptors from parent process. Default is false.
20+
/// On Windows: has no effect unless read_stdout==nullptr, read_stderr==nullptr and open_stdin==false.
21+
bool inherit_file_descriptors = false;
22+
23+
/// If set, invoked when process stdout is closed.
24+
/// This call goes after last call to read_stdout().
25+
std::function<void()> on_stdout_close = nullptr;
26+
/// If set, invoked when process stderr is closed.
27+
/// This call goes after last call to read_stderr().
28+
std::function<void()> on_stderr_close = nullptr;
29+
30+
/// On Windows only: controls how the process is started, mimics STARTUPINFO's wShowWindow.
31+
/// See: https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/ns-processthreadsapi-startupinfoa
32+
/// and https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-showwindow
33+
enum class ShowWindow {
34+
hide = 0,
35+
show_normal = 1,
36+
show_minimized = 2,
37+
maximize = 3,
38+
show_maximized = 3,
39+
show_no_activate = 4,
40+
show = 5,
41+
minimize = 6,
42+
show_min_no_active = 7,
43+
show_na = 8,
44+
restore = 9,
45+
show_default = 10,
46+
force_minimize = 11
47+
};
48+
/// On Windows only: controls how the window is shown.
49+
ShowWindow show_window{ShowWindow::show_default};
50+
51+
/// Set to true to break out of flatpak sandbox by prepending all commands with `/usr/bin/flatpak-spawn --host`
52+
/// which will execute the command line on the host system.
53+
/// Requires the flatpak `org.freedesktop.Flatpak` portal to be opened for the current sandbox.
54+
/// See https://docs.flatpak.org/en/latest/flatpak-command-reference.html#flatpak-spawn.
55+
bool flatpak_spawn_host = false;
56+
};
57+
58+
/// Platform independent class for creating processes.
59+
/// Note on Windows: it seems not possible to specify which pipes to redirect.
60+
/// Thus, at the moment, if read_stdout==nullptr, read_stderr==nullptr and open_stdin==false,
61+
/// the stdout, stderr and stdin are sent to the parent process instead.
62+
class Process {
63+
public:
64+
#ifdef _WIN32
65+
typedef unsigned long id_type; // Process id type
66+
typedef void *fd_type; // File descriptor type
67+
#ifdef UNICODE
68+
typedef std::wstring string_type;
69+
#else
70+
typedef std::string string_type;
71+
#endif
72+
#else
73+
typedef pid_t id_type;
74+
typedef int fd_type;
75+
typedef std::string string_type;
76+
#endif
77+
typedef std::unordered_map<string_type, string_type> environment_type;
78+
79+
private:
80+
class Data {
81+
public:
82+
Data() noexcept;
83+
id_type id;
84+
#ifdef _WIN32
85+
void *handle{nullptr};
86+
#endif
87+
int exit_status{-1};
88+
};
89+
90+
public:
91+
/// Starts a process with the environment of the calling process.
92+
Process(const std::vector<string_type> &arguments, const string_type &path = string_type(),
93+
std::function<void(const char *bytes, size_t n)> read_stdout = nullptr,
94+
std::function<void(const char *bytes, size_t n)> read_stderr = nullptr,
95+
bool open_stdin = false,
96+
const Config &config = {}) noexcept;
97+
/// Starts a process with the environment of the calling process.
98+
Process(const string_type &command, const string_type &path = string_type(),
99+
std::function<void(const char *bytes, size_t n)> read_stdout = nullptr,
100+
std::function<void(const char *bytes, size_t n)> read_stderr = nullptr,
101+
bool open_stdin = false,
102+
const Config &config = {}) noexcept;
103+
104+
/// Starts a process with specified environment.
105+
Process(const std::vector<string_type> &arguments,
106+
const string_type &path,
107+
const environment_type &environment,
108+
std::function<void(const char *bytes, size_t n)> read_stdout = nullptr,
109+
std::function<void(const char *bytes, size_t n)> read_stderr = nullptr,
110+
bool open_stdin = false,
111+
const Config &config = {}) noexcept;
112+
/// Starts a process with specified environment.
113+
Process(const string_type &command,
114+
const string_type &path,
115+
const environment_type &environment,
116+
std::function<void(const char *bytes, size_t n)> read_stdout = nullptr,
117+
std::function<void(const char *bytes, size_t n)> read_stderr = nullptr,
118+
bool open_stdin = false,
119+
const Config &config = {}) noexcept;
120+
#ifndef _WIN32
121+
/// Starts a process with the environment of the calling process.
122+
/// Supported on Unix-like systems only.
123+
/// Since the command line is not known to the Process object itself,
124+
/// this overload does not support the flatpak_spawn_host configuration.
125+
Process(const std::function<void()> &function,
126+
std::function<void(const char *bytes, size_t n)> read_stdout = nullptr,
127+
std::function<void(const char *bytes, size_t n)> read_stderr = nullptr,
128+
bool open_stdin = false,
129+
const Config &config = {});
130+
#endif
131+
~Process() noexcept;
132+
133+
/// Get the process id of the started process.
134+
id_type get_id() const noexcept;
135+
/// Wait until process is finished, and return exit status.
136+
int get_exit_status() noexcept;
137+
/// If process is finished, returns true and sets the exit status. Returns false otherwise.
138+
bool try_get_exit_status(int &exit_status) noexcept;
139+
/// Write to stdin.
140+
bool write(const char *bytes, size_t n);
141+
/// Write to stdin. Convenience function using write(const char *, size_t).
142+
bool write(const std::string &str);
143+
/// Close stdin. If the process takes parameters from stdin, use this to notify that all parameters have been sent.
144+
void close_stdin() noexcept;
145+
146+
/// Kill the process. force=true is only supported on Unix-like systems.
147+
void kill(bool force = false) noexcept;
148+
/// Kill a given process id. Use kill(bool force) instead if possible. force=true is only supported on Unix-like systems.
149+
static void kill(id_type id, bool force = false) noexcept;
150+
#ifndef _WIN32
151+
/// Send the signal signum to the process.
152+
void signal(int signum) noexcept;
153+
#endif
154+
155+
private:
156+
Data data;
157+
bool closed;
158+
std::mutex close_mutex;
159+
std::function<void(const char *bytes, size_t n)> read_stdout;
160+
std::function<void(const char *bytes, size_t n)> read_stderr;
161+
#ifndef _WIN32
162+
std::thread stdout_stderr_thread;
163+
#else
164+
std::thread stdout_thread, stderr_thread;
165+
#endif
166+
bool open_stdin;
167+
std::mutex stdin_mutex;
168+
169+
Config config;
170+
171+
std::unique_ptr<fd_type> stdout_fd, stderr_fd, stdin_fd;
172+
173+
id_type open(const std::vector<string_type> &arguments, const string_type &path, const environment_type *environment = nullptr) noexcept;
174+
id_type open(const string_type &command, const string_type &path, const environment_type *environment = nullptr) noexcept;
175+
#ifndef _WIN32
176+
id_type open(const std::function<void()> &function) noexcept;
177+
#endif
178+
void async_read() noexcept;
179+
void close_fds() noexcept;
180+
};
181+
182+
} // namespace TinyProcessLib
183+
184+
#endif // TINY_PROCESS_LIBRARY_HPP_

include/util.hpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,6 @@ EXPORT std::string binarySearchPCIArray(const std::string_view vendor_id_s, cons
122122
*/
123123
EXPORT std::string binarySearchPCIArray(const std::string_view vendor_id_s);
124124

125-
/* http://stackoverflow.com/questions/478898/ddg#478960
126-
* Execute shell command and read its output from stdout.
127-
* @param cmd The command to execute
128-
*/
129-
EXPORT std::string read_shell_exec(const std::string_view cmd);
130-
131125
/* Get file value from a file and trim quotes and double-quotes
132126
* @param iterIndex The iteration index used for getting the necessary value only tot times
133127
* @param line The string used in std::getline
@@ -167,13 +161,6 @@ EXPORT void ctrl_d_handler(const std::istream& cin);
167161
*/
168162
EXPORT std::string expandVar(std::string ret, bool dont = false);
169163

170-
/* Executes commands with execvp() and keep the program running without existing
171-
* @param cmd_str The command to execute
172-
* @param exitOnFailure Whether to call exit(1) on command failure.
173-
* @return true if the command successed, else false
174-
*/
175-
EXPORT bool taur_exec(const std::vector<std::string_view> cmd_str, const bool noerror_print = true);
176-
177164
/* Get a relative path from an enviroment variable (PATH, XDG_DATA_DIRS, ...)
178165
* Either path of an executable, directory, etc...
179166
* @param relative_path The path we would search in the env
@@ -236,7 +223,7 @@ EXPORT void replace_str(std::string& str, const std::string_view from, const std
236223
* @param noerror_print Print errors (default true)
237224
* @return true if the command successed, else false
238225
*/
239-
EXPORT bool read_exec(std::vector<const char*> cmd, std::string& output, bool useStdErr = false, bool noerror_print = true);
226+
EXPORT bool read_exec(std::vector<std::string> cmd, std::string& output, bool useStdErr = false, bool noerror_print = true);
240227

241228
/* Make whole string lowercase
242229
* @param str The string to use

libcufetch/parse.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <string_view>
3838
#include <vector>
3939

40+
#include "tiny-process-library/process.hpp"
4041
#include "libcufetch/common.hh"
4142
#include "libcufetch/config.hh"
4243
#include "libcufetch/cufetch.hh"
@@ -354,7 +355,8 @@ std::optional<std::string> parse_command_tag(Parser& parser, parse_args_t& parse
354355
if (removetag)
355356
command.erase(0, 1);
356357

357-
const std::string& cmd_output = read_shell_exec(command);
358+
std::string cmd_output;
359+
TinyProcessLib::Process proc(command, "", [&](const char* bytes, size_t n){cmd_output.assign(bytes, n);});
358360
if (!parse_args.parsingLayout && !removetag && parser.dollar_pos != std::string::npos)
359361
parse_args.pureOutput.replace(parser.dollar_pos, command.length() + "$()"_len, cmd_output);
360362

src/core-modules/android/user.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55

66
#include <string>
77

8+
#include "tiny-process-library/process.hpp"
89
#include "core-modules.hh"
910
#include "util.hpp"
1011

12+
using namespace TinyProcessLib;
13+
1114
MODFUNC(user_name)
1215
{ return g_pwd->pw_name; }
1316

@@ -28,9 +31,9 @@ MODFUNC(user_shell_version)
2831
std::string ret;
2932

3033
if (shell_name == "nu")
31-
ret = read_shell_exec("nu -c \"version | get version\"");
34+
Process("nu -c \"version | get version\"", "", [&](const char *bytes, size_t n){ ret.assign(bytes, n); });
3235
else
33-
ret = read_shell_exec(fmt::format("{} -c 'echo \"${}_VERSION\"'", shell_name, str_toupper(shell_name.data())));
36+
Process(fmt::format("{} -c 'echo \"${}_VERSION\"'", shell_name, str_toupper(shell_name.data())), "", [&](const char *bytes, size_t n){ ret.assign(bytes, n); });
3437

3538
strip(ret);
3639
return ret;

src/core-modules/linux/user.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#include <fstream>
77

8+
#include "tiny-process-library/process.hpp"
89
#include "core-modules.hh"
910
#include "libcufetch/common.hh"
1011
#include "fmt/format.h"
@@ -18,6 +19,8 @@
1819
#include <wayland-client.h>
1920
#endif
2021

22+
using namespace TinyProcessLib;
23+
2124
// clang-format off
2225
static std::string get_term_name_env(bool get_default = false)
2326
{
@@ -83,9 +86,9 @@ MODFUNC(user_shell_version)
8386
std::string ret;
8487

8588
if (shell_name == "nu")
86-
ret = read_shell_exec("nu -c \"version | get version\"");
89+
Process("nu -c \"version | get version\"", "", [&](const char *bytes, size_t n){ ret.assign(bytes, n); });
8790
else
88-
ret = read_shell_exec(fmt::format("{} -c 'echo \"${}_VERSION\"'", shell_name, str_toupper(shell_name.data())));
91+
Process(fmt::format("{} -c 'echo \"${}_VERSION\"'", shell_name, str_toupper(shell_name.data())), "", [&](const char *bytes, size_t n){ ret.assign(bytes, n); });
8992

9093
strip(ret);
9194
return ret;

src/display.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
#include "stb_image.h"
6363
#include "utf8/checked.h"
6464
#include "util.hpp"
65+
#include "tiny-process-library/process.hpp"
6566

6667
std::string Display::detect_distro(const Config& config)
6768
{
@@ -144,11 +145,11 @@ static std::vector<std::string> render_with_image(const moduleMap_t& modulesInfo
144145
const size_t height = image_height / font_height;
145146

146147
if (config.args_image_backend == "kitty")
147-
taur_exec({ "kitty", "+kitten", "icat",
148+
TinyProcessLib::Process({ "kitty", "+kitten", "icat",
148149
"--align", (config.logo_position == "top" ? "center" : config.logo_position),
149150
"--place", fmt::format("{}x{}@0x0", width, height), path.string() });
150151
else if (config.args_image_backend == "viu")
151-
taur_exec({ "viu", "-t", "-w", fmt::to_string(width), "-h", fmt::to_string(height), path.string() });
152+
TinyProcessLib::Process({ "viu", "-t", "-w", fmt::to_string(width), "-h", fmt::to_string(height), path.string() });
152153
else
153154
die(_("The image backend '{}' isn't supported, only 'kitty' and 'viu'.\n"
154155
"Please currently use the GUI mode for rendering the image/gif (use -h for more details)"),

0 commit comments

Comments
 (0)