From 4089917696fffbd4b818fb90958d20f0714f93fb Mon Sep 17 00:00:00 2001 From: LexManos Date: Sun, 17 Jan 2021 17:35:01 -0800 Subject: Move to net.minecraftforge package, and update license headers. --- .../artifactural/gradle/DependencyResolver.java | 124 -------- .../artifactural/gradle/GradleArtifact.java | 45 --- .../gradle/GradleRepositoryAdapter.java | 333 --------------------- .../artifactural/gradle/ModifierAccess.java | 55 ---- .../artifactural/gradle/ReflectionUtils.java | 112 ------- .../artifactural/gradle/DependencyResolver.java | 124 ++++++++ .../artifactural/gradle/GradleArtifact.java | 45 +++ .../gradle/GradleRepositoryAdapter.java | 333 +++++++++++++++++++++ .../artifactural/gradle/ModifierAccess.java | 55 ++++ .../artifactural/gradle/ReflectionUtils.java | 112 +++++++ 10 files changed, 669 insertions(+), 669 deletions(-) delete mode 100644 src/gradlecomp/java/com/amadornes/artifactural/gradle/DependencyResolver.java delete mode 100644 src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleArtifact.java delete mode 100644 src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java delete mode 100644 src/gradlecomp/java/com/amadornes/artifactural/gradle/ModifierAccess.java delete mode 100644 src/gradlecomp/java/com/amadornes/artifactural/gradle/ReflectionUtils.java create mode 100644 src/gradlecomp/java/net/minecraftforge/artifactural/gradle/DependencyResolver.java create mode 100644 src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleArtifact.java create mode 100644 src/gradlecomp/java/net/minecraftforge/artifactural/gradle/GradleRepositoryAdapter.java create mode 100644 src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ModifierAccess.java create mode 100644 src/gradlecomp/java/net/minecraftforge/artifactural/gradle/ReflectionUtils.java (limited to 'src/gradlecomp/java') diff --git a/src/gradlecomp/java/com/amadornes/artifactural/gradle/DependencyResolver.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/DependencyResolver.java deleted file mode 100644 index 9040b63..0000000 --- a/src/gradlecomp/java/com/amadornes/artifactural/gradle/DependencyResolver.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Artifactural - * Copyright (c) 2018. - * - * 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 com.amadornes.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>> 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 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 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> 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 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 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 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/com/amadornes/artifactural/gradle/GradleArtifact.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleArtifact.java deleted file mode 100644 index b1fc537..0000000 --- a/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleArtifact.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Artifactural - * Copyright (c) 2018. - * - * 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 com.amadornes.artifactural.gradle; - -import com.amadornes.artifactural.api.artifact.Artifact; -import com.amadornes.artifactural.api.artifact.ArtifactIdentifier; -import com.amadornes.artifactural.api.artifact.ArtifactType; -import com.amadornes.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 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/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java deleted file mode 100644 index 51def33..0000000 --- a/src/gradlecomp/java/com/amadornes/artifactural/gradle/GradleRepositoryAdapter.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Artifactural - * Copyright (c) 2018. - * - * 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 com.amadornes.artifactural.gradle; - -import com.amadornes.artifactural.api.artifact.Artifact; -import com.amadornes.artifactural.api.artifact.ArtifactIdentifier; -import com.amadornes.artifactural.api.artifact.MissingArtifactException; -import com.amadornes.artifactural.api.repository.Repository; -import com.amadornes.artifactural.base.artifact.SimpleArtifactIdentifier; -import com.amadornes.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( - "^(?\\S+(?:/\\S+)*)/(?\\S+)/(?\\S+)/" + - "\\2-\\3(?:-(?[^.\\s]+))?\\.(?\\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 getArtifactCache() { return resolver.getArtifactCache(); } - @Override public InstantiatingAction 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/com/amadornes/artifactural/gradle/ModifierAccess.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/ModifierAccess.java deleted file mode 100644 index 0a84755..0000000 --- a/src/gradlecomp/java/com/amadornes/artifactural/gradle/ModifierAccess.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Artifactural - * Copyright (c) 2018. - * - * 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 com.amadornes.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/com/amadornes/artifactural/gradle/ReflectionUtils.java b/src/gradlecomp/java/com/amadornes/artifactural/gradle/ReflectionUtils.java deleted file mode 100644 index 1bef580..0000000 --- a/src/gradlecomp/java/com/amadornes/artifactural/gradle/ReflectionUtils.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Artifactural - * Copyright (c) 2018. - * - * 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 com.amadornes.artifactural.gradle; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.function.UnaryOperator; - -public class ReflectionUtils { - - @SuppressWarnings("unchecked") - public static void alter(Object target, String name, UnaryOperator 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 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 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); - } - } -} 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>> 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 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 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> 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 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 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 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 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( + "^(?\\S+(?:/\\S+)*)/(?\\S+)/(?\\S+)/" + + "\\2-\\3(?:-(?[^.\\s]+))?\\.(?\\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 getArtifactCache() { return resolver.getArtifactCache(); } + @Override public InstantiatingAction 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 void alter(Object target, String name, UnaryOperator 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 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 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); + } + } +} -- cgit