4545
4646import cpw .mods .fml .relauncher .FMLLaunchHandler ;
4747
48+ import java .io .BufferedInputStream ;
4849import java .io .BufferedOutputStream ;
4950import java .io .File ;
5051import java .io .IOException ;
5960import java .util .ArrayList ;
6061import java .util .Arrays ;
6162import java .util .HashMap ;
63+ import java .util .HashSet ;
64+ import java .util .List ;
6265import java .util .Map ;
6366import java .util .Objects ;
6467import java .util .Set ;
@@ -93,6 +96,52 @@ public class DependencyLoaderImpl {
9396 thread .setName ("Dependency Download Thread " + counter .incrementAndGet ());
9497 return thread ;
9598 });
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+ }
96145
97146 public static void addMavenRepo (String url ) {
98147 mavenRepositories .add (url );
@@ -185,24 +234,25 @@ public static CompletableFuture<Void> loadLibrariesAsync(Library... libraries) {
185234 return CompletableFuture .allOf (futures .toArray (new CompletableFuture [0 ]));
186235 }
187236
188- private static Stream < URL > scanSourceMetaInf (URL source ) {
237+ private static boolean scanForDepSpecs (URL source , List < URL > output ) {
189238 if (!source .getProtocol ().equals ("file" )) {
190239 LOG .warn ("Skipping non-file source: {}" , source );
191- return Stream . empty () ;
240+ return false ;
192241 }
193242 LOG .debug ("Scanning {} for dependencies" , source );
194243 val fileName = source .getFile ();
195- val output = new ArrayList < URL >() ;
244+ boolean found = false ;
196245 if (fileName .endsWith (".jar" )) {
197246 //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 )) {
199248 ZipEntry entry ;
200249 while ((entry = jarFile .getNextEntry ()) != null ) {
201250 if (!entry .getName ().startsWith ("META-INF" ) || !entry .getName ().endsWith (".json" )) {
202251 continue ;
203252 }
204253 try {
205254 output .add (new URL ("jar:" + source + "!/" + entry .getName ()));
255+ found = true ;
206256 } catch (MalformedURLException e ) {
207257 LOG .error ("Failed to add json source {} to dependency source list: {}" , entry .getName (), e );
208258 }
@@ -214,29 +264,30 @@ private static Stream<URL> scanSourceMetaInf(URL source) {
214264 val dir = new File (fileName );
215265 if (!dir .exists () || !dir .isDirectory ()) {
216266 LOG .warn ("Skipping non-directory, nor jar source: {}" , source );
217- return Stream . empty () ;
267+ return false ;
218268 }
219269 //Scan directory for json in META-INF, add them to the list
220270 val metaInf = new File (dir , "META-INF" );
221271 if (!metaInf .exists () || !metaInf .isDirectory ()) {
222- return Stream . empty () ;
272+ return false ;
223273 }
224274 val files = metaInf .listFiles ();
225275 if (files == null ) {
226- return Stream . empty () ;
276+ return false ;
227277 }
228278 for (val file : files ) {
229279 if (!file .getName ().endsWith (".json" )) {
230280 continue ;
231281 }
232282 try {
233283 output .add (file .toURI ().toURL ());
284+ found = true ;
234285 } catch (MalformedURLException e ) {
235286 LOG .error ("Failed to add json source {} to dependency source list: {}" , file .getName (), e );
236287 }
237288 }
238289 }
239- return output . stream () ;
290+ return found ;
240291 }
241292
242293 private static Stream <URL > grabSourceCandidatesFromFolder (File folder ) {
@@ -275,40 +326,67 @@ public static void scanDeps() {
275326 LOG .debug ("Discovering dependency source candidates..." );
276327 val modsDir = new File (FileUtil .getMinecraftHome (), "mods" );
277328 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 );
312390 mavenRepositories .addAll (dependencySpecs .stream ()
313391 .flatMap ((dep ) -> dep .repositories ().stream ())
314392 .collect (Collectors .toSet ()));
@@ -407,7 +485,6 @@ private static class DependencyLoadTask {
407485 private String artifact ;
408486 private String mavenJarName ;
409487 private String jarName ;
410- private File libDir ;
411488 private File file ;
412489
413490 private void load () {
@@ -477,50 +554,9 @@ private void alreadyLoaded() {
477554 }
478555
479556 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" );
490557 mavenJarName =
491558 String .format ("%s-%s%s.jar" , artifactId , preferredVersion , (suffix != null ) ? ("-" + suffix ) : "" );
492559 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- }
524560 file = new File (libDir , jarName );
525561 }
526562
0 commit comments