Skip to content

Commit 4f98791

Browse files
author
Franziska Geiger
committed
[GR-15827] Implemetation of os.execv and os.execl + adding one external dependency file
PullRequest: graalpython/521
2 parents dab01cc + ddec79e commit 4f98791

File tree

6 files changed

+210
-1
lines changed

6 files changed

+210
-1
lines changed

graalpython/com.oracle.graal.python.cext/include/Python.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
#include "funcobject.h"
121121
#include "iterobject.h"
122122
#include "datetime.h"
123+
#include "typeslots.h"
123124

124125
// TODO: we must extend the refcounting behavior to support handles to managed objects
125126
#undef Py_DECREF
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* Copyright (c) 2018, 2019, Oracle and/or its affiliates.
2+
* Copyright (C) 1996-2017 Python Software Foundation
3+
*
4+
* Licensed under the PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
5+
*/
6+
/* Do not renumber the file; these numbers are part of the stable ABI. */
7+
/* Disabled, see #10181 */
8+
#undef Py_bf_getbuffer
9+
#undef Py_bf_releasebuffer
10+
#define Py_mp_ass_subscript 3
11+
#define Py_mp_length 4
12+
#define Py_mp_subscript 5
13+
#define Py_nb_absolute 6
14+
#define Py_nb_add 7
15+
#define Py_nb_and 8
16+
#define Py_nb_bool 9
17+
#define Py_nb_divmod 10
18+
#define Py_nb_float 11
19+
#define Py_nb_floor_divide 12
20+
#define Py_nb_index 13
21+
#define Py_nb_inplace_add 14
22+
#define Py_nb_inplace_and 15
23+
#define Py_nb_inplace_floor_divide 16
24+
#define Py_nb_inplace_lshift 17
25+
#define Py_nb_inplace_multiply 18
26+
#define Py_nb_inplace_or 19
27+
#define Py_nb_inplace_power 20
28+
#define Py_nb_inplace_remainder 21
29+
#define Py_nb_inplace_rshift 22
30+
#define Py_nb_inplace_subtract 23
31+
#define Py_nb_inplace_true_divide 24
32+
#define Py_nb_inplace_xor 25
33+
#define Py_nb_int 26
34+
#define Py_nb_invert 27
35+
#define Py_nb_lshift 28
36+
#define Py_nb_multiply 29
37+
#define Py_nb_negative 30
38+
#define Py_nb_or 31
39+
#define Py_nb_positive 32
40+
#define Py_nb_power 33
41+
#define Py_nb_remainder 34
42+
#define Py_nb_rshift 35
43+
#define Py_nb_subtract 36
44+
#define Py_nb_true_divide 37
45+
#define Py_nb_xor 38
46+
#define Py_sq_ass_item 39
47+
#define Py_sq_concat 40
48+
#define Py_sq_contains 41
49+
#define Py_sq_inplace_concat 42
50+
#define Py_sq_inplace_repeat 43
51+
#define Py_sq_item 44
52+
#define Py_sq_length 45
53+
#define Py_sq_repeat 46
54+
#define Py_tp_alloc 47
55+
#define Py_tp_base 48
56+
#define Py_tp_bases 49
57+
#define Py_tp_call 50
58+
#define Py_tp_clear 51
59+
#define Py_tp_dealloc 52
60+
#define Py_tp_del 53
61+
#define Py_tp_descr_get 54
62+
#define Py_tp_descr_set 55
63+
#define Py_tp_doc 56
64+
#define Py_tp_getattr 57
65+
#define Py_tp_getattro 58
66+
#define Py_tp_hash 59
67+
#define Py_tp_init 60
68+
#define Py_tp_is_gc 61
69+
#define Py_tp_iter 62
70+
#define Py_tp_iternext 63
71+
#define Py_tp_methods 64
72+
#define Py_tp_new 65
73+
#define Py_tp_repr 66
74+
#define Py_tp_richcompare 67
75+
#define Py_tp_setattr 68
76+
#define Py_tp_setattro 69
77+
#define Py_tp_str 70
78+
#define Py_tp_traverse 71
79+
#define Py_tp_members 72
80+
#define Py_tp_getset 73
81+
#define Py_tp_free 74
82+
#define Py_nb_matrix_multiply 75
83+
#define Py_nb_inplace_matrix_multiply 76
84+
#define Py_am_await 77
85+
#define Py_am_aiter 78
86+
#define Py_am_anext 79
87+
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x03050000
88+
/* New in 3.5 */
89+
#define Py_tp_finalize 80
90+
#endif

