34
34
import io .airlift .airline .Arguments ;
35
35
import io .airlift .airline .Command ;
36
36
import io .airlift .airline .Option ;
37
+ import org .apache .commons .io .FileUtils ;
37
38
import org .apache .commons .lang3 .StringUtils ;
38
39
import org .openapitools .codegen .ClientOptInput ;
39
40
import org .openapitools .codegen .CodegenConfig ;
46
47
47
48
import java .io .File ;
48
49
import java .io .IOException ;
50
+ import java .nio .charset .StandardCharsets ;
49
51
import java .nio .file .Files ;
50
52
import java .nio .file .Path ;
51
53
import java .nio .file .Paths ;
@@ -77,6 +79,9 @@ public class GenerateBatch extends OpenApiGeneratorCommand {
77
79
@ Option (name = {"--fail-fast" }, description = "fail fast on any errors" )
78
80
private Boolean failFast ;
79
81
82
+ @ Option (name = {"--clean" }, description = "clean output of previously written files before generation" )
83
+ private Boolean clean ;
84
+
80
85
@ Option (name = {"--timeout" }, description = "execution timeout (minutes)" )
81
86
private Integer timeout ;
82
87
@@ -149,7 +154,10 @@ public void execute() {
149
154
ExecutorService executor = Executors .newFixedThreadPool (numThreads );
150
155
151
156
// Execute each configurator on a separate pooled thread.
152
- configurators .forEach (configurator -> executor .execute (new GenerationRunner (configurator , rootDir , Boolean .TRUE .equals (failFast ))));
157
+ configurators .forEach (configurator -> {
158
+ GenerationRunner runner = new GenerationRunner (configurator , rootDir , Boolean .TRUE .equals (failFast ), Boolean .TRUE .equals (clean ));
159
+ executor .execute (runner );
160
+ });
153
161
154
162
executor .shutdown ();
155
163
@@ -178,11 +186,13 @@ private static class GenerationRunner implements Runnable {
178
186
private final CodegenConfigurator configurator ;
179
187
private final Path rootDir ;
180
188
private final boolean exitOnError ;
189
+ private final boolean clean ;
181
190
182
- private GenerationRunner (CodegenConfigurator configurator , Path rootDir , boolean failFast ) {
191
+ private GenerationRunner (CodegenConfigurator configurator , Path rootDir , boolean failFast , boolean clean ) {
183
192
this .configurator = configurator ;
184
193
this .rootDir = rootDir ;
185
194
this .exitOnError = failFast ;
195
+ this .clean = clean ;
186
196
}
187
197
188
198
/**
@@ -198,7 +208,7 @@ private GenerationRunner(CodegenConfigurator configurator, Path rootDir, boolean
198
208
*/
199
209
@ Override
200
210
public void run () {
201
- String name = "" ;
211
+ String name = null ;
202
212
try {
203
213
GlobalSettings .reset ();
204
214
@@ -210,6 +220,10 @@ public void run() {
210
220
Path updated = rootDir .resolve (target );
211
221
config .setOutputDir (updated .toString ());
212
222
223
+ if (this .clean ) {
224
+ cleanPreviousFiles (name , updated );
225
+ }
226
+
213
227
System .out .printf (Locale .ROOT , "[%s] Generating %s (outputs to %s)…%n" , Thread .currentThread ().getName (), name , updated .toString ());
214
228
215
229
DefaultGenerator defaultGenerator = new DefaultGenerator ();
@@ -234,6 +248,28 @@ public void run() {
234
248
GlobalSettings .reset ();
235
249
}
236
250
}
251
+
252
+ private void cleanPreviousFiles (final String name , Path outDir ) throws IOException {
253
+ System .out .printf (Locale .ROOT , "[%s] Cleaning previous contents for %s in %s…%n" , Thread .currentThread ().getName (), name , outDir .toString ());
254
+ Path filesMeta = Paths .get (outDir .toAbsolutePath ().toString (), ".openapi-generator" , "FILES" );
255
+ if (filesMeta .toFile ().exists ()) {
256
+ FileUtils .readLines (filesMeta .toFile (), StandardCharsets .UTF_8 ).forEach (relativePath -> {
257
+ if (!StringUtils .startsWith (relativePath , "." )) {
258
+ Path file = outDir .resolve (relativePath ).toAbsolutePath ();
259
+ // hack: disallow directory traversal outside of output directory. we don't want to delete wrong files.
260
+ if (file .toString ().startsWith (outDir .toAbsolutePath ().toString ())) {
261
+ try {
262
+ Files .delete (file );
263
+ } catch (Throwable e ) {
264
+ System .out .printf (Locale .ROOT , "[%s] Generator %s failed to clean file %s…%n" , Thread .currentThread ().getName (), name , file );
265
+ }
266
+ }
267
+ } else {
268
+ System .out .printf (Locale .ROOT , "[%s] Generator %s skip cleaning special filename %s…%n" , Thread .currentThread ().getName (), name , relativePath );
269
+ }
270
+ });
271
+ }
272
+ }
237
273
}
238
274
239
275
static SimpleModule getCustomDeserializationModel (final File includesDir ) {
0 commit comments