| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * 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 android.databinding |
| |
| import groovy.io.FileType |
| import org.apache.maven.repository.internal.MavenRepositorySystemUtils |
| import org.eclipse.aether.DefaultRepositorySystemSession |
| import org.eclipse.aether.RepositorySystem |
| import org.eclipse.aether.RepositorySystemSession |
| import org.eclipse.aether.artifact.Artifact |
| import org.eclipse.aether.artifact.DefaultArtifact |
| import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory |
| import org.eclipse.aether.graph.Dependency |
| import org.eclipse.aether.impl.DefaultServiceLocator |
| import org.eclipse.aether.repository.LocalRepository |
| import org.eclipse.aether.repository.RemoteRepository |
| import org.eclipse.aether.resolution.ArtifactDescriptorRequest |
| import org.eclipse.aether.resolution.ArtifactDescriptorResult |
| import org.eclipse.aether.resolution.ArtifactRequest |
| import org.eclipse.aether.spi.connector.RepositoryConnectorFactory |
| import org.eclipse.aether.spi.connector.transport.TransporterFactory |
| import org.eclipse.aether.transport.file.FileTransporterFactory |
| import org.eclipse.aether.transport.http.HttpTransporterFactory |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.artifacts.Configuration |
| import org.gradle.api.artifacts.ModuleVersionIdentifier |
| import org.gradle.api.tasks.TaskAction |
| |
| class LocalizeDependenciesTask extends DefaultTask { |
| |
| private Set<String> ids = new HashSet<>(); |
| |
| private Set<String> fetchTestDependencies = new HashSet<>(); |
| |
| List<Artifact> artifactsToResolve = new LinkedList<>(); |
| |
| Set<String> resolvedArtifacts = new HashSet<>(); |
| |
| Set<String> failed = new HashSet<>(); |
| |
| HashMap<String, Object> licenses = new HashMap<>(); |
| |
| Set<String> missingLicenses = new HashSet<>(); |
| |
| File localRepoDir; |
| |
| @TaskAction |
| doIt() { |
| println(ids) |
| LocalizePluginExtension extension = project.extensions. |
| getByName(MavenDependencyCollectorPlugin.EXTENSION_NAME) |
| if (extension.localRepoDir == null || extension.otherRepoDirs == null) { |
| throw new IllegalArgumentException("you must configure " + |
| "${MavenDependencyCollectorPlugin.EXTENSION_NAME} with localRepoDir and" + |
| " otherRepoDirs") |
| } |
| localRepoDir = extension.localRepoDir |
| downloadAll(extension.localRepoDir, extension.otherRepoDirs) |
| |
| if (!missingLicenses.isEmpty()) { |
| throw new RuntimeException("Missing licenses for $missingLicenses") |
| } |
| println("List of new licenses:") |
| println(ExportLicensesTask.buildNotice(licenses)) |
| } |
| |
| public void add(MavenDependencyCollectorTask task, ModuleVersionIdentifier id, Configuration conf) { |
| def key = toStringIdentifier(id) |
| ids.add(key) |
| println("adding $key in $conf by $task") |
| } |
| |
| public static String toStringIdentifier(ModuleVersionIdentifier id) { |
| return id.group + ":" + id.name + ":" + id.version; |
| } |
| |
| private static String artifactKey(Artifact artifact) { |
| return artifact.groupId + ":" + artifact.artifactId + ":" + artifact.version; |
| } |
| |
| public downloadAll(File localRepoDir, List<String> otherRepoDirs) { |
| println("downloading all dependencies to $localRepoDir") |
| def mavenCentral = new RemoteRepository.Builder("central", "default", |
| "http://central.maven.org/maven2/").build(); |
| def system = newRepositorySystem() |
| localRepoDir = localRepoDir.canonicalFile |
| List<File> otherRepos = new ArrayList<>() |
| otherRepoDirs.each { |
| def repo = new File(it).getCanonicalFile() |
| if (repo.exists() && !repo.equals(localRepoDir)) { |
| otherRepos.add(repo) |
| } |
| } |
| def session = newRepositorySystemSession(system, localRepoDir) |
| ids.each { |
| def artifact = new DefaultArtifact(it) |
| artifactsToResolve.add(artifact) |
| } |
| |
| while (!artifactsToResolve.isEmpty()) { |
| println("remaining artifacts to resolve ${artifactsToResolve.size()}") |
| Artifact artifact = artifactsToResolve.remove(0) |
| println(" handling artifact ${artifact.getArtifactId()}") |
| if (shouldSkip(artifact, otherRepos)) { |
| println("skipping $artifact") |
| continue |
| } |
| resolveArtifactWithDependencies(system, session, Arrays.asList(mavenCentral), artifact); |
| } |
| } |
| |
| public static boolean shouldSkip(Artifact artifact, List<File> otherRepos) { |
| if (artifact.groupId.startsWith('com.android.databinding') || |
| artifact.groupId.startsWith('com.android.support') || |
| artifact.groupId.equals("jdk")){ |
| return true |
| } |
| String targetPath = artifact.groupId.replaceAll("\\.", "/") + "/" + artifact.artifactId + |
| "/" + artifact.version |
| for (File repo : otherRepos) { |
| File f = new File(repo, targetPath) |
| if (f.exists()) { |
| println("skipping ${artifact} because it exists in $repo") |
| return true |
| } |
| } |
| return false |
| } |
| |
| def boolean isInGit(File file) { |
| if (!file.getCanonicalPath().startsWith(localRepoDir.getCanonicalPath())) { |
| println("$file is in another git repo, ignore for license") |
| return false |
| } |
| def gitSt = ["git", "status", "--porcelain", file.getCanonicalPath()]. |
| execute([], localRepoDir) |
| gitSt.waitFor() |
| if (gitSt.exitValue() != 0) { |
| throw new RuntimeException("unable to get git status for $file. ${gitSt.err.text}") |
| } |
| return gitSt.text.trim().isEmpty() |
| } |
| |
| public void resolveArtifactWithDependencies(RepositorySystem system, |
| RepositorySystemSession session, List<RemoteRepository> remoteRepositories, |
| Artifact artifact) { |
| def key = artifactKey(artifact) |
| if (resolvedArtifacts.contains(key) || failed.contains(key)) { |
| return |
| } |
| resolvedArtifacts.add(key) |
| ArtifactRequest artifactRequest = new ArtifactRequest(); |
| artifactRequest.setArtifact(artifact); |
| artifactRequest.setRepositories(remoteRepositories); |
| def resolved; |
| try { |
| resolved = system.resolveArtifact(session, artifactRequest); |
| } catch (Throwable ignored) { |
| println("cannot find $key, skipping") |
| failed.add(key) |
| return |
| } |
| def alreadyInGit = isInGit(resolved.artifact.file) |
| println(" |-> resolved ${resolved.artifact.file}. Already in git? $alreadyInGit") |
| |
| |
| |
| if (!alreadyInGit) { |
| def license = ExportLicensesTask.findLicenseFor(resolved.artifact.artifactId) |
| if (license == null) { |
| missingLicenses.add(artifactKey(artifact)) |
| } else { |
| licenses.put(resolved.artifact.artifactId, license) |
| } |
| } |
| |
| ArtifactDescriptorRequest descriptorRequest = new ArtifactDescriptorRequest(); |
| descriptorRequest.setArtifact(artifact); |
| descriptorRequest.setRepositories(remoteRepositories); |
| |
| ArtifactDescriptorResult descriptorResult = system. |
| readArtifactDescriptor(session, descriptorRequest); |
| for (Dependency dependency : descriptorResult.getDependencies()) { |
| println("dependency $dependency for $artifact . scope: ${dependency.scope}") |
| if ("provided".equals(dependency.scope)) { |
| println("skipping $dependency because provided") |
| continue |
| } |
| if ("optional".equals(dependency.scope)) { |
| println("skipping $dependency because optional") |
| continue |
| } |
| if ("test".equals(dependency.scope)) { |
| if (fetchTestDependencies.contains(key)) { |
| println("${dependency} is test scope but including because $key is in direct dependencies") |
| } else { |
| println("skipping $dependency because test and not first level dependency") |
| continue |
| } |
| } |
| |
| |
| def dependencyKey = artifactKey(dependency.artifact) |
| if (resolvedArtifacts.contains(dependencyKey)) { |
| println("skipping $dependency because is already resolved as ${dependencyKey}") |
| continue |
| } |
| println("adding to the list ${dependency.artifact}") |
| artifactsToResolve.add(dependency.artifact) |
| } |
| File unwanted = new File(resolved.artifact.file.getParentFile(), "_remote.repositories") |
| if (unwanted.exists()) { |
| unwanted.delete() |
| } |
| } |
| |
| public static DefaultRepositorySystemSession newRepositorySystemSession(RepositorySystem system, |
| File localRepoDir) { |
| DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); |
| LocalRepository localRepo = new LocalRepository(localRepoDir); |
| session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); |
| return session; |
| } |
| |
| public static RepositorySystem newRepositorySystem() { |
| DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); |
| locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); |
| locator.addService(TransporterFactory.class, FileTransporterFactory.class); |
| locator.addService(TransporterFactory.class, HttpTransporterFactory.class); |
| |
| return locator.getService(RepositorySystem.class); |
| } |
| } |