graalpython/com.oracle.graal.python.test/src/tests/test_posix.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -41,6 +41,7 @@
4141

4242

4343
class PosixTests(unittest.TestCase):
44+
4445
def test_uname(self):
4546
# just like cpython, a simple smoke test
4647
import posix
@@ -51,3 +52,44 @@ def test_uname(self):
5152
self.assertIsNotNone(uname.release)
5253
self.assertIsNotNone(uname.version)
5354
self.assertIsNotNone(uname.machine)
55+
56+
def test_execv(self):
57+
# test creates a shell script, which again creates a file, to ensure script execution
58+
# Both files are deleted again in the end
59+
import os
60+
import sys
61+
new_file_path, cwd = self.create_file()
62+
# os.execv(new_file_path, [new_file_path, 'the_input'])
63+
os.system("%s -c \"import os; os.execv('%s', ['%s', 'the_input'])\"" % (sys.executable, new_file_path, new_file_path))
64+
assert os.path.isfile(cwd + '/test.txt')
65+
self.delete_file(new_file_path, cwd)
66+
67+
def test_execl(self):
68+
# test creates a shell script, which again creates a file, to ensure script execution
69+
# Both files are deleted again in the end
70+
import os
71+
import sys
72+
new_file_path, cwd = self.create_file()
73+
# os.execl(new_file_path, [new_file_path, 'the_input'])
74+
os.system("%s -c \"import os; os.execl('%s', *['%s', 'the_input'])\"" % (sys.executable, new_file_path, new_file_path))
75+
assert os.path.isfile(cwd + '/test.txt')
76+
self.delete_file(new_file_path, cwd)
77+
78+
def create_file(self):
79+
import os
80+
import stat
81+
cwd = os.getcwd()
82+
new_file_path = os.path.join(cwd , 'myscript.sh')
83+
with open(new_file_path, 'w') as script:
84+
script.write('#!/bin/sh\n')
85+
script.write("echo \"something echo with\" $1 > {}/test.txt\n".format(cwd))
86+
script.write('echo this is an output\n')
87+
assert os.path.isfile(new_file_path)
88+
st = os.stat(new_file_path)
89+
os.chmod(new_file_path, st.st_mode | stat.S_IEXEC)
90+
return new_file_path, cwd
91+
92+
def delete_file(self, new_file_path, cwd):
93+
import os
94+
os.remove(new_file_path)
95+
os.remove(cwd + '/test.txt')

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PosixModuleBuiltins.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@
4949
import static com.oracle.truffle.api.TruffleFile.UNIX_PERMISSIONS;
5050
import static com.oracle.truffle.api.TruffleFile.UNIX_UID;
5151

52+
import java.io.BufferedReader;
5253
import java.io.IOException;
5354
import java.io.InputStream;
55+
import java.io.InputStreamReader;
5456
import java.io.OutputStream;
5557
import java.io.UnsupportedEncodingException;
5658
import java.lang.ProcessBuilder.Redirect;
@@ -105,13 +107,15 @@
105107
import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
106108
import com.oracle.graal.python.builtins.objects.common.SequenceNodes.LenNode;
107109
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
110+
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.GetItemDynamicNode;
108111
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.GetItemNode;
109112
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.ToByteArrayNode;
110113
import com.oracle.graal.python.builtins.objects.dict.PDict;
111114
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
112115
import com.oracle.graal.python.builtins.objects.floats.PFloat;
113116
import com.oracle.graal.python.builtins.objects.function.PKeyword;
114117
import com.oracle.graal.python.builtins.objects.ints.PInt;
118+
import com.oracle.graal.python.builtins.objects.list.PList;
115119
import com.oracle.graal.python.builtins.objects.module.PythonModule;
116120
import com.oracle.graal.python.builtins.objects.str.PString;
117121
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
@@ -136,6 +140,7 @@
136140
import com.oracle.graal.python.runtime.exception.PException;
137141
import com.oracle.graal.python.runtime.exception.PythonErrorType;
138142
import com.oracle.graal.python.runtime.exception.PythonExitException;
143+
import com.oracle.graal.python.runtime.sequence.PSequence;
139144
import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage;
140145
import com.oracle.truffle.api.CompilerDirectives;
141146
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
@@ -283,6 +288,69 @@ public void postInitialize(PythonCore core) {
283288
((PDict) environAttr).setDictStorage(environ.getDictStorage());
284289
}
285290

