blob: 0eea01e367937ff4b019c8be55fb2fd0aad1a531 [file] [log] [blame]
/*
* Copyright (C) 2013 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 com.android.tools.idea.gradle.parser;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import java.util.List;
import static com.android.tools.idea.gradle.parser.BuildFileKey.escapeLiteralString;
/**
* Represents a Maven repository where the Android plugin or library dependencies may be found.
*/
public class Repository extends BuildFileStatement {
public enum Type {
MAVEN_CENTRAL("mavenCentral"),
MAVEN_LOCAL("mavenLocal"),
JCENTER("jcenter"),
URL("maven");
private final String myCallName;
Type(String callName) {
myCallName = callName;
}
public String getCallName() {
return myCallName;
}
}
public final String myUrl;
public final Type myType;
public static BuildFileStatement parse(@NotNull String s, @NotNull Project project) {
String methodCallName = s;
if (methodCallName.endsWith("()")) {
methodCallName = methodCallName.substring(0, methodCallName.length() - 2);
}
if (methodCallName.equalsIgnoreCase(Type.MAVEN_CENTRAL.getCallName())) {
return new Repository(Type.MAVEN_CENTRAL, null);
} else if (methodCallName.equalsIgnoreCase(Type.MAVEN_LOCAL.getCallName())) {
return new Repository(Type.MAVEN_LOCAL, null);
} else if (methodCallName.equalsIgnoreCase(Type.JCENTER.getCallName())) {
return new Repository(Type.JCENTER, null);
} else if (methodCallName.equalsIgnoreCase(Type.URL.getCallName())) {
return new Repository(Type.URL, s);
} else if (s.startsWith("'") && s.endsWith("'")) {
return new Repository(Type.URL, s.substring(1, s.length() - 1));
} else if (s.indexOf('.') >= 0 && s.indexOf('{') == -1) {
return new Repository(Type.URL, s);
} else {
return new UnparseableStatement(s, project);
}
}
public Repository(@NotNull Type type, @Nullable String url) {
myType = type;
myUrl = url;
}
@NotNull
@Override
public List<PsiElement> getGroovyElements(@NotNull GroovyPsiElementFactory factory) {
String callName = myType.getCallName();
String extraGroovyCode;
switch(myType) {
case MAVEN_CENTRAL:
case MAVEN_LOCAL:
case JCENTER:
default:
extraGroovyCode = "()";
break;
case URL:
extraGroovyCode = " { url '" + escapeLiteralString(myUrl) + "' }";
break;
}
return ImmutableList.of((PsiElement)factory.createStatementFromText(callName + extraGroovyCode));
}
@Override
public String toString() {
switch (myType) {
case MAVEN_CENTRAL:
case MAVEN_LOCAL:
case JCENTER:
return myType.getCallName();
case URL:
return "'" + myUrl + "'";
}
return null;
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
Repository that = (Repository)o;
if (myType != that.myType) { return false; }
if (myUrl != null ? !myUrl.equals(that.myUrl) : that.myUrl != null) { return false; }
return true;
}
@Override
public int hashCode() {
int result = myUrl != null ? myUrl.hashCode() : 0;
result = 31 * result + (myType != null ? myType.hashCode() : 0);
return result;
}
public static Factory getFactory() {
return new Factory();
}
public static class Factory extends BuildFileStatementFactory {
@Nullable
@Override
public List<BuildFileStatement> getValues(@NotNull PsiElement statement) {
if (!(statement instanceof GrMethodCall)) {
return getUnparseableStatements(statement);
}
GrMethodCall methodCall = (GrMethodCall)statement;
List<BuildFileStatement> list = Lists.newArrayList();
String callName = GradleGroovyFile.getMethodCallName(methodCall);
if (Type.MAVEN_CENTRAL.getCallName().equals(callName)) {
list.add(new Repository(Type.MAVEN_CENTRAL, null));
} else if (Type.MAVEN_LOCAL.getCallName().equals(callName)) {
list.add(new Repository(Type.MAVEN_LOCAL, null));
} else if (Type.JCENTER.getCallName().equals(callName)) {
list.add(new Repository(Type.JCENTER, null));
} else if (Type.URL.getCallName().equals(callName)) {
// Handles repositories of the form maven('www.foo.com', 'www.fee.com')
Iterable<Object> literals = GradleGroovyFile.getLiteralArgumentValues(methodCall);
if (!Iterables.isEmpty(literals)) {
for (Object literal : literals) {
list.add(new Repository(Type.URL, literal.toString()));
}
} else {
// Handles repositories of the form:
//
// maven {
// url 'www.foo.com'
// url 'www.fee.com'
// }
GrClosableBlock cc = GradleGroovyFile.getMethodClosureArgument(methodCall);
if (cc != null) {
Iterable<GrMethodCall> methodCalls = GradleGroovyFile.getMethodCalls(cc);
Iterable<GrMethodCall> urlMethodCalls = GradleGroovyFile.getMethodCalls(cc, "url");
if (Iterables.size(methodCalls) != Iterables.size(urlMethodCalls)) {
// If there's something other than a "url" in there, that can mean something like credentials:
// maven {
// url 'www.foo.com'
// credentials {
// username 'user'
// password 'password'
// }
// }
// Just punt and treat the statement as unparseable.
return getUnparseableStatements(statement);
}
for (GrMethodCall call : methodCalls) {
Iterable<Object> values = GradleGroovyFile.getLiteralArgumentValues(call);
for (Object value : values) {
list.add(new Repository(Type.URL, value.toString()));
}
}
}
}
if (list.isEmpty()) {
return getUnparseableStatements(statement);
}
} else {
return getUnparseableStatements(statement);
}
return list;
}
@NotNull
@Override
public BuildFileStatement parse(@NotNull String s, Project project) {
return Repository.parse(s, project);
}
}
}