45
45
46
46
import cpw .mods .fml .relauncher .FMLLaunchHandler ;
47
47
48
+ import java .io .BufferedInputStream ;
48
49
import java .io .BufferedOutputStream ;
49
50
import java .io .File ;
50
51
import java .io .IOException ;
59
60
import java .util .ArrayList ;
60
61
import java .util .Arrays ;
61
62
import java .util .HashMap ;
63
+ import java .util .HashSet ;
64
+ import java .util .List ;
62
65
import java .util .Map ;
63
66
import java .util .Objects ;
64
67
import java .util .Set ;
@@ -93,6 +96,52 @@ public class DependencyLoaderImpl {
93
96
thread .setName ("Dependency Download Thread " + counter .incrementAndGet ());
94
97
return thread ;
95
98
});
99
+ private static final File libDir ;
100
+
101
+ static {
102
+
103
+ var homeDir = System .getProperty ("minecraft.sharedDataDir" );
104
+ if (homeDir == null ) {
105
+ homeDir = System .getenv ("MINECRAFT_SHARED_DATA_DIR" );
106
+ if (homeDir == null ) {
107
+ homeDir = FileUtil .getMinecraftHome ().getAbsolutePath ();
108
+ }
109
+ }
110
+ val modsDir = Paths .get (homeDir , "mods" ).toFile ();
111
+ val oldLibDir = new File (modsDir , "falsepattern" );
112
+ libDir = new File (homeDir , "falsepattern" );
113
+ if (!libDir .exists ()) {
114
+ if (!libDir .mkdirs ()) {
115
+ LOG .fatal ("Failed to create directory {}" , libDir );
116
+ throw new RuntimeException ("Failed to create directory " + libDir );
117
+ }
118
+ }
119
+ if (oldLibDir .exists ()) {
120
+ LOG .info ("Migrating old library folder. From: " + oldLibDir .getAbsolutePath () + ", To: " + libDir .getAbsolutePath ());
121
+ val oldFiles = oldLibDir .listFiles ();
122
+ if (oldFiles != null ) {
123
+ for (val file : oldFiles ) {
124
+ try {
125
+ Files .move (file .toPath (), libDir .toPath ().resolve (oldLibDir .toPath ().relativize (file .toPath ())), StandardCopyOption .REPLACE_EXISTING );
126
+ } catch (IOException e ) {
127
+ LOG .warn ("Failed to move file " + file .getName () + " to new dir! Deleting instead." );
128
+ try {
129
+ Files .deleteIfExists (file .toPath ());
130
+ } catch (IOException ex ) {
131
+ LOG .warn ("Failed to delete file " + file .getPath () + "!" );
132
+ file .deleteOnExit ();
133
+ }
134
+ }
135
+ }
136
+ }
137
+ try {
138
+ Files .deleteIfExists (oldLibDir .toPath ());
139
+ } catch (IOException e ) {
140
+ LOG .warn ("Failed to delete old library directory!" );
141
+ oldLibDir .deleteOnExit ();
142
+ }
143
+ }
144
+ }
96
145
97
146
public static void addMavenRepo (String url ) {
98
147
mavenRepositories .add (url );
@@ -185,24 +234,25 @@ public static CompletableFuture<Void> loadLibrariesAsync(Library... libraries) {
185
234
return CompletableFuture .allOf (futures .toArray (new CompletableFuture [0 ]));
186
235
}
187
236
188
- private static Stream < URL > scanSourceMetaInf (URL source ) {
237
+ private static boolean scanForDepSpecs (URL source , List < URL > output ) {
189
238
if (!source .getProtocol ().equals ("file" )) {
190
239
LOG .warn ("Skipping non-file source: {}" , source );
191
- return Stream . empty () ;
240
+ return false ;
192
241
}
193
242
LOG .debug ("Scanning {} for dependencies" , source );
194
243
val fileName = source .getFile ();
195
- val output = new ArrayList < URL >() ;
244
+ boolean found = false ;
196
245
if (fileName .endsWith (".jar" )) {
197
246
//Scan jar file for json in META-INF, add them to the list
198
- try (val inputStream = source .openStream (); val jarFile = new JarInputStream (inputStream )) {
247
+ try (val inputStream = new BufferedInputStream ( source .openStream (), 65536 ); val jarFile = new JarInputStream (inputStream )) {
199
248
ZipEntry entry ;
200
249
while ((entry = jarFile .getNextEntry ()) != null ) {
201
250
if (!entry .getName ().startsWith ("META-INF" ) || !entry .getName ().endsWith (".json" )) {
202
251
continue ;
203
252
}
204
253
try {
205
254
output .add (new URL ("jar:" + source + "!/" + entry .getName ()));
255
+ found = true ;
206
256
} catch (MalformedURLException e ) {
207
257
LOG .error ("Failed to add json source {} to dependency source list: {}" , entry .getName (), e );
208
258
}
@@ -214,29 +264,30 @@ private static Stream<URL> scanSourceMetaInf(URL source) {
214
264
val dir = new File (fileName );
215
265
if (!dir .exists () || !dir .isDirectory ()) {
216
266
LOG .warn ("Skipping non-directory, nor jar source: {}" , source );
217
- return Stream . empty () ;
267
+ return false ;
218
268
}
219
269
//Scan directory for json in META-INF, add them to the list
220
270
val metaInf = new File (dir , "META-INF" );
221
271
if (!metaInf .exists () || !metaInf .isDirectory ()) {
222
- return Stream . empty () ;
272
+ return false ;
223
273
}
224
274
val files = metaInf .listFiles ();
225
275
if (files == null ) {
226
- return Stream . empty () ;
276
+ return false ;
227
277
}
228
278
for (val file : files ) {
229
279
if (!file .getName ().endsWith (".json" )) {
230
280
continue ;
231
281
}
232
282
try {
233
283
output .add (file .toURI ().toURL ());
284
+ found = true ;
234
285
} catch (MalformedURLException e ) {
235
286
LOG .error ("Failed to add json source {} to dependency source list: {}" , file .getName (), e );
236
287
}
237
288
}
238
289
}
239
- return output . stream () ;
290
+ return found ;
240
291
}
241
292
242
293
private static Stream <URL > grabSourceCandidatesFromFolder (File folder ) {
@@ -275,40 +326,67 @@ public static void scanDeps() {
275
326
LOG .debug ("Discovering dependency source candidates..." );
276
327
val modsDir = new File (FileUtil .getMinecraftHome (), "mods" );
277
328
val mods1710Dir = new File (modsDir , "1.7.10" );
278
- val dependencySpecs = Stream .of (Launch .classLoader .getSources ().stream (),
279
- grabSourceCandidatesFromFolder (modsDir ),
280
- grabSourceCandidatesFromFolder (mods1710Dir ))
281
- .flatMap ((i ) -> i )
282
- .flatMap (DependencyLoaderImpl ::scanSourceMetaInf )
283
- .map ((source ) -> {
284
- //Convert source to GSON json
285
- try (val is = source .openStream ()) {
286
- val jsonRaw = new JsonParser ().parse (new InputStreamReader (is ));
287
- if (!jsonRaw .isJsonObject ()) {
288
- return null ;
289
- }
290
- val json = jsonRaw .getAsJsonObject ();
291
- if (!(json .has ("identifier" ) &&
292
- json .get ("identifier" )
293
- .getAsString ()
294
- .equals ("falsepatternlib_dependencies" )
295
- )) {
296
- return null ;
297
- }
298
- val builder = new GsonBuilder ();
299
- builder .excludeFieldsWithoutExposeAnnotation ();
300
- val gson = builder .create ();
301
- json .remove ("identifier" );
302
- val root = gson .fromJson (json , DepRoot .class );
303
- root .source (source .toString ());
304
- return root ;
305
- } catch (Exception e ) {
306
- LOG .error ("Failed to read json from source {}: {}" , source , e );
307
- return null ;
308
- }
309
- })
310
- .filter (Objects ::nonNull )
311
- .collect (Collectors .toSet ());
329
+ long start = System .currentTimeMillis ();
330
+ val urlsWithoutDeps = new HashSet <String >();
331
+ val depCache = new File (libDir , ".depscan_cache" );
332
+ if (depCache .exists ()) {
333
+ try {
334
+ urlsWithoutDeps .addAll (Files .readAllLines (depCache .toPath ()));
335
+ } catch (IOException e ) {
336
+ LOG .error ("Could not read dependency scanner cache" , e );
337
+ }
338
+ }
339
+ val candidates = Stream .of (Launch .classLoader .getSources ().stream (),
340
+ grabSourceCandidatesFromFolder (modsDir ),
341
+ grabSourceCandidatesFromFolder (mods1710Dir ))
342
+ .flatMap ((i ) -> i )
343
+ .filter ((url ) -> !urlsWithoutDeps .contains (url .toString ()))
344
+ .collect (Collectors .toList ());
345
+ val urls = new ArrayList <URL >();
346
+ for (val candidate : candidates ) {
347
+ if (!scanForDepSpecs (candidate , urls )) {
348
+ urlsWithoutDeps .add (candidate .toString ());
349
+ }
350
+ }
351
+ try (val out = Files .newBufferedWriter (depCache .toPath ())) {
352
+ for (val noDep : urlsWithoutDeps ) {
353
+ out .append (noDep ).append (System .lineSeparator ());
354
+ }
355
+ } catch (IOException e ) {
356
+ LOG .error ("Could not write dependency scanner cache" , e );
357
+ }
358
+ val dependencySpecs = urls .stream ()
359
+ .map ((source ) -> {
360
+ //Convert source to GSON json
361
+ try (val is = new BufferedInputStream (source .openStream ())) {
362
+ val jsonRaw = new JsonParser ().parse (new InputStreamReader (is ));
363
+ if (!jsonRaw .isJsonObject ()) {
364
+ return null ;
365
+ }
366
+ val json = jsonRaw .getAsJsonObject ();
367
+ if (!(json .has ("identifier" ) &&
368
+ json .get ("identifier" )
369
+ .getAsString ()
370
+ .equals ("falsepatternlib_dependencies" )
371
+ )) {
372
+ return null ;
373
+ }
374
+ val builder = new GsonBuilder ();
375
+ builder .excludeFieldsWithoutExposeAnnotation ();
376
+ val gson = builder .create ();
377
+ json .remove ("identifier" );
378
+ val root = gson .fromJson (json , DepRoot .class );
379
+ root .source (source .toString ());
380
+ return root ;
381
+ } catch (Exception e ) {
382
+ LOG .error ("Failed to read json from source {}: {}" , source , e );
383
+ return null ;
384
+ }
385
+ })
386
+ .filter (Objects ::nonNull )
387
+ .collect (Collectors .toSet ());
388
+ long end = System .currentTimeMillis ();
389
+ LOG .debug ("Discovered {} dependency source candidates in {}ms" , dependencySpecs .size (), end - start );
312
390
mavenRepositories .addAll (dependencySpecs .stream ()
313
391
.flatMap ((dep ) -> dep .repositories ().stream ())
314
392
.collect (Collectors .toSet ()));
@@ -407,7 +485,6 @@ private static class DependencyLoadTask {
407
485
private String artifact ;
408
486
private String mavenJarName ;
409
487
private String jarName ;
410
- private File libDir ;
411
488
private File file ;
412
489
413
490
private void load () {
@@ -477,50 +554,9 @@ private void alreadyLoaded() {
477
554
}
478
555
479
556
private void setupPaths () {
480
- var homeDir = System .getProperty ("minecraft.sharedDataDir" );
481
- if (homeDir == null ) {
482
- homeDir = System .getenv ("MINECRAFT_SHARED_DATA_DIR" );
483
- if (homeDir == null ) {
484
- homeDir = FileUtil .getMinecraftHome ().getAbsolutePath ();
485
- }
486
- }
487
- val modsDir = Paths .get (homeDir , "mods" ).toFile ();
488
- val oldLibDir = new File (modsDir , "falsepattern" );
489
- libDir = new File (homeDir , "falsepattern" );
490
557
mavenJarName =
491
558
String .format ("%s-%s%s.jar" , artifactId , preferredVersion , (suffix != null ) ? ("-" + suffix ) : "" );
492
559
jarName = groupId + "-" + mavenJarName ;
493
- if (!libDir .exists ()) {
494
- if (!libDir .mkdirs ()) {
495
- LOG .fatal ("Failed to create directory {}" , libDir );
496
- throw new RuntimeException ("Failed to create directory " + libDir );
497
- }
498
- }
499
- if (oldLibDir .exists ()) {
500
- LOG .info ("Migrating old library folder. From: " + oldLibDir .getAbsolutePath () + ", To: " + libDir .getAbsolutePath ());
501
- val oldFiles = oldLibDir .listFiles ();
502
- if (oldFiles != null ) {
503
- for (val file : oldFiles ) {
504
- try {
505
- Files .move (file .toPath (), libDir .toPath ().resolve (oldLibDir .toPath ().relativize (file .toPath ())), StandardCopyOption .REPLACE_EXISTING );
506
- } catch (IOException e ) {
507
- LOG .warn ("Failed to move file " + file .getName () + " to new dir! Deleting instead." );
508
- try {
509
- Files .deleteIfExists (file .toPath ());
510
- } catch (IOException ex ) {
511
- LOG .warn ("Failed to delete file " + file .getPath () + "!" );
512
- file .deleteOnExit ();
513
- }
514
- }
515
- }
516
- }
517
- try {
518
- Files .deleteIfExists (oldLibDir .toPath ());
519
- } catch (IOException e ) {
520
- LOG .warn ("Failed to delete old library directory!" );
521
- oldLibDir .deleteOnExit ();
522
- }
523
- }
524
560
file = new File (libDir , jarName );
525
561
}
526
562
0 commit comments