291+
@Builtin(name = "execv", minNumOfPositionalArgs = 2)
292+
@GenerateNodeFactory
293+
public abstract static class ExecvNode extends PythonBuiltinNode {
294+
295+
@Specialization
296+
Object execute(String path, PList args) {
297+
return doExecute(path, args);
298+
}
299+
300+
@Specialization
301+
Object execute(PString path, PTuple args) {
302+
return execute(path.getValue(), args);
303+
}
304+
305+
@Specialization
306+
Object execute(String path, PTuple args) {
307+
// in case of execl the PList happens to be in the tuples first entry
308+
Object list = GetItemDynamicNode.getUncached().execute(args.getSequenceStorage(), 0);
309+
return doExecute(path, list instanceof PList ? (PList) list : args);
310+
}
311+
312+
@Specialization
313+
Object execute(PString path, PList args) {
314+
return doExecute(path.getValue(), args);
315+
}
316+
317+
@TruffleBoundary
318+
Object doExecute(String path, PSequence args) {
319+
try {
320+
if (!getContext().isExecutableAccessAllowed()) {
321+
throw raise(OSError, "executable access denied");
322+
}
323+
int size = args.getSequenceStorage().length();
324+
String[] cmd = new String[size];
325+
// We don't need the path variable because it's already in the array
326+
// but I need to process it for CI gate
327+
cmd[0] = path;
328+
for (int i = 0; i < size; i++) {
329+
cmd[i] = GetItemDynamicNode.getUncached().execute(args.getSequenceStorage(), i).toString();
330+
}
331+
Runtime rt = Runtime.getRuntime();
332+
Process pr = rt.exec(cmd);
333+
// retrieve output from executed script
334+
BufferedReader bfr = new BufferedReader(new InputStreamReader(pr.getInputStream()));
335+
OutputStream stream = getContext().getEnv().out();
336+
String line = "";
337+
while ((line = bfr.readLine()) != null) {
338+
stream.write(line.getBytes());
339+
}
340+
341+
try {
342+
pr.waitFor();
343+
} catch (InterruptedException e) {
344+
throw new IOException(e);
345+
}
346+
347+
throw new PythonExitException(this, pr.exitValue());
348+
} catch (IOException e) {
349+
throw raise(PythonErrorType.ValueError, "Could not execute script '%s'", e.getMessage());
350+
}
351+
}
352+
}
353+
286354
@Builtin(name = "getcwd", minNumOfPositionalArgs = 0)
287355
@GenerateNodeFactory
288356
public abstract static class CwdNode extends PythonBuiltinNode {

graalpython/lib-graalpython/posix.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,9 @@ def uname():
143143
@__builtin__
144144
def get_terminal_size(fd = None):
145145
return terminal_size(old_get_terminal_size(fd))
146+
147+
def execl(file, *args):
148+
"""execl(file, *args)
149+
Execute the executable file with argument list args, replacing the
150+
current process. """
151+
execv(file, args)

mx.graalpython/copyrights/overrides

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ graalpython/com.oracle.graal.python.cext/include/structseq.h,python.copyright
100100
graalpython/com.oracle.graal.python.cext/include/traceback.h,python.copyright
101101
graalpython/com.oracle.graal.python.cext/include/truffle.h,no.copyright
102102
graalpython/com.oracle.graal.python.cext/include/tupleobject.h,python.copyright
103+
graalpython/com.oracle.graal.python.cext/include/typeslots.h,python.copyright
103104
graalpython/com.oracle.graal.python.cext/include/ucnhash.h,python.copyright
104105
graalpython/com.oracle.graal.python.cext/include/unicodeobject.h,python.copyright
105106
graalpython/com.oracle.graal.python.cext/include/warnings.h,python.copyright
@@ -520,3 +521,4 @@ mx.graalpython/mx_graalpython.py,zippy.copyright
520521
mx.graalpython/mx_graalpython_bench_param.py,zippy.copyright
521522
mx.graalpython/mx_graalpython_benchmark.py,zippy.copyright
522523
mx.graalpython/suite.py,no.copyright
524+

0 commit comments

Comments
 (0)