IDEA-117113 Can't Start Mercurial

*exitValue used as valid detector instead of errors.isEmpty in validate and log command methods;
*unsupported exceptions parsed and stored during getVersions command;
*tests added;
*annotations added;
*see todo issue for  all repository configuration problems
This commit is contained in:
Nadya Zabrodina
2013-11-29 18:58:33 +04:00
parent e42d12eb37
commit b5afa13a3c
5 changed files with 74 additions and 12 deletions
@@ -66,7 +66,9 @@ import org.zmlx.hg4idea.util.HgVersion;
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class HgVcs extends AbstractVcs<CommittedChangeList> {
@@ -111,6 +113,7 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> {
private HgIncomingOutgoingWidget myIncomingWidget;
private HgIncomingOutgoingWidget myOutgoingWidget;
@NotNull private HgVersion myVersion = HgVersion.NULL; // version of Hg which this plugin uses.
@NotNull private Set<String> unsupportedExtension = new HashSet<String>();
public HgVcs(Project project,
@NotNull HgGlobalSettings globalSettings,
@@ -451,7 +454,7 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> {
}
};
try {
myVersion = HgVersion.identifyVersion(executable);
myVersion = HgVersion.identifyVersion(executable, unsupportedExtension);
//if version is not supported, but have valid hg executable
if (!myVersion.isSupported()) {
LOG.info("Unsupported Hg version: " + myVersion);
@@ -459,7 +462,12 @@ public class HgVcs extends AbstractVcs<CommittedChangeList> {
"The minimal supported version is %s. Please <a href='" + UPDATE_LINK + "'>update</a>.",
myVersion, HgVersion.MIN);
errorNotification.notifyError(null, "Unsupported Hg version", message, linkAdapter);
}
if (!unsupportedExtension.isEmpty()) {
LOG.warn("Unsupported Hg extensions: " + unsupportedExtension.toString());
message = String.format("Some hg extensions %s are not found or not supported by your hg version and will be ignored.\n" +
"Please, update your hgrc or Mercurial.ini file", unsupportedExtension.toString());
errorNotification.notifyWarning("Unsupported Hg version", message);
}
}
catch (Exception e) {
@@ -96,7 +96,7 @@ public class HgLogCommand {
*/
public final List<HgFileRevision> execute(final HgFile hgFile, int limit, boolean includeFiles, @Nullable List<String> argsForCmd)
throws HgCommandException {
if ((limit <= 0 && limit != -1) || hgFile == null || hgFile.getRepo() == null) {
if ((limit <= 0 && limit != -1) || hgFile == null) {
return Collections.emptyList();
}
@@ -116,7 +116,10 @@ public class HgLogCommand {
List<String> errors = result.getErrorLines();
if (errors != null && !errors.isEmpty()) {
throw new HgCommandException(errors.toString());
if (result.getExitValue() != 0) {
throw new HgCommandException(errors.toString());
}
LOG.warn(errors.toString());
}
String output = result.getRawOutput();
String[] changeSets = output.split(HgChangesetUtil.CHANGESET_SEPARATOR);
@@ -599,7 +599,7 @@ public abstract class HgUtil {
return false;
}
HgCommandResult result = getVersionOutput(executable);
return result.getRawError().isEmpty();
return result.getExitValue() == 0 && !result.getRawOutput().isEmpty();
}
catch (Throwable e) {
LOG.info("Error during hg executable validation: ", e);
@@ -24,6 +24,10 @@ import org.zmlx.hg4idea.execution.HgCommandResult;
import org.zmlx.hg4idea.execution.ShellCommandException;
import java.text.ParseException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -37,7 +41,8 @@ public final class HgVersion implements Comparable<HgVersion> {
private static final Pattern HG_VERSION_PATTERN =
Pattern.compile(".+\\(\\s*\\S+\\s+(\\d+)\\.(\\d+)[\\.]?(\\d)?.*\\s*\\)\\s*.*\\s*", Pattern.CASE_INSENSITIVE);
//f.e. Mercurial Distributed SCM (version 2.6+20130507) or Mercurial Distributed SCM (version 2.6.2), 2.7-rc+5-ca2dfc2f63eb
private static final Pattern HG_UNSUPPORTED_EXTENSION =
Pattern.compile("\\*\\*\\*\\s*failed to import\\s+extension\\s+([a-zA-z0-9\\.-]+).*", Pattern.CASE_INSENSITIVE);
/**
* The minimal supported version
*/
@@ -48,7 +53,7 @@ public final class HgVersion implements Comparable<HgVersion> {
// since 2.3 - 2.5.3 hg has bug with join function with file_copies
// see http://mercurial.808500.n3.nabble.com/Bug-3887-New-hg-log-template-quot-rev-join-file-copies-n-quot-prints-literal-quot-sourcename-quot-fos-td4000129.html
public static final HgVersion BUILT_IN_FUNCTION_SUPPORTED = new HgVersion(2, 6, 0);
public static final HgVersion PARENT_REVISION_TEMPLATES_SUPPORTED = new HgVersion(2,4,0);
public static final HgVersion PARENT_REVISION_TEMPLATES_SUPPORTED = new HgVersion(2, 4, 0);
//see http://selenic.com/pipermail/mercurial-devel/2013-May/051209.html fixed since 2.7
private static final HgVersion LARGEFILES_WITH_FOLLOW_SUPPORTED = new HgVersion(2, 7, 0);
@@ -73,18 +78,41 @@ public final class HgVersion implements Comparable<HgVersion> {
*/
@NotNull
public static HgVersion parseVersion(@Nullable String output) throws ParseException {
public static HgVersion parseVersionAndExtensionInfo(@Nullable String output,
@NotNull List<String> errorLines,
@NotNull Set<String> unsupportedExtensions)
throws ParseException {
if (StringUtil.isEmptyOrSpaces(output)) {
throw new ParseException("Empty hg version output: " + output, 0);
}
Matcher matcher = HG_VERSION_PATTERN.matcher(output);
if (matcher.matches()) {
unsupportedExtensions.addAll(parseUnsupportedExtensions(errorLines));
return new HgVersion(getIntGroup(matcher, 1), getIntGroup(matcher, 2), getIntGroup(matcher, 3));
}
LOGGER.error("Couldn't identify hg version: " + output);
throw new ParseException("Unsupported format of hg version output: " + output, 0);
}
@NotNull
public static Collection<String> parseUnsupportedExtensions(@NotNull List<String> errorLines) {
// hg version command execute with null start directory,
// but hgrc configuration file may be related to one of repository then extension may be failed to import too
//before fixed use command exit value instead if errors.isEmpty
//todo store all unsupported extensions for all repository and notify once
Set<String> extensions = new HashSet<String>();
if (errorLines.isEmpty()) {
return extensions;
}
for (String line : errorLines) {
Matcher matcher = HG_UNSUPPORTED_EXTENSION.matcher(line);
if (matcher.matches()) {
extensions.add(matcher.group(1));
}
}
return extensions;
}
// Utility method used in parsing - checks that the given capture group exists and captured something - then returns the captured value,
// otherwise returns 0.
private static int getIntGroup(@NotNull Matcher matcher, int group) {
@@ -100,10 +128,10 @@ public final class HgVersion implements Comparable<HgVersion> {
}
@NotNull
public static HgVersion identifyVersion(@NotNull String executable)
public static HgVersion identifyVersion(@NotNull String executable, @NotNull Set<String> unsupportedExtensions)
throws ShellCommandException, InterruptedException, ParseException {
HgCommandResult versionResult = HgUtil.getVersionOutput(executable);
return parseVersion(versionResult.getRawOutput());
return parseVersionAndExtensionInfo(versionResult.getRawOutput(), versionResult.getErrorLines(), unsupportedExtensions);
}
/**
@@ -15,10 +15,16 @@
*/
package hg4idea.test.version;
import com.intellij.openapi.vcs.VcsTestUtil;
import com.intellij.util.containers.HashSet;
import hg4idea.test.HgPlatformTest;
import org.zmlx.hg4idea.util.HgVersion;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* @author Nadya Zabrodina
@@ -41,20 +47,37 @@ public class HgVersionTest extends HgPlatformTest {
};
public void testParseSupported() throws Exception {
Set<String> unsupportedExceptions = new HashSet<String>();
for (TestHgVersion test : commonTests) {
HgVersion version = HgVersion.parseVersion(test.output);
HgVersion version = HgVersion.parseVersionAndExtensionInfo(test.output, Collections.<String>emptyList(), unsupportedExceptions);
assertEqualVersions(version, test);
assertTrue(version.isSupported());
}
}
public void testParseUnsupported() throws Exception {
Set<String> unsupportedExceptions = new HashSet<String>();
TestHgVersion unsupportedVersion = new TestHgVersion("Mercurial Distributed SCM (version 1.5.1)", 1, 5, 1);
HgVersion parsedVersion = HgVersion.parseVersion(unsupportedVersion.output);
HgVersion parsedVersion =
HgVersion.parseVersionAndExtensionInfo(unsupportedVersion.output, Collections.<String>emptyList(), unsupportedExceptions);
assertEqualVersions(parsedVersion, unsupportedVersion);
assertFalse(parsedVersion.isSupported());
}
public void testParseImportExtensionsError() {
List<String> errorLines = Arrays.asList("*** failed to import extension hgcr-gui: No module named hgcr-gui",
"*** failed to import extension hgcr-gui-qt: No module named hgcr-gui-qt");
VcsTestUtil.assertEqualCollections(HgVersion.parseUnsupportedExtensions(errorLines), Arrays.asList("hgcr-gui", "hgcr-gui-qt"));
}
public void testParseImportDeprecatedExtensionsError() {
List<String> errorLines = Arrays.asList("*** failed to import extension kilnpath from" +
" C:\\Users\\Developer\\AppData\\Local\\KilnExtensions\\kilnpath.py:" +
" kilnpath is deprecated, and does not work in Mercurial 2.3 or higher." +
" Use the official schemes extension instead");
VcsTestUtil.assertEqualCollections(HgVersion.parseUnsupportedExtensions(errorLines), Arrays.asList("kilnpath"));
}
private static void assertEqualVersions(HgVersion actual, TestHgVersion expected) throws Exception {
Field field = HgVersion.class.getDeclaredField("myMajor");
field.setAccessible(true);