Skip to content

Commit 6430fab

Browse files
committed
VirtualFileSystem: detect multiple VFS in one app, provide way to namespace and isolate VFS instances
1 parent 69c9749 commit 6430fab

File tree

43 files changed

+1989
-274
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1989
-274
lines changed

docs/user/Embedding-Build-Tools.md

+50-16
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ required for embedding Python code in Java-based applications:
1212
- *Python application files* provided by the user, for example, Python sources which are part of the project.
1313
- *Third-party Python packages* installed by the plugin during the build according to the plugin configuration.
1414

15-
Apart from physically managing and deploying those files, it is also necessary to make them available in Python at runtime by configuring the **GraalPy Context** in your Java code accordingly.
15+
Apart from physically managing and deploying those files, it is also necessary to make them available in Python at runtime by configuring the **GraalPy Context** in your Java code accordingly.
1616
The [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) API provides factory methods to create a Context preconfigured for accessing Python, embedding relevant resources with a **Virtual Filesystem** or from a dedicated **external directory**.
1717

1818
## Deployment
@@ -22,12 +22,15 @@ There are two modes how to deploy the resources: as Java resources using the Vir
2222
### Virtual Filesystem
2323

2424
The Python related resources are embedded in the application file, either in JAR or Native Image generated
25-
executable, as standard Java resources.
26-
The GraalPy Virtual Filesystem accesses resource files as standard Java resources and makes them available to Python code running in GraalPy.
25+
executable, as standard Java resources.
26+
The GraalPy Virtual Filesystem internally accesses the resource files as standard Java resources and makes them available to Python code running in GraalPy.
2727
This is transparent to the Python code, which can use standard Python IO to access those files.
2828

29-
Java resource files in a Maven or Gradle project are typically located in dedicated resources directories.
30-
All resources subdirectories named _org.graalvm.python.vfs_ are merged and mapped to a configurable Virtual Filesystem mount point at the Python side, by default `/graalpy_vfs`.
29+
Java resource files in a Maven or Gradle project are typically located in dedicated resources directories, such as `src/main/resources`.
30+
Moreover, there can be multiple resources directories and Maven or Gradle usually merges them.
31+
32+
User can choose relative Java resources path that will be made accessible in Python through the virtual filesystem,
33+
by default it is `org.graalvm.python.vfs`. All resources subdirectories with this path are merged during build and mapped to a configurable Virtual Filesystem mount point at the Python side, by default `/graalpy_vfs`.
3134
For example, a Python file with the real filesystem path `${project_resources_directory}/org.graalvm.python.vfs/src/foo/bar.py` will be accessible as `/graalpy_vfs/src/foo/bar.py` in Python.
3235

3336
Use the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java)
@@ -36,20 +39,37 @@ factory methods to create GraalPy Context preconfigured for the use of the Virtu
3639
* `GraalPyResources.contextBuilder()`
3740
* `GraalPyResources.contextBuilder(VirtualFileSystem)`
3841

