diff options
author | Alex Ruiz <alruiz@google.com> | 2014-08-21 13:58:04 -0700 |
---|---|---|
committer | Alex Ruiz <alruiz@google.com> | 2014-08-21 14:10:00 -0700 |
commit | 728e8b29a0e820f151fd8756c40ac50ce0d482a2 (patch) | |
tree | 1e638cd64fc8ed495c26bb22b6f70a04af98ee74 | |
parent | b6227b0e6a8efcbdee05711bcd6cba9a8177d301 (diff) | |
download | idea-728e8b29a0e820f151fd8756c40ac50ce0d482a2.tar.gz |
Added a UI test that reproduces bug when Gradle fails due to lack of memory.
CL also cleans up code.
Issue: https://code.google.com/p/android/issues/detail?id=75060
Change-Id: I21260d26ef883ed6c2042654102f660270e9510e
18 files changed, 204 insertions, 187 deletions
diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/GuiTestCase.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/GuiTestCase.java index 8bf8e51ee6c..9d6ee53b9e0 100644 --- a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/GuiTestCase.java +++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/GuiTestCase.java @@ -15,6 +15,7 @@ */ package com.android.tools.idea.tests.gui.framework; +import com.android.SdkConstants; import com.android.tools.idea.gradle.util.LocalProperties; import com.android.tools.idea.sdk.DefaultSdks; import com.android.tools.idea.tests.gui.framework.fixture.FileChooserDialogFixture; @@ -193,6 +194,12 @@ public abstract class GuiTestCase { @NotNull protected File setUpProject(@NotNull String projectDirName, boolean forOpen, boolean updateGradleVersions) throws IOException { final File projectPath = getProjectDirPath(projectDirName); + + File gradlePropertiesFilePath = new File(projectPath, SdkConstants.FN_GRADLE_PROPERTIES); + if (gradlePropertiesFilePath.isFile()) { + delete(gradlePropertiesFilePath); + } + createGradleWrapper(projectPath); if (updateGradleVersions) { diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java index 17f1c49f6eb..4c47d9b1527 100644 --- a/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java +++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/framework/fixture/IdeFrameFixture.java @@ -69,6 +69,7 @@ public class IdeFrameFixture extends ComponentFixture<IdeFrameImpl> { private EditorFixture myEditor; @NotNull private final ProjectSyncListener myProjectSyncListener; + @NotNull private final File myProjectPath; @NotNull public static IdeFrameFixture find(@NotNull final Robot robot, @NotNull final File projectPath, @Nullable final String projectName) { @@ -92,11 +93,12 @@ public class IdeFrameFixture extends ComponentFixture<IdeFrameImpl> { }, LONG_TIMEOUT); IdeFrameImpl ideFrame = robot.finder().find(matcher); - return new IdeFrameFixture(robot, ideFrame); + return new IdeFrameFixture(robot, ideFrame, projectPath); } - public IdeFrameFixture(@NotNull Robot robot, @NotNull IdeFrameImpl target) { + public IdeFrameFixture(@NotNull Robot robot, @NotNull IdeFrameImpl target, @NotNull File projectPath) { super(robot, target); + myProjectPath = projectPath; final Project project = getProject(); Disposable disposable = new NoOpDisposable(); @@ -108,6 +110,11 @@ public class IdeFrameFixture extends ComponentFixture<IdeFrameImpl> { } @NotNull + public File getProjectPath() { + return myProjectPath; + } + + @NotNull public IdeFrameFixture waitForGradleProjectSyncToFinish() { final Project project = getProject(); diff --git a/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java b/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java index 2882cb9c9c9..9d0c4dd9669 100644 --- a/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java +++ b/android/guiTestSrc/com/android/tools/idea/tests/gui/gradle/GradleSyncTest.java @@ -23,18 +23,21 @@ import com.android.tools.idea.tests.gui.framework.fixture.MessagesToolWindowFixt import com.intellij.ide.errorTreeView.ErrorTreeElementKind; import org.fest.util.Strings; import org.jetbrains.annotations.NotNull; +import org.junit.Ignore; import org.junit.Test; import java.io.File; import java.io.IOException; +import java.util.Properties; +import static com.android.SdkConstants.FN_GRADLE_PROPERTIES; import static com.android.tools.idea.gradle.util.GradleUtil.findWrapperPropertiesFile; import static com.android.tools.idea.gradle.util.GradleUtil.updateGradleDistributionUrl; +import static com.android.tools.idea.gradle.util.PropertiesUtil.savePropertiesToFile; import static org.junit.Assert.assertNotNull; public class GradleSyncTest extends GuiTestCase { - @Test - @IdeGuiTest + @Test @IdeGuiTest @Ignore public void testUnsupportedGradleVersion() throws IOException { IdeFrameFixture projectFrame = openProject("SimpleApplication"); @@ -65,4 +68,18 @@ public class GradleSyncTest extends GuiTestCase { projectFrame.waitForGradleProjectSyncToFinish(); } + + // See https://code.google.com/p/android/issues/detail?id=75060 + @Test @IdeGuiTest + public void testUnableToStartDaemon() throws IOException { + IdeFrameFixture projectFrame = openProject("SimpleApplication"); + + // Force a sync failure by allocating not enough memory for the Gradle daemon. + Properties gradleProperties = new Properties(); + gradleProperties.setProperty("org.gradle.jvmargs", "-Xms8m -Xmx24m -XX:MaxPermSize=8m"); + File gradlePropertiesFilePath = new File(projectFrame.getProjectPath(), FN_GRADLE_PROPERTIES); + savePropertiesToFile(gradleProperties, gradlePropertiesFilePath, null); + + projectFrame.requestProjectSync().waitForGradleProjectSyncToFail(); + } } diff --git a/android/src/META-INF/plugin.xml b/android/src/META-INF/plugin.xml index 87a5e3c6fd6..ed675cab8cc 100755 --- a/android/src/META-INF/plugin.xml +++ b/android/src/META-INF/plugin.xml @@ -68,6 +68,7 @@ </action> <group id="Internal.Android" text="Android" popup="true" internal="true"> <action internal="true" id="Android.CleanImportProject" class="com.android.tools.idea.gradle.actions.CleanImportProjectAction" /> + <action internal="true" id="Android.StopGradleDaemons" class="com.android.tools.idea.gradle.actions.StopGradleDaemonsAction" /> <add-to-group group-id="Internal"/> </group> <action id="Android.RunDdms" class="org.jetbrains.android.actions.AndroidRunDdmsAction" icon="AndroidIcons.Android"> diff --git a/android/src/com/android/tools/idea/gradle/actions/CleanImportProjectAction.java b/android/src/com/android/tools/idea/gradle/actions/CleanImportProjectAction.java index 97681fe25ee..654ff5bff1d 100644 --- a/android/src/com/android/tools/idea/gradle/actions/CleanImportProjectAction.java +++ b/android/src/com/android/tools/idea/gradle/actions/CleanImportProjectAction.java @@ -30,6 +30,7 @@ import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; +import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.Messages; @@ -47,7 +48,7 @@ import java.util.List; /** * Closes, removes all IDEA-related files (.idea folder and .iml files) and imports a project. */ -public class CleanImportProjectAction extends AnAction { +public class CleanImportProjectAction extends DumbAwareAction { private static final String MESSAGE_FORMAT = "This action will:\n" + "1. Close project '%1$s'\n" + "2. Delete all project files (.idea folder and .iml files)\n" + diff --git a/android/src/com/android/tools/idea/gradle/actions/StopGradleDaemonsAction.java b/android/src/com/android/tools/idea/gradle/actions/StopGradleDaemonsAction.java new file mode 100644 index 00000000000..fb5ed797414 --- /dev/null +++ b/android/src/com/android/tools/idea/gradle/actions/StopGradleDaemonsAction.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tools.idea.gradle.actions; + +import com.android.tools.idea.gradle.util.GradleUtil; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.ui.Messages; + +import java.io.IOException; + +/** + * Internal action that stops all running Gradle daemons. + */ +public class StopGradleDaemonsAction extends DumbAwareAction { + private static final String TITLE = "Stop Gradle Daemons"; + + public StopGradleDaemonsAction() { + super(TITLE); + } + + @Override + public void actionPerformed(AnActionEvent e) { + try { + GradleUtil.stopAllGradleDaemons(true); + } + catch (IOException error) { + Messages.showErrorDialog("Failed to stop Gradle daemons. Please run 'gradle --stop' from the command line.\n\n" + + "Cause:\n" + error.getMessage(), TITLE + ); + } + } +} diff --git a/android/src/com/android/tools/idea/gradle/eclipse/EclipseProject.java b/android/src/com/android/tools/idea/gradle/eclipse/EclipseProject.java index e7404c5fa3c..283ab7003d6 100755 --- a/android/src/com/android/tools/idea/gradle/eclipse/EclipseProject.java +++ b/android/src/com/android/tools/idea/gradle/eclipse/EclipseProject.java @@ -22,6 +22,7 @@ import com.android.annotations.VisibleForTesting; import com.android.sdklib.AndroidTargetHash; import com.android.sdklib.AndroidVersion; import com.android.sdklib.SdkVersionInfo; +import com.android.tools.idea.gradle.util.PropertiesUtil; import com.android.tools.lint.detector.api.LintUtils; import com.android.utils.SdkUtils; import com.android.utils.XmlUtils; @@ -439,7 +440,7 @@ class EclipseProject implements Comparable<EclipseProject> { File propertyFile = new File(myDir, ".settings" + separator + "org.eclipse.core.resources.prefs"); if (propertyFile.exists()) { - Properties properties = GradleImport.getProperties(propertyFile); + Properties properties = PropertiesUtil.getProperties(propertyFile); if (properties != null) { Enumeration<?> enumeration = properties.propertyNames(); String prefix = "encoding/"; @@ -966,7 +967,7 @@ class EclipseProject implements Comparable<EclipseProject> { myLanguageLevel = DEFAULT_LANGUAGE_LEVEL; // default File file = new File(myDir, ".settings" + separator + "org.eclipse.jdt.core.prefs"); if (file.exists()) { - Properties properties = GradleImport.getProperties(file); + Properties properties = PropertiesUtil.getProperties(file); if (properties != null) { String source = properties.getProperty("org.eclipse.jdt.core.compiler.source"); if (source != null) { @@ -1077,7 +1078,7 @@ class EclipseProject implements Comparable<EclipseProject> { assert isAndroidProject(); File file = getProjectPropertiesFile(); if (file.exists()) { - myProjectProperties = GradleImport.getProperties(file); + myProjectProperties = PropertiesUtil.getProperties(file); } else { myProjectProperties = new Properties(); diff --git a/android/src/com/android/tools/idea/gradle/eclipse/GradleImport.java b/android/src/com/android/tools/idea/gradle/eclipse/GradleImport.java index c095a3b9fac..d8f5c6b3a29 100755 --- a/android/src/com/android/tools/idea/gradle/eclipse/GradleImport.java +++ b/android/src/com/android/tools/idea/gradle/eclipse/GradleImport.java @@ -27,6 +27,7 @@ import com.android.sdklib.AndroidVersion; import com.android.sdklib.BuildToolInfo; import com.android.sdklib.SdkManager; import com.android.sdklib.repository.local.LocalSdk; +import com.android.tools.idea.gradle.util.PropertiesUtil; import com.android.utils.*; import com.google.common.base.Charsets; import com.google.common.base.Objects; @@ -184,7 +185,7 @@ public class GradleImport { File localProperties = new File(projectDir, FN_LOCAL_PROPERTIES); if (localProperties.exists()) { try { - Properties properties = getProperties(localProperties); + Properties properties = PropertiesUtil.getProperties(localProperties); if (properties != null) { String sdk = properties.getProperty(property); if (sdk != null) { @@ -298,14 +299,6 @@ public class GradleImport { return sb.toString(); } - static Properties getProperties(File file) throws IOException { - Properties properties = new Properties(); - InputStreamReader reader = new InputStreamReader(new BufferedInputStream(new FileInputStream(file)), Charsets.UTF_8); - properties.load(reader); - Closeables.close(reader, true); - return properties; - } - /** * Returns true if the given file should be ignored (note: this may not return * true for files inside ignored folders, so to determine if a given file should @@ -646,7 +639,7 @@ public class GradleImport { File settings = getEncodingSettingsFile(); if (settings.exists()) { try { - Properties properties = getProperties(settings); + Properties properties = PropertiesUtil.getProperties(settings); if (properties != null) { String encodingName = properties.getProperty("encoding"); if (encodingName != null) { @@ -675,7 +668,7 @@ public class GradleImport { if (myWorkspaceLocation != null) { if (settings.exists()) { try { - Properties properties = getProperties(settings); + Properties properties = PropertiesUtil.getProperties(settings); if (properties != null) { String path = properties.getProperty(property); if (path == null) { @@ -969,18 +962,12 @@ public class GradleImport { properties.setProperty(PROPERTY_NDK, myNdkLocation.getPath()); } - FileOutputStream out = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - out = new FileOutputStream(new File(destDir, FN_LOCAL_PROPERTIES)); - properties.store(out, "# This file must *NOT* be checked into Version Control Systems,\n" + - "# as it contains information specific to your local configuration.\n" + - "\n" + - "# Location of the SDK. This is only used by Gradle.\n"); - } - finally { - Closeables.close(out, true); - } + File path = new File(destDir, FN_LOCAL_PROPERTIES); + String comments = "# This file must *NOT* be checked into Version Control Systems,\n" + + "# as it contains information specific to your local configuration.\n" + + "\n" + + "# Location of the SDK. This is only used by Gradle.\n"; + PropertiesUtil.savePropertiesToFile(properties, path, comments); } } @@ -1383,7 +1370,7 @@ public class GradleImport { return null; } - return getProperties(settings); + return PropertiesUtil.getProperties(settings); } private File getRuntimeSettingsDir() { @@ -1423,7 +1410,7 @@ public class GradleImport { return null; } - return getProperties(settings); + return PropertiesUtil.getProperties(settings); } private File getWorkspaceLocation() { diff --git a/android/src/com/android/tools/idea/gradle/project/ProjectValidator.java b/android/src/com/android/tools/idea/gradle/project/ProjectValidator.java index 0e11520217d..381f5a247b4 100644 --- a/android/src/com/android/tools/idea/gradle/project/ProjectValidator.java +++ b/android/src/com/android/tools/idea/gradle/project/ProjectValidator.java @@ -21,6 +21,7 @@ import com.android.sdklib.repository.FullRevision; import com.android.tools.idea.gradle.messages.Message; import com.android.tools.idea.gradle.messages.ProjectSyncMessages; import com.android.tools.idea.gradle.util.GradleUtil; +import com.android.tools.idea.gradle.util.PropertiesUtil; import com.android.tools.lint.client.api.LintDriver; import com.android.tools.lint.client.api.LintRequest; import com.android.tools.lint.detector.api.*; @@ -181,7 +182,7 @@ public class ProjectValidator { @NotNull Project project) { Properties wrapperProperties = null; try { - wrapperProperties = GradleUtil.loadGradleWrapperProperties(wrapperPropertiesFile); + wrapperProperties = PropertiesUtil.getProperties(wrapperPropertiesFile); } catch (IOException e) { LOG.warn("Failed to read file " + wrapperPropertiesFile.getPath()); diff --git a/android/src/com/android/tools/idea/gradle/util/GradleUtil.java b/android/src/com/android/tools/idea/gradle/util/GradleUtil.java index bb546d58480..6a1342b1442 100644 --- a/android/src/com/android/tools/idea/gradle/util/GradleUtil.java +++ b/android/src/com/android/tools/idea/gradle/util/GradleUtil.java @@ -26,7 +26,6 @@ import com.google.common.base.CharMatcher; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Lists; -import com.google.common.io.Closeables; import com.intellij.icons.AllIcons; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.diagnostic.Logger; @@ -66,7 +65,9 @@ import org.jetbrains.plugins.gradle.settings.GradleSettings; import org.jetbrains.plugins.gradle.util.GradleConstants; import javax.swing.*; -import java.io.*; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -236,33 +237,20 @@ public final class GradleUtil { * @throws IOException if something goes wrong when saving the file. */ public static boolean updateGradleDistributionUrl(@NotNull String gradleVersion, @NotNull File propertiesFile) throws IOException { - Properties properties = loadGradleWrapperProperties(propertiesFile); + Properties properties = PropertiesUtil.getProperties(propertiesFile); String gradleDistributionUrl = getGradleDistributionUrl(gradleVersion, false); String property = properties.getProperty(DISTRIBUTION_URL_PROPERTY); if (property != null && (property.equals(gradleDistributionUrl) || property.equals(getGradleDistributionUrl(gradleVersion, true)))) { return false; } properties.setProperty(DISTRIBUTION_URL_PROPERTY, gradleDistributionUrl); - FileOutputStream out = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - out = new FileOutputStream(propertiesFile); - properties.store(out, null); - return true; - } - finally { - try { - Closeables.close(out, true); - } - catch (IOException unexpected) { - LOG.info(unexpected); - } - } + PropertiesUtil.savePropertiesToFile(properties, propertiesFile, null); + return true; } @Nullable public static String getGradleWrapperVersion(@NotNull File propertiesFile) throws IOException { - Properties properties = loadGradleWrapperProperties(propertiesFile); + Properties properties = PropertiesUtil.getProperties(propertiesFile); String url = properties.getProperty(DISTRIBUTION_URL_PROPERTY); if (url == null) { return null; @@ -275,26 +263,6 @@ public final class GradleUtil { } @NotNull - public static Properties loadGradleWrapperProperties(@NotNull File propertiesFile) throws IOException { - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - fileInputStream = new FileInputStream(propertiesFile); - properties.load(fileInputStream); - return properties; - } - finally { - try { - Closeables.close(fileInputStream, true); - } - catch (IOException unexpected) { - LOG.info(unexpected); - } - } - } - - @NotNull private static String getGradleDistributionUrl(@NotNull String gradleVersion, boolean binOnly) { String suffix = binOnly ? "bin" : "all"; return String.format("http://services.gradle.org/distributions/gradle-%1$s-" + suffix + ".zip", gradleVersion); diff --git a/android/src/com/android/tools/idea/gradle/util/LocalProperties.java b/android/src/com/android/tools/idea/gradle/util/LocalProperties.java index e74779d4241..a9c7d2e6e10 100644 --- a/android/src/com/android/tools/idea/gradle/util/LocalProperties.java +++ b/android/src/com/android/tools/idea/gradle/util/LocalProperties.java @@ -16,19 +16,17 @@ package com.android.tools.idea.gradle.util; import com.android.SdkConstants; -import com.google.common.base.Charsets; import com.google.common.base.Joiner; import com.google.common.base.Strings; -import com.google.common.io.Closeables; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.util.SystemProperties; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.*; +import java.io.File; +import java.io.IOException; import java.util.Properties; /** @@ -78,28 +76,7 @@ public final class LocalProperties { */ public LocalProperties(@NotNull File projectDirPath) throws IOException { myFilePath = new File(projectDirPath, SdkConstants.FN_LOCAL_PROPERTIES); - myProperties = readFile(myFilePath); - } - - @NotNull - private static Properties readFile(@NotNull File filePath) throws IOException { - if (filePath.isDirectory()) { - // There is a directory named "local.properties". Unlikely to happen, but worth checking. - throw new IllegalArgumentException(String.format("The path '%1$s' belongs to a directory!", filePath.getPath())); - } - if (!filePath.exists()) { - return new Properties(); - } - Properties properties = new Properties(); - Reader reader = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - reader = new InputStreamReader(new BufferedInputStream(new FileInputStream(filePath)), Charsets.UTF_8); - properties.load(reader); - } finally { - Closeables.close(reader, true); - } - return properties; + myProperties = PropertiesUtil.getProperties(myFilePath); } /** @@ -138,20 +115,7 @@ public final class LocalProperties { * Saves any changes to the underlying local.properties file. */ public void save() throws IOException { - FileUtilRt.createParentDirs(myFilePath); - FileOutputStream out = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - out = new FileOutputStream(myFilePath); - // Note that we don't write the properties files in UTF-8; this will *not* write the - // files with the default platform encoding; instead, it will write it using ISO-8859-1 and - // \\u escaping syntax for other characters. This will work with older versions of the Gradle - // plugin which does not read the .properties file with UTF-8 encoding. In the future when - // nobody is using older (0.7.x) versions of the Gradle plugin anymore we can upgrade this - myProperties.store(out, HEADER_COMMENT); - } finally { - Closeables.close(out, true); - } + PropertiesUtil.savePropertiesToFile(myProperties, myFilePath, HEADER_COMMENT); } @NotNull diff --git a/android/src/com/android/tools/idea/gradle/util/PropertiesUtil.java b/android/src/com/android/tools/idea/gradle/util/PropertiesUtil.java new file mode 100644 index 00000000000..7b7218ba935 --- /dev/null +++ b/android/src/com/android/tools/idea/gradle/util/PropertiesUtil.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.tools.idea.gradle.util; + +import com.google.common.base.Charsets; +import com.google.common.io.Closeables; +import com.intellij.openapi.util.io.FileUtilRt; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.*; +import java.util.Properties; + +public final class PropertiesUtil { + private PropertiesUtil() { + } + + @NotNull + public static Properties getProperties(@NotNull File filePath) throws IOException { + if (filePath.isDirectory()) { + throw new IllegalArgumentException(String.format("The path '%1$s' belongs to a directory!", filePath.getPath())); + } + if (!filePath.exists()) { + return new Properties(); + } + Properties properties = new Properties(); + Reader reader = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + reader = new InputStreamReader(new BufferedInputStream(new FileInputStream(filePath)), Charsets.UTF_8); + properties.load(reader); + } finally { + Closeables.close(reader, true); + } + return properties; + } + + public static void savePropertiesToFile(@NotNull Properties properties, @NotNull File filePath, @Nullable String comments) throws IOException { + FileUtilRt.createParentDirs(filePath); + FileOutputStream out = null; + try { + //noinspection IOResourceOpenedButNotSafelyClosed + out = new FileOutputStream(filePath); + // Note that we don't write the properties files in UTF-8; this will *not* write the + // files with the default platform encoding; instead, it will write it using ISO-8859-1 and + // \\u escaping syntax for other characters. This will work with older versions of the Gradle + // plugin which does not read the .properties file with UTF-8 encoding. In the future when + // nobody is using older (0.7.x) versions of the Gradle plugin anymore we can upgrade this + properties.store(out, comments); + } finally { + Closeables.close(out, true); + } + } +} diff --git a/android/src/com/android/tools/idea/startup/AndroidStudioSpecificInitializer.java b/android/src/com/android/tools/idea/startup/AndroidStudioSpecificInitializer.java index b2a7663c85d..1e6ef7356db 100755 --- a/android/src/com/android/tools/idea/startup/AndroidStudioSpecificInitializer.java +++ b/android/src/com/android/tools/idea/startup/AndroidStudioSpecificInitializer.java @@ -20,6 +20,7 @@ import com.android.sdklib.IAndroidTarget; import com.android.tools.idea.actions.*; import com.android.tools.idea.gradle.util.GradleUtil; import com.android.tools.idea.gradle.util.Projects; +import com.android.tools.idea.gradle.util.PropertiesUtil; import com.android.tools.idea.memory.MemoryProfilerAction; import com.android.tools.idea.run.ArrayMapRenderer; import com.android.tools.idea.sdk.DefaultSdks; @@ -29,7 +30,6 @@ import com.android.tools.idea.wizard.ExperimentalActionsForTesting; import com.android.utils.Pair; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; -import com.google.common.io.Closeables; import com.intellij.debugger.settings.NodeRendererSettings; import com.intellij.ide.AppLifecycleListener; import com.intellij.ide.actions.TemplateProjectSettingsGroup; @@ -75,7 +75,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayDeque; import java.util.Deque; @@ -485,22 +484,12 @@ public class AndroidStudioSpecificInitializer implements Runnable { if (!f.exists()) { return null; } - Properties properties = new Properties(); - FileInputStream fis = null; try { - //noinspection IOResourceOpenedButNotSafelyClosed - fis = new FileInputStream(f); - properties.load(fis); + Properties properties = PropertiesUtil.getProperties(f); + return properties.getProperty("lastSdkPath"); } catch (IOException e) { return null; - } finally { - try { - Closeables.close(fis, true /* swallowIOException */); - } catch (IOException e) { - // Cannot happen - } } - return properties.getProperty("lastSdkPath"); } /** diff --git a/android/src/org/jetbrains/android/facet/AndroidRootUtil.java b/android/src/org/jetbrains/android/facet/AndroidRootUtil.java index 83b04bba5e4..5e13fb8cfbd 100644 --- a/android/src/org/jetbrains/android/facet/AndroidRootUtil.java +++ b/android/src/org/jetbrains/android/facet/AndroidRootUtil.java @@ -23,6 +23,7 @@ import com.android.builder.model.Variant; import com.android.tools.idea.AndroidPsiUtils; import com.android.tools.idea.gradle.IdeaAndroidProject; import com.android.tools.idea.gradle.util.GradleUtil; +import com.android.tools.idea.gradle.util.PropertiesUtil; import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.application.ApplicationManager; @@ -34,10 +35,7 @@ import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.JarFileSystem; -import com.intellij.openapi.vfs.LocalFileSystem; -import com.intellij.openapi.vfs.VfsUtilCore; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vfs.*; import com.intellij.psi.PsiFile; import com.intellij.util.containers.OrderedSet; import org.jetbrains.android.compiler.AndroidCompileUtil; @@ -51,7 +49,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.*; @@ -473,9 +470,9 @@ public class AndroidRootUtil { private static Pair<Properties, VirtualFile> readPropertyFile(@NotNull VirtualFile contentRoot, @NotNull String propertyFileName) { final VirtualFile vFile = contentRoot.findChild(propertyFileName); if (vFile != null) { - final Properties properties = new Properties(); try { - properties.load(new FileInputStream(new File(vFile.getPath()))); + File file = VfsUtilCore.virtualToIoFile(vFile); + Properties properties = PropertiesUtil.getProperties(file); return new Pair<Properties, VirtualFile>(properties, vFile); } catch (IOException e) { diff --git a/android/testData/guiTests/SimpleApplication/app/app.iml b/android/testData/guiTests/SimpleApplication/app/app.iml index a2d942c2ba1..8c6eea5d9f3 100644 --- a/android/testData/guiTests/SimpleApplication/app/app.iml +++ b/android/testData/guiTests/SimpleApplication/app/app.iml @@ -13,6 +13,7 @@ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugJava" /> <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" /> <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" /> + <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugTestSources" /> <option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> diff --git a/android/testSrc/com/android/tools/idea/gradle/eclipse/GradleImportTest.java b/android/testSrc/com/android/tools/idea/gradle/eclipse/GradleImportTest.java index 36b7c5d623a..b76c2f2702d 100644 --- a/android/testSrc/com/android/tools/idea/gradle/eclipse/GradleImportTest.java +++ b/android/testSrc/com/android/tools/idea/gradle/eclipse/GradleImportTest.java @@ -4,6 +4,7 @@ import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.sdklib.BuildToolInfo; import com.android.sdklib.SdkManager; +import com.android.tools.idea.gradle.util.PropertiesUtil; import com.android.tools.idea.templates.TemplateManager; import com.android.utils.ILogger; import com.android.utils.Pair; @@ -1324,10 +1325,10 @@ public class GradleImportTest extends AndroidTestCase { // Only because we need .replace(NL, "\n")); assertEquals(sdkLocation.getPath(), - GradleImport.getProperties(new File(imported, FN_LOCAL_PROPERTIES)). + PropertiesUtil.getProperties(new File(imported, FN_LOCAL_PROPERTIES)). getProperty("sdk.dir")); assertEquals(ndkLocation.getPath(), - GradleImport.getProperties(new File(imported, FN_LOCAL_PROPERTIES)). + PropertiesUtil.getProperties(new File(imported, FN_LOCAL_PROPERTIES)). getProperty("ndk.dir")); deleteDir(root); diff --git a/android/testSrc/com/android/tools/idea/gradle/util/GradleUtilTest.java b/android/testSrc/com/android/tools/idea/gradle/util/GradleUtilTest.java index 1e548d10811..bd638f63cc4 100644 --- a/android/testSrc/com/android/tools/idea/gradle/util/GradleUtilTest.java +++ b/android/testSrc/com/android/tools/idea/gradle/util/GradleUtilTest.java @@ -18,14 +18,12 @@ package com.android.tools.idea.gradle.util; import com.android.sdklib.repository.FullRevision; import com.google.common.base.Charsets; import com.google.common.collect.Lists; -import com.google.common.io.Closeables; import com.google.common.io.Files; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtilRt; import junit.framework.TestCase; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.List; import java.util.Properties; @@ -60,18 +58,9 @@ public class GradleUtilTest extends TestCase { FileUtilRt.createIfNotExists(wrapper); GradleUtil.updateGradleDistributionUrl("1.6", wrapper); - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - fileInputStream = new FileInputStream(wrapper); - properties.load(fileInputStream); - String distributionUrl = properties.getProperty("distributionUrl"); - assertEquals("http://services.gradle.org/distributions/gradle-1.6-all.zip", distributionUrl); - } - finally { - Closeables.close(fileInputStream, true /* swallowIOException */); - } + Properties properties = PropertiesUtil.getProperties(wrapper); + String distributionUrl = properties.getProperty("distributionUrl"); + assertEquals("http://services.gradle.org/distributions/gradle-1.6-all.zip", distributionUrl); } public void testLeaveGradleWrapperAloneBin() throws IOException { @@ -86,18 +75,9 @@ public class GradleUtilTest extends TestCase { "distributionUrl=http\\://services.gradle.org/distributions/gradle-1.9-bin.zip", wrapper, Charsets.UTF_8); GradleUtil.updateGradleDistributionUrl("1.9", wrapper); - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - fileInputStream = new FileInputStream(wrapper); - properties.load(fileInputStream); - String distributionUrl = properties.getProperty("distributionUrl"); - assertEquals("http://services.gradle.org/distributions/gradle-1.9-bin.zip", distributionUrl); - } - finally { - Closeables.close(fileInputStream, true /* swallowIOException */); - } + Properties properties = PropertiesUtil.getProperties(wrapper); + String distributionUrl = properties.getProperty("distributionUrl"); + assertEquals("http://services.gradle.org/distributions/gradle-1.9-bin.zip", distributionUrl); } public void testLeaveGradleWrapperAloneAll() throws IOException { @@ -112,18 +92,9 @@ public class GradleUtilTest extends TestCase { "distributionUrl=http\\://services.gradle.org/distributions/gradle-1.9-all.zip", wrapper, Charsets.UTF_8); GradleUtil.updateGradleDistributionUrl("1.9", wrapper); - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - fileInputStream = new FileInputStream(wrapper); - properties.load(fileInputStream); - String distributionUrl = properties.getProperty("distributionUrl"); - assertEquals("http://services.gradle.org/distributions/gradle-1.9-all.zip", distributionUrl); - } - finally { - Closeables.close(fileInputStream, true /* swallowIOException */); - } + Properties properties = PropertiesUtil.getProperties(wrapper); + String distributionUrl = properties.getProperty("distributionUrl"); + assertEquals("http://services.gradle.org/distributions/gradle-1.9-all.zip", distributionUrl); } public void testReplaceGradleWrapper() throws IOException { @@ -138,18 +109,9 @@ public class GradleUtilTest extends TestCase { "distributionUrl=http\\://services.gradle.org/distributions/gradle-1.9-bin.zip", wrapper, Charsets.UTF_8); GradleUtil.updateGradleDistributionUrl("1.6", wrapper); - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - //noinspection IOResourceOpenedButNotSafelyClosed - fileInputStream = new FileInputStream(wrapper); - properties.load(fileInputStream); - String distributionUrl = properties.getProperty("distributionUrl"); - assertEquals("http://services.gradle.org/distributions/gradle-1.6-all.zip", distributionUrl); - } - finally { - Closeables.close(fileInputStream, true /* swallowIOException */); - } + Properties properties = PropertiesUtil.getProperties(wrapper); + String distributionUrl = properties.getProperty("distributionUrl"); + assertEquals("http://services.gradle.org/distributions/gradle-1.6-all.zip", distributionUrl); } public void testUpdateGradleDistributionUrl() { diff --git a/android/testSrc/com/android/tools/idea/gradle/util/LocalPropertiesTest.java b/android/testSrc/com/android/tools/idea/gradle/util/LocalPropertiesTest.java index 51771b30078..322990cb1c5 100644 --- a/android/testSrc/com/android/tools/idea/gradle/util/LocalPropertiesTest.java +++ b/android/testSrc/com/android/tools/idea/gradle/util/LocalPropertiesTest.java @@ -88,7 +88,7 @@ public class LocalPropertiesTest extends IdeaTestCase { outProperties.setProperty(SdkConstants.SDK_DIR_PROPERTY, sdk.getPath()); // First write properties using the default encoding (which will \\u escape all non-iso-8859 chars) - outProperties.store(new FileOutputStream(localPropertiesFile), null); + PropertiesUtil.savePropertiesToFile(outProperties, localPropertiesFile, null); // Read back platform default version of string; confirm that it gets converted properly LocalProperties properties1 = new LocalProperties(myProject); |