/* * Copyright 2016 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.ivyservice.ivyresolve.parser; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor; import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor; import org.apache.ivy.core.module.descriptor.DependencyDescriptor; import org.apache.ivy.core.module.descriptor.ExcludeRule; import org.apache.ivy.core.module.descriptor.ModuleDescriptor; import org.apache.ivy.core.module.id.ArtifactId; import org.apache.ivy.core.module.id.ModuleRevisionId; import org.gradle.api.artifacts.ModuleVersionSelector; import org.gradle.api.artifacts.component.ModuleComponentIdentifier; import org.gradle.api.internal.artifacts.DefaultModuleVersionSelector; import org.gradle.api.internal.artifacts.ImmutableModuleIdentifierFactory; import org.gradle.api.internal.artifacts.ivyservice.NamespaceId; import org.gradle.internal.Cast; import org.gradle.internal.UncheckedException; import org.gradle.internal.component.external.descriptor.Artifact; import org.gradle.internal.component.external.descriptor.Configuration; import org.gradle.internal.component.external.descriptor.DefaultExclude; import org.gradle.internal.component.external.descriptor.ModuleDescriptorState; import org.gradle.internal.component.external.descriptor.MutableModuleDescriptorState; import org.gradle.internal.component.external.model.DefaultModuleComponentIdentifier; import org.gradle.internal.component.external.model.IvyDependencyMetadata; import org.gradle.internal.component.model.DefaultIvyArtifactName; import org.gradle.internal.component.model.Exclude; import org.gradle.internal.component.model.IvyArtifactName; import java.lang.reflect.Field; import java.util.Arrays; import java.util.List; import java.util.Map; public class IvyModuleDescriptorConverter { private static final String CLASSIFIER = "classifier"; private static final Field DEPENDENCY_CONFIG_FIELD; static { try { DEPENDENCY_CONFIG_FIELD = DefaultDependencyDescriptor.class.getDeclaredField("confs"); DEPENDENCY_CONFIG_FIELD.setAccessible(true); } catch (NoSuchFieldException e) { throw UncheckedException.throwAsUncheckedException(e); } } private final ImmutableModuleIdentifierFactory moduleIdentifierFactory; public IvyModuleDescriptorConverter(ImmutableModuleIdentifierFactory moduleIdentifierFactory) { this.moduleIdentifierFactory = moduleIdentifierFactory; } public ModuleDescriptorState forIvyModuleDescriptor(ModuleDescriptor ivyDescriptor) { ModuleRevisionId moduleRevisionId = ivyDescriptor.getModuleRevisionId(); ModuleComponentIdentifier componentIdentifier = DefaultModuleComponentIdentifier.newId(moduleRevisionId.getOrganisation(), moduleRevisionId.getName(), moduleRevisionId.getRevision()); MutableModuleDescriptorState state = new MutableModuleDescriptorState(componentIdentifier, ivyDescriptor.getStatus(), ivyDescriptor.isDefault()); state.setBranch(moduleRevisionId.getBranch()); state.setDescription(ivyDescriptor.getDescription()); state.setPublicationDate(ivyDescriptor.getPublicationDate()); Map<NamespaceId, String> extraInfo = Cast.uncheckedCast(ivyDescriptor.getExtraInfo()); state.getExtraInfo().putAll(extraInfo); for (ExcludeRule excludeRule : ivyDescriptor.getAllExcludeRules()) { addExcludeRule(state, excludeRule); } return state; } public List<IvyDependencyMetadata> extractDependencies(ModuleDescriptor ivyDescriptor) { List<IvyDependencyMetadata> result = Lists.newArrayListWithCapacity(ivyDescriptor.getDependencies().length); for (DependencyDescriptor dependencyDescriptor : ivyDescriptor.getDependencies()) { addDependency(result, dependencyDescriptor); } return result; } public List<Configuration> extractConfigurations(ModuleDescriptor ivyDescriptor) { List<Configuration> result = Lists.newArrayListWithCapacity(ivyDescriptor.getConfigurations().length); for (org.apache.ivy.core.module.descriptor.Configuration ivyConfiguration : ivyDescriptor.getConfigurations()) { addConfiguration(result, ivyConfiguration); } return result; } private static void addConfiguration(List<Configuration> result, org.apache.ivy.core.module.descriptor.Configuration configuration) { String name = configuration.getName(); boolean transitive = configuration.isTransitive(); boolean visible = configuration.getVisibility() == org.apache.ivy.core.module.descriptor.Configuration.Visibility.PUBLIC; List<String> extendsFrom = Lists.newArrayList(configuration.getExtends()); result.add(new Configuration(name, transitive, visible, extendsFrom)); } private void addExcludeRule(MutableModuleDescriptorState state, ExcludeRule excludeRule) { state.addExclude(forIvyExclude(excludeRule)); } private void addDependency(List<IvyDependencyMetadata> result, DependencyDescriptor dependencyDescriptor) { ModuleRevisionId revisionId = dependencyDescriptor.getDependencyRevisionId(); ModuleVersionSelector requested = DefaultModuleVersionSelector.newSelector(revisionId.getOrganisation(), revisionId.getName(), revisionId.getRevision()); ListMultimap<String, String> configMappings = ArrayListMultimap.create(); for (Map.Entry<String, List<String>> entry : readConfigMappings(dependencyDescriptor).entrySet()) { configMappings.putAll(entry.getKey(), entry.getValue()); } List<Artifact> artifacts = Lists.newArrayList(); for (DependencyArtifactDescriptor ivyArtifact : dependencyDescriptor.getAllDependencyArtifacts()) { IvyArtifactName ivyArtifactName = new DefaultIvyArtifactName(ivyArtifact.getName(), ivyArtifact.getType(), ivyArtifact.getExt(), (String) ivyArtifact.getExtraAttributes().get(CLASSIFIER)); artifacts.add(new Artifact(ivyArtifactName, Sets.newHashSet(ivyArtifact.getConfigurations()))); } List<Exclude> excludes = Lists.newArrayList(); for (ExcludeRule excludeRule : dependencyDescriptor.getAllExcludeRules()) { excludes.add(forIvyExclude(excludeRule)); } result.add(new IvyDependencyMetadata( requested, dependencyDescriptor.getDynamicConstraintDependencyRevisionId().getRevision(), false, dependencyDescriptor.isChanging(), dependencyDescriptor.isTransitive(), configMappings, artifacts, excludes)); } private Exclude forIvyExclude(org.apache.ivy.core.module.descriptor.ExcludeRule excludeRule) { ArtifactId id = excludeRule.getId(); return new DefaultExclude( moduleIdentifierFactory.module(id.getModuleId().getOrganisation(), id.getModuleId().getName()), id.getName(), id.getType(), id.getExt(), excludeRule.getConfigurations(), excludeRule.getMatcher().getName()); } // TODO We should get rid of this reflection (will need to reimplement the parser to create a ModuleDescriptorState directly) private static Map<String, List<String>> readConfigMappings(DependencyDescriptor dependencyDescriptor) { if (dependencyDescriptor instanceof DefaultDependencyDescriptor) { try { return (Map<String, List<String>>) DEPENDENCY_CONFIG_FIELD.get(dependencyDescriptor); } catch (IllegalAccessException e) { throw UncheckedException.throwAsUncheckedException(e); } } String[] modConfs = dependencyDescriptor.getModuleConfigurations(); Map<String, List<String>> results = Maps.newLinkedHashMap(); for (String modConf : modConfs) { results.put(modConf, Arrays.asList(dependencyDescriptor.getDependencyConfigurations(modConfs))); } return results; } }