Skip to content

Commit a27a7b7

Browse files
Sowasvonbotelkorchi
authored andcommitted
add graalpy gradle plugin
(cherry picked from commit bd0e25e)
1 parent e4750c1 commit a27a7b7

File tree

9 files changed

+790
-0
lines changed

9 files changed

+790
-0
lines changed
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
4+
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5+
6+
The Universal Permissive License (UPL), Version 1.0
7+
8+
Subject to the condition set forth below, permission is hereby granted to any
9+
person obtaining a copy of this software, associated documentation and/or
10+
data (collectively the "Software"), free of charge and under any and all
11+
copyright rights in the Software, and any and all patent rights owned or
12+
freely licensable by each licensor hereunder covering either (i) the
13+
unmodified Software as contributed to or provided by such licensor, or (ii)
14+
the Larger Works (as defined below), to deal in both
15+
16+
(a) the Software, and
17+
18+
(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
19+
one is included with the Software each a "Larger Work" to which the Software
20+
is contributed by such licensors),
21+
22+
without restriction, including without limitation the rights to copy, create
23+
derivative works of, display, perform, and distribute the Software and make,
24+
use, sell, offer for sale, import, export, have made, and have sold the
25+
Software and the Larger Work(s), and to sublicense the foregoing rights on
26+
either these or other terms.
27+
28+
This license is subject to the following condition:
29+
30+
The above copyright notice and either this complete permission notice or at a
31+
minimum a reference to the UPL must be included in all copies or substantial
32+
portions of the Software.
33+
34+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40+
SOFTWARE.
41+
-->
42+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
43+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
44+
45+
<modelVersion>4.0.0</modelVersion>
46+
47+
<groupId>org.graalvm.python</groupId>
48+
<artifactId>graalpy-gradle-plugin</artifactId>
49+
<packaging>jar</packaging>
50+
<!-- This version is always overridden when deploying using mx -->
51+
<version>24.2.0</version>
52+
<url>http://www.graalvm.org/</url>
53+
<name>graalpy-gradle-plugin</name>
54+
<description>Handles python related resources in a gradle GraalPy - Java application.</description>
55+
56+
<properties>
57+
<maven.compiler.target>17</maven.compiler.target>
58+
<maven.compiler.source>17</maven.compiler.source>
59+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
60+
<graalpy.version>24.2.0</graalpy.version>
61+
<gradle.version>6.1.1</gradle.version>
62+
</properties>
63+
64+
<profiles>
65+
<profile>
66+
<id>Version from suite</id>
67+
<activation>
68+
<property>
69+
<name>env.GRAALPY_VERSION</name>
70+
</property>
71+
</activation>
72+
<properties>
73+
<graalpy.version>${env.GRAALPY_VERSION}</graalpy.version>
74+
</properties>
75+
</profile>
76+
</profiles>
77+
78+
79+
<dependencies>
80+
<dependency>
81+
<groupId>org.codehaus.groovy</groupId>
82+
<artifactId>groovy</artifactId>
83+
<version>3.0.22</version>
84+
<scope>provided</scope>
85+
</dependency>
86+
<dependency>
87+
<groupId>org.gradle</groupId>
88+
<artifactId>gradle-tooling-api</artifactId>
89+
<version>8.8</version>
90+
</dependency>
91+
<dependency>
92+
<groupId>org.gradle</groupId>
93+
<artifactId>gradle-core</artifactId>
94+
<scope>provided</scope>
95+
<version>${gradle.version}</version>
96+
</dependency>
97+
<dependency>
98+
<groupId>org.gradle</groupId>
99+
<artifactId>gradle-core-api</artifactId>
100+
<scope>provided</scope>
101+
<version>${gradle.version}</version>
102+
</dependency>
103+
<dependency>
104+
<groupId>org.gradle</groupId>
105+
<artifactId>gradle-model-core</artifactId>
106+
<scope>provided</scope>
107+
<version>${gradle.version}</version>
108+
</dependency>
109+
<dependency>
110+
<groupId>org.gradle</groupId>
111+
<artifactId>gradle-language-java</artifactId>
112+
<scope>provided</scope>
113+
<version>${gradle.version}</version>
114+
</dependency>
115+
<dependency>
116+
<groupId>org.gradle</groupId>
117+
<artifactId>gradle-language-jvm</artifactId>
118+
<scope>provided</scope>
119+
<version>${gradle.version}</version>
120+
</dependency>
121+
<dependency>
122+
<groupId>org.gradle</groupId>
123+
<artifactId>gradle-platform-jvm</artifactId>
124+
<scope>provided</scope>
125+
<version>${gradle.version}</version>
126+
</dependency>
127+
<dependency>
128+
<groupId>org.gradle</groupId>
129+
<artifactId>gradle-base-services</artifactId>
130+
<version>${gradle.version}</version>
131+
<scope>provided</scope>
132+
</dependency>
133+
<dependency>
134+
<groupId>org.gradle</groupId>
135+
<artifactId>gradle-plugins</artifactId>
136+
<scope>provided</scope>
137+
<version>${gradle.version}</version>
138+
</dependency>
139+
<dependency>
140+
<groupId>org.gradle</groupId>
141+
<artifactId>gradle-logging</artifactId>
142+
<version>${gradle.version}</version>
143+
<scope>provided</scope>
144+
</dependency>
145+
146+
<dependency>
147+
<groupId>org.graalvm.python</groupId>
148+
<artifactId>python-embedding-tools</artifactId>
149+
<version>${graalpy.version}</version>
150+
<scope>compile</scope>
151+
</dependency>
152+
<dependency>
153+
<groupId>org.graalvm.python</groupId>
154+
<artifactId>python-launcher</artifactId>
155+
<version>${graalpy.version}</version>
156+
<scope>runtime</scope>
157+
</dependency>
158+
</dependencies>
159+
160+
<repositories>
161+
<repository>
162+
<id>maven</id>
163+
<url>https://repo1.maven.org/maven2/</url>
164+
</repository>
165+
<repository>
166+
<id>gradle</id>
167+
<url>https://repo.gradle.org/gradle/libs-releases/</url>
168+
<releases>
169+
<enabled>true</enabled>
170+
</releases>
171+
<snapshots>
172+
<enabled>false</enabled>
173+
</snapshots>
174+
</repository>
175+
<repository>
176+
<id>gradle-local</id>
177+
<url>https://repo.gradle.org/gradle/libs-releases-local/</url>
178+
<releases>
179+
<enabled>true</enabled>
180+
</releases>
181+
<snapshots>
182+
<enabled>false</enabled>
183+
</snapshots>
184+
</repository>
185+
</repositories>
186+
187+
188+
</project>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package org.graalvm.python;
2+
3+
import org.graalvm.python.dsl.GraalPyExtension;
4+
import org.graalvm.python.tasks.GenerateManifestTask;
5+
import org.graalvm.python.tasks.InstallPackagesTask;
6+
import org.gradle.api.GradleException;
7+
import org.gradle.api.Plugin;
8+
import org.gradle.api.Project;
9+
import org.gradle.api.artifacts.Dependency;
10+
import org.gradle.api.artifacts.DependencySet;
11+
import org.gradle.api.plugins.JavaPlugin;
12+
import org.gradle.jvm.tasks.Jar;
13+
import org.gradle.language.jvm.tasks.ProcessResources;
14+
15+
import java.util.Collections;
16+
import java.util.List;
17+
18+
19+
public abstract class GraalPyGradlePlugin implements Plugin<Project> {
20+
private static final String PYTHON_LAUNCHER_ARTIFACT_ID = "python-launcher";
21+
private static final String PYTHON_EMBEDDING_ARTIFACT_ID = "python-embedding";
22+
public static final String GRAALPY_GROUP_ID = "org.graalvm.python";
23+
24+
private static final String POLYGLOT_GROUP_ID = "org.graalvm.polyglot";
25+
private static final String PYTHON_COMMUNITY_ARTIFACT_ID = "python-community";
26+
private static final String PYTHON_ARTIFACT_ID = "python";
27+
private static final String GRAALPY_GRADLE_PLUGIN_TASK_GROUP = "graalpy";
28+
29+
private static final String DEFAULT_WRAPPER_DIRECTORY = "python-generated";
30+
31+
GraalPyExtension extension;
32+
Project project;
33+
34+
@Override
35+
public void apply(Project project) {
36+
this.project = project;
37+
project.getPluginManager().apply(JavaPlugin.class);
38+
39+
40+
this.extension = project.getExtensions().create("graalPy", GraalPyExtension.class);
41+
extension.getPythonHome().getIncludes().convention(List.of(".*"));
42+
extension.getPythonHome().getExcludes().convention(Collections.emptyList());
43+
extension.getPackages().convention(Collections.emptyList());
44+
45+
var installPackagesTask = project.getTasks().register("installPackages", InstallPackagesTask.class);
46+
47+
48+
final var generateManifestTask = project.getTasks().register("generateManifest", GenerateManifestTask.class);
49+
project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME, t -> ((Jar) t).getMetaInf().from(generateManifestTask));
50+
generateManifestTask.configure(t -> {
51+
t.getManifestOutputDir().convention(project.getLayout().getBuildDirectory().dir("GRAAL-META-INF"));
52+
t.setGroup(GRAALPY_GRADLE_PLUGIN_TASK_GROUP);
53+
});
54+
55+
installPackagesTask.configure(t -> {
56+
t.getIncludes().set(extension.getPythonHome().getIncludes());
57+
t.getExcludes().set(extension.getPythonHome().getExcludes());
58+
t.getPackages().set(extension.getPackages());
59+
t.getIncludeVfsRoot().set(extension.getIncludeVfsRootDir());
60+
61+
t.getOutput().set(extension.getPythonResourcesDirectory());
62+
63+
t.setGroup(GRAALPY_GRADLE_PLUGIN_TASK_GROUP);
64+
});
65+
66+
project.afterEvaluate(p -> {
67+
checkAndAddDependencies();
68+
69+
if (!extension.getPythonResourcesDirectory().isPresent())
70+
((ProcessResources) project.getTasks().getByName(JavaPlugin.PROCESS_RESOURCES_TASK_NAME)).with(project.copySpec().from(installPackagesTask));
71+
72+
// Provide the default value after the isPresent check, otherwise isPresent always returns true
73+
extension.getPythonResourcesDirectory().convention(project.getLayout().getBuildDirectory().dir(DEFAULT_WRAPPER_DIRECTORY));
74+
});
75+
76+
}
77+
78+
79+
private void checkAndAddDependencies() {
80+
project.getDependencies().add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, "%s:%s:%s".formatted(GRAALPY_GROUP_ID, PYTHON_LAUNCHER_ARTIFACT_ID, getGraalPyVersion(project)));
81+
project.getDependencies().add(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME, "%s:%s:%s".formatted(GRAALPY_GROUP_ID, PYTHON_EMBEDDING_ARTIFACT_ID, getGraalPyVersion(project)));
82+
}
83+
84+
85+
public static String getGraalPyVersion(Project project) {
86+
return getGraalPyDependency(project).getVersion();
87+
}
88+
89+
public static Dependency getGraalPyDependency(Project project) {
90+
return resolveProjectDependencies(project).stream().filter(GraalPyGradlePlugin::isPythonArtifact).findFirst().orElseThrow(() -> new GradleException("Missing GraalPy dependency. Please add to your build.gradle either %s:%s or %s:%s".formatted(POLYGLOT_GROUP_ID, PYTHON_COMMUNITY_ARTIFACT_ID, POLYGLOT_GROUP_ID, PYTHON_ARTIFACT_ID)));
91+
}
92+
93+
private static boolean isPythonArtifact(Dependency dependency) {
94+
return (POLYGLOT_GROUP_ID.equals(dependency.getGroup()) || GRAALPY_GROUP_ID.equals(dependency.getGroup())) &&
95+
(PYTHON_COMMUNITY_ARTIFACT_ID.equals(dependency.getName()) || PYTHON_ARTIFACT_ID.equals(dependency.getName()));
96+
}
97+
98+
private static DependencySet resolveProjectDependencies(Project project) {
99+
return project.getConfigurations().getByName("implementation").getAllDependencies();
100+
}
101+
102+
103+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package org.graalvm.python;
2+
3+
import groovy.util.logging.Log;
4+
import org.graalvm.python.embedding.tools.exec.SubprocessLog;
5+
import org.gradle.api.logging.Logger;
6+
7+
public class GradleLogger implements SubprocessLog {
8+
private Logger logger;
9+
10+
private GradleLogger(Logger logger) {
11+
this.logger = logger;
12+
}
13+
14+
@Override
15+
public void subProcessOut(CharSequence out) {
16+
logger.lifecycle(out.toString());
17+
}
18+
19+
@Override
20+
public void subProcessErr(CharSequence err) {
21+
logger.warn(err.toString());
22+
}
23+
24+
@Override
25+
public void log(CharSequence txt) {
26+
logger.lifecycle(txt.toString());
27+
}
28+
29+
@Override
30+
public void log(CharSequence txt, Throwable t) {
31+
logger.lifecycle(txt.toString(), t);
32+
}
33+
34+
public static GradleLogger of(Logger logger) {
35+
return new GradleLogger(logger);
36+
}
37+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package org.graalvm.python.dsl;
2+
3+
import org.gradle.api.Action;
4+
import org.gradle.api.file.DirectoryProperty;
5+
import org.gradle.api.provider.ListProperty;
6+
import org.gradle.api.provider.Property;
7+
import org.gradle.api.tasks.Nested;
8+
9+
public interface GraalPyExtension {
10+
DirectoryProperty getPythonResourcesDirectory();
11+
12+
ListProperty<String> getPackages();
13+
14+
Property<Boolean> getIncludeVfsRootDir();
15+
16+
@Nested
17+
PythonHomeInfo getPythonHome();
18+
19+
default void pythonHome(Action<? super PythonHomeInfo> action) {
20+
action.execute(getPythonHome());
21+
}
22+
23+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.graalvm.python.dsl;
2+
3+
import org.gradle.api.provider.SetProperty;
4+
5+
public interface PythonHomeInfo {
6+
SetProperty<String> getIncludes();
7+
SetProperty<String> getExcludes();
8+
}

0 commit comments

Comments
 (0)