42+
#### Java Resource Path
43+
Particularly when developing reusable libraries, it is recommended to use custom unique Java resources path for your
44+
virtual filesystem to avoid conflicts with other libraries on the classpath or modulepath that may also use the
45+
Virtual Filesystem. The recommended path is:
46+
```
47+
GRAALPY-VFS/${project.groupId}/${project.artifactId}
48+
```
49+
50+
The Java resources path must be configured in the Maven and Gradle plugins and must be also set to the same value
51+
at runtime using the `VirtualFileSystem$Builder#resourceDirectory` API.
52+
53+
*Note regarding Java module system: resources in named modules are subject to the encapsulation rules specified by
54+
[Module.getResourceAsStream](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Module.html#getResourceAsStream(java.lang.String)).
55+
This is also the case of the default virtual filesystem location. When a resources directory is not
56+
a valid Java package name, such as the recommended "GRAALPY-VFS", the resources are not subject to
57+
the encapsulation rules and do not require additional module system configuration.*
58+
3959
### External Directory
4060

41-
As an alternative to Java resources with the Virtual Filesystem, it is also possible to configure the Maven or Gradle plugin to manage the contents of an external directory, which will **not be embedded** as a Java resource into the resulting application.
42-
A user is then responsible for the deployment of such directory.
61+
As an alternative to Java resources with the Virtual Filesystem, it is also possible to configure the Maven or Gradle plugin to manage the contents of an external directory, which will **not be embedded** as a Java resource into the resulting application.
62+
A user is then responsible for the deployment of such directory.
4363
Python code will access the files directly from the real filesystem.
4464

4565
Use the following [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) factory methods to create GraalPy Context preconfigured for the use of an external directory:
4666
* `GraalPyResources.createContextBuilder(Path)`
4767

4868
## Conventions
4969

50-
The factory methods in [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) rely on the following conventions, where the `${root}` is either an external directory, or a Virtual System mount point on the Python side and `${project_resources_directory}/org.graalvm.python.vfs` on the real filesystem:
70+
The factory methods in [GraalPyResources](https://github.com/oracle/graalpython/blob/master/graalpython/org.graalvm.python.embedding/src/org/graalvm/python/embedding/utils/GraalPyResources.java) rely on the following conventions, where the `${root}` is either an external directory, or a Virtual System mount point on the Python side and Java resources directories, such as `${project_resources_directory}/org.graalvm.python.vfs`, on the real filesystem:
5171
- `${root}/src`: used for Python application files. This directory will be configured as the default search path for Python module files (equivalent to `PYTHONPATH` environment variable).
52-
- `${root}/venv`: used for the Python virtual environment holding installed third-party Python packages.
72+
- `${root}/venv`: used for the Python virtual environment holding installed third-party Python packages.
5373
The Context will be configured as if it is executed from this virtual environment. Notably packages installed in this
5474
virtual environment will be automatically available for importing.
5575

@@ -73,8 +93,8 @@ Add the plugin configuration in the `configuration` block of `graalpy-maven-plug
7393
...
7494
</plugin>
7595
```
76-
The **packages** element declares a list of third-party Python packages to be downloaded and installed by the plugin.
77-
- The Python packages and their versions are specified as if used with `pip`:
96+
- The **packages** element declares a list of third-party Python packages to be downloaded and installed by the plugin.
97+
The Python packages and their versions are specified as if used with `pip`:
7898
```xml
7999
<configuration>
80100
<packages>
@@ -84,11 +104,18 @@ The **packages** element declares a list of third-party Python packages to be do
84104
...
85105
</configuration>
86106
```
87-
- If the **pythonResourcesDirectory** element is specified, then the given directory is used as an [external directory](#external-directory) and no Java resources are embedded.
88-
Remember to use the appropriate `GraalPyResources` API to create the Context.
107+
108+
- The **resourceDirectory** element can specify the relative [Java resource path](#java-resource-path).
109+
Remember to use `VirtualFileSystem$Builder#resourceDirectory` when configuring the `VirtualFileSystem` in Java.
110+
```xml
111+
<resourceDirectory>GRAALPY-VFS/${project.groupId}/${project.artifactId}</resourceDirectory>
112+
```
113+
114+
- If the **externalDirectory** element is specified, then the given directory is used as an [external directory](#external-directory) and no Java resources are embedded.
115+
Remember to use the appropriate `GraalPyResources` API to create the Context. This element and **resourceDirectory** are mutually exclusive.
89116
```xml
90117
<configuration>
91-
<pythonResourcesDirectory>${basedir}/python-resources</pythonResourcesDirectory>
118+
<externalDirectory>${basedir}/python-resources</externalDirectory>
92119
...
93120
</configuration>
94121
```
@@ -118,11 +145,18 @@ The plugin can be configured in the `graalPy` block:
118145
...
119146
}
120147
```
121-
- If the **pythonResourcesDirectory** element is specified, then the given directory is used as an [external directory](#external-directory) and no Java resources are embedded.
148+
149+
- The **resourceDirectory** element can specify the relative [Java resource path](#java-resource-path).
150+
Remember to use `VirtualFileSystem$Builder#resourceDirectory` when configuring the `VirtualFileSystem` in Java.
151+
```
152+
resourceDirectory = "GRAALPY-VFS/my.group.id/artifact.id"
153+
```
154+
155+
- If the **externalDirectory** element is specified, then the given directory is used as an [external directory](#external-directory) and no Java resources are embedded.
122156
Remember to use the appropriate `GraalPyResources` API to create the Context.
123157
```
124158
graalPy {
125-
pythonResourcesDirectory = file("$rootDir/python-resources")
159+
externalDirectory = file("$rootDir/python-resources")
126160
...
127161
}
128162
```

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/SomeFile

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/dir1/extractme

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/dir1/file2

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
text1
2+
text2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
text1
2+
text2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/
2+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/dir1/
3+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/dir1/extractme
4+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/dir1/file2
5+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/emptydir/
6+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/file1
7+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/extractme
8+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/fileslist.txt
9+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/SomeFile
10+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/
11+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg/
12+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg/file.tso
13+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/
14+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/file1.tso
15+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/file2.tso
16+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/
17+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/file1.tso
18+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/file2.tso
19+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/nofilterfile
20+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/dir/
21+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/dir/file1.tso
22+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/dir/file2.tso
23+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg-nolibs/
24+
/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg-nolibs/file.tso

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg-nolibs/file.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/dir/file1.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/dir/file2.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/file1.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/file2.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/dir/nofilterfile

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/file1.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg.libs/file2.tso

Whitespace-only changes.

graalpython/com.oracle.graal.python.test.integration/src/GRAALPY-VFS/com.oracle.graal.python.test/integration/site-packages/testpkg/file.tso

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/GRAALPY-VFS/foo/
2+
/GRAALPY-VFS/foo/otherdir/
3+
/GRAALPY-VFS/foo/otherdir/hello.txt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
world

graalpython/com.oracle.graal.python.test.integration/src/org/graalvm/python/embedding/test/integration/GraalPyResourcesUtilsTests.java

+1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
* Siple copy of GraalPyResourcesTests to test also the deprecated
5252
* org.graalvm.python.embedding.utils pkg
5353
*/
54+
@SuppressWarnings("deprecation")
5455
public class GraalPyResourcesUtilsTests {
5556

5657
@Test

0 commit comments

Comments
 (0)