33import  fish .cichlidmc .cichlid_gradle .cache .CichlidCache ;
44import  fish .cichlidmc .cichlid_gradle .cache .mcmaven .McMavenConnectorFactory ;
55import  fish .cichlidmc .cichlid_gradle .extension .CichlidExtension ;
6+ import  fish .cichlidmc .cichlid_gradle .extension .def .MinecraftDefinition ;
7+ import  fish .cichlidmc .cichlid_gradle .extension .def .MinecraftDefinitionImpl ;
68import  fish .cichlidmc .cichlid_gradle .extension .dep .CichlidDepsExtension ;
7- import  fish .cichlidmc .cichlid_gradle .extension .dep .MinecraftDepsExtension ;
89import  fish .cichlidmc .cichlid_gradle .extension .repo .CichlidReposExtension ;
910import  fish .cichlidmc .cichlid_gradle .extension .repo .MinecraftReposExtension ;
1011import  fish .cichlidmc .cichlid_gradle .run .RunTaskGeneration ;
12+ import  fish .cichlidmc .cichlid_gradle .util .Utils ;
13+ import  org .gradle .api .Action ;
14+ import  org .gradle .api .NamedDomainObjectContainer ;
1115import  org .gradle .api .NamedDomainObjectProvider ;
1216import  org .gradle .api .Plugin ;
1317import  org .gradle .api .Project ;
18+ import  org .gradle .api .artifacts .Configuration ;
1419import  org .gradle .api .artifacts .ConfigurationContainer ;
20+ import  org .gradle .api .artifacts .Dependency ;
1521import  org .gradle .api .artifacts .DependencyScopeConfiguration ;
22+ import  org .gradle .api .artifacts .ModuleIdentifier ;
23+ import  org .gradle .api .internal .artifacts .cache .ArtifactResolutionControl ;
24+ import  org .gradle .api .internal .artifacts .cache .ModuleResolutionControl ;
25+ import  org .gradle .api .internal .artifacts .configurations .ResolutionStrategyInternal ;
26+ import  org .gradle .api .internal .artifacts .ivyservice .resolutionstrategy .DefaultCachePolicy ;
1627import  org .gradle .api .internal .artifacts .repositories .transport .RepositoryTransportFactory ;
28+ import  org .jetbrains .annotations .Nullable ;
1729
1830import  javax .inject .Inject ;
31+ import  java .lang .reflect .Field ;
32+ import  java .util .List ;
33+ import  java .util .concurrent .TimeUnit ;
1934
2035public  class  CichlidGradlePlugin  implements  Plugin <Project > {
2136	public  static  final  String  NAME  = "CichlidGradle" ;
@@ -36,16 +51,17 @@ public void apply(Project project) {
3651		CichlidReposExtension .setup (project );
3752		MinecraftReposExtension .setup (project );
3853		CichlidDepsExtension .setup (project );
39- 		MinecraftDepsExtension .setup (project );
4054		RunTaskGeneration .setup (project );
55+ 		MinecraftDefinition .setup (project );
4156
42- 		ConfigurationContainer  configurations  = project .getConfigurations ();
43- 		setupConfigurations (configurations );
57+ 		setupConfigurations (project );
4458
45- 		McMavenConnectorFactory .inject (this .repositoryTransportFactory , CichlidCache . get ( project ) );
59+ 		McMavenConnectorFactory .inject (this .repositoryTransportFactory , project );
4660	}
4761
48- 	private  static  void  setupConfigurations (ConfigurationContainer  configurations ) {
62+ 	private  static  void  setupConfigurations (Project  project ) {
63+ 		ConfigurationContainer  configurations  = project .getConfigurations ();
64+ 
4965		// configurations for Cichlid. 
5066		// you need one configuration for declaring dependencies and another extending it for resolution 
5167		NamedDomainObjectProvider <DependencyScopeConfiguration > cichlidRuntime  = configurations .dependencyScope ("cichlidRuntime" );
@@ -54,5 +70,81 @@ private static void setupConfigurations(ConfigurationContainer configurations) {
5470
5571		// add Cichlid and its dependencies to the runtime classpath 
5672		configurations .named ("runtimeClasspath" , runtime  -> runtime .extendsFrom (cichlidRuntime .get ()));
73+ 
74+ 		// minecraft dependencies are set as changing so the current transformers are always applied. 
75+ 		// we need to set its cache duration to 0, but gradle API only allows you to do that per-configuration. 
76+ 		// it's possible with some internals though. 
77+ 		configurations .configureEach (CichlidGradlePlugin ::disableMinecraftCaching );
78+ 
79+ 		// if we try to resolve transformers for the first time in the mcmaven, an error 
80+ 		// is thrown because the current thread is already resolving a configuration, 
81+ 		// so we need to resolve them right before they're actually needed. 
82+ 
83+ 		NamedDomainObjectContainer <MinecraftDefinition > defs  = MinecraftDefinition .getExtension (project );
84+ 
85+ 		// for each configuration, right before resolution: 
86+ 		// - check if any dependencies are Minecraft 
87+ 		// - if so, find the corresponding definition 
88+ 		// - if it exists, resolve its transformers 
89+ 		configurations .configureEach (configuration  -> configuration .getIncoming ().beforeResolve (resolvable  -> {
90+ 			for  (Dependency  dep  : resolvable .getDependencies ()) {
91+ 				if  (!isMinecraft (dep ))
92+ 					continue ;
93+ 
94+ 				String  defName  = dep .getVersion ();
95+ 				if  (defName  == null )
96+ 					continue ;
97+ 
98+ 				MinecraftDefinitionImpl  def  = (MinecraftDefinitionImpl ) defs .findByName (defName );
99+ 				if  (def  == null )
100+ 					continue ;
101+ 
102+ 				// call iterator to make sure they're actually resolved 
103+ 				def .resolvableTransformers ().getIncoming ().getFiles ().iterator ();
104+ 			}
105+ 		}));
106+ 	}
107+ 
108+ 	private  static  void  disableMinecraftCaching (Configuration  configuration ) {
109+ 		try  {
110+ 			ResolutionStrategyInternal  strategy  = (ResolutionStrategyInternal ) configuration .getResolutionStrategy ();
111+ 			DefaultCachePolicy  policy  = (DefaultCachePolicy ) strategy .getCachePolicy ();
112+ 
113+ 			Field  moduleCacheRulesField  = DefaultCachePolicy .class .getDeclaredField ("moduleCacheRules" );
114+ 			moduleCacheRulesField .setAccessible (true );
115+ 			Field  artifactCacheRulesField  = DefaultCachePolicy .class .getDeclaredField ("artifactCacheRules" );
116+ 			artifactCacheRulesField .setAccessible (true );
117+ 
118+ 			List <Action <? super  ModuleResolutionControl >> moduleCacheRules  = Utils .get (moduleCacheRulesField , policy );
119+ 			List <Action <? super  ArtifactResolutionControl >> artifactCacheRules  = Utils .get (artifactCacheRulesField , policy );
120+ 
121+ 			// add to the ends of the lists to get final say. 
122+ 			// gradle conveniently adds to the front. 
123+ 
124+ 			moduleCacheRules .add (control  -> {
125+ 				if  (isMinecraft (control .getRequest ().getModule ())) {
126+ 					control .cacheFor (0 , TimeUnit .SECONDS );
127+ 				}
128+ 			});
129+ 			artifactCacheRules .add (control  -> {
130+ 				if  (isMinecraft (control .getRequest ().getId ().getComponentIdentifier ().getModuleIdentifier ())) {
131+ 					control .cacheFor (0 , TimeUnit .SECONDS );
132+ 				}
133+ 			});
134+ 		} catch  (Throwable  t ) {
135+ 			throw  new  RuntimeException ("Error accessing Gradle internals! You probably need to update Gradle, CichlidGradle, or both" , t );
136+ 		}
137+ 	}
138+ 
139+ 	private  static  boolean  isMinecraft (ModuleIdentifier  id ) {
140+ 		return  isMinecraft (id .getGroup (), id .getName ());
141+ 	}
142+ 
143+ 	private  static  boolean  isMinecraft (Dependency  dep ) {
144+ 		return  isMinecraft (dep .getGroup (), dep .getName ());
145+ 	}
146+ 
147+ 	private  static  boolean  isMinecraft (@ Nullable  String  group , @ Nullable  String  module ) {
148+ 		return  CichlidCache .MINECRAFT_GROUP .equals (group ) && CichlidCache .MINECRAFT_MODULE .equals (module );
57149	}
58150}
0 commit comments