/* * Copyright 2011 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.gradle.api.internal.artifacts.repositories; import groovy.lang.Closure; import org.gradle.api.Action; import org.gradle.api.ActionConfiguration; import org.gradle.api.InvalidUserDataException; import org.gradle.api.artifacts.ComponentMetadataSupplier; import org.gradle.api.artifacts.repositories.AuthenticationContainer; import org.gradle.api.artifacts.repositories.IvyArtifactRepository; import org.gradle.api.artifacts.repositories.IvyArtifactRepositoryMetaDataProvider; import org.gradle.api.artifacts.repositories.RepositoryLayout; import org.gradle.api.artifacts.repositories.RepositoryResourceAccessor; import org.gradle.api.internal.DefaultActionConfiguration; import org.gradle.api.internal.InstantiatorFactory; import org.gradle.api.internal.artifacts.ImmutableModuleIdentifierFactory; import org.gradle.api.internal.artifacts.ModuleVersionPublisher; import org.gradle.api.internal.artifacts.ivyservice.IvyContextManager; import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository; import org.gradle.api.internal.artifacts.repositories.layout.AbstractRepositoryLayout; import org.gradle.api.internal.artifacts.repositories.layout.DefaultIvyPatternRepositoryLayout; import org.gradle.api.internal.artifacts.repositories.layout.GradleRepositoryLayout; import org.gradle.api.internal.artifacts.repositories.layout.IvyRepositoryLayout; import org.gradle.api.internal.artifacts.repositories.layout.MavenRepositoryLayout; import org.gradle.api.internal.artifacts.repositories.layout.ResolvedPattern; import org.gradle.api.internal.artifacts.repositories.resolver.ExternalRepositoryResourceAccessor; import org.gradle.api.internal.artifacts.repositories.resolver.IvyResolver; import org.gradle.api.internal.artifacts.repositories.resolver.PatternBasedResolver; import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransport; import org.gradle.api.internal.artifacts.repositories.transport.RepositoryTransportFactory; import org.gradle.api.internal.file.FileResolver; import org.gradle.internal.Factory; import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier; import org.gradle.internal.component.external.model.ModuleComponentArtifactMetadata; import org.gradle.internal.reflect.Instantiator; import org.gradle.internal.resource.local.FileStore; import org.gradle.internal.resource.local.LocallyAvailableResourceFinder; import org.gradle.internal.service.DefaultServiceRegistry; import org.gradle.util.ConfigureUtil; import java.net.URI; import java.util.LinkedHashSet; import java.util.Set; public class DefaultIvyArtifactRepository extends AbstractAuthenticationSupportedRepository implements IvyArtifactRepository, ResolutionAwareRepository, PublicationAwareRepository { private final static Factory<ComponentMetadataSupplier> NO_METADATA_SUPPLIER = new Factory<ComponentMetadataSupplier>() { @Override public ComponentMetadataSupplier create() { return null; } }; private static final Object[] NO_PARAMS = new Object[0]; private Object baseUrl; private AbstractRepositoryLayout layout; private final AdditionalPatternsRepositoryLayout additionalPatternsLayout; private final FileResolver fileResolver; private final RepositoryTransportFactory transportFactory; private final LocallyAvailableResourceFinder<ModuleComponentArtifactMetadata> locallyAvailableResourceFinder; private final MetaDataProvider metaDataProvider; private final Instantiator instantiator; private final FileStore<ModuleComponentArtifactIdentifier> artifactFileStore; private final FileStore<String> externalResourcesFileStore; private final IvyContextManager ivyContextManager; private final ImmutableModuleIdentifierFactory moduleIdentifierFactory; private final InstantiatorFactory instantiatorFactory; private Class<? extends ComponentMetadataSupplier> componentMetadataSupplierClass; private Object[] componentMetadataSupplierParams; public DefaultIvyArtifactRepository(FileResolver fileResolver, RepositoryTransportFactory transportFactory, LocallyAvailableResourceFinder<ModuleComponentArtifactMetadata> locallyAvailableResourceFinder, FileStore<ModuleComponentArtifactIdentifier> artifactFileStore, FileStore<String> externalResourcesFileStore, AuthenticationContainer authenticationContainer, IvyContextManager ivyContextManager, ImmutableModuleIdentifierFactory moduleIdentifierFactory, InstantiatorFactory instantiatorFactory) { super(instantiatorFactory.decorate(), authenticationContainer); this.fileResolver = fileResolver; this.transportFactory = transportFactory; this.locallyAvailableResourceFinder = locallyAvailableResourceFinder; this.artifactFileStore = artifactFileStore; this.externalResourcesFileStore = externalResourcesFileStore; this.additionalPatternsLayout = new AdditionalPatternsRepositoryLayout(fileResolver); this.moduleIdentifierFactory = moduleIdentifierFactory; this.instantiatorFactory = instantiatorFactory; this.layout = new GradleRepositoryLayout(); this.metaDataProvider = new MetaDataProvider(); this.instantiator = instantiatorFactory.decorate(); this.ivyContextManager = ivyContextManager; } public ModuleVersionPublisher createPublisher() { return createRealResolver(); } public ConfiguredModuleComponentRepository createResolver() { return createRealResolver(); } protected IvyResolver createRealResolver() { URI uri = getUrl(); Set<String> schemes = new LinkedHashSet<String>(); layout.addSchemes(uri, schemes); additionalPatternsLayout.addSchemes(uri, schemes); IvyResolver resolver = createResolver(schemes); layout.apply(uri, resolver); additionalPatternsLayout.apply(uri, resolver); return resolver; } private IvyResolver createResolver(Set<String> schemes) { if (schemes.isEmpty()) { throw new InvalidUserDataException("You must specify a base url or at least one artifact pattern for an Ivy repository."); } return createResolver(transportFactory.createTransport(schemes, getName(), getConfiguredAuthentication())); } private IvyResolver createResolver(RepositoryTransport transport) { Instantiator instantiator = createDependencyInjectingInstantiator(transport); return new IvyResolver( getName(), transport, locallyAvailableResourceFinder, metaDataProvider.dynamicResolve, artifactFileStore, ivyContextManager, moduleIdentifierFactory, createComponentMetadataSupplierFactory(instantiator)); } /** * Creates a service registry giving access to the services we want to expose to rules and returns an instantiator that * uses this service registry. * @param transport the transport used to create the repository accessor * @return a dependency injecting instantiator, aware of services we want to expose */ private Instantiator createDependencyInjectingInstantiator(final RepositoryTransport transport) { DefaultServiceRegistry registry = new DefaultServiceRegistry(); registry.addProvider(new Object() { RepositoryResourceAccessor createResourceAccessor() { return createRepositoryAccessor(transport); } }); return instantiatorFactory.inject(registry); } private RepositoryResourceAccessor createRepositoryAccessor(RepositoryTransport transport) { return new ExternalRepositoryResourceAccessor(getUrl(), transport.getResourceAccessor(), externalResourcesFileStore); } private Factory<ComponentMetadataSupplier> createComponentMetadataSupplierFactory(final Instantiator instantiator) { if (componentMetadataSupplierClass == null) { return NO_METADATA_SUPPLIER; } return new Factory<ComponentMetadataSupplier>() { @Override public ComponentMetadataSupplier create() { return instantiator.newInstance(componentMetadataSupplierClass, componentMetadataSupplierParams); } }; } public URI getUrl() { return baseUrl == null ? null : fileResolver.resolveUri(baseUrl); } @Override public void setUrl(URI url) { baseUrl = url; } public void setUrl(Object url) { baseUrl = url; } public void artifactPattern(String pattern) { additionalPatternsLayout.artifactPatterns.add(pattern); } public void ivyPattern(String pattern) { additionalPatternsLayout.ivyPatterns.add(pattern); } public void layout(String layoutName) { if ("ivy".equals(layoutName)) { layout = instantiator.newInstance(IvyRepositoryLayout.class); } else if ("maven".equals(layoutName)) { layout = instantiator.newInstance(MavenRepositoryLayout.class); } else if ("pattern".equals(layoutName)) { layout = instantiator.newInstance(DefaultIvyPatternRepositoryLayout.class); } else { layout = instantiator.newInstance(GradleRepositoryLayout.class); } } public void layout(String layoutName, Closure config) { layout(layoutName, ConfigureUtil.<RepositoryLayout>configureUsing(config)); } public void layout(String layoutName, Action<? extends RepositoryLayout> config) { layout(layoutName); ((Action) config).execute(layout); } public IvyArtifactRepositoryMetaDataProvider getResolve() { return metaDataProvider; } public void setMetadataSupplier(Class<? extends ComponentMetadataSupplier> ruleClass) { this.componentMetadataSupplierClass = ruleClass; this.componentMetadataSupplierParams = NO_PARAMS; } @Override public void setMetadataSupplier(Class<? extends ComponentMetadataSupplier> rule, Action<? super ActionConfiguration> configureAction) { DefaultActionConfiguration configuration = new DefaultActionConfiguration(); configureAction.execute(configuration); this.componentMetadataSupplierClass = rule; this.componentMetadataSupplierParams = configuration.getParams(); } /** * Layout for applying additional patterns added via {@link #artifactPatterns} and {@link #ivyPatterns}. */ private static class AdditionalPatternsRepositoryLayout extends AbstractRepositoryLayout { private final FileResolver fileResolver; private final Set<String> artifactPatterns = new LinkedHashSet<String>(); private final Set<String> ivyPatterns = new LinkedHashSet<String>(); public AdditionalPatternsRepositoryLayout(FileResolver fileResolver) { this.fileResolver = fileResolver; } public void apply(URI baseUri, PatternBasedResolver resolver) { for (String artifactPattern : artifactPatterns) { ResolvedPattern resolvedPattern = new ResolvedPattern(artifactPattern, fileResolver); resolver.addArtifactLocation(resolvedPattern.baseUri, resolvedPattern.pattern); } Set<String> usedIvyPatterns = ivyPatterns.isEmpty() ? artifactPatterns : ivyPatterns; for (String ivyPattern : usedIvyPatterns) { ResolvedPattern resolvedPattern = new ResolvedPattern(ivyPattern, fileResolver); resolver.addDescriptorLocation(resolvedPattern.baseUri, resolvedPattern.pattern); } } @Override public void addSchemes(URI baseUri, Set<String> schemes) { for (String pattern : artifactPatterns) { schemes.add(new ResolvedPattern(pattern, fileResolver).scheme); } for (String pattern : ivyPatterns) { schemes.add(new ResolvedPattern(pattern, fileResolver).scheme); } } } private static class MetaDataProvider implements IvyArtifactRepositoryMetaDataProvider { boolean dynamicResolve; public boolean isDynamicMode() { return dynamicResolve; } public void setDynamicMode(boolean mode) { this.dynamicResolve = mode; } } }