44 */
55package net .minecraftforge .gradleutils .shared ;
66
7+ import org .codehaus .groovy .runtime .DefaultGroovyMethods ;
8+ import org .gradle .api .DefaultTask ;
79import org .gradle .api .Transformer ;
10+ import org .gradle .api .file .ConfigurableFileCollection ;
811import org .gradle .api .file .DirectoryProperty ;
912import org .gradle .api .file .FileSystemLocation ;
1013import org .gradle .api .file .FileSystemLocationProperty ;
1114import org .gradle .api .logging .LogLevel ;
15+ import org .gradle .api .logging .LoggingManager ;
16+ import org .gradle .api .model .ObjectFactory ;
1217import org .gradle .api .provider .ListProperty ;
18+ import org .gradle .api .provider .MapProperty ;
19+ import org .gradle .api .provider .Property ;
1320import org .gradle .api .provider .Provider ;
21+ import org .gradle .api .provider .ProviderFactory ;
22+ import org .gradle .api .tasks .Classpath ;
23+ import org .gradle .api .tasks .Console ;
1424import org .gradle .api .tasks .Input ;
25+ import org .gradle .api .tasks .InputFiles ;
1526import org .gradle .api .tasks .Internal ;
1627import org .gradle .api .tasks .JavaExec ;
28+ import org .gradle .api .tasks .Nested ;
1729import org .gradle .api .tasks .Optional ;
30+ import org .gradle .api .tasks .TaskAction ;
31+ import org .gradle .jvm .toolchain .JavaLauncher ;
32+ import org .gradle .process .ExecOperations ;
33+ import org .gradle .process .ExecResult ;
1834import org .jetbrains .annotations .MustBeInvokedByOverriders ;
35+ import org .jetbrains .annotations .Nullable ;
1936import org .jetbrains .annotations .UnknownNullability ;
2037
2138import javax .inject .Inject ;
2239import java .io .File ;
40+ import java .util .ArrayList ;
41+ import java .util .HashMap ;
42+ import java .util .List ;
2343import java .util .Locale ;
2444import java .util .Map ;
45+ import java .util .Objects ;
2546import java .util .concurrent .Callable ;
2647
2748/// This tool execution task is a template on top of [JavaExec] to make executing [tools][Tool] much easier and more
3253/// should extend from.
3354/// @see JavaExec
3455/// @see Tool
35- public abstract class ToolExecBase <P extends EnhancedProblems > extends JavaExec implements EnhancedTask <P > {
36- private final P problems ;
56+ public abstract class ToolExecBase <P extends EnhancedProblems > extends DefaultTask implements EnhancedTask <P > {
57+ private final P problems = this . getObjects (). newInstance ( this . problemsType ()) ;
3758
3859 /// The default tool directory (usage is not required).
39- protected final DirectoryProperty defaultToolDir = this .getObjectFactory ().directoryProperty ();
40- private final ListProperty <String > additionalArgs = this .getObjectFactory ().listProperty (String .class );
60+ protected final DirectoryProperty defaultToolDir = this .getObjects ().directoryProperty ();
61+ private final ListProperty <String > additionalArgs = this .getObjects ().listProperty (String .class );
4162
4263 /// Additional arguments to use when invoking the tool. Use in configuration instead of [#args].
4364 ///
@@ -46,6 +67,31 @@ public abstract class ToolExecBase<P extends EnhancedProblems> extends JavaExec
4667 return this .additionalArgs ;
4768 }
4869
70+ //region JavaExec
71+ protected abstract @ InputFiles @ Classpath ConfigurableFileCollection getClasspath ();
72+
73+ protected abstract @ Input @ Optional Property <String > getMainClass ();
74+
75+ protected abstract @ Nested Property <JavaLauncher > getJavaLauncher ();
76+ //endregion
77+
78+ //region Logging
79+ @ Deprecated
80+ @ Override public LoggingManager getLogging () {
81+ return super .getLogging ();
82+ }
83+
84+ protected abstract @ Console Property <LogLevel > getStandardOutputLogLevel ();
85+
86+ protected abstract @ Console Property <LogLevel > getStandardErrorLogLevel ();
87+ //endregion
88+
89+ protected abstract @ Inject ObjectFactory getObjects ();
90+
91+ protected abstract @ Inject ProviderFactory getProviders ();
92+
93+ protected abstract @ Inject ExecOperations getExecOperations ();
94+
4995 /// Creates a new task instance using the given types and tool information.
5096 ///
5197 /// @param tool The tool to use for this task
@@ -55,22 +101,19 @@ public abstract class ToolExecBase<P extends EnhancedProblems> extends JavaExec
55101 /// best practice is to make a single `ToolExec` class for the implementing plugin to use, which other tasks can
56102 /// extend off of.
57103 protected ToolExecBase (Tool tool ) {
58- this .problems = this .getObjectFactory ().newInstance (this .problemsType ());
59-
60104 var resolved = this .getTool (tool );
61- this .defaultToolDir .value (
105+ SharedUtil . finalizeProperty ( this .defaultToolDir .value (
62106 this .globalCaches ().dir (tool .getName ().toLowerCase (Locale .ENGLISH )).map (this .ensureFileLocationInternal ())
63- );
64-
65- this .setClasspath (resolved .getClasspath ());
107+ ));
66108
67- SharedUtil . finalizeProperty ( this . defaultToolDir );
109+ this . getClasspath (). setFrom ( resolved . getClasspath () );
68110
69111 if (resolved .hasMainClass ())
70112 this .getMainClass ().set (resolved .getMainClass ());
71113 this .getJavaLauncher ().set (resolved .getJavaLauncher ());
72114
73- this .getLogging ().captureStandardOutput (LogLevel .LIFECYCLE ).captureStandardError (LogLevel .ERROR );
115+ this .getStandardOutputLogLevel ().convention (LogLevel .LIFECYCLE );
116+ this .getStandardErrorLogLevel ().convention (LogLevel .ERROR );
74117 }
75118
76119 /// The enhanced problems instance to use for this task.
@@ -87,22 +130,65 @@ private <T extends FileSystemLocation> Transformer<T, T> ensureFileLocationInter
87130 /// This method should be overridden by subclasses to add arguments to this task via [JavaExec#args]. To preserve
88131 /// arguments added by superclasses, this method [must be invoked by overriders][MustBeInvokedByOverriders].
89132 @ MustBeInvokedByOverriders
90- protected void addArguments () {
91- this .args (this .getAdditionalArgs ().get ());
92- }
133+ protected void addArguments () { }
134+
135+ private transient boolean executing = false ;
136+ private transient @ Nullable List <Provider <String >> args ;
137+ private transient @ Nullable List <Provider <String >> jvmArgs ;
138+ private transient @ Nullable Map <String , String > environment ;
139+ private transient @ Nullable Map <String , String > systemProperties ;
93140
94141 /// @implNote Not invoking this method from an overriding method *will* result in the tool never being executed and
95142 /// [#addArguments()] never being run.
96- @ Override
97- public void exec () {
98- if (!this .getArgs ().isEmpty ())
99- this .getProblems ().reportToolExecEagerArgs (this );
143+ @ TaskAction
144+ protected ExecResult exec () {
145+ this .executing = true ;
146+ this .args = new ArrayList <>();
147+ this .jvmArgs = new ArrayList <>();
148+ this .environment = new HashMap <>();
149+ this .systemProperties = new HashMap <>();
100150
101151 this .addArguments ();
152+ this .args (this .getAdditionalArgs ().get ());
102153
103- this .getLogger ().info ("{} {}" , this .getClasspath ().getAsPath (), String .join (" " , this .getArgs ()));
154+ var args = DefaultGroovyMethods .collect (this .args , Closures .<Provider <String >, String >function (Provider ::get ));
155+ var jvmArgs = DefaultGroovyMethods .collect (this .jvmArgs , Closures .<Provider <String >, String >function (Provider ::get ));
156+ this .getLogger ().info ("{} {}" , this .getClasspath ().getAsPath (), String .join (" " , args ));
104157
105- super .exec ();
158+ var stdOutLevel = this .getStandardOutputLogLevel ().get ();
159+ var stdErrLevel = this .getStandardErrorLogLevel ().get ();
160+ return this .getExecOperations ().javaexec (spec -> {
161+ spec .setClasspath (this .getClasspath ());
162+ spec .getMainClass ().set (this .getMainClass ());
163+ spec .setExecutable (this .getJavaLauncher ().get ().getExecutablePath ().getAsFile ().getAbsolutePath ());
164+ spec .setArgs (args );
165+ spec .setJvmArgs (jvmArgs );
166+ spec .setEnvironment (this .environment );
167+ spec .setSystemProperties (this .systemProperties );
168+
169+ spec .setStandardOutput (SharedUtil .toLog (this .getLogger (), stdOutLevel ));
170+ spec .setErrorOutput (SharedUtil .toLog (this .getLogger (), stdErrLevel ));
171+ });
172+ }
173+
174+ protected final void args (Object ... args ) {
175+ try {
176+ for (var arg : args ) {
177+ Objects .requireNonNull (this .args ).add (this .getProviders ().provider (arg ::toString ));
178+ }
179+ } catch (NullPointerException e ) {
180+ throw new IllegalStateException ("ToolExecBase#jvmArgs can only be called inside of #addArguments()" , e );
181+ }
182+ }
183+
184+ protected final void args (Iterable <?> args ) {
185+ try {
186+ for (var arg : args ) {
187+ Objects .requireNonNull (this .args ).add (this .getProviders ().provider (arg ::toString ));
188+ }
189+ } catch (NullPointerException e ) {
190+ throw new IllegalStateException ("ToolExecBase#jvmArgs can only be called inside of #addArguments()" , e );
191+ }
106192 }
107193
108194 /// Adds each file to the arguments preceded by the given argument. Designed to work well with
@@ -152,9 +238,45 @@ protected final void args(Map<?, ?> args) {
152238 var key = entry .getKey ();
153239 var value = entry .getValue ();
154240 this .args (
155- key instanceof Provider <?> provider ? provider .map (Object ::toString ).get () : this .getProviderFactory ().provider (key ::toString ).get (),
156- value instanceof Provider <?> provider ? (provider instanceof FileSystemLocationProperty <?> file ? file .getLocationOnly () : provider ) : this .getProviderFactory ().provider (() -> value )
241+ key instanceof Provider <?> provider ? provider .map (Object ::toString ).get () : this .getProviders ().provider (key ::toString ).get (),
242+ value instanceof Provider <?> provider ? (provider instanceof FileSystemLocationProperty <?> file ? file .getLocationOnly () : provider ) : this .getProviders ().provider (() -> value )
157243 );
158244 }
159245 }
246+
247+ protected final void jvmArgs (Object ... args ) {
248+ try {
249+ for (var arg : args ) {
250+ Objects .requireNonNull (this .jvmArgs ).add (this .getProviders ().provider (arg ::toString ));
251+ }
252+ } catch (NullPointerException e ) {
253+ throw new IllegalStateException ("ToolExecBase#jvmArgs can only be called inside of #addArguments()" , e );
254+ }
255+ }
256+
257+ protected final void jvmArgs (Iterable <?> args ) {
258+ try {
259+ for (var arg : args ) {
260+ Objects .requireNonNull (this .jvmArgs ).add (this .getProviders ().provider (arg ::toString ));
261+ }
262+ } catch (NullPointerException e ) {
263+ throw new IllegalStateException ("ToolExecBase#jvmArgs can only be called inside of #addArguments()" , e );
264+ }
265+ }
266+
267+ protected final void environment (String key , String value ) {
268+ try {
269+ Objects .requireNonNull (this .environment ).put (key , value );
270+ } catch (NullPointerException e ) {
271+ throw new IllegalStateException ("ToolExecBase#environment can only be called inside of #addArguments()" , e );
272+ }
273+ }
274+
275+ protected final void systemProperty (String key , String value ) {
276+ try {
277+ Objects .requireNonNull (this .systemProperties ).put (key , value );
278+ } catch (NullPointerException e ) {
279+ throw new IllegalStateException ("ToolExecBase#systemProperty can only be called inside of #addArguments()" , e );
280+ }
281+ }
160282}
0 commit comments