* Execute
*/
+static int Pakfire_execute_stdout_callback(
+ struct pakfire_ctx* ctx, void* data, const char* line, const size_t length) {
+ PyObject** output = data;
+ PyObject* chunk = NULL;
+
+ // Allocate a new chunk
+ chunk = PyBytes_FromStringAndSize(line, length);
+ if (!chunk)
+ return -ENOTSUP;
+
+ // Concatenate the chunk to the output
+ PyBytes_ConcatAndDel(output, chunk);
+
+ return 0;
+}
+
static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwargs) {
struct pakfire_jail* jail = NULL;
struct pakfire_env* env = NULL;
PyObject* environ = NULL;
int nice = 0;
+ PyObject* output = NULL;
+ int return_output = 0;
+
+ pakfire_pty_stdout_callback stdout_callback = NULL;
+
const char* kwlist[] = {
"command",
"environ",
"nice",
+ "return_output",
NULL,
};
// Parse arguments
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oi", (char**)kwlist,
- &command, &environ, &nice))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|Oib", (char**)kwlist,
+ &command, &environ, &nice, &return_output))
goto ERROR;
// Check if command is a list
}
}
+ // Capture and return the output?
+ if (return_output) {
+ // Allocate a new buffer
+ output = PyBytes_FromString("");
+ if (!output)
+ goto ERROR;
+
+ // Register a function that captures the output
+ stdout_callback = Pakfire_execute_stdout_callback;
+ }
+
// Create a new jail
r = pakfire_jail_create(&jail, self->pakfire);
if (r < 0) {
Py_BEGIN_ALLOW_THREADS
// Execute command
- r = pakfire_jail_communicate(jail, argv, env, 0, NULL, NULL, NULL, NULL);
+ r = pakfire_jail_communicate(jail, argv, env, 0, NULL, NULL, stdout_callback, &output);
Py_END_ALLOW_THREADS
goto ERROR;
}
+ // Return the output if requested
+ if (return_output) {
+ ret = Py_NewRef(output);
+
// Otherwise return None
- ret = Py_NewRef(Py_None);
+ } else {
+ ret = Py_NewRef(Py_None);
+ }
ERROR:
if (jail)
if (argv)
free(argv);
+ Py_XDECREF(output);
+
return ret;
}
self.pakfire.execute(["/command-does-not-exist"])
def test_execute_output(self):
- self.pakfire.execute(["/command", "echo", "123"])
+ self.assertEqual(
+ self.pakfire.execute(["/command", "echo", "123"], return_output=True),
+ b"123\n",
+ )
# Multiple newlines in one read
- self.pakfire.execute(["/command", "echo", "1\n2\n3"])
+ self.assertEqual(
+ self.pakfire.execute(["/command", "echo", "1\n2\n3"], return_output=True),
+ b"1\n2\n3\n",
+ )
# Run a command with a lot of output which exceeds the buffer size
self.pakfire.execute(["/command", "lines", "1", "65536"])
# Run a command that generates lots of lines
- self.pakfire.execute(["/command", "lines", "100", "40"])
+ output = self.pakfire.execute(["/command", "lines", "100", "40"], return_output=True)
+ self.assertEquals(output.count(b"\n"), 100)
def test_nice(self):
self.pakfire.execute(["/command", "print-nice"], nice=5)