aboutsummaryrefslogtreecommitdiff
path: root/src/gradlecomp/java/net/minecraftforge
diff options
context:
space:
mode:
authorLexManos <LexManos@gmail.com>2021-01-17 17:35:01 -0800
committerLexManos <LexManos@gmail.com>2021-01-17 17:40:39 -0800
commit4089917696fffbd4b818fb90958d20f0714f93fb (patch)
tree1f5de4972d9afe0328d7d0ce929aac06c3bca15e /src/gradlecomp/java/net/minecraftforge
parent631cd05e726092c51e95b52bb8a8bb6a2ae2cc42 (diff)
downloadArtifactural-4089917696fffbd4b818fb90958d20f0714f93fb.tar.gz
Artifactural-4089917696fffbd4b818fb90958d20f0714f93fb.tar.bz2
Artifactural-4089917696fffbd4b818fb90958d20f0714f93fb.zip
Move to net.minecraftforge package, and update license headers.
Diffstat (limited to 'src/gradlecomp/java/net/minecraftforge')
-rw-r--r--src/gradlecomp/java/net/minecraftforge/artifactural/gradle/DependencyResolver.java124
-rw-r--r--src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleArtifact.java45
-rw-r--r--src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleRepositoryAdapter.java333
-rw-r--r--src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ModifierAccess.java55
-rw-r--r--src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ReflectionUtils.java112
5 files changed, 669 insertions, 0 deletions
diff --git a/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/DependencyResolver.java b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/DependencyResolver.java
new file mode 100644
index 0000000..a0d8a00
--- /dev/null
+++ b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/DependencyResolver.java
@@ -0,0 +1,124 @@
+/*
+ * Artifactural
+ * Copyright (c) 2018-2021.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.artifactural.gradle;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import org.gradle.api.Project;
+import org.gradle.api.artifacts.ClientModule;
+import org.gradle.api.artifacts.Configuration;
+import org.gradle.api.artifacts.Dependency;
+import org.gradle.api.artifacts.DependencyArtifact;
+import org.gradle.api.artifacts.FileCollectionDependency;
+import org.gradle.api.artifacts.ModuleDependency;
+
+import java.io.File;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class DependencyResolver {
+
+ private final Project project;
+ private final AtomicInteger counter = new AtomicInteger(0);
+ private final Cache<String, CompletableFuture<Set<File>>> resolved = CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.MINUTES).build();
+
+ public DependencyResolver(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * Resolves a dependency, downloading the file and its transitives
+ * if not cached and returns the set of files.
+ */
+ public Set<File> resolveDependency(Dependency dependency) {
+ if (dependency instanceof FileCollectionDependency) {
+ return ((FileCollectionDependency) dependency).getFiles().getFiles();
+ }
+ String name = dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion();
+ if (dependency instanceof ModuleDependency) {
+ Set<DependencyArtifact> artifacts = ((ModuleDependency) dependency).getArtifacts();
+ if (!artifacts.isEmpty()) {
+ DependencyArtifact artifact = artifacts.iterator().next();
+ name += ":" + artifact.getClassifier() + "@" + artifact.getExtension();
+ }
+ }
+
+ // If this dep is being resolved on another thread, let it do it
+ CompletableFuture<Set<File>> future;
+ boolean found = true;
+ synchronized (resolved) {
+ future = resolved.getIfPresent(name);
+ if (future == null) {
+ resolved.put(name, future = new CompletableFuture<>());
+ found = false;
+ }
+ }
+
+ if (found) {
+ try {
+ return future.get();
+ } catch (InterruptedException | ExecutionException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // No other thread is resolving this dep and we've claimed it, so let's go!
+ int currentID = counter.getAndIncrement();
+ Configuration cfg = project.getConfigurations().maybeCreate("resolve_dep_" + currentID);
+ cfg.getDependencies().add(dependency);
+ Set<File> files = cfg.resolve();
+ project.getConfigurations().remove(cfg);
+ future.complete(files);
+ return files;
+ }
+
+ /**
+ * Resolves a dependency, downloading the file and its transitives
+ * if not cached and returns the set of files.
+ */
+ public Set<File> resolveDependency(Object dependency) {
+ Dependency dep = project.getDependencies().create(dependency);
+ return resolveDependency(dep);
+ }
+
+ /**
+ * Resolves a dependency, downloading the file and its transitives
+ * if not cached and returns the set of files.
+ */
+ public Set<File> resolveDependency(Object dependency, boolean transitive) {
+ Dependency dep = project.getDependencies().create(dependency);
+ if (dep instanceof ClientModule) {
+ dep = ((ClientModule) dep).copy().setTransitive(transitive);
+ }
+ return resolveDependency(dep);
+ }
+
+ /**
+ * Resolves a single dependency without any of its transitives
+ * if not cached and returns the file.
+ */
+ public File resolveSingleDependency(Object dependency) {
+ return resolveDependency(dependency, false).iterator().next();
+ }
+
+}
diff --git a/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleArtifact.java b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleArtifact.java
new file mode 100644
index 0000000..e099c73
--- /dev/null
+++ b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleArtifact.java
@@ -0,0 +1,45 @@
+/*
+ * Artifactural
+ * Copyright (c) 2018-2021.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.artifactural.gradle;
+
+import net.minecraftforge.artifactural.api.artifact.Artifact;
+import net.minecraftforge.artifactural.api.artifact.ArtifactIdentifier;
+import net.minecraftforge.artifactural.api.artifact.ArtifactType;
+import net.minecraftforge.artifactural.base.artifact.StreamableArtifact;
+
+import java.io.File;
+import java.util.Set;
+
+public class GradleArtifact {
+
+ public static Artifact maven(DependencyResolver resolver, ArtifactIdentifier identifier, ArtifactType type) {
+ Set<File> files = resolver.resolveDependency(
+ identifier.getGroup()
+ + ":" + identifier.getName()
+ + ":" + identifier.getVersion()
+ + (identifier.getClassifier().isEmpty() ? "" : ":" + identifier.getClassifier())
+ + (identifier.getExtension().isEmpty() ? "" : "@" + identifier.getExtension()),
+ false
+ );
+ if (files.isEmpty()) return Artifact.none();
+ return StreamableArtifact.ofFile(identifier, type, files.iterator().next());
+ }
+
+}
diff --git a/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleRepositoryAdapter.java b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleRepositoryAdapter.java
new file mode 100644
index 0000000..87cd246
--- /dev/null
+++ b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleRepositoryAdapter.java
@@ -0,0 +1,333 @@
+/*
+ * Artifactural
+ * Copyright (c) 2018-2021.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.artifactural.gradle;
+
+import net.minecraftforge.artifactural.api.artifact.Artifact;
+import net.minecraftforge.artifactural.api.artifact.ArtifactIdentifier;
+import net.minecraftforge.artifactural.api.artifact.MissingArtifactException;
+import net.minecraftforge.artifactural.api.repository.Repository;
+import net.minecraftforge.artifactural.base.artifact.SimpleArtifactIdentifier;
+import net.minecraftforge.artifactural.base.cache.LocatedArtifactCache;
+
+import org.gradle.api.artifacts.ComponentMetadataSupplierDetails;
+import org.gradle.api.artifacts.component.ComponentArtifactIdentifier;
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
+import org.gradle.api.artifacts.dsl.RepositoryHandler;
+import org.gradle.api.internal.artifacts.BaseRepositoryFactory;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentResolvers;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ModuleComponentRepositoryAccess;
+import org.gradle.api.internal.artifacts.ivyservice.resolveengine.artifact.ResolvableArtifact;
+import org.gradle.api.internal.artifacts.repositories.AbstractArtifactRepository;
+import org.gradle.api.internal.artifacts.repositories.DefaultMavenLocalArtifactRepository;
+import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
+import org.gradle.api.internal.artifacts.repositories.descriptor.FlatDirRepositoryDescriptor;
+import org.gradle.api.internal.artifacts.repositories.descriptor.RepositoryDescriptor;
+import org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceArtifactResolver;
+import org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver;
+import org.gradle.api.internal.artifacts.repositories.resolver.MavenResolver;
+import org.gradle.api.internal.artifacts.repositories.resolver.MetadataFetchingCost;
+import org.gradle.api.internal.component.ArtifactType;
+import org.gradle.api.model.ObjectFactory;
+import org.gradle.internal.action.InstantiatingAction;
+import org.gradle.internal.component.external.model.ModuleComponentResolveMetadata;
+import org.gradle.internal.component.external.model.ModuleDependencyMetadata;
+import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetadata;
+import org.gradle.internal.component.model.ComponentArtifactMetadata;
+import org.gradle.internal.component.model.ComponentOverrideMetadata;
+import org.gradle.internal.component.model.ComponentResolveMetadata;
+import org.gradle.internal.component.model.ConfigurationMetadata;
+import org.gradle.internal.component.model.ModuleSources;
+import org.gradle.internal.nativeintegration.filesystem.FileSystem;
+import org.gradle.internal.nativeintegration.services.FileSystems;
+import org.gradle.internal.reflect.Instantiator;
+import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
+import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
+import org.gradle.internal.resolve.result.BuildableComponentArtifactsResolveResult;
+import org.gradle.internal.resolve.result.BuildableModuleComponentMetaDataResolveResult;
+import org.gradle.internal.resolve.result.BuildableModuleVersionListingResolveResult;
+import org.gradle.internal.resource.ExternalResourceName;
+import org.gradle.internal.resource.ExternalResourceRepository;
+import org.gradle.internal.resource.LocalBinaryResource;
+import org.gradle.internal.resource.local.FileResourceRepository;
+import org.gradle.internal.resource.local.LocalFileStandInExternalResource;
+import org.gradle.internal.resource.local.LocallyAvailableExternalResource;
+import org.gradle.internal.resource.metadata.ExternalResourceMetaData;
+import org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class GradleRepositoryAdapter extends AbstractArtifactRepository implements ResolutionAwareRepository {
+
+ private static final Pattern URL_PATTERN = Pattern.compile(
+ "^(?<group>\\S+(?:/\\S+)*)/(?<name>\\S+)/(?<version>\\S+)/" +
+ "\\2-\\3(?:-(?<classifier>[^.\\s]+))?\\.(?<extension>\\S+)$");
+
+ public static GradleRepositoryAdapter add(RepositoryHandler handler, String name, File local, Repository repository) {
+ BaseRepositoryFactory factory = ReflectionUtils.get(handler, "repositoryFactory"); // We reflect here and create it manually so it DOESN'T get attached.
+ DefaultMavenLocalArtifactRepository maven = (DefaultMavenLocalArtifactRepository)factory.createMavenLocalRepository(); // We use maven local because it bypasses the caching and coping to .m2
+ maven.setUrl(local);
+ maven.setName(name);
+
+ GradleRepositoryAdapter repo;
+
+ repo = new GradleRepositoryAdapter(repository, maven);
+ repo.setName(name);
+ handler.add(repo);
+ return repo;
+ }
+
+ private final Repository repository;
+ private final DefaultMavenLocalArtifactRepository local;
+ private final String root;
+ private final LocatedArtifactCache cache;
+
+
+ // This constructor is modified via bytecode manipulation in 'build.gradle'
+ // DO NOT change this without modifying 'build.gradle'
+ // This contructor is used on Gradle 4.9 and below
+ private GradleRepositoryAdapter(Repository repository, DefaultMavenLocalArtifactRepository local) {
+ // This is replaced with a call to 'super()', with no arguments
+ super(null);
+ this.repository = repository;
+ this.local = local;
+ this.root = cleanRoot(local.getUrl());
+ this.cache = new LocatedArtifactCache(new File(root));
+ }
+
+
+ // This constructor is used on Gradle 4.10 and above
+ GradleRepositoryAdapter(ObjectFactory objectFactory, Repository repository, DefaultMavenLocalArtifactRepository local) {
+ super(objectFactory);
+ // This duplication from the above two-argument constructor is unfortunate,
+ // but unavoidable
+ this.repository = repository;
+ this.local = local;
+ this.root = cleanRoot(local.getUrl());
+ this.cache = new LocatedArtifactCache(new File(root));
+ }
+
+ @Override
+ public String getDisplayName() {
+ return local.getDisplayName();
+ }
+
+ @Override
+ public ConfiguredModuleComponentRepository createResolver() {
+ MavenResolver resolver = (MavenResolver)local.createResolver();
+
+ GeneratingFileResourceRepository repo = new GeneratingFileResourceRepository();
+ ReflectionUtils.alter(resolver, "repository", prev -> repo); // ExternalResourceResolver.repository
+ //ReflectionUtils.alter(resolver, "metadataSources", ); //ExternalResourceResolver.metadataSources We need to fix these from returning 'missing'
+ // MavenResolver -> MavenMetadataLoader -> FileCacheAwareExternalResourceAccessor -> DefaultCacheAwareExternalResourceAccessor
+ DefaultCacheAwareExternalResourceAccessor accessor = ReflectionUtils.get(resolver, "mavenMetaDataLoader.cacheAwareExternalResourceAccessor.delegate");
+ ReflectionUtils.alter(accessor, "delegate", prev -> repo); // DefaultCacheAwareExternalResourceAccessor.delegate
+ ReflectionUtils.alter(accessor, "fileResourceRepository", prev -> repo); // DefaultCacheAwareExternalResourceAccessor.fileResourceRepository
+ ExternalResourceArtifactResolver extResolver = ReflectionUtils.invoke(resolver, ExternalResourceResolver.class, "createArtifactResolver"); //Makes the resolver and caches it.
+ ReflectionUtils.alter(extResolver, "repository", prev -> repo);
+ //File transport references, Would be better to get a reference to the transport and work from there, but don't see it stored anywhere.
+ ReflectionUtils.alter(resolver, "cachingResourceAccessor.this$0.repository", prev -> repo);
+ ReflectionUtils.alter(resolver, "cachingResourceAccessor.delegate.delegate", prev -> repo);
+
+ return new ConfiguredModuleComponentRepository() {
+ private final ModuleComponentRepositoryAccess local = wrap(resolver.getLocalAccess());
+ private final ModuleComponentRepositoryAccess remote = wrap(resolver.getRemoteAccess());
+ @Override public String getId() { return resolver.getId(); }
+ @Override public String getName() { return resolver.getName(); }
+ @Override public ModuleComponentRepositoryAccess getLocalAccess() { return local; }
+ @Override public ModuleComponentRepositoryAccess getRemoteAccess() { return remote; }
+ @Override public Map<ComponentArtifactIdentifier, ResolvableArtifact> getArtifactCache() { return resolver.getArtifactCache(); }
+ @Override public InstantiatingAction<ComponentMetadataSupplierDetails> getComponentMetadataSupplier() { return resolver.getComponentMetadataSupplier(); }
+ @Override public boolean isDynamicResolveMode() { return resolver.isDynamicResolveMode(); }
+ @Override public boolean isLocal() { return resolver.isLocal(); }
+
+ @Override
+ public void setComponentResolvers(ComponentResolvers resolver) { }
+ @Override
+ public Instantiator getComponentMetadataInstantiator() {
+ return resolver.getComponentMetadataInstantiator();
+ }
+
+ private ModuleComponentRepositoryAccess wrap(ModuleComponentRepositoryAccess delegate) {
+ return new ModuleComponentRepositoryAccess() {
+ @Override
+ public void resolveComponentMetaData(ModuleComponentIdentifier moduleComponentIdentifier, ComponentOverrideMetadata requestMetaData, BuildableModuleComponentMetaDataResolveResult result) {
+ delegate.resolveComponentMetaData(moduleComponentIdentifier, requestMetaData, result);
+ if (result.getState() == BuildableModuleComponentMetaDataResolveResult.State.Resolved) {
+ ModuleComponentResolveMetadata meta = result.getMetaData();
+ if (meta.isMissing()) {
+ MutableModuleComponentResolveMetadata mutable = meta.asMutable();
+ mutable.setChanging(true);
+ mutable.setMissing(false);
+ result.resolved(mutable.asImmutable());
+ }
+ }
+ }
+
+ @Override
+ public void resolveArtifacts(ComponentResolveMetadata component, ConfigurationMetadata variant, BuildableComponentArtifactsResolveResult result) {
+ delegate.resolveArtifacts(component, variant, result);
+ }
+
+ @Override
+ public void listModuleVersions(ModuleDependencyMetadata dependency, BuildableModuleVersionListingResolveResult result) {
+ delegate.listModuleVersions(dependency, result);
+ }
+
+ @Override
+ public void resolveArtifactsWithType(ComponentResolveMetadata component, ArtifactType artifactType, BuildableArtifactSetResolveResult result) {
+ delegate.resolveArtifactsWithType(component, artifactType, result);
+ }
+
+ @Override
+ public void resolveArtifact(ComponentArtifactMetadata artifact, ModuleSources moduleSources, BuildableArtifactResolveResult result) {
+ delegate.resolveArtifact(artifact, moduleSources, result);
+ }
+
+
+ @Override
+ public MetadataFetchingCost estimateMetadataFetchingCost(ModuleComponentIdentifier moduleComponentIdentifier) {
+ return delegate.estimateMetadataFetchingCost(moduleComponentIdentifier);
+ }
+ };
+ }
+ };
+ }
+
+ public RepositoryDescriptor getDescriptor() {
+ return new FlatDirRepositoryDescriptor("ArtifacturalRepository", new ArrayList<>());
+ }
+
+
+ private static String cleanRoot(URI uri) {
+ String ret = uri.normalize().getPath().replace('\\', '/');
+ if (!ret.endsWith("/")) ret += '/';
+ return ret;
+ }
+
+ private class GeneratingFileResourceRepository implements FileResourceRepository {
+ private final FileSystem fileSystem = FileSystems.getDefault();
+ private void debug(String message) {
+ //System.out.println(message);
+ }
+ private void log(String message) {
+ System.out.println(message);
+ }
+
+ @Override
+ public ExternalResourceRepository withProgressLogging() {
+ return this;
+ }
+
+ @Override
+ public LocalBinaryResource localResource(File file) {
+ debug("localResource: " + file);
+ return null;
+ }
+
+ @Override
+ public LocallyAvailableExternalResource resource(File file) {
+ debug("resource(File): " + file);
+ return findArtifact(file.getAbsolutePath().replace('\\', '/'));
+ }
+
+ @Override
+ public LocallyAvailableExternalResource resource(ExternalResourceName location) {
+ return resource(location, false);
+ }
+
+ @Override
+ public LocallyAvailableExternalResource resource(ExternalResourceName location, boolean revalidate) {
+ debug("resource(ExternalResourceName,boolean): " + location + ", " + revalidate);
+ return findArtifact(location.getUri().getPath().replace('\\', '/'));
+ }
+
+ @Override
+ public LocallyAvailableExternalResource resource(File file, URI originUri, ExternalResourceMetaData originMetadata) {
+ debug("resource(File,URI,ExternalResourceMetaData): " + file + ", " + originUri + ", " + originMetadata);
+ return findArtifact(file.getAbsolutePath().replace('\\', '/'));
+ }
+
+ private LocallyAvailableExternalResource findArtifact(String path) {
+ if (path.startsWith(root)) {
+ String relative = path.substring(root.length());
+ debug(" Relative: " + relative);
+ Matcher matcher = URL_PATTERN.matcher(relative);
+ if (matcher.matches()) {
+ ArtifactIdentifier identifier = new SimpleArtifactIdentifier(
+ matcher.group("group").replace('/', '.'),
+ matcher.group("name"),
+ matcher.group("version"),
+ matcher.group("classifier"),
+ matcher.group("extension"));
+ Artifact artifact = repository.getArtifact(identifier);
+ return wrap(artifact, identifier);
+ } else if (relative.endsWith("maven-metadata.xml")) {
+ String tmp = relative.substring(0, relative.length() - "maven-metadata.xml".length() - 1);
+ int idx = tmp.lastIndexOf('/');
+ if (idx != -1) {
+ File ret = repository.getMavenMetadata(tmp.substring(0, idx - 1), tmp.substring(idx));
+ if (ret != null) {
+ return new LocalFileStandInExternalResource(ret, fileSystem);
+ }
+ }
+ } else if (relative.endsWith("/")) {
+ debug(" Directory listing not supported");
+ } else {
+ log(" Matcher Failed: " + relative);
+ }
+ } else {
+ log("Unknown root: " + path);
+ }
+ return new LocalFileStandInExternalResource(new File(path), fileSystem);
+ }
+
+ private LocallyAvailableExternalResource wrap(Artifact artifact, ArtifactIdentifier id) {
+ if (!artifact.isPresent())
+ return new LocalFileStandInExternalResource(cache.getPath(artifact), fileSystem);
+ Artifact.Cached cached = artifact.optionallyCache(cache);
+ try {
+ return new LocalFileStandInExternalResource(cached.asFile(), fileSystem);
+ } catch (MissingArtifactException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ //TODO: Make this a artifact provider interface with a proper API so we dont have direct reference to GradleRepoAdapter in consumers.
+ public File getArtifact(ArtifactIdentifier identifier) {
+ Artifact art = repository.getArtifact(identifier);
+ if (!art.isPresent())
+ return null;
+
+ Artifact.Cached cached = art.optionallyCache(cache);
+ try {
+ return cached.asFile();
+ } catch (MissingArtifactException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ModifierAccess.java b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ModifierAccess.java
new file mode 100644
index 0000000..fb68144
--- /dev/null
+++ b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ModifierAccess.java
@@ -0,0 +1,55 @@
+/*
+ * Artifactural
+ * Copyright (c) 2018-2021.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.artifactural.gradle;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+public class ModifierAccess {
+ private static Field MODIFIER_ACCESS = null;
+ private static boolean accessAttempted = false;
+
+ public static synchronized boolean definalize(Field target) {
+ if ((target.getModifiers() & Modifier.FINAL) == 0) {
+ return true;
+ }
+
+ if (MODIFIER_ACCESS == null && !accessAttempted) {
+ try {
+ final Field modifiers = Field.class.getDeclaredField("modifiers");
+ modifiers.setAccessible(true);
+ MODIFIER_ACCESS = modifiers;
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException("Could not access Field.modifiers to definalize reflection object. Use Java 8, current version: " + System.getProperty("java.version"), e);
+ }
+ accessAttempted = true;
+ }
+ if (MODIFIER_ACCESS != null) {
+ try {
+ MODIFIER_ACCESS.setInt(target, target.getModifiers() & ~Modifier.FINAL);
+ } catch (IllegalArgumentException | IllegalAccessException e) {
+ throw new RuntimeException("Could not definalize field " + target.getDeclaringClass().getName() + "." + target.getName(), e);
+ }
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ReflectionUtils.java b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ReflectionUtils.java
new file mode 100644
index 0000000..4e18885
--- /dev/null
+++ b/src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ReflectionUtils.java
@@ -0,0 +1,112 @@
+/*
+ * Artifactural
+ * Copyright (c) 2018-2021.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package net.minecraftforge.artifactural.gradle;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.function.UnaryOperator;
+
+public class ReflectionUtils {
+
+ @SuppressWarnings("unchecked")
+ public static <T> void alter(Object target, String name, UnaryOperator<T> operator) {
+ try {
+ int idx = name.lastIndexOf('.');
+ if (idx != -1) {
+ target = drillField(target, name.substring(0, idx));
+ if (target == null) throw new IllegalStateException("Could not find field '" + name + "'");
+ name = name.substring(idx + 1);
+ }
+ Field f = findField(target.getClass(), name);
+ if (f == null) throw new IllegalStateException("Could not find '" + name + "'");
+
+ T oldV = (T)f.get(target);
+ T newV = operator.apply(oldV);
+ f.set(target, newV);
+
+ if (f.get(target) != newV) {
+ throw new IllegalStateException("Failed to set new value on " + f.getDeclaringClass().getName() + "." + f.getName());
+ }
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private static Object drillField(Object obj, String path) {
+ for (String name : path.split("\\.")) {
+ if (obj == null) return null;
+ Field f = findField(obj.getClass(), name);
+ if (f == null) return null;
+ try {
+ obj = f.get(obj);
+ } catch (IllegalAccessException e) {
+ return null;
+ }
+ }
+ return obj;
+ }
+
+ private static Field findField(Class<?> clazz, String name) {
+ while (clazz != Object.class) {
+ for (Field f : clazz.getDeclaredFields()) {
+ if (f.getName().equals(name)) {
+ f.setAccessible(true);
+ if (!ModifierAccess.definalize(f)) {
+ System.out.println("Could not definalize field " + f.getDeclaringClass().getName() + "." + f.getName() + " Exception ate, lets see if it works");
+ }
+ return f;
+ }
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return null;
+ }
+
+ /**
+ * Invokes a method (can be private).
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T invoke(Object target, Class<?> type, String name, Object... args) {
+ try {
+ Method method = type.getDeclaredMethod(name);
+ method.setAccessible(true);
+ return (T) method.invoke(target, args);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static <T> T get(Object target, String name) {
+ try {
+ int idx = name.lastIndexOf('.');
+ if (idx != -1) {
+ target = drillField(target, name.substring(0, idx));
+ if (target == null) throw new IllegalStateException("Could not find field '" + name + "'");
+ name = name.substring(idx + 1);
+ }
+ Field f = findField(target.getClass(), name);
+ if (f == null) throw new IllegalStateException("Could not find '" + name + "'");
+ return (T)f.get(target);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+}