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