diff options
author | Tor Norbye <tnorbye@google.com> | 2014-08-19 12:53:10 -0700 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2014-08-19 12:53:10 -0700 |
commit | 02cf98d65c798d368fcec43ed64a001d513bdd4f (patch) | |
tree | e39e210ab20917b7e5ffdce14a42f5747506eed0 /plugins | |
parent | 2e5965e996aad62ab1338b09d54caaf99ff3dd6a (diff) | |
download | idea-02cf98d65c798d368fcec43ed64a001d513bdd4f.tar.gz |
Snapshot idea/138.1503 from git://git.jetbrains.org/idea/community.git
Change-Id: Ie01af1d8710ec0ff51d90301bda1a18b0b5c0faf
Diffstat (limited to 'plugins')
325 files changed, 7239 insertions, 2582 deletions
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml index 164c690d4da3..5581810b3f2c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/META-INF/InspectionGadgets.xml @@ -1209,6 +1209,10 @@ key="field.has.setter.but.no.getter.display.name" groupBundle="messages.InspectionsBundle" groupKey="group.names.javabeans.issues" enabledByDefault="false" level="WARNING" implementationClass="com.siyeh.ig.javabeans.FieldHasSetterButNoGetterInspection"/> + <localInspection language="JAVA" shortName="PropertyValueSetToItself" bundle="com.siyeh.InspectionGadgetsBundle" + key="property.value.set.to.itself.display.name" groupBundle="messages.InspectionsBundle" + groupKey="group.names.javabeans.issues" enabledByDefault="false" level="WARNING" + implementationClass="com.siyeh.ig.javabeans.PropertyValueSetToItselfInspection"/> <!--group.names.javadoc.issues--> <localInspection language="JAVA" shortName="HtmlTagCanBeJavadocTag" bundle="com.siyeh.InspectionGadgetsBundle" diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index f92925b33bc0..715bf898c50a 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1841,8 +1841,9 @@ double.literal.may.be.float.literal.problem.descriptor=<code>#ref</code> could b double.literal.may.be.float.literal.quickfix=Replace with ''{0}'' multiple.declaration.option=Ignore 'for' loop declarations simplifiable.annotation.display.name=Simplifiable annotation -simplifiable.annotation.problem.descriptor=Annotation <code>#ref</code> can be simplified #loc -simplifiable.annotation.quickfix=Replace with ''{0}'' +simplifiable.annotation.problem.descriptor=Unnecessary <code>#ref</code> in annotation #loc +simplifiable.annotation.whitespace.problem.descriptor=Unnecessary whitespace in annotation #loc +simplifiable.annotation.quickfix=Simplify annotation overloaded.methods.with.same.number.parameters.option=<html>Ignore overloaded methods whose parameter types are definitely incompatible</html> string.concatenation.in.format.call.display.name=String concatenation as argument to 'format()' call string.concatenation.in.format.call.problem.descriptor=<code>#ref()</code> call has a String concatenation argument #loc @@ -2098,3 +2099,4 @@ assignment.to.lambda.parameter.display.name=Assignment to lambda parameter assignment.to.lambda.parameter.problem.descriptor=Assignment to lambda parameter <code>#ref</code> #loc class.with.only.private.constructors.display.name=Class with only 'private' constructors should be declared 'final' class.with.only.private.constructors.problem.descriptor=Class <code>#ref</code> with only 'private' constructors should be declared 'final' +property.value.set.to.itself.display.name=Property value set to itself diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspectionVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspectionVisitor.java index 1ba34a6235d8..d792a1ae1101 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspectionVisitor.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/BaseInspectionVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2013 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -191,8 +191,13 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor { holder.registerProblem(location, description, highlightType, fixes); } - protected final void registerErrorAtOffset(@NotNull PsiElement location, - int offset, int length, Object... infos) { + protected final void registerErrorAtOffset(@NotNull PsiElement location, int offset, int length, Object... infos) { + registerErrorAtOffset(location, offset, length, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, infos); + } + + protected final void registerErrorAtOffset(@NotNull PsiElement location, int offset, int length, + ProblemHighlightType highlightType, + Object... infos) { if (location.getTextLength() == 0 || length == 0) { return; } @@ -202,7 +207,7 @@ public abstract class BaseInspectionVisitor extends JavaElementVisitor { } final String description = inspection.buildErrorString(infos); final TextRange range = new TextRange(offset, offset + length); - holder.registerProblem(location, range, description, fixes); + holder.registerProblem(location, description, highlightType, range, fixes); } @NotNull diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java index 8db2598dc39f..7f5012f2be76 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/abstraction/DeclareCollectionAsInterfaceInspection.java @@ -284,8 +284,10 @@ public class DeclareCollectionAsInterfaceInspection extends BaseInspection { weaklingList.remove(objectClass); if (weaklingList.isEmpty()) { final String typeText = type.getCanonicalText(); - final String interfaceText = - CollectionUtils.getInterfaceForClass(typeText); + final String interfaceText = CollectionUtils.getInterfaceForClass(typeText); + if (interfaceText == null) { + return; + } registerError(nameElement, interfaceText); } else { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java index 41b391183395..17f7a83316ef 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/MismatchedArrayReadWriteInspection.java @@ -72,8 +72,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { return new MismatchedArrayReadWriteVisitor(); } - private static class MismatchedArrayReadWriteVisitor - extends BaseInspectionVisitor { + private static class MismatchedArrayReadWriteVisitor extends BaseInspectionVisitor { @Override public void visitField(@NotNull PsiField field) { @@ -88,8 +87,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { if (!checkVariable(field, containingClass)) { return; } - final boolean written = - arrayContentsAreWritten(field, containingClass); + final boolean written = arrayContentsAreWritten(field, containingClass); final boolean read = arrayContentsAreRead(field, containingClass); if (written == read) { return; @@ -98,16 +96,13 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { } @Override - public void visitLocalVariable( - @NotNull PsiLocalVariable variable) { + public void visitLocalVariable(@NotNull PsiLocalVariable variable) { super.visitLocalVariable(variable); - final PsiCodeBlock codeBlock = - PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); + final PsiCodeBlock codeBlock = PsiTreeUtil.getParentOfType(variable, PsiCodeBlock.class); if (!checkVariable(variable, codeBlock)) { return; } - final boolean written = - arrayContentsAreWritten(variable, codeBlock); + final boolean written = arrayContentsAreWritten(variable, codeBlock); final boolean read = arrayContentsAreRead(variable, codeBlock); if (written == read) { return; @@ -133,8 +128,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { if (VariableAccessUtils.variableIsReturned(variable, context)) { return false; } - return !VariableAccessUtils.variableIsUsedInArrayInitializer( - variable, context); + return !VariableAccessUtils.variableIsUsedInArrayInitializer(variable, context); } private static boolean arrayContentsAreWritten(PsiVariable variable, @@ -187,26 +181,20 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { return true; } if (initializer instanceof PsiNewExpression) { - final PsiNewExpression newExpression = - (PsiNewExpression)initializer; - final PsiArrayInitializerExpression arrayInitializer = - newExpression.getArrayInitializer(); - return arrayInitializer == null || - isDefaultArrayInitializer(arrayInitializer); + final PsiNewExpression newExpression = (PsiNewExpression)initializer; + final PsiArrayInitializerExpression arrayInitializer = newExpression.getArrayInitializer(); + return arrayInitializer == null || isDefaultArrayInitializer(arrayInitializer); } else if (initializer instanceof PsiArrayInitializerExpression) { - final PsiArrayInitializerExpression arrayInitializerExpression = - (PsiArrayInitializerExpression)initializer; - final PsiExpression[] initializers = - arrayInitializerExpression.getInitializers(); + final PsiArrayInitializerExpression arrayInitializerExpression = (PsiArrayInitializerExpression)initializer; + final PsiExpression[] initializers = arrayInitializerExpression.getInitializers(); return initializers.length == 0; } return false; } public static boolean variableIsWritten(@NotNull PsiVariable variable, @NotNull PsiElement context) { - final VariableReadWriteVisitor visitor = - new VariableReadWriteVisitor(variable, true); + final VariableReadWriteVisitor visitor = new VariableReadWriteVisitor(variable, true); context.accept(visitor); return visitor.isPassed(); } @@ -272,8 +260,7 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { final PsiExpression[] arguments = argumentList.getExpressions(); for (int i = 0; i < arguments.length; i++) { final PsiExpression argument = arguments[i]; - if (VariableAccessUtils.mayEvaluateToVariable(argument, - variable)) { + if (VariableAccessUtils.mayEvaluateToVariable(argument, variable)) { if (write && i == 0 && isCallToSystemArraycopy(call)) { return; } @@ -285,49 +272,50 @@ public class MismatchedArrayReadWriteInspection extends BaseInspection { } } - private static boolean isCallToSystemArraycopy( - PsiMethodCallExpression call) { - final PsiReferenceExpression methodExpression = - call.getMethodExpression(); - @NonNls final String name = - methodExpression.getReferenceName(); + private static boolean isCallToSystemArraycopy(PsiMethodCallExpression call) { + final PsiReferenceExpression methodExpression = call.getMethodExpression(); + @NonNls final String name = methodExpression.getReferenceName(); if (!"arraycopy".equals(name)) { return false; } - final PsiExpression qualifier = - methodExpression.getQualifierExpression(); + final PsiExpression qualifier = methodExpression.getQualifierExpression(); if (!(qualifier instanceof PsiReferenceExpression)) { return false; } - final PsiReferenceExpression referenceExpression = - (PsiReferenceExpression)qualifier; - final PsiElement element = - referenceExpression.resolve(); + final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)qualifier; + final PsiElement element = referenceExpression.resolve(); if (!(element instanceof PsiClass)) { return false; } - final PsiClass aClass = (PsiClass)element; - final String qualifiedName = - aClass.getQualifiedName(); - return "java.lang.System".equals(qualifiedName); + return "java.lang.System".equals(((PsiClass)element).getQualifiedName()); } @Override - public void visitNewExpression( - @NotNull PsiNewExpression newExpression) { + public void visitNewExpression(@NotNull PsiNewExpression newExpression) { if (passed) { return; } super.visitNewExpression(newExpression); - final PsiExpressionList argumentList = - newExpression.getArgumentList(); + visitPsiCall(newExpression); + } + + @Override + public void visitEnumConstant(PsiEnumConstant enumConstant) { + if (passed) { + return; + } + super.visitEnumConstant(enumConstant); + visitPsiCall(enumConstant); + } + + private void visitPsiCall(PsiCall newExpression) { + final PsiExpressionList argumentList = newExpression.getArgumentList(); if (argumentList == null) { return; } final PsiExpression[] arguments = argumentList.getExpressions(); for (final PsiExpression argument : arguments) { - if (VariableAccessUtils.mayEvaluateToVariable(argument, - variable)) { + if (VariableAccessUtils.mayEvaluateToVariable(argument, variable)) { passed = true; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java new file mode 100644 index 000000000000..e4ee7c5956bc --- /dev/null +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspection.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.siyeh.ig.javabeans; + +import com.intellij.psi.*; +import com.intellij.psi.util.PropertyUtil; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.psiutils.EquivalenceChecker; +import com.siyeh.ig.psiutils.ParenthesesUtils; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +/** + * @author Bas Leijdekkers + */ +public class PropertyValueSetToItselfInspection extends BaseInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message("property.value.set.to.itself.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + return InspectionGadgetsBundle.message("property.value.set.to.itself.display.name"); + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new PropertyValueSetToItselfVisitor(); + } + + private static class PropertyValueSetToItselfVisitor extends BaseInspectionVisitor { + + @Override + public void visitMethodCallExpression(PsiMethodCallExpression expression) { + super.visitMethodCallExpression(expression); + final PsiExpressionList argumentList1 = expression.getArgumentList(); + final PsiExpression[] arguments1 = argumentList1.getExpressions(); + if (arguments1.length != 1) { + return; + } + final PsiExpression argument = arguments1[0]; + if (!(argument instanceof PsiMethodCallExpression)) { + return; + } + final PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression)argument; + final PsiExpressionList argumentList2 = methodCallExpression.getArgumentList(); + final PsiExpression[] arguments2 = argumentList2.getExpressions(); + if (arguments2.length != 0) { + return; + } + final PsiReferenceExpression methodExpression1 = expression.getMethodExpression(); + final PsiExpression qualifierExpression1 = ParenthesesUtils.stripParentheses(methodExpression1.getQualifierExpression()); + final PsiReferenceExpression methodExpression2 = methodCallExpression.getMethodExpression(); + final PsiExpression qualifierExpression2 = ParenthesesUtils.stripParentheses(methodExpression2.getQualifierExpression()); + if (qualifierExpression1 instanceof PsiReferenceExpression && qualifierExpression2 instanceof PsiReferenceExpression) { + if (!EquivalenceChecker.expressionsAreEquivalent(qualifierExpression1, qualifierExpression2)) { + return; + } + } + else if((qualifierExpression1 != null && + !(qualifierExpression1 instanceof PsiThisExpression) && + !(qualifierExpression1 instanceof PsiSuperExpression)) + || + qualifierExpression2 != null && + !(qualifierExpression2 instanceof PsiThisExpression) && + !(qualifierExpression2 instanceof PsiSuperExpression)) { + return; + } + final PsiMethod method1 = expression.resolveMethod(); + final PsiField fieldOfSetter = PropertyUtil.getFieldOfSetter(method1); + if (fieldOfSetter == null) { + return; + } + final PsiMethod method2 = methodCallExpression.resolveMethod(); + final PsiField fieldOfGetter = PropertyUtil.getFieldOfGetter(method2); + if (!fieldOfSetter.equals(fieldOfGetter)) { + return; + } + registerMethodCallError(expression); + } + } +} diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java index 5b4c0c9c8305..adfff487443e 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/migration/IfCanBeSwitchInspection.java @@ -515,7 +515,10 @@ public class IfCanBeSwitchInspection extends BaseInspection { super.readSettings(node); for (Element child : node.getChildren("option")) { if (Comparing.strEqual(child.getAttributeValue("name"), ONLY_SAFE)) { - onlySuggestNullSafe = Boolean.parseBoolean(child.getAttributeValue("value")); + final String value = child.getAttributeValue("value"); + if (value != null) { + onlySuggestNullSafe = Boolean.parseBoolean(value); + } break; } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java index 375e0f6a8017..9b4a3a832913 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ImportUtils.java @@ -416,7 +416,7 @@ public class ImportUtils { final List<PsiImportStaticStatement> imports = getMatchingImports(importList, qualifiedName); final int onDemandCount = JavaCodeStyleSettingsFacade.getInstance(project).getNamesCountToUseImportOnDemand(); final PsiElementFactory elementFactory = psiFacade.getElementFactory(); - if (imports.size() < onDemandCount) { + if (imports.size() + 1 < onDemandCount) { importList.add(elementFactory.createImportStaticStatement(aClass, memberName)); } else { diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InstanceOfUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InstanceOfUtils.java index 702d84d522ac..fdbc531406de 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InstanceOfUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/InstanceOfUtils.java @@ -117,6 +117,9 @@ public class InstanceOfUtils { inElse = true; } checkExpression(operand); + if (agreeingInstanceof) { + return; + } } if (inElse && conflictingInstanceof != null) { agreeingInstanceof = false; @@ -215,6 +218,7 @@ public class InstanceOfUtils { (PsiInstanceOfExpression)expression; if (isAgreeing(instanceOfExpression)) { agreeingInstanceof = true; + conflictingInstanceof = null; } else if (isConflicting(instanceOfExpression)) { conflictingInstanceof = instanceOfExpression; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WeakestTypeFinder.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WeakestTypeFinder.java index 1440c58e5113..aade5a56361f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WeakestTypeFinder.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/WeakestTypeFinder.java @@ -132,7 +132,7 @@ public class WeakestTypeFinder { else if (referenceParent instanceof PsiVariable) { final PsiVariable variable = (PsiVariable)referenceParent; final PsiType type = variable.getType(); - if (!checkType(type, weakestTypeClasses)) { + if (!type.isAssignableFrom(variableOrMethodType) || !checkType(type, weakestTypeClasses)) { return Collections.emptyList(); } } @@ -251,7 +251,7 @@ public class WeakestTypeFinder { if (!hasUsages) { return Collections.emptyList(); } - weakestTypeClasses = filterAccessibleClasses(weakestTypeClasses, variableOrMethod); + weakestTypeClasses = filterAccessibleClasses(weakestTypeClasses, variableOrMethodClass, variableOrMethod); return weakestTypeClasses; } @@ -442,22 +442,23 @@ public class WeakestTypeFinder { } final PsiExpression lhs = assignmentExpression.getLExpression(); final PsiExpression rhs = assignmentExpression.getRExpression(); + if (rhs == null) { + return false; + } final PsiType lhsType = lhs.getType(); + final PsiType rhsType = rhs.getType(); + if (lhsType == null || rhsType == null || !lhsType.isAssignableFrom(rhsType)) { + return false; + } if (referenceElement.equals(rhs)) { if (!checkType(lhsType, weakestTypeClasses)) { return false; } } - else if (useRighthandTypeAsWeakestTypeInAssignments) { - if (rhs == null) { - return false; - } - if (!(rhs instanceof PsiNewExpression) || !(rhs instanceof PsiTypeCastExpression)) { - final PsiType rhsType = rhs.getType(); - if (lhsType == null || lhsType.equals(rhsType)) { - return false; - } - } + else if (useRighthandTypeAsWeakestTypeInAssignments && + (!(rhs instanceof PsiNewExpression) || !(rhs instanceof PsiTypeCastExpression)) && + lhsType.equals(rhsType)) { + return false; } return true; } @@ -546,14 +547,14 @@ public class WeakestTypeFinder { return true; } - public static Set<PsiClass> filterAccessibleClasses(Set<PsiClass> weakestTypeClasses, PsiElement context) { + public static Set<PsiClass> filterAccessibleClasses(Set<PsiClass> weakestTypeClasses, PsiClass upperBound, PsiElement context) { final Set<PsiClass> result = new HashSet<PsiClass>(); for (PsiClass weakestTypeClass : weakestTypeClasses) { - if (PsiUtil.isAccessible(weakestTypeClass, context, null)) { + if (PsiUtil.isAccessible(weakestTypeClass, context, null) && !weakestTypeClass.isDeprecated()) { result.add(weakestTypeClass); continue; } - final PsiClass visibleInheritor = getVisibleInheritor(weakestTypeClass, context); + final PsiClass visibleInheritor = getVisibleInheritor(weakestTypeClass, upperBound, context); if (visibleInheritor != null) { result.add(visibleInheritor); } @@ -562,16 +563,16 @@ public class WeakestTypeFinder { } @Nullable - private static PsiClass getVisibleInheritor(@NotNull PsiClass superClass, PsiElement context) { + private static PsiClass getVisibleInheritor(@NotNull PsiClass superClass, PsiClass upperBound, PsiElement context) { final Query<PsiClass> search = DirectClassInheritorsSearch.search(superClass, context.getResolveScope()); final Project project = superClass.getProject(); for (PsiClass aClass : search) { - if (superClass.isInheritor(aClass, true)) { + if (aClass.isInheritor(superClass, true) && upperBound.isInheritor(aClass, true)) { if (PsiUtil.isAccessible(project, aClass, context, null)) { return aClass; } else { - return getVisibleInheritor(aClass, context); + return getVisibleInheritor(aClass, upperBound, context); } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java index 794716ba0412..e45f06cac284 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/SimplifiableAnnotationInspection.java @@ -16,9 +16,10 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtilCore; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.IncorrectOperationException; @@ -46,30 +47,30 @@ public class SimplifiableAnnotationInspection extends BaseInspection { @NotNull @Override protected String buildErrorString(Object... infos) { - return InspectionGadgetsBundle.message("simplifiable.annotation.problem.descriptor"); + if (((Boolean)infos[0]).booleanValue()) { + return InspectionGadgetsBundle.message("simplifiable.annotation.whitespace.problem.descriptor"); + } + else { + return InspectionGadgetsBundle.message("simplifiable.annotation.problem.descriptor"); + } } @Override protected InspectionGadgetsFix buildFix(Object... infos) { - final PsiAnnotation annotation = (PsiAnnotation)infos[0]; - return new SimplifiableAnnotationFix(annotation); + return new SimplifiableAnnotationFix(); } private static class SimplifiableAnnotationFix extends InspectionGadgetsFix { - private final String replacement; - - public SimplifiableAnnotationFix(PsiAnnotation annotation) { - this.replacement = buildAnnotationText(annotation, new StringBuilder()).toString(); - } + public SimplifiableAnnotationFix() {} @Override @NotNull public String getName() { - return InspectionGadgetsBundle.message("simplifiable.annotation.quickfix", - StringUtil.shortenTextWithEllipsis(replacement, 50, 0, true)); + return InspectionGadgetsBundle.message("simplifiable.annotation.quickfix"); } - @Override + + @Override @NotNull public String getFamilyName() { return getName(); @@ -78,23 +79,25 @@ public class SimplifiableAnnotationInspection extends BaseInspection { @Override protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { final PsiElement element = descriptor.getPsiElement(); - if (!(element instanceof PsiAnnotation)) { + final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(element, PsiAnnotation.class); + if (annotation == null) { return; } final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiAnnotation annotation = factory.createAnnotationFromText(replacement, element); - element.replace(annotation); + final String annotationText = buildAnnotationText(annotation); + final PsiAnnotation newAnnotation = factory.createAnnotationFromText(annotationText, element); + annotation.replace(newAnnotation); } - private static StringBuilder buildAnnotationText(PsiAnnotation annotation, StringBuilder out) { - out.append('@'); + private static String buildAnnotationText(PsiAnnotation annotation) { + final StringBuilder out = new StringBuilder("@"); final PsiJavaCodeReferenceElement nameReferenceElement = annotation.getNameReferenceElement(); assert nameReferenceElement != null; out.append(nameReferenceElement.getText()); final PsiAnnotationParameterList parameterList = annotation.getParameterList(); final PsiNameValuePair[] attributes = parameterList.getAttributes(); if (attributes.length == 0) { - return out; + return out.toString(); } out.append('('); if (attributes.length == 1) { @@ -116,7 +119,7 @@ public class SimplifiableAnnotationInspection extends BaseInspection { } } out.append(')'); - return out; + return out.toString(); } private static StringBuilder buildAttributeValueText(PsiAnnotationMemberValue value, StringBuilder out) { @@ -128,7 +131,7 @@ public class SimplifiableAnnotationInspection extends BaseInspection { } } else if (value instanceof PsiAnnotation) { - return buildAnnotationText((PsiAnnotation)value, out); + return out.append(buildAnnotationText((PsiAnnotation)value)); } return out.append(value.getText()); } @@ -151,36 +154,36 @@ public class SimplifiableAnnotationInspection extends BaseInspection { } final PsiNameValuePair[] attributes = parameterList.getAttributes(); final PsiElement[] annotationChildren = annotation.getChildren(); - if (annotationChildren.length >= 2 && annotationChildren[1] instanceof PsiWhiteSpace) { - if (!containsError(annotation)) { - registerError(annotation, annotation); - } + if (annotationChildren.length >= 2 && annotationChildren[1] instanceof PsiWhiteSpace && !containsError(annotation)) { + registerError(annotationChildren[1], Boolean.TRUE); } - else if (attributes.length == 0) { - final PsiElement[] children = parameterList.getChildren(); - if (children.length <= 0) { - return; - } - if (!containsError(annotation)) { - registerError(annotation, annotation); + if (attributes.length == 0) { + if (parameterList.getChildren().length > 0 && !containsError(annotation)) { + registerError(parameterList, ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } } else if (attributes.length == 1) { final PsiNameValuePair attribute = attributes[0]; - @NonNls final String name = attribute.getName(); + final PsiIdentifier identifier = attribute.getNameIdentifier(); final PsiAnnotationMemberValue attributeValue = attribute.getValue(); - if (!PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(name)) { - if (!(attributeValue instanceof PsiArrayInitializerMemberValue)) { - return; - } - final PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue)attributeValue; - final PsiAnnotationMemberValue[] initializers = arrayValue.getInitializers(); - if (initializers.length != 1) { - return; + if (identifier != null && attributeValue != null) { + @NonNls final String name = attribute.getName(); + if (PsiAnnotation.DEFAULT_REFERENCED_METHOD_NAME.equals(name) && !containsError(annotation)) { + registerErrorAtOffset(attribute, 0, attributeValue.getStartOffsetInParent(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, + Boolean.FALSE); } } + if (!(attributeValue instanceof PsiArrayInitializerMemberValue)) { + return; + } + final PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue)attributeValue; + final PsiAnnotationMemberValue[] initializers = arrayValue.getInitializers(); + if (initializers.length != 1) { + return; + } if (!containsError(annotation)) { - registerError(annotation, annotation); + registerError(arrayValue.getFirstChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); + registerError(arrayValue.getLastChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } } else if (attributes.length > 1) { @@ -189,15 +192,15 @@ public class SimplifiableAnnotationInspection extends BaseInspection { if (!(value instanceof PsiArrayInitializerMemberValue)) { continue; } - final PsiArrayInitializerMemberValue arrayInitializerMemberValue = (PsiArrayInitializerMemberValue)value; - final PsiAnnotationMemberValue[] initializers = arrayInitializerMemberValue.getInitializers(); + final PsiArrayInitializerMemberValue arrayValue = (PsiArrayInitializerMemberValue)value; + final PsiAnnotationMemberValue[] initializers = arrayValue.getInitializers(); if (initializers.length != 1) { continue; } if (!containsError(annotation)) { - registerError(annotation, annotation); + registerError(arrayValue.getFirstChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); + registerError(arrayValue.getLastChild(), ProblemHighlightType.LIKE_UNUSED_SYMBOL, Boolean.FALSE); } - return; } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java index 4747e7426fd7..70b620f9434c 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/StringBufferReplaceableByStringInspection.java @@ -20,7 +20,6 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import com.siyeh.InspectionGadgetsBundle; import com.siyeh.ig.BaseInspection; @@ -86,7 +85,7 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { } @Override - protected void doFix(Project project, ProblemDescriptor descriptor) throws IncorrectOperationException { + protected void doFix(Project project, ProblemDescriptor descriptor) { final PsiElement element = descriptor.getPsiElement(); final PsiElement parent = element.getParent(); if (!(parent instanceof PsiVariable)) { @@ -290,6 +289,9 @@ public class StringBufferReplaceableByStringInspection extends BaseInspection { methodCallExpression = (PsiMethodCallExpression)grandParent; parent = methodCallExpression.getParent(); grandParent = parent.getParent(); + if ("toString".equals(methodCallExpression.getMethodExpression().getReferenceName())) { + break; + } } if (buildStringExpression(methodCallExpression, myBuilder) == null) { myProblem = true; diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryEnumModifierInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryEnumModifierInspection.java index 2aa72fae7bbe..7d8d9558ef53 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryEnumModifierInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryEnumModifierInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.CleanupLocalInspectionTool; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.util.IncorrectOperationException; @@ -112,7 +113,7 @@ public class UnnecessaryEnumModifierInspection extends BaseInspection implements for (final PsiElement child : children) { final String text = child.getText(); if (PsiModifier.STATIC.equals(text)) { - registerError(child, child, aClass); + registerError(child, ProblemHighlightType.LIKE_UNUSED_SYMBOL, child, aClass); } } } @@ -131,7 +132,7 @@ public class UnnecessaryEnumModifierInspection extends BaseInspection implements for (final PsiElement child : children) { final String text = child.getText(); if (PsiModifier.PRIVATE.equals(text)) { - registerError(child, child, method); + registerError(child, ProblemHighlightType.LIKE_UNUSED_SYMBOL, child, method); } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryInterfaceModifierInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryInterfaceModifierInspection.java index 310cc20c30b6..a0718c07fa8f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryInterfaceModifierInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessaryInterfaceModifierInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2012 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.CleanupLocalInspectionTool; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; @@ -214,7 +215,7 @@ public class UnnecessaryInterfaceModifierInspection extends BaseInspection imple } for (PsiElement child : children) { if (modifiers.contains(child.getText())) { - registerError(child, redundantModifiers.toString(), list); + registerError(child, ProblemHighlightType.LIKE_UNUSED_SYMBOL, redundantModifiers.toString(), list); } } } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java index c1a75887c6aa..36f5af9408df 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/style/UnnecessarySemicolonInspection.java @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009 Dave Griffith, Bas Leijdekkers + * Copyright 2003-2014 Dave Griffith, Bas Leijdekkers * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package com.siyeh.ig.style; import com.intellij.codeInspection.CleanupLocalInspectionTool; import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.codeInspection.ProblemHighlightType; import com.intellij.openapi.project.Project; import com.intellij.psi.*; import com.intellij.psi.tree.IElementType; @@ -111,7 +112,7 @@ public class UnnecessarySemicolonInspection extends BaseInspection implements Cl private void findTopLevelSemicolons(PsiElement element) { for (PsiElement sibling = element.getFirstChild(); sibling != null; sibling = skipForwardWhiteSpacesAndComments(sibling)) { if (PsiUtil.isJavaToken(sibling, JavaTokenType.SEMICOLON)) { - registerError(sibling); + registerError(sibling, ProblemHighlightType.LIKE_UNUSED_SYMBOL); } } } @@ -149,7 +150,7 @@ public class UnnecessarySemicolonInspection extends BaseInspection implements Cl if (next == null || !next.equals(aClass.getRBrace())) { return; } - registerError(element); + registerError(element, ProblemHighlightType.LIKE_UNUSED_SYMBOL); } private void findUnnecessarySemicolonsAfterEnumConstants( @@ -171,11 +172,11 @@ public class UnnecessarySemicolonInspection extends BaseInspection implements Cl if (!JavaTokenType.COMMA.equals(prevTokenType) && !JavaTokenType.LBRACE.equals( prevTokenType)) { - registerError(child); + registerError(child, ProblemHighlightType.LIKE_UNUSED_SYMBOL); } } else { - registerError(child); + registerError(child, ProblemHighlightType.LIKE_UNUSED_SYMBOL); } } } @@ -207,7 +208,7 @@ public class UnnecessarySemicolonInspection extends BaseInspection implements Cl if (semicolon == null) { return; } - registerError(semicolon); + registerError(semicolon, ProblemHighlightType.LIKE_UNUSED_SYMBOL); } } @@ -218,7 +219,7 @@ public class UnnecessarySemicolonInspection extends BaseInspection implements Cl if (last instanceof PsiJavaToken && ((PsiJavaToken)last).getTokenType() == JavaTokenType.RPARENTH) { final PsiElement prev = skipBackwardWhiteSpacesAndComments(last); if (prev instanceof PsiJavaToken && ((PsiJavaToken)prev).getTokenType() == JavaTokenType.SEMICOLON) { - registerError(prev); + registerError(prev, ProblemHighlightType.LIKE_UNUSED_SYMBOL); } } } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/HighlightUtils.java b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/HighlightUtils.java index 1894986e9a5b..6444ff8b0660 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/HighlightUtils.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/psiutils/HighlightUtils.java @@ -34,6 +34,7 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme; import com.intellij.openapi.editor.markup.TextAttributes; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.WindowManager; @@ -41,6 +42,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiNameIdentifierOwner; import com.intellij.psi.PsiReference; import com.intellij.psi.util.PsiUtilCore; +import com.intellij.util.containers.ContainerUtil; import com.siyeh.InspectionGadgetsBundle; import org.jetbrains.annotations.NotNull; @@ -68,7 +70,12 @@ public class HighlightUtils { final PsiElement[] elements = PsiUtilCore.toPsiElementArray(elementCollection); final PsiElement firstElement = elements[0]; - if (!firstElement.isValid()) { + if (ContainerUtil.exists(elements, new Condition<PsiElement>() { + @Override + public boolean value(PsiElement element) { + return !element.isValid(); + } + })) { return; } final Project project = firstElement.getProject(); diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TextField.java b/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TextField.java index 47344f5cc861..28c947e24ac0 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TextField.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/ui/TextField.java @@ -16,13 +16,13 @@ package com.siyeh.ig.ui; import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.util.ReflectionUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; -import java.lang.reflect.Field; public class TextField extends JTextField { @@ -36,35 +36,13 @@ public class TextField extends JTextField { private static String getPropertyValue(InspectionProfileEntry owner, String property) { - try { - final Class<? extends InspectionProfileEntry> aClass = - owner.getClass(); - final Field field = aClass.getField(property); - return (String)field.get(owner); - } - catch (IllegalAccessException ignore) { - return null; - } - catch (NoSuchFieldException ignore) { - return null; - } + return ReflectionUtil.getField(owner.getClass(), owner, String.class, property); } private static void setPropertyValue(InspectionProfileEntry owner, String property, String value) { - try { - final Class<? extends InspectionProfileEntry> aClass = - owner.getClass(); - final Field field = aClass.getField(property); - field.set(owner, value); - } - catch (IllegalAccessException ignore) { - // do nothing - } - catch (NoSuchFieldException ignore) { - // do nothing - } + ReflectionUtil.setField(owner.getClass(), owner, String.class, property, value); } private class TextFieldDocumentListener implements DocumentListener { diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html b/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html index b22ad3712458..b0f698b74e7e 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/AmbiguousFieldAccess.html @@ -12,8 +12,8 @@ accessed, when in fact a field from the super class is accessed. To make the int <b>class</b> Y { <b>void</b> foo(String s) { <b>new</b> X() {{ - System.out.println(s); // problem indicated here - }} + System.out.println(s); // here the field is accessed not the parameter + }}; } } </code></pre> diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html new file mode 100644 index 000000000000..c72e160a9b8c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PropertyValueSetToItself.html @@ -0,0 +1,10 @@ +<html> +<body> +Reports calls on a setter with the value of same objects getter. +For example: <code>bean.setPayerId(bean.getPayerId());</code> +In regular circumstances this code is a no-op and probably not what was intented.. +<!-- tooltip end --> +<p> + <small>New in 14</small> +</body> +</html>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html index 70255c1e9440..c36afbcd8886 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/ReturnNull.html @@ -3,14 +3,14 @@ Reports return statements with <b>null</b> values. While occasionally useful, this construct may make the code more prone to failing with a <b>NullPointerException</b>, and often indicates that the -developer doesn't really understand the classes intended semantics. +developer doesn't really understand the class's intended semantics. <!-- tooltip end --> <p> -Use the first control below to let this inspection ignore private methods. +Use the first checkbox below to let this inspection ignore private methods. <p> -Use bottom three controls to specify whether this inspection should report +Use the bottom three checkboxes to specify whether <b>null</b> values on array returns, collection -object returns, plain object returns, or a combination of the three. +object returns, plain object returns, or a combination of the three should be reported. <p> </body> diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/MethodCallOnString.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/MethodCallOnString.after.java new file mode 100644 index 000000000000..4ced8b802fc5 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/MethodCallOnString.after.java @@ -0,0 +1,5 @@ +public class MethodCallOnString { + public static void main(String... args) { + int length = "ABC".length(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/MethodCallOnString.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/MethodCallOnString.java new file mode 100644 index 000000000000..2ff02036eced --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/style/replace_with_string/MethodCallOnString.java @@ -0,0 +1,6 @@ +public class MethodCallOnString { + public static void main(String... args) { + StringBuilder theBuilder<caret> = new StringBuilder("ABC"); + int length = theBuilder.toString().length(); + } +}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/declare_collection_as_interface/DeclareCollectionAsInterface.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/declare_collection_as_interface/DeclareCollectionAsInterface.java index e5c11992d86c..f21cc080de25 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/declare_collection_as_interface/DeclareCollectionAsInterface.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/declare_collection_as_interface/DeclareCollectionAsInterface.java @@ -60,4 +60,14 @@ public class DeclareCollectionAsInterface <warning descr="Declaration of 'HashSet' should probably be weakened to 'java.util.Set'">HashSet</warning><String> set = new HashSet<>(); set.add("foo"); } + + public static Properties stringToProperties(String propertiesAsString) { return null; } + public static Properties stringToProperties2(String propertiesAsString) { return null; } + public static Properties stringToProperties3(String propertiesAsString) { return null; } + + void m() { + stringToProperties(""); + <error descr="Incompatible types. Found: 'java.util.Properties', required: 'java.lang.String'">String s = stringToProperties2("");</error> + <error descr="Incompatible types. Found: 'java.util.Properties', required: 'java.lang.String'">s = stringToProperties3("")</error>; + } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/AutoClosableTest.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/AutoClosableTest.java index 3d9b0a2fd811..7c96abd2260c 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/AutoClosableTest.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/AutoClosableTest.java @@ -31,13 +31,13 @@ class AutoClosableTest2 public static class Bar extends Foo {} public static void test() { - try (Bar bar = new Bar()) { + try (Bar <warning descr="Type of variable 'bar' may be weakened to 'com.siyeh.igtest.abstraction.weaken_type.AutoClosableTest2.Foo'">bar</warning> = new Bar()) { bar.go(); } } void dodo() throws java.io.IOException { - try (java.io.Reader reader = new java.io.FileReader("/home/steve/foo.txt")) { + try (java.io.Reader <warning descr="Type of variable 'reader' may be weakened to 'java.io.Closeable'">reader</warning> = new java.io.FileReader("/home/steve/foo.txt")) { System.out.println(reader); } } diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/NumberAdderDemo.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/NumberAdderDemo.java index 0a009777a810..4b3547198e83 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/NumberAdderDemo.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/NumberAdderDemo.java @@ -1,6 +1,6 @@ -package com.siyeh.igtest.abstraction.weaken_type; +package weaken_type; -import com.siyeh.igtest.abstraction.weaken_type.sub.NumberAdderExtension; +import weaken_type.sub.NumberAdderExtension; public class NumberAdderDemo { diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java index aeb2e1a5f811..370aba53a19c 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/TypeMayBeWeakened.java @@ -52,7 +52,7 @@ public class TypeMayBeWeakened { foo(new WeakBoolean()); } - void foo(WeakBoolean b) { + void foo(WeakBoolean <warning descr="Type of parameter 'b' may be weakened to 'java.lang.Object'">b</warning>) { System.out.println("b: " + b); } @@ -65,7 +65,7 @@ public class TypeMayBeWeakened { FileInputStream fis=new FileInputStream("/etc/modules"); } catch(FileNotFoundException fnfex) { - IllegalArgumentException iaex=new IllegalArgumentException("Exception Message"); + IllegalArgumentException <warning descr="Type of variable 'iaex' may be weakened to 'java.lang.RuntimeException'">iaex</warning>=new IllegalArgumentException("Exception Message"); iaex.initCause(fnfex); throw iaex; } @@ -82,7 +82,7 @@ public class TypeMayBeWeakened { void foo() { Test f = new Test(); f.x++; } } - void listy(ArrayList list) { + void listy(ArrayList <warning descr="Type of parameter 'list' may be weakened to 'java.lang.Iterable'">list</warning>) { for (Object o : list) { } @@ -130,7 +130,7 @@ class MyClass { public MyClass(java.util.Date date, String[] classNames) {} - static MyClass readMyClass(final ObjectInputStream objectInput) { + static MyClass readMyClass(final ObjectInputStream <warning descr="Type of parameter 'objectInput' may be weakened to 'com.siyeh.igtest.abstraction.weaken_type.DataInput'">objectInput</warning>) { final long time = objectInput.readLong(); final int size = objectInput.readInt(); final String[] classNames = new String[size]; @@ -150,4 +150,16 @@ abstract class ObjectInputStream implements DataInput { public String readUTF() { return null; } -}
\ No newline at end of file +} +class Test implements Foo2 { + void test(Test <warning descr="Type of parameter 't' may be weakened to 'com.siyeh.igtest.abstraction.weaken_type.Foo2'">t</warning>) { + t.bar(); + } + public void bar() { + } +} +@Deprecated +interface Foo { + void bar(); +} +interface Foo2 extends Foo {}
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdder.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdder.java deleted file mode 100644 index 8f15c784c12a..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdder.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.siyeh.igtest.abstraction.weaken_type.sub; - -/** - * Created by IntelliJ IDEA. User: HONOURK Date: 21-Aug-2008 Time: 12:15:41 To change this template - * use File | Settings | File Templates. - */ -public interface NumberAdder { - int doSomething(); -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdderExtension.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdderExtension.java deleted file mode 100644 index 21bdf2988a11..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdderExtension.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.siyeh.igtest.abstraction.weaken_type.sub; - -/** - * Created by IntelliJ IDEA. User: HONOURK Date: 21-Aug-2008 Time: 12:15:41 To change this template - * use File | Settings | File Templates. - */ -public class NumberAdderExtension extends NumberAdderImpl { - @Override - public int getNumberOne() { - return super.getNumberOne(); - } -} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdderImpl.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdderImpl.java deleted file mode 100644 index 669373d0342f..000000000000 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type/sub/NumberAdderImpl.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.siyeh.igtest.abstraction.weaken_type.sub; - -public class NumberAdderImpl implements NumberAdder { - - public int doSomething() { - return getNumberOne() + 1; - } - - protected int getNumberOne() { - return 1; - } -} - diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/castConflictingInstanceof/orInstanceofOrInstanceof/OrInstanceofOrInstanceof.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/castConflictingInstanceof/orInstanceofOrInstanceof/OrInstanceofOrInstanceof.java new file mode 100644 index 000000000000..228fe5c10117 --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/castConflictingInstanceof/orInstanceofOrInstanceof/OrInstanceofOrInstanceof.java @@ -0,0 +1,30 @@ +package com.siyeh.igtest.bugs.castConflictingInstanceof.andAnd; + +class Test { + + public void test(Object o) + { + + if (!(o instanceof Number) || + ((Number)o).intValue() == 0 || + !(o instanceof Integer) || + ((Integer) o).byteValue() == 9) { + System.out.println(); + } + + if (!(o instanceof Number) || + ((Number)o).intValue() == 0 || + !(o instanceof Integer) || + !(o instanceof Number) || + ((Integer) o).byteValue() == 9) { + System.out.println(); + } + + if (!(o instanceof Integer) || + ((Number)o).intValue() == 0 || + !(o instanceof Number) || + ((Integer) o).byteValue() == 9) { + System.out.println(); + } + } +} diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/castConflictingInstanceof/orInstanceofOrInstanceof/expected.xml b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/castConflictingInstanceof/orInstanceofOrInstanceof/expected.xml new file mode 100644 index 000000000000..e8f00e82629f --- /dev/null +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/castConflictingInstanceof/orInstanceofOrInstanceof/expected.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<problems> + +</problems>
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java index beed034bc1ba..33683aaa4d1f 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/bugs/mismatched_array_read_write/MismatchedArrayReadWrite.java @@ -183,4 +183,17 @@ class Ferrari458Spider implements java.io.Serializable { private static final java.io.ObjectStreamField[] serialPersistentFields = { new java.io.ObjectStreamField("b", String.class) }; +} + +class TestIDEA128098 { + private static final String[] CONSTANT_ARRAY = new String[]{""}; // warning is on this constant + + + enum SomeEnum { + ITEM( CONSTANT_ARRAY); + private final String[] myPatterns; + SomeEnum(String... patterns) { + myPatterns = patterns; + } + } }
\ No newline at end of file diff --git a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java index b40289507a08..1fe15e0f3eeb 100644 --- a/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java +++ b/plugins/InspectionGadgets/test/com/siyeh/igtest/style/simplifiable_annotation/SimplifiableAnnotation.java @@ -2,8 +2,8 @@ package com.siyeh.igtest.style.simplifiable_annotation; public class SimplifiableAnnotation { - <warning descr="Annotation '@ SuppressWarnings(value = \\"blabla\\")' can be simplified">@ SuppressWarnings(value = "blabla")</warning> - <warning descr="Annotation '@ Deprecated()' can be simplified">@ Deprecated()</warning> + @<warning descr="Unnecessary whitespace in annotation"> </warning>SuppressWarnings(<warning descr="Unnecessary 'value =' in annotation">value = </warning>"blabla") + @<warning descr="Unnecessary whitespace in annotation"> </warning>Deprecated<warning descr="Unnecessary '()' in annotation">()</warning> Object foo() { return null; } @@ -14,8 +14,8 @@ public class SimplifiableAnnotation { @interface ArrayAnnotation { String[] array(); } -<warning descr="Annotation '@ValueAnnotation({\\"the value\\"})' can be simplified">@ValueAnnotation({"the value"})</warning> -<warning descr="Annotation '@ArrayAnnotation(array = {\\"first\\"})' can be simplified">@ArrayAnnotation(array = {"first"})</warning> +@ValueAnnotation(<warning descr="Unnecessary '{' in annotation">{</warning>"the value"<warning descr="Unnecessary '}' in annotation">}</warning>) +@ArrayAnnotation(array = <warning descr="Unnecessary '{' in annotation">{</warning>"first"<warning descr="Unnecessary '}' in annotation">}</warning>) class MyClass { @ <error descr="'value' missing though required">ValueAnnotation</error> @@ -23,7 +23,7 @@ class MyClass { return -1; } - <warning descr="Annotation '@Two(i={1}, j = 2)' can be simplified">@Two(i={1}, j = 2)</warning> + @Two(i=<warning descr="Unnecessary '{' in annotation">{</warning>1<warning descr="Unnecessary '}' in annotation">}</warning>, j = 2) String s; } @interface Two { diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspectionTest.java index fec91135e731..df0048a5218f 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/abstraction/TypeMayBeWeakenedInspectionTest.java @@ -1,24 +1,48 @@ package com.siyeh.ig.abstraction; -import com.intellij.openapi.roots.LanguageLevelProjectExtension; -import com.intellij.pom.java.LanguageLevel; -import com.siyeh.ig.IGInspectionTestCase; +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; -public class TypeMayBeWeakenedInspectionTest extends IGInspectionTestCase { +public class TypeMayBeWeakenedInspectionTest extends LightInspectionTestCase { - public void test() throws Exception { - final TypeMayBeWeakenedInspection inspection = - new TypeMayBeWeakenedInspection(); + public void testTypeMayBeWeakened() { doTest(); } + public void testNumberAdderDemo() { doTest(); } + public void testAutoClosableTest() { doTest(); } + + @Override + protected String[] getEnvironmentClasses() { + return new String[] { + "package weaken_type.sub;\n" + + "public class NumberAdderImpl implements NumberAdder {\n" + + " public int doSomething() {\n" + + " return getNumberOne() + 1;\n" + + " }\n" + + " protected int getNumberOne() {\n" + + " return 1;\n" + + " }\n" + + "}", + "package weaken_type.sub;\n" + + "public class NumberAdderExtension extends NumberAdderImpl {\n" + + " @Override\n" + + " public int getNumberOne() {\n" + + " return super.getNumberOne();\n" + + " }\n" + + "}" + }; + } + + @Override + protected String getBasePath() { + return "/plugins/InspectionGadgets/test/com/siyeh/igtest/abstraction/weaken_type"; + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + final TypeMayBeWeakenedInspection inspection = new TypeMayBeWeakenedInspection(); inspection.doNotWeakenToJavaLangObject = false; inspection.onlyWeakentoInterface = false; - final LanguageLevelProjectExtension levelProjectExtension = LanguageLevelProjectExtension.getInstance(getProject()); - final LanguageLevel level = levelProjectExtension.getLanguageLevel(); - try { - levelProjectExtension.setLanguageLevel(LanguageLevel.JDK_1_7); - doTest("com/siyeh/igtest/abstraction/weaken_type", inspection); - } - finally { - levelProjectExtension.setLanguageLevel(level); - } + return inspection; } }
\ No newline at end of file diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CastConflictsWithInstanceofInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CastConflictsWithInstanceofInspectionTest.java index ff6d488a6fd9..079bda6ac35f 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CastConflictsWithInstanceofInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/CastConflictsWithInstanceofInspectionTest.java @@ -43,6 +43,10 @@ public class CastConflictsWithInstanceofInspectionTest extends IGInspectionTestC doTest(); } + public void testOrInstanceofOrInstanceof() throws Exception { + doTest(); + } + private void doTest() throws Exception { doTest("com/siyeh/igtest/bugs/castConflictingInstanceof/" + getTestName(true), new CastConflictsWithInstanceofInspection()); } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableByStringFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableByStringFixTest.java index f49e16b89c4a..8c7920b9567d 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableByStringFixTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/style/StringBufferReplaceableByStringFixTest.java @@ -32,4 +32,5 @@ public class StringBufferReplaceableByStringFixTest extends IGQuickFixesTestCase public void testCharLiteral() { doTest(InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } public void testEscape() { doTest(InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } public void testUnescape() { doTest(InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } + public void testMethodCallOnString() { doTest(InspectionGadgetsBundle.message("string.builder.replaceable.by.string.quickfix")); } } diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionTest.java index 99c6a2480928..a2b334c2661c 100644 --- a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionTest.java +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/inheritance/ExtendsConcreteCollectionInspectionTest.java @@ -31,7 +31,7 @@ public class ExtendsConcreteCollectionInspectionTest extends LightInspectionTest protected String[] getEnvironmentClasses() { return new String[] { "package java.util;" + - "public class LinkedHashMap<K, V> {" + + "public class LinkedHashMap<K, V> extends HashMap<K,V> implements Map<K,V>{" + " protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {\n" + " return false;\n" + " }" + diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspectionTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspectionTest.java new file mode 100644 index 000000000000..d17387119ae1 --- /dev/null +++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/javabeans/PropertyValueSetToItselfInspectionTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.siyeh.ig.javabeans; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.siyeh.ig.LightInspectionTestCase; +import org.jetbrains.annotations.Nullable; + +public class PropertyValueSetToItselfInspectionTest extends LightInspectionTestCase { + + public void testSimple() { + doTest("class Bean {\n" + + " private String x;\n" + + " public void setX(String x) {\n" + + " this.x = x;\n" + + " }\n" + + " public String getX() { return x; }\n" + + " void m(Bean b) {\n" + + " (b)./*Property value set to itself*/setX/**/(b.getX());\n" + + " this./*Property value set to itself*/setX/**/(getX());\n" + + " }\n" + + "}"); + } + + public void testNoWarn() { + doTest("class Bean {\n" + + " private String x;\n" + + " public void setX(String x) {\n" + + " this.x = x;\n" + + " }\n" + + " public String getX() { return x; }\n" + + " void m(Bean b, Bean c) {\n" + + " (b).setX(c.getX());\n" + + " }\n" + + "}"); + } + + @Nullable + @Override + protected InspectionProfileEntry getInspection() { + return new PropertyValueSetToItselfInspection(); + } +}
\ No newline at end of file diff --git a/plugins/IntelliLang/java-support/resources/javaInjections.xml b/plugins/IntelliLang/java-support/resources/javaInjections.xml index 4b66c8b13713..97ba2e624ac6 100644 --- a/plugins/IntelliLang/java-support/resources/javaInjections.xml +++ b/plugins/IntelliLang/java-support/resources/javaInjections.xml @@ -130,6 +130,13 @@ <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("PrintStream").withParameters("java.lang.String", "java.lang.String").definedInClass("java.io.PrintStream"))]]></place> <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("encode").withParameters("java.lang.String", "java.lang.String").definedInClass("java.net.URLEncoder"))]]></place> <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("decode").withParameters("java.lang.String", "java.lang.String").definedInClass("java.net.URLDecoder"))]]></place> + <place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("setCharacterEncoding").withParameters("java.lang.String").definedInClass("javax.servlet.ServletResponse"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newReader").withParameters("java.nio.channels.ReadableByteChannel", "java.lang.String").definedInClass("java.nio.channels.Channels"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newWriter").withParameters("java.nio.channels.WritableByteChannel", "java.lang.String").definedInClass("java.nio.channels.Channels"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("createXMLEventReader").withParameters("java.io.InputStream", "java.lang.String").definedInClass("javax.xml.stream.XMLInputFactory"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("createXMLStreamReader").withParameters("java.io.InputStream", "java.lang.String").definedInClass("javax.xml.stream.XMLInputFactory"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("createXMLEventWriter").withParameters("java.io.OutputStream", "java.lang.String").definedInClass("javax.xml.stream.XMLInputFactory"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("createXMLStreamWriter").withParameters("java.io.OutputStream", "java.lang.String").definedInClass("javax.xml.stream.XMLInputFactory"))]]></place> </injection> </component> diff --git a/plugins/IntelliLang/src/META-INF/plugin.xml b/plugins/IntelliLang/src/META-INF/plugin.xml index 8f8806a8b2ec..4caafeba1815 100644 --- a/plugins/IntelliLang/src/META-INF/plugin.xml +++ b/plugins/IntelliLang/src/META-INF/plugin.xml @@ -20,7 +20,6 @@ <depends optional="true" config-file="intellilang-xpath-support.xml">XPathView</depends> <depends optional="true" config-file="intellilang-java-support.xml">com.intellij.modules.java</depends> <depends optional="true" config-file="intellilang-xml-support.xml">com.intellij.modules.xml</depends> - <depends optional="true" config-file="intellilang-python-support.xml">com.intellij.modules.python</depends> <extensionPoints> <extensionPoint name="languageSupport" interface="org.intellij.plugins.intelliLang.inject.LanguageInjectionSupport"/> diff --git a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java index 48ee3b51fac2..1b4e43ec4df1 100644 --- a/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java +++ b/plugins/IntelliLang/src/org/intellij/plugins/intelliLang/inject/InjectorUtils.java @@ -226,7 +226,7 @@ public class InjectorUtils { } @Nullable - public static BaseInjection findCommentInjection(PsiElement context, final String supportId, final Ref<PsiElement> causeRef) { + public static BaseInjection findCommentInjection(@NotNull PsiElement context, @NotNull String supportId, @Nullable Ref<PsiElement> causeRef) { PsiElement target = CompletionUtil.getOriginalOrSelf(context); PsiFile file = target.getContainingFile(); TreeMap<TextRange, BaseInjection> map = getInjectionMap(file); @@ -247,17 +247,17 @@ public class InjectorUtils { // make sure comment is close enough and ... int off1 = r0.getEndOffset(); int off2 = e2.getTextRange().getStartOffset(); - if (off2 - off1 > 120) return null; - if (off2 - off1 > 2) { - // ... there's nothing in between on the top level and ... - for (PsiElement e = e1; e != e2; e = e.getNextSibling()) { - if (!isWhitespaceCommentOrBlank(e)) return null; - } - // ... there's no non-empty host in the left (comment) subtree - Producer<PsiElement> producer = prevWalker(PsiTreeUtil.getDeepestLast(e1), e1); + if (off2 - off1 > 120) { + return null; + } + else if (off2 - off1 > 2) { + // ... there's no non-empty valid host in between comment and e2 + Producer<PsiElement> producer = prevWalker(e2, commonParent); PsiElement e; while ( (e = producer.produce()) != null && e != psiComment) { - if (e instanceof PsiLanguageInjectionHost && !StringUtil.isEmptyOrSpaces(e.getText())) { + if (e instanceof PsiLanguageInjectionHost && + ((PsiLanguageInjectionHost)e).isValidHost() && + !StringUtil.isEmptyOrSpaces(e.getText())) { return null; } } @@ -268,12 +268,9 @@ public class InjectorUtils { return new BaseInjection(supportId).copyFrom(entry.getValue()); } - protected static boolean isWhitespaceCommentOrBlank(PsiElement e) { - return e instanceof PsiWhiteSpace || e instanceof PsiComment || - e instanceof PsiLanguageInjectionHost && StringUtil.isEmptyOrSpaces(e.getText()); - } - - protected static TreeMap<TextRange, BaseInjection> getInjectionMap(final PsiFile file) { + @Nullable + private static TreeMap<TextRange, BaseInjection> getInjectionMap(@Nullable final PsiFile file) { + if (file == null) return null; // e.g. null for synthetic groovy variables return CachedValuesManager.getCachedValue(file, new CachedValueProvider<TreeMap<TextRange, BaseInjection>>() { @Nullable @Override @@ -293,8 +290,6 @@ public class InjectorUtils { CharSequence contents = file.getViewProvider().getContents(); final char[] contentsArray = CharArrayUtil.fromSequenceWithoutCopying(contents); - //long time = System.currentTimeMillis(); - int s0 = 0, s1 = contents.length(); for (int idx = searcher.scan(contents, contentsArray, s0, s1); idx != -1; @@ -309,30 +304,6 @@ public class InjectorUtils { } } } - - //VirtualFile virtualFile = file.getVirtualFile(); - //Document document = FileDocumentManager.getInstance().getDocument(virtualFile); - //EditorHighlighter highlighter = EditorHighlighterCache.getEditorHighlighterForCachesBuilding(document); - // - //ParserDefinition definition = LanguageParserDefinitions.INSTANCE.forLanguage(file.getLanguage()); - //TokenSet commentTokens = definition.getCommentTokens(); - //HighlighterIterator it = highlighter != null && PlatformIdTableBuilding.checkCanUseCachedEditorHighlighter(contents, highlighter) ? - // highlighter.createIterator(0) : null; - // - //do { - // if (it != null) { - // while (!it.atEnd() && !commentTokens.contains(it.getTokenType())) it.advance(); - // if (it.atEnd()) break; - // } - // int s0 = it == null ? 0 : it.getStart(); - // int s1 = it == null ? contents.length() : it.getEnd(); - // - // for () { .. } - // - // if (it != null && !it.atEnd()) it.advance(); - //} while (it != null && !it.atEnd()); - - //System.out.println(Thread.currentThread().getName() + ": " + file.getName() + "@" + file.hashCode() + " indexed: " + (System.currentTimeMillis() - time)); return injectionMap; } @@ -373,18 +344,11 @@ public class InjectorUtils { if (e == null || e == scope) return null; PsiElement prev = e.getPrevSibling(); if (prev != null) { - e = prev; - while (true) { - PsiElement lastChild = e.getLastChild(); - if (lastChild == null) break; - e = lastChild; - } - return e; + return e = PsiTreeUtil.getDeepestLast(prev); } else { PsiElement parent = e.getParent(); - e = parent == scope || parent instanceof PsiFile ? null : parent; - return e; + return e = parent == scope || parent instanceof PsiFile ? null : parent; } } }; diff --git a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties index dc1b4c6f62d8..30e64929f8b2 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties +++ b/plugins/IntentionPowerPak/src/com/siyeh/IntentionPowerPackBundle.properties @@ -145,7 +145,7 @@ convert.j.unit3.test.case.to.j.unit4.intention.name=Convert to JUnit4 Test Case if.to.assertion.intention.family.name=Replace If with Assert Statement if.to.assertion.intention.name=Replace 'if' with 'assert' statement expand.to.normal.annotation.intention.family.name=Expand Annotation to Normal Form -expand.to.normal.annotation.name=Expand to ''{0}'' +expand.to.normal.annotation.intention.name=Add 'value=' to annotation attribute annotate.overridden.methods.intention.family.name=Annotate overriding methods and their parameters annotate.overridden.methods.intention.method.name=Annotate overriding methods as ''@{0}'' annotate.overridden.methods.intention.parameters.name=Annotate same parameter of overriding methods as ''@{0}'' diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntention.java index e9cd879df58e..a1563b807212 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntention.java @@ -15,25 +15,12 @@ */ package com.siyeh.ipp.annotation; -import com.intellij.openapi.editor.CaretModel; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.siyeh.IntentionPowerPackBundle; -import com.siyeh.ipp.base.MutablyNamedIntention; +import com.siyeh.ipp.base.Intention; import com.siyeh.ipp.base.PsiElementPredicate; import org.jetbrains.annotations.NotNull; -public class ExpandToNormalAnnotationIntention extends MutablyNamedIntention { - - @Override - protected String getTextForElement(PsiElement element) { - final PsiNameValuePair annotation = (PsiNameValuePair)element; - final String text = buildReplacementText(annotation); - return IntentionPowerPackBundle.message( - "expand.to.normal.annotation.name", text); - } +public class ExpandToNormalAnnotationIntention extends Intention { @NotNull @Override @@ -41,38 +28,28 @@ public class ExpandToNormalAnnotationIntention extends MutablyNamedIntention { return new ExpandToNormalAnnotationPredicate(); } - public static String buildReplacementText(PsiNameValuePair attribute) { + public static String buildReplacementText(PsiAnnotationParameterList annotationParameterList) { final StringBuilder text = new StringBuilder(); - final PsiAnnotationMemberValue value = attribute.getValue(); - text.append("value = "); - if (value != null) { - text.append(value.getText()); + for (PsiNameValuePair nameValuePair : annotationParameterList.getAttributes()) { + if (text.length() != 0) { + text.append(','); + } + final String name = nameValuePair.getName(); + text.append(name != null ? name : "value").append('='); + final PsiAnnotationMemberValue value = nameValuePair.getValue(); + if (value != null) { + text.append(value.getText()); + } } return text.toString(); } @Override protected void processIntention(@NotNull PsiElement element) { - final PsiNameValuePair attribute = (PsiNameValuePair)element; - final int textOffset = attribute.getTextOffset(); - final Project project = attribute.getProject(); - final String text = buildReplacementText(attribute); - final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project); - final PsiAnnotation newAnnotation = factory.createAnnotationFromText("@A(" + text +" )", attribute); - final PsiAnnotationParameterList parent = (PsiAnnotationParameterList)attribute.getParent(); - for (PsiElement child = parent.getFirstChild(); child != null; child = child.getNextSibling()) { - if (child instanceof PsiErrorElement) { - child.delete(); - break; - } - } - attribute.replace(newAnnotation.getParameterList().getAttributes()[0]); - final FileEditorManager editorManager = FileEditorManager.getInstance(project); - final Editor editor = editorManager.getSelectedTextEditor(); - if (editor == null) { - return; - } - final CaretModel caretModel = editor.getCaretModel(); - caretModel.moveToOffset(textOffset + text.length() - 1); + final PsiAnnotationParameterList annotationParameterList = (PsiAnnotationParameterList)element.getParent(); + final String text = buildReplacementText(annotationParameterList); + final PsiElementFactory factory = JavaPsiFacade.getElementFactory(annotationParameterList.getProject()); + final PsiAnnotation newAnnotation = factory.createAnnotationFromText("@A(" + text +" )", element); + annotationParameterList.replace(newAnnotation.getParameterList()); } } diff --git a/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/ObjectsRequireNonNullIntention.java b/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/ObjectsRequireNonNullIntention.java index 10caec211a5d..e3617711d6c0 100644 --- a/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/ObjectsRequireNonNullIntention.java +++ b/plugins/IntentionPowerPak/src/com/siyeh/ipp/asserttoif/ObjectsRequireNonNullIntention.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import com.siyeh.ig.PsiReplacementUtil; +import com.siyeh.ig.psiutils.ClassUtils; import com.siyeh.ig.psiutils.ParenthesesUtils; import com.siyeh.ig.psiutils.VariableAccessUtils; import com.siyeh.ipp.base.Intention; @@ -58,6 +59,9 @@ public class ObjectsRequireNonNullIntention extends Intention { annotation.delete(); } else { final PsiStatement referenceStatement = PsiTreeUtil.getParentOfType(referenceExpression, PsiStatement.class); + if (referenceStatement == null) { + return; + } final PsiElement parent = referenceStatement.getParent(); if (!(parent instanceof PsiCodeBlock)) { return; @@ -103,6 +107,9 @@ public class ObjectsRequireNonNullIntention extends Intention { return false; } final PsiVariable variable = (PsiVariable)target; + if (ClassUtils.findClass("java.util.Objects", element) == null) { + return false; + } if (NullableNotNullManager.isNotNull(variable)) { return true; } diff --git a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntentionTest.java b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntentionTest.java index dea52b1d28d3..31a5b061f291 100644 --- a/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntentionTest.java +++ b/plugins/IntentionPowerPak/testSrc/com/siyeh/ipp/annotation/ExpandToNormalAnnotationIntentionTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,9 @@ package com.siyeh.ipp.annotation; import com.siyeh.ipp.IPPTestCase; +/** + * @see ExpandToNormalAnnotationIntention + */ public class ExpandToNormalAnnotationIntentionTest extends IPPTestCase { public void testOneAttr() throws Exception { doTest(); @@ -32,7 +35,7 @@ public class ExpandToNormalAnnotationIntentionTest extends IPPTestCase { @Override protected String getIntentionName() { - return "Expand to 'value = \"foo\"'"; + return "Add 'value=' to annotation attribute"; } @Override diff --git a/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java b/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java index 426604fdfe97..baff66317278 100644 --- a/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java +++ b/plugins/ant/jps-plugin/testSrc/org/jetbrains/jps/ant/JpsAntArtifactBuilderTaskTest.java @@ -18,6 +18,7 @@ package org.jetbrains.jps.ant; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.application.ex.PathManagerEx; import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.incremental.artifacts.ArtifactBuilderTestCase; import org.jetbrains.jps.model.serialization.JpsGlobalLoader; @@ -26,6 +27,7 @@ import org.jetbrains.jps.model.serialization.PathMacroUtil; import java.io.File; import java.io.IOException; +import java.util.Collections; import java.util.Map; import static com.intellij.util.io.TestFileSystemBuilder.fs; @@ -61,8 +63,9 @@ public class JpsAntArtifactBuilderTaskTest extends ArtifactBuilderTestCase { return PathManagerEx.findFileUnderProjectHome("plugins/ant/jps-plugin/testData", getClass()).getAbsolutePath(); } + @NotNull @Override - protected void addPathVariables(Map<String, String> pathVariables) { - pathVariables.put("ARTIFACTS_OUT", FileUtil.toSystemIndependentName(myArtifactsOutput.getAbsolutePath())); + protected Map<String, String> getAdditionalPathVariables() { + return Collections.singletonMap("ARTIFACTS_OUT", FileUtil.toSystemIndependentName(myArtifactsOutput.getAbsolutePath())); } } diff --git a/plugins/ant/src/com/intellij/lang/ant/AntIntrospector.java b/plugins/ant/src/com/intellij/lang/ant/AntIntrospector.java index 234a734b08ec..ef0fa80192b1 100644 --- a/plugins/ant/src/com/intellij/lang/ant/AntIntrospector.java +++ b/plugins/ant/src/com/intellij/lang/ant/AntIntrospector.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,12 @@ package com.intellij.lang.ant; import com.intellij.openapi.diagnostic.Logger; import com.intellij.util.Alarm; +import com.intellij.util.ReflectionUtil; import org.apache.tools.ant.IntrospectionHelper; import org.apache.tools.ant.TaskContainer; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; @@ -231,8 +231,7 @@ public final class AntIntrospector { catch (Throwable e) { try { // assume it is older version of ant - final Field helpersField = helperClass.getDeclaredField("helpers"); - final Map helpersCollection = (Map)helpersField.get(null); + Map helpersCollection = ReflectionUtil.getField(helperClass, null, null, "helpers"); helpersCollection.clear(); } catch (Throwable _e) { diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java index 6f2fb8549eb8..3af6d25c5c82 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/OutputParser.java @@ -25,6 +25,8 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; +import com.intellij.problems.Problem; +import com.intellij.problems.WolfTheProblemSolver; import com.intellij.rt.ant.execution.IdeaAntLogger2; import com.intellij.util.text.StringTokenizer; import org.jetbrains.annotations.NonNls; @@ -32,6 +34,7 @@ import org.jetbrains.annotations.Nullable; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.List; public class OutputParser{ @@ -193,7 +196,7 @@ public class OutputParser{ return -1; } - private static void processJavacMessages(final List<String> javacMessages, final AntBuildMessageView messageView, Project project) { + private static void processJavacMessages(final List<String> javacMessages, final AntBuildMessageView messageView, final Project project) { if (javacMessages == null) { return; } @@ -241,6 +244,12 @@ public class OutputParser{ public void run() { VirtualFile file = url == null ? null : VirtualFileManager.getInstance().findFileByUrl(url); messageView.outputJavacMessage(convertCategory(category), strings, file, url, lineNum, columnNum); + + if (file != null && category == CompilerMessageCategory.ERROR) { + final WolfTheProblemSolver wolf = WolfTheProblemSolver.getInstance(project); + final Problem problem = wolf.convertToProblem(file, lineNum, columnNum, strings); + wolf.weHaveGotNonIgnorableProblems(file, Collections.singletonList(problem)); + } } }); } diff --git a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java index 479211ec82f1..c327d760e10d 100644 --- a/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java +++ b/plugins/coverage-common/src/com/intellij/coverage/SrcFileAnnotator.java @@ -25,7 +25,7 @@ import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.fileEditor.TextEditor; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; import com.intellij.openapi.module.Module; -import com.intellij.openapi.module.ModuleUtil; +import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ProjectFileIndex; import com.intellij.openapi.roots.ProjectRootManager; @@ -223,7 +223,7 @@ public class SrcFileAnnotator implements Disposable { } public void showCoverageInformation(final CoverageSuitesBundle suite) { - if (myEditor == null) return; + if (myEditor == null || myFile == null) return; final MarkupModel markupModel = DocumentMarkupModel.forDocument(myDocument, myProject, true); final List<RangeHighlighter> highlighters = new ArrayList<RangeHighlighter>(); final ProjectData data = suite.getCoverageData(); @@ -278,7 +278,7 @@ public class SrcFileAnnotator implements Disposable { @Nullable @Override public Module compute() { - return ModuleUtil.findModuleForPsiElement(myFile); + return ModuleUtilCore.findModuleForPsiElement(myFile); } }); if (module != null) { diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/actions/merge/MergeAction.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/actions/merge/MergeAction.java index e76f2f061485..80efbd46f8fa 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/actions/merge/MergeAction.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/actions/merge/MergeAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -58,13 +58,13 @@ public class MergeAction extends AnAction { final VcsContext context = CvsContextWrapper.createCachedInstance(e); final VirtualFile[] files = context.getSelectedFiles(); - if (files == null || files.length == 0) return; + if (files.length == 0) return; + final Project project = context.getProject(); final ReadonlyStatusHandler.OperationStatus operationStatus = - ReadonlyStatusHandler.getInstance(context.getProject()).ensureFilesWritable(files); + ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files); if (operationStatus.hasReadonlyFiles()) { return; } - final Project project = context.getProject(); AbstractVcsHelper.getInstance(project).showMergeDialog(Arrays.asList(files), new CvsMergeProvider()); } catch (Exception e1) { diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java index a2e055b7b283..a652289a59c7 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsstatuses/CvsChangeProvider.java @@ -33,13 +33,8 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.Comparing; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.FileStatus; -import com.intellij.openapi.vcs.ObjectsConvertor; -import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.actions.VcsContextFactory; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.history.VcsRevisionNumber; @@ -63,13 +58,13 @@ public class CvsChangeProvider implements ChangeProvider { private final CvsVcs2 myVcs; private final CvsEntriesManager myEntriesManager; - private final ProjectFileIndex myFileIndex; + private final ProjectLevelVcsManager myVcsManager; private final ChangeListManager myChangeListManager; public CvsChangeProvider(final CvsVcs2 vcs, CvsEntriesManager entriesManager) { myVcs = vcs; myEntriesManager = entriesManager; - myFileIndex = ProjectRootManager.getInstance(vcs.getProject()).getFileIndex(); + myVcsManager = ProjectLevelVcsManager.getInstance(vcs.getProject()); myChangeListManager = ChangeListManager.getInstance(vcs.getProject()); } @@ -169,7 +164,7 @@ public class CvsChangeProvider implements ChangeProvider { for (VirtualFile file : children) { progress.checkCanceled(); if (file.isDirectory()) { - final boolean isIgnored = myFileIndex.isExcluded(file); + final boolean isIgnored = myVcsManager.isIgnored(file); if (!isIgnored) { processEntriesIn(file, scope, builder, true, progress); } @@ -284,7 +279,7 @@ public class CvsChangeProvider implements ChangeProvider { private void checkSwitchedDir(final VirtualFile dir, final ChangelistBuilder builder, final VcsDirtyScope scope) { final VirtualFile parentDir = dir.getParent(); - if (parentDir == null || !myFileIndex.isInContent(parentDir)) { + if (parentDir == null || !myVcsManager.isFileInContent(parentDir)) { return; } final CvsInfo info = myEntriesManager.getCvsInfoFor(dir); @@ -317,7 +312,7 @@ public class CvsChangeProvider implements ChangeProvider { private void checkSwitchedFile(final FilePath filePath, final ChangelistBuilder builder, final VirtualFile dir, final Entry entry) { // if content root itself is switched, ignore - if (!myFileIndex.isInContent(dir)) { + if (!myVcsManager.isFileInContent(dir)) { return; } final String dirTag = myEntriesManager.getCvsInfoFor(dir).getStickyTag(); diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java index 3877a78a0d35..eb30dd74752c 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/ui/experts/importToCvs/ImportTree.java @@ -30,9 +30,8 @@ import com.intellij.openapi.fileChooser.FileElement; import com.intellij.openapi.fileChooser.FileSystemTree; import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ProjectFileIndex; -import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; @@ -150,12 +149,11 @@ public class ImportTree extends NodeRenderer { if (myProject == null) { return; } - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - if (!fileIndex.isExcluded(selectedFile)) { + if (!isIgnoredByVcs(selectedFile)) { return; } final VirtualFile parent = selectedFile.getParent(); - if (parent != null && fileIndex.isExcluded(parent)) { + if (parent != null && isIgnoredByVcs(parent)) { return; } for (final VirtualFile excludedFile : myExcludedFiles) { @@ -182,12 +180,11 @@ public class ImportTree extends NodeRenderer { if (myProject == null) { continue; } - final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - if (!fileIndex.isExcluded(selectedFile)) { + if (!isIgnoredByVcs(selectedFile)) { continue; } final VirtualFile parent = selectedFile.getParent(); - if (parent == null || fileIndex.isExcluded(parent) || myExcludedFiles.contains(parent)) { + if (parent == null || isIgnoredByVcs(parent) || myExcludedFiles.contains(parent)) { continue; } if (!myIncludedFiles.contains(selectedFile)) { @@ -211,7 +208,7 @@ public class ImportTree extends NodeRenderer { return true; } } - if (myProject == null || !ProjectRootManager.getInstance(myProject).getFileIndex().isExcluded(file)) { + if (myProject == null || !isIgnoredByVcs(file)) { return false; } for (VirtualFile includedFile : myIncludedFiles) { @@ -242,7 +239,7 @@ public class ImportTree extends NodeRenderer { if (FileTypeManager.getInstance().isFileIgnored(abstractFileObject.getName())) return true; if (myProject != null && !includedFiles.contains(file)) { final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file); - if (vFile != null && ProjectRootManager.getInstance(myProject).getFileIndex().isExcluded(vFile)) { + if (vFile != null && isIgnoredByVcs(vFile)) { return true; } } @@ -257,4 +254,8 @@ public class ImportTree extends NodeRenderer { } }; } + + private boolean isIgnoredByVcs(VirtualFile vFile) { + return myProject != null && ProjectLevelVcsManager.getInstance(myProject).isIgnored(vFile); + } } diff --git a/plugins/devkit/resources/META-INF/plugin.xml b/plugins/devkit/resources/META-INF/plugin.xml index 9bb838c8e02c..0a9501ebef94 100644 --- a/plugins/devkit/resources/META-INF/plugin.xml +++ b/plugins/devkit/resources/META-INF/plugin.xml @@ -12,7 +12,7 @@ <depends>com.intellij.properties</depends> - <resource-bundle>DevKitBundle</resource-bundle> + <resource-bundle>org.jetbrains.idea.devkit.DevKitBundle</resource-bundle> <extensions defaultExtensionNs="com.intellij"> <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/> @@ -56,52 +56,44 @@ implementationClass="org.jetbrains.idea.devkit.references.extensions.ExtensionPointDocumentationProvider"/> <localInspection language="XML" shortName="PluginXmlValidity" displayName="Plugin.xml Validity" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.idea.devkit.inspections.PluginXmlDomInspection"/> - <localInspection language="JAVA" shortName="ComponentNotRegistered" bundle="DevKitBundle" + <localInspection language="JAVA" shortName="ComponentNotRegistered" key="inspections.component.not.registered.name" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.ComponentNotRegisteredInspection"/> <localInspection language="JAVA" shortName="InspectionDescriptionNotFoundInspection" displayName="Inspection Description Checker" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.InspectionDescriptionNotFoundInspection"/> <localInspection language="JAVA" shortName="InspectionUsingGrayColors" displayName="Using new Color(a,a,a)" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.UseGrayInspection"/> <localInspection language="JAVA" shortName="IntentionDescriptionNotFoundInspection" displayName="Intention Description Checker" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.IntentionDescriptionNotFoundInspection"/> <localInspection language="JAVA" key="inspections.component.postfix.template.not.found.description.name" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.PostfixTemplateDescriptionNotFoundInspection"/> <localInspection shortName="ComponentRegistrationProblems" - bundle="DevKitBundle" key="inspections.registration.problems.name" + key="inspections.registration.problems.name" groupKey="inspections.group.name" enabledByDefault="true" level="ERROR" implementationClass="org.jetbrains.idea.devkit.inspections.RegistrationProblemsInspection"/> <localInspection language="JAVA" shortName="DialogTitleCapitalization" - bundle="DevKitBundle" groupKey="inspections.group.name" displayName="Incorrect dialog title capitalization" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.TitleCapitalizationInspection"/> <localInspection language="XML" shortName="InspectionMappingConsistency" - bundle="DevKitBundle" groupKey="inspections.group.name" displayName="<inspection> tag consistency" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.InspectionMappingConsistencyInspection"/> <localInspection language="XML" shortName="ExtensionPointBeanClass" - bundle="DevKitBundle" groupKey="inspections.group.name" displayName="<extensionPoint> beanClass specification" enabledByDefault="true" @@ -109,42 +101,34 @@ implementationClass="org.jetbrains.idea.devkit.inspections.ExtensionPointBeanClassInspection"/> <localInspection language="JAVA" shortName="UndesirableClassUsage" displayName="Undesirable class usage" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.UndesirableClassUsageInspection"/> <localInspection language="JAVA" shortName="FileEqualsUsage" displayName="File.equals() usage" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.FileEqualsUsageInspection"/> <localInspection language="JAVA" shortName="GtkPreferredJComboBoxRenderer" displayName="Preferred JComboBox renderer" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.GtkPreferredJComboBoxRendererInspection"/> <localInspection language="JAVA" shortName="UnsafeVfsRecursion" displayName="Unsafe VFS recursion" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.UnsafeVfsRecursionInspection"/> <localInspection language="JAVA" shortName="UseJBColor" displayName="Use Darcula aware JBColor" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.UseJBColorInspection"/> <localInspection language="JAVA" shortName="UseCouple" displayName="Use Couple instead of Pair" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="false" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.UseCoupleInspection"/> <localInspection language="JAVA" shortName="DontUsePairConstructor" displayName="Don't use constructor of Pair class" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.DontUseNewPairInspection"/> <localInspection language="JAVA" shortName="UseVirtualFileEquals" displayName="Use VirtualFile.equals" - bundle="DevKitBundle" groupKey="inspections.group.name" enabledByDefault="true" level="WARNING" implementationClass="org.jetbrains.idea.devkit.inspections.internal.UseVirtualFileEqualsInspection"/> diff --git a/plugins/devkit/resources/DevKitBundle.properties b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties index 6799f6d2415f..6799f6d2415f 100644 --- a/plugins/devkit/resources/DevKitBundle.properties +++ b/plugins/devkit/resources/org/jetbrains/idea/devkit/DevKitBundle.properties diff --git a/plugins/devkit/src/DevKitBundle.java b/plugins/devkit/src/DevKitBundle.java index 013fd2f43e6b..d5460ad123f9 100644 --- a/plugins/devkit/src/DevKitBundle.java +++ b/plugins/devkit/src/DevKitBundle.java @@ -26,7 +26,7 @@ public class DevKitBundle extends AbstractBundle { return ourInstance.getMessage(key, params); } - @NonNls private static final String BUNDLE = "DevKitBundle"; + @NonNls private static final String BUNDLE = "org.jetbrains.idea.devkit.DevKitBundle"; private static final DevKitBundle ourInstance = new DevKitBundle(); private DevKitBundle() { diff --git a/plugins/devkit/src/actions/ShowSerializedXmlAction.java b/plugins/devkit/src/actions/ShowSerializedXmlAction.java index 888042424295..e718eb74989d 100644 --- a/plugins/devkit/src/actions/ShowSerializedXmlAction.java +++ b/plugins/devkit/src/actions/ShowSerializedXmlAction.java @@ -41,6 +41,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.FList; import com.intellij.util.lang.UrlClassLoader; import com.intellij.util.xmlb.Accessor; +import com.intellij.util.xmlb.XmlSerializationException; import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.XmlSerializerUtil; import org.jdom.Element; @@ -121,7 +122,16 @@ public class ShowSerializedXmlAction extends DumbAwareAction { return; } - final Element element = XmlSerializer.serialize(o); + final Element element; + try { + element = XmlSerializer.serialize(o); + } + catch (XmlSerializationException e) { + LOG.info(e); + Throwable cause = e.getCause(); + Messages.showErrorDialog(project, e.getMessage() + (cause != null ? ": " + cause.getMessage() : ""), CommonBundle.getErrorTitle()); + return; + } final String text = JDOMUtil.writeElement(element, "\n"); Messages.showIdeaMessageDialog(project, text, "Serialized XML for '" + className + "'", new String[]{CommonBundle.getOkButtonText()}, 0, Messages.getInformationIcon(), null); diff --git a/plugins/devkit/src/build/PrepareToDeployAction.java b/plugins/devkit/src/build/PrepareToDeployAction.java index b501331596b5..37bedb4d1d3a 100644 --- a/plugins/devkit/src/build/PrepareToDeployAction.java +++ b/plugins/devkit/src/build/PrepareToDeployAction.java @@ -164,6 +164,7 @@ public class PrepareToDeployAction extends AnAction { else { FileUtil.copy(jarFile, dstFile); } + LocalFileSystem.getInstance().refreshIoFiles(Collections.singleton(dstFile), true, false, null); successMessages.add(DevKitBundle.message("saved.message", isZip ? 1 : 2, pluginName, dstPath)); } catch (final IOException e) { diff --git a/plugins/devkit/src/dom/DependencyConfigFileConverter.java b/plugins/devkit/src/dom/DependencyConfigFileConverter.java index 214d21e6e819..b9cb283a1ac5 100644 --- a/plugins/devkit/src/dom/DependencyConfigFileConverter.java +++ b/plugins/devkit/src/dom/DependencyConfigFileConverter.java @@ -93,12 +93,12 @@ public class DependencyConfigFileConverter extends PathReferenceConverter { public Collection<PsiFileSystemItem> computeDefaultContexts() { final PsiFile containingFile = getContainingFile(); if (containingFile == null) { - return super.getDefaultContexts(); + return Collections.emptyList(); } final Module module = ModuleUtilCore.findModuleForPsiElement(getElement()); if (module == null) { - return super.getDefaultContexts(); + return Collections.emptyList(); } final Set<VirtualFile> roots = new HashSet<VirtualFile>(); diff --git a/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java b/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java index 80a3aabce8f3..b3d7fda2c19a 100644 --- a/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java +++ b/plugins/devkit/src/dom/impl/PluginXmlDomFileDescription.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,16 +21,20 @@ import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.HighlightSeverity; import com.intellij.openapi.util.Iconable; import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiField; import com.intellij.util.xml.DomElement; import com.intellij.util.xml.DomFileDescription; import com.intellij.util.xml.DomUtil; import com.intellij.util.xml.GenericAttributeValue; import com.intellij.util.xml.highlighting.DomElementAnnotationHolder; import com.intellij.util.xml.highlighting.DomElementsAnnotator; +import com.intellij.util.xml.reflect.DomAttributeChildDescription; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.dom.*; import javax.swing.*; +import java.util.List; /** * @author mike @@ -73,12 +77,29 @@ public class PluginXmlDomFileDescription extends DomFileDescription<IdeaPlugin> final ExtensionPoint extensionPoint = extension.getExtensionPoint(); if (extensionPoint == null) return; final GenericAttributeValue<PsiClass> interfaceAttribute = extensionPoint.getInterface(); - if (!DomUtil.hasXml(interfaceAttribute)) return; + if (DomUtil.hasXml(interfaceAttribute)) { + final PsiClass value = interfaceAttribute.getValue(); + if (value != null && value.isDeprecated()) { + final Annotation annotation = holder.createAnnotation(extension, HighlightSeverity.WARNING, "Deprecated EP"); + annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED); + return; + } + } - final PsiClass value = interfaceAttribute.getValue(); - if (value != null && value.isDeprecated()) { - final Annotation annotation = holder.createAnnotation(extension, HighlightSeverity.WARNING, "Deprecated EP"); - annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED); + final List<? extends DomAttributeChildDescription> descriptions = extension.getGenericInfo().getAttributeChildrenDescriptions(); + for (DomAttributeChildDescription attributeDescription : descriptions) { + final GenericAttributeValue attributeValue = attributeDescription.getDomAttributeValue(extension); + if (attributeValue == null || !DomUtil.hasXml(attributeValue)) continue; + + final PsiElement declaration = attributeDescription.getDeclaration(extension.getManager().getProject()); + if (declaration instanceof PsiField) { + PsiField psiField = (PsiField)declaration; + if (psiField.isDeprecated()) { + final Annotation annotation = holder.createAnnotation(attributeValue, HighlightSeverity.WARNING, + "Deprecated attribute '" + attributeDescription.getName() + "'"); + annotation.setHighlightType(ProblemHighlightType.LIKE_DEPRECATED); + } + } } } diff --git a/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml b/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml index 6ea4867e4bdf..5466b7ee4485 100644 --- a/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml +++ b/plugins/devkit/testData/codeInsight/deprecatedExtensionAttribute.xml @@ -6,7 +6,7 @@ </extensionPoints> <extensions defaultExtensionNs="com.intellij.myPlugin"> - <myExt <warning descr="'myOld' is deprecated">old</warning>="java.lang.Runnable" attr="value"/> + <myExt <warning descr="Deprecated attribute 'old'">old="java.lang.Runnable"</warning> attr="value"/> </extensions> </idea-plugin>
\ No newline at end of file diff --git a/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentRuntime.java b/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentRuntime.java index 874360a86c5b..9846393b99a8 100644 --- a/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentRuntime.java +++ b/plugins/git4idea/remote-servers-git/src/com/intellij/remoteServer/util/CloudGitDeploymentRuntime.java @@ -16,6 +16,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.remoteServer.agent.util.CloudGitApplication; +import com.intellij.remoteServer.agent.util.CloudLoggingHandler; import com.intellij.remoteServer.configuration.deployment.DeploymentSource; import com.intellij.remoteServer.runtime.deployment.DeploymentLogManager; import com.intellij.remoteServer.runtime.deployment.DeploymentTask; @@ -348,6 +349,11 @@ public class CloudGitDeploymentRuntime extends CloudDeploymentRuntime { }; } + @Override + protected CloudLoggingHandler getLoggingHandler() { + return super.getLoggingHandler(); + } + protected void addGitRemote(CloudGitApplication application) throws ServerRuntimeException { doGitRemote(getRemoteName(), application, "add", CloudBundle.getText("failed.add.remote", getRemoteName())); } diff --git a/plugins/git4idea/src/META-INF/plugin.xml b/plugins/git4idea/src/META-INF/plugin.xml index 32d254f6fb67..dc12d0e03ad0 100644 --- a/plugins/git4idea/src/META-INF/plugin.xml +++ b/plugins/git4idea/src/META-INF/plugin.xml @@ -92,12 +92,13 @@ <separator/> </group> - <action id="Git.CherryPick" class="git4idea.cherrypick.GitCherryPickAction" text="Cherry-Pick" icon="Git4ideaIcons.CherryPick"/> + <action id="Git.CherryPick" class="git4idea.cherrypick.GitCherryPickAction" icon="Git4ideaIcons.CherryPick"/> <action class="git4idea.actions.GitCheckoutRevisionAction" id="Git.CheckoutRevision" text="Checkout Revision"/> - <action class="git4idea.actions.GitCreateNewBranchAction" id="Git.CreateNewBranch" text="New Branch" + <action class="git4idea.actions.GitCreateNewBranchAction" id="Git.CreateNewBranch" text="New Branch..." description="Create new branch starting from the selected commit"/> - <action class="git4idea.actions.GitCreateTagAction" id="Git.CreateNewTag" text="New Tag" + <action class="git4idea.actions.GitCreateTagAction" id="Git.CreateNewTag" text="New Tag..." description="Create new tag pointing to this commit"/> + <action id="Git.Reset.In.Log" class="git4idea.reset.GitResetAction" text="Reset Current Branch to Here..." /> <group id="Git.Log.ContextMenu"> <separator/> @@ -105,6 +106,8 @@ <reference id="Git.CheckoutRevision"/> <reference id="Git.CreateNewBranch" /> <reference id="Git.CreateNewTag" /> + <separator/> + <reference id="Git.Reset.In.Log" /> <add-to-group group-id="Vcs.Log.ContextMenu" /> </group> @@ -121,7 +124,9 @@ <project-components> <component> + <interface-class>git4idea.repo.GitRepositoryManager</interface-class> <implementation-class>git4idea.repo.GitRepositoryManager</implementation-class> + <headless-implementation-class>git4idea.test.GitTestRepositoryManager</headless-implementation-class> </component> </project-components> diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index 5f56de5674e1..4ff61fb4a68b 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -37,7 +37,6 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ChangeListManagerEx; -import com.intellij.openapi.vcs.changes.FilePathsHelper; import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList; import com.intellij.openapi.vcs.vfs.AbstractVcsVirtualFile; import com.intellij.openapi.vfs.LocalFileSystem; @@ -778,6 +777,8 @@ public class GitUtil { /** * Returns absolute paths which have changed remotely comparing to the current branch, i.e. performs * <code>git diff --name-only master..origin/master</code> + * <p/> + * Paths are absolute, Git-formatted (i.e. with forward slashes). */ @NotNull public static Collection<String> getPathsDiffBetweenRefs(@NotNull Git git, @NotNull GitRepository repository, @@ -797,7 +798,7 @@ public class GitUtil { continue; } final String path = repository.getRoot().getPath() + "/" + unescapePath(relative); - remoteChanges.add(FilePathsHelper.convertPath(path)); + remoteChanges.add(path); } return remoteChanges; } @@ -1024,4 +1025,14 @@ public class GitUtil { ApplicationManager.getApplication().getMessageBus().syncPublisher(BatchFileChangeListener.TOPIC).batchChangeCompleted(project); } + @NotNull + public static String cleanupErrorPrefixes(@NotNull String msg) { + final String[] PREFIXES = { "fatal:", "error:" }; + for (String prefix : PREFIXES) { + if (msg.startsWith(prefix)) { + return msg.substring(prefix.length()).trim(); + } + } + return msg; + } } diff --git a/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java b/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java index 39cfb2a625ad..83512de71d1f 100644 --- a/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java +++ b/plugins/git4idea/src/git4idea/actions/GitLogSingleCommitAction.java @@ -15,77 +15,21 @@ */ package git4idea.actions; -import com.intellij.dvcs.DvcsUtil; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.dvcs.ui.VcsLogSingleCommitAction; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.vcs.log.VcsFullCommitDetails; -import com.intellij.vcs.log.VcsLog; -import com.intellij.vcs.log.VcsLogDataKeys; -import git4idea.GitVcs; +import com.intellij.openapi.vfs.VirtualFile; import git4idea.repo.GitRepository; import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.List; - -/** - * @author Kirill Likhodedov - */ -public abstract class GitLogSingleCommitAction extends DumbAwareAction { - - private static final Logger LOG = Logger.getInstance(GitLogSingleCommitAction.class); - - protected abstract void actionPerformed(@NotNull GitRepository repository, @NotNull VcsFullCommitDetails commit); - - @Override - public void actionPerformed(AnActionEvent e) { - Data data = Data.collect(e); - if (!data.isValid()) { - return; - } - - List<VcsFullCommitDetails> details = data.log.getSelectedDetails(); - if (details.size() != 1) { - return; - } - VcsFullCommitDetails commit = details.get(0); - - GitRepositoryManager repositoryManager = ServiceManager.getService(data.project, GitRepositoryManager.class); - final GitRepository repository = repositoryManager.getRepositoryForRoot(commit.getRoot()); - if (repository == null) { - DvcsUtil.noVcsRepositoryForRoot(LOG, commit.getRoot(), data.project, repositoryManager, GitVcs.getInstance(data.project)); - return; - } - - actionPerformed(repository, commit); - } +public abstract class GitLogSingleCommitAction extends VcsLogSingleCommitAction<GitRepository> { @Override - public void update(AnActionEvent e) { - Data data = Data.collect(e); - boolean enabled = data.isValid() && data.log.getSelectedCommits().size() == 1; - e.getPresentation().setVisible(data.isValid()); - e.getPresentation().setEnabled(enabled); - } - - private static class Data { - Project project; - VcsLog log; - - static Data collect(AnActionEvent e) { - Data data = new Data(); - data.project = e.getData(CommonDataKeys.PROJECT); - data.log = e.getData(VcsLogDataKeys.VSC_LOG); - return data; - } - - boolean isValid() { - return project != null && log != null && DvcsUtil.logHasRootForVcs(log, GitVcs.getKey()); - } + @Nullable + protected GitRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { + return ServiceManager.getService(project, GitRepositoryManager.class).getRepositoryForRoot(root); } } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java index 7c2f77eeebd2..9147054ba7b9 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchOperation.java @@ -15,6 +15,7 @@ */ package git4idea.branch; +import com.intellij.dvcs.repo.RepositoryUtil; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; @@ -25,6 +26,9 @@ import com.intellij.openapi.vcs.VcsNotifier; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import git4idea.GitLocalBranch; import git4idea.GitPlatformFacade; import git4idea.GitUtil; import git4idea.commands.Git; @@ -32,6 +36,7 @@ import git4idea.commands.GitMessageWithFilesDetector; import git4idea.config.GitVcsSettings; import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; @@ -50,7 +55,7 @@ abstract class GitBranchOperation { @NotNull protected final Git myGit; @NotNull protected final GitBranchUiHandler myUiHandler; @NotNull private final Collection<GitRepository> myRepositories; - @NotNull protected final String myCurrentBranchOrRev; + @NotNull protected final Map<GitRepository, String> myCurrentHeads; private final GitVcsSettings mySettings; @NotNull private final Collection<GitRepository> mySuccessfulRepositories; @@ -63,7 +68,13 @@ abstract class GitBranchOperation { myGit = git; myUiHandler = uiHandler; myRepositories = repositories; - myCurrentBranchOrRev = GitBranchUtil.getCurrentBranchOrRev(repositories); + myCurrentHeads = ContainerUtil.map2Map(repositories, new Function<GitRepository, Pair<GitRepository, String>>() { + @Override + public Pair<GitRepository, String> fun(GitRepository repository) { + GitLocalBranch currentBranch = repository.getCurrentBranch(); + return Pair.create(repository, currentBranch == null ? repository.getCurrentRevision() : currentBranch.getName()); + } + }); mySuccessfulRepositories = new ArrayList<GitRepository>(); myRemainingRepositories = new ArrayList<GitRepository>(myRepositories); mySettings = myFacade.getSettings(myProject); @@ -220,11 +231,28 @@ abstract class GitBranchOperation { protected void updateRecentBranch() { if (getRepositories().size() == 1) { GitRepository repository = myRepositories.iterator().next(); - mySettings.setRecentBranchOfRepository(repository.getRoot().getPath(), myCurrentBranchOrRev); + mySettings.setRecentBranchOfRepository(repository.getRoot().getPath(), myCurrentHeads.get(repository)); } else { - mySettings.setRecentCommonBranch(myCurrentBranchOrRev); + String recentCommonBranch = getRecentCommonBranch(); + if (recentCommonBranch != null) { + mySettings.setRecentCommonBranch(recentCommonBranch); + } + } + } + + @Nullable + private String getRecentCommonBranch() { + String recentCommonBranch = null; + for (String branch : myCurrentHeads.values()) { + if (recentCommonBranch == null) { + recentCommonBranch = branch; + } + else if (!recentCommonBranch.equals(branch)) { + return null; + } } + return recentCommonBranch; } private void showUnmergedFilesDialogWithRollback() { @@ -340,4 +368,35 @@ abstract class GitBranchOperation { return Pair.create(allConflictingRepositories, affectedChanges); } + + @NotNull + protected static String stringifyBranchesByRepos(@NotNull Map<GitRepository, String> heads) { + MultiMap<String, VirtualFile> grouped = groupByBranches(heads); + if (grouped.size() == 1) { + return grouped.keySet().iterator().next(); + } + return StringUtil.join(grouped.entrySet(), new Function<Map.Entry<String, Collection<VirtualFile>>, String>() { + @Override + public String fun(Map.Entry<String, Collection<VirtualFile>> entry) { + String roots = StringUtil.join(entry.getValue(), new Function<VirtualFile, String>() { + @Override + public String fun(VirtualFile file) { + return file.getName(); + } + }, ", "); + return entry.getKey() + " (in " + roots + ")"; + } + }, "<br/>"); + } + + @NotNull + private static MultiMap<String, VirtualFile> groupByBranches(@NotNull Map<GitRepository, String> heads) { + MultiMap<String, VirtualFile> result = MultiMap.createLinked(); + List<GitRepository> sortedRepos = RepositoryUtil.sortRepositories(heads.keySet()); + for (GitRepository repo : sortedRepos) { + result.putValue(heads.get(repo), repo.getRoot()); + } + return result; + } + } diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUiHandler.java b/plugins/git4idea/src/git4idea/branch/GitBranchUiHandler.java index 3b694c455c7b..95546f0547e8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUiHandler.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUiHandler.java @@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitCommit; import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; @@ -68,14 +69,15 @@ public interface GitBranchUiHandler { * Shows the dialog proposing to execute the operation (checkout or merge) smartly, i.e. stash-execute-unstash. * * @param project - * @param changes local changes that would be overwritten by checkout or merge. - * @param paths paths reported by Git (in most cases this is covered by {@code changes}. - * @param operation operation name: checkout or merge - * @param isForcePossible can the operation be executed force (force checkout is possible, force merge - not). + * @param changes local changes that would be overwritten by checkout or merge. + * @param paths paths reported by Git (in most cases this is covered by {@code changes}. + * @param operation operation name: checkout or merge + * @param forceButtonTitle if the operation can be executed force (force checkout is possible), + * specify the title of the force button; otherwise (force merge is not possible) pass null. * @return the code of the decision. */ int showSmartOperationDialog(@NotNull Project project, @NotNull List<Change> changes, @NotNull Collection<String> paths, - @NotNull String operation, boolean isForcePossible); + @NotNull String operation, @Nullable String forceButtonTitle); boolean showBranchIsNotFullyMergedDialog(@NotNull Project project, @NotNull Map<GitRepository, List<GitCommit>> history, @NotNull String unmergedBranch, @NotNull List<String> mergedToBranches, diff --git a/plugins/git4idea/src/git4idea/branch/GitBranchUiHandlerImpl.java b/plugins/git4idea/src/git4idea/branch/GitBranchUiHandlerImpl.java index cea2b55596e0..20e207d14ba1 100644 --- a/plugins/git4idea/src/git4idea/branch/GitBranchUiHandlerImpl.java +++ b/plugins/git4idea/src/git4idea/branch/GitBranchUiHandlerImpl.java @@ -172,7 +172,7 @@ public class GitBranchUiHandlerImpl implements GitBranchUiHandler { @Override public int showSmartOperationDialog(@NotNull Project project, @NotNull List<Change> changes, @NotNull Collection<String> paths, - @NotNull String operation, boolean isForcePossible) { + @NotNull String operation, @Nullable String forceButtonTitle) { JComponent fileBrowser; if (!changes.isEmpty()) { fileBrowser = new ChangesBrowserWithRollback(project, changes); @@ -180,7 +180,7 @@ public class GitBranchUiHandlerImpl implements GitBranchUiHandler { else { fileBrowser = new GitSimplePathsBrowser(project, paths); } - return GitSmartOperationDialog.showAndGetAnswer(myProject, fileBrowser, operation, isForcePossible); + return GitSmartOperationDialog.showAndGetAnswer(myProject, fileBrowser, operation, forceButtonTitle); } @Override diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java index 22e486e6eab0..cdc4f7711801 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutNewBranchOperation.java @@ -89,7 +89,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { protected String getRollbackProposal() { return "However checkout has succeeded for the following " + repositories() + ":<br/>" + successfulRepositoriesJoined() + - "<br/>You may rollback (checkout back to " + myCurrentBranchOrRev + " and delete " + myNewBranchName + ") not to let branches diverge."; + "<br/>You may rollback (checkout previous branch back, and delete " + myNewBranchName + ") not to let branches diverge."; } @NotNull @@ -104,7 +104,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { GitCompoundResult deleteResult = new GitCompoundResult(myProject); Collection<GitRepository> repositories = getSuccessfulRepositories(); for (GitRepository repository : repositories) { - GitCommandResult result = myGit.checkout(repository, myCurrentBranchOrRev, null, true); + GitCommandResult result = myGit.checkout(repository, myCurrentHeads.get(repository), null, true); checkoutResult.append(repository, result); if (result.success()) { deleteResult.append(repository, myGit.branchDelete(repository, myNewBranchName, false)); @@ -113,7 +113,7 @@ class GitCheckoutNewBranchOperation extends GitBranchOperation { } if (checkoutResult.totalSuccess() && deleteResult.totalSuccess()) { VcsNotifier.getInstance(myProject).notifySuccess("Rollback successful", String - .format("Checked out %s and deleted %s on %s %s", code(myCurrentBranchOrRev), code(myNewBranchName), + .format("Checked out %s and deleted %s on %s %s", stringifyBranchesByRepos(myCurrentHeads), code(myNewBranchName), StringUtil.pluralize("root", repositories.size()), successfulRepositoriesJoined())); } else { diff --git a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java index 2441bf7d46cf..b772434959e8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitCheckoutOperation.java @@ -47,7 +47,7 @@ import static git4idea.util.GitUIUtil.code; */ class GitCheckoutOperation extends GitBranchOperation { - public static final String ROLLBACK_PROPOSAL_FORMAT = "You may rollback (checkout back to %s) not to let branches diverge."; + public static final String ROLLBACK_PROPOSAL_FORMAT = "You may rollback (checkout back to previous branch) not to let branches diverge."; @NotNull private final String myStartPointReference; @Nullable private final String myNewBranch; @@ -115,12 +115,14 @@ class GitCheckoutOperation extends GitBranchOperation { private boolean smartCheckoutOrNotify(@NotNull GitRepository repository, @NotNull GitMessageWithFilesDetector localChangesOverwrittenByCheckout) { Pair<List<GitRepository>, List<Change>> conflictingRepositoriesAndAffectedChanges = - getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByCheckout, myCurrentBranchOrRev, myStartPointReference); + getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByCheckout, myCurrentHeads.get(repository), + myStartPointReference); List<GitRepository> allConflictingRepositories = conflictingRepositoriesAndAffectedChanges.getFirst(); List<Change> affectedChanges = conflictingRepositoriesAndAffectedChanges.getSecond(); Collection<String> absolutePaths = GitUtil.toAbsolute(repository.getRoot(), localChangesOverwrittenByCheckout.getRelativeFilePaths()); - int smartCheckoutDecision = myUiHandler.showSmartOperationDialog(myProject, affectedChanges, absolutePaths, "checkout", true); + int smartCheckoutDecision = myUiHandler.showSmartOperationDialog(myProject, affectedChanges, absolutePaths, "checkout", + "&Force Checkout"); if (smartCheckoutDecision == GitSmartOperationDialog.SMART_EXIT_CODE) { boolean smartCheckedOutSuccessfully = smartCheckout(allConflictingRepositories, myStartPointReference, myNewBranch, getIndicator()); if (smartCheckedOutSuccessfully) { @@ -153,8 +155,7 @@ class GitCheckoutOperation extends GitBranchOperation { @Override protected String getRollbackProposal() { return "However checkout has succeeded for the following " + repositories() + ":<br/>" + - successfulRepositoriesJoined() + - "<br/>" + String.format(ROLLBACK_PROPOSAL_FORMAT, myCurrentBranchOrRev); + successfulRepositoriesJoined() + "<br/>" + ROLLBACK_PROPOSAL_FORMAT; } @NotNull @@ -168,7 +169,7 @@ class GitCheckoutOperation extends GitBranchOperation { GitCompoundResult checkoutResult = new GitCompoundResult(myProject); GitCompoundResult deleteResult = new GitCompoundResult(myProject); for (GitRepository repository : getSuccessfulRepositories()) { - GitCommandResult result = myGit.checkout(repository, myCurrentBranchOrRev, null, true); + GitCommandResult result = myGit.checkout(repository, myCurrentHeads.get(repository), null, true); checkoutResult.append(repository, result); if (result.success() && myNewBranch != null) { /* @@ -183,7 +184,7 @@ class GitCheckoutOperation extends GitBranchOperation { if (!checkoutResult.totalSuccess() || !deleteResult.totalSuccess()) { StringBuilder message = new StringBuilder(); if (!checkoutResult.totalSuccess()) { - message.append("Errors during checking out ").append(myCurrentBranchOrRev).append(": "); + message.append("Errors during checkout: "); message.append(checkoutResult.getErrorOutputWithReposIndication()); } if (!deleteResult.totalSuccess()) { diff --git a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java index d3501caf7089..1dba1e07f6ac 100644 --- a/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitDeleteBranchOperation.java @@ -68,7 +68,7 @@ class GitDeleteBranchOperation extends GitBranchOperation { else if (notFullyMergedDetector.hasHappened()) { String baseBranch = notMergedToUpstreamDetector.getBaseBranch(); if (baseBranch == null) { // GitBranchNotMergedToUpstreamDetector didn't happen - baseBranch = myCurrentBranchOrRev; + baseBranch = myCurrentHeads.get(repository); } Collection<GitRepository> remainingRepositories = getRemainingRepositories(); diff --git a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java index 89a50cfd6054..1b8f382d1dd8 100644 --- a/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java +++ b/plugins/git4idea/src/git4idea/branch/GitMergeOperation.java @@ -34,6 +34,7 @@ import git4idea.commands.*; import git4idea.merge.GitMergeCommittingConflictResolver; import git4idea.merge.GitMerger; import git4idea.repo.GitRepository; +import git4idea.reset.GitResetMode; import git4idea.util.GitPreservingProcess; import org.jetbrains.annotations.NotNull; @@ -189,12 +190,13 @@ class GitMergeOperation extends GitBranchOperation { private boolean proposeSmartMergePerformAndNotify(@NotNull GitRepository repository, @NotNull GitMessageWithFilesDetector localChangesOverwrittenByMerge) { Pair<List<GitRepository>, List<Change>> conflictingRepositoriesAndAffectedChanges = - getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByMerge, myCurrentBranchOrRev, myBranchToMerge); + getConflictingRepositoriesAndAffectedChanges(repository, localChangesOverwrittenByMerge, myCurrentHeads.get(repository), + myBranchToMerge); List<GitRepository> allConflictingRepositories = conflictingRepositoriesAndAffectedChanges.getFirst(); List<Change> affectedChanges = conflictingRepositoriesAndAffectedChanges.getSecond(); Collection<String> absolutePaths = GitUtil.toAbsolute(repository.getRoot(), localChangesOverwrittenByMerge.getRelativeFilePaths()); - int smartCheckoutDecision = myUiHandler.showSmartOperationDialog(myProject, affectedChanges, absolutePaths, "merge", false); + int smartCheckoutDecision = myUiHandler.showSmartOperationDialog(myProject, affectedChanges, absolutePaths, "merge", null); if (smartCheckoutDecision == GitSmartOperationDialog.SMART_EXIT_CODE) { return doSmartMerge(allConflictingRepositories); } @@ -322,7 +324,7 @@ class GitMergeOperation extends GitBranchOperation { @NotNull private GitCommandResult rollback(@NotNull GitRepository repository) { - return myGit.resetHard(repository, myCurrentRevisionsBeforeMerge.get(repository)); + return myGit.reset(repository, GitResetMode.HARD, myCurrentRevisionsBeforeMerge.get(repository)); } @NotNull @@ -339,7 +341,8 @@ class GitMergeOperation extends GitBranchOperation { @NotNull @Override public String getSuccessMessage() { - return String.format("Merged <b><code>%s</code></b> to <b><code>%s</code></b>", myBranchToMerge, myCurrentBranchOrRev); + return String.format("Merged <b><code>%s</code></b> to <b><code>%s</code></b>", + myBranchToMerge, stringifyBranchesByRepos(myCurrentHeads)); } @NotNull diff --git a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java index 9c2ef4a8d107..4f5073027624 100644 --- a/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java +++ b/plugins/git4idea/src/git4idea/branch/GitSmartOperationDialog.java @@ -24,6 +24,7 @@ import com.intellij.ui.components.JBLabel; import com.intellij.util.ui.UIUtil; import git4idea.GitPlatformFacade; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.event.ActionEvent; @@ -44,18 +45,18 @@ public class GitSmartOperationDialog extends DialogWrapper { @NotNull private final JComponent myFileBrowser; @NotNull private final String myOperationTitle; - private final boolean myShowForceButton; + @Nullable private final String myForceButton; /** * Shows the dialog with the list of local changes preventing merge/checkout and returns the dialog exit code. */ static int showAndGetAnswer(@NotNull final Project project, @NotNull final JComponent fileBrowser, - @NotNull final String operationTitle, final boolean showForceButton) { + @NotNull final String operationTitle, @Nullable final String forceButtonTitle) { final AtomicInteger exitCode = new AtomicInteger(); UIUtil.invokeAndWaitIfNeeded(new Runnable() { @Override public void run() { - GitSmartOperationDialog dialog = new GitSmartOperationDialog(project, fileBrowser, operationTitle, showForceButton); + GitSmartOperationDialog dialog = new GitSmartOperationDialog(project, fileBrowser, operationTitle, forceButtonTitle); ServiceManager.getService(project, GitPlatformFacade.class).showDialog(dialog); exitCode.set(dialog.getExitCode()); } @@ -64,11 +65,11 @@ public class GitSmartOperationDialog extends DialogWrapper { } private GitSmartOperationDialog(@NotNull Project project, @NotNull JComponent fileBrowser, @NotNull String operationTitle, - boolean showForceButton) { + @Nullable String forceButton) { super(project); myFileBrowser = fileBrowser; myOperationTitle = operationTitle; - myShowForceButton = showForceButton; + myForceButton = forceButton; String capitalizedOperation = capitalize(myOperationTitle); setTitle("Git " + capitalizedOperation + " Problem"); @@ -82,8 +83,8 @@ public class GitSmartOperationDialog extends DialogWrapper { @NotNull @Override protected Action[] createLeftSideActions() { - if (myShowForceButton) { - return new Action[] {new ForceCheckoutAction(myOperationTitle) }; + if (myForceButton != null) { + return new Action[]{new ForceCheckoutAction(myForceButton, myOperationTitle)}; } return new Action[0]; } @@ -110,8 +111,8 @@ public class GitSmartOperationDialog extends DialogWrapper { private class ForceCheckoutAction extends AbstractAction { - ForceCheckoutAction(@NotNull String operationTitle) { - super("&Force " + capitalize(operationTitle)); + ForceCheckoutAction(@NotNull String buttonTitle, @NotNull String operationTitle) { + super(buttonTitle); putValue(Action.SHORT_DESCRIPTION, capitalize(operationTitle) + " and overwrite local changes"); } diff --git a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java index f1ab1d476c6f..31e731f44937 100644 --- a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java +++ b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java @@ -22,7 +22,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.ChangesUtil; import com.intellij.openapi.vcs.changes.committed.DecoratorManager; import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper; import com.intellij.openapi.vcs.changes.committed.VcsCommittedViewAuxiliary; @@ -199,13 +199,7 @@ public class GitCommittedChangeListProvider implements CommittedChangesProvider< final Collection<Change> changes = commit.getChanges(); if (changes.size() == 1) { Change change = changes.iterator().next(); - ContentRevision revision = change.getAfterRevision(); - if (revision == null) { - revision = change.getBeforeRevision(); - } - assert revision != null : "Revision can't be null in " + change; - FilePath filePathInRevision = revision.getFile(); - return Pair.create(commit, filePathInRevision); + return Pair.create(commit, ChangesUtil.getFilePath(change)); } for (Change change : changes) { if (change.getAfterRevision() != null && FileUtil.filesEqual(filePath.getIOFile(), change.getAfterRevision().getFile().getIOFile())) { diff --git a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java index 3bb008a2f95f..448dd25ef7ab 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCheckinEnvironment.java @@ -226,10 +226,7 @@ public class GitCheckinEnvironment implements CheckinEnvironment { @NotNull private static VcsException cleanupExceptionText(VcsException original) { String msg = original.getMessage(); - final String FATAL_PREFIX = "fatal:"; - if (msg.startsWith(FATAL_PREFIX)) { - msg = msg.substring(FATAL_PREFIX.length()); - } + msg = GitUtil.cleanupErrorPrefixes(msg); final String DURING_EXECUTING_SUFFIX = GitSimpleHandler.DURING_EXECUTING_ERROR_MESSAGE; int suffix = msg.indexOf(DURING_EXECUTING_SUFFIX); if (suffix > 0) { diff --git a/plugins/git4idea/src/git4idea/checkin/GitCommitAuthorCorrector.java b/plugins/git4idea/src/git4idea/checkin/GitCommitAuthorCorrector.java index e46e98a7887f..ac9834efc3ce 100644 --- a/plugins/git4idea/src/git4idea/checkin/GitCommitAuthorCorrector.java +++ b/plugins/git4idea/src/git4idea/checkin/GitCommitAuthorCorrector.java @@ -35,7 +35,7 @@ class GitCommitAuthorCorrector { if (at < 0) { return author; } - int email = author.substring(0, at).lastIndexOf(' '); + int email = author.lastIndexOf(' ', at - 1); if (email < 0) { return author; } diff --git a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java index aa3e1e440277..b4250a0d142b 100644 --- a/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java +++ b/plugins/git4idea/src/git4idea/cherrypick/GitCherryPickAction.java @@ -49,6 +49,8 @@ import java.util.*; * @author Kirill Likhodedov */ public class GitCherryPickAction extends DumbAwareAction { + + private static final String NAME = "Cherry-Pick"; private static final Logger LOG = Logger.getInstance(GitCherryPickAction.class); @NotNull private final GitPlatformFacade myPlatformFacade; @@ -56,7 +58,7 @@ public class GitCherryPickAction extends DumbAwareAction { @NotNull private final Set<Hash> myIdsInProgress; public GitCherryPickAction() { - super("Cherry-pick", "Cherry-pick", Git4ideaIcons.CherryPick); + super(NAME, null, Git4ideaIcons.CherryPick); myGit = ServiceManager.getService(Git.class); myPlatformFacade = ServiceManager.getService(GitPlatformFacade.class); myIdsInProgress = ContainerUtil.newHashSet(); @@ -81,9 +83,8 @@ public class GitCherryPickAction extends DumbAwareAction { new Task.Backgroundable(project, "Cherry-picking", false) { public void run(@NotNull ProgressIndicator indicator) { try { - boolean autoCommit = GitVcsSettings.getInstance(myProject).isAutoCommitOnCherryPick(); Map<GitRepository, List<VcsFullCommitDetails>> commitsInRoots = sortCommits(groupCommitsByRoots(project, commits)); - new GitCherryPicker(myProject, myGit, myPlatformFacade, autoCommit).cherryPick(commitsInRoots); + new GitCherryPicker(project, myGit, myPlatformFacade, isAutoCommit(project)).cherryPick(commitsInRoots); } finally { ApplicationManager.getApplication().invokeLater(new Runnable() { @@ -130,15 +131,21 @@ public class GitCherryPickAction extends DumbAwareAction { return groupedCommits; } + private static boolean isAutoCommit(@NotNull Project project) { + return GitVcsSettings.getInstance(project).isAutoCommitOnCherryPick(); + } + @Override public void update(AnActionEvent e) { super.update(e); - final VcsLog log = getVcsLog(e); - if (log != null && !DvcsUtil.logHasRootForVcs(log, GitVcs.getKey())) { + VcsLog log = getVcsLog(e); + Project project = getEventProject(e); + if (project == null || log == null || !DvcsUtil.logHasRootForVcs(log, GitVcs.getKey())) { e.getPresentation().setEnabledAndVisible(false); } else { e.getPresentation().setEnabled(enabled(e)); + e.getPresentation().setText(isAutoCommit(project) ? NAME : NAME + "..."); } } diff --git a/plugins/git4idea/src/git4idea/commands/Git.java b/plugins/git4idea/src/git4idea/commands/Git.java index 284ccc1e20c5..830f73b4508f 100644 --- a/plugins/git4idea/src/git4idea/commands/Git.java +++ b/plugins/git4idea/src/git4idea/commands/Git.java @@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitCommit; import git4idea.push.GitPushSpec; import git4idea.repo.GitRepository; +import git4idea.reset.GitResetMode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -93,7 +94,8 @@ public interface Git { GitCommandResult branchCreate(@NotNull GitRepository repository, @NotNull String branchName); @NotNull - GitCommandResult resetHard(@NotNull GitRepository repository, @NotNull String revision); + GitCommandResult reset(@NotNull GitRepository repository, @NotNull GitResetMode mode, @NotNull String target, + @NotNull GitLineHandlerListener... listeners); @NotNull GitCommandResult resetMerge(@NotNull GitRepository repository, @Nullable String revision); diff --git a/plugins/git4idea/src/git4idea/commands/GitCommandResult.java b/plugins/git4idea/src/git4idea/commands/GitCommandResult.java index f89a4890a76b..0683d738a9bf 100644 --- a/plugins/git4idea/src/git4idea/commands/GitCommandResult.java +++ b/plugins/git4idea/src/git4idea/commands/GitCommandResult.java @@ -16,10 +16,14 @@ package git4idea.commands; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import git4idea.GitUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -64,9 +68,10 @@ public class GitCommandResult { @NotNull public String getErrorOutputAsHtmlString() { - return StringUtil.join(myErrorOutput, "<br/>"); + return StringUtil.join(cleanup(myErrorOutput), "<br/>"); } - + + @NotNull public String getErrorOutputAsJoinedString() { return StringUtil.join(myErrorOutput, "\n"); } @@ -90,4 +95,14 @@ public class GitCommandResult { return false; // will be implemented later } + @NotNull + private static Collection<String> cleanup(@NotNull Collection<String> errorOutput) { + return ContainerUtil.map(errorOutput, new Function<String, String>() { + @Override + public String fun(String errorMessage) { + return GitUtil.cleanupErrorPrefixes(errorMessage); + } + }); + } + } diff --git a/plugins/git4idea/src/git4idea/commands/GitHandler.java b/plugins/git4idea/src/git4idea/commands/GitHandler.java index 3350b74b1c6a..c2d85b7e3126 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitHandler.java @@ -18,7 +18,6 @@ package git4idea.commands; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; @@ -103,7 +102,6 @@ public abstract class GitHandler { private long myStartTime; // git execution start timestamp private static final long LONG_TIME = 10 * 1000; - @Nullable private ModalityState myState; @Nullable private String myUrl; private boolean myHttpAuthFailed; @@ -423,7 +421,7 @@ public abstract class GitHandler { } else { LOG.debug("cd " + myWorkingDirectory); - LOG.debug(printableCommandLine()); + LOG.debug("[" + myWorkingDirectory.getName() + "] " + printableCommandLine()); } // setup environment @@ -431,7 +429,7 @@ public abstract class GitHandler { if (remoteProtocol == GitRemoteProtocol.SSH && myProjectSettings.isIdeaSsh()) { GitXmlRpcSshService ssh = ServiceManager.getService(GitXmlRpcSshService.class); myEnv.put(GitSSHHandler.GIT_SSH_ENV, ssh.getScriptPath().getPath()); - myHandlerNo = ssh.registerHandler(new GitSSHGUIHandler(myProject, myState)); + myHandlerNo = ssh.registerHandler(new GitSSHGUIHandler(myProject)); myEnvironmentCleanedUp = false; myEnv.put(GitSSHHandler.SSH_HANDLER_ENV, Integer.toString(myHandlerNo)); int port = ssh.getXmlRcpPort(); @@ -458,7 +456,7 @@ public abstract class GitHandler { GitHttpAuthService service = ServiceManager.getService(GitHttpAuthService.class); myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_ENV, service.getScriptPath().getPath()); assert myUrl != null : "myUrl can't be null here"; - GitHttpAuthenticator httpAuthenticator = service.createAuthenticator(myProject, myState, myCommand, myUrl); + GitHttpAuthenticator httpAuthenticator = service.createAuthenticator(myProject, myCommand, myUrl); myHandlerNo = service.registerHandler(httpAuthenticator); myEnvironmentCleanedUp = false; myEnv.put(GitAskPassXmlRpcHandler.GIT_ASK_PASS_HANDLER_ENV, Integer.toString(myHandlerNo)); @@ -474,7 +472,9 @@ public abstract class GitHandler { startHandlingStreams(); } catch (Throwable t) { - LOG.error(t); + if (!ApplicationManager.getApplication().isUnitTestMode() || !myProject.isDisposed()) { + LOG.error(t); // will surely happen if called during unit test disposal, because the working dir is simply removed then + } cleanupEnv(); myListeners.getMulticaster().startFailed(t); } @@ -715,10 +715,6 @@ public abstract class GitHandler { myResumeAction.run(); } - public void setModalityState(@Nullable ModalityState state) { - myState = state; - } - /** * @return true if the command line is too big */ diff --git a/plugins/git4idea/src/git4idea/commands/GitHttpAuthService.java b/plugins/git4idea/src/git4idea/commands/GitHttpAuthService.java index 69be489be44b..712582339405 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHttpAuthService.java +++ b/plugins/git4idea/src/git4idea/commands/GitHttpAuthService.java @@ -15,10 +15,8 @@ */ package git4idea.commands; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.git4idea.http.GitAskPassApp; import org.jetbrains.git4idea.http.GitAskPassXmlRpcHandler; import org.jetbrains.git4idea.ssh.GitXmlRpcHandlerService; @@ -47,8 +45,7 @@ public abstract class GitHttpAuthService extends GitXmlRpcHandlerService<GitHttp * Creates new {@link GitHttpAuthenticator} that will be requested to handle username and password requests from Git. */ @NotNull - public abstract GitHttpAuthenticator createAuthenticator(@NotNull Project project, @Nullable ModalityState state, - @NotNull GitCommand command, @NotNull String url); + public abstract GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url); /** * Internal handler implementation class, it is made public to be accessible via XML RPC. diff --git a/plugins/git4idea/src/git4idea/commands/GitHttpAuthServiceImpl.java b/plugins/git4idea/src/git4idea/commands/GitHttpAuthServiceImpl.java index 06374bf78864..cda188d64e4b 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHttpAuthServiceImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitHttpAuthServiceImpl.java @@ -15,10 +15,8 @@ */ package git4idea.commands; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author Kirill Likhodedov @@ -27,9 +25,8 @@ class GitHttpAuthServiceImpl extends GitHttpAuthService { @Override @NotNull - public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @Nullable ModalityState state, @NotNull GitCommand command, - @NotNull String url) { - return new GitHttpGuiAuthenticator(project, state, command, url); + public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url) { + return new GitHttpGuiAuthenticator(project, command, url); } } diff --git a/plugins/git4idea/src/git4idea/commands/GitHttpGuiAuthenticator.java b/plugins/git4idea/src/git4idea/commands/GitHttpGuiAuthenticator.java index e0312e5471fc..c5931f98df10 100644 --- a/plugins/git4idea/src/git4idea/commands/GitHttpGuiAuthenticator.java +++ b/plugins/git4idea/src/git4idea/commands/GitHttpGuiAuthenticator.java @@ -57,7 +57,6 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { private static final Class<GitHttpAuthenticator> PASS_REQUESTER = GitHttpAuthenticator.class; @NotNull private final Project myProject; - @Nullable private final ModalityState myModalityState; @NotNull private final String myTitle; @NotNull private final String myUrlFromCommand; @@ -69,10 +68,8 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { @Nullable private GitHttpAuthDataProvider myDataProvider; private boolean myWasCancelled; - GitHttpGuiAuthenticator(@NotNull Project project, @Nullable ModalityState modalityState, @NotNull GitCommand command, - @NotNull String url) { + GitHttpGuiAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url) { myProject = project; - myModalityState = modalityState; myTitle = "Git " + StringUtil.capitalize(command.name()); myUrlFromCommand = url; } @@ -87,7 +84,7 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { return ""; } url = adjustUrl(url); - Pair<GitHttpAuthDataProvider, AuthData> authData = findBestAuthData(url, myModalityState); + Pair<GitHttpAuthDataProvider, AuthData> authData = findBestAuthData(url); if (authData != null && authData.second.getPassword() != null) { String password = authData.second.getPassword(); myDataProvider = authData.first; @@ -97,7 +94,7 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { String prompt = "Enter the password for " + url; myPasswordKey = url; - String password = PasswordSafePromptDialog.askPassword(myProject, myModalityState, myTitle, prompt, PASS_REQUESTER, url, false, null); + String password = PasswordSafePromptDialog.askPassword(myProject, myTitle, prompt, PASS_REQUESTER, url, false, null); if (password == null) { myWasCancelled = true; return ""; @@ -114,7 +111,7 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { @NotNull public String askUsername(@NotNull String url) { url = adjustUrl(url); - Pair<GitHttpAuthDataProvider, AuthData> authData = findBestAuthData(url, myModalityState); + Pair<GitHttpAuthDataProvider, AuthData> authData = findBestAuthData(url); String login = null; String password = null; if (authData != null) { @@ -152,7 +149,7 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { dialog.set(new AuthDialog(myProject, myTitle, "Enter credentials for " + url, login, null, true)); dialog.get().show(); } - }, myModalityState == null ? ModalityState.defaultModalityState() : myModalityState); + }, ModalityState.any()); return dialog.get(); } @@ -223,10 +220,10 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { // return the first that knows username + password; otherwise return the first that knows just the username @Nullable - private Pair<GitHttpAuthDataProvider, AuthData> findBestAuthData(@NotNull String url, @Nullable ModalityState modalityState) { + private Pair<GitHttpAuthDataProvider, AuthData> findBestAuthData(@NotNull String url) { Pair<GitHttpAuthDataProvider, AuthData> candidate = null; for (GitHttpAuthDataProvider provider : getProviders()) { - AuthData data = provider.getAuthData(url, modalityState); + AuthData data = provider.getAuthData(url); if (data != null) { Pair<GitHttpAuthDataProvider, AuthData> pair = Pair.create(provider, data); if (data.getPassword() != null) { @@ -268,12 +265,12 @@ class GitHttpGuiAuthenticator implements GitHttpAuthenticator { @Nullable @Override - public AuthData getAuthData(@NotNull String url, @Nullable ModalityState modalityState) { + public AuthData getAuthData(@NotNull String url) { String userName = getUsername(url); String key = makeKey(url, userName); final PasswordSafe passwordSafe = PasswordSafe.getInstance(); try { - String password = passwordSafe.getPassword(myProject, PASS_REQUESTER, key, modalityState); + String password = passwordSafe.getPassword(myProject, PASS_REQUESTER, key); return new AuthData(StringUtil.notNullize(userName), password); } catch (PasswordSafeException e) { diff --git a/plugins/git4idea/src/git4idea/commands/GitImpl.java b/plugins/git4idea/src/git4idea/commands/GitImpl.java index c873e71ff94b..09e254f5392b 100644 --- a/plugins/git4idea/src/git4idea/commands/GitImpl.java +++ b/plugins/git4idea/src/git4idea/commands/GitImpl.java @@ -32,6 +32,7 @@ import git4idea.history.GitHistoryUtils; import git4idea.push.GitPushSpec; import git4idea.repo.GitRemote; import git4idea.repo.GitRepository; +import git4idea.reset.GitResetMode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -338,20 +339,26 @@ public class GitImpl implements Git { @Override @NotNull - public GitCommandResult resetHard(@NotNull GitRepository repository, @NotNull String revision) { - final GitLineHandler handler = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.RESET); - handler.addParameters("--hard", revision); - return run(handler); + public GitCommandResult reset(@NotNull GitRepository repository, @NotNull GitResetMode mode, @NotNull String target, + @NotNull GitLineHandlerListener... listeners) { + return reset(repository, mode.getArgument(), target, listeners); } @Override @NotNull public GitCommandResult resetMerge(@NotNull GitRepository repository, @Nullable String revision) { + return reset(repository, "--merge", revision); + } + + @NotNull + private static GitCommandResult reset(@NotNull GitRepository repository, @NotNull String argument, @Nullable String target, + @NotNull GitLineHandlerListener... listeners) { final GitLineHandler handler = new GitLineHandler(repository.getProject(), repository.getRoot(), GitCommand.RESET); - handler.addParameters("--merge"); - if (revision != null) { - handler.addParameters(revision); + handler.addParameters(argument); + if (target != null) { + handler.addParameters(target); } + addListeners(handler, listeners); return run(handler); } diff --git a/plugins/git4idea/src/git4idea/commands/GitLocalChangesWouldBeOverwrittenDetector.java b/plugins/git4idea/src/git4idea/commands/GitLocalChangesWouldBeOverwrittenDetector.java index b62f12806761..e9d8df89614a 100644 --- a/plugins/git4idea/src/git4idea/commands/GitLocalChangesWouldBeOverwrittenDetector.java +++ b/plugins/git4idea/src/git4idea/commands/GitLocalChangesWouldBeOverwrittenDetector.java @@ -40,6 +40,13 @@ public class GitLocalChangesWouldBeOverwrittenDetector extends GitMessageWithFil ".*Your local changes to '(.*)' would be overwritten by merge.*" ); + private static final Pattern[] RESET_PATTERNS = new Pattern[]{Pattern.compile( + ".*Entry '(.*)' not uptodate. Cannot merge.*" + ), + Pattern.compile( + ".*Entry '(.*)' would be overwritten by merge.*" + )}; + // common for checkout and merge public static final Event NEW_PATTERN = new Event( "Your local changes to the following files would be overwritten by", @@ -49,17 +56,18 @@ public class GitLocalChangesWouldBeOverwrittenDetector extends GitMessageWithFil public enum Operation { CHECKOUT(OLD_CHECKOUT_PATTERN), - MERGE(OLD_MERGE_PATTERN); + MERGE(OLD_MERGE_PATTERN), + RESET(RESET_PATTERNS); - @NotNull private final Pattern myPattern; + @NotNull private final Pattern[] myPatterns; - Operation(@NotNull Pattern pattern) { - myPattern = pattern; + Operation(@NotNull Pattern... patterns) { + myPatterns = patterns; } @NotNull - public Pattern getPattern() { - return myPattern; + Pattern[] getPatterns() { + return myPatterns; } } @@ -71,10 +79,13 @@ public class GitLocalChangesWouldBeOverwrittenDetector extends GitMessageWithFil @Override public void onLineAvailable(@NotNull String line, @NotNull Key outputType) { super.onLineAvailable(line, outputType); - Matcher m = myOperation.getPattern().matcher(line); - if (m.matches()) { - myMessageDetected = true; - myAffectedFiles.add(m.group(1)); + for (Pattern pattern : myOperation.getPatterns()) { + Matcher m = pattern.matcher(line); + if (m.matches()) { + myMessageDetected = true; + myAffectedFiles.add(m.group(1)); + break; + } } } } diff --git a/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java b/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java index 982270421968..4d1c13415ec2 100644 --- a/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitSSHGUIHandler.java @@ -16,7 +16,6 @@ package git4idea.commands; import com.intellij.ide.passwordSafe.ui.PasswordSafePromptDialog; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; @@ -39,17 +38,9 @@ import java.util.concurrent.atomic.AtomicReference; */ public class GitSSHGUIHandler { @Nullable private final Project myProject; - @Nullable private final ModalityState myState; - /** - * A constructor - * - * @param project a project to use - * @param state modality state using which any prompts initiated by the git process should be shown in the UI. - */ - GitSSHGUIHandler(@Nullable Project project, @Nullable ModalityState state) { + GitSSHGUIHandler(@Nullable Project project) { myProject = project; - myState = state; } public boolean verifyServerHostKey(final String hostname, @@ -76,7 +67,7 @@ public class GitSSHGUIHandler { @Nullable public String askPassphrase(final String username, final String keyPath, boolean resetPassword, final String lastError) { String error = processLastError(resetPassword, lastError); - return PasswordSafePromptDialog.askPassphrase(myProject, myState, GitBundle.getString("ssh.ask.passphrase.title"), + return PasswordSafePromptDialog.askPassphrase(myProject, GitBundle.getString("ssh.ask.passphrase.title"), GitBundle.message("ssh.askPassphrase.message", keyPath, username), GitSSHGUIHandler.class, "PASSPHRASE:" + keyPath, resetPassword, error ); @@ -165,7 +156,7 @@ public class GitSSHGUIHandler { @Nullable public String askPassword(final String username, boolean resetPassword, final String lastError) { String error = processLastError(resetPassword, lastError); - return PasswordSafePromptDialog.askPassword(myProject, myState, GitBundle.getString("ssh.password.title"), + return PasswordSafePromptDialog.askPassword(myProject, GitBundle.getString("ssh.password.title"), GitBundle.message("ssh.password.message", username), GitSSHGUIHandler.class, "PASSWORD:" + username, resetPassword, error); } diff --git a/plugins/git4idea/src/git4idea/commands/GitTask.java b/plugins/git4idea/src/git4idea/commands/GitTask.java index c22ce07819c9..79f8e33ef55e 100644 --- a/plugins/git4idea/src/git4idea/commands/GitTask.java +++ b/plugins/git4idea/src/git4idea/commands/GitTask.java @@ -324,7 +324,6 @@ public class GitTask { @Override public final void run(@NotNull ProgressIndicator indicator) { - myHandler.setModalityState(indicator.getModalityState()); myDelegate.run(indicator); } diff --git a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java index 4f74f7ca94f3..1b5860631e59 100644 --- a/plugins/git4idea/src/git4idea/config/GitVcsSettings.java +++ b/plugins/git4idea/src/git4idea/config/GitVcsSettings.java @@ -19,6 +19,7 @@ import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; import com.intellij.util.ArrayUtil; +import git4idea.reset.GitResetMode; import git4idea.ui.branch.GitBranchSyncSetting; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -61,6 +62,7 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S public String RECENT_COMMON_BRANCH = null; public boolean AUTO_COMMIT_ON_CHERRY_PICK = false; public boolean WARN_ABOUT_CRLF = true; + public GitResetMode RESET_MODE = null; } public GitVcsSettings(GitVcsApplicationSettings appSettings) { @@ -177,6 +179,15 @@ public class GitVcsSettings implements PersistentStateComponent<GitVcsSettings.S myState.WARN_ABOUT_CRLF = warn; } + @Nullable + public GitResetMode getResetMode() { + return myState.RESET_MODE; + } + + public void setResetMode(@NotNull GitResetMode mode) { + myState.RESET_MODE = mode; + } + /** * Provides migration from project settings. * This method is to be removed in IDEA 13: it should be moved to {@link GitVcsApplicationSettings} diff --git a/plugins/git4idea/src/git4idea/history/GitDiffFromHistoryHandler.java b/plugins/git4idea/src/git4idea/history/GitDiffFromHistoryHandler.java index 87edd30ae077..a6488d4ce3d0 100644 --- a/plugins/git4idea/src/git4idea/history/GitDiffFromHistoryHandler.java +++ b/plugins/git4idea/src/git4idea/history/GitDiffFromHistoryHandler.java @@ -22,25 +22,22 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogBuilder; import com.intellij.openapi.ui.MessageType; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; -import com.intellij.openapi.util.Couple; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ContentRevision; -import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; -import com.intellij.openapi.vcs.history.CurrentRevision; +import com.intellij.openapi.vcs.history.BaseDiffFromHistoryHandler; import com.intellij.openapi.vcs.history.DiffFromHistoryHandler; import com.intellij.openapi.vcs.history.VcsFileRevision; -import com.intellij.openapi.vcs.history.VcsHistoryUtil; import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.ArrayUtil; import com.intellij.util.Consumer; +import com.intellij.util.containers.ContainerUtil; import git4idea.GitFileRevision; import git4idea.GitRevisionNumber; import git4idea.GitUtil; @@ -67,71 +64,59 @@ import java.util.List; * * @author Kirill Likhodedov */ -public class GitDiffFromHistoryHandler implements DiffFromHistoryHandler { +public class GitDiffFromHistoryHandler extends BaseDiffFromHistoryHandler<GitFileRevision> { private static final Logger LOG = Logger.getInstance(GitDiffFromHistoryHandler.class); - @NotNull private final Project myProject; @NotNull private final Git myGit; @NotNull private final GitRepositoryManager myRepositoryManager; public GitDiffFromHistoryHandler(@NotNull Project project) { - myProject = project; + super(project); myGit = ServiceManager.getService(project, Git.class); myRepositoryManager = GitUtil.getRepositoryManager(project); } @Override - public void showDiffForOne(@NotNull AnActionEvent e, @NotNull FilePath filePath, - @NotNull VcsFileRevision previousRevision, @NotNull VcsFileRevision revision) { + public void showDiffForOne(@NotNull AnActionEvent e, + @NotNull FilePath filePath, + @NotNull VcsFileRevision previousRevision, + @NotNull VcsFileRevision revision) { GitFileRevision rev = (GitFileRevision)revision; Collection<String> parents = rev.getParents(); if (parents.size() < 2) { - doShowDiff(filePath, previousRevision, revision, false); + super.showDiffForOne(e, filePath, previousRevision, revision); } else { // merge showDiffForMergeCommit(e, filePath, rev, parents); } } + @NotNull @Override - public void showDiffForTwo(@NotNull FilePath filePath, @NotNull VcsFileRevision revision1, @NotNull VcsFileRevision revision2) { - doShowDiff(filePath, revision1, revision2, true); - } + protected List<Change> getChangesBetweenRevisions(@NotNull FilePath path, @NotNull GitFileRevision rev1, @Nullable GitFileRevision rev2) + throws VcsException { + GitRepository repository = getRepository(path); + String hash1 = rev1.getHash(); + String hash2 = rev2 != null ? rev2.getHash() : null; - private void doShowDiff(@NotNull FilePath filePath, @NotNull VcsFileRevision revision1, @NotNull VcsFileRevision revision2, - boolean autoSort) { - if (!filePath.isDirectory()) { - VcsHistoryUtil.showDifferencesInBackground(myProject, filePath, revision1, revision2, autoSort); - } - else if (revision2 instanceof CurrentRevision) { - GitFileRevision left = (GitFileRevision)revision1; - showDiffForDirectory(filePath, left.getHash(), null); - } - else if (revision1.equals(VcsFileRevision.NULL)) { - GitFileRevision right = (GitFileRevision)revision2; - showDiffForDirectory(filePath, null, right.getHash()); - } - else { - GitFileRevision left = (GitFileRevision)revision1; - GitFileRevision right = (GitFileRevision)revision2; - if (autoSort) { - Couple<VcsFileRevision> pair = VcsHistoryUtil.sortRevisions(revision1, revision2); - left = (GitFileRevision)pair.first; - right = (GitFileRevision)pair.second; - } - showDiffForDirectory(filePath, left.getHash(), right.getHash()); - } + return ContainerUtil + .newArrayList(GitChangeUtils.getDiff(repository.getProject(), repository.getRoot(), hash1, hash2, Collections.singletonList(path))); } - private void showDiffForDirectory(@NotNull final FilePath path, @Nullable final String hash1, @Nullable final String hash2) { + @NotNull + @Override + protected List<Change> getAffectedChanges(@NotNull FilePath path, @NotNull GitFileRevision rev) throws VcsException { GitRepository repository = getRepository(path); - calculateDiffInBackground(repository, path, hash1, hash2, new Consumer<List<Change>>() { - @Override - public void consume(List<Change> changes) { - showDirDiffDialog(path, hash1, hash2, changes); - } - }); + + return ContainerUtil.newArrayList( + GitChangeUtils.getRevisionChanges(repository.getProject(), repository.getRoot(), rev.getHash(), false, true, true).getChanges()); + } + + @NotNull + @Override + protected String getPresentableName(@NotNull GitFileRevision revision) { + return GitUtil.getShortHash(revision.getHash()); } @NotNull @@ -141,63 +126,6 @@ public class GitDiffFromHistoryHandler implements DiffFromHistoryHandler { return repository; } - // hash1 == null => hash2 is the initial commit - // hash2 == null => comparing hash1 with local - private void calculateDiffInBackground(@NotNull final GitRepository repository, @NotNull final FilePath path, - @Nullable final String hash1, @Nullable final String hash2, - final Consumer<List<Change>> successHandler) { - new Task.Backgroundable(myProject, "Comparing revisions...") { - private List<Change> myChanges; - @Override - public void run(@NotNull ProgressIndicator indicator) { - try { - if (hash1 != null) { - // diff - myChanges = new ArrayList<Change>(GitChangeUtils.getDiff(repository.getProject(), repository.getRoot(), hash1, hash2, - Collections.singletonList(path))); - } - else { - // show the initial commit - myChanges = new ArrayList<Change>(GitChangeUtils.getRevisionChanges(repository.getProject(), repository.getRoot(), hash2, false, - true, true).getChanges()); - } - } - catch (VcsException e) { - showError(e, "Error during requesting diff for directory"); - } - } - - @Override - public void onSuccess() { - successHandler.consume(myChanges); - } - }.queue(); - } - - private void showDirDiffDialog(@NotNull FilePath path, @Nullable String hash1, @Nullable String hash2, @NotNull List<Change> diff) { - DialogBuilder dialogBuilder = new DialogBuilder(myProject); - String title; - if (hash2 != null) { - if (hash1 != null) { - title = String.format("Difference between %s and %s in %s", GitUtil.getShortHash(hash1), GitUtil.getShortHash(hash2), path.getName()); - } - else { - title = String.format("Initial commit %s in %s", GitUtil.getShortHash(hash2), path.getName()); - } - } - else { - LOG.assertTrue(hash1 != null, "hash1 and hash2 can't both be null. Path: " + path); - title = String.format("Difference between %s and local version in %s", GitUtil.getShortHash(hash1), path.getName()); - } - dialogBuilder.setTitle(title); - dialogBuilder.setActionDescriptors(new DialogBuilder.ActionDescriptor[] { new DialogBuilder.CloseDialogAction()}); - final ChangesBrowser changesBrowser = new ChangesBrowser(myProject, null, diff, null, false, true, - null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); - changesBrowser.setChangesToDisplay(diff); - dialogBuilder.setCenterPanel(changesBrowser); - dialogBuilder.showNotModal(); - } - private void showDiffForMergeCommit(@NotNull final AnActionEvent event, @NotNull final FilePath filePath, @NotNull final GitFileRevision rev, @NotNull final Collection<String> parents) { @@ -299,12 +227,6 @@ public class GitDiffFromHistoryHandler implements DiffFromHistoryHandler { return makeRevisionFromHash(currentRevisionPath, parentHash); } - - private void showError(VcsException e, String logMessage) { - LOG.info(logMessage, e); - VcsBalloonProblemNotifier.showOverVersionControlView(this.myProject, e.getMessage(), MessageType.ERROR); - } - private void showPopup(@NotNull AnActionEvent event, @NotNull GitFileRevision rev, @NotNull FilePath filePath, @NotNull Collection<GitFileRevision> parents) { ActionGroup parentActions = createActionGroup(rev, filePath, parents); diff --git a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java index 114b4beb5435..8273c3e1abdc 100644 --- a/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java +++ b/plugins/git4idea/src/git4idea/history/GitHistoryUtils.java @@ -520,9 +520,19 @@ public class GitHistoryUtils { @NotNull VirtualFile root, @NotNull final Consumer<VcsUser> userRegistry, @NotNull List<String> parameters) throws VcsException { + List<TimedVcsCommit> collector = ContainerUtil.newArrayList(); + readCommits(project, root, userRegistry, parameters, new CollectConsumer<TimedVcsCommit>(collector)); + return collector; + } + + public static void readCommits(@NotNull final Project project, + @NotNull VirtualFile root, + @NotNull final Consumer<VcsUser> userRegistry, + @NotNull List<String> parameters, + @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException { final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project); if (factory == null) { - return Collections.emptyList(); + return; } final int COMMIT_BUFFER = 1000; @@ -536,8 +546,6 @@ public class GitHistoryUtils { h.addParameters(parameters); h.endOptions(); - final List<TimedVcsCommit> commits = ContainerUtil.newArrayList(); - final StringBuilder record = new StringBuilder(); final AtomicInteger records = new AtomicInteger(); final Ref<VcsException> ex = new Ref<VcsException>(); @@ -560,7 +568,10 @@ public class GitHistoryUtils { afterParseRemainder = line.substring(recordEnd + 1); } if (afterParseRemainder != null && records.incrementAndGet() > COMMIT_BUFFER) { // null means can't parse now - commits.addAll(parseCommit(parser, record, userRegistry, factory)); + List<TimedVcsCommit> commits = parseCommit(parser, record, userRegistry, factory); + for (TimedVcsCommit commit : commits) { + commitConsumer.consume(commit); + } record.setLength(0); record.append(afterParseRemainder); } @@ -573,7 +584,10 @@ public class GitHistoryUtils { @Override public void processTerminated(int exitCode) { try { - commits.addAll(parseCommit(parser, record, userRegistry, factory)); + List<TimedVcsCommit> commits = parseCommit(parser, record, userRegistry, factory); + for (TimedVcsCommit commit : commits) { + commitConsumer.consume(commit); + } } catch (Exception e) { ex.set(new VcsException(e)); @@ -589,7 +603,6 @@ public class GitHistoryUtils { if (!ex.isNull()) { throw ex.get(); } - return commits; } @NotNull diff --git a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties index 79e7f70df250..03803fbf985c 100644 --- a/plugins/git4idea/src/git4idea/i18n/GitBundle.properties +++ b/plugins/git4idea/src/git4idea/i18n/GitBundle.properties @@ -491,9 +491,9 @@ git.executable.filechooser.description=Specify the full path to Git executable git.push.active.close=Close git.unstash.clear.confirmation.message=Remove all stashes? This cannot be undone. -git.unstash.clear.confirmation.title=Remove all stashes? +git.unstash.clear.confirmation.title=Remove All Stashes? git.unstash.drop.confirmation.message=<html>Do you want to remove {0}?<br/>"{1}"</html> -git.unstash.drop.confirmation.title=Remove stash {0}? +git.unstash.drop.confirmation.title=Remove Stash {0}? branch.delete.not_fully_merged.description=The branch <code><b>{0}</b></code> is not fully merged to the branch <code><b>{1}</b></code>.<br/>Below is the list of unmerged commits. branch.delete.not_fully_merged.description.not_on_branch=You are currently not on the branch (<code>{1}</code>). <br>\ diff --git a/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java b/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java index e469e61ca315..054ed9f90b48 100644 --- a/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java +++ b/plugins/git4idea/src/git4idea/log/GitBekParentFixer.java @@ -27,49 +27,34 @@ import org.jetbrains.annotations.Nullable; import java.util.*; class GitBekParentFixer { - @NotNull - private final static String MAGIC_TEXT = "Merge remote"; - @NotNull - private final VcsLogFilterCollection MAGIC_FILTER = createVcsLogFilterCollection(); + @NotNull private static final String MAGIC_TEXT = "Merge remote"; + @NotNull private static final VcsLogFilterCollection MAGIC_FILTER = createVcsLogFilterCollection(); - @NotNull - private final VirtualFile myRoot; - @NotNull - private final GitLogProvider myGitLogProvider; - @NotNull - private final List<TimedVcsCommit> myAllCommits; + @NotNull private final Set<Hash> myWrongCommits; - GitBekParentFixer(@NotNull VirtualFile root, @NotNull GitLogProvider gitLogProvider, @NotNull List<TimedVcsCommit> allCommits) { - myRoot = root; - myGitLogProvider = gitLogProvider; - myAllCommits = allCommits; + private GitBekParentFixer(@NotNull Set<Hash> wrongCommits) { + myWrongCommits = wrongCommits; } @NotNull - List<TimedVcsCommit> getCorrectCommits() throws VcsException { - if (!BekSorter.isBekEnabled()) - return myAllCommits; - - final Set<Hash> wrongCommits = getWrongCommits(); - return new AbstractList<TimedVcsCommit>() { - @Override - public TimedVcsCommit get(int index) { - TimedVcsCommit commit = myAllCommits.get(index); - if (!wrongCommits.contains(commit.getId())) - return commit; - - return reverseParents(commit); - } + static GitBekParentFixer prepare(@NotNull VirtualFile root, @NotNull GitLogProvider provider) throws VcsException { + if (!BekSorter.isBekEnabled()) { + return new GitBekParentFixer(Collections.<Hash>emptySet()); + } + return new GitBekParentFixer(getWrongCommits(provider, root)); + } - @Override - public int size() { - return myAllCommits.size(); - } - }; + @NotNull + TimedVcsCommit fixCommit(@NotNull TimedVcsCommit commit) { + if (!myWrongCommits.contains(commit.getId())) { + return commit; + } + return reverseParents(commit); } - private Set<Hash> getWrongCommits() throws VcsException { - List<TimedVcsCommit> commitsMatchingFilter = myGitLogProvider.getCommitsMatchingFilter(myRoot, MAGIC_FILTER, -1); + @NotNull + private static Set<Hash> getWrongCommits(@NotNull GitLogProvider provider, @NotNull VirtualFile root) throws VcsException { + List<TimedVcsCommit> commitsMatchingFilter = provider.getCommitsMatchingFilter(root, MAGIC_FILTER, -1); return ContainerUtil.map2Set(commitsMatchingFilter, new Function<TimedVcsCommit, Hash>() { @Override public Hash fun(TimedVcsCommit timedVcsCommit) { diff --git a/plugins/git4idea/src/git4idea/log/GitLogProvider.java b/plugins/git4idea/src/git4idea/log/GitLogProvider.java index ecc4709be5d3..435313fa5c7d 100644 --- a/plugins/git4idea/src/git4idea/log/GitLogProvider.java +++ b/plugins/git4idea/src/git4idea/log/GitLogProvider.java @@ -154,18 +154,23 @@ public class GitLogProvider implements VcsLogProvider { }); } - @NotNull @Override - public List<TimedVcsCommit> readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry) throws VcsException { + public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry, + @NotNull final Consumer<TimedVcsCommit> commitConsumer) throws VcsException { if (!isRepositoryReady(root)) { - return Collections.emptyList(); + return; } List<String> parameters = new ArrayList<String>(GitHistoryUtils.LOG_ALL); parameters.add("--sparse"); - List<TimedVcsCommit> timedVcsCommits = GitHistoryUtils.readCommits(myProject, root, userRegistry, parameters); - return new GitBekParentFixer(root, this, timedVcsCommits).getCorrectCommits(); + final GitBekParentFixer parentFixer = GitBekParentFixer.prepare(root, this); + GitHistoryUtils.readCommits(myProject, root, userRegistry, parameters, new Consumer<TimedVcsCommit>() { + @Override + public void consume(TimedVcsCommit commit) { + commitConsumer.consume(parentFixer.fixCommit(commit)); + } + }); } @NotNull diff --git a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java index f9d8085cfab8..68b16164b335 100644 --- a/plugins/git4idea/src/git4idea/merge/GitPullDialog.java +++ b/plugins/git4idea/src/git4idea/merge/GitPullDialog.java @@ -44,66 +44,23 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -/** - * Git pull dialog - */ public class GitPullDialog extends DialogWrapper { private static final Logger LOG = Logger.getInstance(GitPullDialog.class); - /** - * root panel - */ private JPanel myPanel; - /** - * The selected git root - */ private JComboBox myGitRoot; - /** - * Current branch label - */ private JLabel myCurrentBranch; - /** - * The merge strategy - */ private JComboBox myStrategy; - /** - * No commit option - */ private JCheckBox myNoCommitCheckBox; - /** - * Squash commit option - */ private JCheckBox mySquashCommitCheckBox; - /** - * No fast forward option - */ private JCheckBox myNoFastForwardCheckBox; - /** - * Add log info to commit option - */ private JCheckBox myAddLogInformationCheckBox; - /** - * Selected remote option - */ private JComboBox myRemote; - /** - * The branch chooser - */ private ElementsChooser<String> myBranchChooser; - /** - * The context project - */ private final Project myProject; private final GitRepositoryManager myRepositoryManager; - /** - * A constructor - * - * @param project a project to select - * @param roots a git repository roots for the project - * @param defaultRoot a guessed default root - */ public GitPullDialog(Project project, List<VirtualFile> roots, VirtualFile defaultRoot) { super(project, true); setTitle(GitBundle.getString("pull.title")); @@ -138,9 +95,6 @@ public class GitPullDialog extends DialogWrapper { init(); } - /** - * Validate dialog and enable buttons - */ private void validateDialog() { String selectedRemote = getRemote(); if (StringUtil.isEmptyOrSpaces(selectedRemote)) { @@ -150,9 +104,6 @@ public class GitPullDialog extends DialogWrapper { setOKActionEnabled(myBranchChooser.getMarkedElements().size() != 0); } - /** - * @return a pull handler configured according to dialog options - */ public GitLineHandler makeHandler(@NotNull String url) { GitLineHandler h = new GitLineHandler(myProject, gitRoot(), GitCommand.PULL); // ignore merge failure for the pull @@ -232,9 +183,6 @@ public class GitPullDialog extends DialogWrapper { return branch.getName().startsWith(remote + "/"); } - /** - * Update remotes for the git root - */ private void updateRemotes() { GitRepository repository = getRepository(); if (repository == null) { @@ -331,39 +279,23 @@ public class GitPullDialog extends DialogWrapper { }; } - /** - * @return a currently selected git root - */ public VirtualFile gitRoot() { return (VirtualFile)myGitRoot.getSelectedItem(); } - - /** - * Create branch chooser - */ private void createUIComponents() { myBranchChooser = new ElementsChooser<String>(true); } - /** - * {@inheritDoc} - */ protected JComponent createCenterPanel() { return myPanel; } - /** - * {@inheritDoc} - */ @Override protected String getDimensionServiceKey() { return getClass().getName(); } - /** - * {@inheritDoc} - */ @Override protected String getHelpId() { return "reference.VersionControl.Git.Pull"; diff --git a/plugins/git4idea/src/git4idea/remote/GitHttpAuthDataProvider.java b/plugins/git4idea/src/git4idea/remote/GitHttpAuthDataProvider.java index 281d69b772c3..6c0860ccf20a 100644 --- a/plugins/git4idea/src/git4idea/remote/GitHttpAuthDataProvider.java +++ b/plugins/git4idea/src/git4idea/remote/GitHttpAuthDataProvider.java @@ -15,7 +15,6 @@ */ package git4idea.remote; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.util.AuthData; import org.jetbrains.annotations.NotNull; @@ -32,7 +31,7 @@ public interface GitHttpAuthDataProvider { ExtensionPointName<GitHttpAuthDataProvider> EP_NAME = ExtensionPointName.create("Git4Idea.GitHttpAuthDataProvider"); @Nullable - AuthData getAuthData(@NotNull String url, @Nullable ModalityState modalityState); + AuthData getAuthData(@NotNull String url); void forgetPassword(@NotNull String url); diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java index 29f2c4cf3e2e..e401334416d6 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryImpl.java @@ -34,7 +34,7 @@ import java.util.Collection; /** * @author Kirill Likhodedov */ -public class GitRepositoryImpl extends RepositoryImpl implements GitRepository, Disposable { +public class GitRepositoryImpl extends RepositoryImpl implements GitRepository { @NotNull private final GitPlatformFacade myPlatformFacade; @NotNull private final GitRepositoryReader myReader; diff --git a/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java b/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java index 0cf82d9a521f..4ad12d8a121f 100644 --- a/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java +++ b/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java @@ -237,9 +237,6 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener { break; } String path = event.getPath(); - if (path == null) { - continue; - } if (totalRefreshNeeded(path)) { allChanged = true; } @@ -253,7 +250,7 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener { // if index has changed, no need to refresh specific files - we get the full status of all files if (allChanged) { - LOG.info(String.format("GitUntrackedFilesHolder: Index has changed, marking %s recursively dirty", myRoot)); + LOG.debug(String.format("GitUntrackedFilesHolder: Index has changed, marking %s recursively dirty", myRoot)); myDirtyScopeManager.dirDirtyRecursively(myRoot); synchronized (LOCK) { myReady = false; diff --git a/plugins/git4idea/src/git4idea/reset/GitNewResetDialog.java b/plugins/git4idea/src/git4idea/reset/GitNewResetDialog.java new file mode 100644 index 000000000000..5e2cb18e7c7e --- /dev/null +++ b/plugins/git4idea/src/git4idea/reset/GitNewResetDialog.java @@ -0,0 +1,144 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 git4idea.reset; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.ui.components.JBLabel; +import com.intellij.ui.components.JBRadioButton; +import com.intellij.util.ui.GridBag; +import com.intellij.util.ui.RadioButtonEnumModel; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.VcsFullCommitDetails; +import com.intellij.xml.util.XmlStringUtil; +import git4idea.GitUtil; +import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Map; + +import static com.intellij.dvcs.DvcsUtil.getShortRepositoryName; + +public class GitNewResetDialog extends DialogWrapper { + + private static final String DIALOG_ID = "git.new.reset.dialog"; + + @NotNull private final Project myProject; + @NotNull private final Map<GitRepository, VcsFullCommitDetails> myCommits; + @NotNull private final GitResetMode myDefaultMode; + @NotNull private final ButtonGroup myButtonGroup; + + private RadioButtonEnumModel<GitResetMode> myEnumModel; + + protected GitNewResetDialog(@NotNull Project project, @NotNull Map<GitRepository, VcsFullCommitDetails> commits, + @NotNull GitResetMode defaultMode) { + super(project); + myProject = project; + myCommits = commits; + myDefaultMode = defaultMode; + myButtonGroup = new ButtonGroup(); + + init(); + setTitle("Git Reset"); + setOKButtonText("Reset"); + setOKButtonMnemonic('R'); + setResizable(false); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new GridBagLayout()); + GridBag gb = new GridBag(). + setDefaultAnchor(GridBagConstraints.LINE_START). + setDefaultInsets(0, UIUtil.DEFAULT_HGAP, UIUtil.LARGE_VGAP, 0); + + String description = prepareDescription(myProject, myCommits); + panel.add(new JBLabel(XmlStringUtil.wrapInHtml(description)), gb.nextLine().next().coverLine()); + + String explanation = "This will reset the current branch head to the selected commit, <br/>" + + "and update the working tree and the index according to the selected mode:"; + panel.add(new JBLabel(XmlStringUtil.wrapInHtml(explanation), UIUtil.ComponentStyle.SMALL), gb.nextLine().next().coverLine()); + + for (GitResetMode mode : GitResetMode.values()) { + JBRadioButton button = new JBRadioButton(mode.getName()); + button.setMnemonic(mode.getName().charAt(0)); + myButtonGroup.add(button); + panel.add(button, gb.nextLine().next()); + panel.add(new JBLabel(XmlStringUtil.wrapInHtml(mode.getDescription()), UIUtil.ComponentStyle.SMALL), gb.next()); + } + + myEnumModel = RadioButtonEnumModel.bindEnum(GitResetMode.class, myButtonGroup); + myEnumModel.setSelected(myDefaultMode); + return panel; + } + + @Nullable + @Override + protected String getHelpId() { + return DIALOG_ID; + } + + @NotNull + private static String prepareDescription(@NotNull Project project, @NotNull Map<GitRepository, VcsFullCommitDetails> commits) { + if (commits.size() == 1 && !isMultiRepo(project)) { + Map.Entry<GitRepository, VcsFullCommitDetails> entry = commits.entrySet().iterator().next(); + return String.format("%s -> %s", getSourceText(entry.getKey()), getTargetText(entry.getValue())); + } + + StringBuilder desc = new StringBuilder(""); + for (Map.Entry<GitRepository, VcsFullCommitDetails> entry : commits.entrySet()) { + GitRepository repository = entry.getKey(); + VcsFullCommitDetails commit = entry.getValue(); + desc.append(String.format("%s in %s -> %s<br/>", getSourceText(repository), + getShortRepositoryName(repository), getTargetText(commit))); + } + return desc.toString(); + } + + @NotNull + private static String getTargetText(@NotNull VcsFullCommitDetails commit) { + String commitMessage = StringUtil.shortenTextWithEllipsis(commit.getSubject(), 20, 0); + return String.format("<code><b>%s</b> \"%s\"</code> by <code>%s</code>", + commit.getId().toShortString(), commitMessage, commit.getAuthor().getName()); + } + + @NotNull + private static String getSourceText(@NotNull GitRepository repository) { + String currentRevision = repository.getCurrentRevision(); + assert currentRevision != null; + String text = repository.getCurrentBranch() == null ? + "HEAD (" + GitUtil.getShortHash(currentRevision) + ")" : + repository.getCurrentBranch().getName(); + return "<b>" + text + "</b>"; + } + + private static boolean isMultiRepo(@NotNull Project project) { + return ServiceManager.getService(project, GitRepositoryManager.class).moreThanOneRoot(); + } + + @NotNull + public GitResetMode getResetMode() { + return myEnumModel.getSelected(); + } + +} diff --git a/plugins/git4idea/src/git4idea/reset/GitResetAction.java b/plugins/git4idea/src/git4idea/reset/GitResetAction.java new file mode 100644 index 000000000000..749acd7e7c7c --- /dev/null +++ b/plugins/git4idea/src/git4idea/reset/GitResetAction.java @@ -0,0 +1,65 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 git4idea.reset; + +import com.intellij.dvcs.ui.VcsLogOneCommitPerRepoAction; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.ObjectUtils; +import com.intellij.vcs.log.VcsFullCommitDetails; +import git4idea.config.GitVcsSettings; +import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +public class GitResetAction extends VcsLogOneCommitPerRepoAction<GitRepository> { + + @Nullable + @Override + protected GitRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { + return getRepoManager(project).getRepositoryForRoot(root); + } + + @Override + protected void actionPerformed(@NotNull final Project project, @NotNull final Map<GitRepository, VcsFullCommitDetails> commits) { + GitVcsSettings settings = GitVcsSettings.getInstance(project); + GitResetMode defaultMode = ObjectUtils.notNull(settings.getResetMode(), GitResetMode.getDefault()); + GitNewResetDialog dialog = new GitNewResetDialog(project, commits, defaultMode); + dialog.show(); + if (dialog.isOK()) { + final GitResetMode selectedMode = dialog.getResetMode(); + settings.setResetMode(selectedMode); + new Task.Backgroundable(project, "Git reset", false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + new GitResetOperation(project, commits, selectedMode, indicator).execute(); + } + }.queue(); + } + } + + @NotNull + private static GitRepositoryManager getRepoManager(@NotNull Project project) { + return ServiceManager.getService(project, GitRepositoryManager.class); + } + +} diff --git a/plugins/git4idea/src/git4idea/reset/GitResetMode.java b/plugins/git4idea/src/git4idea/reset/GitResetMode.java new file mode 100644 index 000000000000..c10d95707073 --- /dev/null +++ b/plugins/git4idea/src/git4idea/reset/GitResetMode.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 git4idea.reset; + +import org.jetbrains.annotations.NotNull; + +public enum GitResetMode { + + SOFT("Soft", "--soft", "Files won't change, differences will be staged for commit."), + MIXED("Mixed", "--mixed", "Files won't change, differences won't be staged."), + HARD("Hard", "--hard", "Files will be reverted to the state of the selected commit.<br/>" + + "Warning: any local changes will be lost."), + KEEP("Keep", "--keep", "Files will be reverted to the state of the selected commit,<br/>" + + "but local changes will be kept intact."); + + @NotNull private final String myName; + @NotNull private final String myArgument; + @NotNull private final String myDescription; + + GitResetMode(@NotNull String name, @NotNull String argument, @NotNull String description) { + myName = name; + myArgument = argument; + myDescription = description; + } + + @NotNull + public static GitResetMode getDefault() { + return MIXED; + } + + @NotNull + public String getName() { + return myName; + } + + @NotNull + public String getArgument() { + return myArgument; + } + + @NotNull + public String getDescription() { + return myDescription; + } + +} diff --git a/plugins/git4idea/src/git4idea/reset/GitResetOperation.java b/plugins/git4idea/src/git4idea/reset/GitResetOperation.java new file mode 100644 index 000000000000..9c66a5225a52 --- /dev/null +++ b/plugins/git4idea/src/git4idea/reset/GitResetOperation.java @@ -0,0 +1,191 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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 git4idea.reset; + +import com.intellij.dvcs.repo.RepositoryUtil; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.VcsNotifier; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Function; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.MultiMap; +import com.intellij.util.ui.UIUtil; +import com.intellij.vcs.log.VcsFullCommitDetails; +import git4idea.GitPlatformFacade; +import git4idea.GitUtil; +import git4idea.branch.GitBranchUiHandlerImpl; +import git4idea.branch.GitSmartOperationDialog; +import git4idea.commands.Git; +import git4idea.commands.GitCommandResult; +import git4idea.commands.GitLocalChangesWouldBeOverwrittenDetector; +import git4idea.repo.GitRepository; +import git4idea.util.GitPreservingProcess; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static git4idea.commands.GitLocalChangesWouldBeOverwrittenDetector.Operation.RESET; + +public class GitResetOperation { + + @NotNull private final Project myProject; + @NotNull private final Map<GitRepository, VcsFullCommitDetails> myCommits; + @NotNull private final GitResetMode myMode; + @NotNull private final ProgressIndicator myIndicator; + @NotNull private final Git myGit; + @NotNull private final VcsNotifier myNotifier; + @NotNull private final GitPlatformFacade myFacade; + @NotNull private final GitBranchUiHandlerImpl myUiHandler; + + public GitResetOperation(@NotNull Project project, @NotNull Map<GitRepository, VcsFullCommitDetails> targetCommits, + @NotNull GitResetMode mode, @NotNull ProgressIndicator indicator) { + myProject = project; + myCommits = targetCommits; + myMode = mode; + myIndicator = indicator; + myGit = ServiceManager.getService(Git.class); + myNotifier = VcsNotifier.getInstance(project); + myFacade = ServiceManager.getService(GitPlatformFacade.class); + myUiHandler = new GitBranchUiHandlerImpl(myProject, myFacade, myGit, indicator); + } + + public void execute() { + saveAllDocuments(); + GitUtil.workingTreeChangeStarted(myProject); + Map<GitRepository, GitCommandResult> results = ContainerUtil.newHashMap(); + try { + for (Map.Entry<GitRepository, VcsFullCommitDetails> entry : myCommits.entrySet()) { + GitRepository repository = entry.getKey(); + VirtualFile root = repository.getRoot(); + String target = entry.getValue().getId().asString(); + GitLocalChangesWouldBeOverwrittenDetector detector = new GitLocalChangesWouldBeOverwrittenDetector(root, RESET); + + GitCommandResult result = myGit.reset(repository, myMode, target, detector); + if (!result.success() && detector.wasMessageDetected()) { + GitCommandResult smartResult = proposeSmartReset(detector, repository, target); + if (smartResult != null) { + result = smartResult; + } + } + results.put(repository, result); + repository.update(); + VfsUtil.markDirtyAndRefresh(true, true, false, root); + } + } + finally { + GitUtil.workingTreeChangeFinished(myProject); + } + notifyResult(results); + } + + private GitCommandResult proposeSmartReset(@NotNull GitLocalChangesWouldBeOverwrittenDetector detector, + @NotNull final GitRepository repository, @NotNull final String target) { + Collection<String> absolutePaths = GitUtil.toAbsolute(repository.getRoot(), detector.getRelativeFilePaths()); + List<Change> affectedChanges = GitUtil.findLocalChangesForPaths(myProject, repository.getRoot(), absolutePaths, false); + int choice = myUiHandler.showSmartOperationDialog(myProject, affectedChanges, absolutePaths, "reset", "&Hard Reset"); + if (choice == GitSmartOperationDialog.SMART_EXIT_CODE) { + final Ref<GitCommandResult> result = Ref.create(); + new GitPreservingProcess(myProject, myFacade, myGit, Collections.singleton(repository), "reset", target, myIndicator, new Runnable() { + @Override + public void run() { + result.set(myGit.reset(repository, myMode, target)); + } + }).execute(); + return result.get(); + } + if (choice == GitSmartOperationDialog.FORCE_EXIT_CODE) { + return myGit.reset(repository, GitResetMode.HARD, target); + } + return null; + } + + private void notifyResult(@NotNull Map<GitRepository, GitCommandResult> results) { + Map<GitRepository, GitCommandResult> successes = ContainerUtil.newHashMap(); + Map<GitRepository, GitCommandResult> errors = ContainerUtil.newHashMap(); + for (Map.Entry<GitRepository, GitCommandResult> entry : results.entrySet()) { + GitCommandResult result = entry.getValue(); + GitRepository repository = entry.getKey(); + if (result.success()) { + successes.put(repository, result); + } + else { + errors.put(repository, result); + } + } + + if (errors.isEmpty()) { + myNotifier.notifySuccess("", "Reset successful"); + } + else if (!successes.isEmpty()) { + myNotifier.notifyImportantWarning("Reset partially failed", + "Reset was successful for " + joinRepos(successes.keySet()) + + "<br/>but failed for " + joinRepos(errors.keySet()) + ": <br/>" + formErrorReport(errors)); + } + else { + myNotifier.notifyError("Reset Failed", formErrorReport(errors)); + } + } + + @NotNull + private static String formErrorReport(@NotNull Map<GitRepository, GitCommandResult> errorResults) { + MultiMap<String, GitRepository> grouped = groupByResult(errorResults); + if (grouped.size() == 1) { + return "<code>" + grouped.keySet().iterator().next() + "</code>"; + } + return StringUtil.join(grouped.entrySet(), new Function<Map.Entry<String, Collection<GitRepository>>, String>() { + @NotNull + @Override + public String fun(@NotNull Map.Entry<String, Collection<GitRepository>> entry) { + return joinRepos(entry.getValue()) + ":<br/><code>" + entry.getKey() + "</code>"; + } + }, "<br/>"); + } + + // to avoid duplicate error reports if they are the same for different repositories + @NotNull + private static MultiMap<String, GitRepository> groupByResult(@NotNull Map<GitRepository, GitCommandResult> results) { + MultiMap<String, GitRepository> grouped = MultiMap.create(); + for (Map.Entry<GitRepository, GitCommandResult> entry : results.entrySet()) { + grouped.putValue(entry.getValue().getErrorOutputAsHtmlString(), entry.getKey()); + } + return grouped; + } + + @NotNull + private static String joinRepos(@NotNull Collection<GitRepository> repositories) { + return StringUtil.join(RepositoryUtil.sortRepositories(repositories), ", "); + } + + private static void saveAllDocuments() { + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + FileDocumentManager.getInstance().saveAllDocuments(); + } + }); + } + +} diff --git a/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java b/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java index 9b13bb6cdb65..eccaa446b0ed 100644 --- a/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java +++ b/plugins/git4idea/src/git4idea/ui/GitUnstashDialog.java @@ -72,65 +72,25 @@ import java.util.concurrent.atomic.AtomicBoolean; * The unstash dialog */ public class GitUnstashDialog extends DialogWrapper { - /** - * Git root selector - */ private JComboBox myGitRootComboBox; - /** - * The current branch label - */ private JLabel myCurrentBranch; - /** - * The view stash button - */ private JButton myViewButton; - /** - * The drop stash button - */ private JButton myDropButton; - /** - * The clear stashes button - */ private JButton myClearButton; - /** - * The pop stash checkbox - */ private JCheckBox myPopStashCheckBox; - /** - * The branch text field - */ private JTextField myBranchTextField; - /** - * The root panel of the dialog - */ private JPanel myPanel; - /** - * The stash list - */ private JList myStashList; - /** - * If this checkbox is selected, the index is reinstated as well as working tree - */ private JCheckBox myReinstateIndexCheckBox; /** * Set of branches for the current root */ private final HashSet<String> myBranches = new HashSet<String>(); - /** - * The project - */ private final Project myProject; private GitVcs myVcs; private static final Logger LOG = Logger.getInstance(GitUnstashDialog.class); - /** - * A constructor - * - * @param project the project - * @param roots the list of the roots - * @param defaultRoot the default root to select - */ public GitUnstashDialog(final Project project, final List<VirtualFile> roots, final VirtualFile defaultRoot) { super(project, true); setModal(false); @@ -310,9 +270,6 @@ public class GitUnstashDialog extends DialogWrapper { setOKActionEnabled(true); } - /** - * Refresh stash list - */ private void refreshStashList() { final DefaultListModel listModel = (DefaultListModel)myStashList.getModel(); listModel.clear(); @@ -334,16 +291,10 @@ public class GitUnstashDialog extends DialogWrapper { myStashList.setSelectedIndex(0); } - /** - * @return the selected git root - */ private VirtualFile getGitRoot() { return (VirtualFile)myGitRootComboBox.getSelectedItem(); } - /** - * @return unstash handler - */ private GitLineHandler handler() { GitLineHandler h = new GitLineHandler(myProject, getGitRoot(), GitCommand.STASH); String branch = myBranchTextField.getText(); @@ -361,32 +312,19 @@ public class GitUnstashDialog extends DialogWrapper { return h; } - /** - * @return selected stash - * @throws NullPointerException if no stash is selected - */ private StashInfo getSelectedStash() { return (StashInfo)myStashList.getSelectedValue(); } - /** - * {@inheritDoc} - */ protected JComponent createCenterPanel() { return myPanel; } - /** - * {@inheritDoc} - */ @Override protected String getDimensionServiceKey() { return getClass().getName(); } - /** - * {@inheritDoc} - */ @Override protected String getHelpId() { return "reference.VersionControl.Git.Unstash"; @@ -418,6 +356,7 @@ public class GitUnstashDialog extends DialogWrapper { final Ref<GitCommandResult> result = Ref.create(); ProgressManager.getInstance().run(new Task.Modal(h.project(), GitBundle.getString("unstash.unstashing"), false) { public void run(@NotNull final ProgressIndicator indicator) { + indicator.setIndeterminate(true); h.addLineListener(new GitHandlerUtil.GitLineHandlerListenerProgress(indicator, h, "stash", false)); Git git = ServiceManager.getService(Git.class); result.set(git.runCommand(new Computable.PredefinedValueComputable<GitLineHandler>(h))); diff --git a/plugins/git4idea/src/git4idea/ui/branch/GitBranchWidget.java b/plugins/git4idea/src/git4idea/ui/branch/GitBranchWidget.java index 80074fb64a28..4d3497fae299 100644 --- a/plugins/git4idea/src/git4idea/ui/branch/GitBranchWidget.java +++ b/plugins/git4idea/src/git4idea/ui/branch/GitBranchWidget.java @@ -136,7 +136,7 @@ public class GitBranchWidget extends EditorBasedWidget implements StatusBarWidge @Override public void run() { Project project = getProject(); - if (project == null) { + if (project == null || project.isDisposed()) { emptyTextAndTooltip(); return; } diff --git a/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java b/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java index 4315e65227a3..08c5103007d2 100644 --- a/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java +++ b/plugins/git4idea/src/git4idea/update/GitMergeUpdater.java @@ -19,15 +19,21 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeListManager; +import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.LocalChangeList; import com.intellij.openapi.vcs.changes.ui.ChangeListViewerDialog; import com.intellij.openapi.vcs.update.UpdatedFiles; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import git4idea.GitUtil; import git4idea.branch.GitBranchPair; @@ -173,9 +179,14 @@ public class GitMergeUpdater extends GitUpdater { final Collection<String> remotelyChanged = GitUtil.getPathsDiffBetweenRefs(ServiceManager.getService(Git.class), repository, currentBranch, remoteBranch); final List<File> locallyChanged = myChangeListManager.getAffectedPaths(); - for (File localPath : locallyChanged) { - if (remotelyChanged.contains(FilePathsHelper.convertPath(localPath.getPath()))) { - // found a file which was changed locally and remotely => need to save + for (final File localPath : locallyChanged) { + if (ContainerUtil.exists(remotelyChanged, new Condition<String>() { + @Override + public boolean value(String remotelyChangedPath) { + return FileUtil.pathsEqual(localPath.getPath(), remotelyChangedPath); + } + })) { + // found a file which was changed locally and remotely => need to save return true; } } diff --git a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy index 35acc41fc3cc..9a2bad2ad663 100644 --- a/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy +++ b/plugins/git4idea/tests/git4idea/branch/GitBranchWorkerTest.groovy @@ -14,16 +14,14 @@ * limitations under the License. */ package git4idea.branch -import com.intellij.dvcs.test.MockVirtualFile + import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.util.ProgressIndicatorBase import com.intellij.openapi.project.Project import com.intellij.openapi.ui.DialogWrapper import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vcs.FilePathImpl import com.intellij.openapi.vcs.changes.Change -import com.intellij.openapi.vcs.changes.CurrentContentRevision import com.intellij.openapi.vfs.VirtualFile import com.intellij.util.Function import com.intellij.util.LineSeparator @@ -35,12 +33,11 @@ import git4idea.config.GitVersionSpecialty import git4idea.repo.GitRepository import git4idea.test.GitPlatformTest import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable import java.util.regex.Matcher -import static com.intellij.openapi.vcs.Executor.* -import static git4idea.test.GitExecutor.cd -import static git4idea.test.GitExecutor.git +import static git4idea.test.GitExecutor.* import static git4idea.test.GitScenarios.* class GitBranchWorkerTest extends GitPlatformTest { @@ -248,7 +245,7 @@ class GitBranchWorkerTest extends GitPlatformTest { List<Change> changes = null; checkoutOrMerge(operation, "feature", [ - showSmartOperationDialog: { Project p, List<Change> cs, Collection<String> paths, String op, boolean force -> + showSmartOperationDialog: { Project p, List<Change> cs, Collection<String> paths, String op, String force -> changes = cs DialogWrapper.CANCEL_EXIT_CODE } @@ -270,17 +267,6 @@ class GitBranchWorkerTest extends GitPlatformTest { return !GitVersionSpecialty.OLD_STYLE_OF_UNTRACKED_AND_LOCAL_CHANGES_WOULD_BE_OVERWRITTEN.existsIn(GitVersion.parse(git("version"))); } - Change[] changesFromFiles(Collection<String> paths) { - paths.collect { - toChange(it) - } - } - - Change toChange(String relPath) { - // we don't care about the before revision - new Change(null, CurrentContentRevision.create(new FilePathImpl(new MockVirtualFile(myProjectRoot + "/" + relPath)))) - } - public void "test agree to smart checkout should smart checkout"() { def localChanges = agree_to_smart_operation("checkout", "Checked out <b><code>feature</code></b>") @@ -345,7 +331,7 @@ class GitBranchWorkerTest extends GitPlatformTest { prepareLocalChangesOverwrittenBy(myUltimate) checkoutOrMerge(operation, "feature", [ - showSmartOperationDialog: { Project p, List<Change> cs, Collection<String> paths, String op, boolean f + showSmartOperationDialog: { Project p, List<Change> cs, Collection<String> paths, String op, String force -> GitSmartOperationDialog.CANCEL_EXIT_CODE }, ] as GitBranchUiHandler ) @@ -371,7 +357,7 @@ class GitBranchWorkerTest extends GitPlatformTest { def rollbackMsg = null checkoutOrMerge(operation, "feature", [ showSmartOperationDialog : { - Project p, List<Change> cs, Collection<String> paths, String op, boolean f -> GitSmartOperationDialog.CANCEL_EXIT_CODE + Project p, List<Change> cs, Collection<String> paths, String op, String f -> GitSmartOperationDialog.CANCEL_EXIT_CODE }, notifyErrorWithRollbackProposal: { String t, String m, String rp -> rollbackMsg = m; false } ] as GitBranchUiHandler ) @@ -384,7 +370,7 @@ class GitBranchWorkerTest extends GitPlatformTest { prepareLocalChangesOverwrittenBy(myUltimate) def uiHandler = [ - showSmartOperationDialog: { Project p, List<Change> cs, Collection<String> paths, String op, boolean force -> + showSmartOperationDialog: { Project p, List<Change> cs, Collection<String> paths, String op, String force -> GitSmartOperationDialog.FORCE_EXIT_CODE; }, ] as GitBranchUiHandler @@ -611,6 +597,39 @@ class GitBranchWorkerTest extends GitPlatformTest { assertEquals "Merge in ultimate should have been reset", ultimateTipAfterMerge, tip(myUltimate) } + public void test_checkout_in_detached_head() { + cd(myCommunity); + touch("file.txt", "some content"); + add("file.txt"); + commit("msg"); + git(myCommunity, "checkout HEAD^"); + + checkoutBranch("master", []); + assertCurrentBranch("master"); + } + + // inspired by IDEA-127472 + public void test_checkout_to_common_branch_when_branches_have_diverged() { + branchWithCommit(myUltimate, "feature", "feature-file.txt", "feature_content", false); + branchWithCommit(myCommunity, "newbranch", "newbranch-file.txt", "newbranch_content", false); + checkoutBranch("master", []) + assertCurrentBranch("master"); + } + + public void test_rollback_checkout_from_diverged_branches_should_return_to_proper_branches() { + branchWithCommit(myUltimate, "feature", "feature-file.txt", "feature_content", false); + branchWithCommit(myCommunity, "newbranch", "newbranch-file.txt", "newbranch_content", false); + unmergedFiles(myContrib) + + checkoutBranch "master", [ + showUnmergedFilesMessageWithRollback: { String s1, String s2 -> true }, + ] + + assertCurrentBranch(myUltimate, "feature"); + assertCurrentBranch(myCommunity, "newbranch"); + assertCurrentBranch(myContrib, "master"); + } + static def assertCurrentBranch(GitRepository repository, String name) { def curBranch = git(repository, "branch").split("\n").find { it -> it.contains("*") }.replace('*', ' ').trim() assertEquals("Current branch is incorrect in ${repository}", name, curBranch) @@ -716,7 +735,7 @@ class GitBranchWorkerTest extends GitPlatformTest { @NotNull List<Change> changes, @NotNull Collection<String> paths, @NotNull String operation, - boolean isForcePossible) { + @Nullable String forceButton) { GitSmartOperationDialog.SMART_EXIT_CODE } diff --git a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java index 797e0271b430..0bb67671622b 100644 --- a/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java +++ b/plugins/git4idea/tests/git4idea/log/GitLogProviderTest.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.ArrayUtil; +import com.intellij.util.CollectConsumer; import com.intellij.util.Consumer; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -84,9 +85,10 @@ public class GitLogProviderTest extends GitSingleRepoTest { prepareSomeHistory(); createTaggedBranch(); List<VcsCommitMetadata> expectedLog = log(); - @SuppressWarnings("unchecked") - List<TimedVcsCommit> actualLog = myLogProvider.readAllHashes(myProjectRoot, Consumer.EMPTY_CONSUMER); - assertOrderedEquals(expectedLog, actualLog); + List<TimedVcsCommit> collector = ContainerUtil.newArrayList(); + //noinspection unchecked + myLogProvider.readAllHashes(myProjectRoot, Consumer.EMPTY_CONSUMER, new CollectConsumer<TimedVcsCommit>(collector)); + assertOrderedEquals(expectedLog, collector); } public void test_get_current_user() throws Exception { diff --git a/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java b/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java index 707e97265267..14d88315c596 100644 --- a/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java +++ b/plugins/git4idea/tests/git4idea/log/GitRefManagerTest.java @@ -15,7 +15,7 @@ import git4idea.GitLocalBranch; import git4idea.GitRemoteBranch; import git4idea.branch.GitBranchesCollection; import git4idea.repo.*; -import git4idea.test.GitTestRepositoryManager; +import git4idea.test.GitMockRepositoryManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -145,7 +145,7 @@ public class GitRefManagerTest extends UsefulTestCase { } private static List<VcsRef> sort(final Collection<VcsRef> refs) { - final GitTestRepositoryManager manager = new GitTestRepositoryManager(); + final GitMockRepositoryManager manager = new GitMockRepositoryManager(); manager.add(new MockGitRepository() { @NotNull @Override @@ -304,5 +304,9 @@ public class GitRefManagerTest extends UsefulTestCase { public String toLogString() { throw new UnsupportedOperationException(); } + + @Override + public void dispose() { + } } } diff --git a/plugins/git4idea/tests/git4idea/test/GitExecutor.java b/plugins/git4idea/tests/git4idea/test/GitExecutor.java index 7c561c39ebc5..f1b042ae0565 100644 --- a/plugins/git4idea/tests/git4idea/test/GitExecutor.java +++ b/plugins/git4idea/tests/git4idea/test/GitExecutor.java @@ -53,11 +53,12 @@ public class GitExecutor extends Executor { printVersionTheFirstTime(); List<String> split = splitCommandInParameters(command); split.add(0, PathHolder.GIT_EXECUTABLE); - debug("# git " + command); + File workingDir = ourCurrentDir(); + debug("[" + workingDir.getName() + "] # git " + command); for (int attempt = 0; attempt < MAX_RETRIES; attempt++) { String stdout; try { - stdout = run(split, ignoreNonZeroExitCode); + stdout = run(workingDir, split, ignoreNonZeroExitCode); if (!isIndexLockFileError(stdout)) { return stdout; } @@ -97,7 +98,7 @@ public class GitExecutor extends Executor { } public static void add(@NotNull String path) { - git("add " + path); + git("add --verbose " + path); } public static void addCommit(@NotNull String message) { diff --git a/plugins/git4idea/tests/git4idea/test/GitHttpAuthTestService.java b/plugins/git4idea/tests/git4idea/test/GitHttpAuthTestService.java index b6f25e75e307..8723ce280269 100644 --- a/plugins/git4idea/tests/git4idea/test/GitHttpAuthTestService.java +++ b/plugins/git4idea/tests/git4idea/test/GitHttpAuthTestService.java @@ -15,13 +15,11 @@ */ package git4idea.test; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.project.Project; import git4idea.commands.GitCommand; import git4idea.commands.GitHttpAuthService; import git4idea.commands.GitHttpAuthenticator; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author Kirill Likhodedov @@ -61,8 +59,7 @@ public class GitHttpAuthTestService extends GitHttpAuthService { @NotNull @Override - public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @Nullable ModalityState state, @NotNull GitCommand command, - @NotNull String url) { + public GitHttpAuthenticator createAuthenticator(@NotNull Project project, @NotNull GitCommand command, @NotNull String url) { return myAuthenticator; } diff --git a/plugins/git4idea/tests/git4idea/test/GitMockRepositoryManager.java b/plugins/git4idea/tests/git4idea/test/GitMockRepositoryManager.java new file mode 100644 index 000000000000..21ed4da7bdfb --- /dev/null +++ b/plugins/git4idea/tests/git4idea/test/GitMockRepositoryManager.java @@ -0,0 +1,84 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * 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 git4idea.test; + +import com.intellij.dvcs.repo.RepositoryManager; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vfs.VirtualFile; +import git4idea.repo.GitRepository; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Kirill Likhodedov + */ +public class GitMockRepositoryManager implements RepositoryManager<GitRepository> { + private final List<GitRepository> myRepositories = new ArrayList<GitRepository>(); + + public void add(GitRepository repository) { + myRepositories.add(repository); + } + + @Override + public GitRepository getRepositoryForRoot(@Nullable VirtualFile root) { + for (GitRepository repository : myRepositories) { + if (repository.getRoot().equals(root)) { + return repository; + } + } + + return null; + } + + @Override + public GitRepository getRepositoryForFile(@NotNull VirtualFile file) { + throw new UnsupportedOperationException(); + } + + @Override + public GitRepository getRepositoryForFile(@NotNull FilePath file) { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + public List<GitRepository> getRepositories() { + return myRepositories; + } + + @Override + public boolean moreThanOneRoot() { + return myRepositories.size() > 1; + } + + @Override + public void updateRepository(VirtualFile root) { + throw new UnsupportedOperationException(); + } + + @Override + public void updateAllRepositories() { + throw new UnsupportedOperationException(); + } + + @Override + public void waitUntilInitialized() { + } + +} diff --git a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java index ef3f963c9c7e..c02ec553dd8f 100644 --- a/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java +++ b/plugins/git4idea/tests/git4idea/test/GitPlatformTest.java @@ -19,6 +19,7 @@ import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; @@ -51,19 +52,19 @@ public abstract class GitPlatformTest extends UsefulTestCase { private static final Logger LOG = Logger.getInstance(GitPlatformTest.class); - @NotNull protected Project myProject; - @NotNull protected VirtualFile myProjectRoot; - @NotNull protected String myProjectPath; - @NotNull protected GitRepositoryManager myGitRepositoryManager; - @NotNull protected GitVcsSettings myGitSettings; - @NotNull protected GitPlatformFacade myPlatformFacade; - @NotNull protected Git myGit; - @NotNull protected GitVcs myVcs; + protected Project myProject; + protected VirtualFile myProjectRoot; + protected String myProjectPath; + protected GitRepositoryManager myGitRepositoryManager; + protected GitVcsSettings myGitSettings; + protected GitPlatformFacade myPlatformFacade; + protected Git myGit; + protected GitVcs myVcs; - @NotNull protected TestDialogManager myDialogManager; - @NotNull protected TestVcsNotifier myVcsNotifier; + protected TestDialogManager myDialogManager; + protected TestVcsNotifier myVcsNotifier; - @NotNull private IdeaProjectTestFixture myProjectFixture; + private IdeaProjectTestFixture myProjectFixture; private String myTestStartedIndicator; @SuppressWarnings({"JUnitTestCaseWithNonTrivialConstructors", "UnusedDeclaration"}) @@ -86,35 +87,41 @@ public abstract class GitPlatformTest extends UsefulTestCase { throw e; } - myProject = myProjectFixture.getProject(); - myProjectRoot = myProject.getBaseDir(); - myProjectPath = myProjectRoot.getPath(); - - myGitSettings = GitVcsSettings.getInstance(myProject); - myGitSettings.getAppSettings().setPathToGit(GitExecutor.PathHolder.GIT_EXECUTABLE); - - myDialogManager = (TestDialogManager)ServiceManager.getService(DialogManager.class); - myVcsNotifier = (TestVcsNotifier)ServiceManager.getService(myProject, VcsNotifier.class); - - myGitRepositoryManager = GitUtil.getRepositoryManager(myProject); - myPlatformFacade = ServiceManager.getService(myProject, GitPlatformFacade.class); - myGit = ServiceManager.getService(myProject, Git.class); - myVcs = ObjectUtils.assertNotNull(GitVcs.getInstance(myProject)); - myVcs.doActivate(); - - GitTestUtil.assumeSupportedGitVersion(myVcs); - initChangeListManager(); - addSilently(); - removeSilently(); + try { + myProject = myProjectFixture.getProject(); + myProjectRoot = myProject.getBaseDir(); + myProjectPath = myProjectRoot.getPath(); + + myGitSettings = GitVcsSettings.getInstance(myProject); + myGitSettings.getAppSettings().setPathToGit(GitExecutor.PathHolder.GIT_EXECUTABLE); + + myDialogManager = (TestDialogManager)ServiceManager.getService(DialogManager.class); + myVcsNotifier = (TestVcsNotifier)ServiceManager.getService(myProject, VcsNotifier.class); + + myGitRepositoryManager = GitUtil.getRepositoryManager(myProject); + myPlatformFacade = ServiceManager.getService(myProject, GitPlatformFacade.class); + myGit = ServiceManager.getService(myProject, Git.class); + myVcs = ObjectUtils.assertNotNull(GitVcs.getInstance(myProject)); + myVcs.doActivate(); + + GitTestUtil.assumeSupportedGitVersion(myVcs); + initChangeListManager(); + addSilently(); + removeSilently(); + } + catch (Exception e) { + tearDown(); + throw e; + } } @Override @NotNull public String getTestName(boolean lowercaseFirstLetter) { String name = super.getTestName(lowercaseFirstLetter); - name = name.trim().replace(' ', '_'); - if (name.length() > 50) { - name = name.substring(0, 50); + name = StringUtil.shortenTextWithEllipsis(name.trim().replace(" ", "_"), 12, 6, "_"); + if (name.startsWith("_")) { + name = name.substring(1); } return name; } @@ -127,16 +134,25 @@ public abstract class GitPlatformTest extends UsefulTestCase { @Override protected void tearDown() throws Exception { try { - myDialogManager.cleanup(); - myVcsNotifier.cleanup(); - myProjectFixture.tearDown(); - - String tempTestIndicator = myTestStartedIndicator; - clearFields(this); - myTestStartedIndicator = tempTestIndicator; + if (myDialogManager != null) { + myDialogManager.cleanup(); + } + if (myVcsNotifier != null) { + myVcsNotifier.cleanup(); + } + if (myProjectFixture != null) { + myProjectFixture.tearDown(); + } } finally { - super.tearDown(); + try { + String tempTestIndicator = myTestStartedIndicator; + clearFields(this); + myTestStartedIndicator = tempTestIndicator; + } + finally { + super.tearDown(); + } } } diff --git a/plugins/git4idea/tests/git4idea/test/GitScenarios.groovy b/plugins/git4idea/tests/git4idea/test/GitScenarios.groovy index 77ecf0bc9e20..1fe574ad863d 100644 --- a/plugins/git4idea/tests/git4idea/test/GitScenarios.groovy +++ b/plugins/git4idea/tests/git4idea/test/GitScenarios.groovy @@ -38,14 +38,17 @@ class GitScenarios { /** * Create a branch with a commit and return back to master. */ - static def branchWithCommit(GitRepository repository, String name, String file = "branch_file.txt", String content = "branch content") { + static def branchWithCommit(GitRepository repository, String name, String file = "branch_file.txt", String content = "branch content", + boolean returnToMaster = true) { cd repository git("checkout -b $name") touch(file, content) git("add $file") git("commit -m branch_content") - git("checkout master") + if (returnToMaster) { + git("checkout master") + } } /** diff --git a/plugins/git4idea/tests/git4idea/test/GitTestRepositoryManager.java b/plugins/git4idea/tests/git4idea/test/GitTestRepositoryManager.java index 52bf562280fe..b02e952926c2 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestRepositoryManager.java +++ b/plugins/git4idea/tests/git4idea/test/GitTestRepositoryManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,70 +15,46 @@ */ package git4idea.test; -import com.intellij.dvcs.repo.RepositoryManager; -import com.intellij.openapi.vcs.FilePath; +import com.intellij.dvcs.repo.RepoStateException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vfs.VirtualFile; +import git4idea.GitPlatformFacade; import git4idea.repo.GitRepository; +import git4idea.repo.GitRepositoryImpl; +import git4idea.repo.GitRepositoryManager; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; +public class GitTestRepositoryManager extends GitRepositoryManager { -/** - * @author Kirill Likhodedov - */ -public class GitTestRepositoryManager implements RepositoryManager<GitRepository> { - private final List<GitRepository> myRepositories = new ArrayList<GitRepository>(); + @NotNull private final Project myProject; + @NotNull private final GitPlatformFacade myFacade; - public void add(GitRepository repository) { - myRepositories.add(repository); - } - - @Override - public GitRepository getRepositoryForRoot(@Nullable VirtualFile root) { - for (GitRepository repository : myRepositories) { - if (repository.getRoot().equals(root)) { - return repository; - } - } - - return null; - } - - @Override - public GitRepository getRepositoryForFile(@NotNull VirtualFile file) { - throw new UnsupportedOperationException(); - } - - @Override - public GitRepository getRepositoryForFile(@NotNull FilePath file) { - throw new UnsupportedOperationException(); + public GitTestRepositoryManager(@NotNull Project project, + @NotNull GitPlatformFacade platformFacade, + @NotNull ProjectLevelVcsManager vcsManager) { + super(project, platformFacade, vcsManager); + myProject = project; + myFacade = platformFacade; } @NotNull @Override - public List<GitRepository> getRepositories() { - return myRepositories; - } - - @Override - public boolean moreThanOneRoot() { - return myRepositories.size() > 1; - } - - @Override - public void updateRepository(VirtualFile root) { - throw new UnsupportedOperationException(); - } - - @Override - public void updateAllRepositories() { - throw new UnsupportedOperationException(); - } - - @Override - public void waitUntilInitialized() { + protected GitRepository createRepository(@NotNull VirtualFile root) { + return new GitRepositoryImpl(root, myFacade, myProject, this, false) { + @Override + public void update() { + try { + super.update(); + } + catch (RepoStateException e) { + if (!Disposer.isDisposed(this)) { // project dir will simply be removed during dispose + throw e; + } + } + } + }; } } diff --git a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java index 842b1b1a2bae..3525ad18f0fd 100644 --- a/plugins/git4idea/tests/git4idea/test/GitTestUtil.java +++ b/plugins/git4idea/tests/git4idea/test/GitTestUtil.java @@ -22,6 +22,7 @@ import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitUtil; import git4idea.GitVcs; +import git4idea.config.GitVersion; import git4idea.repo.GitRepository; import org.jetbrains.annotations.NotNull; import org.jetbrains.ide.BuiltInServerManagerImpl; @@ -111,6 +112,7 @@ public class GitTestUtil { } public static void assumeSupportedGitVersion(@NotNull GitVcs vcs) { - assumeTrue(vcs.getVersion().isSupported()); + GitVersion version = vcs.getVersion(); + assumeTrue("Unsupported Git version: " + version, version.isSupported()); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java index 714191d06b98..bfceb0ceec39 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubRebaseAction.java @@ -195,7 +195,7 @@ public class GithubRebaseAction extends DumbAwareAction { } try { - return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(indicator.getModalityState()), indicator, + return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator, new ThrowableConvertor<GithubAuthData, GithubRepoDetailed, IOException>() { @NotNull @Override diff --git a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java index 7c18b3bf7ffc..cca5afa0f5e5 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java +++ b/plugins/github/src/org/jetbrains/plugins/github/GithubShareAction.java @@ -23,10 +23,10 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Ref; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.ChangeListManager; @@ -54,7 +54,6 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.GithubApiUtil; import org.jetbrains.plugins.github.api.GithubRepo; import org.jetbrains.plugins.github.api.GithubUserDetailed; -import org.jetbrains.plugins.github.exceptions.GithubOperationCanceledException; import org.jetbrains.plugins.github.ui.GithubShareDialog; import org.jetbrains.plugins.github.util.*; @@ -125,7 +124,7 @@ public class GithubShareAction extends DumbAwareAction { externalRemoteDetected = !gitRepository.getRemotes().isEmpty(); } - final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings(null); + final GithubAuthDataHolder authHolder = GithubAuthDataHolder.createFromSettings(); // get available GitHub repos with modal progress final GithubInfo githubInfo = loadGithubInfoWithModal(authHolder, project); @@ -351,11 +350,11 @@ public class GithubShareAction extends DumbAwareAction { @NotNull private static Collection<VirtualFile> filterOutIgnored(@NotNull Project project, @NotNull Collection<VirtualFile> files) { final ChangeListManager changeListManager = ChangeListManager.getInstance(project); - final FileIndexFacade fileIndex = FileIndexFacade.getInstance(project); + final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(project); return ContainerUtil.filter(files, new Condition<VirtualFile>() { @Override public boolean value(VirtualFile file) { - return !changeListManager.isIgnoredFile(file) && !fileIndex.isExcludedFile(file); + return !changeListManager.isIgnoredFile(file) && !vcsManager.isIgnored(file); } }); } diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java index 115258d9bee2..6b3f73f5f8be 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubCheckoutProvider.java @@ -61,7 +61,7 @@ public class GithubCheckoutProvider implements CheckoutProvider { @NotNull @Override public List<GithubRepo> convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(indicator.getModalityState()), indicator, + return GithubUtil.runTask(project, GithubAuthDataHolder.createFromSettings(), indicator, new ThrowableConvertor<GithubAuthData, List<GithubRepo>, IOException>() { @NotNull @Override diff --git a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java index 47d3edcb3de5..5a7daf94a9fd 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java +++ b/plugins/github/src/org/jetbrains/plugins/github/extensions/GithubHttpAuthDataProvider.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.github.extensions; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.AuthData; import git4idea.remote.GitHttpAuthDataProvider; @@ -32,7 +31,7 @@ public class GithubHttpAuthDataProvider implements GitHttpAuthDataProvider { @Nullable @Override - public AuthData getAuthData(@NotNull String url, @Nullable ModalityState modalityState) { + public AuthData getAuthData(@NotNull String url) { if (!GithubUrlUtil.isGithubUrl(url)) { return null; } @@ -48,7 +47,7 @@ public class GithubHttpAuthDataProvider implements GitHttpAuthDataProvider { return null; } - GithubAuthData auth = settings.getAuthData(modalityState); + GithubAuthData auth = settings.getAuthData(); switch (auth.getAuthType()) { case BASIC: GithubAuthData.BasicAuth basicAuth = auth.getBasicAuth(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java index 9cf3cdf4b4fe..5333d82e3baf 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java +++ b/plugins/github/src/org/jetbrains/plugins/github/tasks/GithubRepositoryEditor.java @@ -125,8 +125,7 @@ public class GithubRepositoryEditor extends BaseRepositoryEditor<GithubRepositor @Override public String convert(ProgressIndicator indicator) throws IOException { return GithubUtil - .runTaskWithBasicAuthForHost(myProject, GithubAuthDataHolder.createFromSettings(indicator.getModalityState()), - indicator, getHost(), + .runTaskWithBasicAuthForHost(myProject, GithubAuthDataHolder.createFromSettings(), indicator, getHost(), new ThrowableConvertor<GithubAuthData, String, IOException>() { @NotNull @Override diff --git a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java index 229170e29ead..7de0dae30d69 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java +++ b/plugins/github/src/org/jetbrains/plugins/github/ui/GithubSettingsPanel.java @@ -130,8 +130,7 @@ public class GithubSettingsPanel { @NotNull @Override public String convert(ProgressIndicator indicator) throws IOException { - return GithubUtil.runTaskWithBasicAuthForHost(project, GithubAuthDataHolder.createFromSettings(indicator.getModalityState()), - indicator, getHost(), + return GithubUtil.runTaskWithBasicAuthForHost(project, GithubAuthDataHolder.createFromSettings(), indicator, getHost(), new ThrowableConvertor<GithubAuthData, String, IOException>() { @NotNull @Override @@ -263,7 +262,7 @@ public class GithubSettingsPanel { @NotNull public GithubAuthData getAuthData() { if (!myCredentialsModified) { - return mySettings.getAuthData(null); + return mySettings.getAuthData(); } Object selected = myAuthTypeComboBox.getSelectedItem(); if (AUTH_PASSWORD.equals(selected)) return GithubAuthData.createBasicAuth(getHost(), getLogin(), getPassword()); @@ -291,7 +290,7 @@ public class GithubSettingsPanel { public void apply() { if (myCredentialsModified) { - mySettings.setAuthData(getAuthData(), true, null); + mySettings.setAuthData(getAuthData(), true); } mySettings.setConnectionTimeout(getConnectionTimeout()); resetCredentialsModification(); diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java index d7981b261d7c..f11044422154 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthData.java @@ -15,7 +15,6 @@ */ package org.jetbrains.plugins.github.util; -import com.intellij.openapi.application.ModalityState; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.github.api.GithubApiUtil; @@ -53,8 +52,8 @@ public class GithubAuthData { myUseProxy = useProxy; } - public static GithubAuthData createFromSettings(@Nullable ModalityState state) { - return GithubSettings.getInstance().getAuthData(state); + public static GithubAuthData createFromSettings() { + return GithubSettings.getInstance().getAuthData(); } public static GithubAuthData createAnonymous() { diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java index 24303a34d240..695dfe734c34 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubAuthDataHolder.java @@ -15,10 +15,8 @@ */ package org.jetbrains.plugins.github.util; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.util.ThrowableComputable; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class GithubAuthDataHolder { @@ -42,7 +40,7 @@ public class GithubAuthDataHolder { myAuthData = task.compute(); } - public static GithubAuthDataHolder createFromSettings(@Nullable ModalityState state) { - return new GithubAuthDataHolder(GithubSettings.getInstance().getAuthData(state)); + public static GithubAuthDataHolder createFromSettings() { + return new GithubAuthDataHolder(GithubSettings.getInstance().getAuthData()); } } diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java index a2bdca59bbe4..3523e412a95e 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubSettings.java @@ -19,7 +19,6 @@ import com.intellij.ide.passwordSafe.PasswordSafe; import com.intellij.ide.passwordSafe.PasswordSafeException; import com.intellij.ide.passwordSafe.config.PasswordSafeSettings; import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl; -import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; @@ -152,10 +151,10 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } @NotNull - private String getPassword(@Nullable ModalityState state) { + private String getPassword() { String password; try { - password = PasswordSafe.getInstance().getPassword(null, GithubSettings.class, GITHUB_SETTINGS_PASSWORD_KEY, state); + password = PasswordSafe.getInstance().getPassword(null, GithubSettings.class, GITHUB_SETTINGS_PASSWORD_KEY); } catch (PasswordSafeException e) { LOG.info("Couldn't get password for key [" + GITHUB_SETTINGS_PASSWORD_KEY + "]", e); @@ -165,10 +164,10 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S return StringUtil.notNullize(password); } - private void setPassword(@NotNull String password, boolean rememberPassword, @Nullable ModalityState state) { + private void setPassword(@NotNull String password, boolean rememberPassword) { try { if (rememberPassword) { - PasswordSafe.getInstance().storePassword(null, GithubSettings.class, GITHUB_SETTINGS_PASSWORD_KEY, password, state); + PasswordSafe.getInstance().storePassword(null, GithubSettings.class, GITHUB_SETTINGS_PASSWORD_KEY, password); } else { final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance(); @@ -197,13 +196,13 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } @NotNull - public GithubAuthData getAuthData(@Nullable ModalityState state) { + public GithubAuthData getAuthData() { switch (getAuthType()) { case BASIC: //noinspection ConstantConditions - return GithubAuthData.createBasicAuth(getHost(), getLogin(), getPassword(state)); + return GithubAuthData.createBasicAuth(getHost(), getLogin(), getPassword()); case TOKEN: - return GithubAuthData.createTokenAuth(getHost(), getPassword(state)); + return GithubAuthData.createTokenAuth(getHost(), getPassword()); case ANONYMOUS: return GithubAuthData.createAnonymous(); default: @@ -211,7 +210,7 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S } } - public void setAuthData(@NotNull GithubAuthData auth, boolean rememberPassword, @Nullable ModalityState state) { + public void setAuthData(@NotNull GithubAuthData auth, boolean rememberPassword) { setValidGitAuth(isValidGitAuth(auth)); setAuthType(auth.getAuthType()); @@ -221,16 +220,16 @@ public class GithubSettings implements PersistentStateComponent<GithubSettings.S case BASIC: assert auth.getBasicAuth() != null; setLogin(auth.getBasicAuth().getLogin()); - setPassword(auth.getBasicAuth().getPassword(), rememberPassword, state); + setPassword(auth.getBasicAuth().getPassword(), rememberPassword); break; case TOKEN: assert auth.getTokenAuth() != null; setLogin(null); - setPassword(auth.getTokenAuth().getToken(), rememberPassword, state); + setPassword(auth.getTokenAuth().getToken(), rememberPassword); break; case ANONYMOUS: setLogin(null); - setPassword("", rememberPassword, state); + setPassword("", rememberPassword); break; default: throw new IllegalStateException("GithubSettings: setAuthData - wrong AuthType: " + auth.getAuthType()); diff --git a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java index e4af54f84639..edd12ab85ab6 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java +++ b/plugins/github/src/org/jetbrains/plugins/github/util/GithubUtil.java @@ -161,7 +161,7 @@ public class GithubUtil { if (ok[0]) { authData[0] = dialog.getAuthData(); - GithubSettings.getInstance().setAuthData(authData[0], dialog.isSavePasswordSelected(), indicator.getModalityState()); + GithubSettings.getInstance().setAuthData(authData[0], dialog.isSavePasswordSelected()); } } }, indicator.getModalityState()); @@ -195,7 +195,7 @@ public class GithubUtil { final GithubSettings settings = GithubSettings.getInstance(); if (settings.getAuthType() != GithubAuthData.AuthType.TOKEN) { - GithubSettings.getInstance().setAuthData(authData[0], dialog.isSavePasswordSelected(), indicator.getModalityState()); + GithubSettings.getInstance().setAuthData(authData[0], dialog.isSavePasswordSelected()); } } } @@ -247,7 +247,7 @@ public class GithubUtil { @NotNull public static GithubAuthDataHolder getValidAuthDataHolderFromConfig(@NotNull Project project, @NotNull ProgressIndicator indicator) throws IOException { - GithubAuthData auth = GithubAuthData.createFromSettings(indicator.getModalityState()); + GithubAuthData auth = GithubAuthData.createFromSettings(); GithubAuthDataHolder authHolder = new GithubAuthDataHolder(auth); try { checkAuthData(project, authHolder, indicator); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java index d313398548a5..b54bd8c62b4e 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubCreateGistTestBase.java @@ -54,12 +54,12 @@ public abstract class GithubCreateGistTestBase extends GithubTest { @NotNull protected GithubAuthDataHolder getAuthDataHolder() { - return new GithubAuthDataHolder(myGitHubSettings.getAuthData(null)); + return new GithubAuthDataHolder(myGitHubSettings.getAuthData()); } protected void deleteGist() throws IOException { if (GIST_ID != null) { - GithubApiUtil.deleteGist(myGitHubSettings.getAuthData(null), GIST_ID); + GithubApiUtil.deleteGist(myGitHubSettings.getAuthData(), GIST_ID); GIST = null; GIST_ID = null; } @@ -82,7 +82,7 @@ public abstract class GithubCreateGistTestBase extends GithubTest { if (GIST == null) { try { - GIST = GithubApiUtil.getGist(myGitHubSettings.getAuthData(null), GIST_ID); + GIST = GithubApiUtil.getGist(myGitHubSettings.getAuthData(), GIST_ID); } catch (IOException e) { System.err.println(e.getMessage()); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java index 97b34aa7b26c..4fec0d1c7a5c 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubRequestPagingTest.java @@ -36,7 +36,7 @@ public class GithubRequestPagingTest extends GithubTest { public void testAvailableRepos() throws Throwable { - List<GithubRepo> availableRepos = GithubApiUtil.getUserRepos(myGitHubSettings.getAuthData(null), myLogin2); + List<GithubRepo> availableRepos = GithubApiUtil.getUserRepos(myGitHubSettings.getAuthData(), myLogin2); List<String> realData = new ArrayList<String>(); for (GithubRepo info : availableRepos) { realData.add(info.getName()); diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java index e6da326777c5..c4063629cbbe 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTest.java @@ -99,7 +99,7 @@ public class GithubShareProjectTest extends GithubShareProjectTestBase { } protected void checkGithubExists() throws IOException { - GithubAuthData auth = myGitHubSettings.getAuthData(null); + GithubAuthData auth = myGitHubSettings.getAuthData(); GithubRepoDetailed githubInfo = GithubApiUtil.getDetailedRepoInfo(auth, myLogin1, PROJECT_NAME); assertNotNull("GitHub repository does not exist", githubInfo); } diff --git a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java index f146b37f4208..abfb5ece3819 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java +++ b/plugins/github/test/org/jetbrains/plugins/github/GithubShareProjectTestBase.java @@ -48,7 +48,7 @@ public abstract class GithubShareProjectTestBase extends GithubTest { } protected void deleteGithubRepo() throws IOException { - GithubApiUtil.deleteGithubRepository(myGitHubSettings.getAuthData(null), myLogin1, PROJECT_NAME); + GithubApiUtil.deleteGithubRepository(myGitHubSettings.getAuthData(), myLogin1, PROJECT_NAME); } protected void registerDefaultShareDialogHandler() { diff --git a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java index b728913aeacb..3d3d8201e03a 100644 --- a/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java +++ b/plugins/github/test/org/jetbrains/plugins/github/test/GithubTest.java @@ -172,7 +172,7 @@ public abstract class GithubTest extends GitPlatformTest { myAuth = GithubAuthData.createBasicAuth(host, login1, password); myGitHubSettings = GithubSettings.getInstance(); - myGitHubSettings.setAuthData(myAuth, false, null); + myGitHubSettings.setAuthData(myAuth, false); myHttpAuthService = (GitHttpAuthTestService)ServiceManager.getService(GitHttpAuthService.class); diff --git a/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/build/AppEngineEnhancerBuilder.java b/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/build/AppEngineEnhancerBuilder.java index 549aa1a5b361..e6ab8747c2a3 100644 --- a/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/build/AppEngineEnhancerBuilder.java +++ b/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/build/AppEngineEnhancerBuilder.java @@ -113,7 +113,11 @@ public class AppEngineEnhancerBuilder extends ModuleLevelBuilder { List<String> classpath = new ArrayList<String>(); classpath.add(extension.getToolsApiJarPath()); classpath.add(PathManager.getJarPathForClass(EnhancerRunner.class)); + boolean removeOrmJars = Boolean.parseBoolean(System.getProperty("jps.appengine.enhancer.remove.orm.jars", "true")); for (File file : JpsJavaExtensionService.dependencies(module).recursively().compileOnly().productionOnly().classes().getRoots()) { + if (removeOrmJars && FileUtil.isAncestor(new File(extension.getOrmLibPath()), file, true)) { + continue; + } classpath.add(file.getAbsolutePath()); } diff --git a/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/JpsAppEngineModuleExtension.java b/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/JpsAppEngineModuleExtension.java index 0c68b4139ff6..beb54b57cc7c 100644 --- a/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/JpsAppEngineModuleExtension.java +++ b/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/JpsAppEngineModuleExtension.java @@ -26,6 +26,8 @@ import java.util.List; public interface JpsAppEngineModuleExtension extends JpsElement { JpsModule getModule(); + String getOrmLibPath(); + String getSdkHomePath(); boolean isRunEnhancerOnMake(); diff --git a/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/impl/JpsAppEngineModuleExtensionImpl.java b/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/impl/JpsAppEngineModuleExtensionImpl.java index e52d54db2bee..d40f7c007959 100644 --- a/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/impl/JpsAppEngineModuleExtensionImpl.java +++ b/plugins/google-app-engine/jps-plugin/src/org/jetbrains/jps/appengine/model/impl/JpsAppEngineModuleExtensionImpl.java @@ -71,6 +71,11 @@ public class JpsAppEngineModuleExtensionImpl extends JpsElementBase<JpsAppEngine } @Override + public String getOrmLibPath() { + return FileUtil.toSystemDependentName(JpsArtifactPathUtil.appendToPath(getSdkHomePath(), "/lib/user/orm")); + } + + @Override public String getSdkHomePath() { return myProperties.mySdkHomePath; } diff --git a/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java b/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java index afe24f134587..e3a7762fa539 100644 --- a/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java +++ b/plugins/google-app-engine/source/com/intellij/appengine/actions/UploadApplicationAction.java @@ -21,6 +21,7 @@ import com.intellij.appengine.util.AppEngineUtil; import com.intellij.facet.ProjectFacetManager; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.packaging.artifacts.Artifact; @@ -67,8 +68,12 @@ public class UploadApplicationAction extends AnAction { } @Override - public void errorOccurred(@NotNull String errorMessage) { - Messages.showErrorDialog(project, errorMessage, CommonBundle.getErrorTitle()); + public void errorOccurred(@NotNull final String errorMessage) { + ApplicationManager.getApplication().invokeLater(new Runnable() { + public void run() { + Messages.showErrorDialog(project, errorMessage, CommonBundle.getErrorTitle()); + } + }); } }, null); if (uploader != null) { diff --git a/plugins/gradle/gradle.iml b/plugins/gradle/gradle.iml index 878ec399b87c..9e9fb73cdd72 100644 --- a/plugins/gradle/gradle.iml +++ b/plugins/gradle/gradle.iml @@ -14,6 +14,7 @@ <orderEntry type="module" module-name="external-system-impl" exported="" /> <orderEntry type="module" module-name="gradle-tooling-extension-api" exported="" /> <orderEntry type="module" module-name="gradle-tooling-extension-impl" /> + <orderEntry type="module" module-name="gradle-jps-plugin" /> <orderEntry type="module" module-name="idea-ui" /> <orderEntry type="module" module-name="lang-api" /> <orderEntry type="module" module-name="compiler-openapi" /> @@ -105,6 +106,9 @@ <orderEntry type="module" module-name="testFramework-java" scope="TEST" /> <orderEntry type="module" module-name="junit" /> <orderEntry type="module" module-name="smRunner" /> + <orderEntry type="library" name="Kryo" level="project" /> + <orderEntry type="library" name="Ant" level="project" /> + <orderEntry type="library" name="gson" level="project" /> </component> </module> diff --git a/plugins/gradle/jps-plugin/gradle-jps-plugin.iml b/plugins/gradle/jps-plugin/gradle-jps-plugin.iml new file mode 100644 index 000000000000..0d1d5300e84b --- /dev/null +++ b/plugins/gradle/jps-plugin/gradle-jps-plugin.iml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="JAVA_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$"> + <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> + </content> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + <orderEntry type="module" module-name="util" /> + <orderEntry type="module" module-name="jps-builders" /> + <orderEntry type="module" module-name="jps-model-impl" /> + <orderEntry type="module" module-name="jps-model-api" /> + <orderEntry type="module" module-name="jps-model-serialization" /> + <orderEntry type="module-library"> + <library> + <CLASSES> + <root url="jar://$MODULE_DIR$/../lib/gradle-tooling-api-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-core-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-messaging-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-wrapper-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-base-services-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-base-services-groovy-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-native-2.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-resources-2.0.jar!/" /> + </CLASSES> + <JAVADOC /> + <SOURCES> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/tooling-api/src/main/java" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/core/src/main/groovy" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/messaging/src/main/java" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/wrapper/src/main/java" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/base-services/src/main/java" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/base-services-groovy/src/main/groovy" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/native/src/main/java" /> + <root url="jar://$MODULE_DIR$/../lib/gradle-2.0-src.zip!/gradle-2.0/subprojects/resources/src/main/java" /> + </SOURCES> + </library> + </orderEntry> + <orderEntry type="library" exported="" name="Ant" level="project" /> + <orderEntry type="library" name="gson" level="project" /> + </component> +</module> + diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService new file mode 100644 index 000000000000..526afcc9d0a9 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.gradle.model.JpsGradleExtensionService @@ -0,0 +1,16 @@ +# +# Copyright 2000-2014 JetBrains s.r.o. +# +# 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. +# +org.jetbrains.jps.gradle.model.impl.JpsGradleExtensionServiceImpl
\ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService new file mode 100644 index 000000000000..90e686daeaca --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.incremental.BuilderService @@ -0,0 +1,16 @@ +# +# Copyright 2000-2014 JetBrains s.r.o. +# +# 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. +# +org.jetbrains.jps.gradle.compiler.GradleBuilderService
\ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory new file mode 100644 index 000000000000..f1518a33d329 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler$Factory @@ -0,0 +1,16 @@ +# +# Copyright 2000-2014 JetBrains s.r.o. +# +# 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. +# +org.jetbrains.jps.gradle.model.impl.JpsGradleDependenciesEnumerationHandler$GradleFactory
\ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension new file mode 100644 index 000000000000..a86ddcf7d451 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/META-INF/services/org.jetbrains.jps.model.serialization.JpsModelSerializerExtension @@ -0,0 +1,16 @@ +# +# Copyright 2000-2014 JetBrains s.r.o. +# +# 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. +# +org.jetbrains.jps.gradle.model.impl.JpsGradleModelSerializationExtension
\ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java new file mode 100644 index 000000000000..c717fe16c792 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/ChainingFilterTransformer.java @@ -0,0 +1,111 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.compiler; + +import com.intellij.openapi.util.Ref; +import org.gradle.api.Transformer; +import org.gradle.util.ConfigureUtil; +import org.jetbrains.jps.gradle.model.impl.ResourceRootFilter; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; + +import java.io.File; +import java.io.FilterReader; +import java.io.Reader; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.regex.Matcher; + +/** + * @author Vladislav.Soroka + * @since 7/24/2014 + */ +public class ChainingFilterTransformer implements Transformer<Reader, Reader> { + private final Collection<ResourceRootFilter> myFilters = new ArrayList<ResourceRootFilter>(); + private final CompileContext myContext; + private final Ref<File> myOutputFileRef; + + + public ChainingFilterTransformer(CompileContext context, Collection<ResourceRootFilter> filters, Ref<File> outputFileRef) { + myContext = context; + myOutputFileRef = outputFileRef; + myFilters.addAll(filters); + } + + public ChainingFilterTransformer(CompileContext context, Collection<ResourceRootFilter> filters) { + this(context, filters, null); + } + + public void addAll(Collection<ResourceRootFilter> filters) { + myFilters.addAll(filters); + } + + public void add(ResourceRootFilter... filters) { + Collections.addAll(myFilters, filters); + } + + @Override + public Reader transform(Reader original) { + Reader value = original; + for (ResourceRootFilter filter : myFilters) { + value = doTransform(filter, value); + } + return value; + } + + private Reader doTransform(ResourceRootFilter filter, Reader original) { + if ("RenamingCopyFilter" .equals(filter.filterType)) { + final Matcher matcher = (Matcher)filter.getProperties().get("matcher"); + final String replacement = (String)filter.getProperties().get("replacement"); + if (matcher == null || replacement == null) return original; + + matcher.reset(myOutputFileRef.get().getName()); + if (matcher.find()) { + final String newFileName = matcher.replaceFirst(replacement); + myOutputFileRef.set(new File(myOutputFileRef.get().getParentFile(), newFileName)); + } + return original; + } + try { + Class<?> clazz = Class.forName(filter.filterType); + if (!FilterReader.class.isAssignableFrom(clazz)) { + myContext.processMessage( + new CompilerMessage( + GradleResourcesBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, + String.format("Error - Invalid filter specification for %s. It should extend java.io.FilterReader.", filter.filterType), null) + ); + } + Constructor constructor = clazz.getConstructor(Reader.class); + FilterReader result = (FilterReader)constructor.newInstance(original); + final Map<Object, Object> properties = filter.getProperties(); + if (!properties.isEmpty()) { + ConfigureUtil.configureByMap(properties, result); + } + return result; + } + catch (Throwable th) { + myContext.processMessage(new CompilerMessage( + GradleResourcesBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, + String.format("Error - Failed to apply filter(%s): %s", filter.filterType, th.getMessage()), null) + ); + } + return original; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java new file mode 100644 index 000000000000..5219a2ccad7b --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleBuilderService.java @@ -0,0 +1,44 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.compiler; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.BuildTargetType; +import org.jetbrains.jps.gradle.model.impl.GradleResourcesTargetType; +import org.jetbrains.jps.incremental.BuilderService; +import org.jetbrains.jps.incremental.TargetBuilder; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleBuilderService extends BuilderService { + @NotNull + @Override + public List<? extends BuildTargetType<?>> getTargetTypes() { + return Arrays.asList(GradleResourcesTargetType.PRODUCTION, GradleResourcesTargetType.TEST); + } + + @NotNull + @Override + public List<? extends TargetBuilder<?, ?>> createBuilders() { + return Collections.singletonList(new GradleResourcesBuilder()); + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java new file mode 100644 index 000000000000..dadfa21906a0 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourceFileProcessor.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.compiler; + +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.StreamUtil; +import org.apache.tools.ant.util.ReaderInputStream; +import org.jetbrains.jps.gradle.model.impl.GradleModuleResourceConfiguration; +import org.jetbrains.jps.gradle.model.impl.GradleProjectConfiguration; +import org.jetbrains.jps.gradle.model.impl.ResourceRootConfiguration; +import org.jetbrains.jps.gradle.model.impl.ResourceRootFilter; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.messages.BuildMessage; +import org.jetbrains.jps.incremental.messages.CompilerMessage; +import org.jetbrains.jps.model.JpsEncodingConfigurationService; +import org.jetbrains.jps.model.JpsEncodingProjectConfiguration; +import org.jetbrains.jps.model.JpsProject; + +import java.io.*; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceFileProcessor { + private static final int FILTERING_SIZE_LIMIT = 10 * 1024 * 1024 /*10 mb*/; + protected final JpsEncodingProjectConfiguration myEncodingConfig; + protected final GradleProjectConfiguration myProjectConfig; + protected final GradleModuleResourceConfiguration myModuleConfiguration; + + public GradleResourceFileProcessor(GradleProjectConfiguration projectConfiguration, JpsProject project, + GradleModuleResourceConfiguration moduleConfiguration) { + myProjectConfig = projectConfiguration; + myEncodingConfig = JpsEncodingConfigurationService.getInstance().getEncodingConfiguration(project); + myModuleConfiguration = moduleConfiguration; + } + + public void copyFile(File file, Ref<File> targetFileRef, ResourceRootConfiguration rootConfiguration, CompileContext context, + FileFilter filteringFilter) throws IOException { + boolean shouldFilter = rootConfiguration.isFiltered && !rootConfiguration.filters.isEmpty() && filteringFilter.accept(file); + if (shouldFilter && file.length() > FILTERING_SIZE_LIMIT) { + context.processMessage(new CompilerMessage( + GradleResourcesBuilder.BUILDER_NAME, BuildMessage.Kind.WARNING, + "File is too big to be filtered. Most likely it is a binary file and should be excluded from filtering", file.getPath()) + ); + shouldFilter = false; + } + if (shouldFilter) { + copyWithFiltering(file, targetFileRef, rootConfiguration.filters, context); + } + else { + FileUtil.copyContent(file, targetFileRef.get()); + } + } + + private static void copyWithFiltering(File file, Ref<File> outputFileRef, List<ResourceRootFilter> filters, CompileContext context) + throws IOException { + final FileInputStream originalInputStream = new FileInputStream(file); + try { + final InputStream inputStream = transform(filters, originalInputStream, outputFileRef, context); + FileUtil.createIfDoesntExist(outputFileRef.get()); + FileOutputStream outputStream = new FileOutputStream(outputFileRef.get()); + try { + FileUtil.copy(inputStream, outputStream); + } + finally { + StreamUtil.closeStream(inputStream); + StreamUtil.closeStream(outputStream); + } + } + finally { + StreamUtil.closeStream(originalInputStream); + } + } + + private static InputStream transform(List<ResourceRootFilter> filters, FileInputStream original, Ref<File> outputFileRef, CompileContext context) { + return new ReaderInputStream(new ChainingFilterTransformer(context, filters, outputFileRef).transform(new InputStreamReader(original))); + } +}
\ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java new file mode 100644 index 000000000000..295c8bab8133 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/compiler/GradleResourcesBuilder.java @@ -0,0 +1,128 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.compiler; + +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.FileUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.BuildOutputConsumer; +import org.jetbrains.jps.builders.DirtyFilesHolder; +import org.jetbrains.jps.builders.FileProcessor; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.gradle.model.impl.*; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.incremental.ProjectBuildException; +import org.jetbrains.jps.incremental.TargetBuilder; +import org.jetbrains.jps.incremental.messages.ProgressMessage; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourcesBuilder extends TargetBuilder<GradleResourceRootDescriptor, GradleResourcesTarget> { + public static final String BUILDER_NAME = "Gradle Resources Compiler"; + + public GradleResourcesBuilder() { + super(Arrays.asList(GradleResourcesTargetType.PRODUCTION, GradleResourcesTargetType.TEST)); + } + + @Override + public void build(@NotNull final GradleResourcesTarget target, + @NotNull final DirtyFilesHolder<GradleResourceRootDescriptor, GradleResourcesTarget> holder, + @NotNull final BuildOutputConsumer outputConsumer, + @NotNull final CompileContext context) throws ProjectBuildException, IOException { + final BuildDataPaths dataPaths = context.getProjectDescriptor().dataManager.getDataPaths(); + final GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths); + final GradleModuleResourceConfiguration config = target.getModuleResourcesConfiguration(dataPaths); + if (config == null) return; + + final Map<GradleResourceRootDescriptor, List<File>> files = new HashMap<GradleResourceRootDescriptor, List<File>>(); + + holder.processDirtyFiles(new FileProcessor<GradleResourceRootDescriptor, GradleResourcesTarget>() { + + @Override + public boolean apply(GradleResourcesTarget t, File file, GradleResourceRootDescriptor rd) throws IOException { + assert target == t; + + List<File> fileList = files.get(rd); + if (fileList == null) { + fileList = new ArrayList<File>(); + files.put(rd, fileList); + } + + fileList.add(file); + return true; + } + }); + + GradleResourceRootDescriptor[] roots = files.keySet().toArray(new GradleResourceRootDescriptor[files.keySet().size()]); + Arrays.sort(roots, new Comparator<GradleResourceRootDescriptor>() { + @Override + public int compare(GradleResourceRootDescriptor r1, GradleResourceRootDescriptor r2) { + int res = r1.getIndexInPom() - r2.getIndexInPom(); + if (r1.isOverwrite()) { + assert r2.isOverwrite(); + return res; + } + + if (r1.getConfiguration().isFiltered && !r2.getConfiguration().isFiltered) return 1; + if (!r1.getConfiguration().isFiltered && r2.getConfiguration().isFiltered) return -1; + + if (!r1.getConfiguration().isFiltered) { + res = -res; + } + + return res; + } + }); + + GradleResourceFileProcessor fileProcessor = new GradleResourceFileProcessor(projectConfig, target.getModule().getProject(), config); + + for (GradleResourceRootDescriptor rd : roots) { + for (File file : files.get(rd)) { + + String relPath = FileUtil.getRelativePath(rd.getRootFile(), file); + if (relPath == null) continue; + + final File outputDir = + GradleResourcesTarget.getOutputDir(target.getModuleOutputDir(), rd.getConfiguration(), config.outputDirectory); + if (outputDir == null) continue; + + context.processMessage(new ProgressMessage("Copying resources... [" + target.getModule().getName() + "]")); + + final Ref<File> fileRef = Ref.create(new File(outputDir, relPath)); + fileProcessor.copyFile(file, fileRef, rd.getConfiguration(), context, FileUtilRt.ALL_FILES); + outputConsumer.registerOutputFile(fileRef.get(), Collections.singleton(file.getPath())); + + if (context.getCancelStatus().isCanceled()) return; + } + } + + context.checkCanceled(); + context.processMessage(new ProgressMessage("")); + } + + @NotNull + public String getPresentableName() { + return BUILDER_NAME; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java new file mode 100644 index 000000000000..126cf5758ac1 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleExtensionService.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.gradle.model.impl.GradleProjectConfiguration; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.service.JpsServiceManager; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public abstract class JpsGradleExtensionService { + public static JpsGradleExtensionService getInstance() { + return JpsServiceManager.getInstance().getService(JpsGradleExtensionService.class); + } + + @Nullable + public abstract JpsGradleModuleExtension getExtension(@NotNull JpsModule module); + + @NotNull + public abstract JpsGradleModuleExtension getOrCreateExtension(@NotNull JpsModule module); + + public abstract void setProductionOnTestDependency(@NotNull JpsDependencyElement dependency, boolean value); + + public abstract boolean isProductionOnTestDependency(@NotNull JpsDependencyElement dependency); + + public abstract boolean hasGradleProjectConfiguration(@NotNull BuildDataPaths paths); + + @NotNull + public abstract GradleProjectConfiguration getGradleProjectConfiguration(BuildDataPaths paths); +} diff --git a/plugins/properties/resources/icons/PropertiesIcons.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleModuleExtension.java index 156d14467707..c673e4c0d27c 100644 --- a/plugins/properties/resources/icons/PropertiesIcons.java +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/JpsGradleModuleExtension.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -13,20 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package icons; +package org.jetbrains.jps.gradle.model; -import com.intellij.openapi.util.IconLoader; - -import javax.swing.*; +import org.jetbrains.jps.model.JpsElement; /** - * NOTE THIS FILE IS AUTO-GENERATED - * DO NOT EDIT IT BY HAND, run build/scripts/icons.gant instead + * @author Vladislav.Soroka + * @since 7/10/2014 */ -public class PropertiesIcons { - private static Icon load(String path) { - return IconLoader.getIcon(path, PropertiesIcons.class); - } - - public static final Icon XmlProperties = load("/icons/xmlProperties.png"); // 16x16 +public interface JpsGradleModuleExtension extends JpsElement { } diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java new file mode 100644 index 000000000000..98938f596d05 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/FilePattern.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Tag; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class FilePattern { + + @Tag("includes") + @AbstractCollection(surroundWithTag = false, elementTag = "pattern") + public Set<String> includes = new HashSet<String>(); + + @Tag("excludes") + @AbstractCollection(surroundWithTag = false, elementTag = "pattern") + public Set<String> excludes = new HashSet<String>(); + +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java new file mode 100644 index 000000000000..9b6732a6d5d5 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleModuleResourceConfiguration.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.OptionTag; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleModuleResourceConfiguration { + @NotNull + @Tag("id") + public ModuleVersion id; + + @Nullable + @Tag("parentId") + public ModuleVersion parentId; + + @NotNull + @Tag("directory") + public String directory; + + @OptionTag + public boolean overwrite; + + @OptionTag + public String outputDirectory = null; + + @Tag("resources") + @AbstractCollection(surroundWithTag = false, elementTag = "resource") + public List<ResourceRootConfiguration> resources = new ArrayList<ResourceRootConfiguration>(); + + @Tag("test-resources") + @AbstractCollection(surroundWithTag = false, elementTag = "resource") + public List<ResourceRootConfiguration> testResources = new ArrayList<ResourceRootConfiguration>(); + + public int computeConfigurationHash(boolean forTestResources) { + int result = computeModuleConfigurationHash(); + + final List<ResourceRootConfiguration> _resources = forTestResources ? testResources : resources; + result = 31 * result; + for (ResourceRootConfiguration resource : _resources) { + result += resource.computeConfigurationHash(); + } + return result; + } + + public int computeModuleConfigurationHash() { + int result = id.hashCode(); + result = 31 * result + (parentId != null ? parentId.hashCode() : 0); + result = 31 * result + directory.hashCode(); + result = 31 * result + (outputDirectory != null ? outputDirectory.hashCode() : 0); + result = 31 * result + (overwrite ? 1 : 0); + return result; + } +} + + + diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java new file mode 100644 index 000000000000..083bba570d8a --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleProjectConfiguration.java @@ -0,0 +1,35 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.MapAnnotation; +import com.intellij.util.xmlb.annotations.Tag; +import gnu.trove.THashMap; + +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleProjectConfiguration { + public static final String CONFIGURATION_FILE_RELATIVE_PATH = "gradle/configuration.xml"; + + @Tag("resource-processing") + @MapAnnotation(surroundWithTag = false, surroundKeyWithTag = false, surroundValueWithTag = false, entryTagName = "gradle-module", + keyAttributeName = "name") + public Map<String, GradleModuleResourceConfiguration> moduleConfigurations = new THashMap<String, GradleModuleResourceConfiguration>(); +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java new file mode 100644 index 000000000000..60e7fd295daa --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceFileFilter.java @@ -0,0 +1,81 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.openapi.util.io.FileUtil; +import org.gradle.api.file.RelativePath; +import org.gradle.api.internal.file.pattern.PatternMatcherFactory; +import org.gradle.api.specs.Spec; +import org.gradle.api.specs.Specs; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.regex.Pattern; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceFileFilter implements FileFilter { + private FilePattern myFilePattern; + private File myRoot; + private final Spec<RelativePath> myFileFilterSpec; + + public GradleResourceFileFilter(@NotNull File rootFile, @NotNull FilePattern filePattern) { + myFilePattern = filePattern; + myRoot = rootFile; + myFileFilterSpec = getAsSpec(); + } + + @Override + public boolean accept(@NotNull File file) { + final String relPath = FileUtil.getRelativePath(myRoot, file); + return relPath != null && isIncluded(relPath); + } + + private boolean isIncluded(@NotNull String relativePath) { + RelativePath path = new RelativePath(true, relativePath.split(Pattern.quote(File.separator))); + return myFileFilterSpec.isSatisfiedBy(path); + } + + private Spec<RelativePath> getAsSpec() { + return Specs.and(getAsIncludeSpec(true), Specs.not(getAsExcludeSpec(true))); + } + + private Spec<RelativePath> getAsExcludeSpec(boolean caseSensitive) { + Collection<String> allExcludes = new LinkedHashSet<String>(myFilePattern.excludes); + List<Spec<RelativePath>> matchers = new ArrayList<Spec<RelativePath>>(); + for (String exclude : allExcludes) { + Spec<RelativePath> patternMatcher = PatternMatcherFactory.getPatternMatcher(false, caseSensitive, exclude); + matchers.add(patternMatcher); + } + return Specs.or(false, matchers); + } + + private Spec<RelativePath> getAsIncludeSpec(boolean caseSensitive) { + List<Spec<RelativePath>> matchers = new ArrayList<Spec<RelativePath>>(); + for (String include : myFilePattern.includes) { + Spec<RelativePath> patternMatcher = PatternMatcherFactory.getPatternMatcher(true, caseSensitive, include); + matchers.add(patternMatcher); + } + return Specs.or(true, matchers); + } +}
\ No newline at end of file diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java new file mode 100644 index 000000000000..e8ae0d701200 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourceRootDescriptor.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.openapi.util.io.FileUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.builders.BuildRootDescriptor; + +import java.io.File; +import java.io.FileFilter; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceRootDescriptor extends BuildRootDescriptor { + private final GradleResourcesTarget myTarget; + private final ResourceRootConfiguration myConfig; + private final File myFile; + private final String myId; + private final boolean myOverwrite; + + private final int myIndexInPom; + + public GradleResourceRootDescriptor(@NotNull GradleResourcesTarget target, + ResourceRootConfiguration config, + int indexInPom, + boolean overwrite) { + myTarget = target; + myConfig = config; + final String path = FileUtil.toCanonicalPath(config.directory); + myFile = new File(path); + myId = path; + myIndexInPom = indexInPom; + myOverwrite = overwrite; + } + + public ResourceRootConfiguration getConfiguration() { + return myConfig; + } + + @Override + public String getRootId() { + return myId; + } + + @Override + public File getRootFile() { + return myFile; + } + + @Override + public GradleResourcesTarget getTarget() { + return myTarget; + } + + @NotNull + @Override + public FileFilter createFileFilter() { + return new GradleResourceFileFilter(myFile, myConfig); + } + + @Override + public boolean canUseFileCache() { + return true; + } + + public int getIndexInPom() { + return myIndexInPom; + } + + public boolean isOverwrite() { + return myOverwrite; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java new file mode 100644 index 000000000000..344c83080186 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTarget.java @@ -0,0 +1,161 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.*; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.cmdline.ProjectDescriptor; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.incremental.CompileContext; +import org.jetbrains.jps.indices.IgnoredFileIndex; +import org.jetbrains.jps.indices.ModuleExcludeIndex; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.jps.model.java.JpsJavaExtensionService; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.util.JpsPathUtil; + +import java.io.File; +import java.io.PrintWriter; +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourcesTarget extends ModuleBasedTarget<GradleResourceRootDescriptor> { + + GradleResourcesTarget(final GradleResourcesTargetType type, @NotNull JpsModule module) { + super(type, module); + } + + @Override + public String getId() { + return myModule.getName(); + } + + @Override + public Collection<BuildTarget<?>> computeDependencies(BuildTargetRegistry targetRegistry, TargetOutputIndex outputIndex) { + return Collections.emptyList(); + } + + @Override + public boolean isCompiledBeforeModuleLevelBuilders() { + return true; + } + + @NotNull + @Override + public List<GradleResourceRootDescriptor> computeRootDescriptors(JpsModel model, ModuleExcludeIndex index, IgnoredFileIndex ignoredFileIndex, BuildDataPaths dataPaths) { + final List<GradleResourceRootDescriptor> result = new ArrayList<GradleResourceRootDescriptor>(); + + GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths); + GradleModuleResourceConfiguration moduleConfig = projectConfig.moduleConfigurations.get(myModule.getName()); + if (moduleConfig == null) return Collections.emptyList(); + + int i = 0; + + for (ResourceRootConfiguration resource : getRootConfigurations(moduleConfig)) { + result.add(new GradleResourceRootDescriptor(this, resource, i++, moduleConfig.overwrite)); + } + return result; + } + + private Collection<ResourceRootConfiguration> getRootConfigurations(@Nullable GradleModuleResourceConfiguration moduleConfig) { + if (moduleConfig != null) { + return isTests() ? moduleConfig.testResources : moduleConfig.resources; + } + return Collections.emptyList(); + } + + public GradleModuleResourceConfiguration getModuleResourcesConfiguration(BuildDataPaths dataPaths) { + final GradleProjectConfiguration projectConfig = JpsGradleExtensionService.getInstance().getGradleProjectConfiguration(dataPaths); + return projectConfig.moduleConfigurations.get(myModule.getName()); + } + + public boolean isTests() { + return ((GradleResourcesTargetType)getTargetType()).isTests(); + } + + @Nullable + @Override + public GradleResourceRootDescriptor findRootDescriptor(String rootId, BuildRootIndex rootIndex) { + for (GradleResourceRootDescriptor descriptor : rootIndex.getTargetRoots(this, null)) { + if (descriptor.getRootId().equals(rootId)) { + return descriptor; + } + } + return null; + } + + @NotNull + @Override + public String getPresentableName() { + return getTargetType().getTypeId() + ":" + myModule.getName(); + } + + @NotNull + @Override + public Collection<File> getOutputRoots(CompileContext context) { + GradleModuleResourceConfiguration configuration = + getModuleResourcesConfiguration(context.getProjectDescriptor().dataManager.getDataPaths()); + final Set<File> result = new THashSet<File>(FileUtil.FILE_HASHING_STRATEGY); + final File moduleOutput = getModuleOutputDir(); + for (ResourceRootConfiguration resConfig : getRootConfigurations(configuration)) { + final File output = getOutputDir(moduleOutput, resConfig, configuration.outputDirectory); + if (output != null) { + result.add(output); + } + } + return result; + } + + @Nullable + public File getModuleOutputDir() { + return JpsJavaExtensionService.getInstance().getOutputDirectory(myModule, isTests()); + } + + @Nullable + public static File getOutputDir(@Nullable File moduleOutput, ResourceRootConfiguration config, @Nullable String outputDirectory) { + if(outputDirectory != null) { + moduleOutput = JpsPathUtil.urlToFile(outputDirectory); + } + + if (moduleOutput == null) { + return null; + } + String targetPath = config.targetPath; + if (StringUtil.isEmptyOrSpaces(targetPath)) { + return moduleOutput; + } + final File targetPathFile = new File(targetPath); + final File outputFile = targetPathFile.isAbsolute() ? targetPathFile : new File(moduleOutput, targetPath); + return new File(FileUtil.toCanonicalPath(outputFile.getPath())); + } + + @Override + public void writeConfiguration(ProjectDescriptor pd, PrintWriter out) { + final BuildDataPaths dataPaths = pd.getTargetsState().getDataPaths(); + final GradleModuleResourceConfiguration configuration = getModuleResourcesConfiguration(dataPaths); + if (configuration != null) { + out.write(Integer.toHexString(configuration.computeConfigurationHash(isTests()))); + } + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java new file mode 100644 index 000000000000..bd399a164d31 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/GradleResourcesTargetType.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.BuildTargetLoader; +import org.jetbrains.jps.builders.ModuleBasedBuildTargetType; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.model.JpsModel; +import org.jetbrains.jps.model.module.JpsModule; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourcesTargetType extends ModuleBasedBuildTargetType<GradleResourcesTarget> { + public static final GradleResourcesTargetType PRODUCTION = new GradleResourcesTargetType("gradle-resources-production", false); + public static final GradleResourcesTargetType TEST = new GradleResourcesTargetType("gradle-resources-test", true); + + private final boolean myIsTests; + + private GradleResourcesTargetType(final String typeId, boolean isTests) { + super(typeId); + myIsTests = isTests; + } + + public boolean isTests() { + return myIsTests; + } + + @NotNull + @Override + public List<GradleResourcesTarget> computeAllTargets(@NotNull JpsModel model) { + final List<GradleResourcesTarget> targets = new ArrayList<GradleResourcesTarget>(); + for (JpsModule module : model.getProject().getModules()) { + if (JpsGradleExtensionService.getInstance().getExtension(module) != null) { + targets.add(new GradleResourcesTarget(this, module)); + } + } + return targets; + } + + @NotNull + @Override + public BuildTargetLoader<GradleResourcesTarget> createLoader(@NotNull JpsModel model) { + final Map<String, JpsModule> modules = new HashMap<String, JpsModule>(); + for (JpsModule module : model.getProject().getModules()) { + modules.put(module.getName(), module); + } + return new BuildTargetLoader<GradleResourcesTarget>() { + @Nullable + @Override + public GradleResourcesTarget createTarget(@NotNull String targetId) { + final JpsModule module = modules.get(targetId); + return module != null ? new GradleResourcesTarget(GradleResourcesTargetType.this, module) : null; + } + }; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java new file mode 100644 index 000000000000..af0fd08fb6cf --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleDependenciesEnumerationHandler.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.model.java.impl.JpsJavaDependenciesEnumerationHandler; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; + +import java.util.Collection; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleDependenciesEnumerationHandler extends JpsJavaDependenciesEnumerationHandler { + private static final JpsGradleDependenciesEnumerationHandler INSTANCE = new JpsGradleDependenciesEnumerationHandler(); + + @Override + public boolean shouldAddRuntimeDependenciesToTestCompilationClasspath() { + return true; + } + + @Override + public boolean isProductionOnTestsDependency(JpsDependencyElement element) { + return JpsGradleExtensionService.getInstance().isProductionOnTestDependency(element); + } + + public static class GradleFactory extends Factory { + @Nullable + @Override + public JpsJavaDependenciesEnumerationHandler createHandler(@NotNull Collection<JpsModule> modules) { + JpsGradleExtensionService service = JpsGradleExtensionService.getInstance(); + for (JpsModule module : modules) { + if (service.getExtension(module) != null) { + return INSTANCE; + } + } + return null; + } + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java new file mode 100644 index 000000000000..81ed9076f13e --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleExtensionServiceImpl.java @@ -0,0 +1,136 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.FactoryMap; +import com.intellij.util.xmlb.XmlSerializer; +import gnu.trove.THashMap; +import org.jdom.Document; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.builders.storage.BuildDataPaths; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.gradle.model.JpsGradleModuleExtension; +import org.jetbrains.jps.incremental.resources.ResourcesBuilder; +import org.jetbrains.jps.incremental.resources.StandardResourceBuilderEnabler; +import org.jetbrains.jps.model.JpsElementChildRole; +import org.jetbrains.jps.model.JpsElementFactory; +import org.jetbrains.jps.model.JpsSimpleElement; +import org.jetbrains.jps.model.ex.JpsElementChildRoleBase; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; + +import java.io.File; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleExtensionServiceImpl extends JpsGradleExtensionService { + private static final Logger LOG = Logger.getInstance(JpsGradleExtensionServiceImpl.class); + private static final JpsElementChildRole<JpsSimpleElement<Boolean>> PRODUCTION_ON_TEST_ROLE = JpsElementChildRoleBase.create("production on test"); + private final Map<File, GradleProjectConfiguration> myLoadedConfigs = + new THashMap<File, GradleProjectConfiguration>(FileUtil.FILE_HASHING_STRATEGY); + private final FactoryMap<File, Boolean> myConfigFileExists = new ConcurrentFactoryMap<File, Boolean>() { + @Nullable + @Override + protected Boolean create(File key) { + return key.exists(); + } + }; + + public JpsGradleExtensionServiceImpl() { + ResourcesBuilder.registerEnabler(new StandardResourceBuilderEnabler() { + @Override + public boolean isResourceProcessingEnabled(JpsModule module) { + // enable standard resource processing only if this is not a gradle module + // for gradle modules use gradle-aware resource builder + return getExtension(module) == null; + } + }); + } + + @Nullable + @Override + public JpsGradleModuleExtension getExtension(@NotNull JpsModule module) { + return module.getContainer().getChild(JpsGradleModuleExtensionImpl.ROLE); + } + + @NotNull + @Override + public JpsGradleModuleExtension getOrCreateExtension(@NotNull JpsModule module) { + JpsGradleModuleExtension extension = module.getContainer().getChild(JpsGradleModuleExtensionImpl.ROLE); + if (extension == null) { + extension = new JpsGradleModuleExtensionImpl(); + module.getContainer().setChild(JpsGradleModuleExtensionImpl.ROLE, extension); + } + return extension; + } + + @Override + public void setProductionOnTestDependency(@NotNull JpsDependencyElement dependency, boolean value) { + if (value) { + dependency.getContainer().setChild(PRODUCTION_ON_TEST_ROLE, JpsElementFactory.getInstance().createSimpleElement(true)); + } + else { + dependency.getContainer().removeChild(PRODUCTION_ON_TEST_ROLE); + } + } + + @Override + public boolean isProductionOnTestDependency(@NotNull JpsDependencyElement dependency) { + JpsSimpleElement<Boolean> child = dependency.getContainer().getChild(PRODUCTION_ON_TEST_ROLE); + return child != null && child.getData(); + } + + @Override + public boolean hasGradleProjectConfiguration(@NotNull BuildDataPaths paths) { + return myConfigFileExists.get(new File(paths.getDataStorageRoot(), GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH)); + } + + @NotNull + @Override + public GradleProjectConfiguration getGradleProjectConfiguration(BuildDataPaths paths) { + final File dataStorageRoot = paths.getDataStorageRoot(); + return getGradleProjectConfiguration(dataStorageRoot); + } + + @NotNull + public GradleProjectConfiguration getGradleProjectConfiguration(@NotNull File dataStorageRoot) { + final File configFile = new File(dataStorageRoot, GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH); + GradleProjectConfiguration config; + synchronized (myLoadedConfigs) { + config = myLoadedConfigs.get(configFile); + if (config == null) { + config = new GradleProjectConfiguration(); + try { + final Document document = JDOMUtil.loadDocument(configFile); + XmlSerializer.deserializeInto(config, document.getRootElement()); + } + catch (Exception e) { + LOG.info(e); + } + myLoadedConfigs.put(configFile, config); + } + } + return config; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java new file mode 100644 index 000000000000..cebd00878b19 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModelSerializationExtension.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.gradle.model.JpsGradleExtensionService; +import org.jetbrains.jps.model.module.JpsDependencyElement; +import org.jetbrains.jps.model.module.JpsModule; +import org.jetbrains.jps.model.serialization.JpsModelSerializerExtension; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleModelSerializationExtension extends JpsModelSerializerExtension { + private static final String PRODUCTION_ON_TEST_ATTRIBUTE = "production-on-test"; + + @Override + public void loadModuleOptions(@NotNull JpsModule module, @NotNull Element rootElement) { + if ("GRADLE".equals(rootElement.getAttributeValue("external.system.id"))) { + JpsGradleExtensionService.getInstance().getOrCreateExtension(module); + } + } + + @Override + public void saveModuleOptions(@NotNull JpsModule module, @NotNull Element rootElement) { + if (JpsGradleExtensionService.getInstance().getExtension(module) != null) { + rootElement.setAttribute("external.system.id", "GRADLE"); + } + } + + @Override + public void loadModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) { + if (orderEntry.getAttributeValue(PRODUCTION_ON_TEST_ATTRIBUTE) != null) { + JpsGradleExtensionService.getInstance().setProductionOnTestDependency(dependency, true); + } + } + + @Override + public void saveModuleDependencyProperties(JpsDependencyElement dependency, Element orderEntry) { + if (JpsGradleExtensionService.getInstance().isProductionOnTestDependency(dependency)) { + orderEntry.setAttribute(PRODUCTION_ON_TEST_ATTRIBUTE, ""); + } + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java new file mode 100644 index 000000000000..ecdd04fce10e --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/JpsGradleModuleExtensionImpl.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jps.gradle.model.JpsGradleModuleExtension; +import org.jetbrains.jps.model.JpsElementChildRole; +import org.jetbrains.jps.model.ex.JpsElementBase; +import org.jetbrains.jps.model.ex.JpsElementChildRoleBase; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class JpsGradleModuleExtensionImpl extends JpsElementBase<JpsGradleModuleExtensionImpl> implements JpsGradleModuleExtension { + public static final JpsElementChildRole<JpsGradleModuleExtension> ROLE = JpsElementChildRoleBase.create("gradle"); + + public JpsGradleModuleExtensionImpl() { + } + + @NotNull + @Override + public JpsGradleModuleExtensionImpl createCopy() { + return new JpsGradleModuleExtensionImpl(); + } + + @Override + public void applyChanges(@NotNull JpsGradleModuleExtensionImpl modified) { + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java new file mode 100644 index 000000000000..dbb696d8c33c --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ModuleVersion.java @@ -0,0 +1,64 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.Tag; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class ModuleVersion { + @Tag("groupId") + public String groupId; + + @Tag("artifactId") + public String artifactId; + + @Tag("version") + public String version; + + public ModuleVersion() { + } + + public ModuleVersion(String groupId, String artifactId, String version) { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ModuleVersion bean = (ModuleVersion)o; + + if (artifactId != null ? !artifactId.equals(bean.artifactId) : bean.artifactId != null) return false; + if (groupId != null ? !groupId.equals(bean.groupId) : bean.groupId != null) return false; + if (version != null ? !version.equals(bean.version) : bean.version != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = groupId != null ? groupId.hashCode() : 0; + result = 31 * result + (artifactId != null ? artifactId.hashCode() : 0); + result = 31 * result + (version != null ? version.hashCode() : 0); + return result; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java new file mode 100644 index 000000000000..efd419175dc3 --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootConfiguration.java @@ -0,0 +1,59 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.intellij.util.xmlb.annotations.AbstractCollection; +import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +@Tag("resource") +public class ResourceRootConfiguration extends FilePattern { + @Tag("directory") + @NotNull + public String directory; + + @Tag("targetPath") + @Nullable + public String targetPath; + + @Attribute("filtered") + public boolean isFiltered; + + @Tag("filters") + @AbstractCollection(surroundWithTag = false, elementTag = "filter") + public List<ResourceRootFilter> filters = new ArrayList<ResourceRootFilter>(); + + public int computeConfigurationHash() { + int result = directory.hashCode(); + result = 31 * result + (targetPath != null ? targetPath.hashCode() : 0); + result = 31 * result + (isFiltered ? 1 : 0); + result = 31 * result + includes.hashCode(); + result = 31 * result + excludes.hashCode(); + for (ResourceRootFilter filter : filters) { + result = 31 * result + filter.computeConfigurationHash(); + } + return result; + } +} diff --git a/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java new file mode 100644 index 000000000000..e8c39e32417e --- /dev/null +++ b/plugins/gradle/jps-plugin/src/org/jetbrains/jps/gradle/model/impl/ResourceRootFilter.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.jps.gradle.model.impl; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.intellij.util.xmlb.annotations.Tag; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @author Vladislav.Soroka + * @since 7/22/2014 + */ +@Tag("filter") +public class ResourceRootFilter { + @Tag("filterType") + @NotNull + public String filterType; + @Tag("properties") + @NotNull + public String properties; + + private transient Map<Object, Object> propertiesMap; + + public int computeConfigurationHash() { + int result = filterType.hashCode(); + result = 31 * result + properties.hashCode(); + return result; + } + + @NotNull + public Map<Object, Object> getProperties() { + if (propertiesMap == null) { + try { + Gson gson = new GsonBuilder().create(); + propertiesMap = gson.fromJson( + properties, + new TypeToken<Map<Object, Object>>() { + }.getType()); + + if("RenamingCopyFilter".equals(filterType)) { + final Object pattern = propertiesMap.get("pattern"); + final Matcher matcher = Pattern.compile(pattern instanceof String ? (String)pattern : "").matcher(""); + propertiesMap.put("matcher", matcher); + } + } + catch (JsonSyntaxException e) { + throw new RuntimeException("Unsupported filter: " + properties , e); + } catch (JsonParseException e) { + throw new RuntimeException("Unsupported filter: " + properties , e); + } + } + return propertiesMap; + } +} diff --git a/plugins/gradle/src/META-INF/gradle-maven-integration.xml b/plugins/gradle/src/META-INF/gradle-maven-integration.xml index 72f46b785ea7..b8fad2f5c3be 100644 --- a/plugins/gradle/src/META-INF/gradle-maven-integration.xml +++ b/plugins/gradle/src/META-INF/gradle-maven-integration.xml @@ -21,7 +21,6 @@ <postStartupActivity implementation="org.jetbrains.plugins.gradle.integrations.maven.GradleProjectStartupActivity"/> <externalSystemTaskNotificationListener implementation="org.jetbrains.plugins.gradle.integrations.maven.GradleMavenProjectImportNotificationListener"/> - <externalProjectDataService implementation="com.intellij.openapi.externalSystem.service.project.manage.ModuleDataService"/> <completion.contributor language="Groovy" order="first" implementationClass="org.jetbrains.plugins.gradle.integrations.maven.codeInsight.completion.MavenDependenciesGradleCompletionContributor"/> </extensions> diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index de6937c18c6c..f15f424a10b8 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -67,6 +67,11 @@ <extensions defaultExtensionNs="com.intellij"> <postStartupActivity implementation="org.jetbrains.plugins.gradle.service.project.GradleStartupActivity"/> + + <orderEnumerationHandlerFactory implementation="org.jetbrains.plugins.gradle.execution.GradleOrderEnumeratorHandler$FactoryImpl"/> + <compileServer.plugin classpath="gradle-jps-plugin.jar"/> + <buildProcess.parametersProvider implementation="org.jetbrains.plugins.gradle.compiler.GradleBuildProcessParametersProvider"/> + <resolveScopeEnlarger implementation="org.jetbrains.plugins.gradle.config.GradleBuildClasspathResolveScopeEnlarger"/> <errorHandler implementation="com.intellij.diagnostic.ITNReporter"/> @@ -95,6 +100,7 @@ <externalSystemConfigLocator implementation="org.jetbrains.plugins.gradle.service.settings.GradleConfigLocator"/> <externalSystemManager implementation="org.jetbrains.plugins.gradle.GradleManager"/> <externalProjectDataService implementation="org.jetbrains.plugins.gradle.service.project.data.BuildClasspathModuleGradleDataService"/> + <externalProjectDataService implementation="org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService"/> <externalSystemNotificationExtension implementation="org.jetbrains.plugins.gradle.service.notification.GradleNotificationExtension" order="last"/> <externalSystemTaskNotificationListener implementation="org.jetbrains.plugins.gradle.service.project.GradleProjectImportNotificationListener"/> diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java new file mode 100644 index 000000000000..4337686235f5 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/compiler/GradleBuildProcessParametersProvider.java @@ -0,0 +1,93 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.compiler; + +import com.google.gson.Gson; +import com.intellij.compiler.server.BuildProcessParametersProvider; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.PathUtil; +import com.intellij.util.containers.ContainerUtil; +import groovy.lang.GroovyObject; +import org.apache.tools.ant.taskdefs.Ant; +import org.gradle.tooling.ProjectConnection; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.util.List; + +/** + * Adds Gradle build dependencies to the project build process' classpath. + * + * @author Vladislav.Soroka + * @since 7/22/2014 + */ +public class GradleBuildProcessParametersProvider extends BuildProcessParametersProvider { + @NotNull private final Project myProject; + + private List<String> myClasspath; + + public GradleBuildProcessParametersProvider(@NotNull Project project) { + myProject = project; + } + + @Override + @NotNull + public List<String> getClassPath() { + if (myClasspath == null) { + myClasspath = ContainerUtil.newArrayList(); + addGradleClassPath(myClasspath); + final ModuleManager moduleManager = ModuleManager.getInstance(myProject); + for (Module module : moduleManager.getModules()) { + if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) { + addOtherClassPath(myClasspath); + break; + } + } + } + return myClasspath; + } + + private static void addGradleClassPath(@NotNull final List<String> classpath) { + String gradleLibDirPath = null; + String gradleToolingApiJarPath = PathUtil.getJarPathForClass(ProjectConnection.class); + if (!StringUtil.isEmpty(gradleToolingApiJarPath)) { + gradleLibDirPath = PathUtil.getParentPath(gradleToolingApiJarPath); + } + if (gradleLibDirPath == null || gradleLibDirPath.isEmpty()) return; + + File gradleLibDir = new File(gradleLibDirPath); + if (!gradleLibDir.isDirectory()) return; + + File[] children = FileUtil.notNullize(gradleLibDir.listFiles()); + for (File child : children) { + if (child.isFile() && child.getName().endsWith(".jar")) { + classpath.add(child.getAbsolutePath()); + } + } + } + + private static void addOtherClassPath(@NotNull final List<String> classpath) { + classpath.add(PathUtil.getJarPathForClass(Ant.class)); + classpath.add(PathUtil.getJarPathForClass(GroovyObject.class)); + classpath.add(PathUtil.getJarPathForClass(Gson.class)); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java new file mode 100644 index 000000000000..01c5275f3828 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/config/GradleResourceCompilerConfigurationGenerator.java @@ -0,0 +1,186 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.config; + +import com.intellij.compiler.server.BuildManager; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompilerMessageCategory; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.ExternalFilter; +import com.intellij.openapi.externalSystem.model.ExternalProject; +import com.intellij.openapi.externalSystem.model.ExternalSourceDirectorySet; +import com.intellij.openapi.externalSystem.model.ExternalSourceSet; +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.CompilerModuleExtension; +import com.intellij.openapi.util.JDOMUtil; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VfsUtilCore; +import com.intellij.util.containers.FactoryMap; +import com.intellij.util.xmlb.XmlSerializer; +import org.jdom.Document; +import org.jdom.Element; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jps.gradle.model.impl.*; +import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/10/2014 + */ +public class GradleResourceCompilerConfigurationGenerator { + + private static Logger LOG = Logger.getInstance(GradleResourceCompilerConfigurationGenerator.class); + + @NotNull private final Project myProject; + @NotNull private final CompileContext myContext; + @NotNull private final Map<String, ExternalProject> myExternalProjectMap; + private final ExternalProjectDataService myExternalProjectDataService; + + public GradleResourceCompilerConfigurationGenerator(@NotNull final Project project, @NotNull final CompileContext context) { + myProject = project; + myContext = context; + myExternalProjectDataService = + (ExternalProjectDataService)ServiceManager.getService(ProjectDataManager.class).getDataService(ExternalProjectDataService.KEY); + assert myExternalProjectDataService != null; + + myExternalProjectMap = new FactoryMap<String, ExternalProject>() { + @Nullable + @Override + protected ExternalProject create(String gradleProjectPath) { + return myExternalProjectDataService.getOrImportRootExternalProject(project, GradleConstants.SYSTEM_ID, new File(gradleProjectPath)); + } + }; + } + + public void generateBuildConfiguration() { + if (!hasGradleModules()) return; + + final BuildManager buildManager = BuildManager.getInstance(); + final File projectSystemDir = buildManager.getProjectSystemDirectory(myProject); + if (projectSystemDir == null) return; + + final File gradleConfigFile = new File(projectSystemDir, GradleProjectConfiguration.CONFIGURATION_FILE_RELATIVE_PATH); + + GradleProjectConfiguration projectConfig = new GradleProjectConfiguration(); + for (Module module : myContext.getCompileScope().getAffectedModules()) { + if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) continue; + + final String gradleProjectPath = module.getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); + assert gradleProjectPath != null; + final ExternalProject externalRootProject = myExternalProjectMap.get(gradleProjectPath); + if (externalRootProject == null) { + myContext.addMessage(CompilerMessageCategory.ERROR, + String.format("Unable to make the module: %s, related gradle module configuration was not imported", + module.getName()), + VfsUtilCore.pathToUrl(gradleProjectPath), -1, -1); + continue; + } + + ExternalProject externalProject = myExternalProjectDataService.findExternalProject(externalRootProject, module); + if (externalProject == null) { + LOG.warn("Unable to find config for module: " + module.getName()); + continue; + } + + final CompilerModuleExtension compilerModuleExtension = CompilerModuleExtension.getInstance(module); + assert compilerModuleExtension != null; + + GradleModuleResourceConfiguration resourceConfig = new GradleModuleResourceConfiguration(); + resourceConfig.id = new ModuleVersion(externalProject.getGroup(), externalProject.getName(), externalProject.getVersion()); + resourceConfig.directory = FileUtil.toSystemIndependentName(externalProject.getProjectDir().getPath()); + + final ExternalSourceSet mainSourcesSet = externalProject.getSourceSets().get("main"); + addResources(resourceConfig.resources, mainSourcesSet, ExternalSystemSourceType.RESOURCE); + + final ExternalSourceSet testSourcesSet = externalProject.getSourceSets().get("test"); + addResources(resourceConfig.testResources, testSourcesSet, ExternalSystemSourceType.TEST_RESOURCE); + + projectConfig.moduleConfigurations.put(module.getName(), resourceConfig); + } + + final Document document = new Document(new Element("gradle-project-configuration")); + XmlSerializer.serializeInto(projectConfig, document.getRootElement()); + buildManager.runCommand(new Runnable() { + @Override + public void run() { + buildManager.clearState(myProject); + FileUtil.createIfDoesntExist(gradleConfigFile); + try { + JDOMUtil.writeDocument(document, gradleConfigFile, "\n"); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + }); + } + + private boolean hasGradleModules() { + for (Module module : myContext.getCompileScope().getAffectedModules()) { + if (ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module)) return true; + } + return false; + } + + private static void addResources(@NotNull List<ResourceRootConfiguration> container, + @Nullable ExternalSourceSet externalSourceSet, + @NotNull ExternalSystemSourceType sourceType) { + if (externalSourceSet == null) return; + final ExternalSourceDirectorySet directorySet = externalSourceSet.getSources().get(sourceType); + if (directorySet == null) return; + + for (File file : directorySet.getSrcDirs()) { + final String dir = file.getPath(); + final ResourceRootConfiguration rootConfiguration = new ResourceRootConfiguration(); + rootConfiguration.directory = FileUtil.toSystemIndependentName(dir); + final String target = directorySet.getOutputDir().getPath(); + rootConfiguration.targetPath = FileUtil.toSystemIndependentName(target); + + rootConfiguration.includes.clear(); + for (String include : directorySet.getIncludes()) { + rootConfiguration.includes.add(include.trim()); + } + rootConfiguration.excludes.clear(); + for (String exclude : directorySet.getExcludes()) { + rootConfiguration.excludes.add(exclude.trim()); + } + + rootConfiguration.isFiltered = !directorySet.getFilters().isEmpty(); + rootConfiguration.filters.clear(); + for (ExternalFilter filter : directorySet.getFilters()) { + final ResourceRootFilter resourceRootFilter = new ResourceRootFilter(); + resourceRootFilter.filterType = filter.getFilterType(); + resourceRootFilter.properties = filter.getPropertiesAsJsonMap(); + rootConfiguration.filters.add(resourceRootFilter); + } + + container.add(rootConfiguration); + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java new file mode 100644 index 000000000000..113e49a61a25 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/execution/GradleOrderEnumeratorHandler.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.execution; + +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.ExternalProject; +import com.intellij.openapi.externalSystem.model.ExternalSourceDirectorySet; +import com.intellij.openapi.externalSystem.model.ExternalSourceSet; +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; +import com.intellij.openapi.externalSystem.util.ExternalSystemConstants; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootModel; +import com.intellij.openapi.roots.OrderEnumerationHandler; +import com.intellij.openapi.roots.OrderRootType; +import com.intellij.openapi.vfs.VfsUtilCore; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService; +import org.jetbrains.plugins.gradle.util.GradleConstants; + +import java.io.File; +import java.util.Collection; + +public class GradleOrderEnumeratorHandler extends OrderEnumerationHandler { + private static final Logger LOG = Logger.getInstance(GradleOrderEnumeratorHandler.class); + + public static class FactoryImpl extends Factory { + @Override + public boolean isApplicable(@NotNull Project project) { + return true; + } + + @Override + public boolean isApplicable(@NotNull Module module) { + return ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, module); + } + + @Override + public OrderEnumerationHandler createHandler(@Nullable Module module) { + return INSTANCE; + } + } + + private static final GradleOrderEnumeratorHandler INSTANCE = new GradleOrderEnumeratorHandler(); + + @Override + public boolean addCustomModuleRoots(@NotNull OrderRootType type, + @NotNull ModuleRootModel rootModel, + @NotNull Collection<String> result, + boolean includeProduction, + boolean includeTests) { + if (!type.equals(OrderRootType.CLASSES)) return false; + if (!ExternalSystemApiUtil.isExternalSystemAwareModule(GradleConstants.SYSTEM_ID, rootModel.getModule())) return false; + + final String gradleProjectPath = rootModel.getModule().getOptionValue(ExternalSystemConstants.ROOT_PROJECT_PATH_KEY); + if (gradleProjectPath == null) { + LOG.error("Root project path of the Gradle project not found for " + rootModel.getModule()); + return false; + } + + final ExternalProjectDataService externalProjectDataService = + (ExternalProjectDataService)ServiceManager.getService(ProjectDataManager.class).getDataService(ExternalProjectDataService.KEY); + + assert externalProjectDataService != null; + final ExternalProject externalRootProject = + externalProjectDataService.getRootExternalProject(GradleConstants.SYSTEM_ID, new File(gradleProjectPath)); + if (externalRootProject == null) { + LOG.debug("Root external project was not yep imported for the project path: " + gradleProjectPath); + return false; + } + + ExternalProject externalProject = externalProjectDataService.findExternalProject(externalRootProject, rootModel.getModule()); + if (externalProject == null) return false; + + if (includeProduction) { + addOutputRoots(externalProject.getSourceSets().get("main"), ExternalSystemSourceType.RESOURCE, result); + } + + if (includeTests) { + addOutputRoots(externalProject.getSourceSets().get("test"), ExternalSystemSourceType.TEST_RESOURCE, result); + } + + return true; + } + + private static void addOutputRoots(@Nullable ExternalSourceSet externalSourceSet, + @NotNull ExternalSystemSourceType sourceType, + @NotNull Collection<String> result) { + if (externalSourceSet == null) return; + final ExternalSourceDirectorySet directorySet = externalSourceSet.getSources().get(sourceType); + if (directorySet == null) return; + + result.add(VfsUtilCore.pathToUrl(directorySet.getOutputDir().getAbsolutePath())); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java index 1d8addd31369..9603470a0878 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/AbstractProjectResolverExtension.java @@ -28,6 +28,7 @@ import com.intellij.openapi.externalSystem.util.Order; import com.intellij.openapi.util.KeyValue; import com.intellij.util.Consumer; import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -80,6 +81,11 @@ public abstract class AbstractProjectResolverExtension implements GradleProjectR return nextResolver.createJavaProjectData(); } + @Override + public void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject) { + nextResolver.populateProjectExtraModels(gradleProject, ideProject); + } + @NotNull @Override public ModuleData createModule(@NotNull IdeaModule gradleModule, @NotNull ProjectData projectData) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java index 6f43559f7a11..ad7ade6a3c58 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/BaseGradleProjectResolverExtension.java @@ -15,14 +15,13 @@ */ package org.jetbrains.plugins.gradle.service.project; +import com.google.gson.GsonBuilder; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.SimpleJavaParameters; import com.intellij.externalSystem.JavaProjectData; import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.externalSystem.model.DataNode; -import com.intellij.openapi.externalSystem.model.ExternalSystemException; -import com.intellij.openapi.externalSystem.model.ProjectKeys; +import com.intellij.openapi.externalSystem.model.*; import com.intellij.openapi.externalSystem.model.project.*; import com.intellij.openapi.externalSystem.model.task.TaskData; import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil; @@ -56,6 +55,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.*; import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData; +import org.jetbrains.plugins.gradle.service.project.data.ExternalProjectDataService; import org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl; import org.jetbrains.plugins.gradle.tooling.internal.init.Init; import org.jetbrains.plugins.gradle.util.GradleBundle; @@ -79,6 +79,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver private static final Logger LOG = Logger.getInstance("#" + BaseGradleProjectResolverExtension.class.getName()); @NotNull @NonNls private static final String UNRESOLVED_DEPENDENCY_PREFIX = "unresolved dependency - "; + private static final String MAIN_SOURCE_SET = "main"; + private static final String TEST_SOURCE_SET = "test"; @NotNull private ProjectResolverContext resolverCtx; @NotNull private final BaseProjectImportErrorHandler myErrorHandler = new BaseProjectImportErrorHandler(); @@ -120,6 +122,14 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver return javaProjectData; } + @Override + public void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject) { + final ExternalProject externalProject = resolverCtx.getExtraProject(ExternalProject.class); + if (externalProject != null) { + ideProject.createChild(ExternalProjectDataService.KEY, externalProject); + } + } + @NotNull @Override public ModuleData createModule(@NotNull IdeaModule gradleModule, @NotNull ProjectData projectData) { @@ -220,6 +230,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver File sourceCompileOutputPath = null; File testCompileOutputPath = null; + File resourceCompileOutputPath; + File testResourceCompileOutputPath; boolean inheritOutputDirs = false; ModuleData moduleData = ideModule.getData(); @@ -229,30 +241,71 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver inheritOutputDirs = moduleCompilerOutput.getInheritOutputDirs(); } + ExternalProject externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject.class); + if (externalProject != null) { + externalProject = new DefaultExternalProject(externalProject); + } + if (!inheritOutputDirs && (sourceCompileOutputPath == null || testCompileOutputPath == null)) { - ModuleExtendedModel moduleExtendedModel = resolverCtx.getExtraProject(gradleModule, ModuleExtendedModel.class); - if (moduleExtendedModel != null) { - ExtIdeaCompilerOutput output = moduleExtendedModel.getCompilerOutput(); - if (output != null) { - if (sourceCompileOutputPath == null) { - sourceCompileOutputPath = output.getMainClassesDir(); + sourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.SOURCE); + resourceCompileOutputPath = getCompileOutputPath(externalProject, MAIN_SOURCE_SET, ExternalSystemSourceType.RESOURCE); + testCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST); + testResourceCompileOutputPath = getCompileOutputPath(externalProject, TEST_SOURCE_SET, ExternalSystemSourceType.TEST_RESOURCE); + } + else { + resourceCompileOutputPath = sourceCompileOutputPath; + testResourceCompileOutputPath = testCompileOutputPath; + + if (externalProject != null) { + final ExternalSourceSet mainSourceSet = externalProject.getSourceSets().get(MAIN_SOURCE_SET); + if (mainSourceSet != null) { + final ExternalSourceDirectorySet resourceDirectories = mainSourceSet.getSources().get(ExternalSystemSourceType.RESOURCE); + if (resourceDirectories instanceof DefaultExternalSourceDirectorySet) { + ((DefaultExternalSourceDirectorySet)resourceDirectories).setOutputDir(sourceCompileOutputPath); } - if (testCompileOutputPath == null) { - testCompileOutputPath = output.getTestClassesDir(); + } + final ExternalSourceSet testSourceSet = externalProject.getSourceSets().get(TEST_SOURCE_SET); + if (testSourceSet != null) { + final ExternalSourceDirectorySet testResourceDirectories = testSourceSet.getSources().get(ExternalSystemSourceType.TEST_RESOURCE); + if (testResourceDirectories instanceof DefaultExternalSourceDirectorySet) { + ((DefaultExternalSourceDirectorySet)testResourceDirectories).setOutputDir(testCompileOutputPath); } } + + final DataNode<ProjectData> projectDataNode = ExternalSystemApiUtil.findParent(ideModule, ProjectKeys.PROJECT); + assert projectDataNode != null; + projectDataNode.createOrReplaceChild(ExternalProjectDataService.KEY, externalProject); } } if (sourceCompileOutputPath != null) { moduleData.setCompileOutputPath(ExternalSystemSourceType.SOURCE, sourceCompileOutputPath.getAbsolutePath()); } + if (resourceCompileOutputPath != null) { + moduleData.setCompileOutputPath(ExternalSystemSourceType.RESOURCE, resourceCompileOutputPath.getAbsolutePath()); + } if (testCompileOutputPath != null) { moduleData.setCompileOutputPath(ExternalSystemSourceType.TEST, testCompileOutputPath.getAbsolutePath()); } + if (testResourceCompileOutputPath != null) { + moduleData.setCompileOutputPath(ExternalSystemSourceType.TEST_RESOURCE, testResourceCompileOutputPath.getAbsolutePath()); + } + moduleData.setInheritProjectCompileOutputPath(inheritOutputDirs || sourceCompileOutputPath == null); } + @Nullable + private static File getCompileOutputPath(@Nullable ExternalProject externalProject, + @NotNull String sourceSetName, + @NotNull ExternalSystemSourceType sourceType) { + if (externalProject == null) return null; + final ExternalSourceSet sourceSet = externalProject.getSourceSets().get(sourceSetName); + if(sourceSet == null) return null; + + final ExternalSourceDirectorySet directorySet = sourceSet.getSources().get(sourceType); + return directorySet != null ? directorySet.getOutputDir() : null; + } + @Override public void populateModuleDependencies(@NotNull IdeaModule gradleModule, @NotNull DataNode<ModuleData> ideModule, @@ -319,17 +372,19 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver @Override public Set<Class> getExtraProjectModelClasses() { return ContainerUtil.<Class>set( - GradleBuild.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); + GradleBuild.class, ExternalProject.class, ModuleExtendedModel.class, BuildScriptClasspathModel.class); } @NotNull @Override public Set<Class> getToolingExtensionsClasses() { return ContainerUtil.<Class>set( + ExternalProject.class, // gradle-tooling-extension-api jar ProjectImportAction.class, // gradle-tooling-extension-impl jar - ModelBuildScriptClasspathBuilderImpl.class + ModelBuildScriptClasspathBuilderImpl.class, + GsonBuilder.class ); } @@ -416,6 +471,8 @@ public class BaseGradleProjectResolverExtension implements GradleProjectResolver List<String> additionalEntries = ContainerUtilRt.newArrayList(); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(GroovyObject.class)); + ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(GsonBuilder.class)); + ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(ExternalProject.class)); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(JavaProjectData.class)); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(LanguageLevel.class)); ContainerUtilRt.addIfNotNull(additionalEntries, PathUtil.getJarPathForClass(StdModuleTypes.class)); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java index 8a2ffaae36c9..24c8e126ed3f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolver.java @@ -199,6 +199,9 @@ public class GradleProjectResolver implements ExternalSystemProjectResolver<Grad projectDataNode.createChild(JavaProjectData.KEY, javaProjectData); IdeaProject ideaProject = resolverCtx.getModels().getIdeaProject(); + + projectResolverChain.populateProjectExtraModels(ideaProject, projectDataNode); + DomainObjectSet<? extends IdeaModule> gradleModules = ideaProject.getModules(); if (gradleModules == null || gradleModules.isEmpty()) { throw new IllegalStateException("No modules found for the target project: " + ideaProject); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java index b727005db845..6dd201b839fb 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleProjectResolverExtension.java @@ -27,6 +27,7 @@ import com.intellij.openapi.externalSystem.service.ParametersEnhancer; import com.intellij.openapi.util.KeyValue; import com.intellij.util.Consumer; import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.GradleManager; @@ -62,6 +63,8 @@ public interface GradleProjectResolverExtension extends ParametersEnhancer { @NotNull JavaProjectData createJavaProjectData(); + void populateProjectExtraModels(@NotNull IdeaProject gradleProject, @NotNull DataNode<ProjectData> ideProject); + @NotNull ModuleData createModule(@NotNull IdeaModule gradleModule, @NotNull ProjectData projectData); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java index 81ceaa3177e2..0e5fcc12f3dc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/GradleStartupActivity.java @@ -21,6 +21,11 @@ import com.intellij.ide.util.newProjectWizard.AddModuleWizard; import com.intellij.notification.Notification; import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationType; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys; import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; @@ -30,6 +35,8 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vfs.VfsUtilCore; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.project.MavenResourceCompilerConfigurationGenerator; +import org.jetbrains.plugins.gradle.config.GradleResourceCompilerConfigurationGenerator; import org.jetbrains.plugins.gradle.service.GradleBuildClasspathManager; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportBuilder; import org.jetbrains.plugins.gradle.service.project.wizard.GradleProjectImportProvider; @@ -52,9 +59,22 @@ public class GradleStartupActivity implements StartupActivity { private static final String DO_NOT_SHOW_EVENT_DESCRIPTION = "do.not.show"; @Override - public void runActivity(@NotNull Project project) { + public void runActivity(@NotNull final Project project) { configureBuildClasspath(project); showNotificationForUnlinkedGradleProject(project); + CompilerManager.getInstance(project).addBeforeTask(new CompileTask() { + @Override + public boolean execute(CompileContext context) { + AccessToken token = ReadAction.start(); + try { + new GradleResourceCompilerConfigurationGenerator(project, context).generateBuildConfiguration(); + } + finally { + token.finish(); + } + return true; + } + }); } private static void configureBuildClasspath(@NotNull final Project project) { diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java index b7f94dd57122..3aa0027185bf 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/ProjectResolverContext.java @@ -19,6 +19,7 @@ import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId; import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.model.idea.IdeaModule; +import org.gradle.tooling.model.idea.IdeaProject; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.model.ProjectImportAction; @@ -93,7 +94,12 @@ public class ProjectResolverContext { } @Nullable - public <T> T getExtraProject(@NotNull IdeaModule module, Class<T> modelClazz) { + public <T> T getExtraProject(Class<T> modelClazz) { + return myModels.getExtraProject(null, modelClazz); + } + + @Nullable + public <T> T getExtraProject(@Nullable IdeaModule module, Class<T> modelClazz) { return myModels.getExtraProject(module, modelClazz); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java new file mode 100644 index 000000000000..fae9ee0d88c1 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectDataService.java @@ -0,0 +1,233 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.service.project.data; + +import com.intellij.CommonBundle; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.project.ProjectData; +import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener; +import com.intellij.openapi.externalSystem.service.internal.ExternalSystemResolveProjectTask; +import com.intellij.openapi.externalSystem.service.notification.ExternalSystemNotificationManager; +import com.intellij.openapi.externalSystem.service.notification.NotificationSource; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataManager; +import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataService; +import com.intellij.openapi.externalSystem.settings.ExternalProjectSettings; +import com.intellij.openapi.externalSystem.util.*; +import com.intellij.openapi.module.Module; +import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ex.ProjectRootManagerEx; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.Function; +import com.intellij.util.containers.ConcurrentFactoryMap; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.ui.UIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.util.Collection; +import java.util.Map; + +/** + * @author Vladislav.Soroka + * @since 7/17/2014 + */ +@Order(ExternalSystemConstants.BUILTIN_SERVICE_ORDER) +public class ExternalProjectDataService implements ProjectDataService<ExternalProject, Project> { + private static final Logger LOG = Logger.getInstance(ExternalProjectDataService.class); + + @NotNull public static final Key<ExternalProject> KEY = Key.create(ExternalProject.class, ProjectKeys.TASK.getProcessingWeight() + 1); + + @NotNull private final Map<Pair<ProjectSystemId, File>, ExternalProject> myExternalRootProjects; + + @NotNull private ProjectDataManager myProjectDataManager; + + public ExternalProjectDataService(@NotNull ProjectDataManager projectDataManager) { + myProjectDataManager = projectDataManager; + myExternalRootProjects = new ConcurrentFactoryMap<Pair<ProjectSystemId, File>, ExternalProject>() { + @Nullable + @Override + protected ExternalProject create(Pair<ProjectSystemId, File> key) { + return new ExternalProjectSerializer().load(key.first, key.second); + } + + @Override + public ExternalProject put(Pair<ProjectSystemId, File> key, ExternalProject value) { + new ExternalProjectSerializer().save(value); + return super.put(key, value); + } + }; + } + + @NotNull + @Override + public Key<ExternalProject> getTargetDataKey() { + return KEY; + } + + public void importData(@NotNull final Collection<DataNode<ExternalProject>> toImport, + @NotNull final Project project, + final boolean synchronous) { + if (toImport.size() != 1) { + throw new IllegalArgumentException( + String.format("Expected to get a single external project but got %d: %s", toImport.size(), toImport)); + } + saveExternalProject(toImport.iterator().next().getData()); + } + + @Override + public void removeData(@NotNull final Collection<? extends Project> modules, @NotNull Project project, boolean synchronous) { + } + + @Nullable + public ExternalProject getOrImportRootExternalProject(@NotNull Project project, + @NotNull ProjectSystemId systemId, + @NotNull File projectRootDir) { + final ExternalProject externalProject = getRootExternalProject(systemId, projectRootDir); + return externalProject != null ? externalProject : importExternalProject(project, systemId, projectRootDir); + } + + @Nullable + private ExternalProject importExternalProject(@NotNull final Project project, + @NotNull final ProjectSystemId projectSystemId, + @NotNull final File projectRootDir) { + final Boolean result = UIUtil.invokeAndWaitIfNeeded(new Computable<Boolean>() { + @Override + public Boolean compute() { + final Ref<Boolean> result = new Ref<Boolean>(false); + if (project.isDisposed()) return false; + + final String linkedProjectPath = FileUtil.toCanonicalPath(projectRootDir.getPath()); + final ExternalProjectSettings projectSettings = + ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectSettings(linkedProjectPath); + if (projectSettings == null) { + LOG.warn("Unable to get project settings for project path: " + linkedProjectPath); + if (LOG.isDebugEnabled()) { + LOG.debug("Available projects paths: " + ContainerUtil.map( + ExternalSystemApiUtil.getSettings(project, projectSystemId).getLinkedProjectsSettings(), + new Function<ExternalProjectSettings, String>() { + @Override + public String fun(ExternalProjectSettings settings) { + return settings.getExternalProjectPath(); + } + })); + } + return false; + } + + final File projectFile = new File(linkedProjectPath); + final String projectName; + if (projectFile.isFile()) { + projectName = projectFile.getParentFile().getName(); + } + else { + projectName = projectFile.getName(); + } + + // ask a user for the project import if auto-import is disabled + if (!projectSettings.isUseAutoImport()) { + String message = String.format("Project '%s' require synchronization with %s configuration. \nImport the project?", + projectName, projectSystemId.getReadableName()); + int returnValue = Messages.showOkCancelDialog( + message, "Import Project", CommonBundle.getOkButtonText(), CommonBundle.getCancelButtonText(), Messages.getQuestionIcon() + ); + if (returnValue != Messages.OK) return false; + } + + final String title = ExternalSystemBundle.message("progress.import.text", linkedProjectPath, projectSystemId.getReadableName()); + new Task.Modal(project, title, false) { + @Override + public void run(@NotNull ProgressIndicator indicator) { + if (project.isDisposed()) return; + + ExternalSystemNotificationManager.getInstance(project) + .clearNotifications(null, NotificationSource.PROJECT_SYNC, projectSystemId); + ExternalSystemResolveProjectTask task = + new ExternalSystemResolveProjectTask(projectSystemId, project, linkedProjectPath, false); + task.execute(indicator, ExternalSystemTaskNotificationListener.EP_NAME.getExtensions()); + if (project.isDisposed()) return; + + final Throwable error = task.getError(); + if (error != null) { + ExternalSystemNotificationManager.getInstance(project) + .processExternalProjectRefreshError(error, projectName, projectSystemId); + return; + } + final DataNode<ProjectData> projectDataDataNode = task.getExternalProject(); + if (projectDataDataNode == null) return; + + final Collection<DataNode<ExternalProject>> nodes = ExternalSystemApiUtil.findAll(projectDataDataNode, KEY); + if (nodes.size() != 1) { + throw new IllegalArgumentException( + String.format("Expected to get a single external project but got %d: %s", nodes.size(), nodes)); + } + + ProjectRootManagerEx.getInstanceEx(myProject).mergeRootsChangesDuring(new Runnable() { + @Override + public void run() { + myProjectDataManager.importData(KEY, nodes, project, true); + } + }); + + result.set(true); + } + }.queue(); + + return result.get(); + } + }); + + return result ? getRootExternalProject(projectSystemId, projectRootDir) : null; + } + + @Nullable + public ExternalProject getRootExternalProject(@NotNull ProjectSystemId systemId, @NotNull File projectRootDir) { + return myExternalRootProjects.get(Pair.create(systemId, projectRootDir)); + } + + public void saveExternalProject(@NotNull ExternalProject externalProject) { + myExternalRootProjects.put( + Pair.create(new ProjectSystemId(externalProject.getExternalSystemId()), externalProject.getProjectDir()), + new DefaultExternalProject(externalProject) + ); + } + + @Nullable + public ExternalProject findExternalProject(@NotNull ExternalProject parentProject, @NotNull Module module) { + String externalProjectId = ExternalSystemApiUtil.getExternalProjectId(module); + return externalProjectId != null ? findExternalProject(parentProject, externalProjectId) : null; + } + + @Nullable + private static ExternalProject findExternalProject(@NotNull ExternalProject parentProject, @NotNull String externalProjectId) { + if (parentProject.getQName().equals(externalProjectId)) return parentProject; + if (parentProject.getChildProjects().containsKey(externalProjectId)) { + return parentProject.getChildProjects().get(externalProjectId); + } + for (ExternalProject externalProject : parentProject.getChildProjects().values()) { + final ExternalProject project = findExternalProject(externalProject, externalProjectId); + if (project != null) return project; + } + return null; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectSerializer.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectSerializer.java new file mode 100644 index 000000000000..8828b9ef5880 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/data/ExternalProjectSerializer.java @@ -0,0 +1,262 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.service.project.data; + +import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; +import com.esotericsoftware.kryo.io.Input; +import com.esotericsoftware.kryo.io.Output; +import com.esotericsoftware.kryo.serializers.CollectionSerializer; +import com.esotericsoftware.kryo.serializers.DefaultSerializers; +import com.esotericsoftware.kryo.serializers.FieldSerializer; +import com.esotericsoftware.kryo.serializers.MapSerializer; +import com.esotericsoftware.minlog.Log; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.externalSystem.model.*; +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.io.StreamUtil; +import gnu.trove.THashMap; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.objenesis.strategy.StdInstantiatorStrategy; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.util.*; + +/** + * @author Vladislav.Soroka + * @since 7/15/2014 + */ +public class ExternalProjectSerializer { + private static final Logger LOG = Logger.getInstance(ExternalProjectSerializer.class); + + private final Kryo myKryo; + + public ExternalProjectSerializer() { + myKryo = new Kryo() { + @Override + public <T> T newInstance(Class<T> type) { + LOG.error("Serializing default type: " + type); + return super.newInstance(type); + } + }; + configureKryo(); + } + + private void configureKryo() { + myKryo.setAutoReset(true); + + myKryo.setRegistrationRequired(true); + Log.set(Log.LEVEL_WARN); + + myKryo.register(ArrayList.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new ArrayList(); + } + }); + myKryo.register(HashMap.class, new MapSerializer() { + @Override + protected Map create(Kryo kryo, Input input, Class<Map> type) { + return new HashMap(); + } + }); + myKryo.register(HashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new HashSet(); + } + }); + + myKryo.register(File.class, new FileSerializer()); + myKryo.register(DefaultExternalProject.class, new FieldSerializer<DefaultExternalProject>(myKryo, DefaultExternalProject.class) { + @Override + protected DefaultExternalProject create(Kryo kryo, Input input, Class<DefaultExternalProject> type) { + return new DefaultExternalProject(); + } + }); + + myKryo.register(DefaultExternalTask.class, new FieldSerializer<DefaultExternalTask>(myKryo, DefaultExternalTask.class) { + @Override + protected DefaultExternalTask create(Kryo kryo, Input input, Class<DefaultExternalTask> type) { + return new DefaultExternalTask(); + } + }); + + myKryo.register(DefaultExternalPlugin.class, new FieldSerializer<DefaultExternalPlugin>(myKryo, DefaultExternalPlugin.class) { + @Override + protected DefaultExternalPlugin create(Kryo kryo, Input input, Class<DefaultExternalPlugin> type) { + return new DefaultExternalPlugin(); + } + }); + + myKryo.register(DefaultExternalSourceSet.class, new FieldSerializer<DefaultExternalSourceSet>(myKryo, DefaultExternalSourceSet.class) { + @Override + protected DefaultExternalSourceSet create(Kryo kryo, Input input, Class<DefaultExternalSourceSet> type) { + return new DefaultExternalSourceSet(); + } + }); + + myKryo.register( + DefaultExternalSourceDirectorySet.class, + new FieldSerializer<DefaultExternalSourceDirectorySet>(myKryo, DefaultExternalSourceDirectorySet.class) { + @Override + protected DefaultExternalSourceDirectorySet create(Kryo kryo, Input input, Class<DefaultExternalSourceDirectorySet> type) { + return new DefaultExternalSourceDirectorySet(); + } + } + ); + + myKryo.register(DefaultExternalFilter.class, new FieldSerializer<DefaultExternalFilter>(myKryo, DefaultExternalFilter.class) { + @Override + protected DefaultExternalFilter create(Kryo kryo, Input input, Class<DefaultExternalFilter> type) { + return new DefaultExternalFilter(); + } + }); + + myKryo.register(ExternalSystemSourceType.class, new DefaultSerializers.EnumSerializer(ExternalSystemSourceType.class)); + + myKryo.register(LinkedHashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new LinkedHashSet(); + } + }); + myKryo.register(HashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new HashSet(); + } + }); + myKryo.register(THashSet.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new THashSet(); + } + }); + myKryo.register(Set.class, new CollectionSerializer() { + @Override + protected Collection create(Kryo kryo, Input input, Class<Collection> type) { + return new HashSet(); + } + }); + myKryo.register(THashMap.class, new MapSerializer() { + @Override + protected Map create(Kryo kryo, Input input, Class<Map> type) { + return new THashMap(); + } + }); + } + + + public void save(@NotNull ExternalProject externalProject) { + Output output = null; + try { + final String externalProjectPath = externalProject.getProjectDir().getPath(); + final File configurationFile = + getProjectConfigurationFile(new ProjectSystemId(externalProject.getExternalSystemId()), externalProjectPath); + if (!FileUtil.createParentDirs(configurationFile)) return; + + output = new Output(new FileOutputStream(configurationFile)); + myKryo.writeObject(output, externalProject); + } + catch (FileNotFoundException e) { + LOG.error(e); + } + finally { + StreamUtil.closeStream(output); + } + } + + @Nullable + public ExternalProject load(@NotNull ProjectSystemId externalSystemId, File externalProjectPath) { + Input input = null; + try { + final File configurationFile = getProjectConfigurationFile(externalSystemId, externalProjectPath.getPath()); + if (!configurationFile.isFile()) return null; + + input = new Input(new FileInputStream(configurationFile)); + return myKryo.readObject(input, DefaultExternalProject.class); + } + catch (Exception e) { + LOG.error(e); + } + finally { + StreamUtil.closeStream(input); + } + + return null; + } + + private static File getProjectConfigurationFile(ProjectSystemId externalSystemId, String externalProjectPath) { + return new File(getProjectConfigurationDir(externalSystemId), Integer.toHexString(externalProjectPath.hashCode()) + "/project.dat"); + } + + private static File getProjectConfigurationDir(ProjectSystemId externalSystemId) { + return getPluginSystemDir(externalSystemId, "Projects"); + } + + private static File getPluginSystemDir(ProjectSystemId externalSystemId, String folder) { + return new File(PathManager.getSystemPath(), externalSystemId.getId().toLowerCase() + "/" + folder).getAbsoluteFile(); + } + + private static class FileSerializer extends Serializer<File> { + private final Kryo myStdKryo; + + public FileSerializer() { + myStdKryo = new Kryo(); + myStdKryo.register(File.class); + myStdKryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); + } + + @Override + public void write(Kryo kryo, Output output, File object) { + myStdKryo.writeObject(output, object); + } + + @Override + public File read(Kryo kryo, Input input, Class<File> type) { + File file = myStdKryo.readObject(input, File.class); + return new File(file.getPath()); + } + } + + private static class StdSerializer<T> extends Serializer<T> { + private final Kryo myStdKryo; + + public StdSerializer(Class<T> clazz) { + myStdKryo = new Kryo(); + myStdKryo.register(clazz); + myStdKryo.setInstantiatorStrategy(new StdInstantiatorStrategy()); + } + + @Override + public void write(Kryo kryo, Output output, T object) { + myStdKryo.writeObject(output, object); + } + + @Override + public T read(Kryo kryo, Input input, Class<T> type) { + return myStdKryo.readObject(input, type); + } + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java index 213ba84271ef..10f766cc5e34 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/project/wizard/GradleProjectOpenProcessor.java @@ -16,17 +16,26 @@ package org.jetbrains.plugins.gradle.service.project.wizard; import com.intellij.ide.util.newProjectWizard.AddModuleWizard; -import com.intellij.ide.util.projectWizard.ProjectBuilder; +import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.ide.wizard.Step; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.externalSystem.service.project.wizard.SelectExternalProjectStep; -import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.projectImport.ProjectOpenProcessorBase; import com.intellij.util.Function; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl; +import org.jetbrains.plugins.gradle.service.settings.GradleSystemSettingsControl; +import org.jetbrains.plugins.gradle.service.settings.ImportFromGradleControl; +import org.jetbrains.plugins.gradle.settings.DistributionType; +import org.jetbrains.plugins.gradle.settings.GradleProjectSettings; +import org.jetbrains.plugins.gradle.settings.GradleSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; +import static org.jetbrains.plugins.gradle.util.GradleEnvironment.Headless.*; /** * @author Denis Zhdanov @@ -61,24 +70,90 @@ public class GradleProjectOpenProcessor extends ProjectOpenProcessorBase<GradleP @Override protected boolean doQuickImport(VirtualFile file, WizardContext wizardContext) { - AddModuleWizard dialog = new AddModuleWizard(null, file.getPath(), new GradleProjectImportProvider(getBuilder())); + final GradleProjectImportProvider projectImportProvider = new GradleProjectImportProvider(getBuilder()); + getBuilder().setFileToImport(file.getPath()); getBuilder().prepare(wizardContext); getBuilder().getControl(null).setLinkedProjectPath(file.getPath()); - dialog.getWizardContext().setProjectBuilder(getBuilder()); - dialog.navigateToStep(new Function<Step, Boolean>() { - @Override - public Boolean fun(Step step) { - return step instanceof SelectExternalProjectStep; - } - }); - boolean result = dialog.showAndGet(); + final boolean result; + if (ApplicationManager.getApplication().isHeadlessEnvironment()) { + result = setupGradleProjectSettingsInHeadlessMode(file, projectImportProvider, wizardContext); + } + else { + AddModuleWizard dialog = new AddModuleWizard(null, file.getPath(), projectImportProvider); + dialog.getWizardContext().setProjectBuilder(getBuilder()); + dialog.navigateToStep(new Function<Step, Boolean>() { + @Override + public Boolean fun(Step step) { + return step instanceof SelectExternalProjectStep; + } + }); + result = dialog.showAndGet(); + } if (result && getBuilder().getExternalProjectNode() != null) { wizardContext.setProjectName(getBuilder().getExternalProjectNode().getData().getInternalName()); } return result; } + private boolean setupGradleProjectSettingsInHeadlessMode(VirtualFile file, + GradleProjectImportProvider projectImportProvider, + WizardContext wizardContext) { + final ModuleWizardStep[] wizardSteps = projectImportProvider.createSteps(wizardContext); + if (wizardSteps.length > 0 && wizardSteps[0] instanceof SelectExternalProjectStep) { + SelectExternalProjectStep selectExternalProjectStep = (SelectExternalProjectStep)wizardSteps[0]; + wizardContext.setProjectBuilder(getBuilder()); + try { + selectExternalProjectStep.updateStep(); + final ImportFromGradleControl importFromGradleControl = getBuilder().getControl(wizardContext.getProject()); + + GradleProjectSettingsControl gradleProjectSettingsControl = + (GradleProjectSettingsControl)importFromGradleControl.getProjectSettingsControl(); + + final GradleProjectSettings projectSettings = gradleProjectSettingsControl.getInitialSettings(); + + if (GRADLE_DISTRIBUTION_TYPE != null) { + for (DistributionType type : DistributionType.values()) { + if (type.name().equals(GRADLE_DISTRIBUTION_TYPE)) { + projectSettings.setDistributionType(type); + break; + } + } + } + if (GRADLE_HOME != null) { + projectSettings.setGradleHome(GRADLE_HOME); + } + gradleProjectSettingsControl.reset(); + + final GradleSystemSettingsControl systemSettingsControl = + (GradleSystemSettingsControl)importFromGradleControl.getSystemSettingsControl(); + assert systemSettingsControl != null; + final GradleSettings gradleSettings = systemSettingsControl.getInitialSettings(); + if (GRADLE_VM_OPTIONS != null) { + gradleSettings.setGradleVmOptions(GRADLE_VM_OPTIONS); + } + if (GRADLE_OFFLINE != null) { + gradleSettings.setOfflineWork(Boolean.parseBoolean(GRADLE_OFFLINE)); + } + String serviceDirectory = GRADLE_SERVICE_DIRECTORY; + if (GRADLE_SERVICE_DIRECTORY != null) { + gradleSettings.setServiceDirectoryPath(serviceDirectory); + } + systemSettingsControl.reset(); + + if (!selectExternalProjectStep.validate()) { + return false; + } + } + catch (ConfigurationException e) { + Messages.showErrorDialog(wizardContext.getProject(), e.getMessage(), e.getTitle()); + return false; + } + selectExternalProjectStep.updateDataModel(); + } + return true; + } + @Override public boolean lookForProjectsInDirectory() { return false; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java index ffdf37c74b87..ab6454c46c99 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/service/settings/GradleSystemSettingsControl.java @@ -173,4 +173,9 @@ public class GradleSystemSettingsControl implements ExternalSystemSettingsContro public void disposeUIResources() { ExternalSystemUiUtil.disposeUi(this); } + + @NotNull + public GradleSettings getInitialSettings() { + return myInitialSettings; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java index 2c61ac6c10eb..eb780ced4d5a 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleEnvironment.java @@ -13,6 +13,18 @@ public class GradleEnvironment { @NonNls public static final boolean DISABLE_ENHANCED_TOOLING_API = Boolean.getBoolean("gradle.disable.enhanced.tooling.api"); @NonNls public static final boolean ADJUST_USER_DIR = Boolean.getBoolean("gradle.adjust.userdir"); + public static class Headless { + @NonNls public static final String GRADLE_DISTRIBUTION_TYPE = System.getProperty("idea.gradle.distributionType"); + @NonNls public static final String GRADLE_HOME = System.getProperty("idea.gradle.home"); + @NonNls public static final String GRADLE_VM_OPTIONS = System.getProperty("idea.gradle.vmOptions"); + @NonNls public static final String GRADLE_OFFLINE = System.getProperty("idea.gradle.offline"); + @NonNls public static final String GRADLE_SERVICE_DIRECTORY = System.getProperty("idea.gradle.serviceDirectory"); + + private Headless() { + } + } + + private GradleEnvironment() { } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java new file mode 100644 index 000000000000..3b508c8cf289 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleCompilingTestCase.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.compiler; + +import com.intellij.compiler.artifacts.ArtifactsTestUtil; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ReadAction; +import com.intellij.openapi.compiler.CompileContext; +import com.intellij.openapi.compiler.CompileTask; +import com.intellij.openapi.compiler.CompilerManager; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.packaging.impl.artifacts.ArtifactUtil; +import com.intellij.util.io.TestFileSystemItem; +import org.jetbrains.plugins.gradle.config.GradleResourceCompilerConfigurationGenerator; +import org.jetbrains.plugins.gradle.importing.GradleImportingTestCase; + +import java.io.File; + +/** + * @author Vladislav.Soroka + * @since 7/21/2014 + */ +public abstract class GradleCompilingTestCase extends GradleImportingTestCase { + @Override + protected void setUpInWriteAction() throws Exception { + super.setUpInWriteAction(); + CompilerManager.getInstance(myProject).addBeforeTask(new CompileTask() { + @Override + public boolean execute(CompileContext context) { + AccessToken token = ReadAction.start(); + try { + new GradleResourceCompilerConfigurationGenerator(myProject, context).generateBuildConfiguration(); + } + finally { + token.finish(); + } + return true; + } + }); + } + + protected void assertCopied(String path) { + assertTrue(new File(myProjectConfig.getParent().getPath(), path).exists()); + } + + protected void assertCopied(String path, String content) { + assertCopied(path); + assertSameLinesWithFile(new File(myProjectConfig.getParent().getPath(), path).getPath(), content); + } + + protected void assertNotCopied(String path) { + assertFalse(new File(myProjectConfig.getParent().getPath(), path).exists()); + } + + @Override + protected void assertArtifactOutputPath(String artifactName, String expected) { + final String defaultArtifactOutputPath = ArtifactUtil.getDefaultArtifactOutputPath(artifactName, myProject); + assert defaultArtifactOutputPath != null; + final String basePath = FileUtil.toSystemIndependentName(new File(defaultArtifactOutputPath).getParent()); + super.assertArtifactOutputPath(artifactName, basePath + expected); + } + + protected void assertArtifactOutputFile(String artifactName, String path, String content) { + final String defaultArtifactOutputPath = ArtifactUtil.getDefaultArtifactOutputPath(artifactName, myProject); + assert defaultArtifactOutputPath != null; + final String basePath = FileUtil.toSystemIndependentName(new File(defaultArtifactOutputPath).getParent()); + assertSameLinesWithFile(basePath + path, content); + } + + protected void assertArtifactOutputFile(String artifactName, String path) { + final String defaultArtifactOutputPath = ArtifactUtil.getDefaultArtifactOutputPath(artifactName, myProject); + assert defaultArtifactOutputPath != null; + final String basePath = FileUtil.toSystemIndependentName(new File(defaultArtifactOutputPath).getParent()); + assertExists(new File(basePath + path)); + } +} diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java new file mode 100644 index 000000000000..df9c6a879ac7 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceFilteringTest.java @@ -0,0 +1,132 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.compiler; + +import org.junit.Test; + +/** + * @author Vladislav.Soroka + * @since 7/21/2014 + */ +@SuppressWarnings("JUnit4AnnotatedMethodInJUnit3TestCase") +public class GradleResourceFilteringTest extends GradleCompilingTestCase { + + @Test + public void testHeadFilter() throws Exception { + createProjectSubFile( + "src/main/resources/dir/file.txt", "1 Header\n" + + "2\n" + + "3 another text\n" + + "4\n" + + "5 another text \n" + + "6 another text @token@ another text\n" + + "7\n" + + "8 Footer"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " filter(HeadFilter, lines:3, skip:2)\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file.txt", "3 another text\n" + + "4\n" + + "5 another text \n"); + } + + @Test + public void testReplaceTokensFilter() throws Exception { + createProjectSubFile( + "src/main/resources/dir/file.txt", "1 Header\n" + + "2\n" + + "3 #token1#another text\n" + + "4\n" + + "5 another text \n" + + "6 another text #token2# another text\n" + + "7\n" + + "8 Footer"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " filter(ReplaceTokens, tokens:[token1:'<11111>', token2:'<2222>'], beginToken: '#', endToken: '#')\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file.txt", "1 Header\n" + + "2\n" + + "3 <11111>another text\n" + + "4\n" + + "5 another text \n" + + "6 another text <2222> another text\n" + + "7\n" + + "8 Footer"); + } + + @Test + public void testRenameFilter() throws Exception { + createProjectSubFile("src/main/resources/dir/file.txt"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " rename 'file.txt', 'file001.txt'\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file001.txt"); + } + + @Test + public void testFiltersChain() throws Exception { + createProjectSubFile( + "src/main/resources/dir/file.txt", "1 Header\n" + + "2\n" + + "3 another text@token1@\n" + + "4\n" + + "5 another text \n" + + "6 another text @token2@ another text\n" + + "7\n" + + "8 Footer"); + importProject( + "apply plugin: 'java'\n" + + "\n" + + "import org.apache.tools.ant.filters.*\n" + + "processResources {\n" + + " filter(HeadFilter, lines:4, skip:2)\n" + + " filter(ReplaceTokens, tokens:[token1:'<11111>', token2:'<2222>'])\n" + + " rename 'file.txt', 'file001.txt'\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file001.txt", "3 another text<11111>\n" + + "4\n" + + "5 another text \n" + + "6 another text <2222> another text"); + } +}
\ No newline at end of file diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java new file mode 100644 index 000000000000..873234425e30 --- /dev/null +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/compiler/GradleResourceProcessingTest.java @@ -0,0 +1,176 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.compiler; + +import org.junit.Test; + +import java.io.IOException; + +/** + * @author Vladislav.Soroka + * @since 7/21/2014 + */ +@SuppressWarnings("JUnit4AnnotatedMethodInJUnit3TestCase") +public class GradleResourceProcessingTest extends GradleCompilingTestCase { + + @Test + public void testBasicResourceCopying() throws Exception { + createProjectSubFile("src/main/resources/dir/file.properties"); + createProjectSubFile("src/test/resources/dir/file-test.properties"); + importProject( + "apply plugin: 'java'" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("build/resources/main/dir/file.properties"); + assertCopied("build/resources/test/dir/file-test.properties"); + } + + @Test + public void testResourceProcessingWithIdeaGradlePluginCustomization() throws Exception { + createProjectSubFile("src/main/resources/dir/file.properties"); + createProjectSubFile("src/test/resources/dir/file-test.properties"); + importProject( + "apply plugin: 'java'\n" + + "apply plugin: 'idea'\n" + + "idea {\n" + + " module {\n" + + " inheritOutputDirs = false\n" + + " outputDir = file('muchBetterOutputDir')\n" + + " testOutputDir = file('muchBetterTestOutputDir')\n" + + " }\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopied("muchBetterOutputDir/dir/file.properties"); + assertCopied("muchBetterTestOutputDir/dir/file-test.properties"); + } + + @Test + public void testIncludesAndExcludesInSourceSets() throws Exception { + createFilesForIncludesAndExcludesTest(); + + importProject( + "apply plugin: 'java'\n" + + "\n" + + "sourceSets {\n" + + " main {\n" + + " resources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + " }\n" + + " }\n" + + " test {\n" + + " resources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + " }\n" + + " }\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopiedResources(); + } + + @Test + public void testIncludesAndExcludesInAllSourceSets() throws Exception { + createFilesForIncludesAndExcludesTest(); + + importProject( + "apply plugin: 'java'\n" + + "\n" + + "sourceSets.all {\n" + + " resources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + " }\n" + + "}" + ); + assertModules("project"); + compileModules("project"); + + assertCopiedResources(); + } + + + @Test + public void testIncludesAndExcludesInResourcesTask() throws Exception { + createFilesForIncludesAndExcludesTest(); + + importProject( + "apply plugin: 'java'\n" + + "\n" + + "processResources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + "}\n" + + "\n" + + "processTestResources {\n" + + " include '**/*.yyy'\n" + + " include '**/*.xxx'\n" + + " exclude 'dir/*.yyy'\n" + + " exclude '*.xxx'\n" + + "}\n" + ); + assertModules("project"); + compileModules("project"); + + assertCopiedResources(); + } + + private void createFilesForIncludesAndExcludesTest() throws IOException { + createProjectSubFile("src/main/resources/dir/file.xxx"); + createProjectSubFile("src/main/resources/dir/file.yyy"); + createProjectSubFile("src/main/resources/file.xxx"); + createProjectSubFile("src/main/resources/file.yyy"); + createProjectSubFile("src/main/resources/file.zzz"); + + createProjectSubFile("src/test/resources/dir/file.xxx"); + createProjectSubFile("src/test/resources/dir/file.yyy"); + createProjectSubFile("src/test/resources/file.xxx"); + createProjectSubFile("src/test/resources/file.yyy"); + createProjectSubFile("src/test/resources/file.zzz"); + } + + private void assertCopiedResources() { + // assert production resources + assertCopied("build/resources/main/dir/file.xxx"); + assertCopied("build/resources/main/file.yyy"); + assertNotCopied("build/resources/main/dir/file.yyy"); + assertNotCopied("build/resources/main/file.xxx"); + assertNotCopied("build/resources/main/file.zzz"); + + // assert test resources + assertCopied("build/resources/test/dir/file.xxx"); + assertCopied("build/resources/test/file.yyy"); + assertNotCopied("build/resources/test/dir/file.yyy"); + assertNotCopied("build/resources/test/file.xxx"); + assertNotCopied("build/resources/test/file.zzz"); + } +} diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java index 97dfd2547b73..91889d85fa9f 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ModuleExtendedModel.java @@ -22,9 +22,12 @@ import java.io.Serializable; import java.util.List; /** + * @deprecated Use {@link com.intellij.openapi.externalSystem.model.ExternalProject} model instead. + * * @author Vladislav.Soroka * @since 11/5/13 */ +@Deprecated() public interface ModuleExtendedModel extends Serializable { /** * The group of the module. diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java index af6f4fed60f4..5b20894b318d 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/model/ProjectImportAction.java @@ -48,8 +48,8 @@ public class ProjectImportAction implements BuildAction<ProjectImportAction.AllM @Nullable @Override public AllModels execute(final BuildController controller) { - Class<? extends IdeaProject> aClass1 = myIsPreviewMode ? BasicIdeaProject.class : IdeaProject.class; - final IdeaProject ideaProject = controller.getModel(aClass1); + //outer conditional is needed to be compatible with 1.8 + final IdeaProject ideaProject = myIsPreviewMode ? controller.getModel(BasicIdeaProject.class) : controller.getModel(IdeaProject.class); if (ideaProject == null || ideaProject.getModules().isEmpty()) { return null; } @@ -59,25 +59,30 @@ public class ProjectImportAction implements BuildAction<ProjectImportAction.AllM // TODO ask gradle guys why there is always null got for BuildEnvironment model //allModels.setBuildEnvironment(controller.findModel(BuildEnvironment.class)); + addExtraProject(controller, allModels, null); for (IdeaModule module : ideaProject.getModules()) { - for (Class aClass : myExtraProjectModelClasses) { - try { - Object extraProject = controller.findModel(module, aClass); - if (extraProject == null) continue; - allModels.addExtraProject(extraProject, aClass, module); - } - catch (Exception e) { - // do not fail project import in a preview mode - if (!myIsPreviewMode) { - throw new ExternalSystemException(e); - } - } - } + addExtraProject(controller, allModels, module); } return allModels; } + private void addExtraProject(@NotNull BuildController controller, @NotNull AllModels allModels, @Nullable IdeaModule model) { + for (Class aClass : myExtraProjectModelClasses) { + try { + Object extraProject = controller.findModel(model, aClass); + if (extraProject == null) continue; + allModels.addExtraProject(extraProject, aClass, model); + } + catch (Exception e) { + // do not fail project import in a preview mode + if (!myIsPreviewMode) { + throw new ExternalSystemException(e); + } + } + } + } + public static class AllModels implements Serializable { @NotNull private final Map<String, Object> projectsByPath = new HashMap<String, Object>(); @NotNull private final IdeaProject myIdeaProject; @@ -101,9 +106,13 @@ public class ProjectImportAction implements BuildAction<ProjectImportAction.AllM myBuildEnvironment = buildEnvironment; } + @Nullable + public <T> T getExtraProject(Class<T> modelClazz) { + return getExtraProject(null, modelClazz); + } @Nullable - public <T> T getExtraProject(@NotNull IdeaModule module, Class<T> modelClazz) { + public <T> T getExtraProject(@Nullable IdeaModule module, Class<T> modelClazz) { Object extraProject = projectsByPath.get(extractMapKey(modelClazz, module)); if (modelClazz.isInstance(extraProject)) { //noinspection unchecked @@ -129,13 +138,17 @@ public class ProjectImportAction implements BuildAction<ProjectImportAction.AllM return modules; } - public void addExtraProject(@NotNull Object project, @NotNull Class modelClazz, @NotNull IdeaModule module) { + public void addExtraProject(@NotNull Object project, @NotNull Class modelClazz) { + projectsByPath.put(extractMapKey(modelClazz, null), project); + } + + public void addExtraProject(@NotNull Object project, @NotNull Class modelClazz, @Nullable IdeaModule module) { projectsByPath.put(extractMapKey(modelClazz, module), project); } @NotNull - private static String extractMapKey(Class modelClazz, @NotNull IdeaModule module) { - return modelClazz.getName() + '@' + module.getGradleProject().getPath(); + private String extractMapKey(Class modelClazz, @Nullable IdeaModule module) { + return modelClazz.getName() + '@' + (module != null ? module.getGradleProject().getPath() : "root" + myIdeaProject.getName().hashCode()); } @NotNull diff --git a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ErrorMessageBuilder.java b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ErrorMessageBuilder.java index 97e449992235..da938dccdf0d 100644 --- a/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ErrorMessageBuilder.java +++ b/plugins/gradle/tooling-extension-api/src/org/jetbrains/plugins/gradle/tooling/ErrorMessageBuilder.java @@ -31,17 +31,21 @@ public class ErrorMessageBuilder { public static final String EOL_TAG = "<eol>"; @NotNull private final Project myProject; - @NotNull private final Exception myException; + @Nullable private final Exception myException; @NotNull private final String myGroup; @Nullable private String myDescription; - private ErrorMessageBuilder(@NotNull Project project, @NotNull Exception exception, @NotNull String group) { + private ErrorMessageBuilder(@NotNull Project project, @Nullable Exception exception, @NotNull String group) { myProject = project; myException = exception; myGroup = group; } - public static ErrorMessageBuilder create(@NotNull Project project, @NotNull Exception exception, @NotNull String group) { + public static ErrorMessageBuilder create(@NotNull Project project, @NotNull String group) { + return new ErrorMessageBuilder(project, null, group); + } + + public static ErrorMessageBuilder create(@NotNull Project project, @Nullable Exception exception, @NotNull String group) { return new ErrorMessageBuilder(project, exception, group); } @@ -59,7 +63,7 @@ public class ErrorMessageBuilder { ( "<i>" + "<b>" + myProject + ((myDescription != null) ? ": " + myDescription : "") + "</b>" + - "\nDetails: " + getErrorMessage(myException) + + (myException != null ? "\nDetails: " + getErrorMessage(myException) : "") + "</i>" ).replaceAll("\r\n|\n\r|\n|\r", EOL_TAG) ); diff --git a/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml b/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml index 1bcde5e35b79..ea579287b3e8 100644 --- a/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml +++ b/plugins/gradle/tooling-extension-impl/gradle-tooling-extension-impl.iml @@ -67,6 +67,7 @@ <SOURCES /> </library> </orderEntry> + <orderEntry type="library" name="gson" level="project" /> </component> </module> diff --git a/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService b/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService index 244e58d2128e..816ef05c1e4d 100644 --- a/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService +++ b/plugins/gradle/tooling-extension-impl/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService @@ -17,3 +17,4 @@ org.jetbrains.plugins.gradle.tooling.builder.WarModelBuilderImpl org.jetbrains.plugins.gradle.tooling.builder.ModuleExtendedModelBuilderImpl org.jetbrains.plugins.gradle.tooling.builder.ModelBuildScriptClasspathBuilderImpl org.jetbrains.plugins.gradle.tooling.builder.ScalaModelBuilderImpl +org.jetbrains.plugins.gradle.tooling.builder.ExternalProjectBuilderImpl diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy new file mode 100644 index 000000000000..3bb6b471b755 --- /dev/null +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/ExternalProjectBuilderImpl.groovy @@ -0,0 +1,231 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.gradle.tooling.builder + +import com.google.gson.GsonBuilder +import com.intellij.openapi.externalSystem.model.* +import com.intellij.openapi.externalSystem.model.project.ExternalSystemSourceType +import org.gradle.api.Action +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.file.ContentFilterable +import org.gradle.api.file.FileCopyDetails +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.SourceSetContainer +import org.gradle.api.tasks.util.PatternFilterable +import org.jetbrains.annotations.NotNull +import org.jetbrains.annotations.Nullable +import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder +import org.jetbrains.plugins.gradle.tooling.ModelBuilderService + +import java.util.concurrent.ConcurrentHashMap + +/** + * @author Vladislav.Soroka + * @since 12/20/13 + */ +class ExternalProjectBuilderImpl implements ModelBuilderService { + + private final cache = new ConcurrentHashMap<String, ExternalProject>() + + @Override + public boolean canBuild(String modelName) { + return ExternalProject.name.equals(modelName) + } + + @Nullable + @Override + public Object buildAll(final String modelName, final Project project) { + ExternalProject externalProject = cache[project.path] + if (externalProject != null) return externalProject + + DefaultExternalProject defaultExternalProject = new DefaultExternalProject() + defaultExternalProject.externalSystemId = "GRADLE" + defaultExternalProject.name = project.name + defaultExternalProject.QName = ":".equals(project.path) ? project.name : project.path + defaultExternalProject.version = wrap(project.version) + defaultExternalProject.description = project.description + defaultExternalProject.buildDir = project.buildDir + defaultExternalProject.buildFile = project.buildFile + defaultExternalProject.group = wrap(project.group) + defaultExternalProject.projectDir = project.projectDir + defaultExternalProject.sourceSets = getSourceSets(project) + defaultExternalProject.tasks = getTasks(project) + + defaultExternalProject.plugins = getPlugins(project) + //defaultExternalProject.setProperties(project.getProperties()) + + + final Map<String, ExternalProject> childProjects = new HashMap<String, ExternalProject>(project.getChildProjects().size()) + for (Map.Entry<String, Project> projectEntry : project.getChildProjects().entrySet()) { + final Object externalProjectChild = buildAll(modelName, projectEntry.getValue()) + if (externalProjectChild instanceof ExternalProject) { + childProjects.put(projectEntry.getKey(), (ExternalProject)externalProjectChild) + } + } + defaultExternalProject.setChildProjects(childProjects) + cache.put(project.getPath(), defaultExternalProject) + + defaultExternalProject + } + + static Map<String, ExternalPlugin> getPlugins(Project project) { + def result = [:] as Map<String, ExternalPlugin> + project.convention.plugins.each { key, value -> + ExternalPlugin externalPlugin = new DefaultExternalPlugin() + externalPlugin.id = key + result.put(key, externalPlugin) + } + + result + } + + static Map<String, ExternalTask> getTasks(Project project) { + def result = [:] as Map<String, ExternalTask> + + project.tasks.all { Task task -> + ExternalTask externalTask = new DefaultExternalTask() + externalTask.name = task.name + externalTask.description = task.description + externalTask.group = task.group + externalTask.QName = task.path + result.put(externalTask.QName, externalTask) + } + + result + } + + static Map<String, ExternalSourceSet> getSourceSets(Project project) { + def result = [:] as Map<String, ExternalSourceSet> + if (!project.hasProperty("sourceSets") || !(project.sourceSets instanceof SourceSetContainer)) { + return result + } + def sourceSets = project.sourceSets as SourceSetContainer + + def (resourcesIncludes, resourcesExcludes, filterReaders) = getFilters(project, 'processResources') + def (testResourcesIncludes, testResourcesExcludes, testFilterReaders) = getFilters(project, 'processTestResources') + //def (javaIncludes,javaExcludes) = getFilters(project,'compileJava') + + sourceSets.all { SourceSet sourceSet -> + ExternalSourceSet externalSourceSet = new DefaultExternalSourceSet() + externalSourceSet.name = sourceSet.name + + def sources = [:] as Map<ExternalSystemSourceType, ExternalSourceDirectorySet> + ExternalSourceDirectorySet resourcesDirectorySet = new DefaultExternalSourceDirectorySet() + resourcesDirectorySet.name = sourceSet.resources.name + resourcesDirectorySet.srcDirs = sourceSet.resources.srcDirs + resourcesDirectorySet.outputDir = sourceSet.output.resourcesDir + + ExternalSourceDirectorySet javaDirectorySet = new DefaultExternalSourceDirectorySet() + javaDirectorySet.name = sourceSet.allJava.name + javaDirectorySet.srcDirs = sourceSet.allJava.srcDirs + javaDirectorySet.outputDir = sourceSet.output.classesDir +// javaDirectorySet.excludes = javaExcludes + sourceSet.java.excludes; +// javaDirectorySet.includes = javaIncludes + sourceSet.java.includes; + + if (SourceSet.TEST_SOURCE_SET_NAME.equals(sourceSet.name)) { + resourcesDirectorySet.excludes = testResourcesExcludes + sourceSet.resources.excludes; + resourcesDirectorySet.includes = testResourcesIncludes + sourceSet.resources.includes; + resourcesDirectorySet.filters = testFilterReaders + sources.put(ExternalSystemSourceType.TEST, javaDirectorySet) + sources.put(ExternalSystemSourceType.TEST_RESOURCE, resourcesDirectorySet) + } + else { + resourcesDirectorySet.excludes = resourcesExcludes + sourceSet.resources.excludes; + resourcesDirectorySet.includes = resourcesIncludes + sourceSet.resources.includes; + resourcesDirectorySet.filters = filterReaders + sources.put(ExternalSystemSourceType.SOURCE, javaDirectorySet) + sources.put(ExternalSystemSourceType.RESOURCE, resourcesDirectorySet) + } + + externalSourceSet.sources = sources + result[sourceSet.name] = externalSourceSet + } + result + } + + static getFilters(Project project, String taskName) { + def includes = [] + def excludes = [] + def filterReaders = [] as List<ExternalFilter> + def filterableTask = project.tasks.findByName(taskName) + if (filterableTask instanceof PatternFilterable) { + includes += filterableTask.includes + excludes += filterableTask.excludes + } + + if(System.getProperty('idea.disable.gradle.resource.filtering', 'false').toBoolean()) { + return [includes, excludes, filterReaders] + } + + try { + if (filterableTask instanceof ContentFilterable && filterableTask.metaClass.respondsTo(filterableTask, "getMainSpec")) { + def properties = filterableTask.getMainSpec().properties + def copyActions = properties?.allCopyActions ?: properties?.copyActions + + if(copyActions) { + copyActions.each { Action<? super FileCopyDetails> action -> + if (action.hasProperty('val$filterType') && action.hasProperty('val$properties')) { + def filterType = (action?.val$filterType as Class).name + def filter = [filterType: filterType] as DefaultExternalFilter + def props = action?.val$properties + if (props) { + filter.propertiesAsJsonMap = new GsonBuilder().create().toJson(props); + } + filterReaders << filter + } + else if (action.class.simpleName.equals('RenamingCopyAction') && action.hasProperty('transformer')) { + if (action.transformer.hasProperty('matcher') && action?.transformer.hasProperty('replacement')) { + String pattern = action?.transformer?.matcher.pattern().pattern + String replacement = action?.transformer?.replacement + def filter = [filterType: 'RenamingCopyFilter'] as DefaultExternalFilter + if(pattern && replacement){ + filter.propertiesAsJsonMap = new GsonBuilder().create().toJson([pattern: pattern, replacement: replacement]); + filterReaders << filter + } + } + } +// else { +// project.logger.error( +// ErrorMessageBuilder.create(project, "Resource configuration errors") +// .withDescription("Unsupported copy action found: " + action.class.name).build()) +// } + } + } + } + } + catch (Exception ignore) { +// project.logger.error( +// ErrorMessageBuilder.create(project, e, "Resource configuration errors") +// .withDescription("Unable to resolve resources filtering configuration").build()) + } + + return [includes, excludes, filterReaders] + } + + + private static String wrap(Object o) { + return o instanceof CharSequence ? o.toString() : "" + } + + @NotNull + @Override + public ErrorMessageBuilder getErrorMessageBuilder(@NotNull Project project, @NotNull Exception e) { + return ErrorMessageBuilder.create( + project, e, "Project resolve errors" + ).withDescription("Unable to resolve additional project configuration.") + } +} diff --git a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/WarModelBuilderImpl.groovy b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/WarModelBuilderImpl.groovy index 00f4c8bb0b6e..2eb7137949e2 100644 --- a/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/WarModelBuilderImpl.groovy +++ b/plugins/gradle/tooling-extension-impl/src/org/jetbrains/plugins/gradle/tooling/builder/WarModelBuilderImpl.groovy @@ -88,20 +88,25 @@ class WarModelBuilderImpl implements ModelBuilderService { if (resolver.metaClass.respondsTo(resolver, 'getSourcePaths')) { sourcePaths = resolver.getSourcePaths() - } else if (resolver.this$0.metaClass.respondsTo(resolver, 'getSourcePaths')) { + } else if (resolver.hasProperty('sourcePaths')) { + sourcePaths = resolver.sourcePaths + } else if (resolver.hasProperty('this$0') && resolver.this$0.metaClass.respondsTo(resolver, 'getSourcePaths')) { sourcePaths = resolver.this$0.getSourcePaths() - } else { + } else if (resolver.hasProperty('this$0') && resolver.this$0.hasProperty('sourcePaths')) { + sourcePaths = resolver.this$0.sourcePaths + } /*else { throw new RuntimeException("${GradleVersion.current()} is not supported by web artifact importer") - } + }*/ - (sourcePaths.flatten() as List).each { def path -> - if (path instanceof String) { - def file = new File(warTask.project.projectDir, path) - addPath(webResources, relativePath, "", file) + if(sourcePaths) { + (sourcePaths.flatten() as List).each { def path -> + if (path instanceof String) { + def file = new File(warTask.project.projectDir, path) + addPath(webResources, relativePath, "", file) + } } } - resolver.source.visit(new FileVisitor() { @Override public void visitDir(FileVisitDetails dirDetails) { diff --git a/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java b/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java index d09a9b7c5e3c..faf3a98bc3a4 100644 --- a/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java +++ b/plugins/gradle/tooling-extension-impl/testSources/org/jetbrains/plugins/gradle/tooling/builder/AbstractModelBuilderTest.java @@ -15,6 +15,7 @@ */ package org.jetbrains.plugins.gradle.tooling.builder; +import com.intellij.openapi.externalSystem.model.ExternalProject; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; import com.intellij.testFramework.UsefulTestCase; @@ -127,7 +128,7 @@ public abstract class AbstractModelBuilderTest { BuildActionExecuter<ProjectImportAction.AllModels> buildActionExecutor = connection.action(projectImportAction); File initScript = GradleExecutionHelper.generateInitScript(false, getToolingExtensionClasses()); assertNotNull(initScript); - buildActionExecutor.withArguments(GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath()); + buildActionExecutor.withArguments("--recompile-scripts", GradleConstants.INIT_SCRIPT_CMD_OPTION, initScript.getAbsolutePath()); allModels = buildActionExecutor.run(); assertNotNull(allModels); } @@ -135,6 +136,7 @@ public abstract class AbstractModelBuilderTest { @NotNull private Set<Class> getToolingExtensionClasses() { final Set<Class> classes = ContainerUtil.<Class>set( + ExternalProject.class, // gradle-tooling-extension-api jar ProjectImportAction.class, // gradle-tooling-extension-impl jar diff --git a/plugins/groovy/groovy-psi/src/resources/groovyInjections.xml b/plugins/groovy/groovy-psi/src/resources/groovyInjections.xml index dcb426aa135f..910d211476f6 100644 --- a/plugins/groovy/groovy-psi/src/resources/groovyInjections.xml +++ b/plugins/groovy/groovy-psi/src/resources/groovyInjections.xml @@ -50,4 +50,13 @@ <display-name>RegExp</display-name> <place><![CDATA[groovyLiteralExpression().regExpOperatorArgument()]]></place> </injection> + <injection language="encoding-reference" injector-id="java"> + <display-name>Charset Name</display-name> + <place><![CDATA[psiParameter().ofMethod(0, psiMethod().withName("getBytes").withParameters("java.lang.String").definedInClass("groovy.lang.GString"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newPrintWriter").withParameters("java.io.File", "java.lang.String").definedInClass("org.codehaus.groovy.runtime.DefaultGroovyMethods"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newReader").withParameters("java.io.File", "java.lang.String").definedInClass("org.codehaus.groovy.runtime.DefaultGroovyMethods"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newReader").withParameters("java.io.InputStream", "java.lang.String").definedInClass("org.codehaus.groovy.runtime.DefaultGroovyMethods"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newWriter").withParameters("java.io.File", "java.lang.String").definedInClass("org.codehaus.groovy.runtime.DefaultGroovyMethods"))]]></place> + <place><![CDATA[psiParameter().ofMethod(1, psiMethod().withName("newWriter").withParameters("java.io.File", "java.lang.String", "boolean").definedInClass("org.codehaus.groovy.runtime.DefaultGroovyMethods"))]]></place> + </injection> </component> diff --git a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java index 855deba56575..03e3b544b5ed 100644 --- a/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java +++ b/plugins/groovy/jps-plugin/src/org/jetbrains/jps/incremental/groovy/GroovyBuilder.java @@ -18,6 +18,7 @@ package org.jetbrains.jps.incremental.groovy; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; @@ -58,6 +59,8 @@ import org.jetbrains.jps.model.library.sdk.JpsSdk; import org.jetbrains.jps.service.JpsServiceManager; import org.jetbrains.jps.service.SharedThreadPool; import org.jetbrains.org.objectweb.asm.ClassReader; +import org.jetbrains.org.objectweb.asm.ClassVisitor; +import org.jetbrains.org.objectweb.asm.Opcodes; import java.io.File; import java.io.IOException; @@ -434,9 +437,14 @@ public class GroovyBuilder extends ModuleLevelBuilder { final String sourcePath = FileUtil.toSystemIndependentName(item.sourcePath); final String outputPath = FileUtil.toSystemIndependentName(item.outputPath); final File outputFile = new File(outputPath); - outputConsumer.registerOutputFile(target, outputFile, Collections.singleton(sourcePath)); + final File srcFile = new File(sourcePath); try { - callback.associate(outputPath, sourcePath, new ClassReader(FileUtil.loadFileBytes(outputFile))); + final byte[] bytes = FileUtil.loadFileBytes(outputFile); + outputConsumer.registerCompiledClass( + target, + new CompiledClass(outputFile, srcFile, readClassName(bytes), new BinaryContent(bytes)) + ); + callback.associate(outputPath, sourcePath, new ClassReader(bytes)); } catch (Throwable e) { // need this to make sure that unexpected errors in, for example, ASM will not ruin the compilation @@ -446,7 +454,7 @@ public class GroovyBuilder extends ModuleLevelBuilder { myBuilderName, BuildMessage.Kind.WARNING, message + "\n" + CompilerMessage.getTextFromThrowable(e), sourcePath) ); } - successfullyCompiledFiles.add(new File(sourcePath)); + successfullyCompiledFiles.add(srcFile); } } } @@ -454,6 +462,16 @@ public class GroovyBuilder extends ModuleLevelBuilder { return JavaBuilderUtil.updateMappings(context, delta, dirtyFilesHolder, chunk, toCompile, successfullyCompiledFiles); } + private static String readClassName(byte[] classBytes) throws IOException{ + final Ref<String> nameRef = Ref.create(null); + new ClassReader(classBytes).accept(new ClassVisitor(Opcodes.ASM5) { + public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { + nameRef.set(name.replace('/', '.')); + } + }, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + return nameRef.get(); + } + private static Collection<String> generateClasspath(CompileContext context, ModuleChunk chunk) { final Set<String> cp = new LinkedHashSet<String>(); //groovy_rt.jar diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettings.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettings.java index 273fd4cb8531..c2538426a871 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettings.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettings.java @@ -19,23 +19,31 @@ import com.intellij.openapi.components.State; import com.intellij.openapi.components.Storage; import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.SimpleConfigurable; +import com.intellij.openapi.util.Getter; import com.intellij.openapi.util.registry.Registry; import com.intellij.util.xmlb.XmlSerializerUtil; +import com.intellij.xdebugger.settings.DebuggerSettingsCategory; import com.intellij.xdebugger.settings.XDebuggerSettings; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.GroovyBundle; + +import java.util.Collection; +import java.util.Collections; + +import static java.util.Collections.singletonList; /** * @author ilyas */ @State( - name = "GroovyDebuggerSettings", - storages = { + name = "GroovyDebuggerSettings", + storages = { @Storage( - file = StoragePathMacros.APP_CONFIG + "/groovy_debug.xml" + file = StoragePathMacros.APP_CONFIG + "/groovy_debug.xml" )} ) -public class GroovyDebuggerSettings extends XDebuggerSettings<GroovyDebuggerSettings> { +public class GroovyDebuggerSettings extends XDebuggerSettings<GroovyDebuggerSettings> implements Getter<GroovyDebuggerSettings> { public Boolean DEBUG_DISABLE_SPECIFIC_GROOVY_METHODS = true; public boolean ENABLE_GROOVY_HOTSWAP = Registry.is("enable.groovy.hotswap"); @@ -43,19 +51,19 @@ public class GroovyDebuggerSettings extends XDebuggerSettings<GroovyDebuggerSett super("groovy_debugger"); } - @Override @NotNull - public Configurable createConfigurable() { - return new GroovyDebuggerSettingsConfigurable(this); - } - - @Nullable + @SuppressWarnings("EnumSwitchStatementWhichMissesCases") @Override - public Configurable createConfigurable(@NotNull Category category) { - if (category == Category.STEPPING) { - return new GroovySteppingConfigurable(); + public Collection<? extends Configurable> createConfigurables(@NotNull DebuggerSettingsCategory category) { + switch (category) { + case STEPPING: + return singletonList(SimpleConfigurable.create("reference.idesettings.debugger.groovy", GroovyBundle.message("groovy.debug.caption"), + "reference.idesettings.debugger.groovy", GroovySteppingConfigurableUi.class, this)); + case HOTSWAP: + return singletonList(SimpleConfigurable.create("reference.idesettings.debugger.groovy", GroovyBundle.message("groovy.debug.caption"), + "reference.idesettings.debugger.groovy", GroovyHotSwapConfigurableUi.class, this)); } - return null; + return Collections.emptyList(); } @Override @@ -71,4 +79,9 @@ public class GroovyDebuggerSettings extends XDebuggerSettings<GroovyDebuggerSett public static GroovyDebuggerSettings getInstance() { return getInstance(GroovyDebuggerSettings.class); } + + @Override + public GroovyDebuggerSettings get() { + return this; + } }
\ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettingsConfigurable.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettingsConfigurable.java deleted file mode 100644 index 8f143d9a5fd1..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettingsConfigurable.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2000-2014 JetBrains s.r.o. - * - * 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.jetbrains.plugins.groovy.debugger; - -import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.SearchableConfigurable; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.plugins.groovy.GroovyBundle; - -import javax.swing.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - -/** - * @author ilyas - */ -public class GroovyDebuggerSettingsConfigurable implements SearchableConfigurable { - private JPanel myPanel; - private JCheckBox myEnableHotSwap; - private boolean isModified = false; - private final GroovyDebuggerSettings mySettings; - - public GroovyDebuggerSettingsConfigurable(final GroovyDebuggerSettings settings) { - mySettings = settings; - - myEnableHotSwap.addActionListener(new ActionListener() { - @Override - public void actionPerformed(final ActionEvent e) { - isModified = mySettings.ENABLE_GROOVY_HOTSWAP != myEnableHotSwap.isSelected(); - } - }); - } - - @Override - @Nls - public String getDisplayName() { - return GroovyBundle.message("groovy.debug.caption"); - } - - @Override - @NotNull - public String getHelpTopic() { - return "reference.idesettings.debugger.groovy"; - } - - @Override - @NotNull - public String getId() { - return getHelpTopic(); - } - - @Override - public Runnable enableSearch(String option) { - return null; - } - - @Override - public JComponent createComponent() { - return myPanel; - } - - @Override - public boolean isModified() { - return isModified; - } - - @Override - public void apply() throws ConfigurationException { - if (isModified) { - mySettings.ENABLE_GROOVY_HOTSWAP = myEnableHotSwap.isSelected(); - } - isModified = false; - } - - @Override - public void reset() { - myEnableHotSwap.setSelected(mySettings.ENABLE_GROOVY_HOTSWAP); - } - - @Override - public void disposeUIResources() { - } -} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettingsConfigurable.form b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapConfigurableUi.form index 171170b00571..cbe2154a9d31 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyDebuggerSettingsConfigurable.form +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapConfigurableUi.form @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.groovy.debugger.GroovyDebuggerSettingsConfigurable"> +<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.plugins.groovy.debugger.GroovyHotSwapConfigurableUi"> <grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1"> <margin top="0" left="0" bottom="0" right="0"/> <constraints> @@ -19,6 +19,7 @@ </constraints> <properties> <componentStyle value="SMALL"/> + <fontColor value="BRIGHTER"/> <text value="May cause serialization issues in the debugged application"/> </properties> </component> diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapConfigurableUi.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapConfigurableUi.java new file mode 100644 index 000000000000..400d344bb156 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovyHotSwapConfigurableUi.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.plugins.groovy.debugger; + +import com.intellij.openapi.options.ConfigurableUi; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; + +/** + * @author ilyas + */ +class GroovyHotSwapConfigurableUi implements ConfigurableUi<GroovyDebuggerSettings> { + private JPanel myPanel; + private JCheckBox myEnableHotSwap; + + @NotNull + @Override + public JComponent getComponent() { + return myPanel; + } + + @Override + public boolean isModified(@NotNull GroovyDebuggerSettings settings) { + return settings.ENABLE_GROOVY_HOTSWAP != myEnableHotSwap.isSelected(); + } + + @Override + public void apply(@NotNull GroovyDebuggerSettings settings) { + settings.ENABLE_GROOVY_HOTSWAP = myEnableHotSwap.isSelected(); + } + + @Override + public void reset(@NotNull GroovyDebuggerSettings settings) { + myEnableHotSwap.setSelected(settings.ENABLE_GROOVY_HOTSWAP); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovySteppingConfigurable.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovySteppingConfigurable.java deleted file mode 100644 index 0e5d99552d47..000000000000 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/debugger/GroovySteppingConfigurable.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.jetbrains.plugins.groovy.debugger; - -import com.intellij.openapi.options.ConfigurableBase; -import org.jetbrains.annotations.Nls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.plugins.groovy.GroovyBundle; - -class GroovySteppingConfigurable extends ConfigurableBase<GroovySteppingConfigurableUi, GroovyDebuggerSettings> { - @Override - protected GroovyDebuggerSettings getSettings() { - return GroovyDebuggerSettings.getInstance(); - } - - @Override - protected GroovySteppingConfigurableUi createUi() { - return new GroovySteppingConfigurableUi(); - } - - @NotNull - @Override - public String getId() { - return "debugger.stepping.groovy"; - } - - @Nls - @Override - public String getDisplayName() { - return GroovyBundle.message("groovy.debug.caption"); - } - - @Nullable - @Override - public String getHelpTopic() { - return "reference.idesettings.debugger.groovy"; - } -}
\ No newline at end of file diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyReferenceCopyPasteProcessor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyReferenceCopyPasteProcessor.java index 63784b58f298..d4b67e1540bf 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyReferenceCopyPasteProcessor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/editor/GroovyReferenceCopyPasteProcessor.java @@ -97,7 +97,7 @@ public class GroovyReferenceCopyPasteProcessor extends CopyPasteReferenceProcess } else { if (reference instanceof GrReferenceExpression) { - PsiElement referent = reference.resolve(); + PsiElement referent = resolveReferenceIgnoreOverriding(reference); if (!(referent instanceof PsiNamedElement) || !data.staticMemberName.equals(((PsiNamedElement)referent).getName()) || !(referent instanceof PsiMember) diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/GroovySdkWizardStepBase.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/GroovySdkWizardStepBase.java index 84b96c39fd78..19649574c2bc 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/GroovySdkWizardStepBase.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/GroovySdkWizardStepBase.java @@ -23,7 +23,6 @@ import com.intellij.ide.util.projectWizard.ModuleWizardStep; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.ide.wizard.CommitStepException; import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModifiableRootModel; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer; @@ -51,8 +50,9 @@ public abstract class GroovySdkWizardStepBase extends ModuleWizardStep { public GroovySdkWizardStepBase(@Nullable final MvcFramework framework, WizardContext wizardContext, String basePath) { myBasePath = basePath; - final Project project = wizardContext.getProject(); - myLibrariesContainer = LibrariesContainerFactory.createContainer(project); + myLibrariesContainer = wizardContext.getModulesProvider() == null + ? LibrariesContainerFactory.createContainer(wizardContext.getProject()) + : LibrariesContainerFactory.createContainer(wizardContext, wizardContext.getModulesProvider()); myFramework = framework; } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy index 2b5933fb4d31..d6363fb560db 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTest.groovy @@ -18,16 +18,28 @@ package org.jetbrains.plugins.groovy.compiler import com.intellij.compiler.CompilerConfiguration import com.intellij.compiler.CompilerConfigurationImpl +import com.intellij.execution.executors.DefaultRunExecutor +import com.intellij.execution.impl.DefaultJavaProgramRunner +import com.intellij.execution.process.ProcessAdapter +import com.intellij.execution.process.ProcessEvent +import com.intellij.execution.process.ProcessHandler +import com.intellij.execution.process.ProcessOutputTypes +import com.intellij.execution.runners.ProgramRunner import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.PathManager import com.intellij.openapi.compiler.CompilerMessage import com.intellij.openapi.compiler.CompilerMessageCategory import com.intellij.openapi.compiler.options.ExcludeEntryDescription import com.intellij.openapi.compiler.options.ExcludedEntriesConfiguration import com.intellij.openapi.module.Module import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.util.Key +import com.intellij.openapi.util.Ref import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFile +import com.intellij.testFramework.PsiTestUtil import com.intellij.testFramework.TestLoggerFactory +import org.jetbrains.annotations.NotNull import org.jetbrains.plugins.groovy.lang.psi.GroovyFile /** @@ -822,4 +834,35 @@ class AppTest { def messages = make() assert messages.find { it.message.contains("Cannot compile Groovy files: no Groovy library is defined for module 'dependent'") } } + + public void testGroovyOutputIsInstrumented() { + myFixture.addFileToProject("Bar.groovy", + "import org.jetbrains.annotations.NotNull; " + + "public class Bar {" + + "void xxx(@NotNull String param) { println param }\n" + + "static void main(String[] args) { new Bar().xxx(null) }"+ + "}" + ); + + File annotations = new File(PathManager.getJarPathForClass(NotNull.class)); + PsiTestUtil.addLibrary(myModule, "annotations", annotations.getParent(), annotations.getName()); + + assertEmpty(make()); + + final Ref<Boolean> exceptionFound = Ref.create(Boolean.FALSE); + ProcessHandler process = runProcess("Bar", myModule, DefaultRunExecutor.class, new ProcessAdapter() { + @Override + public void onTextAvailable(ProcessEvent event, Key outputType) { + if (ProcessOutputTypes.SYSTEM != outputType) { + if (!exceptionFound.get()) { + exceptionFound.set(event.getText().contains("java.lang.IllegalArgumentException: Argument for @NotNull parameter 'param' of Bar.xxx must not be null")); + } + } + } + }, ProgramRunner.PROGRAM_RUNNER_EP.findExtension(DefaultJavaProgramRunner.class)); + process.waitFor(); + + assertTrue(exceptionFound.get()); + } + } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java index 7cbf9a9d665b..28b2e26949ad 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/compiler/GroovyCompilerTestCase.java @@ -44,6 +44,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.testFramework.CompilerTester; import com.intellij.testFramework.IdeaTestUtil; +import com.intellij.testFramework.PlatformTestUtil; import com.intellij.testFramework.PsiTestUtil; import com.intellij.testFramework.builders.JavaModuleFixtureBuilder; import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase; @@ -80,6 +81,13 @@ public abstract class GroovyCompilerTestCase extends JavaCodeInsightFixtureTestC super.tuneFixture(moduleBuilder); } + @Override + protected void runTest() throws Throwable { + if (PlatformTestUtil.COVERAGE_ENABLED_BUILD) return; + + super.runTest(); + } + protected static void addGroovyLibrary(final Module to) { File jar = GroovyFacetUtil.getBundledGroovyJar(); PsiTestUtil.addLibrary(to, "groovy", jar.getParent(), jar.getName()); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy index 223927107763..ce323a17d5d9 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/refactoring/optimizeImports/OptimizeImportsTest.groovy @@ -15,11 +15,9 @@ */ package org.jetbrains.plugins.groovy.refactoring.optimizeImports - import com.intellij.codeInsight.CodeInsightSettings import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.command.CommandProcessor -import com.intellij.openapi.fileEditor.impl.TrailingSpacesStripper import com.intellij.psi.codeStyle.CodeStyleSettings import com.intellij.psi.codeStyle.CodeStyleSettingsManager import com.intellij.psi.impl.source.PostprocessReformattingAspect @@ -195,7 +193,6 @@ class Fooxx <caret>{ doOptimizeImports(); PostprocessReformattingAspect.getInstance(getProject()).doPostponedFormatting(); - TrailingSpacesStripper.stripIfNotCurrentLine(myFixture.getEditor().getDocument(), false); myFixture.checkResultByFile(getTestName(false) + "_after.groovy"); } finally { diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java index 7410b0e7703e..43ef70ed2446 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/action/HgLogSingleCommitAction.java @@ -16,76 +16,21 @@ package org.zmlx.hg4idea.action; -import com.intellij.dvcs.DvcsUtil; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; +import com.intellij.dvcs.ui.VcsLogSingleCommitAction; import com.intellij.openapi.components.ServiceManager; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; -import com.intellij.vcs.log.VcsFullCommitDetails; -import com.intellij.vcs.log.VcsLog; -import com.intellij.vcs.log.VcsLogDataKeys; +import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; -import org.zmlx.hg4idea.HgVcs; +import org.jetbrains.annotations.Nullable; import org.zmlx.hg4idea.repo.HgRepository; import org.zmlx.hg4idea.repo.HgRepositoryManager; -import java.util.List; - -/** - * @author Nadya Zabrodina - */ -public abstract class HgLogSingleCommitAction extends DumbAwareAction { - - private static final Logger LOG = Logger.getInstance(HgLogSingleCommitAction.class); - - protected abstract void actionPerformed(@NotNull HgRepository repository, @NotNull VcsFullCommitDetails commit); +public abstract class HgLogSingleCommitAction extends VcsLogSingleCommitAction<HgRepository> { + @Nullable @Override - public void actionPerformed(AnActionEvent e) { - Data data = Data.collect(e); - if (!data.isValid()) { - return; - } - - List<VcsFullCommitDetails> details = data.log.getSelectedDetails(); - if (details.size() != 1) { - return; - } - VcsFullCommitDetails commit = details.get(0); - - HgRepositoryManager repositoryManager = ServiceManager.getService(data.project, HgRepositoryManager.class); - final HgRepository repository = repositoryManager.getRepositoryForRoot(commit.getRoot()); - if (repository == null) { - DvcsUtil.noVcsRepositoryForRoot(LOG, commit.getRoot(), data.project, repositoryManager, HgVcs.getInstance(data.project)); - return; - } - - actionPerformed(repository, commit); + protected HgRepository getRepositoryForRoot(@NotNull Project project, @NotNull VirtualFile root) { + return ServiceManager.getService(project, HgRepositoryManager.class).getRepositoryForRoot(root); } - @Override - public void update(AnActionEvent e) { - Data data = Data.collect(e); - boolean enabled = data.isValid() && data.log.getSelectedCommits().size() == 1; - e.getPresentation().setVisible(data.isValid()); - e.getPresentation().setEnabled(enabled); - } - - private static class Data { - Project project; - VcsLog log; - - static Data collect(AnActionEvent e) { - Data data = new Data(); - data.project = e.getData(CommonDataKeys.PROJECT); - data.log = e.getData(VcsLogDataKeys.VSC_LOG); - return data; - } - - boolean isValid() { - return project != null && log != null && DvcsUtil.logHasRootForVcs(log, HgVcs.getKey()); - } - } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java index 1d41cdc688f9..14f6c981777b 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandAuthenticator.java @@ -35,7 +35,7 @@ import org.zmlx.hg4idea.HgVcsMessages; class HgCommandAuthenticator { private static final Logger LOG = Logger.getInstance(HgCommandAuthenticator.class.getName()); - + private GetPasswordRunnable myGetPassword; private final Project myProject; private boolean myForceAuthorization; @@ -71,7 +71,7 @@ class HgCommandAuthenticator { } public boolean promptForAuthentication(Project project, String proposedLogin, String uri, String path, @Nullable ModalityState state) { - GetPasswordRunnable runnable = new GetPasswordRunnable(project, proposedLogin, uri, path, myForceAuthorization, state); + GetPasswordRunnable runnable = new GetPasswordRunnable(project, proposedLogin, uri, path, myForceAuthorization); ApplicationManager.getApplication().invokeAndWait(runnable, state == null ? ModalityState.defaultModalityState() : state); myGetPassword = runnable; return runnable.isOk(); @@ -96,21 +96,14 @@ class HgCommandAuthenticator { @Nullable private String myURL; private boolean myRememberPassword; private boolean myForceAuthorization; - @Nullable private ModalityState myState; - - public GetPasswordRunnable(Project project, - String proposedLogin, - String uri, - String path, - boolean forceAuthorization, - @Nullable ModalityState state) { + + public GetPasswordRunnable(Project project, String proposedLogin, String uri, String path, boolean forceAuthorization) { this.myProject = project; this.myProposedLogin = proposedLogin; this.myURL = uri + path; this.myForceAuthorization = forceAuthorization; - myState = state; } - + public void run() { // find if we've already been here @@ -135,9 +128,11 @@ class HgCommandAuthenticator { final String key = keyForUrlAndLogin(myURL, login); try { final PasswordSafeImpl passwordSafe = (PasswordSafeImpl)PasswordSafe.getInstance(); - password = passwordSafe.getPassword(myProject, HgCommandAuthenticator.class, key, myState); - } - catch (PasswordSafeException e) { + password = passwordSafe.getMemoryProvider().getPassword(myProject, HgCommandAuthenticator.class, key); + if (password == null) { + password = passwordSafe.getPassword(myProject, HgCommandAuthenticator.class, key); + } + } catch (PasswordSafeException e) { LOG.info("Couldn't get password for key [" + key + "]", e); } } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java index 03c98621a8c2..4adec9dff515 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/log/HgLogProvider.java @@ -64,10 +64,13 @@ public class HgLogProvider implements VcsLogProvider { return HgHistoryUtil.loadMetadata(myProject, root, requirements.getCommitCount(), Collections.<String>emptyList()); } - @NotNull @Override - public List<TimedVcsCommit> readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry) throws VcsException { - return HgHistoryUtil.readAllHashes(myProject, root, userRegistry, Collections.<String>emptyList()); + public void readAllHashes(@NotNull VirtualFile root, @NotNull Consumer<VcsUser> userRegistry, + @NotNull Consumer<TimedVcsCommit> commitConsumer) throws VcsException { + List<TimedVcsCommit> commits = HgHistoryUtil.readAllHashes(myProject, root, userRegistry, Collections.<String>emptyList()); + for (TimedVcsCommit commit : commits) { + commitConsumer.consume(commit); + } } @NotNull diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgDiffFromHistoryHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgDiffFromHistoryHandler.java index 61d08bc94e8c..1d556a8b19cb 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgDiffFromHistoryHandler.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgDiffFromHistoryHandler.java @@ -15,22 +15,13 @@ */ package org.zmlx.hg4idea.provider; -import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogBuilder; -import com.intellij.openapi.util.Couple; import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vcs.changes.ui.ChangesBrowser; -import com.intellij.openapi.vcs.history.CurrentRevision; -import com.intellij.openapi.vcs.history.DiffFromHistoryHandler; -import com.intellij.openapi.vcs.history.VcsFileRevision; -import com.intellij.openapi.vcs.history.VcsHistoryUtil; +import com.intellij.openapi.vcs.history.BaseDiffFromHistoryHandler; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.util.Consumer; import com.intellij.vcsUtil.VcsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,111 +35,37 @@ import java.util.List; * * @author Nadya Zabrodina */ -public class HgDiffFromHistoryHandler implements DiffFromHistoryHandler { +public class HgDiffFromHistoryHandler extends BaseDiffFromHistoryHandler<HgFileRevision> { private static final Logger LOG = Logger.getInstance(HgDiffFromHistoryHandler.class); - @NotNull private final Project myProject; - public HgDiffFromHistoryHandler(@NotNull Project project) { - myProject = project; + super(project); } + @NotNull @Override - public void showDiffForOne(@NotNull AnActionEvent e, @NotNull FilePath filePath, - @NotNull VcsFileRevision previousRevision, @NotNull VcsFileRevision revision) { - doShowDiff(filePath, previousRevision, revision, false); + protected List<Change> getChangesBetweenRevisions(@NotNull FilePath path, @NotNull HgFileRevision rev1, @Nullable HgFileRevision rev2) { + return executeDiff(path, rev1, rev2); } - + @NotNull @Override - public void showDiffForTwo(@NotNull FilePath filePath, @NotNull VcsFileRevision revision1, @NotNull VcsFileRevision revision2) { - doShowDiff(filePath, revision1, revision2, true); + protected List<Change> getAffectedChanges(@NotNull FilePath path, @NotNull HgFileRevision rev) throws VcsException { + return executeDiff(path, null, rev); } - private void doShowDiff(@NotNull FilePath filePath, @NotNull VcsFileRevision revision1, @NotNull VcsFileRevision revision2, - boolean autoSort) { - if (!filePath.isDirectory()) { - VcsHistoryUtil.showDifferencesInBackground(myProject, filePath, revision1, revision2, autoSort); - } - else if (revision2 instanceof CurrentRevision) { - HgFileRevision left = (HgFileRevision)revision1; - showDiffForDirectory(filePath, left, null); - } - else if (revision1.equals(VcsFileRevision.NULL)) { - HgFileRevision right = (HgFileRevision)revision2; - showDiffForDirectory(filePath, null, right); - } - else { - HgFileRevision left = (HgFileRevision)revision1; - HgFileRevision right = (HgFileRevision)revision2; - if (autoSort) { - Couple<VcsFileRevision> pair = VcsHistoryUtil.sortRevisions(revision1, revision2); - left = (HgFileRevision)pair.first; - right = (HgFileRevision)pair.second; - } - showDiffForDirectory(filePath, left, right); - } + @NotNull + @Override + protected String getPresentableName(@NotNull HgFileRevision revision) { + return revision.getRevisionNumber().getChangeset(); } - private void showDiffForDirectory(@NotNull final FilePath path, - @Nullable final HgFileRevision rev1, - @Nullable final HgFileRevision rev2) { + @NotNull + private List<Change> executeDiff(@NotNull FilePath path, @Nullable HgFileRevision rev1, @Nullable HgFileRevision rev2) { VirtualFile root = VcsUtil.getVcsRootFor(myProject, path); LOG.assertTrue(root != null, "Repository is null for " + path); - calculateDiffInBackground(root, path, rev1, rev2, new Consumer<List<Change>>() { - @Override - public void consume(List<Change> changes) { - showDirDiffDialog(path, rev1 != null ? rev1.getRevisionNumber().getChangeset() : null, - rev2 != null ? rev2.getRevisionNumber().getChangeset() : null, changes); - } - }); - } - - // rev1 == null => rev2 is the initial commit - // rev2 == null => comparing rev1 with local - private void calculateDiffInBackground(@NotNull final VirtualFile root, @NotNull final FilePath path, - @Nullable final HgFileRevision rev1, @Nullable final HgFileRevision rev2, - final Consumer<List<Change>> successHandler) { - new Task.Backgroundable(myProject, "Comparing revisions...") { - private List<Change> myChanges; - @Override - public void run(@NotNull ProgressIndicator indicator) { - if (myProject != null) { - myChanges = HgUtil.getDiff(HgDiffFromHistoryHandler.this.myProject, root, path, rev1, rev2); - } - } - - @Override - public void onSuccess() { - successHandler.consume(myChanges); - } - }.queue(); - } - - private void showDirDiffDialog(@NotNull FilePath path, @Nullable String hash1, @Nullable String hash2, @NotNull List<Change> diff) { - DialogBuilder dialogBuilder = new DialogBuilder(myProject); - String title; - if (hash2 != null) { - if (hash1 != null) { - title = String.format("Difference between %s and %s in %s", hash1, hash2, path.getName()); - } - else { - title = String.format("Initial commit %s in %s", hash2, path.getName()); - } - } - else { - LOG.assertTrue(hash1 != null, "hash1 and hash2 can't both be null. Path: " + path); - title = String.format("Difference between %s and local version in %s", hash1, path.getName()); - } - dialogBuilder.setTitle(title); - dialogBuilder.setActionDescriptors(new DialogBuilder.ActionDescriptor[]{new DialogBuilder.CloseDialogAction()}); - final ChangesBrowser changesBrowser = new ChangesBrowser(myProject, null, diff, null, false, true, - null, ChangesBrowser.MyUseCase.COMMITTED_CHANGES, null); - changesBrowser.setChangesToDisplay(diff); - dialogBuilder.setCenterPanel(changesBrowser); - dialogBuilder.showNotModal(); + return HgUtil.getDiff(myProject, root, path, rev1, rev2); } -} - +}
\ No newline at end of file diff --git a/plugins/hg4idea/testSrc/hg4idea/test/HgExecutor.java b/plugins/hg4idea/testSrc/hg4idea/test/HgExecutor.java index 2a654c4e534d..359c850362c9 100644 --- a/plugins/hg4idea/testSrc/hg4idea/test/HgExecutor.java +++ b/plugins/hg4idea/testSrc/hg4idea/test/HgExecutor.java @@ -65,7 +65,7 @@ public class HgExecutor extends Executor { List<String> split = splitCommandInParameters(command); split.add(0, HG_EXECUTABLE); debug("hg " + command); - return run(split, ignoreNonZeroExitCode); + return run(ourCurrentDir(), split, ignoreNonZeroExitCode); } public static void updateProject() { diff --git a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java index 592bfbc6051f..155d83767f8b 100644 --- a/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java +++ b/plugins/java-i18n/src/com/intellij/codeInspection/i18n/folding/I18nMessageGotoDeclarationHandler.java @@ -39,7 +39,7 @@ public class I18nMessageGotoDeclarationHandler extends GotoDeclarationHandlerBas int i = 4; //some street magic while (element != null && i > 0) { final ASTNode node = element.getNode(); - if (node != null && node.getUserData(KEY) != null) { + if (node != null && node.getUserData(KEY) instanceof PropertyFoldingBuilder) { break; } else { diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFXNSDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFXNSDescriptor.java index 28c99b0ff067..9aa2e7250464 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFXNSDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/JavaFXNSDescriptor.java @@ -54,7 +54,7 @@ public class JavaFXNSDescriptor implements XmlNSDescriptor, Validator<XmlDocumen final PsiClass paneClass = JavaPsiFacade.getInstance(project).findClass(JavaFxCommonClassNames.JAVAFX_SCENE_LAYOUT_PANE, GlobalSearchScope.allScope(project)); if (paneClass != null) { final ArrayList<XmlElementDescriptor> result = new ArrayList<XmlElementDescriptor>(); - ClassInheritorsSearch.search(paneClass).forEach(new Processor<PsiClass>() { + ClassInheritorsSearch.search(paneClass, paneClass.getUseScope(), true, true, false).forEach(new Processor<PsiClass>() { @Override public boolean process(PsiClass psiClass) { result.add(new JavaFxClassBackedElementDescriptor(psiClass.getName(), psiClass)); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyElementDescriptor.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyElementDescriptor.java index b10ebcb76689..617895ff2576 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyElementDescriptor.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/fxml/descriptors/JavaFxPropertyElementDescriptor.java @@ -78,7 +78,7 @@ public class JavaFxPropertyElementDescriptor implements XmlElementDescriptor { if (collectionItemType != null) { final PsiClass aClass = PsiUtil.resolveClassInType(collectionItemType); if (aClass != null) { - ClassInheritorsSearch.search(aClass).forEach(new Processor<PsiClass>() { + ClassInheritorsSearch.search(aClass, aClass.getUseScope(), true, true, false).forEach(new Processor<PsiClass>() { @Override public boolean process(PsiClass aClass) { descriptors.add(new JavaFxClassBackedElementDescriptor(aClass.getName(), aClass)); diff --git a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java index 6ea5c510ce4d..a0e9bd531ddc 100644 --- a/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java +++ b/plugins/javaFX/src/org/jetbrains/plugins/javaFX/sceneBuilder/SceneBuilderEditorProvider.java @@ -27,7 +27,7 @@ public class SceneBuilderEditorProvider implements FileEditorProvider, DumbAware public boolean accept(@NotNull Project project, @NotNull VirtualFile file) { return JavaFxFileTypeFactory.FXML_EXTENSION.equalsIgnoreCase(file.getExtension()) && SystemInfo.isJavaVersionAtLeast("1.8") && - Registry.is("embed.scene.builder", true); + Registry.is("embed.scene.builder"); } @NotNull diff --git a/plugins/junit/src/com/intellij/execution/junit/TestObject.java b/plugins/junit/src/com/intellij/execution/junit/TestObject.java index 9a7887621cb7..cc7c0ee66b74 100644 --- a/plugins/junit/src/com/intellij/execution/junit/TestObject.java +++ b/plugins/junit/src/com/intellij/execution/junit/TestObject.java @@ -217,7 +217,7 @@ public abstract class TestObject implements JavaCommandLine { myJavaParameters.getClassPath().add(JavaSdkUtil.getIdeaRtJarPath()); myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(JUnitStarter.class)); - if (Registry.is("junit_sm_runner", false)) { + if (Registry.is("junit_sm_runner")) { myJavaParameters.getClassPath().add(PathUtil.getJarPathForClass(ServiceMessageTypes.class)); } myJavaParameters.getProgramParametersList().add(JUnitStarter.IDE_VERSION + JUnitStarter.VERSION); @@ -273,7 +273,7 @@ public abstract class TestObject implements JavaCommandLine { @Override public ExecutionResult execute(final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { - final boolean smRunner = Registry.is("junit_sm_runner", false); + final boolean smRunner = Registry.is("junit_sm_runner"); if (smRunner) { myJavaParameters.getVMParametersList().add("-Didea.junit.sm_runner"); } diff --git a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java index fe5a13181ab9..9f04e6ac30bf 100644 --- a/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java +++ b/plugins/junit/src/com/intellij/execution/junit2/configuration/JUnitConfigurationModel.java @@ -172,7 +172,7 @@ public class JUnitConfigurationModel { final JUnitConfiguration.Data data = configuration.getPersistentData(); setTestType(data.TEST_OBJECT); setJUnitTextValue(ALL_IN_PACKAGE, data.getPackageName()); - setJUnitTextValue(CLASS, data.getMainClassName().replaceAll("\\$", "\\.")); + setJUnitTextValue(CLASS, data.getMainClassName() != null ? data.getMainClassName().replaceAll("\\$", "\\.") : ""); setJUnitTextValue(METHOD, data.getMethodName()); setJUnitTextValue(PATTERN, data.getPatternPresentation()); setJUnitTextValue(DIR, data.getDirName()); diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenExplicitProfiles.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenExplicitProfiles.java new file mode 100644 index 000000000000..ed9886a7e352 --- /dev/null +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/model/MavenExplicitProfiles.java @@ -0,0 +1,77 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.maven.model; + +import gnu.trove.THashSet; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; + +/** + * Created with IntelliJ IDEA. + * User: vladimir.dubovik + * Date: 4/9/2014 + * Time: 2:30 AM + */ +public class MavenExplicitProfiles implements Serializable { + public static final MavenExplicitProfiles NONE = new MavenExplicitProfiles(Collections.<String>emptySet()); + + private Collection<String> myEnabledProfiles; + private Collection<String> myDisabledProfiles; + + public MavenExplicitProfiles(Collection<String> enabledProfiles, Collection<String> disabledProfiles) { + myEnabledProfiles = enabledProfiles; + myDisabledProfiles = disabledProfiles; + } + + public MavenExplicitProfiles(Collection<String> enabledProfiles) { + this(enabledProfiles, Collections.<String>emptySet()); + } + + public Collection<String> getEnabledProfiles() { + return myEnabledProfiles; + } + + public Collection<String> getDisabledProfiles() { + return myDisabledProfiles; + } + + @Override + public MavenExplicitProfiles clone() { + return new MavenExplicitProfiles(new THashSet<String>(myEnabledProfiles), new THashSet<String>(myDisabledProfiles)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MavenExplicitProfiles that = (MavenExplicitProfiles)o; + + if (!myEnabledProfiles.equals(that.myEnabledProfiles)) return false; + if (!myDisabledProfiles.equals(that.myDisabledProfiles)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myEnabledProfiles.hashCode(); + result = 31 * result + myDisabledProfiles.hashCode(); + return result; + } +} diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServer.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServer.java index 7c945e8e0c39..827fc2816f5a 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServer.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServer.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.maven.server; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenModel; import java.io.File; @@ -35,6 +36,6 @@ public interface MavenServer extends Remote { ProfileApplicationResult applyProfiles(MavenModel model, File basedir, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, Collection<String> alwaysOnProfiles) throws RemoteException; } diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java index 0c4be99814c1..6b3db15e7035 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/MavenServerEmbedder.java @@ -34,12 +34,15 @@ public interface MavenServerEmbedder extends Remote { @NotNull MavenServerExecutionResult resolveProject(@NotNull File file, - @NotNull Collection<String> activeProfiles) throws RemoteException, - MavenServerProcessCanceledException; + @NotNull Collection<String> activeProfiles, + @NotNull Collection<String> inactiveProfiles) throws RemoteException, + MavenServerProcessCanceledException; @Nullable - String evaluateEffectivePom(@NotNull File file, @NotNull List<String> activeProfiles) throws RemoteException, - MavenServerProcessCanceledException; + String evaluateEffectivePom(@NotNull File file, + @NotNull List<String> activeProfiles, + @NotNull List<String> inactiveProfiles) throws RemoteException, + MavenServerProcessCanceledException; @NotNull MavenArtifact resolve(@NotNull MavenArtifactInfo info, diff --git a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/ProfileApplicationResult.java b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/ProfileApplicationResult.java index f86f74ce124f..d8283d4f8c0c 100644 --- a/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/ProfileApplicationResult.java +++ b/plugins/maven/maven-server-api/src/org/jetbrains/idea/maven/server/ProfileApplicationResult.java @@ -15,16 +15,16 @@ */ package org.jetbrains.idea.maven.server; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenModel; import java.io.Serializable; -import java.util.Collection; public class ProfileApplicationResult implements Serializable { private final MavenModel myModel; - private final Collection<String> myActivatedProfiles; + private final MavenExplicitProfiles myActivatedProfiles; - public ProfileApplicationResult(MavenModel model, Collection<String> activatedProfiles) { + public ProfileApplicationResult(MavenModel model, MavenExplicitProfiles activatedProfiles) { myModel = model; myActivatedProfiles = activatedProfiles; } @@ -33,7 +33,7 @@ public class ProfileApplicationResult implements Serializable { return myModel; } - public Collection<String> getActivatedProfiles() { + public MavenExplicitProfiles getActivatedProfiles() { return myActivatedProfiles; } } diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/Maven2ServerImpl.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/Maven2ServerImpl.java index 770b952e3de0..801bae42962d 100644 --- a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/Maven2ServerImpl.java +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/Maven2ServerImpl.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.maven.server; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenModel; import org.jetbrains.idea.maven.server.embedder.Maven2ServerEmbedderImpl; import org.jetbrains.idea.maven.server.embedder.Maven2ServerIndexerImpl; @@ -76,7 +77,7 @@ public class Maven2ServerImpl extends MavenRemoteObject implements MavenServer { public ProfileApplicationResult applyProfiles(MavenModel model, File basedir, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, Collection<String> alwaysOnProfiles) { try { return Maven2ServerEmbedderImpl.applyProfiles(model, basedir, explicitProfiles, alwaysOnProfiles); diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java index 7ed82b0494dc..08e98de53c6c 100644 --- a/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/idea/maven/server/embedder/Maven2ServerEmbedderImpl.java @@ -127,13 +127,15 @@ public class Maven2ServerEmbedderImpl extends MavenRemoteObject implements Maven @NotNull public MavenServerExecutionResult resolveProject(@NotNull final File file, - @NotNull final Collection<String> activeProfiles) + @NotNull final Collection<String> activeProfiles, + @NotNull final Collection<String> inactiveProfiles) throws MavenServerProcessCanceledException, RemoteException { return doExecute(new Executor<MavenServerExecutionResult>() { public MavenServerExecutionResult execute() throws Exception { DependencyTreeResolutionListener listener = new DependencyTreeResolutionListener(myConsoleWrapper); MavenExecutionResult result = myImpl.resolveProject(file, new ArrayList<String>(activeProfiles), + new ArrayList<String>(inactiveProfiles), Arrays.<ResolutionListener>asList(listener)); return createExecutionResult(file, result, listener.getRootNode()); } @@ -199,7 +201,7 @@ public class Maven2ServerEmbedderImpl extends MavenRemoteObject implements Maven } @Nullable - public String evaluateEffectivePom(@NotNull File file, @NotNull List<String> activeProfiles) { + public String evaluateEffectivePom(@NotNull File file, @NotNull List<String> activeProfiles, @NotNull List<String> inactiveProfiles) { throw new UnsupportedOperationException(); } @@ -422,21 +424,29 @@ public class Maven2ServerEmbedderImpl extends MavenRemoteObject implements Maven public static ProfileApplicationResult applyProfiles(MavenModel model, File basedir, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, Collection<String> alwaysOnProfiles) throws RemoteException { Model nativeModel = Maven2ModelConverter.toNativeModel(model); + Collection<String> enabledProfiles = explicitProfiles.getEnabledProfiles(); + Collection<String> disabledProfiles = explicitProfiles.getDisabledProfiles(); List<Profile> activatedPom = new ArrayList<Profile>(); List<Profile> activatedExternal = new ArrayList<Profile>(); List<Profile> activeByDefault = new ArrayList<Profile>(); List<Profile> rawProfiles = nativeModel.getProfiles(); List<Profile> expandedProfilesCache = null; + List<Profile> deactivatedProfiles = new ArrayList<Profile>(); for (int i = 0; i < rawProfiles.size(); i++) { Profile eachRawProfile = rawProfiles.get(i); - boolean shouldAdd = explicitProfiles.contains(eachRawProfile.getId()) || alwaysOnProfiles.contains(eachRawProfile.getId()); + if (disabledProfiles.contains(eachRawProfile.getId())) { + deactivatedProfiles.add(eachRawProfile); + continue; + } + + boolean shouldAdd = enabledProfiles.contains(eachRawProfile.getId()) || alwaysOnProfiles.contains(eachRawProfile.getId()); Activation activation = eachRawProfile.getActivation(); if (activation != null) { @@ -479,7 +489,9 @@ public class Maven2ServerEmbedderImpl extends MavenRemoteObject implements Maven } return new ProfileApplicationResult(Maven2ModelConverter.convertModel(nativeModel, null), - collectProfilesIds(activatedProfiles)); + new MavenExplicitProfiles(collectProfilesIds(activatedProfiles), + collectProfilesIds(deactivatedProfiles)) + ); } private static ProfileActivator[] getProfileActivators(File basedir) throws RemoteException { diff --git a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java index 3926a3d1f030..70a6e470926c 100644 --- a/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java +++ b/plugins/maven/maven2-server-impl/src/org/jetbrains/maven/embedder/MavenEmbedder.java @@ -173,15 +173,18 @@ public class MavenEmbedder { } @NotNull - public MavenExecutionResult resolveProject(@NotNull final File file, @NotNull final List<String> activeProfiles) { - return resolveProject(file, activeProfiles, Collections.<ResolutionListener>emptyList()); + public MavenExecutionResult resolveProject(@NotNull final File file, + @NotNull final List<String> activeProfiles, + @NotNull final List<String> inactiveProfiles) { + return resolveProject(file, activeProfiles, inactiveProfiles, Collections.<ResolutionListener>emptyList()); } @NotNull public MavenExecutionResult resolveProject(@NotNull final File file, @NotNull final List<String> activeProfiles, + @NotNull final List<String> inactiveProfiles, List<ResolutionListener> listeners) { - MavenExecutionRequest request = createRequest(file, activeProfiles, Collections.<String>emptyList(), Collections.<String>emptyList()); + MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.<String>emptyList()); ProjectBuilderConfiguration config = request.getProjectBuilderConfiguration(); request.getGlobalProfileManager().loadSettingsProfiles(mySettings); diff --git a/plugins/maven/maven2-server-impl/test/org/jetbrains/idea/maven/embedder/MavenServerEmbedderTest.java b/plugins/maven/maven2-server-impl/test/org/jetbrains/idea/maven/embedder/MavenServerEmbedderTest.java index 53a6d0fa6d72..0fc588e7127b 100644 --- a/plugins/maven/maven2-server-impl/test/org/jetbrains/idea/maven/embedder/MavenServerEmbedderTest.java +++ b/plugins/maven/maven2-server-impl/test/org/jetbrains/idea/maven/embedder/MavenServerEmbedderTest.java @@ -94,7 +94,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "<version>1</version>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.execute(myProjectPom, Collections.<String>emptyList(), Arrays.asList("compile")); + MavenServerExecutionResult result = + myEmbedder.execute(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList(), Arrays.asList("compile")); assertNotNull(result.projectData); assertNotNull(new File(getProjectPath(), "target").exists()); @@ -119,7 +120,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</dependencies>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result.projectData); assertOrderedElementsAreEqual(result.unresolvedArtifacts); @@ -135,7 +137,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "<version>1</version>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); MavenModel project = result.projectData.mavenModel; assertNotNull(project); @@ -171,7 +174,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</build>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result.projectData); assertOrderedElementsAreEqual(result.unresolvedArtifacts); @@ -203,7 +207,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</dependencies>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result.projectData); assertOrderedElementsAreEqual(result.unresolvedArtifacts); @@ -264,7 +269,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</dependencies>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result.projectData); assertOrderedElementsAreEqual(result.unresolvedArtifacts, new MavenId("fff", "zzz", "666")); @@ -286,7 +292,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</dependencies>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result.projectData); assertOrderedElementsAreEqual(result.unresolvedArtifacts, new MavenId("fff", "zzz", "666")); @@ -304,7 +311,7 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "<version>1</version>" + "<packaging>pom</packaging>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - myEmbedder.execute(m, Collections.<String>emptyList(), Arrays.asList("install")); + myEmbedder.execute(m, Collections.<String>emptyList(), Collections.<String>emptyList(), Arrays.asList("install")); myEmbedder.reset(); File fooParentFile = new File(repo, "test/foo-parent/1/foo-parent-1.pom"); assertTrue(fooParentFile.exists()); @@ -319,7 +326,7 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { " <version>1</version>" + "</parent>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - myEmbedder.execute(m, Collections.<String>emptyList(), Arrays.asList("install")); + myEmbedder.execute(m, Collections.<String>emptyList(), Collections.<String>emptyList(), Arrays.asList("install")); myEmbedder.reset(); assertTrue(new File(repo, "test/foo/1/foo-1.pom").exists()); @@ -339,7 +346,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</dependencies>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result.projectData); assertOrderedElementsAreEqual(result.unresolvedArtifacts, new MavenId("test", "foo-parent", "1")); @@ -361,7 +369,8 @@ public class MavenServerEmbedderTest extends MavenImportingTestCase { "</dependencies>"); myEmbedder.customizeForResolve(new SoutMavenConsole(), EMPTY_MAVEN_PROCESS); - MavenServerExecutionResult result = myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList()); + MavenServerExecutionResult result = + myEmbedder.resolveProject(myProjectPom, Collections.<String>emptyList(), Collections.<String>emptyList()); assertNotNull(result); assertOrderedElementsAreEqual(result.unresolvedArtifacts, new MavenId("fff", "zzz", "666")); diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java index 66a5943211c7..854c099d25b4 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerEmbedderImpl.java @@ -300,20 +300,22 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven @NotNull @Override - public MavenServerExecutionResult resolveProject(@NotNull File file, @NotNull Collection<String> activeProfiles) + public MavenServerExecutionResult resolveProject(@NotNull File file, + @NotNull Collection<String> activeProfiles, + @NotNull Collection<String> inactiveProfiles) throws RemoteException, MavenServerProcessCanceledException { DependencyTreeResolutionListener listener = new DependencyTreeResolutionListener(myConsoleWrapper); - MavenExecutionResult result = - doResolveProject(file, new ArrayList<String>(activeProfiles), Arrays.<ResolutionListener>asList(listener)); + MavenExecutionResult result = doResolveProject(file, new ArrayList<String>(activeProfiles), new ArrayList<String>(inactiveProfiles), + Arrays.<ResolutionListener>asList(listener)); return createExecutionResult(file, result, listener.getRootNode()); } @Nullable @Override - public String evaluateEffectivePom(@NotNull File file, @NotNull List<String> activeProfiles) + public String evaluateEffectivePom(@NotNull File file, @NotNull List<String> activeProfiles, @NotNull List<String> inactiveProfiles) throws RemoteException, MavenServerProcessCanceledException { - return MavenEffectivePomDumper.evaluateEffectivePom(this, file, activeProfiles); + return MavenEffectivePomDumper.evaluateEffectivePom(this, file, activeProfiles, inactiveProfiles); } public void executeWithMavenSession(MavenExecutionRequest request, Runnable runnable) { @@ -350,9 +352,9 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven @NotNull public MavenExecutionResult doResolveProject(@NotNull final File file, @NotNull final List<String> activeProfiles, + @NotNull final List<String> inactiveProfiles, final List<ResolutionListener> listeners) throws RemoteException { - final MavenExecutionRequest request = - createRequest(file, activeProfiles, Collections.<String>emptyList(), Collections.<String>emptyList()); + final MavenExecutionRequest request = createRequest(file, activeProfiles, inactiveProfiles, Collections.<String>emptyList()); request.setUpdateSnapshots(myAlwaysUpdateSnapshots); @@ -899,21 +901,29 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven public static ProfileApplicationResult applyProfiles(MavenModel model, File basedir, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, Collection<String> alwaysOnProfiles) throws RemoteException { Model nativeModel = MavenModelConverter.toNativeModel(model); + Collection<String> enabledProfiles = explicitProfiles.getEnabledProfiles(); + Collection<String> disabledProfiles = explicitProfiles.getDisabledProfiles(); List<Profile> activatedPom = new ArrayList<Profile>(); List<Profile> activatedExternal = new ArrayList<Profile>(); List<Profile> activeByDefault = new ArrayList<Profile>(); List<Profile> rawProfiles = nativeModel.getProfiles(); List<Profile> expandedProfilesCache = null; + List<Profile> deactivatedProfiles = new ArrayList<Profile>(); for (int i = 0; i < rawProfiles.size(); i++) { Profile eachRawProfile = rawProfiles.get(i); - boolean shouldAdd = explicitProfiles.contains(eachRawProfile.getId()) || alwaysOnProfiles.contains(eachRawProfile.getId()); + if (disabledProfiles.contains(eachRawProfile.getId())) { + deactivatedProfiles.add(eachRawProfile); + continue; + } + + boolean shouldAdd = enabledProfiles.contains(eachRawProfile.getId()) || alwaysOnProfiles.contains(eachRawProfile.getId()); Activation activation = eachRawProfile.getActivation(); if (activation != null) { @@ -955,7 +965,10 @@ public class Maven3ServerEmbedderImpl extends MavenRemoteObject implements Maven new DefaultProfileInjector().injectProfile(nativeModel, each, null, null); } - return new ProfileApplicationResult(MavenModelConverter.convertModel(nativeModel, null), collectProfilesIds(activatedProfiles)); + return new ProfileApplicationResult(MavenModelConverter.convertModel(nativeModel, null), + new MavenExplicitProfiles(collectProfilesIds(activatedProfiles), + collectProfilesIds(deactivatedProfiles)) + ); } private static Model doInterpolate(Model result, File basedir) throws RemoteException { diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerImpl.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerImpl.java index 0e4d468297f3..cc33728cd46b 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerImpl.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/Maven3ServerImpl.java @@ -15,6 +15,7 @@ */ package org.jetbrains.idea.maven.server; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenModel; import java.io.File; @@ -74,7 +75,7 @@ public class Maven3ServerImpl extends MavenRemoteObject implements MavenServer { public ProfileApplicationResult applyProfiles(MavenModel model, File basedir, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, Collection<String> alwaysOnProfiles) { try { return Maven3ServerEmbedderImpl.applyProfiles(model, basedir, explicitProfiles, alwaysOnProfiles); diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenEffectivePomDumper.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenEffectivePomDumper.java index 2d0c90dd3c0a..75d45f59fd08 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenEffectivePomDumper.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenEffectivePomDumper.java @@ -47,14 +47,14 @@ public class MavenEffectivePomDumper { @Nullable public static String evaluateEffectivePom(final Maven3ServerEmbedderImpl embedder, @NotNull final File file, - @NotNull List<String> activeProfiles) + @NotNull List<String> activeProfiles, + @NotNull List<String> inactiveProfiles) throws RemoteException, MavenServerProcessCanceledException { final StringWriter w = new StringWriter(); try { - final MavenExecutionRequest - request = embedder.createRequest(file, activeProfiles, Collections.<String>emptyList(), Collections.<String>emptyList()); + final MavenExecutionRequest request = embedder.createRequest(file, activeProfiles, inactiveProfiles, Collections.<String>emptyList()); embedder.executeWithMavenSession(request, new Runnable() { @Override diff --git a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java index 15899e7aa38f..a51ddfe0210a 100644 --- a/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java +++ b/plugins/maven/maven3-server-impl/src/org/jetbrains/idea/maven/server/MavenLeakDetector.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.maven.server; import com.intellij.util.ReflectionUtil; import java.rmi.RemoteException; +import java.util.Collections; import java.util.IdentityHashMap; import java.util.Map; @@ -54,14 +55,14 @@ public class MavenLeakDetector { } private Map<Thread, Thread> getShutdownHooks() { - Class clazz = null; + Class clazz; try { clazz = Class.forName("java.lang.ApplicationShutdownHooks"); } catch (ClassNotFoundException e) { // we can ignore this one + return Collections.emptyMap(); } return ReflectionUtil.getField(clazz, null, Map.class, "hooks"); } - } diff --git a/plugins/maven/pom.xml b/plugins/maven/pom.xml index 41052264aaf0..c2f0c71115cd 100644 --- a/plugins/maven/pom.xml +++ b/plugins/maven/pom.xml @@ -9,7 +9,7 @@ <name>Maven Integration</name> <description>Maven Integration plugin</description> - + <repositories> </repositories> @@ -17,7 +17,7 @@ <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-embedder</artifactId> - <version>2.1-SNAPSHOT</version> + <version>3.0.5</version> <exclusions> <exclusion> <groupId>aspectj</groupId> @@ -38,9 +38,9 @@ </exclusions> </dependency> <dependency> - <groupId>com.sonatype.nexus</groupId> + <groupId>org.sonatype.nexus</groupId> <artifactId>nexus-indexer</artifactId> - <version>1.0.0-SNAPSHOT</version> + <version>3.0.4</version> <exclusions> <exclusion> <groupId>junit</groupId> diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomProjectProcessorUtils.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomProjectProcessorUtils.java index ceebebb093e5..ba3d265b7d10 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomProjectProcessorUtils.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenDomProjectProcessorUtils.java @@ -514,11 +514,12 @@ public class MavenDomProjectProcessorUtils { MavenProject mavenProjectOrNull, Processor<T> processor, Function<? super MavenDomProfile, T> f) { - Collection<String> activePropfiles = mavenProjectOrNull == null ? null : mavenProjectOrNull.getActivatedProfilesIds(); + Collection<String> activeProfiles = + mavenProjectOrNull == null ? null : mavenProjectOrNull.getActivatedProfilesIds().getEnabledProfiles(); for (MavenDomProfile each : profilesDom.getProfiles()) { XmlTag idTag = each.getId().getXmlTag(); if (idTag == null) continue; - if (activePropfiles != null && !activePropfiles.contains(idTag.getValue().getTrimmedText())) continue; + if (activeProfiles != null && !activeProfiles.contains(idTag.getValue().getTrimmedText())) continue; if (processProfile(each, processor, f)) return true; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java index 66875895f278..0422898a2bbb 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/dom/MavenPropertyResolver.java @@ -81,10 +81,10 @@ public class MavenPropertyResolver { @Nullable Map<String, String> resolvedPropertiesParam, Appendable out) throws IOException { Map<String, String> resolvedProperties = resolvedPropertiesParam; - + Matcher matcher = pattern.matcher(text); int groupCount = matcher.groupCount(); - + int last = 0; while (matcher.find()) { if (escapeString != null) { @@ -116,7 +116,7 @@ public class MavenPropertyResolver { if (resolvedProperties == null) { resolvedProperties = new HashMap<String, String>(); } - + String propertyValue = resolvedProperties.get(propertyName); if (propertyValue == null) { if (resolvedProperties.containsKey(propertyName)) { // if cyclic property dependencies @@ -146,7 +146,7 @@ public class MavenPropertyResolver { out.append(propertyValue); } } - + out.append(text, last, text.length()); } @@ -177,10 +177,10 @@ public class MavenPropertyResolver { collectPropertiesFromDOM(projectDom.getProperties(), result); - Collection<String> activePropfiles = project.getActivatedProfilesIds(); + Collection<String> activeProfiles = project.getActivatedProfilesIds().getEnabledProfiles(); for (MavenDomProfile each : projectDom.getProfiles().getProfiles()) { XmlTag idTag = each.getId().getXmlTag(); - if (idTag == null || !activePropfiles.contains(idTag.getValue().getTrimmedText())) continue; + if (idTag == null || !activeProfiles.contains(idTag.getValue().getTrimmedText())) continue; collectPropertiesFromDOM(each.getProperties(), result); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenConfigurationProducer.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenConfigurationProducer.java index 0bf342fcdcfa..13b58ca94b12 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenConfigurationProducer.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenConfigurationProducer.java @@ -29,6 +29,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenProjectsManager; import java.util.Collection; @@ -76,9 +77,9 @@ public class MavenConfigurationProducer extends RuntimeConfigurationProducer { VirtualFile f = ((PsiFile)l.getPsiElement()).getVirtualFile(); List<String> goals = ((MavenGoalLocation)l).getGoals(); - Collection<String> profiles = MavenProjectsManager.getInstance(l.getProject()).getExplicitProfiles(); + MavenExplicitProfiles profiles = MavenProjectsManager.getInstance(l.getProject()).getExplicitProfiles(); - return new MavenRunnerParameters(true, f.getParent().getPath(), goals, profiles); + return new MavenRunnerParameters(true, f.getParent().getPath(), goals, profiles.getEnabledProfiles(), profiles.getDisabledProfiles()); } public int compareTo(Object o) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerParameters.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerParameters.java index c04f2d344e51..bca71b2c0d8f 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerParameters.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/execution/MavenRunnerParameters.java @@ -23,6 +23,7 @@ import com.intellij.util.xmlb.annotations.Transient; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.model.MavenConstants; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.utils.Path; import java.io.File; @@ -53,6 +54,13 @@ public class MavenRunnerParameters implements Cloneable { public MavenRunnerParameters(boolean isPomExecution, @NotNull String workingDirPath, @Nullable List<String> goals, + @NotNull MavenExplicitProfiles explicitProfiles) { + this(isPomExecution, workingDirPath, goals, explicitProfiles.getEnabledProfiles(), explicitProfiles.getDisabledProfiles()); + } + + public MavenRunnerParameters(boolean isPomExecution, + @NotNull String workingDirPath, + @Nullable List<String> goals, @Nullable Collection<String> explicitEnabledProfiles, @Nullable Collection<String> explicitDisabledProfiles) { this.isPomExecution = isPomExecution; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java index 65e1b5ed2dce..e2a313ef30a9 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/importing/MavenRootModelAdapter.java @@ -19,12 +19,15 @@ import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.module.ModifiableModuleModel; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.impl.ModuleOrderEntryImpl; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFileManager; @@ -45,6 +48,7 @@ import org.jetbrains.jps.model.java.JpsJavaExtensionService; import org.jetbrains.jps.model.module.JpsModuleSourceRootType; import java.io.File; +import java.util.Arrays; import java.util.Set; public class MavenRootModelAdapter { @@ -176,10 +180,7 @@ public class MavenRootModelAdapter { public boolean isAlreadyExcluded(File f) { String url = toUrl(f.getPath()).getUrl(); - for (String excludedUrl : myRootModel.getExcludeRootUrls()) { - if (VfsUtilCore.isEqualOrAncestor(excludedUrl, url)) return true; - } - return false; + return VfsUtilCore.isUnder(url, Arrays.asList(myRootModel.getExcludeRootUrls())); } private boolean exists(String path) { @@ -193,6 +194,10 @@ public class MavenRootModelAdapter { if (e == null) return; if (e.getUrl().equals(url.getUrl())) return; e.addExcludeFolder(url.getUrl()); + if (!Registry.is("ide.hide.excluded.files")) { + Project project = myRootModel.getProject(); + ChangeListManager.getInstance(project).addDirectoryToIgnoreImplicitly(toPath(path).getPath()); + } } public void unregisterAll(String path, boolean under, boolean unregisterSources) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorPanel.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorPanel.java index 86761532f6a0..04e93ac9e0e2 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorPanel.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorPanel.java @@ -39,6 +39,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.execution.MavenGoalLocation; import org.jetbrains.idea.maven.model.MavenArtifact; import org.jetbrains.idea.maven.model.MavenConstants; +import org.jetbrains.idea.maven.model.MavenProfileKind; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenDataKeys; @@ -226,9 +227,9 @@ public class MavenProjectsNavigatorPanel extends SimpleToolWindowPanel implement private Object extractProfiles() { final List<MavenProjectsStructure.ProfileNode> nodes = getSelectedNodes(MavenProjectsStructure.ProfileNode.class); - final List<String> profiles = new ArrayList<String>(); + final Map<String, MavenProfileKind> profiles = new THashMap<String, MavenProfileKind>(); for (MavenProjectsStructure.ProfileNode node : nodes) { - profiles.add(node.getProfileName()); + profiles.put(node.getProfileName(), node.getState()); } return profiles; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenExecuteGoalAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenExecuteGoalAction.java index e591bb61d11b..8c02946b5b72 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenExecuteGoalAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/navigator/actions/MavenExecuteGoalAction.java @@ -37,6 +37,7 @@ import org.jetbrains.idea.maven.utils.MavenUtil; import javax.swing.event.HyperlinkEvent; import java.io.File; import java.util.Arrays; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -105,7 +106,7 @@ public class MavenExecuteGoalAction extends DumbAwareAction { return; } - MavenRunnerParameters parameters = new MavenRunnerParameters(true, workDirectory, Arrays.asList(ParametersList.parse(goals)), null); + MavenRunnerParameters parameters = new MavenRunnerParameters(true, workDirectory, Arrays.asList(ParametersList.parse(goals)), Collections.<String>emptyList()); MavenGeneralSettings generalSettings = new MavenGeneralSettings(); generalSettings.setMavenHome(mavenHome.getPath()); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java index 70a8aa8cfd81..01fc83800372 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProject.java @@ -19,7 +19,6 @@ import com.intellij.execution.configurations.ParametersList; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.module.StdModuleTypes; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.ui.LightFilePointer; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Key; @@ -29,13 +28,11 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.pointers.VirtualFilePointer; import com.intellij.util.containers.ContainerUtil; import gnu.trove.THashSet; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.maven.dom.MavenDomUtil; import org.jetbrains.idea.maven.importing.MavenExtraArtifactType; import org.jetbrains.idea.maven.importing.MavenImporter; import org.jetbrains.idea.maven.model.*; @@ -607,7 +604,7 @@ public class MavenProject { @NotNull public MavenProjectChanges read(@NotNull MavenGeneralSettings generalSettings, - @NotNull Collection<String> profiles, + @NotNull MavenExplicitProfiles profiles, @NotNull MavenProjectReader reader, @NotNull MavenProjectReaderProjectLocator locator) { return set(reader.readProject(generalSettings, myFile, profiles, locator), generalSettings, true, false, true); @@ -805,7 +802,7 @@ public class MavenProject { } @NotNull - public Collection<String> getActivatedProfilesIds() { + public MavenExplicitProfiles getActivatedProfilesIds() { return myState.myActivatedProfilesIds; } @@ -1089,7 +1086,7 @@ public class MavenProject { Map<String, String> myModelMap; Collection<String> myProfilesIds; - Collection<String> myActivatedProfilesIds; + MavenExplicitProfiles myActivatedProfilesIds; Collection<MavenProjectProblem> myReadingProblems; Set<MavenId> myUnresolvedArtifactIds; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.java index bb465f5e5fc1..31f245ccfdc6 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReader.java @@ -47,9 +47,9 @@ public class MavenProjectReader { public MavenProjectReaderResult readProject(MavenGeneralSettings generalSettings, VirtualFile file, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, MavenProjectReaderProjectLocator locator) { - Pair<RawModelReadResult, Collection<String>> readResult = + Pair<RawModelReadResult, MavenExplicitProfiles> readResult = doReadProjectModel(generalSettings, file, explicitProfiles, new THashSet<VirtualFile>(), locator); File basedir = getBaseDir(file); @@ -76,11 +76,11 @@ public class MavenProjectReader { return new File(file.getParent().getPath()); } - private Pair<RawModelReadResult, Collection<String>> doReadProjectModel(MavenGeneralSettings generalSettings, - VirtualFile file, - Collection<String> explicitProfiles, - Set<VirtualFile> recursionGuard, - MavenProjectReaderProjectLocator locator) { + private Pair<RawModelReadResult, MavenExplicitProfiles> doReadProjectModel(MavenGeneralSettings generalSettings, + VirtualFile file, + MavenExplicitProfiles explicitProfiles, + Set<VirtualFile> recursionGuard, + MavenProjectReaderProjectLocator locator) { RawModelReadResult cachedModel = myRawModelsCache.get(file); if (cachedModel == null) { cachedModel = doReadProjectModel(file, false); @@ -364,7 +364,7 @@ public class MavenProjectReader { private static ProfileApplicationResult applyProfiles(MavenModel model, File basedir, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, Collection<String> alwaysOnProfiles) { return MavenServerManager.getInstance().applyProfiles(model, basedir, explicitProfiles, alwaysOnProfiles); } @@ -372,7 +372,7 @@ public class MavenProjectReader { private MavenModel resolveInheritance(final MavenGeneralSettings generalSettings, MavenModel model, final VirtualFile file, - final Collection<String> explicitProfiles, + final MavenExplicitProfiles explicitProfiles, final Set<VirtualFile> recursionGuard, final MavenProjectReaderProjectLocator locator, Collection<MavenProjectProblem> problems) { @@ -456,21 +456,23 @@ public class MavenProjectReader { public MavenProjectReaderResult resolveProject(MavenGeneralSettings generalSettings, MavenEmbedderWrapper embedder, VirtualFile file, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, MavenProjectReaderProjectLocator locator) throws MavenProcessCanceledException { try { - MavenServerExecutionResult result = embedder.resolveProject(file, explicitProfiles); - if (result.projectData == null) { + MavenServerExecutionResult result = + embedder.resolveProject(file, explicitProfiles.getEnabledProfiles(), explicitProfiles.getDisabledProfiles()); + MavenServerExecutionResult.ProjectData projectData = result.projectData; + if (projectData == null) { MavenProjectReaderResult temp = readProject(generalSettings, file, explicitProfiles, locator); temp.readingProblems.addAll(result.problems); temp.unresolvedArtifactIds.addAll(result.unresolvedArtifacts); return temp; } - return new MavenProjectReaderResult(result.projectData.mavenModel, - result.projectData.mavenModelMap, - result.projectData.activatedProfiles, - result.projectData.nativeMavenProject, + return new MavenProjectReaderResult(projectData.mavenModel, + projectData.mavenModelMap, + new MavenExplicitProfiles(projectData.activatedProfiles, explicitProfiles.getDisabledProfiles()), + projectData.nativeMavenProject, result.problems, result.unresolvedArtifacts); } @@ -497,17 +499,18 @@ public class MavenProjectReader { public static MavenProjectReaderResult generateSources(MavenEmbedderWrapper embedder, MavenImportingSettings importingSettings, VirtualFile file, - Collection<String> profiles, + MavenExplicitProfiles profiles, MavenConsole console) throws MavenProcessCanceledException { try { List<String> goals = Collections.singletonList(importingSettings.getUpdateFoldersOnImportPhase()); - MavenServerExecutionResult result = embedder.execute(file, profiles, goals); - if (result.projectData == null) return null; - - return new MavenProjectReaderResult(result.projectData.mavenModel, - result.projectData.mavenModelMap, - result.projectData.activatedProfiles, - result.projectData.nativeMavenProject, + MavenServerExecutionResult result = embedder.execute(file, profiles.getEnabledProfiles(), profiles.getDisabledProfiles(), goals); + MavenServerExecutionResult.ProjectData projectData = result.projectData; + if (projectData == null) return null; + + return new MavenProjectReaderResult(projectData.mavenModel, + projectData.mavenModelMap, + new MavenExplicitProfiles(projectData.activatedProfiles, profiles.getDisabledProfiles()), + projectData.nativeMavenProject, result.problems, result.unresolvedArtifacts); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReaderResult.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReaderResult.java index 29ac462b115a..cbec80162fd0 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReaderResult.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectReaderResult.java @@ -16,6 +16,7 @@ package org.jetbrains.idea.maven.project; import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenId; import org.jetbrains.idea.maven.model.MavenModel; import org.jetbrains.idea.maven.model.MavenProjectProblem; @@ -28,14 +29,14 @@ import java.util.Set; public class MavenProjectReaderResult { public final MavenModel mavenModel; public final Map<String, String> nativeModelMap; - public final Collection<String> activatedProfiles; + public final MavenExplicitProfiles activatedProfiles; @Nullable public final NativeMavenProjectHolder nativeMavenProject; public final Collection<MavenProjectProblem> readingProblems; public final Set<MavenId> unresolvedArtifactIds; public MavenProjectReaderResult(MavenModel mavenModel, Map<String, String> nativeModelMap, - Collection<String> activatedProfiles, + MavenExplicitProfiles activatedProfiles, @Nullable NativeMavenProjectHolder nativeMavenProject, Collection<MavenProjectProblem> readingProblems, Set<MavenId> unresolvedArtifactIds) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java index 4671a261b590..6ff6c851c67b 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectSettings.java @@ -25,8 +25,11 @@ import org.jetbrains.annotations.Nullable; */ @State( name = "MavenProjectSettings", - storages = {@Storage( - file = StoragePathMacros.PROJECT_CONFIG_DIR + "/mavenProjectSettings.xml")}) + storages = { + @Storage(file = StoragePathMacros.PROJECT_FILE), + @Storage(file = StoragePathMacros.PROJECT_CONFIG_DIR + "/mavenProjectSettings.xml", scheme = StorageScheme.DIRECTORY_BASED) + } +) public class MavenProjectSettings implements PersistentStateComponent<MavenProjectSettings> { private final Project myProject; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java index 37a1a47cde6a..88b92ae679a6 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManager.java @@ -183,9 +183,10 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent doInit(false); } - private void initNew(List<VirtualFile> files, List<String> explicitProfiles) { + private void initNew(List<VirtualFile> files, MavenExplicitProfiles explicitProfiles) { myState.originalFiles = MavenUtil.collectPaths(files); - getWorkspaceSettings().setEnabledProfiles(explicitProfiles); + getWorkspaceSettings().setEnabledProfiles(explicitProfiles.getEnabledProfiles()); + getWorkspaceSettings().setDisabledProfiles(explicitProfiles.getDisabledProfiles()); doInit(true); } @@ -241,7 +242,9 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent } private void applyStateToTree() { - myProjectsTree.resetManagedFilesPathsAndProfiles(myState.originalFiles, getWorkspaceSettings().enabledProfiles); + MavenWorkspaceSettings settings = getWorkspaceSettings(); + MavenExplicitProfiles explicitProfiles = new MavenExplicitProfiles(settings.enabledProfiles, settings.disabledProfiles); + myProjectsTree.resetManagedFilesPathsAndProfiles(myState.originalFiles, explicitProfiles); myProjectsTree.setIgnoredFilesPaths(new ArrayList<String>(myState.ignoredFiles)); myProjectsTree.setIgnoredFilesPatterns(myState.ignoredPathMasks); } @@ -474,11 +477,11 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent } @TestOnly - public void resetManagedFilesAndProfilesInTests(List<VirtualFile> files, List<String> profiles) { + public void resetManagedFilesAndProfilesInTests(List<VirtualFile> files, MavenExplicitProfiles profiles) { myWatcher.resetManagedFilesAndProfilesInTests(files, profiles); } - public void addManagedFilesWithProfiles(List<VirtualFile> files, List<String> profiles) { + public void addManagedFilesWithProfiles(List<VirtualFile> files, MavenExplicitProfiles profiles) { if (!isInitialized()) { initNew(files, profiles); } @@ -488,7 +491,7 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent } public void addManagedFiles(@NotNull List<VirtualFile> files) { - addManagedFilesWithProfiles(files, Collections.<String>emptyList()); + addManagedFilesWithProfiles(files, MavenExplicitProfiles.NONE); } public void addManagedFilesOrUnignore(@NotNull List<VirtualFile> files) { @@ -506,12 +509,12 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent } @NotNull - public Collection<String> getExplicitProfiles() { - if (!isInitialized()) return Collections.emptyList(); + public MavenExplicitProfiles getExplicitProfiles() { + if (!isInitialized()) return MavenExplicitProfiles.NONE; return myProjectsTree.getExplicitProfiles(); } - public void setExplicitProfiles(@NotNull Collection<String> profiles) { + public void setExplicitProfiles(@NotNull MavenExplicitProfiles profiles) { myWatcher.setExplicitProfiles(profiles); } @@ -776,8 +779,10 @@ public class MavenProjectsManager extends MavenSimpleProjectComponent @Override public void run(MavenEmbedderWrapper embedder) throws MavenProcessCanceledException { try { + MavenExplicitProfiles profiles = mavenProject.getActivatedProfilesIds(); String res = - embedder.evaluateEffectivePom(mavenProject.getFile(), mavenProject.getActivatedProfilesIds()); + embedder.evaluateEffectivePom(mavenProject.getFile(), profiles.getEnabledProfiles(), + profiles.getDisabledProfiles()); consumer.consume(res); } catch (UnsupportedOperationException e) { diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java index 81eb778b2466..b8644991eaff 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsManagerWatcher.java @@ -51,6 +51,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; import org.jetbrains.idea.maven.model.MavenConstants; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.utils.MavenMergingUpdateQueue; import org.jetbrains.idea.maven.utils.MavenUtil; @@ -247,13 +248,13 @@ public class MavenProjectsManagerWatcher { Disposer.dispose(myChangedDocumentsQueue); } - public synchronized void addManagedFilesWithProfiles(List<VirtualFile> files, List<String> explicitProfiles) { + public synchronized void addManagedFilesWithProfiles(List<VirtualFile> files, MavenExplicitProfiles explicitProfiles) { myProjectsTree.addManagedFilesWithProfiles(files, explicitProfiles); scheduleUpdateAll(false, true); } @TestOnly - public synchronized void resetManagedFilesAndProfilesInTests(List<VirtualFile> files, List<String> explicitProfiles) { + public synchronized void resetManagedFilesAndProfilesInTests(List<VirtualFile> files, MavenExplicitProfiles explicitProfiles) { myProjectsTree.resetManagedFilesAndProfiles(files, explicitProfiles); scheduleUpdateAll(false, true); } @@ -263,7 +264,7 @@ public class MavenProjectsManagerWatcher { scheduleUpdateAll(false, true); } - public synchronized void setExplicitProfiles(Collection<String> profiles) { + public synchronized void setExplicitProfiles(MavenExplicitProfiles profiles) { myProjectsTree.setExplicitProfiles(profiles); scheduleUpdateAll(false, false); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java index 89bf69711114..c7adefebf207 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenProjectsTree.java @@ -68,8 +68,9 @@ public class MavenProjectsTree { private volatile List<String> myIgnoredFilesPatterns = new ArrayList<String>(); private volatile Pattern myIgnoredFilesPatternsCache; - private Set<String> myExplicitProfiles = new HashSet<String>(); - private final Set<String> myTemporarilyRemovedExplicitProfiles = new HashSet<String>(); + private MavenExplicitProfiles myExplicitProfiles = MavenExplicitProfiles.NONE; + private final MavenExplicitProfiles myTemporarilyRemovedExplicitProfiles = + new MavenExplicitProfiles(new HashSet<String>(), new HashSet<String>()); private final List<MavenProject> myRootProjects = new ArrayList<MavenProject>(); @@ -100,7 +101,8 @@ public class MavenProjectsTree { result.myManagedFilesPaths = readCollection(in, new LinkedHashSet<String>()); result.myIgnoredFilesPaths = readCollection(in, new ArrayList<String>()); result.myIgnoredFilesPatterns = readCollection(in, new ArrayList<String>()); - result.myExplicitProfiles = readCollection(in, new THashSet<String>()); + result.myExplicitProfiles = new MavenExplicitProfiles(readCollection(in, new THashSet<String>()), + readCollection(in, new THashSet<String>())); result.myRootProjects.addAll(readProjectsRecursively(in, result)); } catch (IOException e) { @@ -166,7 +168,8 @@ public class MavenProjectsTree { writeCollection(out, myManagedFilesPaths); writeCollection(out, myIgnoredFilesPaths); writeCollection(out, myIgnoredFilesPatterns); - writeCollection(out, myExplicitProfiles); + writeCollection(out, myExplicitProfiles.getEnabledProfiles()); + writeCollection(out, myExplicitProfiles.getDisabledProfiles()); writeProjectsRecursively(out, myRootProjects); } finally { @@ -194,7 +197,7 @@ public class MavenProjectsTree { } } - public void resetManagedFilesPathsAndProfiles(List<String> paths, Collection<String> profiles) { + public void resetManagedFilesPathsAndProfiles(List<String> paths, MavenExplicitProfiles profiles) { synchronized (myStateLock) { myManagedFilesPaths = new LinkedHashSet<String>(paths); } @@ -202,19 +205,20 @@ public class MavenProjectsTree { } @TestOnly - public void resetManagedFilesAndProfiles(List<VirtualFile> files, Collection<String> profiles) { + public void resetManagedFilesAndProfiles(List<VirtualFile> files, MavenExplicitProfiles profiles) { resetManagedFilesPathsAndProfiles(MavenUtil.collectPaths(files), profiles); } - public void addManagedFilesWithProfiles(List<VirtualFile> files, Collection<String> profiles) { + public void addManagedFilesWithProfiles(List<VirtualFile> files, MavenExplicitProfiles profiles) { List<String> newFiles; - Set<String> newProfiles; + MavenExplicitProfiles newProfiles; synchronized (myStateLock) { newFiles = new ArrayList<String>(myManagedFilesPaths); newFiles.addAll(MavenUtil.collectPaths(files)); - newProfiles = new THashSet<String>(myExplicitProfiles); - newProfiles.addAll(profiles); + newProfiles = myExplicitProfiles.clone(); + newProfiles.getEnabledProfiles().addAll(profiles.getEnabledProfiles()); + newProfiles.getDisabledProfiles().addAll(profiles.getDisabledProfiles()); } resetManagedFilesPathsAndProfiles(newFiles, newProfiles); @@ -349,15 +353,15 @@ public class MavenProjectsTree { } } - public Collection<String> getExplicitProfiles() { + public MavenExplicitProfiles getExplicitProfiles() { synchronized (myStateLock) { - return new THashSet<String>(myExplicitProfiles); + return myExplicitProfiles.clone(); } } - public void setExplicitProfiles(Collection<String> explicitProfiles) { + public void setExplicitProfiles(MavenExplicitProfiles explicitProfiles) { synchronized (myStateLock) { - myExplicitProfiles = new THashSet<String>(explicitProfiles); + myExplicitProfiles = explicitProfiles.clone(); } fireProfilesChanged(); } @@ -366,17 +370,25 @@ public class MavenProjectsTree { Collection<String> available = getAvailableProfiles(); synchronized (myStateLock) { - Collection<String> removedProfiles = new THashSet<String>(myExplicitProfiles); - removedProfiles.removeAll(available); - myTemporarilyRemovedExplicitProfiles.addAll(removedProfiles); + updateExplicitProfiles(myExplicitProfiles.getEnabledProfiles(), myTemporarilyRemovedExplicitProfiles.getEnabledProfiles(), + available); + updateExplicitProfiles(myExplicitProfiles.getDisabledProfiles(), myTemporarilyRemovedExplicitProfiles.getDisabledProfiles(), + available); + } + } - Collection<String> restoredProfiles = new THashSet<String>(myTemporarilyRemovedExplicitProfiles); - restoredProfiles.retainAll(available); - myTemporarilyRemovedExplicitProfiles.removeAll(restoredProfiles); + private void updateExplicitProfiles(Collection<String> explicitProfiles, Collection<String> temporarilyRemovedExplicitProfiles, + Collection<String> available) { + Collection<String> removedProfiles = new THashSet<String>(explicitProfiles); + removedProfiles.removeAll(available); + temporarilyRemovedExplicitProfiles.addAll(removedProfiles); - myExplicitProfiles.removeAll(removedProfiles); - myExplicitProfiles.addAll(restoredProfiles); - } + Collection<String> restoredProfiles = new THashSet<String>(temporarilyRemovedExplicitProfiles); + restoredProfiles.retainAll(available); + temporarilyRemovedExplicitProfiles.removeAll(restoredProfiles); + + explicitProfiles.removeAll(removedProfiles); + explicitProfiles.addAll(restoredProfiles); } public Collection<String> getAvailableProfiles() { @@ -396,17 +408,26 @@ public class MavenProjectsTree { Collection<String> active = new THashSet<String>(); for (MavenProject each : getProjects()) { available.addAll(each.getProfilesIds()); - active.addAll(each.getActivatedProfilesIds()); + active.addAll(each.getActivatedProfilesIds().getEnabledProfiles()); } - Collection<String> explicitProfiles = getExplicitProfiles(); + Collection<String> enabledProfiles = getExplicitProfiles().getEnabledProfiles(); + Collection<String> disabledProfiles = getExplicitProfiles().getDisabledProfiles(); for (String each : available) { - MavenProfileKind state = MavenProfileKind.NONE; - if (explicitProfiles.contains(each)) { + MavenProfileKind state; + if (disabledProfiles.contains(each)) { + state = MavenProfileKind.NONE; + } + else if (enabledProfiles.contains(each)) { state = MavenProfileKind.EXPLICIT; } - else if (active.contains(each)) state = MavenProfileKind.IMPLICIT; + else if (active.contains(each)) { + state = MavenProfileKind.IMPLICIT; + } + else { + state = MavenProfileKind.NONE; + } result.add(Pair.create(each, state)); } return result; @@ -414,7 +435,7 @@ public class MavenProjectsTree { public void updateAll(boolean force, MavenGeneralSettings generalSettings, MavenProgressIndicator process) { List<VirtualFile> managedFiles = getExistingManagedFiles(); - Collection<String> explicitProfiles = getExplicitProfiles(); + MavenExplicitProfiles explicitProfiles = getExplicitProfiles(); MavenProjectReader projectReader = new MavenProjectReader(); update(managedFiles, true, force, explicitProfiles, projectReader, generalSettings, process); @@ -434,7 +455,7 @@ public class MavenProjectsTree { private void update(Collection<VirtualFile> files, boolean recursive, boolean force, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, MavenProjectReader projectReader, MavenGeneralSettings generalSettings, MavenProgressIndicator process) { @@ -469,7 +490,7 @@ public class MavenProjectsTree { private void doAdd(final VirtualFile f, boolean recursuve, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, UpdateContext updateContext, Stack<MavenProject> updateStack, MavenProjectReader reader, @@ -503,7 +524,7 @@ public class MavenProjectsTree { boolean isNew, boolean recursive, boolean force, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, UpdateContext updateContext, Stack<MavenProject> updateStack, MavenProjectReader reader, @@ -649,7 +670,7 @@ public class MavenProjectsTree { } private MavenProjectTimestamp calculateTimestamp(final MavenProject mavenProject, - final Collection<String> explicitProfiles, + final MavenExplicitProfiles explicitProfiles, final MavenGeneralSettings generalSettings) { AccessToken accessToken = ApplicationManager.getApplication().acquireReadActionLock(); try { @@ -712,7 +733,7 @@ public class MavenProjectsTree { private void delete(MavenProjectReader projectReader, List<VirtualFile> files, - Collection<String> explicitProfiles, + MavenExplicitProfiles explicitProfiles, MavenGeneralSettings generalSettings, MavenProgressIndicator process) { if (files.isEmpty()) return; @@ -892,7 +913,7 @@ public class MavenProjectsTree { try { final CRC32 crc = new CRC32(); - Set<String> profiles = myExplicitProfiles; + MavenExplicitProfiles profiles = myExplicitProfiles; if (profiles != null) { updateCrc(crc, profiles.hashCode()); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettings.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettings.java index 3451f0c33f2e..4b0ef285a76d 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettings.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettings.java @@ -24,10 +24,16 @@ public class MavenWorkspaceSettings { public MavenImportingSettings importingSettings = new MavenImportingSettings(); public List<String> enabledProfiles = new ArrayList<String>(); + public List<String> disabledProfiles = new ArrayList<String>(); public void setEnabledProfiles(Collection<String> profiles) { enabledProfiles.clear(); enabledProfiles.addAll(profiles); } + public void setDisabledProfiles(Collection<String> profiles) { + disabledProfiles.clear(); + disabledProfiles.addAll(profiles); + } + } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettingsComponent.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettingsComponent.java index dc1bbdb79a8e..d5e9e2d92815 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettingsComponent.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/MavenWorkspaceSettingsComponent.java @@ -18,6 +18,7 @@ package org.jetbrains.idea.maven.project; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; @State(name = "MavenImportPreferences", storages = {@Storage( file = StoragePathMacros.WORKSPACE_FILE)}) public class MavenWorkspaceSettingsComponent implements PersistentStateComponent<MavenWorkspaceSettings> { @@ -35,7 +36,9 @@ public class MavenWorkspaceSettingsComponent implements PersistentStateComponent @NotNull public MavenWorkspaceSettings getState() { - mySettings.setEnabledProfiles(MavenProjectsManager.getInstance(myProject).getExplicitProfiles()); + MavenExplicitProfiles profiles = MavenProjectsManager.getInstance(myProject).getExplicitProfiles(); + mySettings.setEnabledProfiles(profiles.getEnabledProfiles()); + mySettings.setDisabledProfiles(profiles.getDisabledProfiles()); return mySettings; } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RunBuildAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RunBuildAction.java index e52453070a0e..497f29b6a7a8 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RunBuildAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/RunBuildAction.java @@ -19,6 +19,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.DataContext; import org.jetbrains.idea.maven.execution.MavenRunConfigurationType; import org.jetbrains.idea.maven.execution.MavenRunnerParameters; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.utils.MavenDataKeys; import org.jetbrains.idea.maven.utils.actions.MavenAction; @@ -46,10 +47,12 @@ public class RunBuildAction extends MavenAction { if (!perform) return true; + MavenExplicitProfiles explicitProfiles = MavenActionUtil.getProjectsManager(context).getExplicitProfiles(); final MavenRunnerParameters params = new MavenRunnerParameters(true, project.getDirectory(), goals, - MavenActionUtil.getProjectsManager(context).getExplicitProfiles()); + explicitProfiles.getEnabledProfiles(), + explicitProfiles.getDisabledProfiles()); MavenRunConfigurationType.runConfiguration(MavenActionUtil.getProject(context), params, null); return true; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/ToggleProfileAction.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/ToggleProfileAction.java index 3e9bf7f92ddd..af0fbd091aad 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/ToggleProfileAction.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/project/actions/ToggleProfileAction.java @@ -16,15 +16,15 @@ package org.jetbrains.idea.maven.project.actions; import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; +import org.jetbrains.idea.maven.model.MavenProfileKind; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.project.ProjectBundle; import org.jetbrains.idea.maven.utils.MavenDataKeys; import org.jetbrains.idea.maven.utils.actions.MavenAction; import org.jetbrains.idea.maven.utils.actions.MavenActionUtil; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; +import java.util.Map; import java.util.Set; public class ToggleProfileAction extends MavenAction { @@ -32,47 +32,105 @@ public class ToggleProfileAction extends MavenAction { super.update(e); if (!isAvailable(e)) return; - MavenProjectsManager projectsManager = MavenActionUtil.getProjectsManager(e.getDataContext()); - List<String> profiles = e.getData(MavenDataKeys.MAVEN_PROFILES); - - e.getPresentation().setText(isActive(projectsManager, profiles) - ? ProjectBundle.message("maven.profile.deactivate") - : ProjectBundle.message("maven.profile.activate")); + MavenProfileKind targetState = getTargetState(e); + String text; + switch (targetState) { + case NONE: + text = ProjectBundle.message("maven.profile.deactivate"); + break; + case EXPLICIT: + text = ProjectBundle.message("maven.profile.activate"); + break; + case IMPLICIT: + default: + text = ProjectBundle.message("maven.profile.default"); + break; + } + e.getPresentation().setText(text); } @Override protected boolean isAvailable(AnActionEvent e) { if (!super.isAvailable(e)) return false; - List<String> selectedProfiles = e.getData(MavenDataKeys.MAVEN_PROFILES); - if (selectedProfiles == null || selectedProfiles.isEmpty()) return false; + return getTargetState(e) != null; + } + + private static MavenProfileKind getTargetState(AnActionEvent e) { + Map<String, MavenProfileKind> selectedProfiles = e.getData(MavenDataKeys.MAVEN_PROFILES); + if (selectedProfiles == null || selectedProfiles.isEmpty()) return null; - Collection<String> activeProfiles = MavenActionUtil.getProjectsManager(e.getDataContext()).getExplicitProfiles(); - int activeCount = 0; - for (String profile : selectedProfiles) { - if (activeProfiles.contains(profile)) { - activeCount++; + MavenProjectsManager projectsManager = MavenActionUtil.getProjectsManager(e.getDataContext()); + return getTargetState(projectsManager, selectedProfiles); + } + + private static MavenProfileKind getTargetState(MavenProjectsManager projectsManager, Map<String, MavenProfileKind> profiles) { + MavenExplicitProfiles explicitProfiles = projectsManager.getExplicitProfiles(); + MavenProfileKind targetState = null; + // all profiles should target to the same state + for (Map.Entry<String, MavenProfileKind> profile : profiles.entrySet()) { + MavenProfileKind profileTargetState = getTargetState(profile, explicitProfiles); + if (targetState == null) { + targetState = profileTargetState; + } + else if (!targetState.equals(profileTargetState)) { + targetState = null; + break; } } - return activeCount == 0 || activeCount == selectedProfiles.size(); + return targetState; } - private static boolean isActive(MavenProjectsManager projectsManager, List<String> profiles) { - return projectsManager.getExplicitProfiles().contains(profiles.get(0)); + private static MavenProfileKind getTargetState(Map.Entry<String, MavenProfileKind> profile, MavenExplicitProfiles explicitProfiles) { + MavenProfileKind targetState; + if (explicitProfiles.getDisabledProfiles().contains(profile.getKey())) { + // explicitly disabled -> explicitly enabled + targetState = MavenProfileKind.EXPLICIT; + } + else if (explicitProfiles.getEnabledProfiles().contains(profile.getKey())) { + // explicitly enabled -> default + targetState = MavenProfileKind.IMPLICIT; + } + else { + // default + if (MavenProfileKind.NONE.equals(profile.getValue())) { + // default inactive -> explicitly enabled + targetState = MavenProfileKind.EXPLICIT; + } + else { + // default active -> explicitly disabled + targetState = MavenProfileKind.NONE; + } + } + return targetState; } @Override public void actionPerformed(AnActionEvent e) { MavenProjectsManager manager = MavenActionUtil.getProjectsManager(e.getDataContext()); - List<String> selectedProfiles = e.getData(MavenDataKeys.MAVEN_PROFILES); + Map<String, MavenProfileKind> selectedProfiles = e.getData(MavenDataKeys.MAVEN_PROFILES); + Set<String> selectedProfileIds = selectedProfiles.keySet(); - Set<String> activeProfiles = new HashSet<String>(manager.getExplicitProfiles()); - if (isActive(manager, selectedProfiles)) { - activeProfiles.removeAll(selectedProfiles); - } - else { - activeProfiles.addAll(selectedProfiles); + MavenProfileKind targetState = getTargetState(manager, selectedProfiles); + MavenExplicitProfiles newExplicitProfiles = manager.getExplicitProfiles().clone(); + switch (targetState) { + case NONE: + // disable explicitly + newExplicitProfiles.getEnabledProfiles().removeAll(selectedProfileIds); + newExplicitProfiles.getDisabledProfiles().addAll(selectedProfileIds); + break; + case EXPLICIT: + // enable explicitly + newExplicitProfiles.getDisabledProfiles().removeAll(selectedProfileIds); + newExplicitProfiles.getEnabledProfiles().addAll(selectedProfileIds); + break; + case IMPLICIT: + default: + // reset to default state + newExplicitProfiles.getEnabledProfiles().removeAll(selectedProfileIds); + newExplicitProfiles.getDisabledProfiles().removeAll(selectedProfileIds); + break; } - manager.setExplicitProfiles(activeProfiles); + manager.setExplicitProfiles(newExplicitProfiles); } } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java index a0882e7c87fd..006f4caeac3a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenEmbedderWrapper.java @@ -93,22 +93,26 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ @NotNull public MavenServerExecutionResult resolveProject(@NotNull final VirtualFile file, - @NotNull final Collection<String> activeProfiles) throws MavenProcessCanceledException { + @NotNull final Collection<String> activeProfiles, + @NotNull final Collection<String> inactiveProfiles) + throws MavenProcessCanceledException { return perform(new RetriableCancelable<MavenServerExecutionResult>() { @Override public MavenServerExecutionResult execute() throws RemoteException, MavenServerProcessCanceledException { - return getOrCreateWrappee().resolveProject(new File(file.getPath()), activeProfiles); + return getOrCreateWrappee().resolveProject(new File(file.getPath()), activeProfiles, inactiveProfiles); } }); } @Nullable - public String evaluateEffectivePom(@NotNull final VirtualFile file, @NotNull final Collection<String> activeProfiles) - throws MavenProcessCanceledException { + public String evaluateEffectivePom(@NotNull final VirtualFile file, + @NotNull final Collection<String> activeProfiles, + @NotNull final Collection<String> inactiveProfiles) throws MavenProcessCanceledException { return perform(new RetriableCancelable<String>() { @Override public String execute() throws RemoteException, MavenServerProcessCanceledException { - return getOrCreateWrappee().evaluateEffectivePom(new File(file.getPath()), new ArrayList<String>(activeProfiles)); + return getOrCreateWrappee() + .evaluateEffectivePom(new File(file.getPath()), new ArrayList<String>(activeProfiles), new ArrayList<String>(inactiveProfiles)); } }); } @@ -165,14 +169,14 @@ public abstract class MavenEmbedderWrapper extends RemoteObjectWrapper<MavenServ @NotNull public MavenServerExecutionResult execute(@NotNull final VirtualFile file, - @NotNull final Collection<String> activeProfiles, - @NotNull final List<String> goals) throws MavenProcessCanceledException { + @NotNull final Collection<String> activeProfiles, + @NotNull final Collection<String> inactiveProfiles, + @NotNull final List<String> goals) throws MavenProcessCanceledException { return perform(new RetriableCancelable<MavenServerExecutionResult>() { @Override public MavenServerExecutionResult execute() throws RemoteException, MavenServerProcessCanceledException { return getOrCreateWrappee() - .execute(new File(file.getPath()), activeProfiles, Collections.<String>emptyList(), goals, Collections.<String>emptyList(), false, - false); + .execute(new File(file.getPath()), activeProfiles, inactiveProfiles, goals, Collections.<String>emptyList(), false, false); } }); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java index 5777e246f858..7ef16bdcfc4e 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/server/MavenServerManager.java @@ -45,6 +45,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.execution.MavenRunnerSettings; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenId; import org.jetbrains.idea.maven.model.MavenModel; import org.jetbrains.idea.maven.project.MavenConsole; @@ -409,7 +410,7 @@ public class MavenServerManager extends RemoteObjectWrapper<MavenServer> impleme public ProfileApplicationResult applyProfiles(final MavenModel model, final File basedir, - final Collection<String> explicitProfiles, + final MavenExplicitProfiles explicitProfiles, final Collection<String> alwaysOnProfiles) { return perform(new Retriable<ProfileApplicationResult>() { @Override diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java index b98fff5cd5d7..d128dac01b80 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenBeforeRunTasksProvider.java @@ -39,6 +39,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.execution.MavenEditGoalDialog; import org.jetbrains.idea.maven.execution.MavenRunner; import org.jetbrains.idea.maven.execution.MavenRunnerParameters; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenLog; @@ -162,7 +163,7 @@ public class MavenBeforeRunTasksProvider extends BeforeRunTaskProvider<MavenBefo FileDocumentManager.getInstance().saveAllDocuments(); - final Collection<String> explicitProfiles = MavenProjectsManager.getInstance(project).getExplicitProfiles(); + final MavenExplicitProfiles explicitProfiles = MavenProjectsManager.getInstance(project).getExplicitProfiles(); final MavenRunner mavenRunner = MavenRunner.getInstance(project); targetDone.down(); @@ -173,7 +174,8 @@ public class MavenBeforeRunTasksProvider extends BeforeRunTaskProvider<MavenBefo true, mavenProject.getDirectory(), ParametersListUtil.parse(task.getGoal()), - explicitProfiles); + explicitProfiles.getEnabledProfiles(), + explicitProfiles.getDisabledProfiles()); result[0] = mavenRunner.runBatch(Collections.singletonList(params), null, diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java index 7bde42d519e1..25db4aa482be 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenKeymapExtension.java @@ -27,6 +27,7 @@ import org.jetbrains.annotations.TestOnly; import org.jetbrains.idea.maven.execution.MavenRunConfigurationType; import org.jetbrains.idea.maven.execution.MavenRunnerParameters; import org.jetbrains.idea.maven.model.MavenConstants; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenPlugin; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.utils.MavenArtifactUtil; @@ -176,10 +177,12 @@ public class MavenKeymapExtension implements KeymapExtension { public void actionPerformed(AnActionEvent e) { final DataContext context = e.getDataContext(); + MavenExplicitProfiles explicitProfiles = MavenActionUtil.getProjectsManager(context).getExplicitProfiles(); MavenRunnerParameters params = new MavenRunnerParameters(true, myMavenProject.getDirectory(), Arrays.asList(myGoal), - MavenActionUtil.getProjectsManager(context).getExplicitProfiles()); + explicitProfiles.getEnabledProfiles(), + explicitProfiles.getDisabledProfiles()); MavenRunConfigurationType.runConfiguration(MavenActionUtil.getProject(context), params, null); } diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java index 3dabc5a32f25..c085e1867d10 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/tasks/MavenTasksManager.java @@ -33,6 +33,7 @@ import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.maven.execution.MavenRunner; import org.jetbrains.idea.maven.execution.MavenRunnerParameters; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; import org.jetbrains.idea.maven.utils.MavenSimpleProjectComponent; @@ -133,10 +134,12 @@ public class MavenTasksManager extends MavenSimpleProjectComponent implements Pe for (MavenCompilerTask each : tasks) { VirtualFile file = LocalFileSystem.getInstance().findFileByPath(each.getProjectPath()); if (file == null) continue; + MavenExplicitProfiles explicitProfiles = myProjectsManager.getExplicitProfiles(); parametersList.add(new MavenRunnerParameters(true, file.getParent().getPath(), Arrays.asList(each.getGoal()), - myProjectsManager.getExplicitProfiles())); + explicitProfiles.getEnabledProfiles(), + explicitProfiles.getDisabledProfiles())); } } return myRunner.runBatch(parametersList, null, null, TasksBundle.message("maven.tasks.executing"), context.getProgressIndicator()); @@ -194,4 +197,4 @@ public class MavenTasksManager extends MavenSimpleProjectComponent implements Pe public interface Listener { void compileTasksChanged(); } -}
\ No newline at end of file +} diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenDataKeys.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenDataKeys.java index 397447c44393..aff34a18217a 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenDataKeys.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/utils/MavenDataKeys.java @@ -18,16 +18,18 @@ package org.jetbrains.idea.maven.utils; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.openapi.actionSystem.DataKey; import org.jetbrains.idea.maven.model.MavenArtifact; +import org.jetbrains.idea.maven.model.MavenProfileKind; import javax.swing.*; import java.util.Collection; import java.util.List; +import java.util.Map; public class MavenDataKeys { public static final DataKey<List<String>> MAVEN_GOALS = DataKey.create("MAVEN_GOALS"); public static final DataKey<RunnerAndConfigurationSettings> RUN_CONFIGURATION = DataKey.create("MAVEN_RUN_CONFIGURATION"); - public static final DataKey<List<String>> MAVEN_PROFILES = DataKey.create("MAVEN_PROFILES"); + public static final DataKey<Map<String, MavenProfileKind>> MAVEN_PROFILES = DataKey.create("MAVEN_PROFILES"); public static final DataKey<Collection<MavenArtifact>> MAVEN_DEPENDENCIES = DataKey.create("MAVEN_DEPENDENCIES"); public static final DataKey<JTree> MAVEN_PROJECTS_TREE = DataKey.create("MAVEN_PROJECTS_TREE"); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java index 30755ff733d8..1f0190aaff48 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenModuleBuilderHelper.java @@ -194,7 +194,9 @@ public class MavenModuleBuilderHelper { } MavenRunnerParameters params = new MavenRunnerParameters( - false, workingDir.getPath(), Collections.singletonList("org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate"), null); + false, workingDir.getPath(), + Collections.singletonList("org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate"), + Collections.<String>emptyList()); MavenRunner runner = MavenRunner.getInstance(project); MavenRunnerSettings settings = runner.getState().clone(); diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectBuilder.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectBuilder.java index 53a486fb47ba..730284863e32 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectBuilder.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectBuilder.java @@ -36,6 +36,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.importing.MavenDefaultModifiableModelsProvider; import org.jetbrains.idea.maven.importing.MavenUIModifiableModelsProvider; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.model.MavenId; import org.jetbrains.idea.maven.project.*; import org.jetbrains.idea.maven.utils.*; @@ -53,7 +54,8 @@ public class MavenProjectBuilder extends ProjectImportBuilder<MavenProject> { private VirtualFile myImportRoot; private List<VirtualFile> myFiles; private List<String> myProfiles = new ArrayList<String>(); - private List<String> mySelectedProfiles = new ArrayList<String>(); + private List<String> myActivatedProfiles = new ArrayList<String>(); + private MavenExplicitProfiles mySelectedProfiles = MavenExplicitProfiles.NONE; private MavenProjectsTree myMavenProjectTree; private List<MavenProject> mySelectedProjects; @@ -109,20 +111,14 @@ public class MavenProjectBuilder extends ProjectImportBuilder<MavenProject> { settings.generalSettings.setUserSettingsFile(settingsFile.trim()); } - List<String> selectedProfiles = getSelectedProfiles(); + MavenExplicitProfiles selectedProfiles = getSelectedProfiles(); - String profilesList = System.getProperty("idea.maven.import.enabled.profiles"); - if (profilesList != null) { - Set<String> selectedProfilesSet = new LinkedHashSet<String>(selectedProfiles); - - for (String profile : StringUtil.split(profilesList, ",")) { - String trimmedProfileName = profile.trim(); - if (!trimmedProfileName.isEmpty()) { - selectedProfilesSet.add(trimmedProfileName); - } - } - - selectedProfiles = new ArrayList<String>(selectedProfilesSet); + String enabledProfilesList = System.getProperty("idea.maven.import.enabled.profiles"); + String disabledProfilesList = System.getProperty("idea.maven.import.disabled.profiles"); + if (enabledProfilesList != null || disabledProfilesList != null) { + selectedProfiles = selectedProfiles.clone(); + appendProfilesFromString(selectedProfiles.getEnabledProfiles(), enabledProfilesList); + appendProfilesFromString(selectedProfiles.getDisabledProfiles(), disabledProfilesList); } MavenProjectsManager manager = MavenProjectsManager.getInstance(project); @@ -138,9 +134,21 @@ public class MavenProjectBuilder extends ProjectImportBuilder<MavenProject> { : new MavenDefaultModifiableModelsProvider(project)); } + private void appendProfilesFromString(Collection<String> selectedProfiles, String profilesList) { + if (profilesList == null) return; + + for (String profile : StringUtil.split(profilesList, ",")) { + String trimmedProfileName = profile.trim(); + if (!trimmedProfileName.isEmpty()) { + selectedProfiles.add(trimmedProfileName); + } + } + } + public boolean setRootDirectory(@Nullable Project projectToUpdate, final String root) throws ConfigurationException { getParameters().myFiles = null; getParameters().myProfiles.clear(); + getParameters().myActivatedProfiles.clear(); getParameters().myMavenProjectTree = null; getParameters().myProjectToUpdate = projectToUpdate; // We cannot determinate project in non-EDT thread. @@ -174,7 +182,8 @@ public class MavenProjectBuilder extends ProjectImportBuilder<MavenProject> { private void collectProfiles(MavenProgressIndicator process) { process.setText(ProjectBundle.message("maven.searching.profiles")); - Set<String> uniqueProfiles = new LinkedHashSet<String>(); + Set<String> availableProfiles = new LinkedHashSet<String>(); + Set<String> activatedProfiles = new LinkedHashSet<String>(); MavenProjectReader reader = new MavenProjectReader(); MavenGeneralSettings generalSettings = getGeneralSettings(); MavenProjectReaderProjectLocator locator = new MavenProjectReaderProjectLocator() { @@ -185,21 +194,27 @@ public class MavenProjectBuilder extends ProjectImportBuilder<MavenProject> { for (VirtualFile f : getParameters().myFiles) { MavenProject project = new MavenProject(f); process.setText2(ProjectBundle.message("maven.reading.pom", f.getPath())); - project.read(generalSettings, Collections.<String>emptyList(), reader, locator); - uniqueProfiles.addAll(project.getProfilesIds()); + project.read(generalSettings, MavenExplicitProfiles.NONE, reader, locator); + availableProfiles.addAll(project.getProfilesIds()); + activatedProfiles.addAll(project.getActivatedProfilesIds().getEnabledProfiles()); } - getParameters().myProfiles = new ArrayList<String>(uniqueProfiles); + getParameters().myProfiles = new ArrayList<String>(availableProfiles); + getParameters().myActivatedProfiles = new ArrayList<String>(activatedProfiles); } public List<String> getProfiles() { return getParameters().myProfiles; } - public List<String> getSelectedProfiles() { + public List<String> getActivatedProfiles() { + return getParameters().myActivatedProfiles; + } + + public MavenExplicitProfiles getSelectedProfiles() { return getParameters().mySelectedProfiles; } - public boolean setSelectedProfiles(List<String> profiles) { + public boolean setSelectedProfiles(MavenExplicitProfiles profiles) { getParameters().myMavenProjectTree = null; getParameters().mySelectedProfiles = profiles; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectOpenProcessor.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectOpenProcessor.java index 0ba88d7330a1..db9b5562e073 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectOpenProcessor.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/MavenProjectOpenProcessor.java @@ -26,9 +26,9 @@ import com.intellij.projectImport.ProjectOpenProcessorBase; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.model.MavenConstants; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenProject; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -45,7 +45,7 @@ public class MavenProjectOpenProcessor extends ProjectOpenProcessorBase<MavenPro public boolean doQuickImport(VirtualFile file, WizardContext wizardContext) { getBuilder().setFiles(Arrays.asList(file)); - if (!getBuilder().setSelectedProfiles(new ArrayList<String>())) return false; + if (!getBuilder().setSelectedProfiles(MavenExplicitProfiles.NONE)) return false; List<MavenProject> projects = getBuilder().getList(); if (projects.size() != 1) return false; diff --git a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectProfilesStep.java b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectProfilesStep.java index 4f0238c2694b..3fc7fb47b202 100644 --- a/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectProfilesStep.java +++ b/plugins/maven/src/main/java/org/jetbrains/idea/maven/wizards/SelectProfilesStep.java @@ -15,14 +15,21 @@ */ package org.jetbrains.idea.maven.wizards; -import com.intellij.ide.util.ElementsChooser; +import com.intellij.ide.util.MultiStateElementsChooser; import com.intellij.ide.util.projectWizard.WizardContext; import com.intellij.openapi.options.ConfigurationException; import com.intellij.projectImport.ProjectImportWizardStep; +import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; +import org.jetbrains.idea.maven.model.MavenProfileKind; import javax.swing.*; -import java.util.ArrayList; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.util.*; import java.util.List; /** @@ -30,7 +37,8 @@ import java.util.List; */ public class SelectProfilesStep extends ProjectImportWizardStep { private JPanel panel; - private ElementsChooser<String> profileChooser; + private MultiStateElementsChooser<String, MavenProfileKind> profileChooser; + private MavenProfileKindMarkStateDescriptor myMarkStateDescriptor; public SelectProfilesStep(final WizardContext context) { super(context); @@ -52,7 +60,8 @@ public class SelectProfilesStep extends ProjectImportWizardStep { } public void createUIComponents() { - profileChooser = new ElementsChooser<String>(true); + myMarkStateDescriptor = new MavenProfileKindMarkStateDescriptor(); + profileChooser = new MultiStateElementsChooser<String, MavenProfileKind>(true, myMarkStateDescriptor); } public JComponent getComponent() { @@ -61,15 +70,39 @@ public class SelectProfilesStep extends ProjectImportWizardStep { public void updateStep() { List<String> allProfiles = getBuilder().getProfiles(); - List<String> markedProfiles = new ArrayList<String>(getBuilder().getSelectedProfiles()); - markedProfiles.retainAll(allProfiles); // mark only existing profiles + List<String> activatedProfiles = getBuilder().getActivatedProfiles(); + MavenExplicitProfiles selectedProfiles = getBuilder().getSelectedProfiles(); + List<String> enabledProfiles = new ArrayList<String>(selectedProfiles.getEnabledProfiles()); + List<String> disabledProfiles = new ArrayList<String>(selectedProfiles.getDisabledProfiles()); + enabledProfiles.retainAll(allProfiles); // mark only existing profiles + disabledProfiles.retainAll(allProfiles); // mark only existing profiles - profileChooser.setElements(allProfiles, false); - profileChooser.markElements(markedProfiles); + myMarkStateDescriptor.setActivatedProfiles(activatedProfiles); + profileChooser.setElements(allProfiles, null); + profileChooser.markElements(enabledProfiles, MavenProfileKind.EXPLICIT); + profileChooser.markElements(disabledProfiles, MavenProfileKind.NONE); } public boolean validate() throws ConfigurationException { - return getBuilder().setSelectedProfiles(profileChooser.getMarkedElements()); + Collection<String> activatedProfiles = myMarkStateDescriptor.getActivatedProfiles(); + MavenExplicitProfiles newSelectedProfiles = MavenExplicitProfiles.NONE.clone(); + for (Map.Entry<String, MavenProfileKind> entry : profileChooser.getElementMarkStates().entrySet()) { + String profile = entry.getKey(); + MavenProfileKind profileKind = entry.getValue(); + switch (profileKind) { + case NONE: + if (activatedProfiles.contains(profile)) { + newSelectedProfiles.getDisabledProfiles().add(profile); + } + break; + case EXPLICIT: + newSelectedProfiles.getEnabledProfiles().add(profile); + break; + case IMPLICIT: + break; + } + } + return getBuilder().setSelectedProfiles(newSelectedProfiles); } public void updateDataModel() { @@ -79,4 +112,100 @@ public class SelectProfilesStep extends ProjectImportWizardStep { public String getHelpId() { return "reference.dialogs.new.project.import.maven.page2"; } + + private static class MavenProfileKindMarkStateDescriptor + implements MultiStateElementsChooser.MarkStateDescriptor<String, MavenProfileKind> { + private Collection<String> myActivatedProfiles = Collections.emptySet(); + + public Collection<String> getActivatedProfiles() { + return myActivatedProfiles; + } + + public void setActivatedProfiles(Collection<String> activatedProfiles) { + myActivatedProfiles = new THashSet<String>(activatedProfiles); + } + + @NotNull + @Override + public MavenProfileKind getDefaultState(@NotNull String element) { + return myActivatedProfiles.contains(element) ? MavenProfileKind.IMPLICIT : MavenProfileKind.NONE; + } + + @NotNull + @Override + public MavenProfileKind getNextState(@NotNull String element, @NotNull MavenProfileKind state) { + MavenProfileKind nextState; + switch (state) { + case NONE: + nextState = MavenProfileKind.EXPLICIT; + break; + case EXPLICIT: + nextState = getDefaultState(element); + break; + case IMPLICIT: + default: + nextState = MavenProfileKind.NONE; + break; + } + return nextState; + } + + @Nullable + @Override + public MavenProfileKind getNextState(@NotNull Map<String, MavenProfileKind> elementsWithStates) { + MavenProfileKind nextState = null; + for (Map.Entry<String, MavenProfileKind> entry : elementsWithStates.entrySet()) { + MavenProfileKind nextElementState = getNextState(entry.getKey(), entry.getValue()); + if (nextState == null) { + nextState = nextElementState; + } + else if (!nextState.equals(nextElementState)) { + nextState = null; + break; + } + } + return nextState; + } + + @Override + public boolean isMarked(@NotNull MavenProfileKind state) { + return state != MavenProfileKind.NONE; + } + + @Nullable + @Override + public MavenProfileKind getMarkState(@Nullable Object value) { + return value instanceof MavenProfileKind ? (MavenProfileKind)value : null; + } + + @Nullable + @Override + public TableCellRenderer getMarkRenderer() { + return new CheckboxTableCellRenderer(); + } + } + + private static class CheckboxTableCellRenderer extends JCheckBox implements TableCellRenderer { + public CheckboxTableCellRenderer() { + setHorizontalAlignment(SwingConstants.CENTER); + setBorder(null); + } + + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + if (isSelected) { + setForeground(table.getSelectionForeground()); + super.setBackground(table.getSelectionBackground()); + } + else { + setForeground(table.getForeground()); + setBackground(table.getBackground()); + } + + MavenProfileKind state = (MavenProfileKind)value; + setSelected(state != MavenProfileKind.NONE); + setEnabled(state != MavenProfileKind.IMPLICIT); + + return this; + } + } } diff --git a/plugins/maven/src/main/resources/ProjectBundle.properties b/plugins/maven/src/main/resources/ProjectBundle.properties index 926720c4d82e..6ceac4f4fcee 100644 --- a/plugins/maven/src/main/resources/ProjectBundle.properties +++ b/plugins/maven/src/main/resources/ProjectBundle.properties @@ -66,6 +66,7 @@ maven.ingored.no.file=No Maven files maven.ignore.edit=Edit Ignored Files... maven.profile.activate=Activate maven.profile.deactivate=Deactivate +maven.profile.default=Use default maven.project.problem.recursiveInheritance=Recursive inheritance found maven.project.problem.selfInheritance=Self-inheritance found diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java index 6cc0966180b0..79639e96c8b8 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/MavenImportingTestCase.java @@ -42,6 +42,7 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.maven.execution.*; import org.jetbrains.idea.maven.model.MavenArtifact; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenArtifactDownloader; import org.jetbrains.idea.maven.project.MavenProject; import org.jetbrains.idea.maven.project.MavenProjectsManager; @@ -402,7 +403,7 @@ public abstract class MavenImportingTestCase extends MavenTestCase { } protected void readProjects(List<VirtualFile> files, String... profiles) { - myProjectsManager.resetManagedFilesAndProfilesInTests(files, Arrays.asList(profiles)); + myProjectsManager.resetManagedFilesAndProfilesInTests(files, new MavenExplicitProfiles(Arrays.asList(profiles))); waitForReadingCompletion(); } @@ -502,7 +503,7 @@ public abstract class MavenImportingTestCase extends MavenTestCase { protected void executeGoal(String relativePath, String goal) { VirtualFile dir = myProjectRoot.findFileByRelativePath(relativePath); - MavenRunnerParameters rp = new MavenRunnerParameters(true, dir.getPath(), Arrays.asList(goal), null); + MavenRunnerParameters rp = new MavenRunnerParameters(true, dir.getPath(), Arrays.asList(goal), Collections.<String>emptyList()); MavenRunnerSettings rs = new MavenRunnerSettings(); MavenExecutor e = new MavenExternalExecutor(myProject, rp, getMavenGeneralSettings(), rs, new SoutMavenConsole()); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java index 24b6e5f4e39c..38fc7e27d99a 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/compiler/ResourceFilteringTest.java @@ -19,6 +19,7 @@ import com.intellij.openapi.fileTypes.FileTypeManager; import com.intellij.openapi.fileTypes.FileTypes; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import java.util.Arrays; @@ -658,7 +659,7 @@ public class ResourceFilteringTest extends MavenCompilingTestCase { compileModules("project"); assertResult("target/classes/file.properties", "value=val1"); - myProjectsManager.setExplicitProfiles(Arrays.asList("two")); + myProjectsManager.setExplicitProfiles(new MavenExplicitProfiles(Arrays.asList("two"))); scheduleResolveAll(); resolveDependenciesAndImport(); compileModules("project"); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenPropertyCompletionAndResolutionTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenPropertyCompletionAndResolutionTest.java index dc3fb091287b..f9c648cacd5b 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenPropertyCompletionAndResolutionTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/dom/MavenPropertyCompletionAndResolutionTest.java @@ -27,6 +27,7 @@ import com.intellij.psi.xml.XmlTag; import org.jetbrains.idea.maven.dom.model.MavenDomProfiles; import org.jetbrains.idea.maven.dom.model.MavenDomProfilesModel; import org.jetbrains.idea.maven.dom.model.MavenDomSettingsModel; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.vfs.MavenPropertiesVirtualFileSystem; import java.util.Arrays; @@ -933,7 +934,7 @@ public class MavenPropertyCompletionAndResolutionTest extends MavenDomTestCase { assertContain(variants, "project.groupId"); assertDoNotContain(variants, "groupId"); } - + public void testCompletingAfterOpenBraceAndSomeTextWithDot() throws Exception { createProjectPom("<groupId>test</groupId>" + "<artifactId>project</artifactId>" + @@ -955,7 +956,7 @@ public class MavenPropertyCompletionAndResolutionTest extends MavenDomTestCase { } private void readWithProfiles(String... profiles) { - myProjectsManager.setExplicitProfiles(Arrays.asList(profiles)); + myProjectsManager.setExplicitProfiles(new MavenExplicitProfiles(Arrays.asList(profiles))); waitForReadingCompletion(); } } diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenExecutionTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenExecutionTest.java index 4a0f5e22cc45..f8c019c5b6be 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenExecutionTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/execution/MavenExecutionTest.java @@ -30,6 +30,7 @@ import org.jetbrains.idea.maven.MavenImportingTestCase; import javax.swing.*; import java.io.File; import java.util.Arrays; +import java.util.Collections; @SuppressWarnings({"ConstantConditions"}) public class MavenExecutionTest extends MavenImportingTestCase { @@ -59,7 +60,7 @@ public class MavenExecutionTest extends MavenImportingTestCase { assertFalse(new File(getProjectPath(), "target").exists()); - execute(new MavenRunnerParameters(true, getProjectPath(), Arrays.asList("compile"), null)); + execute(new MavenRunnerParameters(true, getProjectPath(), Arrays.asList("compile"), Collections.<String>emptyList())); assertTrue(new File(getProjectPath(), "target").exists()); } @@ -84,7 +85,7 @@ public class MavenExecutionTest extends MavenImportingTestCase { assertModules("project"); assertExcludes("project", "target"); - MavenRunnerParameters params = new MavenRunnerParameters(true, getProjectPath(), Arrays.asList("compile"), null); + MavenRunnerParameters params = new MavenRunnerParameters(true, getProjectPath(), Arrays.asList("compile"), Collections.<String>emptyList()); execute(params); SwingUtilities.invokeAndWait(new Runnable() { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenPerformanceTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenPerformanceTest.java index e98fe82ec4b8..008fc9c88076 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenPerformanceTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/importing/MavenPerformanceTest.java @@ -19,6 +19,7 @@ import com.intellij.idea.Bombed; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.maven.MavenImportingTestCase; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.project.MavenProject; import java.util.Calendar; @@ -34,7 +35,7 @@ public abstract class MavenPerformanceTest extends MavenImportingTestCase { super.setUp(); VirtualFile file = LocalFileSystem.getInstance().findFileByPath("C:\\projects\\mvn\\_projects\\geronimo\\pom.xml"); initProjectsManager(false); - myProjectsManager.resetManagedFilesAndProfilesInTests(Collections.singletonList(file), Collections.<String>emptyList()); + myProjectsManager.resetManagedFilesAndProfilesInTests(Collections.singletonList(file), MavenExplicitProfiles.NONE); } public void testReading() throws Exception { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorTest.java index 86a80e0b98e6..a04fe5bd94d5 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/navigator/MavenProjectsNavigatorTest.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.maven.navigator; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.maven.MavenImportingTestCase; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import java.util.Arrays; import java.util.Collections; @@ -50,7 +51,7 @@ public class MavenProjectsNavigatorTest extends MavenImportingTestCase { createModulePom("m", "<groupId>test</groupId>" + "<artifactId>m</artifactId>" + "<version>1</version>"); - myProjectsManager.resetManagedFilesAndProfilesInTests(Collections.singletonList(myProjectPom), Collections.<String>emptyList()); + myProjectsManager.resetManagedFilesAndProfilesInTests(Collections.singletonList(myProjectPom), MavenExplicitProfiles.NONE); waitForReadingCompletion(); myProjectsManager.fireActivatedInTests(); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenFoldersImporterTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenFoldersImporterTest.java index e6e946e71c15..cea4ea2232e9 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenFoldersImporterTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenFoldersImporterTest.java @@ -18,6 +18,8 @@ package org.jetbrains.idea.maven.project; import com.intellij.ProjectTopics; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.roots.*; +import com.intellij.openapi.util.registry.Registry; +import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; import org.jetbrains.idea.maven.MavenImportingTestCase; @@ -49,6 +51,23 @@ public class MavenFoldersImporterTest extends MavenImportingTestCase { assertNull(myProjectRoot.findChild("target")); } + public void testIgnoreTargetFolder() throws Exception { + importProject("<groupId>test</groupId>" + + "<artifactId>project</artifactId>" + + "<version>1</version>"); + + new File(myProjectRoot.getPath(), "target/classes").mkdirs(); + updateProjectFolders(); + + assertExcludes("project", "target"); + myProjectRoot.refresh(false, true); + VirtualFile target = myProjectRoot.findChild("target"); + assertNotNull(target); + if (!Registry.is("ide.hide.excluded.files")) { + assertTrue(ChangeListManager.getInstance(myProject).isIgnoredFile(target)); + } + } + public void testUpdatingFoldersForAllTheProjects() throws Exception { createProjectPom("<groupId>test</groupId>" + "<artifactId>project</artifactId>" + diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.java index 770196b390b9..8fc251ac3791 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectReaderTest.java @@ -1586,7 +1586,7 @@ public class MavenProjectReaderTest extends MavenTestCase { String... profiles) { MavenProjectReaderResult result = new MavenProjectReader().readProject(getMavenGeneralSettings(), file, - Arrays.asList(profiles), + new MavenExplicitProfiles(Arrays.asList(profiles)), locator); return result; } @@ -1629,7 +1629,7 @@ public class MavenProjectReaderTest extends MavenTestCase { private void assertActiveProfiles(List<String> explicitProfiles, String... expected) { MavenProjectReaderResult result = readProject(myProjectPom, new NullProjectLocator(), ArrayUtil.toStringArray(explicitProfiles)); - assertUnorderedElementsAreEqual(result.activatedProfiles, expected); + assertUnorderedElementsAreEqual(result.activatedProfiles.getEnabledProfiles(), expected); } private static class NullProjectLocator implements MavenProjectReaderProjectLocator { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsManagerTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsManagerTest.java index 6c9bc1c4d08f..dc7f5490f272 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsManagerTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsManagerTest.java @@ -29,6 +29,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.FileContentUtil; import org.jetbrains.idea.maven.MavenImportingTestCase; import org.jetbrains.idea.maven.importing.MavenRootModelAdapter; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; import java.io.File; @@ -686,7 +687,7 @@ public class MavenProjectsManagerTest extends MavenImportingTestCase { "<version>1</version>"); importProjects(p1, p2); - myProjectsManager.setExplicitProfiles(Arrays.asList("one", "two")); + myProjectsManager.setExplicitProfiles(new MavenExplicitProfiles(Arrays.asList("one", "two"))); myProjectsManager.setIgnoredFilesPaths(Arrays.asList(p1.getPath())); myProjectsManager.setIgnoredFilesPatterns(Arrays.asList("*.xxx")); @@ -707,7 +708,7 @@ public class MavenProjectsManagerTest extends MavenImportingTestCase { assertUnorderedPathsAreEqual(myProjectsManager.getProjectsTreeForTests().getManagedFilesPaths(), Arrays.asList(p1.getPath(), p3.getPath())); - assertUnorderedElementsAreEqual(myProjectsManager.getExplicitProfiles(), "three"); + assertUnorderedElementsAreEqual(myProjectsManager.getExplicitProfiles().getEnabledProfiles(), "three"); assertUnorderedPathsAreEqual(myProjectsManager.getIgnoredFilesPaths(), Arrays.asList(p1.getPath())); assertUnorderedElementsAreEqual(myProjectsManager.getIgnoredFilesPatterns(), "*.zzz"); diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeReadingTest.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeReadingTest.java index 842b6099b721..c3a322c49c0a 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeReadingTest.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeReadingTest.java @@ -22,6 +22,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.testFramework.PlatformTestUtil; import com.intellij.util.Function; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.server.NativeMavenProjectHolder; import org.jetbrains.idea.maven.utils.MavenUtil; @@ -1539,7 +1540,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { MyLoggingListener l = new MyLoggingListener(); myTree.addListener(l); - myTree.addManagedFilesWithProfiles(Collections.singletonList(myProjectPom), Collections.<String>emptyList()); + myTree.addManagedFilesWithProfiles(Collections.singletonList(myProjectPom), MavenExplicitProfiles.NONE); myTree.updateAll(false, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS); assertEquals("updated: parent m1 m2 deleted: <none> ", l.log); @@ -2022,7 +2023,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { myProjectPom); MavenProject project = myTree.findProject(myProjectPom); - assertUnorderedElementsAreEqual(project.getActivatedProfilesIds(), + assertUnorderedElementsAreEqual(project.getActivatedProfilesIds().getEnabledProfiles(), "projectProfileXml", "projectProfile", "parent1Profile", @@ -2044,7 +2045,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { embeddersManager.releaseInTests(); } - assertUnorderedElementsAreEqual(project.getActivatedProfilesIds(), + assertUnorderedElementsAreEqual(project.getActivatedProfilesIds().getEnabledProfiles(), "projectProfileXml", "projectProfile", "parent1Profile", @@ -2069,24 +2070,24 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { "</profile>"); updateAll(Arrays.asList("one", "two"), myProjectPom); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "one", "two"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "one", "two"); deleteProfilesXml(); update(myProjectPom); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "one"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "one"); createProjectPom("<groupId>test</groupId>" + "<artifactId>project</artifactId>" + "<version>1</version>"); update(myProjectPom); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles()); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles()); createProfilesXml("<profile>" + " <id>two</id>" + "</profile>"); update(myProjectPom); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "two"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "two"); createProjectPom("<groupId>test</groupId>" + "<artifactId>project</artifactId>" + @@ -2097,7 +2098,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { " </profile>" + "</profiles>"); update(myProjectPom); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "one", "two"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "one", "two"); } public void testDeletingAndRestoringActiveProfilesWhenProjectDeletes() throws Exception { @@ -2128,7 +2129,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { "</profiles>"); updateAll(Arrays.asList("one", "two"), myProjectPom); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "one", "two"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "one", "two"); final VirtualFile finalM = m; new WriteCommandAction.Simple(myProject) { @@ -2139,7 +2140,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { } }.execute().throwException(); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "one"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "one"); m = createModulePom("m", "<groupId>test</groupId>" + @@ -2152,7 +2153,7 @@ public class MavenProjectsTreeReadingTest extends MavenProjectsTreeTestCase { " </profile>" + "</profiles>"); update(m); - assertUnorderedElementsAreEqual(myTree.getExplicitProfiles(), "one", "two"); + assertUnorderedElementsAreEqual(myTree.getExplicitProfiles().getEnabledProfiles(), "one", "two"); } public void testFindRootWithMultiLevelAggregator() throws Exception { diff --git a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeTestCase.java b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeTestCase.java index 3688a2df46dd..8d73c5f53bb1 100644 --- a/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeTestCase.java +++ b/plugins/maven/src/test/java/org/jetbrains/idea/maven/project/MavenProjectsTreeTestCase.java @@ -17,6 +17,7 @@ package org.jetbrains.idea.maven.project; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.maven.MavenImportingTestCase; +import org.jetbrains.idea.maven.model.MavenExplicitProfiles; import org.jetbrains.idea.maven.utils.MavenProcessCanceledException; import java.io.IOException; @@ -33,7 +34,7 @@ public abstract class MavenProjectsTreeTestCase extends MavenImportingTestCase { } protected void updateAll(List<String> profiles, VirtualFile... files) throws MavenProcessCanceledException { - myTree.resetManagedFilesAndProfiles(asList(files), profiles); + myTree.resetManagedFilesAndProfiles(asList(files), new MavenExplicitProfiles(profiles)); myTree.updateAll(false, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS); } @@ -50,4 +51,4 @@ public abstract class MavenProjectsTreeTestCase extends MavenImportingTestCase { each.setBinaryContent(each.contentsToByteArray()); } } -}
\ No newline at end of file +} diff --git a/plugins/properties/resources/icons/xmlProperties.png b/plugins/properties/properties-psi-api/resources/icons/xmlProperties.png Binary files differindex a9958c7311ad..a9958c7311ad 100644 --- a/plugins/properties/resources/icons/xmlProperties.png +++ b/plugins/properties/properties-psi-api/resources/icons/xmlProperties.png diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java index b29fc4f78141..8f5084b87391 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/PropertiesImplUtil.java @@ -115,21 +115,18 @@ public class PropertiesImplUtil extends PropertiesUtil { @Nullable public static ResourceBundle createByUrl(final @NotNull String url, final @NotNull Project project) { - if (!url.startsWith(ResourceBundleImpl.RESOURCE_BUNDLE_PREFIX)) return null; - - final String defaultPropertiesUrl = url.substring(ResourceBundleImpl.RESOURCE_BUNDLE_PREFIX.length()); - final int idx = defaultPropertiesUrl.lastIndexOf('/'); + final int idx = url.lastIndexOf('/'); if (idx == -1) return null; - final String baseDirectoryName = defaultPropertiesUrl.substring(0, idx); - final String baseName = defaultPropertiesUrl.substring(idx + 1); + final String baseDirectoryName = url.substring(0, idx); + final String baseName = url.substring(idx + 1); final VirtualFile baseDirectoryVirtualFile = VirtualFileManager.getInstance().findFileByUrl(baseDirectoryName); if (baseDirectoryVirtualFile == null) { return null; } - final PsiFile baseDirectory = PsiManager.getInstance(project).findFile(baseDirectoryVirtualFile); - if (baseDirectory == null || !(baseDirectory instanceof PsiDirectory)) { + final PsiDirectory baseDirectory = PsiManager.getInstance(project).findDirectory(baseDirectoryVirtualFile); + if (baseDirectory == null) { return null; } - return getResourceBundle(baseName, (PsiDirectory)baseDirectory); + return getResourceBundle(baseName, baseDirectory); } } diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java index d257824166e9..ca5c8aa39a36 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/ResourceBundleImpl.java @@ -23,16 +23,13 @@ import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.util.SmartList; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import java.util.List; public class ResourceBundleImpl extends ResourceBundle { - @NonNls public static final String RESOURCE_BUNDLE_PREFIX = "resourceBundle:"; @NotNull private final PropertiesFile myDefaultPropertiesFile; public ResourceBundleImpl(@NotNull final PropertiesFile defaultPropertiesFile) { @@ -106,6 +103,6 @@ public class ResourceBundleImpl extends ResourceBundle { } public String getUrl() { - return RESOURCE_BUNDLE_PREFIX + getBaseDirectory() + "/" + getBaseName(); + return getBaseDirectory() + "/" + getBaseName(); } }
\ No newline at end of file diff --git a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java index cb60de04bc4f..398b9ae1f8e4 100644 --- a/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java +++ b/plugins/properties/properties-psi-impl/src/com/intellij/lang/properties/structureView/PropertiesSeparatorManager.java @@ -23,11 +23,13 @@ import com.intellij.lang.properties.*; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.components.*; import com.intellij.openapi.project.Project; -import gnu.trove.THashMap; +import com.intellij.util.containers.HashMap; +import com.intellij.util.containers.SoftFactoryMap; +import com.intellij.util.xmlb.annotations.MapAnnotation; +import com.intellij.util.xmlb.annotations.Property; +import com.intellij.util.xmlb.annotations.Transient; import gnu.trove.TIntLongHashMap; import gnu.trove.TIntProcedure; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,17 +43,22 @@ import java.util.Map; file = StoragePathMacros.PROJECT_FILE )} ) -public class PropertiesSeparatorManager implements PersistentStateComponent<Element> { - @NonNls private static final String FILE_ELEMENT = "file"; - @NonNls private static final String URL_ELEMENT = "url"; - @NonNls private static final String SEPARATOR_ATTR = "separator"; +public class PropertiesSeparatorManager implements PersistentStateComponent<PropertiesSeparatorManager.PropertiesSeparatorManagerState> { private final Project myProject; public static PropertiesSeparatorManager getInstance(final Project project) { return ServiceManager.getService(project, PropertiesSeparatorManager.class); } - private final Map<String, String> mySeparators = new THashMap<String, String>(); + private PropertiesSeparatorManagerState myUserDefinedSeparators = new PropertiesSeparatorManagerState(); + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private final SoftFactoryMap<ResourceBundleImpl, String> myGuessedSeparators = new SoftFactoryMap<ResourceBundleImpl, String>() { + @Nullable + @Override + protected String create(ResourceBundleImpl resourceBundle) { + return guessSeparator(resourceBundle); + } + }; public PropertiesSeparatorManager(final Project project) { myProject = project; @@ -62,12 +69,9 @@ public class PropertiesSeparatorManager implements PersistentStateComponent<Elem if (!(resourceBundle instanceof ResourceBundleImpl)) { return "."; } - String separator = mySeparators.get(((ResourceBundleImpl)resourceBundle).getUrl()); - if (separator == null) { - separator = guessSeparator((ResourceBundleImpl)resourceBundle); - setSeparator(resourceBundle, separator); - } - return separator; + final ResourceBundleImpl resourceBundleImpl = (ResourceBundleImpl)resourceBundle; + String separator = myUserDefinedSeparators.getSeparators().get(resourceBundleImpl.getUrl()); + return separator == null ? myGuessedSeparators.get(resourceBundleImpl) : separator; } //returns most probable separator in properties files @@ -108,23 +112,68 @@ public class PropertiesSeparatorManager implements PersistentStateComponent<Elem public void setSeparator(ResourceBundle resourceBundle, String separator) { if (resourceBundle instanceof ResourceBundleImpl) { - mySeparators.put(((ResourceBundleImpl)resourceBundle).getUrl(), separator); + myUserDefinedSeparators.getSeparators().put(((ResourceBundleImpl)resourceBundle).getUrl(), separator); } } - public void loadState(final Element element) { - List<Element> files = element.getChildren(FILE_ELEMENT); - for (Element fileElement : files) { - String url = fileElement.getAttributeValue(URL_ELEMENT, ""); - String separator = fileElement.getAttributeValue(SEPARATOR_ATTR,""); - separator = decodeSeparator(separator); - if (separator == null) { - continue; + public void loadState(final PropertiesSeparatorManagerState state) { + myUserDefinedSeparators = state.decode(myProject); + } + + @Nullable + @Override + public PropertiesSeparatorManagerState getState() { + return myUserDefinedSeparators.isEmpty() ? null : myUserDefinedSeparators.encode(); + } + + public static class PropertiesSeparatorManagerState { + @Property(surroundWithTag = false) + @MapAnnotation(surroundWithTag = false, + surroundKeyWithTag = false, + surroundValueWithTag = false, + keyAttributeName = "url", + valueAttributeName = "separator", + entryTagName = "file") + public Map<String, String> mySeparators = new HashMap<String, String>(); + + public Map<String, String> getSeparators() { + return mySeparators; + } + + public boolean isEmpty() { + return mySeparators.isEmpty(); + } + + public PropertiesSeparatorManagerState encode() { + PropertiesSeparatorManagerState encodedState = new PropertiesSeparatorManagerState(); + for (final Map.Entry<String, String> entry : mySeparators.entrySet()) { + String separator = entry.getValue(); + StringBuilder encoded = new StringBuilder(separator.length()); + for (int i=0;i<separator.length();i++) { + char c = separator.charAt(i); + encoded.append("\\u"); + encoded.append(String.format("%04x", (int) c)); + } + encodedState.getSeparators().put(entry.getKey(), encoded.toString()); } - ResourceBundle resourceBundle = PropertiesImplUtil.createByUrl(url, myProject); - if (resourceBundle != null) { - mySeparators.put(url, separator); + return encodedState; + } + + public PropertiesSeparatorManagerState decode(final Project project) { + PropertiesSeparatorManagerState decoded = new PropertiesSeparatorManagerState(); + for (final Map.Entry<String, String> entry : mySeparators.entrySet()) { + String separator = entry.getValue(); + separator = decodeSeparator(separator); + if (separator == null) { + continue; + } + final String url = entry.getKey(); + ResourceBundle resourceBundle = PropertiesImplUtil.createByUrl(url, project); + if (resourceBundle != null) { + decoded.getSeparators().put(url, separator); + } } + return decoded; } } @@ -140,42 +189,10 @@ public class PropertiesSeparatorManager implements PersistentStateComponent<Elem if (!encodedCharacter.startsWith("\\u")) { return null; } - int d1 = Character.digit(encodedCharacter.charAt(2), 16); - int d2 = Character.digit(encodedCharacter.charAt(3), 16); - int d3 = Character.digit(encodedCharacter.charAt(4), 16); - int d4 = Character.digit(encodedCharacter.charAt(5), 16); - if (d1 == -1 || d2 == -1 || d3 == -1 || d4 == -1) { - return null; - } - int b1 = (d1 << 12) & 0xF000; - int b2 = (d2 << 8) & 0x0F00; - int b3 = (d3 << 4) & 0x00F0; - int b4 = (d4 << 0) & 0x000F; - char code = (char) (b1 | b2 | b3 | b4); + char code = (char) Integer.parseInt(encodedCharacter.substring(2), 16); result.append(code); pos += 6; } return result.toString(); } - - public Element getState() { - Element element = new Element("PropertiesSeparatorManager"); - for (final String url: mySeparators.keySet()) { - String separator = mySeparators.get(url); - StringBuilder encoded = new StringBuilder(separator.length()); - for (int i=0;i<separator.length();i++) { - char c = separator.charAt(i); - encoded.append("\\u"); - encoded.append(Character.forDigit(c >> 12, 16)); - encoded.append(Character.forDigit((c >> 8) & 0xf, 16)); - encoded.append(Character.forDigit((c >> 4) & 0xf, 16)); - encoded.append(Character.forDigit(c & 0xf, 16)); - } - Element fileElement = new Element(FILE_ELEMENT); - fileElement.setAttribute(URL_ELEMENT, url); - fileElement.setAttribute(SEPARATOR_ATTR, encoded.toString()); - element.addContent(fileElement); - } - return element; - } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java index d0eafb77bc4b..062666fbd402 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/NestedCopiesBuilder.java @@ -86,6 +86,10 @@ public class NestedCopiesBuilder implements StatusReceiver { } } + @Override + public void finish() { + } + public Set<NestedCopyInfo> getCopies() { return mySet; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java index ac165c48f5c3..f6515de0ebf1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusReceiver.java @@ -29,4 +29,5 @@ public interface StatusReceiver extends EventListener { void processUnversioned(final VirtualFile vFile); void processCopyRoot(VirtualFile file, SVNURL url, WorkingCopyFormat format, SVNURL rootURL); void bewareRoot(VirtualFile vf, SVNURL url); + void finish(); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java index 367ae1bc4619..690eb1e76ee3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/StatusWalkerPartner.java @@ -15,12 +15,11 @@ */ package org.jetbrains.idea.svn; -import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressIndicator; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; @@ -34,14 +33,14 @@ import org.tmatesoft.svn.core.wc.ISVNStatusFileProvider; public class StatusWalkerPartner { private final SvnVcs myVcs; private final ChangeListManager myClManager; - private final FileIndexFacade myExcludedFileIndex; + private final ProjectLevelVcsManager myVcsManager; private final ProgressIndicator myIndicator; private ISVNStatusFileProvider myFileProvider; public StatusWalkerPartner(final SvnVcs vcs, final ProgressIndicator pi) { myVcs = vcs; myClManager = ChangeListManager.getInstance(myVcs.getProject()); - myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(myVcs.getProject(), FileIndexFacade.class); + myVcsManager = ProjectLevelVcsManager.getInstance(myVcs.getProject()); myIndicator = pi; } @@ -75,12 +74,12 @@ public class StatusWalkerPartner { } } - public boolean isExcluded(final VirtualFile vFile) { + public boolean isIgnoredByVcs(final VirtualFile vFile) { return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { if (myVcs.getProject().isDisposed()) throw new ProcessCanceledException(); - return myExcludedFileIndex.isExcludedFile(vFile); + return myVcsManager.isIgnored(vFile); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java index 073826f6b035..41461ed623c6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProvider.java @@ -95,6 +95,8 @@ public class SvnChangeProvider implements ChangeProvider { walker.go(item.getDir(), Depth.IMMEDIATES); } + statusReceiver.getMulticaster().finish(); + processCopiedAndDeleted(context, dirtyScope); processUnsaved(dirtyScope, addGate, context); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java index 716abbe1b20b..9ae90c722cb3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnChangeProviderContext.java @@ -23,6 +23,7 @@ import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.actions.AbstractShowPropertiesDiffAction; @@ -48,6 +49,7 @@ class SvnChangeProviderContext implements StatusReceiver { private Map<FilePath, String> myCopyFromURLs = null; private final SvnVcs myVcs; private final SvnBranchConfigurationManager myBranchConfigurationManager; + private final List<File> filesToRefresh = ContainerUtil.newArrayList(); private final ProgressIndicator myProgress; @@ -79,6 +81,11 @@ class SvnChangeProviderContext implements StatusReceiver { public void bewareRoot(VirtualFile vf, SVNURL url) { } + @Override + public void finish() { + LocalFileSystem.getInstance().refreshIoFiles(filesToRefresh, true, false, null); + } + public ChangelistBuilder getBuilder() { return myChangelistBuilder; } @@ -302,7 +309,7 @@ class SvnChangeProviderContext implements StatusReceiver { * * @param filePath the path of a changed file. */ - private static void loadEntriesFile(final FilePath filePath) { + private void loadEntriesFile(final FilePath filePath) { final FilePath parentPath = filePath.getParentPath(); if (parentPath == null) { return; @@ -313,9 +320,11 @@ class SvnChangeProviderContext implements StatusReceiver { } } - private static void refreshDotSvnAndEntries(FilePath filePath) { + private void refreshDotSvnAndEntries(FilePath filePath) { final File svn = new File(filePath.getPath(), SvnUtil.SVN_ADMIN_DIR_NAME); - LocalFileSystem.getInstance().refreshIoFiles(Arrays.asList(svn, new File(svn, SvnUtil.ENTRIES_FILE_NAME)), true, false, null); + + filesToRefresh.add(svn); + filesToRefresh.add(new File(svn, SvnUtil.ENTRIES_FILE_NAME)); } // seems here we can only have a tree conflict; which can be marked on either path (?) diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java index 49ea87d44f6e..5f5edd12eea7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnDiffProvider.java @@ -34,14 +34,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.history.LatestExistentSearcher; -import org.jetbrains.idea.svn.info.InfoConsumer; import org.jetbrains.idea.svn.info.Info; +import org.jetbrains.idea.svn.info.InfoConsumer; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.jetbrains.idea.svn.status.Status; import org.jetbrains.idea.svn.status.StatusType; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; @@ -162,11 +162,12 @@ public class SvnDiffProvider extends DiffProviderEx implements DiffProvider, Dif } } + @Nullable private String getCommitMessage(File path) throws VcsException { - SVNPropertyData property = + PropertyValue property = myVcs.getFactory(path).createPropertyClient().getProperty(SvnTarget.fromFile(path), COMMIT_MESSAGE, true, SVNRevision.BASE); - return property != null ? SVNPropertyValue.getPropertyAsString(property.getValue()) : null; + return PropertyValue.toString(property); } private static ItemLatestState defaultResult() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnEditFileProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnEditFileProvider.java index 64248892614a..c8b47aa0928e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnEditFileProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnEditFileProvider.java @@ -19,7 +19,7 @@ import com.intellij.openapi.vcs.EditFileProvider; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.idea.svn.properties.PropertyClient; -import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -42,10 +42,10 @@ public class SvnEditFileProvider implements EditFileProvider { ioFiles[i] = new File(files[i].getPath()); PropertyClient client = myVCS.getFactory(ioFiles[i]).createPropertyClient(); - SVNPropertyData property = client.getProperty(SvnTarget.fromFile(ioFiles[i], SVNRevision.WORKING), SvnPropertyKeys.SVN_NEEDS_LOCK, + PropertyValue property = client.getProperty(SvnTarget.fromFile(ioFiles[i], SVNRevision.WORKING), SvnPropertyKeys.SVN_NEEDS_LOCK, false, SVNRevision.WORKING); - if (property == null || property.getValue() == null) { + if (property == null) { throw new VcsException(SvnBundle.message("exception.text.file.miss.svn", ioFiles[i].getName())); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java index 1719f781a34a..977c6add0c1f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnFormatSelector.java @@ -15,122 +15,15 @@ */ package org.jetbrains.idea.svn; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.tmatesoft.svn.core.SVNErrorCode; -import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.internal.wc.admin.ISVNAdminAreaFactorySelector; import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaFactory; import org.tmatesoft.svn.core.internal.wc2.SvnWcGeneration; import org.tmatesoft.svn.core.wc2.SvnOperationFactory; import java.io.File; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -public class SvnFormatSelector implements ISVNAdminAreaFactorySelector { - - private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnFormatSelector"); - - public Collection getEnabledFactories(File path, Collection factories, boolean writeAccess) throws SVNException { - if (ApplicationManager.getApplication().isUnitTestMode()) { - return factories; - } - - if (! writeAccess) { - return factories; - } - - Collection result = null; - final WorkingCopyFormat presetFormat = SvnWorkingCopyFormatHolder.getPresetFormat(); - if (presetFormat != null) { - result = format2Factories(presetFormat, factories); - } - - if (result == null) { - final WorkingCopyFormat format = getWorkingCopyFormat(path); - result = format2Factories(format, factories); - } - - if (result == null) { - throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); - } - return result; - } - - @Nullable - static Collection format2Factories(final WorkingCopyFormat format, final Collection factories) { - if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) { - return factories; - } else if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) { - return factoriesFor16(factories); - } else if (WorkingCopyFormat.ONE_DOT_FIVE.equals(format)) { - return factoriesFor15(factories); - } else if (WorkingCopyFormat.ONE_DOT_FOUR.equals(format)) { - return factoriesFor14(factories); - } else if (WorkingCopyFormat.ONE_DOT_THREE.equals(format)) { - return factoriesFor13(factories); - } - return null; - } - - private static Collection<SVNAdminAreaFactory> factoriesFor13(final Collection factories) { - for (Iterator iterator = factories.iterator(); iterator.hasNext();) { - final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next(); - final int supportedVersion = factory.getSupportedVersion(); - if (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) { - return Collections.singletonList(factory); - } - } - return Collections.emptyList(); - } - - private static Collection<SVNAdminAreaFactory> factoriesFor14(final Collection factories) { - final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2); - for (Iterator iterator = factories.iterator(); iterator.hasNext();) { - final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next(); - final int supportedVersion = factory.getSupportedVersion(); - if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) || - (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion)) { - result.add(factory); - } - } - return result; - } - - private static Collection<SVNAdminAreaFactory> factoriesFor15(final Collection factories) { - final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2); - for (Iterator iterator = factories.iterator(); iterator.hasNext();) { - final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next(); - final int supportedVersion = factory.getSupportedVersion(); - if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) || - (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) || - (WorkingCopyFormat.ONE_DOT_FIVE.getFormat() == supportedVersion)) { - result.add(factory); - } - } - return result; - } - - private static Collection<SVNAdminAreaFactory> factoriesFor16(final Collection factories) { - final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2); - for (Iterator iterator = factories.iterator(); iterator.hasNext();) { - final SVNAdminAreaFactory factory = (SVNAdminAreaFactory) iterator.next(); - final int supportedVersion = factory.getSupportedVersion(); - if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) || - (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) || - (WorkingCopyFormat.ONE_DOT_FIVE.getFormat() == supportedVersion) || - (WorkingCopyFormat.ONE_DOT_SIX.getFormat() == supportedVersion)) { - result.add(factory); - } - } - return result; - } +public class SvnFormatSelector { @NotNull public static WorkingCopyFormat findRootAndGetFormat(final File path) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java index 1b1cd00589d0..13c15b23efa8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnRecursiveStatusWalker.java @@ -103,7 +103,7 @@ public class SvnRecursiveStatusWalker { if (e.contains(SVNErrorCode.WC_NOT_DIRECTORY) || e.contains(SVNErrorCode.WC_NOT_FILE)) { final VirtualFile virtualFile = path.getVirtualFile(); if (virtualFile != null) { - if (! myPartner.isExcluded(virtualFile)) { + if (! myPartner.isIgnoredByVcs(virtualFile)) { // self is unversioned myReceiver.processUnversioned(virtualFile); @@ -184,15 +184,20 @@ public class SvnRecursiveStatusWalker { } }; if (Depth.EMPTY.equals(newDepth)) { - directoryFilter = Processor.TRUE; + // just process immediate children - so only root directory itself should satisfy filter + directoryFilter = new Processor<File>() { + @Override + public boolean process(File file) { + return FileUtil.filesEqual(ioFile, file); + } + }; processor = new Processor<File>() { @Override public boolean process(File file) { - // here we deal only with immediate children - so ignored on IDEA level for children is not important - we nevertheless do not go into - // other levels - if (! FileUtil.filesEqual(ioFile, file)) return true; - if (! FileUtil.filesEqual(ioFile, file.getParentFile())) return false; - return checkDirProcessor.process(file); + // TODO: check if we should still call checkDirProcessor() here - or we really could not check ignore settings but just call + // TODO: myReceiver.processUnversioned() for all immediate children + // here we deal only with immediate children - so ignored on IDEA level for children is not important + return FileUtil.filesEqual(ioFile, file) || checkDirProcessor.process(file); } }; } else { @@ -278,7 +283,7 @@ public class SvnRecursiveStatusWalker { @Override public Boolean compute() { if (myProject.isDisposed()) return null; - return myPartner.isExcluded(vFile); + return myPartner.isIgnoredByVcs(vFile); } }); if (Boolean.TRUE.equals(excluded)) return; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java index 5010ac580750..b44fd16f979f 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/SvnVcs.java @@ -81,6 +81,8 @@ import org.jetbrains.idea.svn.history.SvnHistoryProvider; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.info.InfoConsumer; import org.jetbrains.idea.svn.properties.PropertyClient; +import org.jetbrains.idea.svn.properties.PropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.jetbrains.idea.svn.rollback.SvnRollbackEnvironment; import org.jetbrains.idea.svn.status.Status; import org.jetbrains.idea.svn.status.StatusType; @@ -89,7 +91,6 @@ import org.jetbrains.idea.svn.update.SvnIntegrateEnvironment; import org.jetbrains.idea.svn.update.SvnUpdateEnvironment; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.wc.SVNAdminUtil; -import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -108,8 +109,8 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { private static final VcsKey ourKey = createKey(VCS_NAME); public static final Topic<Runnable> WC_CONVERTED = new Topic<Runnable>("WC_CONVERTED", Runnable.class); - private final Map<String, Map<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>>> myPropertyCache = - new SoftHashMap<String, Map<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>>>(); + private final Map<String, Map<String, Pair<PropertyValue, Trinity<Long, Long, Long>>>> myPropertyCache = + new SoftHashMap<String, Map<String, Pair<PropertyValue, Trinity<Long, Long, Long>>>>(); private final SvnConfiguration myConfiguration; private final SvnEntriesFileListener myEntriesFileListener; @@ -567,9 +568,9 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { } @Nullable - public SVNPropertyValue getPropertyWithCaching(final VirtualFile file, final String propName) throws VcsException { - Map<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>> cachedMap = myPropertyCache.get(keyForVf(file)); - final Pair<SVNPropertyValue, Trinity<Long, Long, Long>> cachedValue = cachedMap == null ? null : cachedMap.get(propName); + public PropertyValue getPropertyWithCaching(final VirtualFile file, final String propName) throws VcsException { + Map<String, Pair<PropertyValue, Trinity<Long, Long, Long>>> cachedMap = myPropertyCache.get(keyForVf(file)); + final Pair<PropertyValue, Trinity<Long, Long, Long>> cachedValue = cachedMap == null ? null : cachedMap.get(propName); final File ioFile = new File(file.getPath()); final Trinity<Long, Long, Long> tsTrinity = getTimestampForPropertiesChange(ioFile, file.isDirectory()); @@ -582,17 +583,16 @@ public class SvnVcs extends AbstractVcs<CommittedChangeList> { } PropertyClient client = getFactory(ioFile).createPropertyClient(); - final SVNPropertyData value = client.getProperty(SvnTarget.fromFile(ioFile, SVNRevision.WORKING), propName, false, SVNRevision.WORKING); - final SVNPropertyValue propValue = value == null ? null : value.getValue(); + final PropertyValue value = client.getProperty(SvnTarget.fromFile(ioFile, SVNRevision.WORKING), propName, false, SVNRevision.WORKING); if (cachedMap == null) { - cachedMap = new HashMap<String, Pair<SVNPropertyValue, Trinity<Long, Long, Long>>>(); + cachedMap = new HashMap<String, Pair<PropertyValue, Trinity<Long, Long, Long>>>(); myPropertyCache.put(keyForVf(file), cachedMap); } - cachedMap.put(propName, Pair.create(propValue, tsTrinity)); + cachedMap.put(propName, Pair.create(value, tsTrinity)); - return propValue; + return value; } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java index 97e6a618ba7c..395dc36b7371 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/AbstractShowPropertiesDiffAction.java @@ -19,12 +19,15 @@ import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.diff.DiffManager; import com.intellij.openapi.diff.SimpleContent; import com.intellij.openapi.diff.SimpleDiffRequest; +import com.intellij.openapi.progress.PerformInBackgroundOption; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsDataKeys; @@ -34,17 +37,20 @@ import com.intellij.openapi.vcs.changes.ChangesUtil; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.MarkerVcsContentRevision; import com.intellij.openapi.vfs.VirtualFile; -import org.jetbrains.annotations.NonNls; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; -import org.jetbrains.idea.svn.SvnRevisionNumber; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.history.SvnRepositoryContentRevision; -import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.jetbrains.idea.svn.properties.PropertyConsumer; +import org.jetbrains.idea.svn.properties.PropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -69,8 +75,6 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen @Override public void update(final AnActionEvent e) { final DataContext dataContext = e.getDataContext(); - final Project project = CommonDataKeys.PROJECT.getData(dataContext); - final Presentation presentation = e.getPresentation(); final Change[] data = VcsDataKeys.CHANGES.getData(dataContext); boolean showAction = checkThatChangesAreUnderSvn(data); @@ -78,38 +82,23 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen presentation.setEnabled(showAction); } - private boolean checkThatChangesAreUnderSvn(Change[] data) { - boolean showAction = false; - if (data != null) { - for (Change change : data) { - final ContentRevision before = change.getBeforeRevision(); - if (before != null) { - showAction = showAction || before instanceof MarkerVcsContentRevision && SvnVcs.getKey().equals(((MarkerVcsContentRevision)before).getVcsKey()); - } - final ContentRevision after = change.getAfterRevision(); - if (after != null) { - showAction = showAction || after instanceof MarkerVcsContentRevision && SvnVcs.getKey().equals(((MarkerVcsContentRevision)after).getVcsKey()); + private static boolean checkThatChangesAreUnderSvn(@Nullable Change[] changes) { + boolean result = false; + + if (changes != null) { + result = ContainerUtil.or(changes, new Condition<Change>() { + @Override + public boolean value(Change change) { + return isUnderSvn(change.getBeforeRevision()) || isUnderSvn(change.getAfterRevision()); } - if (showAction) break; - } + }); } - return showAction; - } - private boolean enabled(final Project project, final Change[] changes) { - final boolean noChange = (project == null) || (changes == null) || (changes.length != 1); - if (noChange) { - return false; - } else { - final Change change = changes[0]; - - final ContentRevision revision = (change.getBeforeRevision() != null) ? change.getBeforeRevision() : change.getAfterRevision(); - if ((revision == null) || (! (revision.getRevisionNumber() instanceof SvnRevisionNumber))) { - return false; - } + return result; + } - return checkVcs(project, change); - } + private static boolean isUnderSvn(@Nullable ContentRevision revision) { + return revision instanceof MarkerVcsContentRevision && SvnVcs.getKey().equals(((MarkerVcsContentRevision)revision).getVcsKey()); } protected boolean checkVcs(final Project project, final Change change) { @@ -146,7 +135,7 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen private final String myErrorTitle; private CalculateAndShow(@Nullable final Project project, final Change change, final String errorTitle) { - super(project, SvnBundle.message("fetching.properties.contents.progress.title"), true, Backgroundable.DEAF); + super(project, SvnBundle.message("fetching.properties.contents.progress.title"), true, PerformInBackgroundOption.DEAF); myChange = change; myErrorTitle = errorTitle; } @@ -179,7 +168,7 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen } if (myBeforeContent != null && myAfterContent != null && myBeforeRevisionValue != null && myAfterRevision != null) { final SimpleDiffRequest diffRequest = new SimpleDiffRequest(myProject, getDiffWindowTitle(myChange)); - if (compareRevisions(myBeforeRevisionValue, myAfterRevision) >= 0) { + if (compareRevisions(myBeforeRevisionValue, myAfterRevision) > 0) { // before ahead diffRequest.setContents(new SimpleContent(myAfterContent), new SimpleContent(myBeforeContent)); diffRequest.setContentTitles(revisionToString(myAfterRevision), revisionToString(myBeforeRevisionValue)); @@ -194,7 +183,8 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen } } - private String getDiffWindowTitle(final Change change) { + @NotNull + private static String getDiffWindowTitle(@NotNull Change change) { if (change.isMoved() || change.isRenamed()) { final FilePath beforeFilePath = ChangesUtil.getBeforePath(change); final FilePath afterFilePath = ChangesUtil.getAfterPath(change); @@ -207,7 +197,7 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen } } - private int compareRevisions(@NonNls final SVNRevision revision1, @NonNls final SVNRevision revision2) { + private static int compareRevisions(@NotNull SVNRevision revision1, @NotNull SVNRevision revision2) { if (revision1.equals(revision2)) { return 0; } @@ -227,11 +217,9 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen return revision1.getNumber() > revision2.getNumber() ? 1 : -1; } - private String revisionToString(final SVNRevision revision) { - if (revision == null) { - return "not exists"; - } - return revision.toString(); + @NotNull + private static String revisionToString(@Nullable SVNRevision revision) { + return revision == null ? "not exists" : revision.toString(); } private final static String ourPropertiesDelimiter = "\n"; @@ -273,35 +261,35 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen private static String getPropertyList(@NotNull SvnVcs vcs, @NotNull SvnTarget target, @Nullable SVNRevision revision) throws VcsException { - final List<SVNPropertyData> lines = new ArrayList<SVNPropertyData>(); - final ISVNPropertyHandler propertyHandler = createHandler(revision, lines); + final List<PropertyData> lines = new ArrayList<PropertyData>(); + final PropertyConsumer propertyHandler = createHandler(revision, lines); vcs.getFactory(target).createPropertyClient().list(target, revision, Depth.EMPTY, propertyHandler); return toSortedStringPresentation(lines); } - private static ISVNPropertyHandler createHandler(SVNRevision revision, final List<SVNPropertyData> lines) { + private static PropertyConsumer createHandler(SVNRevision revision, final List<PropertyData> lines) { final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator(); if (indicator != null) { indicator.checkCanceled(); indicator.setText(SvnBundle.message("show.properties.diff.progress.text.revision.information", revision.toString())); } - return new ISVNPropertyHandler() { - public void handleProperty(final File path, final SVNPropertyData property) throws SVNException { + return new PropertyConsumer() { + public void handleProperty(final File path, final PropertyData property) throws SVNException { registerProperty(property); } - public void handleProperty(final SVNURL url, final SVNPropertyData property) throws SVNException { + public void handleProperty(final SVNURL url, final PropertyData property) throws SVNException { registerProperty(property); } - public void handleProperty(final long revision, final SVNPropertyData property) throws SVNException { + public void handleProperty(final long revision, final PropertyData property) throws SVNException { // revision properties here } - private void registerProperty(@NotNull SVNPropertyData property) { + private void registerProperty(@NotNull PropertyData property) { if (indicator != null) { indicator.checkCanceled(); indicator.setText2(SvnBundle.message("show.properties.diff.progress.text2.property.information", property.getName())); @@ -311,26 +299,26 @@ public abstract class AbstractShowPropertiesDiffAction extends AnAction implemen }; } - private static String toSortedStringPresentation(List<SVNPropertyData> lines) { + private static String toSortedStringPresentation(List<PropertyData> lines) { StringBuilder sb = new StringBuilder(); - Collections.sort(lines, new Comparator<SVNPropertyData>() { - public int compare(final SVNPropertyData o1, final SVNPropertyData o2) { + Collections.sort(lines, new Comparator<PropertyData>() { + public int compare(final PropertyData o1, final PropertyData o2) { return o1.getName().compareTo(o2.getName()); } }); - for (SVNPropertyData line : lines) { + for (PropertyData line : lines) { addPropertyPresentation(line, sb); } return sb.toString(); } - private static void addPropertyPresentation(final SVNPropertyData property, final StringBuilder sb) { + private static void addPropertyPresentation(final PropertyData property, final StringBuilder sb) { if (sb.length() != 0) { sb.append(ourPropertiesDelimiter); } - sb.append(property.getName()).append("=").append((property.getValue() == null) ? "" : SVNPropertyValue.getPropertyAsString(property.getValue())); + sb.append(property.getName()).append("=").append(StringUtil.notNullize(PropertyValue.toString(property.getValue()))); } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/CreateExternalAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/CreateExternalAction.java index 31206eec045c..d6d9c3152dde 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/CreateExternalAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/CreateExternalAction.java @@ -24,7 +24,6 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.VcsDirtyScopeManager; @@ -42,15 +41,16 @@ import org.jetbrains.idea.svn.api.ProgressEvent; import org.jetbrains.idea.svn.api.ProgressTracker; import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.dialogs.SelectCreateExternalTargetDialog; +import org.jetbrains.idea.svn.properties.ExternalsDefinitionParser; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.jetbrains.idea.svn.update.UpdateClient; import org.tmatesoft.svn.core.SVNCancelException; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.internal.wc.SVNExternal; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; +import java.util.Map; /** * Created with IntelliJ IDEA. @@ -132,25 +132,24 @@ public class CreateExternalAction extends DumbAwareAction { public static boolean addToExternalProperty(@NotNull SvnVcs vcs, @NotNull File ioFile, String target, String url) throws SVNException, VcsException { ClientFactory factory = vcs.getFactory(ioFile); - SVNPropertyData propertyData = factory.createPropertyClient().getProperty(SvnTarget.fromFile(ioFile), SvnPropertyKeys.SVN_EXTERNALS, + PropertyValue propertyValue = factory.createPropertyClient().getProperty(SvnTarget.fromFile(ioFile), SvnPropertyKeys.SVN_EXTERNALS, false, SVNRevision.UNDEFINED); String newValue; - if (propertyData != null && propertyData.getValue() != null && ! StringUtil.isEmptyOrSpaces(propertyData.getValue().getString())) { - final SVNExternal[] externals = SVNExternal.parseExternals("Create External", propertyData.getValue().getString()); - for (SVNExternal external : externals) { - if (Comparing.equal(external.getPath(), target)) { - AbstractVcsHelper - .getInstance(vcs.getProject()).showError(new VcsException("Selected destination conflicts with existing: " + external.toString()), "Create External"); - return true; - } + if (propertyValue != null && !StringUtil.isEmptyOrSpaces(propertyValue.toString())) { + Map<String, String> externalsMap = ExternalsDefinitionParser.parseExternalsProperty(propertyValue.toString()); + String externalsForTarget = externalsMap.get(target); + + if (externalsForTarget != null) { + AbstractVcsHelper.getInstance(vcs.getProject()).showError( + new VcsException("Selected destination conflicts with existing: " + externalsForTarget), "Create External"); + return true; } final String string = createExternalDefinitionString(url, target); - newValue = propertyData.getValue().getString().trim() + "\n" + string; + newValue = propertyValue.toString().trim() + "\n" + string; } else { newValue = createExternalDefinitionString(url, target); } - factory.createPropertyClient().setProperty(ioFile, SvnPropertyKeys.SVN_EXTERNALS, SVNPropertyValue.create(newValue), Depth.EMPTY, - false); + factory.createPropertyClient().setProperty(ioFile, SvnPropertyKeys.SVN_EXTERNALS, PropertyValue.create(newValue), Depth.EMPTY, false); return false; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SetPropertyAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SetPropertyAction.java index cdc738cf2d40..5e53cc956e92 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SetPropertyAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SetPropertyAction.java @@ -30,7 +30,7 @@ import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.dialogs.SetPropertyDialog; import org.jetbrains.idea.svn.properties.PropertyClient; -import org.tmatesoft.svn.core.SVNPropertyValue; +import org.jetbrains.idea.svn.properties.PropertyValue; import java.io.File; @@ -79,7 +79,7 @@ public class SetPropertyAction extends BasicAction { // TODO: most likely SVNDepth.getInfinityOrEmptyDepth should be used instead of SVNDepth.fromRecursive - to have either "infinity" // TODO: or "empty" depth, and not "infinity" or "files" depth. But previous logic used SVNDepth.fromRecursive implicitly - client.setProperty(ioFile, name, SVNPropertyValue.create(value), Depth.allOrFiles(recursive), false); + client.setProperty(ioFile, name, PropertyValue.create(value), Depth.allOrFiles(recursive), false); } for(int i = 0; i < file.length; i++) { if (recursive && file[i].isDirectory()) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java index c206cd3451d8..94fc2e11c96e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnExcludingIgnoredOperation.java @@ -15,11 +15,10 @@ */ package org.jetbrains.idea.svn.actions; -import com.intellij.lifecycle.PeriodicalTasksCloser; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.util.Computable; +import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vfs.VfsUtilCore; @@ -42,39 +41,36 @@ public class SvnExcludingIgnoredOperation { public static class Filter { private final Project myProject; - private final FileIndexFacade myIndex; + private final ProjectLevelVcsManager myVcsManager; private final ChangeListManager myClManager; public Filter(final Project project) { myProject = project; if (!project.isDefault()) { - myIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, FileIndexFacade.class); + myVcsManager = ProjectLevelVcsManager.getInstance(project); myClManager = ChangeListManager.getInstance(project); } else { - myIndex = null; + myVcsManager = null; myClManager = null; } } public boolean accept(final VirtualFile file) { if (!myProject.isDefault()) { - if (isExcluded(file)) { - return false; - } - if (myClManager.isIgnoredFile(file)) { + if (isIgnoredByVcs(file) || myClManager.isIgnoredFile(file)) { return false; } } return true; } - private boolean isExcluded(final VirtualFile file) { + private boolean isIgnoredByVcs(final VirtualFile file) { return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { - return myIndex.isExcludedFile(file); + return myVcsManager.isIgnored(file); } }); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java index 912bd970f7b0..ddd9bd572f0e 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/actions/SvnMergeProvider.java @@ -32,9 +32,9 @@ import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.info.Info; import org.jetbrains.idea.svn.properties.PropertyClient; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.SVNProperty; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.wc.*; +import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.ByteArrayOutputStream; @@ -162,8 +162,8 @@ public class SvnMergeProvider implements MergeProvider { File ioFile = new File(file.getPath()); PropertyClient client = vcs.getFactory(ioFile).createPropertyClient(); - SVNPropertyData svnPropertyData = client.getProperty(SvnTarget.fromFile(ioFile), SVNProperty.MIME_TYPE, false, SVNRevision.WORKING); - if (svnPropertyData != null && SVNProperty.isBinaryMimeType(SVNPropertyValue.getPropertyAsString(svnPropertyData.getValue()))) { + PropertyValue value = client.getProperty(SvnTarget.fromFile(ioFile), SVNProperty.MIME_TYPE, false, SVNRevision.WORKING); + if (value != null && SVNProperty.isBinaryMimeType(value.toString())) { return true; } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java index 33e06739ad0b..0b484e41d1c5 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandExecutor.java @@ -23,6 +23,7 @@ import com.intellij.openapi.application.PathManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.util.registry.Registry; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.util.EventDispatcher; @@ -36,6 +37,7 @@ import java.io.File; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; @@ -152,9 +154,20 @@ public class CommandExecutor { protected void beforeCreateProcess() throws SvnBindException { EncodingEnvironmentUtil.fixDefaultEncodingIfMac(myCommandLine, null); + setupLocale(); ensureMessageFile(); } + private void setupLocale() { + String locale = Registry.stringValue("svn.executable.locale"); + Map<String, String> environment = myCommandLine.getEnvironment(); + + // TODO: check if we need to set LC_ALL to configured locale or just clear it + environment.put("LC_ALL", ""); + environment.put("LC_MESSAGES", locale); + environment.put("LANG", locale); + } + private void ensureMessageFile() throws SvnBindException { if (myMessage != null) { myMessageFile = createTempFile("commit-message", ".txt"); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java index eee798737846..eb2e6cf976cb 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/commandLine/CommandUtil.java @@ -58,8 +58,7 @@ public class CommandUtil { boolean hasPegRevision = pegRevision != null && !SVNRevision.UNDEFINED.equals(pegRevision) && !SVNRevision.WORKING.equals(pegRevision) && - pegRevision.isValid() && - pegRevision.getNumber() != 0; + pegRevision.isValid(); if (hasPegRevision || hasAtSymbol) { // add '@' to correctly handle paths that contain '@' symbol diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/config/SvnConfigureProxiesDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/config/SvnConfigureProxiesDialog.java index a70a4f28d0fd..40e3c80d1fc6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/config/SvnConfigureProxiesDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/config/SvnConfigureProxiesDialog.java @@ -63,16 +63,10 @@ public class SvnConfigureProxiesDialog extends DialogWrapper implements Validati public void onError(final String text, final JComponent component, final boolean forbidSave) { myTabbedPane.setSelectedComponent(component); - String prefixString = ""; - for (int i = 0; i < myTabbedPane.getComponentCount(); i++) { - final Component currentComponent = myTabbedPane.getComponentAt(i); - // compare referencies - same objects - if (currentComponent == component) { - prefixString = myTabbedPane.getTitleAt(i) + ": "; - } - } + String errorPrefix = myTabbedPane.getTitleAt(myTabbedPane.indexOfComponent(component)) + ": "; + setOKActionEnabled(! forbidSave); - setInvalid(prefixString + text); + setInvalid(errorPrefix + text); } public void onSuccess() { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.java index 6bd08c1089cb..50ddd9615d41 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/BranchConfigurationDialog.java @@ -22,10 +22,12 @@ import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.MultiLineLabelUI; import com.intellij.openapi.ui.TextFieldWithBrowseButton; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.*; import com.intellij.ui.components.JBList; +import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -100,16 +102,23 @@ public class BranchConfigurationDialog extends DialogWrapper { myListPanel.add( ToolbarDecorator.createDecorator(myLocationList) .setAddAction(new AnActionButtonRunnable() { + + @Nullable private SVNURL usedRootUrl; + @Override public void run(AnActionButton button) { - final String selectedUrl = SelectLocationDialog.selectLocation(project, rootUrl.toDecodedString()); - if (selectedUrl != null) { - if (!configuration.getBranchUrls().contains(selectedUrl)) { - configuration - .addBranches(selectedUrl, new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(), InfoReliability.empty)); - mySvnBranchConfigManager.reloadBranches(myRoot, selectedUrl, null); - listModel.fireItemAdded(); - myLocationList.setSelectedIndex(listModel.getSize() - 1); + Pair<String, SVNURL> result = SelectLocationDialog.selectLocation(project, ObjectUtils.notNull(usedRootUrl, rootUrl)); + if (result != null) { + String selectedUrl = result.getFirst(); + usedRootUrl = result.getSecond(); + if (selectedUrl != null) { + if (!configuration.getBranchUrls().contains(selectedUrl)) { + configuration + .addBranches(selectedUrl, new InfoStorage<List<SvnBranchItem>>(new ArrayList<SvnBranchItem>(), InfoReliability.empty)); + mySvnBranchConfigManager.reloadBranches(myRoot, selectedUrl, null); + listModel.fireItemAdded(); + myLocationList.setSelectedIndex(listModel.getSize() - 1); + } } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java index 860c524ed591..cd504be56077 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/PropertiesComponent.java @@ -37,9 +37,12 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; -import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.jetbrains.idea.svn.properties.PropertyConsumer; +import org.jetbrains.idea.svn.properties.PropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNProperty; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -151,20 +154,20 @@ public class PropertiesComponent extends JPanel { } } - private void collectProperties(@NotNull SvnVcs vcs, @NotNull File file, @NotNull final Map<String, String> props) { + private static void collectProperties(@NotNull SvnVcs vcs, @NotNull File file, @NotNull final Map<String, String> props) { try { - ISVNPropertyHandler handler = new ISVNPropertyHandler() { - public void handleProperty(File path, SVNPropertyData property) throws SVNException { - final SVNPropertyValue value = property.getValue(); + PropertyConsumer handler = new PropertyConsumer() { + public void handleProperty(File path, PropertyData property) throws SVNException { + final PropertyValue value = property.getValue(); if (value != null) { - props.put(property.getName(), SVNPropertyValue.getPropertyAsString(property.getValue())); + props.put(property.getName(), PropertyValue.toString(property.getValue())); } } - public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + public void handleProperty(SVNURL url, PropertyData property) throws SVNException { } - public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + public void handleProperty(long revision, PropertyData property) throws SVNException { } }; vcs.getFactory(file).createPropertyClient().list(SvnTarget.fromFile(file, SVNRevision.UNDEFINED), SVNRevision.WORKING, Depth.EMPTY, @@ -229,10 +232,12 @@ public class PropertiesComponent extends JPanel { String url = "file://" + myFile.getPath().replace(File.separatorChar, '/'); VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(url); if (file != null) { + VcsDirtyScopeManager dirtyScopeManager = VcsDirtyScopeManager.getInstance(myVcs.getProject()); + if (recursive && file.isDirectory()) { - VcsDirtyScopeManager.getInstance(myVcs.getProject()).dirDirtyRecursively(file, true); + dirtyScopeManager.dirDirtyRecursively(file); } else { - VcsDirtyScopeManager.getInstance(myVcs.getProject()).fileDirty(file); + dirtyScopeManager.fileDirty(file); } } } @@ -272,8 +277,7 @@ public class PropertiesComponent extends JPanel { if (!StringUtil.isEmpty(property)) { try { myVcs.getFactory(myFile).createPropertyClient() - .setProperty(myFile, property, value != null ? SVNPropertyValue.create(value) : null, - Depth.allOrEmpty(recursive), force); + .setProperty(myFile, property, PropertyValue.create(value), Depth.allOrEmpty(recursive), force); } catch (VcsException error) { VcsBalloonProblemNotifier @@ -302,7 +306,7 @@ public class PropertiesComponent extends JPanel { public void actionPerformed(AnActionEvent e) { Project project = CommonDataKeys.PROJECT.getData(e.getDataContext()); - SVNPropertyData propValue = null; + PropertyValue propValue = null; try { propValue = myVcs.getFactory(myFile).createPropertyClient() .getProperty(SvnTarget.fromFile(myFile), SVNProperty.KEYWORDS, false, SVNRevision.WORKING); @@ -311,8 +315,7 @@ public class PropertiesComponent extends JPanel { // show erorr message } - SetKeywordsDialog dialog = new SetKeywordsDialog(project, - propValue != null ? SVNPropertyValue.getPropertyAsString(propValue.getValue()) : null); + SetKeywordsDialog dialog = new SetKeywordsDialog(project, PropertyValue.toString(propValue)); dialog.show(); if (dialog.isOK()) { setProperty(SvnPropertyKeys.SVN_KEYWORDS, dialog.getKeywords(), false, false); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java index 0fd1f06bf7cb..163be4922224 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserComponent.java @@ -76,10 +76,26 @@ public class RepositoryBrowserComponent extends JPanel implements Disposable, Da } public void setRepositoryURLs(SVNURL[] urls, final boolean showFiles) { + setRepositoryURLs(urls, showFiles, null, false); + } + + public void setRepositoryURLs(SVNURL[] urls, + final boolean showFiles, + @Nullable NotNullFunction<RepositoryBrowserComponent, Expander> defaultExpanderFactory, + boolean expandFirst) { RepositoryTreeModel model = new RepositoryTreeModel(myVCS, showFiles, this); + + if (defaultExpanderFactory != null) { + model.setDefaultExpanderFactory(defaultExpanderFactory); + } + model.setRoots(urls); Disposer.register(this, model); myRepositoryTree.setModel(model); + + if (expandFirst) { + myRepositoryTree.expandRow(0); + } } public void setRepositoryURL(SVNURL url, boolean showFiles, final NotNullFunction<RepositoryBrowserComponent, Expander> defaultExpanderFactory) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java index 191acf387b86..83d895b93ffc 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/RepositoryBrowserDialog.java @@ -93,7 +93,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { private final boolean myShowFiles; - @NonNls private static final String PLACE_TOOLBAR = "RepositoryBrowser.Toolbar"; + @NonNls public static final String PLACE_TOOLBAR = "RepositoryBrowser.Toolbar"; @NonNls private static final String PLACE_MENU = "RepositoryBrowser.Menu"; private final String myRepositoriesLabelText; protected JLabel myRepositoriesLabel; @@ -138,7 +138,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { DefaultActionGroup group = new DefaultActionGroup(); final RepositoryBrowserComponent browser = getRepositoryBrowser(); group.add(new AddLocationAction(browser)); - group.add(new EditLocationAction()); + group.add(new EditLocationAction(browser)); group.add(new DiscardLocationAction(browser)); group.add(new DetailsAction()); group.addSeparator(); @@ -216,7 +216,7 @@ public class RepositoryBrowserDialog extends DialogWrapper { group.add(copyUrlAction); group.addSeparator(); group.add(new RefreshAction(browser)); - group.add(new EditLocationAction()); + group.add(new EditLocationAction(browser)); group.add(new DiscardLocationAction(browser)); ActionPopupMenu menu = ActionManager.getInstance().createActionPopupMenu(PLACE_MENU, group); return menu.getComponent(); @@ -413,13 +413,17 @@ public class RepositoryBrowserDialog extends DialogWrapper { } } - protected class EditLocationAction extends AnAction { - public EditLocationAction() { + protected static class EditLocationAction extends AnAction { + + @NotNull private final RepositoryBrowserComponent myBrowserComponent; + + public EditLocationAction(@NotNull RepositoryBrowserComponent browserComponent) { super(SvnBundle.message("repository.browser.edit.location.menu.item")); + myBrowserComponent = browserComponent; } public void update(AnActionEvent e) { - RepositoryTreeNode node = getRepositoryBrowser().getSelectedNode(); + RepositoryTreeNode node = myBrowserComponent.getSelectedNode(); if (e.getPlace().equals(PLACE_TOOLBAR)) { e.getPresentation().setDescription(SvnBundle.message("repository.browser.edit.location.menu.item")); e.getPresentation().setText(SvnBundle.message("repository.browser.edit.location.menu.item")); @@ -429,13 +433,14 @@ public class RepositoryBrowserDialog extends DialogWrapper { } public void actionPerformed(AnActionEvent e) { - RepositoryTreeNode node = getRepositoryBrowser().getSelectedNode(); + RepositoryTreeNode node = myBrowserComponent.getSelectedNode(); if (node == null || (! (node.getParent() instanceof RepositoryTreeRootNode))) { return; } final String oldUrl = node.getURL().toString(); final SvnApplicationSettings settings = SvnApplicationSettings.getInstance(); - final AddRepositoryLocationDialog dialog = new AddRepositoryLocationDialog(myProject, settings.getTypedUrlsListCopy()) { + final AddRepositoryLocationDialog dialog = + new AddRepositoryLocationDialog(myBrowserComponent.getProject(), settings.getTypedUrlsListCopy()) { @Override protected String initText() { return oldUrl; @@ -453,9 +458,9 @@ public class RepositoryBrowserDialog extends DialogWrapper { settings.addTypedUrl(url); settings.removeCheckoutURL(oldUrl); settings.addCheckoutURL(url); - final RepositoryBrowserComponent browser = getRepositoryBrowser(); - browser.removeURL(oldUrl); - browser.addURL(url); + + myBrowserComponent.removeURL(oldUrl); + myBrowserComponent.addURL(url); } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SelectLocationDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SelectLocationDialog.java index a6ca6ad54f11..bcbbe79c1b45 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SelectLocationDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SelectLocationDialog.java @@ -15,12 +15,15 @@ */ package org.jetbrains.idea.svn.dialogs; +import com.intellij.openapi.actionSystem.ActionManager; +import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.help.HelpManager; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Ref; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -52,21 +55,30 @@ public class SelectLocationDialog extends DialogWrapper { private final String myDstLabel; private JTextField myDstText; private final boolean myIsShowFiles; + private final boolean myAllowActions; @NonNls private static final String HELP_ID = "vcs.subversion.common"; // todo check that works when authenticated @Nullable public static String selectLocation(Project project, String url) { - SelectLocationDialog dialog = openDialog(project, url, null, null, true, null); + SelectLocationDialog dialog = openDialog(project, url, null, null, true, false, null); return dialog == null || !dialog.isOK() ? null : dialog.getSelectedURL(); } @Nullable + public static Pair<String, SVNURL> selectLocation(Project project, @NotNull SVNURL url) { + SelectLocationDialog dialog = new SelectLocationDialog(project, url, null, null, true, true); + dialog.show(); + + return dialog.isOK() ? Pair.create(dialog.getSelectedURL(), dialog.getRootUrl()) : null; + } + + @Nullable public static String selectCopyDestination(Project project, String url, String dstLabel, String dstName, boolean showFiles) { SelectLocationDialog dialog = - openDialog(project, url, dstLabel, dstName, showFiles, SvnBundle.message("select.location.invalid.url.message", url)); + openDialog(project, url, dstLabel, dstName, showFiles, false, SvnBundle.message("select.location.invalid.url.message", url)); return dialog == null || !dialog.isOK() ? null : SVNPathUtil.append(dialog.getSelectedURL(), dialog.getDestinationName()); } @@ -77,6 +89,7 @@ public class SelectLocationDialog extends DialogWrapper { String dstLabel, String dstName, boolean showFiles, + boolean allowActions, String errorMessage) { try { SVNURL svnUrl = SvnUtil.createUrl(url); @@ -86,8 +99,7 @@ public class SelectLocationDialog extends DialogWrapper { SvnBundle.message("dialog.title.select.repository.location")); return null; } - - SelectLocationDialog dialog = new SelectLocationDialog(project, repositoryUrl, dstLabel, dstName, showFiles); + SelectLocationDialog dialog = new SelectLocationDialog(project, repositoryUrl, dstLabel, dstName, showFiles, allowActions); dialog.show(); return dialog; } @@ -98,13 +110,14 @@ public class SelectLocationDialog extends DialogWrapper { } } - private SelectLocationDialog(Project project, SVNURL url, String dstLabel, String dstName, boolean showFiles) { + private SelectLocationDialog(Project project, SVNURL url, String dstLabel, String dstName, boolean showFiles, boolean allowActions) { super(project, true); myProject = project; myDstLabel = dstLabel; myDstName = dstName; myURL = url; myIsShowFiles = showFiles; + myAllowActions = allowActions; setTitle(SvnBundle.message("dialog.title.select.repository.location")); getHelpAction().setEnabled(true); init(); @@ -146,7 +159,13 @@ public class SelectLocationDialog extends DialogWrapper { protected void init() { super.init(); final String urlString = myURL.toString(); - myRepositoryBrowser.setRepositoryURL(myURL, myIsShowFiles, new UrlOpeningExpander.Factory(urlString, urlString)); + if (myAllowActions) { + // initialize repo browser this way - to make actions work correctly + myRepositoryBrowser.setRepositoryURLs(new SVNURL[]{myURL}, myIsShowFiles, new UrlOpeningExpander.Factory(urlString, urlString), true); + } + else { + myRepositoryBrowser.setRepositoryURL(myURL, myIsShowFiles, new UrlOpeningExpander.Factory(urlString, urlString)); + } myRepositoryBrowser.addChangeListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { getOKAction().setEnabled(isOKActionEnabled()); @@ -162,7 +181,10 @@ public class SelectLocationDialog extends DialogWrapper { protected JComponent createCenterPanel() { JPanel panel = new JPanel(); - panel.setLayout(new GridBagLayout()); + panel.setLayout(new BorderLayout()); + + JPanel browserPanel = new JPanel(); + browserPanel.setLayout(new GridBagLayout()); GridBagConstraints gc = new GridBagConstraints(); gc.insets = new Insets(2, 2, 2, 2); @@ -177,7 +199,7 @@ public class SelectLocationDialog extends DialogWrapper { myRepositoryBrowser = new RepositoryBrowserComponent(SvnVcs.getInstance(myProject)); - panel.add(myRepositoryBrowser, gc); + browserPanel.add(myRepositoryBrowser, gc); if (myDstName != null) { gc.gridy += 1; gc.gridwidth = 1; @@ -187,7 +209,7 @@ public class SelectLocationDialog extends DialogWrapper { gc.weighty = 0; JLabel dstLabel = new JLabel(myDstLabel); - panel.add(dstLabel, gc); + browserPanel.add(dstLabel, gc); gc.gridx += 1; gc.weightx = 1; @@ -196,7 +218,7 @@ public class SelectLocationDialog extends DialogWrapper { myDstText = new JTextField(); myDstText.setText(myDstName); myDstText.selectAll(); - panel.add(myDstText, gc); + browserPanel.add(myDstText, gc); myDstText.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { @@ -217,12 +239,25 @@ public class SelectLocationDialog extends DialogWrapper { gc.gridy += 1; gc.gridwidth = 2; - panel.add(new JSeparator(), gc); + browserPanel.add(new JSeparator(), gc); + } + + if (myAllowActions) { + panel.add(createToolbar(), BorderLayout.NORTH); } + panel.add(browserPanel, BorderLayout.CENTER); return panel; } + @NotNull + private JComponent createToolbar() { + DefaultActionGroup group = new DefaultActionGroup(); + group.add(new RepositoryBrowserDialog.EditLocationAction(myRepositoryBrowser)); + + return ActionManager.getInstance().createActionToolbar(RepositoryBrowserDialog.PLACE_TOOLBAR, group, true).getComponent(); + } + public JComponent getPreferredFocusedComponent() { return (JComponent)myRepositoryBrowser.getPreferredFocusedComponent(); } @@ -246,4 +281,16 @@ public class SelectLocationDialog extends DialogWrapper { public String getSelectedURL() { return myRepositoryBrowser.getSelectedURL(); } + + @Nullable + public SVNURL getRootUrl() { + RepositoryTreeNode node = myRepositoryBrowser.getSelectedNode(); + + // find the most top parent of type RepositoryTreeNode + while (node != null && node.getParent() instanceof RepositoryTreeNode) { + node = (RepositoryTreeNode)node.getParent(); + } + + return node != null ? node.getURL() : null; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SetPropertyDialog.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SetPropertyDialog.java index 28375d28b7ba..f2a58a0bd2da 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SetPropertyDialog.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/dialogs/SetPropertyDialog.java @@ -24,15 +24,16 @@ import com.intellij.openapi.vcs.VcsException; import com.intellij.ui.DocumentAdapter; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnBundle; import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.properties.PropertyClient; -import org.tmatesoft.svn.core.SVNPropertyValue; +import org.jetbrains.idea.svn.properties.PropertyConsumer; +import org.jetbrains.idea.svn.properties.PropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.SVNURL; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -154,10 +155,10 @@ public class SetPropertyDialog extends DialogWrapper { return; } File file = myFiles[0]; - SVNPropertyData property = !StringUtil.isEmpty(name) ? getProperty(file, name) : null; + PropertyValue property = !StringUtil.isEmpty(name) ? getProperty(file, name) : null; if (property != null) { - myValueText.setText(SVNPropertyValue.getPropertyAsString(property.getValue())); + myValueText.setText(property.toString()); myValueText.selectAll(); } else { @@ -165,19 +166,20 @@ public class SetPropertyDialog extends DialogWrapper { } } - private SVNPropertyData getProperty(@NotNull File file, @NotNull String name) { - SVNPropertyData property; + @Nullable + private PropertyValue getProperty(@NotNull File file, @NotNull String name) { + PropertyValue result; try { PropertyClient client = myVCS.getFactory(file).createPropertyClient(); - property = client.getProperty(SvnTarget.fromFile(file, SVNRevision.WORKING), name, false, SVNRevision.WORKING); + result = client.getProperty(SvnTarget.fromFile(file, SVNRevision.WORKING), name, false, SVNRevision.WORKING); } catch (VcsException e) { LOG.info(e); - property = null; + result = null; } - return property; + return result; } protected JComponent createCenterPanel() { @@ -205,18 +207,18 @@ public class SetPropertyDialog extends DialogWrapper { if (files.length == 1) { File file = files[0]; try { - ISVNPropertyHandler handler = new ISVNPropertyHandler() { - public void handleProperty(File path, SVNPropertyData property) { + PropertyConsumer handler = new PropertyConsumer() { + public void handleProperty(File path, PropertyData property) { String name = property.getName(); if (name != null) { names.add(name); } } - public void handleProperty(SVNURL url, SVNPropertyData property) { + public void handleProperty(SVNURL url, PropertyData property) { } - public void handleProperty(long revision, SVNPropertyData property) { + public void handleProperty(long revision, PropertyData property) { } }; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CmdDiffClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CmdDiffClient.java index 497134727ee4..be084b0986d0 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CmdDiffClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/CmdDiffClient.java @@ -52,13 +52,14 @@ import java.util.List; */ public class CmdDiffClient extends BaseSvnClient implements DiffClient { + @NotNull @Override public List<Change> compare(@NotNull SvnTarget target1, @NotNull SvnTarget target2) throws VcsException { - assertUrl(target2); - if (target1.isFile()) { + assertUrl(target1); + if (target2.isFile()) { // Such combination (file and url) with "--summarize" option is supported only in svn 1.8. // For svn 1.7 "--summarize" is only supported when both targets are repository urls. - assertDirectory(target1); + assertDirectory(target2); WorkingCopyFormat format = WorkingCopyFormat.from(myFactory.createVersionClient().getVersion()); if (format.less(WorkingCopyFormat.ONE_DOT_EIGHT)) { @@ -95,6 +96,7 @@ public class CmdDiffClient extends BaseSvnClient implements DiffClient { } } + @NotNull private List<Change> parseOutput(@NotNull SvnTarget target1, @NotNull SvnTarget target2, @NotNull CommandExecutor executor) throws SvnBindException { try { @@ -114,16 +116,30 @@ public class CmdDiffClient extends BaseSvnClient implements DiffClient { } } - private ContentRevision createRemoteRevision(@NotNull FilePath remotePath, @NotNull FilePath localPath, @NotNull FileStatus status) { + @NotNull + private ContentRevision createRevision(@NotNull FilePath path, + @NotNull FilePath localPath, + @NotNull SVNRevision revision, + @NotNull FileStatus status) { + ContentRevision result; + + if (path.isNonLocal()) { // explicitly use local path for deleted items - so these items will be correctly displayed as deleted under local working copy node // and not as deleted under remote branch node (in ChangesBrowser) // NOTE, that content is still retrieved using remotePath. - return SvnRepositoryContentRevision - .create(myVcs, remotePath, status == FileStatus.DELETED ? localPath : null, SVNRevision.HEAD.getNumber()); + result = SvnRepositoryContentRevision.create(myVcs, path, status == FileStatus.DELETED ? localPath : null, revision.getNumber()); + } + else { + result = CurrentContentRevision.create(path); } - private static ContentRevision createLocalRevision(@NotNull FilePath path) { - return CurrentContentRevision.create(path); + return result; + } + + private static FilePath createFilePath(@NotNull SvnTarget target, boolean isDirectory) { + return target.isFile() + ? VcsUtil.getFilePath(target.getFile(), isDirectory) + : VcsUtil.getFilePathOnNonLocal(SvnUtil.toDecodedString(target), isDirectory); } @NotNull @@ -134,9 +150,7 @@ public class CmdDiffClient extends BaseSvnClient implements DiffClient { // TODO: 3) Properties change is currently not added as part of result change like in SvnChangeProviderContext.patchWithPropertyChange SvnTarget subTarget1 = SvnUtil.append(target1, diffPath.path, true); - String relativePath = target1.isFile() - ? FileUtil.getRelativePath(target1.getFile(), subTarget1.getFile()) - : SvnUtil.getRelativeUrl(SvnUtil.toDecodedString(target1), SvnUtil.toDecodedString(subTarget1)); + String relativePath = SvnUtil.getRelativeUrl(SvnUtil.toDecodedString(target1), SvnUtil.toDecodedString(subTarget1)); if (relativePath == null) { throw new SvnBindException("Could not get relative path for " + target1 + " and " + subTarget1); @@ -144,27 +158,19 @@ public class CmdDiffClient extends BaseSvnClient implements DiffClient { SvnTarget subTarget2 = SvnUtil.append(target2, FileUtil.toSystemIndependentName(relativePath)); - FilePath target1Path = target1.isFile() - ? VcsUtil.getFilePath(subTarget1.getFile(), diffPath.isDirectory()) - : VcsUtil.getFilePathOnNonLocal(SvnUtil.toDecodedString(subTarget1), diffPath.isDirectory()); - FilePath target2Path = VcsUtil.getFilePathOnNonLocal(SvnUtil.toDecodedString(subTarget2), diffPath.isDirectory()); + FilePath target1Path = createFilePath(subTarget1, diffPath.isDirectory()); + FilePath target2Path = createFilePath(subTarget2, diffPath.isDirectory()); FileStatus status = SvnStatusConvertor .convertStatus(SvnStatusHandler.getStatus(diffPath.itemStatus), SvnStatusHandler.getStatus(diffPath.propertiesStatus)); - // for "file + url" pair - statuses determine changes needs to be done to "url" to get "file" state - // for "url1 + url2" pair - statuses determine changes needs to be done to "url1" to get "url2" state + // statuses determine changes needs to be done to "target1" to get "target2" state ContentRevision beforeRevision = status == FileStatus.ADDED ? null - : target1.isFile() - ? createRemoteRevision(target2Path, target1Path, status) - : createRemoteRevision(target1Path, target2Path, status); + : createRevision(target1Path, target2Path, target1.getPegRevision(), status); ContentRevision afterRevision = status == FileStatus.DELETED ? null - : target1.isFile() - ? createLocalRevision(target1Path) - : createRemoteRevision(target2Path, target1Path, status); - + : createRevision(target2Path, target1Path, target2.getPegRevision(), status); return createChange(status, beforeRevision, afterRevision); } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DiffClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DiffClient.java index 35c35e9313f1..dfa43ddcb4bd 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DiffClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DiffClient.java @@ -29,6 +29,11 @@ import java.util.List; */ public interface DiffClient extends SvnClient { + /** + * @param target1 Should always be url. + * @param target2 Could be either url or file. And should be directory if file. + */ + @NotNull List<Change> compare(@NotNull SvnTarget target1, @NotNull SvnTarget target2) throws VcsException; void unifiedDiff(@NotNull SvnTarget target1, @NotNull SvnTarget target2, @NotNull OutputStream output) throws VcsException; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DirectoryWithBranchComparer.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DirectoryWithBranchComparer.java index 0f0e6a714037..784548d9e661 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DirectoryWithBranchComparer.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/DirectoryWithBranchComparer.java @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnBundle; +import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.WorkingCopyFormat; import org.jetbrains.idea.svn.api.ClientFactory; import org.tmatesoft.svn.core.SVNException; @@ -53,19 +54,24 @@ public class DirectoryWithBranchComparer extends ElementWithBranchComparer { titleBuilder.append(SvnBundle.message("repository.browser.compare.title", myElementUrl, FileUtil.toSystemDependentName(myVirtualFile.getPresentableUrl()))); - SvnTarget target1 = SvnTarget.fromFile(new File(myVirtualFile.getPath())); - SvnTarget target2 = SvnTarget.fromURL(myElementUrl); + SvnTarget target1 = SvnTarget.fromURL(myElementUrl); + SvnTarget target2 = SvnTarget.fromFile(new File(myVirtualFile.getPath())); changes.addAll(getClientFactory().createDiffClient().compare(target1, target2)); } @NotNull private ClientFactory getClientFactory() { - WorkingCopyFormat format = myVcs.getWorkingCopyFormat(VfsUtilCore.virtualToIoFile(myVirtualFile)); + return getClientFactory(myVcs, VfsUtilCore.virtualToIoFile(myVirtualFile)); + } + + @NotNull + public static ClientFactory getClientFactory(@NotNull SvnVcs vcs, @NotNull File file) { + WorkingCopyFormat format = vcs.getWorkingCopyFormat(file); // svn 1.7 command line "--summarize" option for "diff" command does not support comparing working copy directories with repository // directories - that is why command line is only used explicitly for svn 1.8 - return format.isOrGreater(WorkingCopyFormat.ONE_DOT_EIGHT) ? myVcs.getCommandLineFactory() : myVcs.getSvnKitFactory(); + return format.isOrGreater(WorkingCopyFormat.ONE_DOT_EIGHT) ? vcs.getCommandLineFactory() : vcs.getSvnKitFactory(); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/SvnKitDiffClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/SvnKitDiffClient.java index 0a1b14837b7e..ec4c51288cc2 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/SvnKitDiffClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/diff/SvnKitDiffClient.java @@ -54,6 +54,7 @@ import java.util.List; */ public class SvnKitDiffClient extends BaseSvnClient implements DiffClient { + @NotNull @Override public List<Change> compare(@NotNull SvnTarget target1, @NotNull SvnTarget target2) throws VcsException { DiffExecutor executor = new DiffExecutor(target1, target2); @@ -99,12 +100,12 @@ public class SvnKitDiffClient extends BaseSvnClient implements DiffClient { } public void run() throws SVNException { - assertUrl(myTarget2); + assertUrl(myTarget1); - if (myTarget1.isFile()) { - assertDirectory(myTarget1); + if (myTarget2.isFile()) { + assertDirectory(myTarget2); - WorkingCopyFormat format = myVcs.getWorkingCopyFormat(myTarget1.getFile()); + WorkingCopyFormat format = myVcs.getWorkingCopyFormat(myTarget2.getFile()); myChanges.addAll(WorkingCopyFormat.ONE_DOT_SIX.equals(format) ? run16Diff() : run17Diff()); } else { @@ -142,20 +143,20 @@ public class SvnKitDiffClient extends BaseSvnClient implements DiffClient { } private Collection<Change> run17Diff() throws SVNException { - final Info info1 = myVcs.getInfo(myTarget1.getFile(), SVNRevision.HEAD); + final Info info1 = myVcs.getInfo(myTarget2.getFile(), SVNRevision.HEAD); if (info1 == null) { SVNErrorMessage err = - SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "''{0}'' is not under version control", myTarget1); + SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "''{0}'' is not under version control", myTarget2); SVNErrorManager.error(err, SVNLogType.WC); } else if (info1.getURL() == null) { - SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", myTarget1); + SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", myTarget2); SVNErrorManager.error(err, SVNLogType.WC); } final SVNReporter17 reporter17 = - new SVNReporter17(myTarget1.getFile(), new SVNWCContext(myVcs.getSvnKitManager().getSvnOptions(), new ISVNEventHandler() { + new SVNReporter17(myTarget2.getFile(), new SVNWCContext(myVcs.getSvnKitManager().getSvnOptions(), new ISVNEventHandler() { @Override public void handleEvent(SVNEvent event, double progress) throws SVNException { } @@ -169,9 +170,9 @@ public class SvnKitDiffClient extends BaseSvnClient implements DiffClient { try { repository = myVcs.getSvnKitManager().createRepository(info1.getURL()); long rev = repository.getLatestRevision(); - repository2 = myVcs.getSvnKitManager().createRepository(myTarget2.getURL()); - SvnDiffEditor diffEditor = new SvnDiffEditor(myTarget1.getFile(), repository2, rev, true); - repository.diff(myTarget2.getURL(), rev, rev, null, true, SVNDepth.INFINITY, false, reporter17, + repository2 = myVcs.getSvnKitManager().createRepository(myTarget1.getURL()); + SvnDiffEditor diffEditor = new SvnDiffEditor(myTarget2.getFile(), repository2, rev, true); + repository.diff(myTarget1.getURL(), rev, rev, null, true, SVNDepth.INFINITY, false, reporter17, SVNCancellableEditor.newInstance(diffEditor, new SvnKitProgressCanceller(), null)); return diffEditor.getChangesMap().values(); @@ -193,7 +194,7 @@ public class SvnKitDiffClient extends BaseSvnClient implements DiffClient { SVNRepository repository = null; SVNRepository repository2 = null; try { - SVNAdminAreaInfo info = wcAccess.openAnchor(myTarget1.getFile(), false, SVNWCAccess.INFINITE_DEPTH); + SVNAdminAreaInfo info = wcAccess.openAnchor(myTarget2.getFile(), false, SVNWCAccess.INFINITE_DEPTH); File anchorPath = info.getAnchor().getRoot(); String target = "".equals(info.getTargetName()) ? null : info.getTargetName(); @@ -215,10 +216,10 @@ public class SvnKitDiffClient extends BaseSvnClient implements DiffClient { repository = myVcs.getSvnKitManager().createRepository(anchorURL.toString()); long rev = repository.getLatestRevision(); repository2 = - myVcs.getSvnKitManager().createRepository((target == null) ? myTarget2.getURL() : myTarget2.getURL().removePathTail()); + myVcs.getSvnKitManager().createRepository((target == null) ? myTarget1.getURL() : myTarget1.getURL().removePathTail()); SvnDiffEditor diffEditor = - new SvnDiffEditor(target == null ? myTarget1.getFile() : myTarget1.getFile().getParentFile(), repository2, rev, true); - repository.diff(myTarget2.getURL(), rev, rev, target, true, true, false, reporter, + new SvnDiffEditor(target == null ? myTarget2.getFile() : myTarget2.getFile().getParentFile(), repository2, rev, true); + repository.diff(myTarget1.getURL(), rev, rev, target, true, true, false, reporter, SVNCancellableEditor.newInstance(diffEditor, new SvnKitProgressCanceller(), null)); return diffEditor.getChangesMap().values(); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnDiffFromHistoryHandler.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnDiffFromHistoryHandler.java new file mode 100644 index 000000000000..be112127ecc9 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnDiffFromHistoryHandler.java @@ -0,0 +1,80 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.history; + +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.history.BaseDiffFromHistoryHandler; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnUtil; +import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.api.ClientFactory; +import org.jetbrains.idea.svn.diff.DirectoryWithBranchComparer; +import org.tmatesoft.svn.core.wc.SVNRevision; +import org.tmatesoft.svn.core.wc2.SvnTarget; + +import java.io.File; +import java.util.List; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnDiffFromHistoryHandler extends BaseDiffFromHistoryHandler<SvnFileRevision> { + + @NotNull private final SvnVcs myVcs; + + public SvnDiffFromHistoryHandler(@NotNull SvnVcs vcs) { + super(vcs.getProject()); + myVcs = vcs; + } + + @NotNull + @Override + protected List<Change> getChangesBetweenRevisions(@NotNull FilePath path, @NotNull SvnFileRevision rev1, @Nullable SvnFileRevision rev2) + throws VcsException { + File file = path.getIOFile(); + SvnTarget target1 = SvnTarget.fromURL(SvnUtil.createUrl(rev1.getURL()), rev1.getRevision()); + SvnTarget target2 = rev2 != null ? SvnTarget.fromURL(SvnUtil.createUrl(rev2.getURL()), rev2.getRevision()) : SvnTarget.fromFile(file); + + return executeDiff(path, target1, target2); + } + + @NotNull + @Override + protected List<Change> getAffectedChanges(@NotNull FilePath path, @NotNull SvnFileRevision rev) throws VcsException { + // Diff with zero revision is used here to get just affected changes under the path, and not all affected changes of the revision. + SvnTarget target1 = SvnTarget.fromURL(SvnUtil.createUrl(rev.getURL()), SVNRevision.create(0)); + SvnTarget target2 = SvnTarget.fromURL(SvnUtil.createUrl(rev.getURL()), rev.getRevision()); + + return executeDiff(path, target1, target2); + } + + @NotNull + @Override + protected String getPresentableName(@NotNull SvnFileRevision revision) { + return revision.getRevisionNumber().asString(); + } + + @NotNull + private List<Change> executeDiff(@NotNull FilePath path, @NotNull SvnTarget target1, @NotNull SvnTarget target2) throws VcsException { + File file = path.getIOFile(); + ClientFactory factory = target2.isURL() ? myVcs.getFactory(file) : DirectoryWithBranchComparer.getClientFactory(myVcs, file); + + return factory.createDiffClient().compare(target1, target2); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java index d2b820607ff4..8d1830763fc6 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnEditCommitMessageAction.java @@ -40,8 +40,8 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnUtil; import org.jetbrains.idea.svn.SvnVcs; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.SVNException; -import org.tmatesoft.svn.core.SVNPropertyValue; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -145,7 +145,7 @@ public class SvnEditCommitMessageAction extends AnAction { } SvnTarget target = SvnTarget.fromURL(root); myVcs.getFactory(target).createPropertyClient() - .setRevisionProperty(target, SvnPropertyKeys.LOG, SVNRevision.create(myNumber), SVNPropertyValue.create(myNewMessage), false); + .setRevisionProperty(target, SvnPropertyKeys.LOG, SVNRevision.create(myNumber), PropertyValue.create(myNewMessage), false); } catch (SVNException e) { myException = new VcsException(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java index 9e9dd7e1befc..b23b57772535 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistoryProvider.java @@ -73,7 +73,7 @@ public class SvnHistoryProvider @Override public DiffFromHistoryHandler getHistoryDiffHandler() { - return null; + return new SvnDiffFromHistoryHandler(myVcs); } @Override diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java index f2f91bceec14..8ae2da7cf8b3 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnHistorySession.java @@ -77,11 +77,6 @@ public class SvnHistorySession extends VcsAbstractHistorySession { return myCommittedPath; } - @Override - public boolean isContentAvailable(final VcsFileRevision revision) { - return !myCommittedPath.isDirectory(); - } - public boolean isHaveMergeSources() { return myHaveMergeSources; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/ignore/SvnPropertyService.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/ignore/SvnPropertyService.java index 8a9dbf760922..e0bdc15f78b1 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/ignore/SvnPropertyService.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/ignore/SvnPropertyService.java @@ -24,8 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.api.Depth; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -68,7 +67,7 @@ public class SvnPropertyService { protected final boolean myCanUseCachedProperty; protected abstract void processFolder(final VirtualFile folder, final File folderDir, final Set<String> data, - final SVNPropertyValue propertyValue) throws VcsException; + final PropertyValue propertyValue) throws VcsException; protected abstract void onAfterProcessing(final VirtualFile[] file) throws VcsException; @@ -92,14 +91,12 @@ public class SvnPropertyService { } final File dir = new File(entry.getKey().getPath()); try { - final SVNPropertyValue value; + final PropertyValue value; if (myCanUseCachedProperty) { value = myVcs.getPropertyWithCaching(entry.getKey(), SvnPropertyKeys.SVN_IGNORE); } else { - final SVNPropertyData data = - myVcs.getFactory(dir).createPropertyClient() - .getProperty(SvnTarget.fromFile(dir), SvnPropertyKeys.SVN_IGNORE, false, SVNRevision.WORKING); - value = data == null ? null : data.getValue(); + value = myVcs.getFactory(dir).createPropertyClient() + .getProperty(SvnTarget.fromFile(dir), SvnPropertyKeys.SVN_IGNORE, false, SVNRevision.WORKING); } processFolder(entry.getKey(), dir, entry.getValue(), value); } @@ -127,7 +124,7 @@ public class SvnPropertyService { return (! myFilesOk) && (! myExtensionOk); } - protected void processFolder(final VirtualFile folder, final File folderDir, final Set<String> data, final SVNPropertyValue propertyValue) + protected void processFolder(final VirtualFile folder, final File folderDir, final Set<String> data, final PropertyValue propertyValue) throws VcsException { if (propertyValue == null) { myFilesOk = false; @@ -135,7 +132,7 @@ public class SvnPropertyService { return; } final Set<String> ignorePatterns = new HashSet<String>(); - final StringTokenizer st = new StringTokenizer(SVNPropertyValue.getPropertyAsString(propertyValue), "\r\n "); + final StringTokenizer st = new StringTokenizer(PropertyValue.toString(propertyValue), "\r\n "); while (st.hasMoreElements()) { final String ignorePattern = (String)st.nextElement(); ignorePatterns.add(ignorePattern); @@ -180,14 +177,14 @@ public class SvnPropertyService { return false; } - protected abstract String getNewPropertyValue(final Set<String> data, final SVNPropertyValue propertyValue); + protected abstract String getNewPropertyValue(final Set<String> data, final PropertyValue propertyValue); - protected void processFolder(final VirtualFile folder, final File folderDir, final Set<String> data, final SVNPropertyValue propertyValue) + protected void processFolder(final VirtualFile folder, final File folderDir, final Set<String> data, final PropertyValue propertyValue) throws VcsException { String newValue = getNewPropertyValue(data, propertyValue); newValue = (newValue.trim().isEmpty()) ? null : newValue; myVcs.getFactory(folderDir).createPropertyClient() - .setProperty(folderDir, SvnPropertyKeys.SVN_IGNORE, SVNPropertyValue.create(newValue), Depth.EMPTY, false); + .setProperty(folderDir, SvnPropertyKeys.SVN_IGNORE, PropertyValue.create(newValue), Depth.EMPTY, false); if (myUseCommonExtension) { dirtyScopeManager.dirDirtyRecursively(folder); @@ -216,9 +213,9 @@ public class SvnPropertyService { super(activeVcs, project, useCommonExtension); } - protected String getNewPropertyValue(final Set<String> data, final SVNPropertyValue propertyValue) { + protected String getNewPropertyValue(final Set<String> data, final PropertyValue propertyValue) { if (propertyValue != null) { - return getNewPropertyValueForRemove(data, SVNPropertyValue.getPropertyAsString(propertyValue)); + return getNewPropertyValueForRemove(data, PropertyValue.toString(propertyValue)); } return ""; } @@ -241,7 +238,7 @@ public class SvnPropertyService { super(activeVcs, project, useCommonExtension); } - protected String getNewPropertyValue(final Set<String> data, final SVNPropertyValue propertyValue) { + protected String getNewPropertyValue(final Set<String> data, final PropertyValue propertyValue) { final String ignoreString; if (data.size() == 1) { ignoreString = data.iterator().next(); @@ -252,7 +249,7 @@ public class SvnPropertyService { } ignoreString = sb.toString(); } - return (propertyValue == null) ? ignoreString : (SVNPropertyValue.getPropertyAsString(propertyValue) + '\n' + ignoreString); + return (propertyValue == null) ? ignoreString : (PropertyValue.toString(propertyValue) + '\n' + ignoreString); } } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/GatheringChangelistBuilder.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/GatheringChangelistBuilder.java index b6228fca921d..1e031e20d408 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/GatheringChangelistBuilder.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/integrate/GatheringChangelistBuilder.java @@ -20,7 +20,10 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsKey; -import com.intellij.openapi.vcs.changes.*; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ChangeList; +import com.intellij.openapi.vcs.changes.ChangesUtil; +import com.intellij.openapi.vcs.changes.EmptyChangelistBuilder; import com.intellij.openapi.vcs.update.UpdatedFilesReverseSide; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; @@ -28,12 +31,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnPropertyKeys; import org.jetbrains.idea.svn.SvnVcs; -import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; -import java.util.*; +import java.util.Iterator; +import java.util.List; +import java.util.Set; public class GatheringChangelistBuilder extends EmptyChangelistBuilder { @@ -92,13 +97,13 @@ public class GatheringChangelistBuilder extends EmptyChangelistBuilder { SvnTarget target = SvnTarget.fromFile(file); try { - SVNPropertyData current = + PropertyValue current = myVcs.getFactory(target).createPropertyClient().getProperty(target, SvnPropertyKeys.MERGE_INFO, false, SVNRevision.WORKING); - SVNPropertyData base = + PropertyValue base = myVcs.getFactory(target).createPropertyClient().getProperty(target, SvnPropertyKeys.MERGE_INFO, false, SVNRevision.BASE); if (current != null) { - return base == null || !Comparing.equal(current.getValue(), base.getValue()); + return base == null || !Comparing.equal(current, base); } } catch (VcsException e) { diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java index 62638291b485..701bb2575001 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/BranchInfo.java @@ -22,10 +22,10 @@ import com.intellij.util.containers.MultiMap; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.history.SvnChangeList; import org.jetbrains.idea.svn.info.Info; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNMergeInfoUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; -import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -205,7 +205,7 @@ public class BranchInfo { return SvnMergeInfoCache.MergeCheckResult.getInstance(mergeInfo.contains(revisionAsked)); } - final SVNPropertyData mergeinfoProperty; + final PropertyValue mergeinfoProperty; SvnTarget target = SvnTarget.fromURL(branchUrl); try { @@ -235,7 +235,7 @@ public class BranchInfo { return goUpInRepo(revisionAsked, targetRevision, newBranchUrl, newTrunkUrl); } // process - return processMergeinfoProperty(keyString, revisionAsked, mergeinfoProperty.getValue(), trunkUrl, false); + return processMergeinfoProperty(keyString, revisionAsked, mergeinfoProperty, trunkUrl, false); } private Info getInfo(final File pathFile) { @@ -277,7 +277,7 @@ public class BranchInfo { return SvnMergeInfoCache.MergeCheckResult.getInstance(merged); } - final SVNPropertyData mergeinfoProperty; + final PropertyValue mergeinfoProperty; try { if (actualRevision == targetRevisionCorrected) { // look in WC @@ -302,11 +302,11 @@ public class BranchInfo { return goUp(revisionAsked, targetRevisionCorrected, branchRootPath, path, trunkUrl); } // process - return processMergeinfoProperty(keyString, revisionAsked, mergeinfoProperty.getValue(), trunkUrl, self); + return processMergeinfoProperty(keyString, revisionAsked, mergeinfoProperty, trunkUrl, self); } private SvnMergeInfoCache.MergeCheckResult processMergeinfoProperty(final String pathWithRevisionNumber, final long revisionAsked, - final SVNPropertyValue value, final String trunkRelativeUrl, + final PropertyValue value, final String trunkRelativeUrl, final boolean self) { final String valueAsString = value.toString().trim(); @@ -318,7 +318,7 @@ public class BranchInfo { final Map<String, SVNMergeRangeList> map; try { - map = SVNMergeInfoUtil.parseMergeInfo(new StringBuffer(replaceSeparators(value.getString())), null); + map = SVNMergeInfoUtil.parseMergeInfo(new StringBuffer(replaceSeparators(value.toString())), null); } catch (SVNException e) { LOG.info(e); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java index 0ea95c99c4d4..225bc6ad0396 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/mergeinfo/OneRecursiveShotMergeInfoWorker.java @@ -23,11 +23,12 @@ import com.intellij.util.PairProcessor; import org.jetbrains.annotations.NotNull; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.dialogs.MergeContext; +import org.jetbrains.idea.svn.properties.PropertyConsumer; +import org.jetbrains.idea.svn.properties.PropertyData; +import org.jetbrains.idea.svn.properties.PropertyValue; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.internal.util.SVNMergeInfoUtil; import org.tmatesoft.svn.core.internal.util.SVNPathUtil; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -63,19 +64,19 @@ public class OneRecursiveShotMergeInfoWorker implements MergeInfoWorker { public void prepare() throws VcsException { final Depth depth = Depth.allOrEmpty(myMergeContext.getVcs().getSvnConfiguration().isCheckNestedForQuickMerge()); - ISVNPropertyHandler handler = new ISVNPropertyHandler() { - public void handleProperty(File path, SVNPropertyData property) throws SVNException { + PropertyConsumer handler = new PropertyConsumer() { + public void handleProperty(File path, PropertyData property) throws SVNException { final String key = keyFromFile(path); synchronized (myLock) { myDataMap.put(key, SVNMergeInfoUtil - .parseMergeInfo(new StringBuffer(replaceSeparators(SVNPropertyValue.getPropertyAsString(property.getValue()))), null)); + .parseMergeInfo(new StringBuffer(replaceSeparators(PropertyValue.toString(property.getValue()))), null)); } } - public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + public void handleProperty(SVNURL url, PropertyData property) throws SVNException { } - public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + public void handleProperty(long revision, PropertyData property) throws SVNException { } }; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java index e855abe1ec2e..e053776d14ce 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/CmdPropertyClient.java @@ -10,9 +10,8 @@ import org.jetbrains.idea.svn.commandLine.CommandExecutor; import org.jetbrains.idea.svn.commandLine.CommandUtil; import org.jetbrains.idea.svn.commandLine.SvnCommandName; import org.jetbrains.idea.svn.info.Info; -import org.tmatesoft.svn.core.*; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -24,6 +23,7 @@ import javax.xml.bind.annotation.XmlValue; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Map; /** * @author Konstantin Kolosovsky. @@ -32,10 +32,10 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { @Nullable @Override - public SVNPropertyData getProperty(@NotNull SvnTarget target, - @NotNull String property, - boolean revisionProperty, - @Nullable SVNRevision revision) + public PropertyValue getProperty(@NotNull SvnTarget target, + @NotNull String property, + boolean revisionProperty, + @Nullable SVNRevision revision) throws VcsException { List<String> parameters = new ArrayList<String>(); @@ -57,7 +57,9 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { parameters.add("--xml"); CommandExecutor command = execute(myVcs, target, SvnCommandName.propget, parameters, null); - return parseSingleProperty(target, command.getOutput()); + PropertyData data = parseSingleProperty(target, command.getOutput()); + + return data != null ? data.getValue() : null; } @Override @@ -65,7 +67,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { @NotNull String property, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException { + @Nullable PropertyConsumer handler) throws VcsException { List<String> parameters = new ArrayList<String>(); parameters.add(property); @@ -79,7 +81,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { public void list(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException { + @Nullable PropertyConsumer handler) throws VcsException { List<String> parameters = new ArrayList<String>(); fillListParameters(target, revision, depth, parameters, true); @@ -90,39 +92,39 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { @Override public void setProperty(@NotNull File file, @NotNull String property, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, @Nullable Depth depth, boolean force) throws VcsException { runSetProperty(SvnTarget.fromFile(file), property, null, depth, value, force); } @Override - public void setProperties(@NotNull File file, @NotNull SVNProperties properties) throws VcsException { - SVNProperties currentProperties = collectPropertiesToDelete(file); + public void setProperties(@NotNull File file, @NotNull PropertiesMap properties) throws VcsException { + PropertiesMap currentProperties = collectPropertiesToDelete(file); currentProperties.putAll(properties); - for (String propertyName : currentProperties.nameSet()) { - setProperty(file, propertyName, currentProperties.getSVNPropertyValue(propertyName), Depth.EMPTY, true); + for (Map.Entry<String, PropertyValue> entry : currentProperties.entrySet()) { + setProperty(file, entry.getKey(), entry.getValue(), Depth.EMPTY, true); } } @NotNull - private SVNProperties collectPropertiesToDelete(@NotNull File file) throws VcsException { - final SVNProperties result = new SVNProperties(); + private PropertiesMap collectPropertiesToDelete(@NotNull File file) throws VcsException { + final PropertiesMap result = new PropertiesMap(); - list(SvnTarget.fromFile(file), null, Depth.EMPTY, new ISVNPropertyHandler() { + list(SvnTarget.fromFile(file), null, Depth.EMPTY, new PropertyConsumer() { @Override - public void handleProperty(File path, SVNPropertyData property) throws SVNException { + public void handleProperty(File path, PropertyData property) throws SVNException { // null indicates property will be deleted - result.put(property.getName(), (SVNPropertyValue)null); + result.put(property.getName(), null); } @Override - public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + public void handleProperty(SVNURL url, PropertyData property) throws SVNException { } @Override - public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + public void handleProperty(long revision, PropertyData property) throws SVNException { } }); @@ -133,7 +135,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { public void setRevisionProperty(@NotNull SvnTarget target, @NotNull String property, @NotNull SVNRevision revision, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, boolean force) throws VcsException { runSetProperty(target, property, revision, null, value, force); } @@ -142,7 +144,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { @NotNull String property, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, boolean force) throws VcsException { List<String> parameters = new ArrayList<String>(); boolean isDelete = value == null; @@ -153,7 +155,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { CommandUtil.put(parameters, revision); } if (!isDelete) { - parameters.add(SVNPropertyValue.getPropertyAsString(value)); + parameters.add(PropertyValue.toString(value)); // --force could only be used in "propset" command, but not in "propdel" command CommandUtil.put(parameters, force, "--force"); } @@ -180,21 +182,22 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { CommandUtil.put(parameters, verbose, "--verbose"); } - private SVNPropertyData parseSingleProperty(SvnTarget target, String output) throws VcsException { - final SVNPropertyData[] data = new SVNPropertyData[1]; - ISVNPropertyHandler handler = new ISVNPropertyHandler() { + @Nullable + private PropertyData parseSingleProperty(SvnTarget target, String output) throws VcsException { + final PropertyData[] data = new PropertyData[1]; + PropertyConsumer handler = new PropertyConsumer() { @Override - public void handleProperty(File path, SVNPropertyData property) throws SVNException { + public void handleProperty(File path, PropertyData property) throws SVNException { data[0] = property; } @Override - public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + public void handleProperty(SVNURL url, PropertyData property) throws SVNException { data[0] = property; } @Override - public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + public void handleProperty(long revision, PropertyData property) throws SVNException { data[0] = property; } }; @@ -204,7 +207,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { return data[0]; } - private static void parseOutput(SvnTarget target, String output, ISVNPropertyHandler handler) throws VcsException { + private static void parseOutput(SvnTarget target, String output, PropertyConsumer handler) throws VcsException { try { Properties properties = CommandUtil.parse(output, Properties.class); @@ -231,7 +234,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { } } - private static void invokeHandler(@NotNull SvnTarget target, @Nullable SVNPropertyData data, @Nullable ISVNPropertyHandler handler) + private static void invokeHandler(@NotNull SvnTarget target, @Nullable PropertyData data, @Nullable PropertyConsumer handler) throws SVNException { if (handler != null && data != null) { if (target.isFile()) { @@ -242,7 +245,7 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { } } - private static void invokeHandler(long revision, @Nullable SVNPropertyData data, @Nullable ISVNPropertyHandler handler) + private static void invokeHandler(long revision, @Nullable PropertyData data, @Nullable PropertyConsumer handler) throws SVNException { if (handler != null && data != null) { handler.handleProperty(revision, data); @@ -250,13 +253,13 @@ public class CmdPropertyClient extends BaseSvnClient implements PropertyClient { } @Nullable - private static SVNPropertyData create(@NotNull String property, @Nullable String value) { - SVNPropertyData result = null; + private static PropertyData create(@NotNull String property, @Nullable String value) { + PropertyData result = null; // such behavior is required to compatibility with SVNKit as some logic in merge depends on // whether null property data or property data with empty string value is returned if (value != null) { - result = new SVNPropertyData(property, SVNPropertyValue.create(value.trim()), LF_SEPARATOR_OPTIONS); + result = new PropertyData(property, PropertyValue.create(value.trim())); } return result; diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/ExternalsDefinitionParser.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/ExternalsDefinitionParser.java new file mode 100644 index 000000000000..b3ec74e397cb --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/ExternalsDefinitionParser.java @@ -0,0 +1,106 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.properties; + +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.commandLine.SvnBindException; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Konstantin Kolosovsky. + */ +public class ExternalsDefinitionParser { + + /** + * Parses "svn:externals" property in format starting from svn 1.5. + * + * @return map of externals definitions: key - relative directory, value - corresponding complete externals definition. + */ + @NotNull + public static Map<String, String> parseExternalsProperty(@NotNull String externals) throws SvnBindException { + HashMap<String, String> map = ContainerUtil.newHashMap(); + + for (String external : StringUtil.splitByLines(externals, true)) { + map.put(parseRelativeDirectory(external), external); + } + + return map; + } + + /** + * Parses relative directory from externals definition (in format starting from svn 1.5). Restrictions for relative directory: + * - is at the end of externals definition separated from other parameters by ' ' char + * - could be quoted with '"' char + * - certain chars could be escaped with '\' char + */ + @NotNull + public static String parseRelativeDirectory(@NotNull String s) throws SvnBindException { + s = s.trim(); + + int length = s.length(); + String result; + + if (isUnescapedQuote(s, length - 1)) { + int index = lastUnescapedIndexOf(s, length - 1, '"'); + assertIndex(s, index, "Could not find start quote"); + result = s.substring(index + 1, length - 1); + } + else { + int index = lastUnescapedIndexOf(s, length, ' '); + assertIndex(s, index, "Could not find separating space"); + result = s.substring(index + 1); + } + + return unescape(result); + } + + private static void assertIndex(@NotNull String s, int index, @NotNull String message) throws SvnBindException { + if (index < 0) { + throw new SvnBindException(message + " - " + s); + } + } + + @NotNull + private static String unescape(@NotNull String s) { + return s.replace("\\", ""); + } + + /** + * "from" index is excluded. + */ + private static int lastUnescapedIndexOf(@NotNull String s, int from, char c) { + int result = from; + + do { + result = s.lastIndexOf(c, result - 1); + } + while (result != -1 && !isUnescaped(s, result, c)); + + return result; + } + + private static boolean isUnescapedQuote(@NotNull String s, int index) { + return isUnescaped(s, index, '"'); + } + + private static boolean isUnescaped(@NotNull String s, int index, char c) { + return StringUtil.isChar(s, index, c) && !StringUtil.isChar(s, index - 1, '\\'); + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertiesMap.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertiesMap.java new file mode 100644 index 000000000000..c5857aa4b345 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertiesMap.java @@ -0,0 +1,24 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.properties; + +import com.intellij.util.containers.HashMap; + +/** + * @author Konstantin Kolosovsky. + */ +public class PropertiesMap extends HashMap<String, PropertyValue> { +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java index 1b61d59c0e20..42acfc8109d7 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyClient.java @@ -1,18 +1,10 @@ package org.jetbrains.idea.svn.properties; import com.intellij.openapi.vcs.VcsException; -import com.intellij.openapi.vfs.CharsetToolkit; -import com.intellij.util.LineSeparator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.api.SvnClient; -import org.tmatesoft.svn.core.SVNProperties; -import org.tmatesoft.svn.core.SVNPropertyValue; -import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; -import org.tmatesoft.svn.core.wc.ISVNOptions; -import org.tmatesoft.svn.core.wc.ISVNPropertyHandler; -import org.tmatesoft.svn.core.wc.SVNPropertyData; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -23,40 +15,33 @@ import java.io.File; */ public interface PropertyClient extends SvnClient { - ISVNOptions LF_SEPARATOR_OPTIONS = new DefaultSVNOptions() { - @Override - public byte[] getNativeEOL() { - return CharsetToolkit.getUtf8Bytes(LineSeparator.LF.getSeparatorString()); - } - }; - @Nullable - SVNPropertyData getProperty(@NotNull final SvnTarget target, - @NotNull final String property, - boolean revisionProperty, - @Nullable SVNRevision revision) throws VcsException; + PropertyValue getProperty(@NotNull final SvnTarget target, + @NotNull final String property, + boolean revisionProperty, + @Nullable SVNRevision revision) throws VcsException; void getProperty(@NotNull SvnTarget target, @NotNull String property, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException; + @Nullable PropertyConsumer handler) throws VcsException; void list(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException; + @Nullable PropertyConsumer handler) throws VcsException; void setProperty(@NotNull File file, @NotNull String property, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, @Nullable Depth depth, boolean force) throws VcsException; - void setProperties(@NotNull File file, @NotNull SVNProperties properties) throws VcsException; + void setProperties(@NotNull File file, @NotNull PropertiesMap properties) throws VcsException; void setRevisionProperty(@NotNull SvnTarget target, @NotNull String property, @NotNull SVNRevision revision, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, boolean force) throws VcsException; } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyConsumer.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyConsumer.java new file mode 100644 index 000000000000..f45e09df39d5 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyConsumer.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.properties; + +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.SVNURL; + +import java.io.File; + +/** + * @author Konstantin Kolosovsky. + */ +public interface PropertyConsumer { + + void handleProperty(File path, PropertyData property) throws SVNException; + + void handleProperty(SVNURL url, PropertyData property) throws SVNException; + + void handleProperty(long revision, PropertyData property) throws SVNException; +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyData.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyData.java new file mode 100644 index 000000000000..3953636d870c --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyData.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.properties; + +import org.jetbrains.annotations.Nullable; +import org.tmatesoft.svn.core.wc.SVNPropertyData; + +/** + * @author Konstantin Kolosovsky. + */ +public class PropertyData { + + private final PropertyValue myValue; + + private final String myName; + + public PropertyData(String name, PropertyValue value) { + myName = name; + myValue = value; + } + + public String getName() { + return myName; + } + + public PropertyValue getValue() { + return myValue; + } + + @Nullable + public static PropertyData create(@Nullable SVNPropertyData data) { + PropertyData result = null; + + if (data != null) { + result = new PropertyData(data.getName(), PropertyValue.create(data.getValue())); + } + + return result; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyValue.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyValue.java new file mode 100644 index 000000000000..62cb7cbd0340 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/PropertyValue.java @@ -0,0 +1,53 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.properties; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.tmatesoft.svn.core.SVNPropertyValue; + +/** + * TODO: Add correct support of binary properties - support in api, diff, etc. + * + * @author Konstantin Kolosovsky. + */ +public class PropertyValue { + + @NotNull private final String myValue; + + @Nullable + public static PropertyValue create(@Nullable SVNPropertyValue value) { + return create(SVNPropertyValue.getPropertyAsString(value)); + } + + private PropertyValue(@NotNull String propertyValue) { + myValue = propertyValue; + } + + @Nullable + public static PropertyValue create(@Nullable String propertyValue) { + return propertyValue == null ? null : new PropertyValue(propertyValue); + } + + @Nullable + public static String toString(@Nullable PropertyValue value) { + return value == null ? null : value.myValue; + } + + public String toString() { + return myValue; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java index 4ad3f10afccc..23fedd3c7ac8 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/properties/SvnKitPropertyClient.java @@ -1,42 +1,57 @@ package org.jetbrains.idea.svn.properties; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.CharsetToolkit; +import com.intellij.util.LineSeparator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.api.BaseSvnClient; import org.jetbrains.idea.svn.api.Depth; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.tmatesoft.svn.core.*; +import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions; import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.core.wc2.SvnTarget; import java.io.File; +import java.util.Map; /** * @author Konstantin Kolosovsky. */ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClient { + public static final ISVNOptions LF_SEPARATOR_OPTIONS = new DefaultSVNOptions() { + @Override + public byte[] getNativeEOL() { + return CharsetToolkit.getUtf8Bytes(LineSeparator.LF.getSeparatorString()); + } + }; + @Nullable @Override - public SVNPropertyData getProperty(@NotNull SvnTarget target, - @NotNull String property, - boolean revisionProperty, - @Nullable SVNRevision revision) throws VcsException { + public PropertyValue getProperty(@NotNull SvnTarget target, + @NotNull String property, + boolean revisionProperty, + @Nullable SVNRevision revision) throws VcsException { + PropertyData resultData; + try { if (!revisionProperty) { if (target.isFile()) { - return createClient().doGetProperty(target.getFile(), property, target.getPegRevision(), revision); + resultData = PropertyData.create(createClient().doGetProperty(target.getFile(), property, target.getPegRevision(), revision)); } else { - return createClient().doGetProperty(target.getURL(), property, target.getPegRevision(), revision); + resultData = PropertyData.create(createClient().doGetProperty(target.getURL(), property, target.getPegRevision(), revision)); } } else { - return getRevisionProperty(target, property, revision); + resultData = getRevisionProperty(target, property, revision); } } catch (SVNException e) { throw new VcsException(e); } + + return resultData != null ? resultData.getValue() : null; } @NotNull @@ -52,7 +67,7 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien @NotNull String property, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException { + @Nullable PropertyConsumer handler) throws VcsException { runGetProperty(target, property, revision, depth, handler); } @@ -60,18 +75,18 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien public void list(@NotNull SvnTarget target, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException { + @Nullable PropertyConsumer handler) throws VcsException { runGetProperty(target, null, revision, depth, handler); } @Override public void setProperty(@NotNull File file, @NotNull String property, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, @Nullable Depth depth, boolean force) throws VcsException { try { - createClient().doSetProperty(file, property, value, force, toDepth(depth), null, null); + createClient().doSetProperty(file, property, toPropertyValue(value), force, toDepth(depth), null, null); } catch (SVNException e) { throw new SvnBindException(e); @@ -79,12 +94,13 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien } @Override - public void setProperties(@NotNull File file, @NotNull SVNProperties properties) throws VcsException { + public void setProperties(@NotNull File file, @NotNull PropertiesMap properties) throws VcsException { + final SVNProperties propertiesToSet = toSvnProperties(properties); try { createClient().doSetProperty(file, new ISVNPropertyValueProvider() { @Override public SVNProperties providePropertyValues(File path, SVNProperties properties) throws SVNException { - return properties; + return propertiesToSet; } }, true, SVNDepth.EMPTY, null, null); } @@ -97,14 +113,14 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien public void setRevisionProperty(@NotNull SvnTarget target, @NotNull String property, @NotNull SVNRevision revision, - @Nullable SVNPropertyValue value, + @Nullable PropertyValue value, boolean force) throws VcsException { try { if (target.isFile()) { - createClient().doSetRevisionProperty(target.getFile(), revision, property, value, force, null); + createClient().doSetRevisionProperty(target.getFile(), revision, property, toPropertyValue(value), force, null); } else { - createClient().doSetRevisionProperty(target.getURL(), revision, property, value, force, null); + createClient().doSetRevisionProperty(target.getURL(), revision, property, toPropertyValue(value), force, null); } } catch (SVNException e) { @@ -112,27 +128,39 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien } } + @NotNull + private static SVNProperties toSvnProperties(@NotNull PropertiesMap properties) { + SVNProperties result = new SVNProperties(); + + for (Map.Entry<String, PropertyValue> entry : properties.entrySet()) { + result.put(entry.getKey(), toPropertyValue(entry.getValue())); + } + + return result; + } + private void runGetProperty(@NotNull SvnTarget target, @Nullable String property, @Nullable SVNRevision revision, @Nullable Depth depth, - @Nullable ISVNPropertyHandler handler) throws VcsException { + @Nullable PropertyConsumer handler) throws VcsException { SVNWCClient client = createClient(); try { if (target.isURL()) { - client.doGetProperty(target.getURL(), property, target.getPegRevision(), revision, toDepth(depth), handler); + client.doGetProperty(target.getURL(), property, target.getPegRevision(), revision, toDepth(depth), toHandler(handler)); } else { - client.doGetProperty(target.getFile(), property, target.getPegRevision(), revision, toDepth(depth), handler, null); + client.doGetProperty(target.getFile(), property, target.getPegRevision(), revision, toDepth(depth), toHandler(handler), null); } } catch (SVNException e) { throw new VcsException(e); } } - private SVNPropertyData getRevisionProperty(@NotNull SvnTarget target, @NotNull final String property, @Nullable SVNRevision revision) throws SVNException{ + private PropertyData getRevisionProperty(@NotNull SvnTarget target, @NotNull final String property, @Nullable SVNRevision revision) + throws SVNException { final SVNWCClient client = createClient(); - final SVNPropertyData[] result = new SVNPropertyData[1]; + final PropertyData[] result = new PropertyData[1]; ISVNPropertyHandler handler = new ISVNPropertyHandler() { @Override public void handleProperty(File path, SVNPropertyData property) throws SVNException { @@ -151,7 +179,7 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien private void handle(@NotNull SVNPropertyData data) { if (property.equals(data.getName())) { - result[0] = data; + result[0] = PropertyData.create(data); } } }; @@ -164,4 +192,41 @@ public class SvnKitPropertyClient extends BaseSvnClient implements PropertyClien return result[0]; } + + @Nullable + private static ISVNPropertyHandler toHandler(@Nullable final PropertyConsumer consumer) { + ISVNPropertyHandler result = null; + + if (consumer != null) { + result = new ISVNPropertyHandler() { + @Override + public void handleProperty(File path, SVNPropertyData property) throws SVNException { + consumer.handleProperty(path, PropertyData.create(property)); + } + + @Override + public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + consumer.handleProperty(url, PropertyData.create(property)); + } + + @Override + public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + consumer.handleProperty(revision, PropertyData.create(property)); + } + }; + } + + return result; + } + + @Nullable + private static SVNPropertyValue toPropertyValue(@Nullable PropertyValue value) { + SVNPropertyValue result = null; + + if (value != null) { + result = SVNPropertyValue.create(value.toString()); + } + + return result; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java index 237d05bd5f7a..7b09461b3766 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/rollback/SvnRollbackEnvironment.java @@ -34,6 +34,9 @@ import org.jetbrains.idea.svn.api.ProgressEvent; import org.jetbrains.idea.svn.api.ProgressTracker; import org.jetbrains.idea.svn.commandLine.SvnBindException; import org.jetbrains.idea.svn.info.Info; +import org.jetbrains.idea.svn.properties.PropertiesMap; +import org.jetbrains.idea.svn.properties.PropertyConsumer; +import org.jetbrains.idea.svn.properties.PropertyData; import org.tmatesoft.svn.core.*; import org.tmatesoft.svn.core.wc.*; import org.tmatesoft.svn.core.wc2.SvnTarget; @@ -100,7 +103,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { }; final List<CopiedAsideInfo> fromToModified = new ArrayList<CopiedAsideInfo>(); - final Map<File, SVNProperties> properties = ContainerUtil.newHashMap(); + final Map<File, PropertiesMap> properties = ContainerUtil.newHashMap(); moveRenamesToTmp(exceptions, fromToModified, properties, collector); // adds (deletes) // deletes (adds) @@ -123,29 +126,29 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { private void moveRenamesToTmp(List<VcsException> exceptions, List<CopiedAsideInfo> fromToModified, - final Map<File, SVNProperties> properties, + final Map<File, PropertiesMap> properties, final UnversionedAndNotTouchedFilesGroupCollector collector) { final Map<File, ThroughRenameInfo> fromTo = collector.getFromTo(); try { final File tmp = FileUtil.createTempDirectory("forRename", ""); - final ISVNPropertyHandler handler = new ISVNPropertyHandler() { + final PropertyConsumer handler = new PropertyConsumer() { @Override - public void handleProperty(File path, SVNPropertyData property) throws SVNException { + public void handleProperty(File path, PropertyData property) throws SVNException { final ThroughRenameInfo info = collector.findToFile(new FilePathImpl(path, path.isDirectory()), null); if (info != null) { if (!properties.containsKey(info.getTo())) { - properties.put(info.getTo(), new SVNProperties()); + properties.put(info.getTo(), new PropertiesMap()); } properties.get(info.getTo()).put(property.getName(), property.getValue()); } } @Override - public void handleProperty(SVNURL url, SVNPropertyData property) throws SVNException { + public void handleProperty(SVNURL url, PropertyData property) throws SVNException { } @Override - public void handleProperty(long revision, SVNPropertyData property) throws SVNException { + public void handleProperty(long revision, PropertyData property) throws SVNException { } }; @@ -181,7 +184,7 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { private void moveGroup(final List<VcsException> exceptions, List<CopiedAsideInfo> fromTo, - Map<File, SVNProperties> properties) { + Map<File, PropertiesMap> properties) { Collections.sort(fromTo, new Comparator<CopiedAsideInfo>() { @Override public int compare(CopiedAsideInfo o1, CopiedAsideInfo o2) { @@ -240,8 +243,8 @@ public class SvnRollbackEnvironment extends DefaultRollbackEnvironment { applyProperties(properties, exceptions); } - private void applyProperties(Map<File, SVNProperties> propertiesMap, final List<VcsException> exceptions) { - for (Map.Entry<File, SVNProperties> entry : propertiesMap.entrySet()) { + private void applyProperties(Map<File, PropertiesMap> propertiesMap, final List<VcsException> exceptions) { + for (Map.Entry<File, PropertiesMap> entry : propertiesMap.entrySet()) { File file = entry.getKey(); try { mySvnVcs.getFactory(file).createPropertyClient().setProperties(file, entry.getValue()); diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitAdminAreaFactorySelector.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitAdminAreaFactorySelector.java new file mode 100644 index 000000000000..0d1a4c0106e0 --- /dev/null +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitAdminAreaFactorySelector.java @@ -0,0 +1,137 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn.svnkit; + +import com.intellij.openapi.application.ApplicationManager; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.svn.SvnFormatSelector; +import org.jetbrains.idea.svn.SvnWorkingCopyFormatHolder; +import org.jetbrains.idea.svn.WorkingCopyFormat; +import org.tmatesoft.svn.core.SVNErrorCode; +import org.tmatesoft.svn.core.SVNErrorMessage; +import org.tmatesoft.svn.core.SVNException; +import org.tmatesoft.svn.core.internal.wc.admin.ISVNAdminAreaFactorySelector; +import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaFactory; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +/** + * @author Konstantin Kolosovsky. + */ +public class SvnKitAdminAreaFactorySelector implements ISVNAdminAreaFactorySelector { + + public Collection getEnabledFactories(File path, Collection factories, boolean writeAccess) throws SVNException { + if (ApplicationManager.getApplication().isUnitTestMode()) { + return factories; + } + + if (!writeAccess) { + return factories; + } + + Collection result = null; + final WorkingCopyFormat presetFormat = SvnWorkingCopyFormatHolder.getPresetFormat(); + if (presetFormat != null) { + result = format2Factories(presetFormat, factories); + } + + if (result == null) { + final WorkingCopyFormat format = SvnFormatSelector.getWorkingCopyFormat(path); + result = format2Factories(format, factories); + } + + if (result == null) { + throw new SVNException(SVNErrorMessage.create(SVNErrorCode.WC_NOT_DIRECTORY)); + } + return result; + } + + @Nullable + static Collection format2Factories(final WorkingCopyFormat format, final Collection factories) { + if (WorkingCopyFormat.ONE_DOT_SEVEN.equals(format)) { + return factories; + } + else if (WorkingCopyFormat.ONE_DOT_SIX.equals(format)) { + return factoriesFor16(factories); + } + else if (WorkingCopyFormat.ONE_DOT_FIVE.equals(format)) { + return factoriesFor15(factories); + } + else if (WorkingCopyFormat.ONE_DOT_FOUR.equals(format)) { + return factoriesFor14(factories); + } + else if (WorkingCopyFormat.ONE_DOT_THREE.equals(format)) { + return factoriesFor13(factories); + } + return null; + } + + private static Collection<SVNAdminAreaFactory> factoriesFor13(final Collection factories) { + for (Object item : factories) { + final SVNAdminAreaFactory factory = (SVNAdminAreaFactory)item; + final int supportedVersion = factory.getSupportedVersion(); + if (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) { + return Collections.singletonList(factory); + } + } + return Collections.emptyList(); + } + + private static Collection<SVNAdminAreaFactory> factoriesFor14(final Collection factories) { + final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2); + for (Object item : factories) { + final SVNAdminAreaFactory factory = (SVNAdminAreaFactory)item; + final int supportedVersion = factory.getSupportedVersion(); + if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) || + (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion)) { + result.add(factory); + } + } + return result; + } + + private static Collection<SVNAdminAreaFactory> factoriesFor15(final Collection factories) { + final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2); + for (Object item : factories) { + final SVNAdminAreaFactory factory = (SVNAdminAreaFactory)item; + final int supportedVersion = factory.getSupportedVersion(); + if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) || + (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) || + (WorkingCopyFormat.ONE_DOT_FIVE.getFormat() == supportedVersion)) { + result.add(factory); + } + } + return result; + } + + private static Collection<SVNAdminAreaFactory> factoriesFor16(final Collection factories) { + final Collection<SVNAdminAreaFactory> result = new ArrayList<SVNAdminAreaFactory>(2); + for (Object item : factories) { + final SVNAdminAreaFactory factory = (SVNAdminAreaFactory)item; + final int supportedVersion = factory.getSupportedVersion(); + if ((WorkingCopyFormat.ONE_DOT_FOUR.getFormat() == supportedVersion) || + (WorkingCopyFormat.ONE_DOT_THREE.getFormat() == supportedVersion) || + (WorkingCopyFormat.ONE_DOT_FIVE.getFormat() == supportedVersion) || + (WorkingCopyFormat.ONE_DOT_SIX.getFormat() == supportedVersion)) { + result.add(factory); + } + } + return result; + } +} diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitManager.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitManager.java index a446b58bb1cb..757100026797 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitManager.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/svnkit/SvnKitManager.java @@ -26,7 +26,6 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.svn.SvnConfiguration; -import org.jetbrains.idea.svn.SvnFormatSelector; import org.jetbrains.idea.svn.SvnHttpAuthMethodsDefaultChecker; import org.jetbrains.idea.svn.SvnVcs; import org.jetbrains.idea.svn.auth.SvnAuthenticationManager; @@ -72,7 +71,7 @@ public class SvnKitManager { SVNJNAUtil.setJNAEnabled(true); SvnHttpAuthMethodsDefaultChecker.check(); - SVNAdminAreaFactory.setSelector(new SvnFormatSelector()); + SVNAdminAreaFactory.setSelector(new SvnKitAdminAreaFactorySelector()); DAVRepositoryFactory.setup(); SVNRepositoryFactoryImpl.setup(); diff --git a/plugins/svn4idea/testSource/org/jetbrains/idea/svn/ExternalsDefinitionParserTest.java b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/ExternalsDefinitionParserTest.java new file mode 100644 index 000000000000..ff24c79a6b4c --- /dev/null +++ b/plugins/svn4idea/testSource/org/jetbrains/idea/svn/ExternalsDefinitionParserTest.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * 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.jetbrains.idea.svn; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.idea.svn.properties.ExternalsDefinitionParser; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * @author Konstantin Kolosovsky. + */ +public class ExternalsDefinitionParserTest { + + @Test + public void test_no_space_directory_with_revision() throws Exception { + assertRelativeDirectory("third-party/skins", "-r148 http://svn.example.com/skinproj third-party/skins"); + } + + @Test + public void test_no_space_directory_with_peg_revision() throws Exception { + assertRelativeDirectory("third-party/skins", "http://svn.example.com/skinproj@148 third-party/skins"); + } + + @Test + public void test_no_space_directory_without_revision() throws Exception { + assertRelativeDirectory("third-party/sounds", " http://svn.example.com/repos/sounds third-party/sounds"); + } + + @Test + public void test_quoted_no_space_directory() throws Exception { + assertRelativeDirectory("third-party/skins", "-r148 http://svn.example.com/skinproj \"third-party/skins\""); + } + + @Test + public void test_quoted_with_space_directory() throws Exception { + assertRelativeDirectory("My Project", "http://svn.thirdparty.com/repos/My%20Project \"My Project\""); + } + + @Test + public void test_escaped_with_space_and_quotes_directory() throws Exception { + assertRelativeDirectory("\"Quotes Too\"", "http://svn.thirdparty.com/repos/%22Quotes%20Too%22 \\\"Quotes\\ Too\\\""); + } + + private static void assertRelativeDirectory(@NotNull String expected, @NotNull String external) throws Exception { + assertEquals(expected, ExternalsDefinitionParser.parseRelativeDirectory(external)); + } +} diff --git a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskConfigurable.java b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskConfigurable.java index 2e2da7228dda..06f2685fceb1 100644 --- a/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskConfigurable.java +++ b/plugins/tasks/tasks-core/src/com/intellij/tasks/config/TaskConfigurable.java @@ -2,7 +2,6 @@ package com.intellij.tasks.config; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.options.NonDefaultProjectConfigurable; import com.intellij.openapi.options.SearchableConfigurable; import com.intellij.openapi.options.binding.BindControl; import com.intellij.openapi.options.binding.BindableConfigurable; @@ -24,8 +23,7 @@ import java.awt.event.ActionListener; * @author Dmitry Avdeev */ @SuppressWarnings({"UnusedDeclaration"}) -public class TaskConfigurable extends BindableConfigurable implements SearchableConfigurable.Parent, - NonDefaultProjectConfigurable, Configurable.NoScroll { +public class TaskConfigurable extends BindableConfigurable implements SearchableConfigurable.Parent, Configurable.NoScroll { private JPanel myPanel; diff --git a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java index 3da6ad3d82d7..2f93b83bef09 100644 --- a/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java +++ b/plugins/tasks/tasks-tests/test/com/intellij/tasks/integration/live/TrelloIntegrationTest.java @@ -29,16 +29,20 @@ public class TrelloIntegrationTest extends LiveIntegrationTestCase<TrelloReposit @Override protected TrelloRepository createRepository() throws Exception { - TrelloRepository repository = new TrelloRepository(new TrelloRepositoryType()); - String token = System.getProperty("tasks.tests.trello.token"); - if (StringUtil.isEmpty(token)) { - throw new AssertionError("Authorization token is not set"); + try { + TrelloRepository repository = new TrelloRepository(new TrelloRepositoryType()); + String token = System.getProperty("tasks.tests.trello.token"); + assertTrue("Authorization token is not set", !StringUtil.isEmpty(token)); + repository.setPassword(token); + TrelloUser user = repository.fetchUserByToken(); + assertNotNull(user); + repository.setCurrentUser(user); + return repository; + } + catch (AssertionError ae){ + tearDown(); + throw ae; } - repository.setPassword(token); - TrelloUser user = repository.fetchUserByToken(); - assertNotNull(user); - repository.setCurrentUser(user); - return repository; } // TODO Check closed tasks exclusion diff --git a/plugins/terminal/lib/jediterm-pty-2.0.jar b/plugins/terminal/lib/jediterm-pty-2.0.jar Binary files differindex 794d97412396..e8eaa9bd7a9b 100644 --- a/plugins/terminal/lib/jediterm-pty-2.0.jar +++ b/plugins/terminal/lib/jediterm-pty-2.0.jar diff --git a/plugins/terminal/resources/META-INF/terminal.xml b/plugins/terminal/resources/META-INF/terminal.xml index 11a18e18d81f..e85297f2b715 100644 --- a/plugins/terminal/resources/META-INF/terminal.xml +++ b/plugins/terminal/resources/META-INF/terminal.xml @@ -1,12 +1,4 @@ <idea-plugin version="2"> - <actions> - <action id="org.jetbrains.plugins.terminal.OpenLocalTerminalAction" - class="org.jetbrains.plugins.terminal.OpenLocalTerminalAction" - text="Open Terminal..." description="Open terminal locally"> - <add-to-group group-id="ToolsMenu" anchor="last"/> - </action> - </actions> - <extensions defaultExtensionNs="com.intellij"> <toolWindow id="Terminal" anchor="bottom" icon="TerminalIcons.OpenTerminal_13x13" factoryClass="org.jetbrains.plugins.terminal.TerminalToolWindowFactory" secondary="false"/> diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java index caaa54166e7d..f67f84412a02 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/LocalTerminalDirectRunner.java @@ -16,6 +16,7 @@ import com.jediterm.pty.PtyProcessTtyConnector; import com.jediterm.terminal.TtyConnector; import com.pty4j.PtyProcess; import com.pty4j.util.PtyUtil; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; @@ -63,6 +64,11 @@ public class LocalTerminalDirectRunner extends AbstractTerminalRunner<PtyProcess return null; } + @NotNull + public static LocalTerminalDirectRunner createTerminalRunner(Project project) { + return new LocalTerminalDirectRunner(project); + } + @Override protected PtyProcess createProcess(@Nullable String directory) throws ExecutionException { Map<String, String> envs = new HashMap<String, String>(System.getenv()); @@ -77,10 +83,14 @@ public class LocalTerminalDirectRunner extends AbstractTerminalRunner<PtyProcess } private String currentProjectFolder() { - for (VirtualFile vf : ProjectRootManager.getInstance(myProject).getContentRoots()) { - return vf.getCanonicalPath(); + final ProjectRootManager projectRootManager = ProjectRootManager.getInstance(myProject); + + final VirtualFile[] roots = projectRootManager.getContentRoots(); + if (roots.length == 1) { + roots[0].getCanonicalPath(); } - return null; + final VirtualFile baseDir = myProject.getBaseDir(); + return baseDir == null ? null : baseDir.getCanonicalPath(); } @Override diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/OpenLocalTerminalAction.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/OpenLocalTerminalAction.java deleted file mode 100644 index 4d93dd9fc46e..000000000000 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/OpenLocalTerminalAction.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.jetbrains.plugins.terminal; - -import com.intellij.openapi.actionSystem.AnAction; -import com.intellij.openapi.actionSystem.AnActionEvent; -import com.intellij.openapi.actionSystem.CommonDataKeys; -import com.intellij.openapi.project.DumbAware; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.wm.ToolWindow; -import com.intellij.openapi.wm.ToolWindowManager; -import icons.TerminalIcons; -import org.jetbrains.annotations.NotNull; - -/** - * @author traff - */ -public class OpenLocalTerminalAction extends AnAction implements DumbAware { - public OpenLocalTerminalAction() { - super("Open Terminal...", null, TerminalIcons.OpenTerminal); - } - - @Override - public void update(final AnActionEvent e) { - e.getPresentation().setVisible(true); - e.getPresentation().setEnabled(true); - } - - public void actionPerformed(final AnActionEvent e) { - runLocalTerminal(e); - } - - public void runLocalTerminal(AnActionEvent event) { - final Project project = event.getData(CommonDataKeys.PROJECT); - runLocalTerminal(project); - } - - public static void runLocalTerminal(final Project project) { - ToolWindow terminal = ToolWindowManager.getInstance(project).getToolWindow("Terminal"); - if (terminal.isActive()) { - TerminalView.getInstance(project).openLocalSession(project, terminal); - } - terminal.activate(new Runnable() { - @Override - public void run() { - - } - }, true); - } - - @NotNull - public static LocalTerminalDirectRunner createTerminalRunner(Project project) { - return new LocalTerminalDirectRunner(project); - } -} diff --git a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalView.java b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalView.java index 14b992a7c143..32b7c9b13c06 100644 --- a/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalView.java +++ b/plugins/terminal/src/org/jetbrains/plugins/terminal/TerminalView.java @@ -1,7 +1,6 @@ package org.jetbrains.plugins.terminal; import com.intellij.icons.AllIcons; -import com.intellij.notification.EventLog; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.project.DumbAwareAction; @@ -23,7 +22,6 @@ import com.intellij.util.ui.UIUtil; import com.jediterm.terminal.ui.JediTermWidget; import com.jediterm.terminal.ui.TabbedTerminalWidget; import com.jediterm.terminal.ui.TerminalWidget; -import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.terminal.vfs.TerminalSessionVirtualFileImpl; @@ -54,7 +52,7 @@ public class TerminalView { public void initTerminal(final ToolWindow toolWindow) { - LocalTerminalDirectRunner terminalRunner = OpenLocalTerminalAction.createTerminalRunner(myProject); + LocalTerminalDirectRunner terminalRunner = LocalTerminalDirectRunner.createTerminalRunner(myProject); toolWindow.setToHideOnEmptyContent(true); @@ -99,14 +97,9 @@ public class TerminalView { } } - private Content createTerminalInContentPanel(@Nullable LocalTerminalDirectRunner terminalRunner, + private Content createTerminalInContentPanel(@NotNull AbstractTerminalRunner terminalRunner, final @NotNull ToolWindow toolWindow) { - SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true) { - @Override - public Object getData(@NonNls String dataId) { - return PlatformDataKeys.HELP_ID.is(dataId) ? EventLog.HELP_ID : super.getData(dataId); - } - }; + SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true); final Content content = ContentFactory.SERVICE.getInstance().createContent(panel, "", false); content.setCloseable(true); @@ -162,14 +155,14 @@ public class TerminalView { } public void openLocalSession(Project project, ToolWindow terminal) { - LocalTerminalDirectRunner terminalRunner = OpenLocalTerminalAction.createTerminalRunner(project); + LocalTerminalDirectRunner terminalRunner = LocalTerminalDirectRunner.createTerminalRunner(project); openSession(terminal, terminalRunner); } private void openSession(@NotNull ToolWindow toolWindow, @NotNull AbstractTerminalRunner terminalRunner) { if (myTerminalWidget == null) { toolWindow.getContentManager().removeAllContents(true); - final Content content = createTerminalInContentPanel(null, toolWindow); + final Content content = createTerminalInContentPanel(terminalRunner, toolWindow); toolWindow.getContentManager().addContent(content); } else { @@ -184,7 +177,7 @@ public class TerminalView { }, true); } - private ActionToolbar createToolbar(@Nullable final LocalTerminalDirectRunner terminalRunner, + private ActionToolbar createToolbar(@Nullable final AbstractTerminalRunner terminalRunner, @NotNull final JBTabbedTerminalWidget terminal, @NotNull ToolWindow toolWindow) { DefaultActionGroup group = new DefaultActionGroup(); @@ -215,10 +208,10 @@ public class TerminalView { private static class NewSession extends DumbAwareAction { - private final LocalTerminalDirectRunner myTerminalRunner; + private final AbstractTerminalRunner myTerminalRunner; private final TerminalWidget myTerminal; - public NewSession(@NotNull LocalTerminalDirectRunner terminalRunner, @NotNull TerminalWidget terminal) { + public NewSession(@NotNull AbstractTerminalRunner terminalRunner, @NotNull TerminalWidget terminal) { super("New Session", "Create New Terminal Session", AllIcons.General.Add); myTerminalRunner = terminalRunner; myTerminal = terminal; diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java index 639236152acb..413aceebf8d4 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/SearchingForTestsTask.java @@ -122,7 +122,7 @@ public class SearchingForTestsTask extends Task.Backgroundable { writeTempFile(); finish(); - if (!Registry.is("testng_sm_runner", false)) myClient.startListening(myConfig); + if (!Registry.is("testng_sm_runner")) myClient.startListening(myConfig); } @Override diff --git a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java index be953950ccb8..21afb568e912 100644 --- a/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java +++ b/plugins/testng/src/com/theoryinpractice/testng/configuration/TestNGRunnableState.java @@ -122,7 +122,7 @@ public class TestNGRunnableState extends JavaCommandLineState { @Override public ExecutionResult execute(@NotNull final Executor executor, @NotNull final ProgramRunner runner) throws ExecutionException { - final boolean smRunner = Registry.is("testng_sm_runner", false); + final boolean smRunner = Registry.is("testng_sm_runner"); if (smRunner) { return startSMRunner(executor); } diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/PsiPropertiesProvider.java b/plugins/ui-designer/src/com/intellij/uiDesigner/PsiPropertiesProvider.java index 5b8518f0d70b..91b75c91b619 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/PsiPropertiesProvider.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/PsiPropertiesProvider.java @@ -16,6 +16,7 @@ package com.intellij.uiDesigner; import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.ClassUtil; @@ -74,7 +75,8 @@ public final class PsiPropertiesProvider implements PropertiesProvider { } final PsiType type = getter.getReturnType(); - final String propertyClassName = type.getCanonicalText(); + String propertyClassName = + StringUtil.defaultIfEmpty(StringUtil.substringBefore(type.getCanonicalText(), "<"), type.getCanonicalText()); LwIntrospectedProperty property = CompiledClassPropertiesProvider.propertyFromClassName(propertyClassName, name); if (property == null) { diff --git a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/ColorEditor.java b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/ColorEditor.java index 7e6b94dc4784..96ddb74494d1 100644 --- a/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/ColorEditor.java +++ b/plugins/ui-designer/src/com/intellij/uiDesigner/propertyInspector/editors/ColorEditor.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,33 +15,19 @@ */ package com.intellij.uiDesigner.propertyInspector.editors; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.TextFieldWithBrowseButton; -import com.intellij.ui.ListSpeedSearch; -import com.intellij.ui.ScrollPaneFactory; -import com.intellij.ui.components.JBList; +import com.intellij.ui.ColorChooser; +import com.intellij.ui.JBColor; import com.intellij.uiDesigner.UIDesignerBundle; import com.intellij.uiDesigner.lw.ColorDescriptor; import com.intellij.uiDesigner.propertyInspector.InplaceContext; import com.intellij.uiDesigner.propertyInspector.PropertyEditor; -import com.intellij.uiDesigner.propertyInspector.renderers.ColorRenderer; import com.intellij.uiDesigner.radComponents.RadComponent; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.colorchooser.AbstractColorChooserPanel; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; -import javax.swing.plaf.ColorChooserUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.*; -import java.util.List; /** * @author yole @@ -50,7 +36,6 @@ public class ColorEditor extends PropertyEditor<ColorDescriptor> { private final String myPropertyName; private final TextFieldWithBrowseButton myTextField = new TextFieldWithBrowseButton(); private ColorDescriptor myValue; - private Project myProject; public ColorEditor(String propertyName) { myPropertyName = propertyName; @@ -58,11 +43,10 @@ public class ColorEditor extends PropertyEditor<ColorDescriptor> { myTextField.getTextField().setEditable(false); myTextField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - MyColorChooserDialog dialog = new MyColorChooserDialog(myProject); - dialog.setSelectedValue(myValue); - dialog.show(); - if (dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { - myValue = dialog.getSelectedValue(); + String title = UIDesignerBundle.message("color.chooser.title", myPropertyName); + Color color = ColorChooser.chooseColor(myTextField, title , myValue.getColor()); + if (color != null) { + myValue = new ColorDescriptor(color); updateTextField(); } } @@ -74,8 +58,7 @@ public class ColorEditor extends PropertyEditor<ColorDescriptor> { } public JComponent getComponent(RadComponent component, ColorDescriptor value, InplaceContext inplaceContext) { - myValue = value != null ? value : new ColorDescriptor(new Color(0)); - myProject = component.getProject(); + myValue = value != null ? value : new ColorDescriptor(JBColor.BLACK); updateTextField(); return myTextField; } @@ -87,174 +70,4 @@ public class ColorEditor extends PropertyEditor<ColorDescriptor> { public void updateUI() { SwingUtilities.updateComponentTreeUI(myTextField); } - - private static class ColorDescriptorWrapper extends Color { - private final ColorDescriptor myDescriptor; - - public ColorDescriptorWrapper(ColorDescriptor descriptor) { - super(descriptor.getResolvedColor() == null ? 0 : descriptor.getResolvedColor().getRGB()); - myDescriptor = descriptor; - } - - public ColorDescriptor getDescriptor() { - return myDescriptor; - } - } - - private class MyColorChooserDialog extends DialogWrapper { - private JColorChooser myColorChooser; - private MyDescriptorChooserPanel mySwingChooserPanel; - private MyDescriptorChooserPanel mySystemChooserPanel; - private MyDescriptorChooserPanel myAWTChooserPanel; - - public MyColorChooserDialog(Project project) { - super(project, false); - setTitle(UIDesignerBundle.message("color.chooser.title", myPropertyName)); - init(); - } - - protected JComponent createCenterPanel() { - myColorChooser = new JColorChooser(); - mySwingChooserPanel = new MyDescriptorChooserPanel(UIDesignerBundle.message("color.chooser.swing.palette"), collectSwingColorDescriptors()); - myColorChooser.addChooserPanel(mySwingChooserPanel); - mySystemChooserPanel = new MyDescriptorChooserPanel(UIDesignerBundle.message("color.chooser.system.palette"), - collectColorFields(SystemColor.class, true)); - myColorChooser.addChooserPanel(mySystemChooserPanel); - myAWTChooserPanel = new MyDescriptorChooserPanel(UIDesignerBundle.message("color.chooser.awt.palette"), - collectColorFields(Color.class, false)); - myColorChooser.addChooserPanel(myAWTChooserPanel); - return myColorChooser; - } - - private void selectTabForColor(@Nullable final ColorDescriptor value) { - String tabName; - - if (value == null || value.getSwingColor() != null) { - tabName = mySwingChooserPanel.getDisplayName(); - } - else if (value.getSystemColor() != null) { - tabName = mySystemChooserPanel.getDisplayName(); - } - else if (value.getAWTColor() != null) { - tabName = myAWTChooserPanel.getDisplayName(); - } - else { - return; - } - - final ColorChooserUI ui = myColorChooser.getUI(); - try { - final Field field = ui.getClass().getDeclaredField("tabbedPane"); - field.setAccessible(true); - JTabbedPane tabbedPane = (JTabbedPane) field.get(ui); - for(int i=0; i<tabbedPane.getTabCount(); i++) { - if (tabbedPane.getTitleAt(i).equals(tabName)) { - tabbedPane.setSelectedIndex(i); - break; - } - } - } - catch (NoSuchFieldException e) { - // ignore - } - catch (IllegalAccessException e) { - // ignore - } - } - - private List<ColorDescriptor> collectSwingColorDescriptors() { - ArrayList<ColorDescriptor> result = new ArrayList<ColorDescriptor>(); - UIDefaults defaults = UIManager.getDefaults(); - Enumeration e = defaults.keys (); - while(e.hasMoreElements()) { - Object key = e.nextElement(); - Object value = defaults.get(key); - if (key instanceof String && value instanceof Color) { - result.add(ColorDescriptor.fromSwingColor((String) key)); - } - } - return result; - } - - private List<ColorDescriptor> collectColorFields(final Class aClass, final boolean isSystem) { - ArrayList<ColorDescriptor> result = new ArrayList<ColorDescriptor>(); - Field[] colorFields = aClass.getDeclaredFields(); - for(Field field: colorFields) { - if ((field.getModifiers() & Modifier.STATIC) != 0 && - Color.class.isAssignableFrom(field.getType()) && - Character.isLowerCase(field.getName().charAt(0))) { - final ColorDescriptor color = isSystem - ? ColorDescriptor.fromSystemColor(field.getName()) - : ColorDescriptor.fromAWTColor(field.getName()); - result.add(color); - } - } - return result; - } - - public void setSelectedValue(@NotNull final ColorDescriptor value) { - myColorChooser.setColor(new ColorDescriptorWrapper(value)); - selectTabForColor(value); - } - - public ColorDescriptor getSelectedValue() { - final Color color = myColorChooser.getColor(); - if (color instanceof ColorDescriptorWrapper) { - return ((ColorDescriptorWrapper) color).getDescriptor(); - } - return new ColorDescriptor(color); - } - } - - private static class MyDescriptorChooserPanel extends AbstractColorChooserPanel { - private final String myDisplayName; - private final ColorDescriptor[] myColorDescriptors; - private JList myDescriptorList; - - public MyDescriptorChooserPanel(final String displayName, List<ColorDescriptor> colorDescriptorList) { - myDisplayName = displayName; - - Collections.sort(colorDescriptorList, new Comparator<ColorDescriptor>() { - public int compare(final ColorDescriptor o1, final ColorDescriptor o2) { - return o1.toString().compareTo(o2.toString()); - } - }); - - myColorDescriptors = colorDescriptorList.toArray(new ColorDescriptor[colorDescriptorList.size()]); - } - - public void updateChooser() { - myDescriptorList.setSelectedValue(getColorFromModel(), true); - } - - protected void buildChooser() { - setLayout(new BorderLayout()); - myDescriptorList = new JBList(myColorDescriptors); - myDescriptorList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - myDescriptorList.setVisibleRowCount(15); - myDescriptorList.setCellRenderer(new ColorRenderer()); - myDescriptorList.addListSelectionListener(new ListSelectionListener() { - public void valueChanged(ListSelectionEvent e) { - ColorDescriptor descriptor = (ColorDescriptor)myDescriptorList.getSelectedValue(); - getColorSelectionModel().setSelectedColor(new ColorDescriptorWrapper(descriptor)); - } - }); - new ListSpeedSearch(myDescriptorList); - add(ScrollPaneFactory.createScrollPane(myDescriptorList), BorderLayout.CENTER); - } - - public String getDisplayName() { - return myDisplayName; - } - - @Nullable - public Icon getSmallDisplayIcon() { - return null; - } - - @Nullable - public Icon getLargeDisplayIcon() { - return null; - } - } } diff --git a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java index 0313fb41ded6..dc8c73771a46 100644 --- a/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java +++ b/plugins/xpath/xpath-lang/src/org/intellij/lang/xpath/xslt/associations/impl/FileAssociationsConfigurable.java @@ -20,14 +20,17 @@ import com.intellij.ide.util.treeView.TreeState; import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.application.Result; import com.intellij.openapi.components.*; -import com.intellij.openapi.options.*; +import com.intellij.openapi.options.Configurable; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.SearchableConfigurable; +import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; import javax.swing.*; -public class FileAssociationsConfigurable implements SearchableConfigurable, NonDefaultProjectConfigurable, Configurable.NoScroll { +public class FileAssociationsConfigurable implements SearchableConfigurable, Configurable.NoScroll { private final Project myProject; private final UIState myState; private AssociationsEditor myEditor; @@ -37,17 +40,21 @@ public class FileAssociationsConfigurable implements SearchableConfigurable, Non myState = ServiceManager.getService(project, UIState.class); } + @Override public String getDisplayName() { return "XSLT File Associations"; } + @Override @NotNull public String getHelpTopic() { return "xslt.associations"; } + @Override public JComponent createComponent() { myEditor = new ReadAction<AssociationsEditor>() { + @Override protected void run(Result<AssociationsEditor> result) throws Throwable { result.setResult(new AssociationsEditor(myProject, myState.state)); } @@ -55,19 +62,23 @@ public class FileAssociationsConfigurable implements SearchableConfigurable, Non return myEditor.getComponent(); } + @Override public synchronized boolean isModified() { return myEditor != null && myEditor.isModified(); } + @Override public void apply() throws ConfigurationException { myEditor.apply(); DaemonCodeAnalyzer.getInstance(myProject).restart(); } + @Override public void reset() { myEditor.reset(); } + @Override public synchronized void disposeUIResources() { if (myEditor != null) { myState.state = myEditor.getState(); @@ -84,6 +95,7 @@ public class FileAssociationsConfigurable implements SearchableConfigurable, Non final FileAssociationsConfigurable instance = new FileAssociationsConfigurable(project); ShowSettingsUtil.getInstance().editConfigurable(project, instance, new Runnable() { + @Override public void run() { final AssociationsEditor editor = instance.getEditor(); if (file != null) { @@ -99,20 +111,24 @@ public class FileAssociationsConfigurable implements SearchableConfigurable, Non public static class UIState implements PersistentStateComponent<TreeState> { private TreeState state; + @Override public TreeState getState() { return state != null ? state : new TreeState(); } + @Override public void loadState(TreeState state) { this.state = state; } } + @Override @NotNull public String getId() { return getHelpTopic(); } + @Override public Runnable enableSearch(final String option) { return null; } |