blob: a9e8d05893f81ee85d4a0b4c4fcd2d2eae58b3ba [file] [log] [blame]
/*
* 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);
}
}