@@ -69,21 +69,29 @@ String constructJarUrl(String version) {
6969}
7070
7171/// Downloads a JAR file to the specified output path if it doesn't already exist
72- Future <void > downloadJar (String url, String outputPath) async {
72+ Future <void > downloadJar (
73+ String url,
74+ String outputPath, {
75+ http.Client ? client, // Injected HTTP client for testing
76+ void Function (String message) log =
77+ _logOutput, // Optional log function for testing
78+ }) async {
7379 outputPath = resolvePath (outputPath);
7480 final file = File (outputPath);
81+ client ?? =
82+ http.Client (); // Use the injected client or default to a new client
83+
7584 if (! await file.exists ()) {
76- _logOutput ('Downloading $url ...' );
85+ log ('Downloading $url ...' );
7786
7887 final request = http.Request ('GET' , Uri .parse (url));
79- final response = await request .send ();
88+ final response = await client .send (request );
8089
8190 if (response.statusCode == 200 ) {
8291 final contentLength = response.contentLength ?? 0 ;
8392 final output = file.openWrite ();
8493 var downloadedBytes = 0 ;
8594
86- // Listen to the stream and write to the file in smaller chunks
8795 await response.stream.listen (
8896 (chunk) {
8997 downloadedBytes += chunk.length;
@@ -92,15 +100,15 @@ Future<void> downloadJar(String url, String outputPath) async {
92100 // Display progress if content length is known
93101 if (contentLength != 0 ) {
94102 final progress = (downloadedBytes / contentLength) * 100 ;
95- stdout. write ('\r Progress: ${progress .toStringAsFixed (2 )}%' );
103+ log ('\r Progress: ${progress .toStringAsFixed (2 )}%' );
96104 }
97105 },
98106 onDone: () async {
99107 await output.close ();
100- print ('\n Downloaded to $outputPath \n ' );
108+ log ('\n Downloaded to $outputPath \n ' );
101109 },
102110 onError: (e) {
103- print ('\n Download failed: $e \n ' );
111+ log ('\n Download failed: $e \n ' );
104112 },
105113 cancelOnError: true ,
106114 ).asFuture ();
@@ -109,13 +117,13 @@ Future<void> downloadJar(String url, String outputPath) async {
109117 'Failed to download $url . Status code: ${response .statusCode }' );
110118 }
111119 } else {
112- print ('[info] $outputPath found. No need to download' );
120+ log ('[info] $outputPath found. No need to download' );
113121 }
114122}
115123
116124/// Executes the OpenAPI Generator using all JARs in the classpath
117- Future <void > executeWithClasspath (
118- List < String > jarPaths, List < String > arguments ) async {
125+ Future <void > executeWithClasspath (List < String > jarPaths, List < String > arguments,
126+ [ ProcessRunner process = const ProcessRunner ()] ) async {
119127 final javaOpts = Platform .environment['JAVA_OPTS' ] ?? '' ;
120128 final classpath = jarPaths.join (Platform .isWindows ? ';' : ':' );
121129 final commands = [
@@ -129,14 +137,31 @@ Future<void> executeWithClasspath(
129137 commands.insert (0 , javaOpts);
130138 }
131139
132- final result = await Process .run ('java' , commands);
140+ final result =
141+ await process.run ('java' , commands, runInShell: Platform .isWindows);
133142 print (result.stdout);
134143 print (result.stderr);
135144}
136145
137- /// Main function handling config loading, JAR downloading, and command execution
138146Future <void > main (List <String > arguments) async {
139- exitCode = 0 ; // presume success
147+ await runMain (
148+ arguments: arguments,
149+ loadConfig: loadOrCreateConfig,
150+ downloadJar: downloadJar,
151+ executeWithClasspath: executeWithClasspath,
152+ log: _logOutput,
153+ );
154+ }
155+
156+ Future <void > runMain ({
157+ required List <String > arguments,
158+ required Future <Map <String , dynamic >> Function (String ) loadConfig,
159+ required Future <void > Function (String , String ) downloadJar,
160+ required Future <void > Function (List <String >, List <String >)
161+ executeWithClasspath,
162+ required void Function (String ) log,
163+ }) async {
164+ exitCode = 0 ;
140165
141166 // Determine config path from arguments or default to 'openapi_generator_config.json'
142167 final configArgIndex = arguments.indexOf ('--config' );
@@ -145,22 +170,21 @@ Future<void> main(List<String> arguments) async {
145170 ? arguments[configArgIndex + 1 ]
146171 : 'openapi_generator_config.json' ;
147172
148- print ('Using config file: $configFilePath ' );
149-
150- final config = await loadOrCreateConfig (configFilePath);
151- final String version = (config[ConfigKeys .openapiGeneratorVersion] ??
152- ConfigDefaults .openapiGeneratorVersion);
153- final String additionalCommands = config[ConfigKeys .additionalCommands] ??
154- ConfigDefaults .additionalCommands;
155- final String ? overrideUrl = config[ConfigKeys .downloadUrlOverride];
156- final cachePath = resolvePath (
157- config[ConfigKeys .jarCachePath] ?? ConfigDefaults .jarCacheDir);
173+ log ('Using config file: $configFilePath ' );
158174
159- final customGeneratorUrls = List <String >.from (
160- config[ConfigKeys .customGeneratorUrls] ??
161- ConfigDefaults .customGeneratorUrls);
162175 try {
163- // Load or create configuration
176+ final config = await loadConfig (configFilePath);
177+ final version = config[ConfigKeys .openapiGeneratorVersion] ??
178+ ConfigDefaults .openapiGeneratorVersion;
179+ final additionalCommands = config[ConfigKeys .additionalCommands] ??
180+ ConfigDefaults .additionalCommands;
181+ final overrideUrl = config[ConfigKeys .downloadUrlOverride];
182+ final cachePath = resolvePath (
183+ config[ConfigKeys .jarCachePath] ?? ConfigDefaults .jarCacheDir);
184+
185+ final customGeneratorUrls = List <String >.from (
186+ config[ConfigKeys .customGeneratorUrls] ??
187+ ConfigDefaults .customGeneratorUrls);
164188
165189 // Ensure the cache directory exists
166190 await Directory (cachePath).create (recursive: true );
@@ -173,15 +197,14 @@ Future<void> main(List<String> arguments) async {
173197 await downloadJar (overrideUrl ?? constructJarUrl (version), openapiJarPath);
174198
175199 // Download each custom generator JAR if it doesn't exist and store in `customJarPaths`
176- for (var i = 0 ; i < customGeneratorUrls.length; i++ ) {
177- final customJarUrl = customGeneratorUrls[i];
200+ for (var customJarUrl in customGeneratorUrls) {
178201 final originalFileName = customJarUrl.split ('/' ).last;
179202 final customJarPath = '$cachePath /custom-$originalFileName ' ;
180203 await downloadJar (customJarUrl, customJarPath);
181204 customJarPaths.add (customJarPath);
182205 }
183206
184- // Combine all JAR paths (OpenAPI Generator + custom generators) for the classpath
207+ // Combine all JAR paths for the classpath
185208 final jarPaths = [openapiJarPath, ...customJarPaths];
186209
187210 // Prepare additional arguments, excluding the --config flag and its value
@@ -190,19 +213,30 @@ Future<void> main(List<String> arguments) async {
190213 ...arguments.where ((arg) => arg != '--config' && arg != configFilePath),
191214 ];
192215
193- // Execute using all JARs in the classpath
216+ // Execute with classpath
194217 await executeWithClasspath (
195- jarPaths,
196- filteredArguments
197- .map (
198- (e) => e.trim (),
199- )
200- .where (
201- (element) => element.isNotEmpty,
202- )
203- .toList ());
218+ jarPaths,
219+ filteredArguments
220+ .map ((e) => e.trim ())
221+ .where ((e) => e.isNotEmpty)
222+ .toList (),
223+ );
204224 } catch (e) {
205- _logOutput ('Error: $e ' );
225+ log ('Error: $e ' );
206226 exitCode = 1 ;
207227 }
208228}
229+
230+ class ProcessRunner {
231+ const ProcessRunner ();
232+
233+ Future <ProcessResult > run (String executable, List <String > arguments,
234+ {Map <String , String >? environment,
235+ String ? workingDirectory,
236+ bool runInShell = false }) {
237+ return Process .run (executable, arguments,
238+ environment: environment,
239+ workingDirectory: workingDirectory,
240+ runInShell: runInShell);
241+ }
242+ }
0 commit comments