Skip to content

Commit abc0d44

Browse files
committed
[GR-50391] Create template for JBang
PullRequest: graalpython/3085
2 parents 2203667 + 8123175 commit abc0d44

File tree

6 files changed

+345
-0
lines changed

6 files changed

+345
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ GRAALPYTHON.dist
2222
GRAALPYTHON_UNIT_TESTS.dist
2323
mx.graalpython/eclipse-launches
2424
*.json
25+
!jbang-catalog.json
2526
!**/resources/*.json
2627
!**/META-INF/**/*.json
2728
!graalpython/lib-graalpython/modules/standalone/native-image-resources.json

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ language runtime. The main focus is on user-observable behavior of the engine.
1717
* Add option `python.InitialLocale` to change the default locale. If not set, then Java Locale#getDefault is used.
1818
* `multiprocessing` module now uses the `spawn` method (creates new processes) by default. The formerly default method that uses threads and multiple Truffle contexts can be selected using `multiprocessing.set_start_method('graalpy')`.
1919
* `polyglot` module: add API to redefine Truffle interop messages for external / user defined types. For more details see [The Truffle Interoperability Extension API](docs/user/Interoperability.md).
20+
*Adding integration with jBang (https://www.jbang.dev/)
21+
** running example via `jbang hello@oracle/graalpython` or `jbang hello@oracle/graalpython "print(1*4)"`
22+
** creating new script via: `jbang init --template=graalpy@oracle/graalpython myscript.java`
23+
** creating new script with local maven repo for testing: `jbang init --template=graalpy@oracle/graalpython -Dpath_to_local_repo=/absolute/path/to/local/maven/repository myscript.java'
2024

2125
## Version 23.1.0
2226
* Oracle GraalPy distributions (previously known as GraalPy Enterprise) are now available under the [GFTC license](https://www.oracle.com/downloads/licenses/graal-free-license.html). The community builds published on Github have been renamed to `graalpy-community-<version>-<os>-<arch>.tar.gz`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
///usr/bin/env jbang "$0" "$@" ; exit $?
42+
43+
//DEPS org.graalvm.python:python-language:24.0.0-dev
44+
//DEPS org.graalvm.python:python-resources:24.0.0-dev
45+
//DEPS org.graalvm.python:python-launcher:24.0.0-dev
46+
//DEPS org.graalvm.python:python-embedding:24.0.0-dev
47+
//PIP termcolor
48+
49+
import org.graalvm.polyglot.Context;
50+
import org.graalvm.polyglot.PolyglotAccess;
51+
import org.graalvm.polyglot.PolyglotException;
52+
import org.graalvm.polyglot.io.IOAccess;
53+
import org.graalvm.python.embedding.utils.VirtualFileSystem;
54+
55+
public class hello {
56+
public static void main(String[] args) {
57+
System.out.println("Running main method from Java.");
58+
try (Context context = VirtualGraalPyContext.getContext()) {
59+
switch (args.length) {
60+
case 0:
61+
context.eval("python", "print('Hello from Python')");
62+
break;
63+
case 1:
64+
context.eval("python", args[0]);
65+
break;
66+
default:
67+
throw new IllegalArgumentException("The main() helper only takes 0-1 arguments.");
68+
}
69+
} catch (PolyglotException e) {
70+
if (e.isExit()) {
71+
System.exit(e.getExitStatus());
72+
} else {
73+
throw e;
74+
}
75+
}
76+
}
77+
}
78+
79+
final class VirtualGraalPyContext {
80+
private static final String VENV_PREFIX = "/vfs/venv";
81+
private static final String HOME_PREFIX = "/vfs/home";
82+
83+
public static Context getContext() {
84+
VirtualFileSystem vfs = VirtualFileSystem.create();
85+
var builder = Context.newBuilder()
86+
// set true to allow experimental options
87+
.allowExperimentalOptions(false)
88+
// deny all privileges unless configured below
89+
.allowAllAccess(false)
90+
// allow access to the virtual and the host filesystem, as well as sockets
91+
.allowIO(IOAccess.newBuilder()
92+
.allowHostSocketAccess(true)
93+
.fileSystem(vfs)
94+
.build())
95+
// allow creating python threads
96+
.allowCreateThread(true)
97+
// allow running Python native extensions
98+
.allowNativeAccess(true)
99+
// allow exporting Python values to polyglot bindings and accessing Java from Python
100+
.allowPolyglotAccess(PolyglotAccess.ALL)
101+
// choose the backend for the POSIX module
102+
.option("python.PosixModuleBackend", "java")
103+
// equivalent to the Python -B flag
104+
.option("python.DontWriteBytecodeFlag", "true")
105+
// equivalent to the Python -v flag
106+
.option("python.VerboseFlag", System.getenv("PYTHONVERBOSE") != null ? "true" : "false")
107+
// log level
108+
.option("log.python.level", System.getenv("PYTHONVERBOSE") != null ? "FINE" : "SEVERE")
109+
// equivalent to setting the PYTHONWARNINGS environment variable
110+
.option("python.WarnOptions", System.getenv("PYTHONWARNINGS") == null ? "" : System.getenv("PYTHONWARNINGS"))
111+
// print Python exceptions directly
112+
.option("python.AlwaysRunExcepthook", "true")
113+
// Force to automatically import site.py module, to make Python packages available
114+
.option("python.ForceImportSite", "true")
115+
// The sys.executable path, a virtual path that is used by the interpreter to discover packages
116+
.option("python.Executable", vfs.resourcePathToPlatformPath(VENV_PREFIX) + (VirtualFileSystem.isWindows() ? "\\Scripts\\python.exe" : "/bin/python"))
117+
// Do not warn if running without JIT. This can be desirable for short running scripts
118+
// to reduce memory footprint.
119+
.option("engine.WarnInterpreterOnly", "false");
120+
if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
121+
// Set the python home to be read from the embedded resources
122+
builder.option("python.PythonHome", vfs.resourcePathToPlatformPath(HOME_PREFIX));
123+
}
124+
return builder.build();
125+
}
126+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
{#for dep in dependencies.orEmpty}
3+
//DEPS {dep}
4+
{/for}
5+
{#if dependencies.isEmpty()}// //DEPS <dependency1> <dependency2>{/if}
6+
7+
//DEPS org.graalvm.python:python-language:24.0.0-dev
8+
//DEPS org.graalvm.python:python-resources:24.0.0-dev
9+
//DEPS org.graalvm.python:python-launcher:24.0.0-dev
10+
//DEPS org.graalvm.python:python-embedding:24.0.0-dev
11+
//PIP termcolor
12+
13+
import org.graalvm.polyglot.Context;
14+
import org.graalvm.polyglot.PolyglotAccess;
15+
import org.graalvm.polyglot.PolyglotException;
16+
import org.graalvm.polyglot.io.IOAccess;
17+
import org.graalvm.python.embedding.utils.VirtualFileSystem;
18+
19+
public class {baseName} {
20+
public static void main(String[] args) {
21+
System.out.println("Running2");
22+
try (Context context = VirtualGraalPyContext.getContext()) {
23+
switch (args.length) {
24+
case 0:
25+
context.eval("python", "import site; site._script()");
26+
break;
27+
case 1:
28+
context.eval("python", args[0]);
29+
break;
30+
default:
31+
throw new IllegalArgumentException("The main() helper only takes 0-1 arguments.");
32+
}
33+
} catch (PolyglotException e) {
34+
if (e.isExit()) {
35+
System.exit(e.getExitStatus());
36+
} else {
37+
throw e;
38+
}
39+
}
40+
}
41+
}
42+
43+
final class VirtualGraalPyContext {
44+
private static final String VENV_PREFIX = "/vfs/venv";
45+
private static final String HOME_PREFIX = "/vfs/home";
46+
47+
public static Context getContext() {
48+
VirtualFileSystem vfs = VirtualFileSystem.create();
49+
var builder = Context.newBuilder()
50+
// set true to allow experimental options
51+
.allowExperimentalOptions(false)
52+
// deny all privileges unless configured below
53+
.allowAllAccess(false)
54+
// allow access to the virtual and the host filesystem, as well as sockets
55+
.allowIO(IOAccess.newBuilder()
56+
.allowHostSocketAccess(true)
57+
.fileSystem(vfs)
58+
.build())
59+
// allow creating python threads
60+
.allowCreateThread(true)
61+
// allow running Python native extensions
62+
.allowNativeAccess(true)
63+
// allow exporting Python values to polyglot bindings and accessing Java from Python
64+
.allowPolyglotAccess(PolyglotAccess.ALL)
65+
// choose the backend for the POSIX module
66+
.option("python.PosixModuleBackend", "java")
67+
// equivalent to the Python -B flag
68+
.option("python.DontWriteBytecodeFlag", "true")
69+
// equivalent to the Python -v flag
70+
.option("python.VerboseFlag", System.getenv("PYTHONVERBOSE") != null ? "true" : "false")
71+
// log level
72+
.option("log.python.level", System.getenv("PYTHONVERBOSE") != null ? "FINE" : "SEVERE")
73+
// equivalent to setting the PYTHONWARNINGS environment variable
74+
.option("python.WarnOptions", System.getenv("PYTHONWARNINGS") == null ? "" : System.getenv("PYTHONWARNINGS"))
75+
// print Python exceptions directly
76+
.option("python.AlwaysRunExcepthook", "true")
77+
// Force to automatically import site.py module, to make Python packages available
78+
.option("python.ForceImportSite", "true")
79+
// The sys.executable path, a virtual path that is used by the interpreter to discover packages
80+
.option("python.Executable", vfs.resourcePathToPlatformPath(VENV_PREFIX) + (VirtualFileSystem.isWindows() ? "\\Scripts\\python.exe" : "/bin/python"))
81+
// Do not warn if running without JIT. This can be desirable for short running scripts
82+
// to reduce memory footprint.
83+
.option("engine.WarnInterpreterOnly", "false");
84+
if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
85+
// Set the python home to be read from the embedded resources
86+
builder.option("python.PythonHome", vfs.resourcePathToPlatformPath(HOME_PREFIX));
87+
}
88+
return builder.build();
89+
}
90+
}
91+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
///usr/bin/env jbang "$0" "$@" ; exit $?
2+
{#for dep in dependencies.orEmpty}
3+
//DEPS {dep}
4+
{/for}
5+
{#if dependencies.isEmpty()}// //DEPS <dependency1> <dependency2>{/if}
6+
7+
//REPOS mc=https://repo1.maven.org/maven2/
8+
//REPOS local=file://{path_to_local_repo}
9+
//DEPS org.graalvm.python:python-language:24.0.0-dev
10+
//DEPS org.graalvm.python:python-resources:24.0.0-dev
11+
//DEPS org.graalvm.python:python-launcher:24.0.0-dev
12+
//DEPS org.graalvm.python:python-embedding:24.0.0-dev
13+
//PIP termcolor
14+
15+
import org.graalvm.polyglot.Context;
16+
import org.graalvm.polyglot.PolyglotAccess;
17+
import org.graalvm.polyglot.PolyglotException;
18+
import org.graalvm.polyglot.io.IOAccess;
19+
import org.graalvm.python.embedding.utils.VirtualFileSystem;
20+
21+
public class {baseName} {
22+
public static void main(String[] args) {
23+
System.out.println("Running2");
24+
try (Context context = VirtualGraalPyContext.getContext()) {
25+
switch (args.length) {
26+
case 0:
27+
context.eval("python", "import site; site._script()");
28+
break;
29+
case 1:
30+
context.eval("python", args[0]);
31+
break;
32+
default:
33+
throw new IllegalArgumentException("The main() helper only takes 0-1 arguments.");
34+
}
35+
} catch (PolyglotException e) {
36+
if (e.isExit()) {
37+
System.exit(e.getExitStatus());
38+
} else {
39+
throw e;
40+
}
41+
}
42+
}
43+
}
44+
45+
final class VirtualGraalPyContext {
46+
private static final String VENV_PREFIX = "/vfs/venv";
47+
private static final String HOME_PREFIX = "/vfs/home";
48+
49+
public static Context getContext() {
50+
VirtualFileSystem vfs = VirtualFileSystem.create();
51+
var builder = Context.newBuilder()
52+
// set true to allow experimental options
53+
.allowExperimentalOptions(false)
54+
// deny all privileges unless configured below
55+
.allowAllAccess(false)
56+
// allow access to the virtual and the host filesystem, as well as sockets
57+
.allowIO(IOAccess.newBuilder()
58+
.allowHostSocketAccess(true)
59+
.fileSystem(vfs)
60+
.build())
61+
// allow creating python threads
62+
.allowCreateThread(true)
63+
// allow running Python native extensions
64+
.allowNativeAccess(true)
65+
// allow exporting Python values to polyglot bindings and accessing Java from Python
66+
.allowPolyglotAccess(PolyglotAccess.ALL)
67+
// choose the backend for the POSIX module
68+
.option("python.PosixModuleBackend", "java")
69+
// equivalent to the Python -B flag
70+
.option("python.DontWriteBytecodeFlag", "true")
71+
// equivalent to the Python -v flag
72+
.option("python.VerboseFlag", System.getenv("PYTHONVERBOSE") != null ? "true" : "false")
73+
// log level
74+
.option("log.python.level", System.getenv("PYTHONVERBOSE") != null ? "FINE" : "SEVERE")
75+
// equivalent to setting the PYTHONWARNINGS environment variable
76+
.option("python.WarnOptions", System.getenv("PYTHONWARNINGS") == null ? "" : System.getenv("PYTHONWARNINGS"))
77+
// print Python exceptions directly
78+
.option("python.AlwaysRunExcepthook", "true")
79+
// Force to automatically import site.py module, to make Python packages available
80+
.option("python.ForceImportSite", "true")
81+
// The sys.executable path, a virtual path that is used by the interpreter to discover packages
82+
.option("python.Executable", vfs.resourcePathToPlatformPath(VENV_PREFIX) + (VirtualFileSystem.isWindows() ? "\\Scripts\\python.exe" : "/bin/python"))
83+
// Do not warn if running without JIT. This can be desirable for short running scripts
84+
// to reduce memory footprint.
85+
.option("engine.WarnInterpreterOnly", "false");
86+
if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
87+
// Set the python home to be read from the embedded resources
88+
builder.option("python.PythonHome", vfs.resourcePathToPlatformPath(HOME_PREFIX));
89+
}
90+
return builder.build();
91+
}
92+
}
93+

jbang-catalog.json

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"catalogs": {},
3+
"aliases": {
4+
"hello": {
5+
"script-ref": "./graalpython/graalpy-jbang/examples/hello.java",
6+
"description": "Script that says hello from Python started from Java or execute Python expression as parameter."
7+
}
8+
},
9+
"templates": {
10+
"graalpy": {
11+
"file-refs": {
12+
"{basename}.java": "./graalpython/graalpy-jbang/templates/graalpy-template.java.qute"
13+
},
14+
"properties": {},
15+
"description": "Basic template for Graal Python java file."
16+
},
17+
"graalpy_local_repo": {
18+
"file-refs": {
19+
"{basename}.java": "./graalpython/graalpy-jbang/templates/graalpy-template_local_repo.java.qute"
20+
},
21+
"properties": {
22+
"path_to_local_repo": {
23+
"default": "/path/to/local/maven/repository",
24+
"description": "Path to your local maven repository"
25+
}
26+
},
27+
"description": "Basic template for Graal Python java file. Mainly for testing."
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)