@@ -69,21 +69,29 @@ String constructJarUrl(String version) {
69
69
}
70
70
71
71
/// 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 {
73
79
outputPath = resolvePath (outputPath);
74
80
final file = File (outputPath);
81
+ client ?? =
82
+ http.Client (); // Use the injected client or default to a new client
83
+
75
84
if (! await file.exists ()) {
76
- _logOutput ('Downloading $url ...' );
85
+ log ('Downloading $url ...' );
77
86
78
87
final request = http.Request ('GET' , Uri .parse (url));
79
- final response = await request .send ();
88
+ final response = await client .send (request );
80
89
81
90
if (response.statusCode == 200 ) {
82
91
final contentLength = response.contentLength ?? 0 ;
83
92
final output = file.openWrite ();
84
93
var downloadedBytes = 0 ;
85
94
86
- // Listen to the stream and write to the file in smaller chunks
87
95
await response.stream.listen (
88
96
(chunk) {
89
97
downloadedBytes += chunk.length;
@@ -92,15 +100,15 @@ Future<void> downloadJar(String url, String outputPath) async {
92
100
// Display progress if content length is known
93
101
if (contentLength != 0 ) {
94
102
final progress = (downloadedBytes / contentLength) * 100 ;
95
- stdout. write ('\r Progress: ${progress .toStringAsFixed (2 )}%' );
103
+ log ('\r Progress: ${progress .toStringAsFixed (2 )}%' );
96
104
}
97
105
},
98
106
onDone: () async {
99
107
await output.close ();
100
- print ('\n Downloaded to $outputPath \n ' );
108
+ log ('\n Downloaded to $outputPath \n ' );
101
109
},
102
110
onError: (e) {
103
- print ('\n Download failed: $e \n ' );
111
+ log ('\n Download failed: $e \n ' );
104
112
},
105
113
cancelOnError: true ,
106
114
).asFuture ();
@@ -109,13 +117,13 @@ Future<void> downloadJar(String url, String outputPath) async {
109
117
'Failed to download $url . Status code: ${response .statusCode }' );
110
118
}
111
119
} else {
112
- print ('[info] $outputPath found. No need to download' );
120
+ log ('[info] $outputPath found. No need to download' );
113
121
}
114
122
}
115
123
116
124
/// 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 {
119
127
final javaOpts = Platform .environment['JAVA_OPTS' ] ?? '' ;
120
128
final classpath = jarPaths.join (Platform .isWindows ? ';' : ':' );
121
129
final commands = [
@@ -129,14 +137,31 @@ Future<void> executeWithClasspath(
129
137
commands.insert (0 , javaOpts);
130
138
}
131
139
132
- final result = await Process .run ('java' , commands);
140
+ final result =
141
+ await process.run ('java' , commands, runInShell: Platform .isWindows);
133
142
print (result.stdout);
134
143
print (result.stderr);
135
144
}
136
145
137
- /// Main function handling config loading, JAR downloading, and command execution
138
146
Future <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 ;
140
165
141
166
// Determine config path from arguments or default to 'openapi_generator_config.json'
142
167
final configArgIndex = arguments.indexOf ('--config' );
@@ -145,22 +170,21 @@ Future<void> main(List<String> arguments) async {
145
170
? arguments[configArgIndex + 1 ]
146
171
: 'openapi_generator_config.json' ;
147
172
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 ' );
158
174
159
- final customGeneratorUrls = List <String >.from (
160
- config[ConfigKeys .customGeneratorUrls] ??
161
- ConfigDefaults .customGeneratorUrls);
162
175
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);
164
188
165
189
// Ensure the cache directory exists
166
190
await Directory (cachePath).create (recursive: true );
@@ -173,15 +197,14 @@ Future<void> main(List<String> arguments) async {
173
197
await downloadJar (overrideUrl ?? constructJarUrl (version), openapiJarPath);
174
198
175
199
// 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) {
178
201
final originalFileName = customJarUrl.split ('/' ).last;
179
202
final customJarPath = '$cachePath /custom-$originalFileName ' ;
180
203
await downloadJar (customJarUrl, customJarPath);
181
204
customJarPaths.add (customJarPath);
182
205
}
183
206
184
- // Combine all JAR paths (OpenAPI Generator + custom generators) for the classpath
207
+ // Combine all JAR paths for the classpath
185
208
final jarPaths = [openapiJarPath, ...customJarPaths];
186
209
187
210
// Prepare additional arguments, excluding the --config flag and its value
@@ -190,19 +213,30 @@ Future<void> main(List<String> arguments) async {
190
213
...arguments.where ((arg) => arg != '--config' && arg != configFilePath),
191
214
];
192
215
193
- // Execute using all JARs in the classpath
216
+ // Execute with classpath
194
217
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
+ );
204
224
} catch (e) {
205
- _logOutput ('Error: $e ' );
225
+ log ('Error: $e ' );
206
226
exitCode = 1 ;
207
227
}
208
228
}
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