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
305 command line arguments following. This is just like the ``run`` command305 command line arguments following. This is just like the ``run`` command
306 argument list.306 argument list.
307 307
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
308 ``playback_only`` (``MPV_FORMAT_FLAG``)313 ``playback_only`` (``MPV_FORMAT_FLAG``)
309 Boolean indicating whether the process should be killed when playback314 Boolean indicating whether the process should be killed when playback
310 terminates (optional, default: yes). If enabled, stopping playback315 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
50 function(res, val, err)50 function(res, val, err)
51 print("done err scr.: " .. join(" ", {res, val, err}))51 print("done err scr.: " .. join(" ", {res, val, err}))
52 end)52 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)
53end)58end)
input/cmd.h+1−0
@@ -80,6 +80,7 @@ struct mp_cmd_arg { · 79 unmodified lines
80 const struct m_option *type;80 const struct m_option *type;
81 union {81 union {
82 int i;82 int i;
83 int64_t i64;
83 float f;84 float f;
84 double d;85 double d;
85 char *s;86 char *s;
options/m_option.h+1−0
@@ -568,6 +568,7 @@ extern const char m_option_path_separator; · 567 unmodified lines
568 568
569#define OPTDEF_STR(s) .defval = (void *)&(char * const){s}569#define OPTDEF_STR(s) .defval = (void *)&(char * const){s}
570#define OPTDEF_INT(i) .defval = (void *)&(const int){i}570#define OPTDEF_INT(i) .defval = (void *)&(const int){i}
571#define OPTDEF_INT64(i) .defval = (void *)&(const int64_t){i}
571#define OPTDEF_FLOAT(f) .defval = (void *)&(const float){f}572#define OPTDEF_FLOAT(f) .defval = (void *)&(const float){f}
572#define OPTDEF_DOUBLE(d) .defval = (void *)&(const double){d}573#define OPTDEF_DOUBLE(d) .defval = (void *)&(const double){d}
573 574
player/command.c+96−0
@@ -5633,6 +5633,91 @@ static void cmd_run(void *p) · 5632 unmodified lines
5633 talloc_free(args);5633 talloc_free(args);
5634}5634}
5635 5635
5636struct 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
5644static 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
5656static 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
5662static 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
5668static 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
5636static void cmd_enable_input_section(void *p)5721static void cmd_enable_input_section(void *p)
5637{5722{
5638 struct mp_cmd_ctx *cmd = p;5723 struct mp_cmd_ctx *cmd = p;
@@ -6047,6 +6132,17 @@ const struct mp_cmd_def mp_cmds[] = { · 408 unmodified lines
6047 }},6132 }},
6048 { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } },6133 { "playlist-move", cmd_playlist_move, { ARG_INT, ARG_INT } },
6049 { "run", cmd_run, { ARG_STRING, ARG_STRING }, .vararg = true },6134 { "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 },
6050 6146
6051 { "set", cmd_set, { ARG_STRING, ARG_STRING } },6147 { "set", cmd_set, { ARG_STRING, ARG_STRING } },
6052 { "change-list", cmd_change_list, { ARG_STRING, ARG_STRING, ARG_STRING } },6148 { "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