40
40
*/
41
41
package org .graalvm .python .maven .plugin ;
42
42
43
+ import org .apache .maven .artifact .Artifact ;
44
+ import org .apache .maven .artifact .DefaultArtifact ;
45
+ import org .apache .maven .artifact .handler .DefaultArtifactHandler ;
46
+ import org .apache .maven .execution .MavenSession ;
47
+ import org .apache .maven .plugin .AbstractMojo ;
48
+ import org .apache .maven .plugin .MojoExecutionException ;
49
+ import org .apache .maven .plugin .logging .Log ;
50
+ import org .apache .maven .plugins .annotations .*;
51
+ import org .apache .maven .project .*;
52
+ import org .eclipse .aether .graph .Dependency ;
53
+ import org .graalvm .python .embedding .utils .GraalPyRunner ;
54
+ import org .graalvm .python .embedding .utils .VFSUtils ;
55
+
43
56
import java .io .File ;
44
57
import java .io .FileWriter ;
45
58
import java .io .IOException ;
46
- import java .nio .file .*;
59
+ import java .nio .file .Files ;
60
+ import java .nio .file .Path ;
61
+ import java .nio .file .Paths ;
62
+ import java .nio .file .StandardOpenOption ;
47
63
import java .nio .file .attribute .PosixFilePermission ;
48
64
import java .util .*;
49
65
import java .util .stream .Collectors ;
50
66
51
- import org .apache .maven .artifact .Artifact ;
52
- import org .apache .maven .plugin .AbstractMojo ;
53
- import org .apache .maven .plugin .MojoExecutionException ;
54
- import org .apache .maven .plugin .logging .Log ;
55
- import org .apache .maven .plugins .annotations .LifecyclePhase ;
56
- import org .apache .maven .plugins .annotations .Mojo ;
57
- import org .apache .maven .plugins .annotations .Parameter ;
58
- import org .apache .maven .plugins .annotations .ResolutionScope ;
59
- import org .apache .maven .project .MavenProject ;
60
- import org .graalvm .python .embedding .utils .VFSUtils ;
61
- import org .graalvm .python .embedding .utils .GraalPyRunner ;
62
-
63
67
@ Mojo (name = "process-graalpy-resources" , defaultPhase = LifecyclePhase .PROCESS_RESOURCES ,
64
68
requiresDependencyCollection = ResolutionScope .COMPILE_PLUS_RUNTIME ,
65
69
requiresDependencyResolution = ResolutionScope .COMPILE_PLUS_RUNTIME )
66
70
public class ManageResourcesMojo extends AbstractMojo {
67
71
68
- private static final String PYTHON_LANGUAGE = "python-language" ;
72
+ private static final String PYTHON_LANGUAGE_ARTIFACT_ID = "python-language" ;
69
73
private static final String PYTHON_RESOURCES = "python-resources" ;
70
- private static final String PYTHON_LAUNCHER = "python-launcher" ;
71
- private static final String GRAALPY_GROUP = "org.graalvm.python" ;
74
+ private static final String PYTHON_LAUNCHER_ARTIFACT_ID = "python-launcher" ;
75
+ private static final String GRAALPY_GROUP_ID = "org.graalvm.python" ;
76
+
77
+ private static final String POLYGLOT_GROUP_ID = "org.graalvm.polyglot" ;
78
+ private static final String PYTHON_COMMUNITY_ARTIFACT_ID = "python-community" ;
79
+ private static final String PYTHON_ARTIFACT_ID = "python" ;
80
+ private static final String GRAALPY_MAVEN_PLUGIN_ARTIFACT_ID = "graalpy-maven-plugin" ;
72
81
73
82
private static final String GRAALPY_MAIN_CLASS = "com.oracle.graal.python.shell.GraalPythonMain" ;
74
83
@@ -88,6 +97,14 @@ public class ManageResourcesMojo extends AbstractMojo {
88
97
@ Parameter
89
98
PythonHome pythonHome ;
90
99
100
+ @ Parameter (defaultValue = "${session}" , readonly = true , required = true )
101
+ private MavenSession session ;
102
+
103
+ @ Component
104
+ private ProjectBuilder projectBuilder ;
105
+
106
+ private Set <String > launcherClassPath ;
107
+
91
108
static Path getHomeDirectory (MavenProject project ) {
92
109
return Path .of (project .getBuild ().getOutputDirectory (), "vfs" , "home" );
93
110
}
@@ -136,7 +153,7 @@ private void manageHome() throws MojoExecutionException {
136
153
try {
137
154
if (!Files .exists (homeDirectory )) {
138
155
Files .createDirectories (homeDirectory .getParent ());
139
- VFSUtils .copyGraalPyHome (calculateClasspath (project ), homeDirectory , pythonHomeIncludes , pythonHomeExcludes , new MavenDelegateLog (getLog ()));
156
+ VFSUtils .copyGraalPyHome (calculateLauncherClasspath (project ), homeDirectory , pythonHomeIncludes , pythonHomeExcludes , new MavenDelegateLog (getLog ()));
140
157
}
141
158
Files .write (tag , List .of (graalPyVersion ), StandardOpenOption .CREATE , StandardOpenOption .TRUNCATE_EXISTING );
142
159
write (tag , pythonHomeIncludes , INCLUDE_PREFIX );
@@ -279,7 +296,7 @@ private void generateLaunchers() throws MojoExecutionException {
279
296
var launcher = getLauncherPath ();
280
297
if (!Files .exists (launcher )) {
281
298
var java = Paths .get (System .getProperty ("java.home" ), "bin" , "java" );
282
- var classpath = calculateClasspath (project );
299
+ var classpath = calculateLauncherClasspath (project );
283
300
if (!IS_WINDOWS ) {
284
301
var script = String .format ("""
285
302
#!/usr/bin/env bash
@@ -357,8 +374,8 @@ private void runVenvBin(Path venvDirectory, String bin, String... args) throws M
357
374
}
358
375
}
359
376
360
- private static void runGraalPy (MavenProject project , Log log , String ... args ) throws MojoExecutionException {
361
- var classpath = calculateClasspath (project );
377
+ private void runGraalPy (MavenProject project , Log log , String ... args ) throws MojoExecutionException {
378
+ var classpath = calculateLauncherClasspath (project );
362
379
try {
363
380
GraalPyRunner .run (classpath , new MavenDelegateLog (log ), args );
364
381
} catch (IOException | InterruptedException e ) {
@@ -367,17 +384,21 @@ private static void runGraalPy(MavenProject project, Log log, String... args) th
367
384
}
368
385
369
386
private static String getGraalPyVersion (MavenProject project ) throws MojoExecutionException {
370
- return getGraalPyArtifact (project , PYTHON_LANGUAGE ).getVersion ();
387
+ return getGraalPyArtifact (project ).getVersion ();
371
388
}
372
389
373
- private static Artifact getGraalPyArtifact (MavenProject project , String aid ) throws MojoExecutionException {
390
+ private static Artifact getGraalPyArtifact (MavenProject project ) throws MojoExecutionException {
374
391
var projectArtifacts = resolveProjectDependencies (project );
375
- for (var a : projectArtifacts ) {
376
- if (a .getGroupId ().equals (GRAALPY_GROUP ) && a .getArtifactId ().equals (aid )) {
377
- return a ;
378
- }
379
- }
380
- throw new MojoExecutionException (String .format ("Missing GraalPy dependency %s:%s. Please add it to your pom" , GRAALPY_GROUP , aid ));
392
+ Artifact graalPyArtifact = projectArtifacts .stream ().
393
+ filter (a -> isPythonArtifact (a ))
394
+ .findFirst ()
395
+ .orElse (null );
396
+ return Optional .ofNullable (graalPyArtifact ).orElseThrow (() -> new MojoExecutionException ("Missing GraalPy dependency. Please add to your pom either %s:%s or %s:%s" .formatted (POLYGLOT_GROUP_ID , PYTHON_COMMUNITY_ARTIFACT_ID , POLYGLOT_GROUP_ID , PYTHON_ARTIFACT_ID )));
397
+ }
398
+
399
+ private static boolean isPythonArtifact (Artifact a ) {
400
+ return POLYGLOT_GROUP_ID .equals (a .getGroupId ()) &&
401
+ (PYTHON_COMMUNITY_ARTIFACT_ID .equals (a .getArtifactId ()) || PYTHON_ARTIFACT_ID .equals (a .getArtifactId ()));
381
402
}
382
403
383
404
private static Collection <Artifact > resolveProjectDependencies (MavenProject project ) {
@@ -387,11 +408,62 @@ private static Collection<Artifact> resolveProjectDependencies(MavenProject proj
387
408
.collect (Collectors .toList ());
388
409
}
389
410
390
- private static HashSet <String > calculateClasspath (MavenProject project ) throws MojoExecutionException {
391
- var classpath = new HashSet <String >();
392
- for (var r : resolveProjectDependencies (project )) {
393
- classpath .add (r .getFile ().getAbsolutePath ());
411
+ private Set <String > calculateLauncherClasspath (MavenProject project ) throws MojoExecutionException {
412
+ if (launcherClassPath == null ) {
413
+ String version = getGraalPyVersion (project );
414
+ launcherClassPath = new HashSet <String >();
415
+
416
+ // 1.) python-launcher and transitive dependencies
417
+ // get the artifact from its direct dependency in graalpy-maven-plugin
418
+ DefaultArtifact mvnPlugin = new DefaultArtifact (GRAALPY_GROUP_ID , GRAALPY_MAVEN_PLUGIN_ARTIFACT_ID , version , "compile" , "jar" , null , new DefaultArtifactHandler ("pom" ));
419
+ ProjectBuildingResult result = buildProjectFromArtifact (mvnPlugin );
420
+ Artifact graalPyLauncherArtifact = result .getProject ().getArtifacts ().stream ().filter (a ->GRAALPY_GROUP_ID .equals (a .getGroupId ()) && PYTHON_LAUNCHER_ARTIFACT_ID .equals (a .getArtifactId ()) && version .equals (a .getVersion ()))
421
+ .findFirst ()
422
+ .orElse (null );
423
+ // python-launcher artifact
424
+ launcherClassPath .add (graalPyLauncherArtifact .getFile ().getAbsolutePath ());
425
+ // and transitively all its dependencies
426
+ launcherClassPath .addAll (resolveDependencies (graalPyLauncherArtifact ));
427
+
428
+ // 2.) graalpy dependencies
429
+ Artifact graalPyArtifact = getGraalPyArtifact (project );
430
+ assert graalPyArtifact != null ;
431
+ launcherClassPath .addAll (resolveDependencies (graalPyArtifact ));
432
+ }
433
+ return launcherClassPath ;
434
+ }
435
+
436
+ private Set <String > resolveDependencies (Artifact artifact ) throws MojoExecutionException {
437
+ Set <String > dependencies = new HashSet <>();
438
+ ProjectBuildingResult result = buildProjectFromArtifact (artifact );
439
+ for (Dependency d : result .getDependencyResolutionResult ().getResolvedDependencies ()) {
440
+ addDependency (d , dependencies );
441
+ }
442
+ return dependencies ;
443
+ }
444
+
445
+ private ProjectBuildingResult buildProjectFromArtifact (Artifact artifact ) throws MojoExecutionException {
446
+ try {
447
+ ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest (session .getProjectBuildingRequest ());
448
+ buildingRequest .setProject (null );
449
+ buildingRequest .setResolveDependencies (true );
450
+ buildingRequest .setPluginArtifactRepositories (project .getPluginArtifactRepositories ());
451
+ buildingRequest .setRemoteRepositories (project .getRemoteArtifactRepositories ());
452
+
453
+ return projectBuilder .build (artifact , buildingRequest );
454
+ } catch (ProjectBuildingException e ) {
455
+ throw new MojoExecutionException ("Error while building project" , e );
456
+ }
457
+ }
458
+
459
+ private void addDependency (Dependency d , Set <String > dependencies ) {
460
+ File f = d .getArtifact ().getFile ();
461
+ if (f != null ) {
462
+ dependencies .add (f .getAbsolutePath ());
463
+ } else {
464
+ getLog ().warn ("could not retrieve local file for artifact " + d .getArtifact ());
394
465
}
395
- return classpath ;
396
466
}
397
467
}
468
+
469
+
0 commit comments