From 0a12b70d7ba97390e8eb6bd71a29be79b537578f Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Wed, 13 Sep 2023 23:03:51 +0300 Subject: [PATCH] utils-file: improve mu_play implement in terms of run_command --- lib/utils/mu-utils-file.cc | 121 ++++++++++++++++++------------------- lib/utils/mu-utils-file.hh | 57 +++++++++-------- 2 files changed, 91 insertions(+), 87 deletions(-) diff --git a/lib/utils/mu-utils-file.cc b/lib/utils/mu-utils-file.cc index 419aca83..4a0ba25b 100644 --- a/lib/utils/mu-utils-file.cc +++ b/lib/utils/mu-utils-file.cc @@ -35,64 +35,6 @@ using namespace Mu; -Mu::Option -Mu::program_in_path(const std::string& name) -{ - if (char *path = g_find_program_in_path(name.c_str()); path) - return to_string_gchar(std::move(path)/*consumes*/); - else - return Nothing; -} - -/* - * Set the child to a group leader to avoid being killed when the - * parent group is killed. - */ -static void -maybe_setsid (G_GNUC_UNUSED gpointer user_data) -{ -#if HAVE_SETSID - setsid(); -#endif /*HAVE_SETSID*/ -} - -Mu::Result -Mu::play (const std::string& path) -{ - /* check nativity */ - GFile *gf = g_file_new_for_path(path.c_str()); - auto is_native = g_file_is_native(gf); - g_object_unref(gf); - if (!is_native) - return Err(Error::Code::File, "'{}' is not a native file", path); - - const char *prog{g_getenv ("MU_PLAY_PROGRAM")}; - if (!prog) { -#ifdef __APPLE__ - prog = "open"; -#else - prog = "xdg-open"; -#endif /*!__APPLE__*/ - } - - const auto program_path{program_in_path(prog)}; - if (!program_path) - return Err(Error::Code::File, "cannot find '{}' in path", prog); - - const gchar *argv[3]{}; - argv[0] = program_path->c_str(); - argv[1] = path.c_str(); - argv[2] = nullptr; - - GError *err{}; - if (!g_spawn_async ({}, (gchar**)&argv, {}, G_SPAWN_SEARCH_PATH, maybe_setsid, - {}, {}, &err)) - return Err(Error::Code::File, &err/*consumes*/, - "failed to open '{}' with '{}'", path, *program_path); - return Ok(); -} - - bool Mu::check_dir (const std::string& path, bool readable, bool writeable) { @@ -293,8 +235,22 @@ Mu::read_from_stdin() g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(outmem))}); } + + +/* + * Set the child to a group leader to avoid being killed when the + * parent group is killed. + */ +static void +maybe_setsid (G_GNUC_UNUSED gpointer user_data) +{ +#if HAVE_SETSID + setsid(); +#endif /*HAVE_SETSID*/ +} + Result -Mu::run_command(std::initializer_list args) +Mu::run_command(std::initializer_list args, bool try_setsid) { std::vector argvec{}; for (auto&& arg: args) @@ -315,9 +271,8 @@ Mu::run_command(std::initializer_list args) static_cast(argvec.data()), {}, (GSpawnFlags)(G_SPAWN_SEARCH_PATH), - {}, {}, - &std_out, &std_err, - &wait_status, &err); + try_setsid ? maybe_setsid : nullptr, {}, + &std_out, &std_err, &wait_status, &err); for (auto& a: argvec) g_free(a); @@ -331,6 +286,48 @@ Mu::run_command(std::initializer_list args) to_string_gchar(std::move(std_err/*consumed*/))}); } +Mu::Option +Mu::program_in_path(const std::string& name) +{ + if (char *path = g_find_program_in_path(name.c_str()); path) + return to_string_gchar(std::move(path)/*consumes*/); + else + return Nothing; +} + + +/* LCOV_EXCL_START*/ +constexpr auto default_open_program = +#ifdef __APPLE__ + "open" +#else + "xdg-open" +#endif /*!__APPLE__*/ + ; + +Mu::Result +Mu::play (const std::string& path) +{ + /* check nativity */ + GFile *gf = g_file_new_for_path(path.c_str()); + auto is_native = g_file_is_native(gf); + g_object_unref(gf); + if (!is_native) + return Err(Error::Code::File, "'{}' is not a native file", path); + + auto mpp{g_getenv ("MU_PLAY_PROGRAM")}; + const std::string prog{mpp ? mpp : default_open_program}; + + const auto program_path{program_in_path(prog)}; + if (!program_path) + return Err(Error::Code::File, "cannot find '{}' in path", prog); + else if (auto&& res{run_command({*program_path, path}, true/*try-setsid*/)}; !res) + return Err(std::move(res.error())); + else + return Ok(); +} +/* LCOV_EXCL_STOP*/ + Result Mu::expand_path(const std::string& str) diff --git a/lib/utils/mu-utils-file.hh b/lib/utils/mu-utils-file.hh index fd889e53..e76f83d2 100644 --- a/lib/utils/mu-utils-file.hh +++ b/lib/utils/mu-utils-file.hh @@ -31,29 +31,6 @@ namespace Mu { -/** - * Try to 'play' (ie., open with it's associated program) a file. On MacOS, the - * the program 'open' is used for this; on other platforms 'xdg-open' to do the - * actual opening. In addition you can set it to another program by setting thep - * MU_PLAY_PROGRAM environment variable - * - * This requires a 'native' file, see g_file_is_native() - * - * @param path full path of the file to open - * - * @return Ok() if succeeded, some error otherwise. - */ -Result play(const std::string& path); - -/** - * Find program in PATH - * - * @param name the name of the program - * - * @return either the full path to program, or Nothing if not found. - */ -Option program_in_path(const std::string& name); - /** * Check if the directory has the given attributes * @@ -253,7 +230,9 @@ Result remove_directory(const std::string& path); /** * Run some system command * - * @param cmd the command + * @param args a list of commmand line arguments (like argv) + * @param try_setsid whether to try setsid(2) (see its manpage for details) if this + * system supports it. * * @return Ok(exit code) or an error. Note that exit-code != 0 is _not_ * considered an error from the perspective of this function. @@ -263,7 +242,35 @@ struct CommandOutput { std::string standard_out; std::string standard_err; }; -Result run_command(std::initializer_list args); +Result run_command(std::initializer_list args, + bool try_setsid=false); + +/** + * Try to 'play' (ie., open with it's associated program) a file. On MacOS, the + * the program 'open' is used for this; on other platforms 'xdg-open' to do the + * actual opening. In addition you can set it to another program by setting thep + * MU_PLAY_PROGRAM environment variable + * + * This requires a 'native' file, see g_file_is_native() + * + * @param path full path of the file to open + * + * @return Ok() if succeeded, some error otherwise. + */ +Result play(const std::string& path); + +/** + * Find program in PATH + * + * @param name the name of the program + * + * @return either the full path to program, or Nothing if not found. + */ +Option program_in_path(const std::string& name); + + + + } // namespace Mu