History

command: add a subprocess command

This supports named arguments. It benefits from the infrastructure of async commands. The plan is to reimplement Lua's utils.subprocess() on top of it.

wm4 committed 8 years ago

Commit d9bc97b1 parent 1aae88b5 files · +108 −0Browse files

Unified · Split

5 files
  1. DOCS/man/input.rst +5 −0
  2. TOOLS/lua/command-test.lua +5 −0
  3. input/cmd.h +1 −0
  4. options/m_option.h +1 −0
  5. player/command.c +96 −0
DOCS/man/input.rst+5−0
@@ -305,6 +305,11 @@ List of Input Commands · 304 unmodified lines
305305 command line arguments following. This is just like the ``run`` command
306306 argument list.
307307
308+ The first array entry is either an absolute path to the executable, or
309+ a filename with no path components, in which case the ``PATH``
310+ environment variable. On Unix, this is equivalent to ``posix_spawnp``
311+ and ``execvp`` behavior.
312+
308313 ``playback_only`` (``MPV_FORMAT_FLAG``)
309314 Boolean indicating whether the process should be killed when playback
310315 terminates (optional, default: yes). If enabled, stopping playback
TOOLS/lua/command-test.lua+5−0
@@ -50,4 +50,9 @@ mp.observe_property("vo-configured", "bool", function(_, v) · 49 unmodified lines
5050 function(res, val, err)
5151 print("done err scr.: " .. join(" ", {res, val, err}))
5252 end)
53+
54+ mp.command_native_async({name = "subprocess", args = {"sh", "-c", "echo hi && sleep 10s"}, capture_stdout = true},
55+ function(res, val, err)
56+ print("done subprocess: " .. join(" ", {res, val, err}))
57+ end)
5358 end)
input/cmd.h+1−0
@@ -80,6 +80,7 @@ struct mp_cmd_arg { · 79 unmodified lines
8080 const struct m_option *type;
8181 union {
8282 int i;
83+ int64_t i64;
8384 float f;
8485 double d;
8586 char *s;
options/m_option.h+1−0
@@ -568,6 +568,7 @@ extern const char m_option_path_separator; · 567 unmodified lines
568568
569569 #define OPTDEF_STR(s) .defval = (void *)&(char * const){s}
570570 #define OPTDEF_INT(i) .defval = (void *)&(const int){i}
571+#define OPTDEF_INT64(i) .defval = (void *)&(const int64_t){i}
571572 #define OPTDEF_FLOAT(f) .defval = (void *)&(const float){f}
572573 #define OPTDEF_DOUBLE(d) .defval = (void *)&(const double){d}
573574
player/command.c+96−0
@@ -5633,6 +5633,91 @@ static void cmd_run(void *p) · 5632 unmodified lines
56335633 talloc_free(args);
56345634 }
56355635
5636+struct subprocess_cb_ctx {
5637+ struct mp_log *log;
5638+ void* talloc_ctx;
5639+ int64_t max_size;
5640+ bool capture[3];
5641+ bstr output[3];
5642+};
5643+
5644+static void subprocess_output(struct subprocess_cb_ctx *ctx, int fd,
5645+ char *data, size_t size)
5646+{
5647+ if (ctx->capture[fd]) {
5648+ if (ctx->output[fd].len < ctx->max_size)
5649+ bstr_xappend(ctx->talloc_ctx, &ctx->output[fd], (bstr){data, size});
5650+ } else {
5651+ int msgl = fd == 2 ? MSGL_ERR : MSGL_INFO;
5652+ mp_msg(ctx->log, msgl, "%.*s", (int)size, data);
5653+ }
5654+}
5655+
5656+static void subprocess_stdout(void *p, char *data, size_t size)
5657+{
5658+ struct subprocess_cb_ctx *ctx = p;
5659+ subprocess_output(ctx, 1, data, size);
5660+}
5661+
5662+static void subprocess_stderr(void *p, char *data, size_t size)
5663+{
5664+ struct subprocess_cb_ctx *ctx = p;
5665+ subprocess_output(ctx, 2, data, size);
5666+}
5667+
5668+static void cmd_subprocess(void *p)
5669+{
5670+ struct mp_cmd_ctx *cmd = p;
5671+ struct MPContext *mpctx = cmd->mpctx;
5672+ char **args = cmd->args[0].v.str_list;
5673+ bool playback_only = cmd->args[1].v.i;
5674+
5675+ if (!args || !args[0]) {
5676+ MP_ERR(mpctx, "program name missing\n");
5677+ cmd->success = false;
5678+ return;
5679+ }
5680+
5681+ void *tmp = talloc_new(NULL);
5682+ struct subprocess_cb_ctx ctx = {
5683+ .log = mpctx->log,
5684+ .talloc_ctx = tmp,
5685+ .max_size = cmd->args[2].v.i,
5686+ .capture = {0, cmd->args[3].v.i, cmd->args[4].v.i},
5687+ };
5688+
5689+ struct mp_cancel *cancel = NULL;
5690+ if (playback_only)
5691+ cancel = mpctx->playback_abort;
5692+
5693+ mp_core_unlock(mpctx);
5694+
5695+ char *error = NULL;
5696+ int status = mp_subprocess(args, cancel, &ctx, subprocess_stdout,
5697+ subprocess_stderr, &error);
5698+
5699+ mp_core_lock(mpctx);
5700+
5701+ struct mpv_node *res = &cmd->result;
5702+ node_init(res, MPV_FORMAT_NODE_MAP, NULL);
5703+ node_map_add_int64(res, "status", status);
5704+ node_map_add_flag(res, "killed_by_us", status == MP_SUBPROCESS_EKILLED_BY_US);
5705+ node_map_add_string(res, "error_string", error ? error : "");
5706+ const char *sname[] = {NULL, "stdout", "stderr"};
5707+ for (int n = 1; n < 3; n++) {
5708+ if (!ctx.capture[n])
5709+ continue;
5710+ struct mpv_byte_array *ba =
5711+ node_map_add(res, sname[n], MPV_FORMAT_BYTE_ARRAY)->u.ba;
5712+ *ba = (struct mpv_byte_array){
5713+ .data = talloc_steal(ba, ctx.output[n].start),
5714+ .size = ctx.output[n].len,
5715+ };
5716+ }
5717+
5718+ talloc_free(tmp);
5719+}
5720+
56365721 static void cmd_enable_input_section(void *p)
56375722 {
56385723 struct mp_cmd_ctx *cmd = p;
@@ -6047,6 +6132,17 @@ const struct mp_cmd_def mp_cmds[] = { · 408 unmodified lines
60476132 }},
60486133 { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } },
60496134 { "run", cmd_run, { ARG_STRING, ARG_STRING }, .vararg = true },
6135+ { "subprocess", cmd_subprocess,
6136+ {
6137+ OPT_STRINGLIST("args", v.str_list, 0),
6138+ OPT_FLAG("playback_only", v.i, 0, OPTDEF_INT(1)),
6139+ OPT_BYTE_SIZE("capture_size", v.i64, 0, 0, INT_MAX,
6140+ OPTDEF_INT64(64 * 1024 * 1024)),
6141+ OPT_FLAG("capture_stdout", v.i, 0, OPTDEF_INT(0)),
6142+ OPT_FLAG("capture_stderr", v.i, 0, OPTDEF_INT(0)),
6143+ },
6144+ .spawn_thread = true,
6145+ },
60506146
60516147 { "set", cmd_set, { ARG_STRING, ARG_STRING } },
60526148 { "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } },

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t